MediaWiki:Gadget-PrintOptions.js:修订间差异
外观
小无编辑摘要 标签:已被回退 |
小无编辑摘要 标签:已被回退 |
||
| 第15行: | 第15行: | ||
'hideImages': mw.message('printdialog-opt-hide-images').plain() || '隐藏图片', | 'hideImages': mw.message('printdialog-opt-hide-images').plain() || '隐藏图片', | ||
'hideRefs': mw.message('printdialog-opt-hide-refs').plain() || '隐藏参考文献' | 'hideRefs': mw.message('printdialog-opt-hide-refs').plain() || '隐藏参考文献' | ||
}, | }, | ||
'help': { | 'help': { | ||
'hideImages': mw.message('printdialog-help-hide-images').plain() || '不打印页面中的图片和缩略图' | 'hideImages': mw.message('printdialog-help-hide-images').plain() || '不打印页面中的图片和缩略图', | ||
'hideRefs': mw.message('printdialog-help-hide-refs').plain() || '不打印参考文献和引用部分' | |||
} | } | ||
}; | }; | ||
| 第28行: | 第28行: | ||
dependencies: ['oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows'], | dependencies: ['oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows'], | ||
hotkeys: { | hotkeys: { | ||
print: 'ctrl+enter', | print: 'ctrl+enter', | ||
cancel: 'esc' | cancel: 'esc' | ||
} | } | ||
}, | }, | ||
| 第36行: | 第36行: | ||
init: function () { | init: function () { | ||
if (!this.shouldInit()) return; | if (!this.shouldInit()) return; | ||
// 预加载依赖 | |||
if (!this.isDepsLoaded()) { | |||
mw.loader.load(this.config.dependencies); | |||
} | |||
// 绑定打印按钮 | // 绑定打印按钮 | ||
| 第43行: | 第48行: | ||
.on('click.print', this.onPrintClick.bind(this)); | .on('click.print', this.onPrintClick.bind(this)); | ||
this.registerHotkeys(); | |||
if ( | |||
if (this.config.debug) { | |||
console.log('PrintDialog initialized'); | |||
} | } | ||
}, | }, | ||
| 第72行: | 第75行: | ||
}, | }, | ||
// 🏗️ | // 🏗️ 创建对话框类 | ||
createDialogClass: function () { | |||
var self = this; | |||
function Dialog(config) { | function Dialog(config) { | ||
Dialog.super.call(this, config); | Dialog.super.call(this, config); | ||
| 第85行: | 第84行: | ||
OO.inheritClass(Dialog, OO.ui.ProcessDialog); | OO.inheritClass(Dialog, OO.ui.ProcessDialog); | ||
// | // 静态配置 | ||
Dialog.static.name = 'printDialog'; | Dialog.static.name = 'printDialog'; | ||
Dialog.static.title = i18n.title; | Dialog.static.title = i18n.title; | ||
| 第107行: | 第106行: | ||
Dialog.super.prototype.initialize.apply(this, arguments); | Dialog.super.prototype.initialize.apply(this, arguments); | ||
this.buildForm(); | this.buildForm(); | ||
if (self.config.debug) { | |||
console.log('PrintDialog: Dialog initialized'); | |||
} | |||
}; | }; | ||
// | // 构建表单 | ||
Dialog.prototype.buildForm = function () { | Dialog.prototype.buildForm = function () { | ||
var panel = new OO.ui.PanelLayout({ padded: true }); | var panel = new OO.ui.PanelLayout({ padded: true }); | ||
var fieldset = new OO.ui.FieldsetLayout(); | var fieldset = new OO.ui.FieldsetLayout({ | ||
label: mw.message('printdialog-options-title').plain() || '打印选项' | |||
}); | |||
// 初始化选项部件存储 | |||
self.optionWidgets = {}; | |||
self.options.forEach(function (opt) { | |||
if (opt.type === 'checkbox') { | if (opt.type === 'checkbox') { | ||
var widget = new OO.ui.CheckboxInputWidget({ | var widget = new OO.ui.CheckboxInputWidget({ | ||
| 第120行: | 第128行: | ||
}); | }); | ||
// 保存部件引用 | |||
self.optionWidgets[opt.id] = widget; | |||
opt. | var fieldLayout = new OO.ui.FieldLayout(widget, { | ||
label: i18n.options[opt.id] || opt.id, | |||
align: 'inline', | |||
help: i18n.help[opt.id] ? | |||
new OO.ui.LabelWidget({ | |||
label: i18n.help[opt.id] | |||
}) : null | |||
}); | |||
fieldset.addItems([fieldLayout]); | |||
} | } | ||
}); | }); | ||
| 第135行: | 第146行: | ||
panel.$element.append(fieldset.$element); | panel.$element.append(fieldset.$element); | ||
this.$body.append(panel.$element); | this.$body.append(panel.$element); | ||
if (self.config.debug) { | |||
console.log('PrintDialog: Form built with options', self.options); | |||
} | |||
}; | }; | ||
// | // 处理动作 | ||
Dialog.prototype.getActionProcess = function (action) { | Dialog.prototype.getActionProcess = function (action) { | ||
if (action === 'print') { | if (action === 'print') { | ||
| 第147行: | 第162行: | ||
}; | }; | ||
// | // 执行打印 | ||
Dialog.prototype.executePrintAction = function () { | Dialog.prototype.executePrintAction = function () { | ||
var process = new OO.ui.Process(); | |||
// 保存设置 | // 保存设置 | ||
if (self.optionWidgets) { | |||
Object.keys(self.optionWidgets).forEach(function (key) { | |||
}); | self.settings[key] = self.optionWidgets[key].isSelected(); | ||
}); | |||
} | |||
if (self.config.debug) { | |||
console.log('PrintDialog: Settings saved', self.settings); | |||
} | |||
// | // 关闭窗口 | ||
return this.close({ action: 'print' }) | return this.close({ action: 'print' }) | ||
.then(function () { | .then(function () { | ||
if (typeof window.print === 'function') { | return self.applyPrintStyles(); | ||
}) | |||
.then(function () { | |||
// 延迟确保样式已应用 | |||
} | return new Promise(function (resolve) { | ||
setTimeout(function () { | |||
if (typeof window.print === 'function') { | |||
window.print(); | |||
resolve(); | |||
} else { | |||
throw new Error(i18n['no-print-support']); | |||
} | |||
}, 100); | |||
}); | |||
}) | }) | ||
.catch(function (err) { | .catch(function (err) { | ||
mw.notify(i18n['print-error'].replace('$1', err.message), { type: 'error' }); | mw.notify( | ||
i18n['print-error'].replace('$1', err.message), | |||
{ type: 'error', tag: 'printdialog' } | |||
); | |||
throw err; // 重新抛出以保持错误链 | |||
}); | }); | ||
}; | }; | ||
return Dialog; | |||
}, | |||
// 🏗️ 创建对话框实例 | |||
createDialog: function () { | |||
if (this.dialog && this.windowManager) { | |||
this.windowManager.openWindow(this.dialog); | |||
return Promise.resolve(); | |||
} | |||
// 初始化窗口管理器 | // 初始化窗口管理器 | ||
| 第173行: | 第218行: | ||
this.windowManager = new OO.ui.WindowManager(); | this.windowManager = new OO.ui.WindowManager(); | ||
$('body').append(this.windowManager.$element); | $('body').append(this.windowManager.$element); | ||
} | |||
// 创建对话框类(如果不存在) | |||
if (!this.DialogClass) { | |||
this.DialogClass = this.createDialogClass(); | |||
} | } | ||
// 创建对话框实例 | // 创建对话框实例 | ||
this.dialog = new | this.dialog = new this.DialogClass({ | ||
size: 'medium' | |||
}); | |||
this.windowManager.addWindows([this.dialog]); | this.windowManager.addWindows([this.dialog]); | ||
this.windowManager.openWindow(this.dialog); | return this.windowManager.openWindow(this.dialog); | ||
}, | }, | ||
| 第185行: | 第238行: | ||
var style = []; | var style = []; | ||
if ( | // 隐藏图片 | ||
style.push('img, .thumb { display:none !important; }'); | if (this.settings.hideImages) { | ||
style.push( | |||
'img, .thumb, .gallery, .image, .thumbinner, .thumbimage { ' + | |||
'display:none !important; }' | |||
); | |||
} | } | ||
// | // 隐藏参考文献 | ||
if (this.settings.hideRefs) { | |||
style.push( | |||
'.references, .ref-list, #References, .reflist, .citation { ' + | |||
'display:none !important; }' | |||
); | |||
} | |||
// 清理旧样式 | |||
$('style.print-styles').remove(); | $('style.print-styles').remove(); | ||
if (style.length) { | |||
// 添加新样式 | |||
if (style.length > 0) { | |||
$('<style>') | $('<style>') | ||
.addClass('print-styles') | .addClass('print-styles') | ||
.attr('media', 'print') | .attr('media', 'print') | ||
.attr('type', 'text/css') | |||
.text(style.join('\n')) | .text(style.join('\n')) | ||
.appendTo('head'); | .appendTo('head'); | ||
if (this.config.debug) { | |||
console.log('PrintDialog: Applied print styles', style); | |||
} | |||
} | } | ||
return Promise.resolve(); | return Promise.resolve(); | ||
}, | }, | ||
| 第217行: | 第278行: | ||
e.preventDefault(); | e.preventDefault(); | ||
if (this.config.debug) { | |||
console.log('PrintDialog: Print button clicked'); | |||
} | |||
// 创建加载通知 | |||
var progressBar = new OO.ui.ProgressBarWidget({ progress: false }); | |||
); | var notification = mw.notify(progressBar.$element, { | ||
title: i18n.loading, | |||
autoHide: false, | |||
tag: 'printdialog-loading' | |||
}); | |||
// 确保依赖已加载并创建对话框 | |||
mw.loader.using(this.config.dependencies) | mw.loader.using(this.config.dependencies) | ||
.then(this.createDialog.bind(this)) | .then(this.createDialog.bind(this)) | ||
.catch(function (err) { | .catch(function (err) { | ||
mw.notify(i18n['print-error'].replace('$1', err.message), { type: 'error' }); | console.error('PrintDialog: Error creating dialog', err); | ||
mw.notify( | |||
i18n['print-error'].replace('$1', err.message), | |||
{ type: 'error', tag: 'printdialog' } | |||
); | |||
}) | }) | ||
.always(function () { | .always(function () { | ||
notification.close(); | notification.close(); | ||
}); | }); | ||
}, | |||
// ✅ 工具方法 | |||
shouldInit: function () { | |||
// 只在内容命名空间显示 | |||
return mw.config.get('wgNamespaceNumber') >= 0 && | |||
$('#t-print').length > 0; | |||
}, | |||
isDepsLoaded: function () { | |||
return this.config.dependencies.every(function (dep) { | |||
var state = mw.loader.getState(dep); | |||
return state === 'ready' || state === 'loaded'; | |||
}); | |||
}, | }, | ||
| 第240行: | 第324行: | ||
id: 'hideImages', | id: 'hideImages', | ||
type: 'checkbox', | type: 'checkbox', | ||
default: false | default: false, | ||
description: 'Hide images and thumbnails in print' | |||
}, | }, | ||
{ | { | ||
id: 'hideRefs', | id: 'hideRefs', | ||
type: 'checkbox', | type: 'checkbox', | ||
default: false | default: false, | ||
description: 'Hide references and citations in print' | |||
} | } | ||
], | ], | ||
| 第251行: | 第337行: | ||
// 🗃️ 状态存储 | // 🗃️ 状态存储 | ||
settings: {}, | settings: {}, | ||
optionWidgets: null, | |||
// ♻️ 清理方法 | // ♻️ 清理方法 | ||
destroy: function () { | destroy: function () { | ||
$(document).off('keydown.printdialog'); | $(document).off('keydown.printdialog'); | ||
if (this.windowManager) { | if (this.windowManager) { | ||
this.windowManager.destroy(); | this.windowManager.destroy(); | ||
this.windowManager = null; | this.windowManager = null; | ||
} | } | ||
$('style.print-styles').remove(); | |||
this.dialog = null; | this.dialog = null; | ||
this.DialogClass = null; | |||
this.optionWidgets = null; | |||
if (this.config.debug) { | |||
console.log('PrintDialog: Destroyed'); | |||
} | |||
} | } | ||
}; | }; | ||
| 第265行: | 第362行: | ||
// 📅 延迟初始化 | // 📅 延迟初始化 | ||
mw.hook('wikipage.content').add(function () { | mw.hook('wikipage.content').add(function () { | ||
setTimeout(PrintDialog.init.bind(PrintDialog), 300); | // 等待页面完全加载后再初始化 | ||
if (document.readyState === 'loading') { | |||
$(document).ready(function () { | |||
setTimeout(PrintDialog.init.bind(PrintDialog), 300); | |||
}); | |||
} else { | |||
setTimeout(PrintDialog.init.bind(PrintDialog), 300); | |||
} | |||
}); | }); | ||
// 🖇️ | // 🖇️ 暴露到全局 | ||
window.PrintDialog = PrintDialog; | window.PrintDialog = PrintDialog; | ||
if (PrintDialog.config.debug) { | |||
console.log('PrintDialog: Module loaded'); | |||
} | |||
})(mediaWiki, jQuery); | })(mediaWiki, jQuery); | ||
2025年11月1日 (六) 22:26的版本
/*! PrintDialog v3.0 - 支持多语言&快捷键 */
(function (mw, $) {
'use strict';
// 🌐 本地化文本库
var i18n = {
'title': mw.message('printdialog-title').plain() || '打印选项',
'print-btn': mw.message('printdialog-print-btn').plain() || '打印',
'cancel-btn': mw.message('printdialog-cancel-btn').plain() || '取消',
'loading': mw.message('printdialog-loading').plain() || '准备打印中...',
'print-error': mw.message('printdialog-error').plain() || '打印失败:$1',
'no-print-support': mw.message('printdialog-no-support').plain() || '您的浏览器不支持直接打印',
// 选项文本
'options': {
'hideImages': mw.message('printdialog-opt-hide-images').plain() || '隐藏图片',
'hideRefs': mw.message('printdialog-opt-hide-refs').plain() || '隐藏参考文献'
},
'help': {
'hideImages': mw.message('printdialog-help-hide-images').plain() || '不打印页面中的图片和缩略图',
'hideRefs': mw.message('printdialog-help-hide-refs').plain() || '不打印参考文献和引用部分'
}
};
var PrintDialog = {
// ⚙️ 配置项
config: {
debug: false,
dependencies: ['oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows'],
hotkeys: {
print: 'ctrl+enter',
cancel: 'esc'
}
},
// 🚀 初始化
init: function () {
if (!this.shouldInit()) return;
// 预加载依赖
if (!this.isDepsLoaded()) {
mw.loader.load(this.config.dependencies);
}
// 绑定打印按钮
$('#t-print a').first()
.text(mw.message('printdialog-link-text').plain() || '可打印版本')
.off('click.print')
.on('click.print', this.onPrintClick.bind(this));
this.registerHotkeys();
if (this.config.debug) {
console.log('PrintDialog initialized');
}
},
// 🔥 快捷键支持
registerHotkeys: function () {
$(document).off('keydown.printdialog')
.on('keydown.printdialog', function (e) {
if (!PrintDialog.dialog || !PrintDialog.windowManager) return;
// ESC - 取消
if (e.key === 'Escape') {
PrintDialog.dialog.executeAction('cancel');
e.preventDefault();
}
// Ctrl+Enter - 打印
if (e.ctrlKey && e.key === 'Enter') {
PrintDialog.dialog.executeAction('print');
e.preventDefault();
}
});
},
// 🏗️ 创建对话框类
createDialogClass: function () {
var self = this;
function Dialog(config) {
Dialog.super.call(this, config);
}
OO.inheritClass(Dialog, OO.ui.ProcessDialog);
// 静态配置
Dialog.static.name = 'printDialog';
Dialog.static.title = i18n.title;
Dialog.static.actions = [
{
action: 'print',
label: i18n['print-btn'],
flags: ['primary', 'progressive'],
icon: 'printer'
},
{
action: 'cancel',
label: i18n['cancel-btn'],
flags: 'safe',
icon: 'close'
}
];
// 初始化内容
Dialog.prototype.initialize = function () {
Dialog.super.prototype.initialize.apply(this, arguments);
this.buildForm();
if (self.config.debug) {
console.log('PrintDialog: Dialog initialized');
}
};
// 构建表单
Dialog.prototype.buildForm = function () {
var panel = new OO.ui.PanelLayout({ padded: true });
var fieldset = new OO.ui.FieldsetLayout({
label: mw.message('printdialog-options-title').plain() || '打印选项'
});
// 初始化选项部件存储
self.optionWidgets = {};
self.options.forEach(function (opt) {
if (opt.type === 'checkbox') {
var widget = new OO.ui.CheckboxInputWidget({
selected: !!opt.default
});
// 保存部件引用
self.optionWidgets[opt.id] = widget;
var fieldLayout = new OO.ui.FieldLayout(widget, {
label: i18n.options[opt.id] || opt.id,
align: 'inline',
help: i18n.help[opt.id] ?
new OO.ui.LabelWidget({
label: i18n.help[opt.id]
}) : null
});
fieldset.addItems([fieldLayout]);
}
});
panel.$element.append(fieldset.$element);
this.$body.append(panel.$element);
if (self.config.debug) {
console.log('PrintDialog: Form built with options', self.options);
}
};
// 处理动作
Dialog.prototype.getActionProcess = function (action) {
if (action === 'print') {
return new OO.ui.Process(function () {
return this.executePrintAction();
}.bind(this));
}
return Dialog.super.prototype.getActionProcess.call(this, action);
};
// 执行打印
Dialog.prototype.executePrintAction = function () {
var process = new OO.ui.Process();
// 保存设置
if (self.optionWidgets) {
Object.keys(self.optionWidgets).forEach(function (key) {
self.settings[key] = self.optionWidgets[key].isSelected();
});
}
if (self.config.debug) {
console.log('PrintDialog: Settings saved', self.settings);
}
// 关闭窗口
return this.close({ action: 'print' })
.then(function () {
return self.applyPrintStyles();
})
.then(function () {
// 延迟确保样式已应用
return new Promise(function (resolve) {
setTimeout(function () {
if (typeof window.print === 'function') {
window.print();
resolve();
} else {
throw new Error(i18n['no-print-support']);
}
}, 100);
});
})
.catch(function (err) {
mw.notify(
i18n['print-error'].replace('$1', err.message),
{ type: 'error', tag: 'printdialog' }
);
throw err; // 重新抛出以保持错误链
});
};
return Dialog;
},
// 🏗️ 创建对话框实例
createDialog: function () {
if (this.dialog && this.windowManager) {
this.windowManager.openWindow(this.dialog);
return Promise.resolve();
}
// 初始化窗口管理器
if (!this.windowManager) {
this.windowManager = new OO.ui.WindowManager();
$('body').append(this.windowManager.$element);
}
// 创建对话框类(如果不存在)
if (!this.DialogClass) {
this.DialogClass = this.createDialogClass();
}
// 创建对话框实例
this.dialog = new this.DialogClass({
size: 'medium'
});
this.windowManager.addWindows([this.dialog]);
return this.windowManager.openWindow(this.dialog);
},
// 🎨 应用打印样式
applyPrintStyles: function () {
var style = [];
// 隐藏图片
if (this.settings.hideImages) {
style.push(
'img, .thumb, .gallery, .image, .thumbinner, .thumbimage { ' +
'display:none !important; }'
);
}
// 隐藏参考文献
if (this.settings.hideRefs) {
style.push(
'.references, .ref-list, #References, .reflist, .citation { ' +
'display:none !important; }'
);
}
// 清理旧样式
$('style.print-styles').remove();
// 添加新样式
if (style.length > 0) {
$('<style>')
.addClass('print-styles')
.attr('media', 'print')
.attr('type', 'text/css')
.text(style.join('\n'))
.appendTo('head');
if (this.config.debug) {
console.log('PrintDialog: Applied print styles', style);
}
}
return Promise.resolve();
},
// 🖨️ 主入口处理
onPrintClick: function (e) {
e.preventDefault();
if (this.config.debug) {
console.log('PrintDialog: Print button clicked');
}
// 创建加载通知
var progressBar = new OO.ui.ProgressBarWidget({ progress: false });
var notification = mw.notify(progressBar.$element, {
title: i18n.loading,
autoHide: false,
tag: 'printdialog-loading'
});
// 确保依赖已加载并创建对话框
mw.loader.using(this.config.dependencies)
.then(this.createDialog.bind(this))
.catch(function (err) {
console.error('PrintDialog: Error creating dialog', err);
mw.notify(
i18n['print-error'].replace('$1', err.message),
{ type: 'error', tag: 'printdialog' }
);
})
.always(function () {
notification.close();
});
},
// ✅ 工具方法
shouldInit: function () {
// 只在内容命名空间显示
return mw.config.get('wgNamespaceNumber') >= 0 &&
$('#t-print').length > 0;
},
isDepsLoaded: function () {
return this.config.dependencies.every(function (dep) {
var state = mw.loader.getState(dep);
return state === 'ready' || state === 'loaded';
});
},
// ⚙️ 可配置选项
options: [
{
id: 'hideImages',
type: 'checkbox',
default: false,
description: 'Hide images and thumbnails in print'
},
{
id: 'hideRefs',
type: 'checkbox',
default: false,
description: 'Hide references and citations in print'
}
],
// 🗃️ 状态存储
settings: {},
optionWidgets: null,
// ♻️ 清理方法
destroy: function () {
$(document).off('keydown.printdialog');
if (this.windowManager) {
this.windowManager.destroy();
this.windowManager = null;
}
$('style.print-styles').remove();
this.dialog = null;
this.DialogClass = null;
this.optionWidgets = null;
if (this.config.debug) {
console.log('PrintDialog: Destroyed');
}
}
};
// 📅 延迟初始化
mw.hook('wikipage.content').add(function () {
// 等待页面完全加载后再初始化
if (document.readyState === 'loading') {
$(document).ready(function () {
setTimeout(PrintDialog.init.bind(PrintDialog), 300);
});
} else {
setTimeout(PrintDialog.init.bind(PrintDialog), 300);
}
});
// 🖇️ 暴露到全局
window.PrintDialog = PrintDialog;
if (PrintDialog.config.debug) {
console.log('PrintDialog: Module loaded');
}
})(mediaWiki, jQuery);