LLWiki正在建设中,欢迎加入我们!
“MediaWiki:Gadget-SettingsDialog.js”的版本间差异
跳转到导航
跳转到搜索
小 |
(// 使用Wikiplus小工具快速编辑) 标签:移动版网页编辑 移动版编辑 |
||
(未显示同一用户的20个中间版本) | |||
第3行: | 第3行: | ||
/** |
/** |
||
* @Function: 定义小工具设置对话框 |
* @Function: 定义小工具设置对话框 |
||
* @Methods: |
* @Methods: getName: 获取小工具名称 |
||
* getName: 获取小工具名称 |
|||
* getObject: 获取小工具对象 |
* getObject: 获取小工具对象 |
||
* getPanel: 获取小工具标签页 |
|||
* addTab: 添加小工具 |
* addTab: 添加小工具 |
||
* |
* generateOptions: 生成设置对象 |
||
* saveOptions: 将设置保存到localStorage |
* saveOptions: 将设置保存到localStorage |
||
* standardSaveOptions: 默认的saveOptions函数 |
|||
* clearOptions: 还原设置 |
* clearOptions: 还原设置 |
||
* standardClearOptions: 默认的clearOptions函数 |
|||
* export: 导出设置 |
* export: 导出设置 |
||
* standardExport: 默认的export函数 |
|||
* @Dependencies: mediawiki.util, mediawiki.storage, oojs-ui-windows, oojs-ui-widgets, ext.gadget.site-lib, user |
* @Dependencies: mediawiki.util, mediawiki.storage, oojs-ui-windows, oojs-ui-widgets, ext.gadget.site-lib, user |
||
* @Author: [[User:Bhsd]] |
* @Author: [[User:Bhsd]] |
||
第19行: | 第16行: | ||
"use strict"; |
"use strict"; |
||
/* global OO, hljs, wgULS */ |
/* global OO, hljs, wgULS */ |
||
mw.gadgets = mw.gadgets || {}; |
|||
//避免使用API加载消息,直接手动添加 |
|||
// 1. 设置繁简文字信息 |
|||
mw.messages.set( wgULS({ |
mw.messages.set( wgULS({ |
||
'gadget-sd- |
'gadget-sd-copy': '请将以下代码添加至您的', 'gadget-sd-notify': '您的设置已保存!新设置将于刷新页面后生效。', |
||
'gadget-sd-tooltip': '为当前浏览器设置小工具偏好', 'gadget-sd-back': '还原', 'gadget-sd-save': '保存', |
|||
'gadget-sd-help': '您可以在这里修改小工具偏好,修改仅对当前浏览器有效。如果想要修改设置对所有浏览器生效,请查阅', |
'gadget-sd-help': '您可以在这里修改小工具偏好,修改仅对当前浏览器有效。如果想要修改设置对所有浏览器生效,请查阅', |
||
'gadget-sd-helptext': '帮助页面', 'gadget-sd- |
'gadget-sd-helptext': '帮助页面', 'gadget-sd-exporthelp': '导出代码', 'gadget-sd-js': '用户JS', |
||
'gadget-sd- |
'gadget-sd-title': '小工具设置', 'gadget-sd-back': '还原', 'gadget-sd-save': '保存', 'gadget-sd-export': '导出' |
||
}, { |
}, { |
||
'gadget-sd- |
'gadget-sd-copy': '請將以下代碼添加至您的', 'gadget-sd-notify': '您的偏好設定已儲存!新設定將於重新載入頁面後生效。', |
||
'gadget-sd-tooltip': '為當前瀏覽器設定小工具偏好', 'gadget-sd-back': '復原', 'gadget-sd-save': '儲存', |
|||
'gadget-sd-help': '您可以在這裡修改小工具偏好,修改僅對當前瀏覽器有效。如果想要修改設定對所有瀏覽器生效,請查閱', |
'gadget-sd-help': '您可以在這裡修改小工具偏好,修改僅對當前瀏覽器有效。如果想要修改設定對所有瀏覽器生效,請查閱', |
||
'gadget-sd-helptext': '說明頁面', 'gadget-sd- |
'gadget-sd-helptext': '說明頁面', 'gadget-sd-exporthelp': '導出代碼', 'gadget-sd-js': '使用者JS', |
||
'gadget-sd- |
'gadget-sd-title': '小工具偏好設定', 'gadget-sd-back': '復原', 'gadget-sd-save': '儲存', 'gadget-sd-export': '導出' |
||
}) ); |
}) ); |
||
// 2. 准备HTML元素 |
|||
var ready = false; // 是否是第一次打开对话框 |
|||
var ready = false, dialog; // 是否是第一次打开对话框 |
|||
const $helpPage = $('<a>', {target: '_blank', text: mw.msg('gadget-sd-helptext')}), // 需要动态设置href |
|||
const isUser = mw.config.get( 'wgUserGroups' ).includes( 'user' ), |
|||
$help = $('<div>', {html: [ |
|||
gadgets = mw.gadgets, |
|||
mw.msg('gadget-sd-help'), $helpPage, ',或', |
|||
$helpPage = $('<a>', {target: '_blank', text: mw.msg('gadget-sd-helptext')}), // 需要动态设置href |
|||
$help = $('<div>', {html: [ mw.msg('gadget-sd-help'), $helpPage, ',或', |
|||
$('<a>', {href: '#settingsDialog-btns', text: mw.msg('gadget-sd-exporthelp')}), '。' // 链接跳转到“导出”按钮 |
$('<a>', {href: '#settingsDialog-btns', text: mw.msg('gadget-sd-exporthelp')}), '。' // 链接跳转到“导出”按钮 |
||
]}), |
]}), |
||
$ |
$block = $('<pre>', {class: 'javascript'}), |
||
mw.msg('gadget-sd-copy'), |
$code = $('<div>', {id: 'settingsDialog-code', html: [ mw.msg('gadget-sd-copy'), |
||
$('<a>', {href: '/zh/special:mypage/common.js', target: '_blank', text: mw.msg('gadget-sd-js')}), |
$('<a>', {href: '/zh/special:mypage/common.js', target: '_blank', text: mw.msg('gadget-sd-js')}), |
||
':', |
':', $block |
||
$('<pre>', {class: 'javascript'}) |
|||
]}), |
]}), |
||
$btns = $('<div>', {id: 'settingsDialog-btns', html: [ |
$btns = $('<div>', {id: 'settingsDialog-btns', html: [ |
||
new OO.ui.ButtonWidget({label: mw.msg('gadget-sd-back'), flags: 'destructive'}) |
new OO.ui.ButtonWidget({label: mw.msg('gadget-sd-back'), flags: 'destructive'}) |
||
.on('click', function() { dialog.clearOptions(); }).$element, |
|||
new OO.ui.ButtonWidget({label: mw.msg('gadget-sd-export'), flags: 'progressive', disabled: !isUser}) |
|||
name = dialog.content.getCurrentTabPanelName(); |
|||
.on('click', function() { |
|||
dialog.clearOptions( name ); |
|||
const $panel = $btns.parent(); |
|||
}).$element, |
|||
$block.text( dialog.export() ); |
|||
new OO.ui.ButtonWidget({label: mw.msg('gadget-sd-export'), flags: 'progressive'}).on('click', function() { |
|||
const dialog = mw.settingsDialog, |
|||
name = dialog.content.getCurrentTabPanelName(), |
|||
$panel = $btns.parent(), |
|||
$block = $code.children( 'pre' ); |
|||
$block.text( dialog.export( name ) ); |
|||
if (window.hljs) { hljs.highlightBlock( $block[0] ); } |
if (window.hljs) { hljs.highlightBlock( $block[0] ); } |
||
$code.show(); |
$code.show(); |
||
$panel.animate({scrollTop: $panel.prop( 'scrollHeight' )}, 'slow'); |
$panel.animate({scrollTop: $panel.prop( 'scrollHeight' )}, 'slow'); |
||
}).$element, |
}).$element, $code |
||
$code |
|||
]}), |
]}), |
||
// 3. 准备私有工具函数 |
|||
buildWidget = function(obj) { // 生成单个OOUI widget |
|||
deleteKeys = function(arr, obj) { arr.forEach(function(ele) { delete obj[ele]; }); }, |
|||
buildWidget = function(obj, settings) { // 生成单个OOUI widget |
|||
obj.widget = new OO.ui[obj.type + 'InputWidget']( $.extend({value: (settings || {})[ obj.key ]}, obj.config) ); |
|||
const layout = new OO.ui.FieldLayout(obj.widget, {label: mw.msg( obj.label ), help: obj.help}); |
const layout = new OO.ui.FieldLayout(obj.widget, {label: mw.msg( obj.label ), help: obj.help}); |
||
['config', 'label', 'help'] |
deleteKeys(['config', 'label', 'help'], obj); |
||
return layout; |
return layout; |
||
}, |
|||
clearWidgets = function(arr, settings) { // 还原一组OOUI widget |
|||
(arr || []).forEach(function(ele) { ele.widget.setValue( settings ? settings[ele.key] || '' : '' ); }); |
|||
}, |
|||
getValues = function(arr) { // 获取一组OOUI widget的值 |
|||
return Object.fromEntries( (arr || []).map(function(ele) { |
|||
return [ele.key, !ele.widget.isDisabled() && ele.widget.getValue()]; |
|||
}).filter(function(ele) { return ele[1]; }) ); |
|||
}, |
}, |
||
buildForm = function(params, $element) { |
buildForm = function(params, $element) { |
||
if (!params.ready) { // 生成表单,只需要执行一次,不用写成SettingsDialog的内置方法 |
if (!params.ready) { // 生成表单,只需要执行一次,不用写成SettingsDialog的内置方法 |
||
const settings = gadgets[ params.name ]; |
|||
(params.items || []).forEach(function(ele) { $element.append( buildWidget(ele).$element ); }); |
|||
(params. |
$element.append( (params.items || []).map(function(ele) { return buildWidget(ele, settings).$element; }) ); |
||
$element.append( (params.fields || []).map(function(ele) { |
|||
const field = new OO.ui.FieldsetLayout({label: mw.msg( ele.label ), help: ele.help, helpInline: true}); |
|||
field. |
const field = new OO.ui.FieldsetLayout({ label: mw.msg( ele.label ), help: ele.help, helpInline: true, |
||
items: (ele.items || []).map(function(e) { return buildWidget(e, settings[ ele.key ]); }) }); |
|||
$element.append( field.$element ); |
|||
deleteKeys(['label', 'help'], ele); |
|||
return field.$element; |
|||
}) ); |
|||
params.ready = true; |
params.ready = true; |
||
mw.hook( 'settings.dialog' ).fire( params ); // 生成一个Hook |
mw.hook( 'settings.dialog' ).fire( params ); // 生成一个Hook |
||
} |
} |
||
// 切换标签时添加帮助和按钮,不用写成SettingsDialog的内置方法 |
// 切换标签时添加帮助和按钮,不用写成SettingsDialog的内置方法 |
||
$helpPage.attr('href', mw.util.getUrl('Help:小工具/' + params.help)); |
$helpPage.attr('href', mw.util.getUrl( 'Help:小工具/' + params.help )); |
||
$element.prepend( $help ).append( $btns ); |
$element.prepend( $help ).append( $btns ); |
||
$code.hide(); |
$code.hide(); |
||
}, |
|||
openDialog = function(e) { |
|||
e.preventDefault(); |
|||
$(document.body).removeClass( 'navigation-enabled primary-navigation-enabled' ); |
|||
dialog.open().opening.then(function() { buildForm(dialog.getObject(), dialog.getPanel().$element); }); |
|||
}; |
}; |
||
// 4. 定义SettingsDialog类 |
|||
function SettingsDialog() { // constructor只添加一个id,剩下的交给addTab方法逐一添加小工具 |
function SettingsDialog() { // constructor只添加一个id,剩下的交给addTab方法逐一添加小工具 |
||
SettingsDialog.super.call(this, {id: 'settingsDialog'}); |
SettingsDialog.super.call(this, {id: 'settingsDialog'}); |
||
第96行: | 第105行: | ||
}; |
}; |
||
SettingsDialog.prototype.getActionProcess = function(action) { |
SettingsDialog.prototype.getActionProcess = function(action) { |
||
const dialog = this, |
const dialog = this, // ES5不允许箭头函数,无法直接使用this关键字 |
||
gadget = this.gadgets.filter(function(ele) { return ele.ready; }); // 忽略未加载的小工具 |
|||
if (action == 'save') { |
if (action == 'save') { gadget.forEach(function(ele) { dialog.saveOptions( ele ); }); } |
||
else { |
else { gadget.forEach(function(ele) { dialog.clearOptions( ele ); }); } |
||
this.close(); |
this.close(); |
||
return new OO.ui.Process(); |
return new OO.ui.Process(); |
||
第117行: | 第126行: | ||
// 添加按钮,注意手机版的执行时机 |
// 添加按钮,注意手机版的执行时机 |
||
if (mw.config.get('skin') == 'minerva') { |
if (mw.config.get('skin') == 'minerva') { |
||
$(mw.addMobileLinks( {icon: 'user-cog', msg: 'gadget-sd-title'} )).click( openDialog ) |
|||
mw.hook( 'mobile.menu' ).add(function($menu) { |
|||
.appendTo( $('#mw-mf-page-left').find('ul:not(.hlist)').last() ); |
|||
console.log('Hook: mobile.menu, 开始添加小工具设置按钮'); |
|||
mw.addMobileLinks([{icon: 'user-cog', msg: 'gadget-sd-title', attr: {id: 'ca-settingsDialog'}}])[0] |
|||
.appendTo( $menu.find('ul:not(.hlist)').last() ); |
|||
}); |
|||
} else { |
|||
mw.util.addPortletLink('p-cactions', '#', mw.msg('gadget-sd-title'), 'ca-settingsDialog', |
|||
mw.msg('gadget-sd-tooltip')); |
|||
} |
} |
||
else { $( mw.util.addPortletLink('p-cactions', '#', mw.msg('gadget-sd-title')) ).click( openDialog ); } |
|||
ready = true; |
ready = true; |
||
}; |
|||
/** |
|||
* @Description: 获取小工具序号 |
|||
* @Param {String} 小工具名称 |
|||
* @Param {Object} 小工具数据 |
|||
* @Return {Number} 小工具序号 |
|||
*/ |
|||
SettingsDialog.prototype.getIndex = function(arg) { |
|||
if (typeof arg == 'string') { return this.gadgets.findIndex(function(ele) { return ele.name == arg; }); } |
|||
else if (typeof arg == 'number') { return arg; } |
|||
else { return this.gadgets.indexOf( arg ); } |
|||
}; |
}; |
||
/** |
/** |
||
* @Description: 获取小工具名称 |
* @Description: 获取小工具名称 |
||
* @Param { |
* @Param {Object} 小工具数据(可选),默认为当前小工具 |
||
* @Param {Object} 小工具数据 |
|||
* @Return {String} 小工具名称 |
* @Return {String} 小工具名称 |
||
*/ |
*/ |
||
SettingsDialog.prototype.getName = function(arg) { |
SettingsDialog.prototype.getName = function(arg) { |
||
return arg ? arg.name || arg : this.content.getCurrentTabPanelName(); |
|||
if (typeof arg == 'string') { return arg; } |
|||
else if (typeof arg == 'number') { return this.gadgets[ arg ].name; } |
|||
else { return arg.name; } |
|||
}; |
}; |
||
/** |
/** |
||
* @Description: 获取小工具数据 |
* @Description: 获取小工具数据 |
||
* @Param {String} 小工具名称 |
* @Param {String} 小工具名称(可选),默认为当前小工具 |
||
* @Param {Number} 小工具序号 |
|||
* @Return {Object} 小工具数据 |
* @Return {Object} 小工具数据 |
||
*/ |
*/ |
||
SettingsDialog.prototype.getObject = function(arg) { |
SettingsDialog.prototype.getObject = function(arg) { |
||
if (typeof arg == ' |
if (typeof arg == 'object') { return arg; } |
||
const name = arg || this.getName(); |
|||
return this.gadgets.find(function(ele) { return ele.name == name; }); |
|||
}; |
}; |
||
/** |
/** |
||
* @Description: |
* @Description: 获取小工具标签页 |
||
* @Param {String} 小工具名称 |
* @Param {String} 小工具名称(可选),默认为当前小工具 |
||
* @Param { |
* @Param {Object} 小工具数据(可选),默认为当前小工具 |
||
* @ |
* @Return {OO.ui.TabPanelLayout} 小工具标签页 |
||
*/ |
*/ |
||
SettingsDialog.prototype. |
SettingsDialog.prototype.getPanel = function(arg) { |
||
return arg ? this.content.getTabPanel( arg.name || arg ) : this.content.getCurrentTabPanel(); |
|||
const name = this.getName(arg), |
|||
}; |
|||
index = this.getIndex(arg); |
|||
/** |
|||
if (index == -1) { |
|||
* @Description: 生成设置对象 |
|||
console.warn( '无法删除不存在的小工具设置!' ); |
|||
* @Param {String} 小工具名称(可选),默认为当前小工具 |
|||
return; |
|||
* @Param {Object} 小工具数据(可选),默认为当前小工具 |
|||
} |
|||
* @Param {Boolean} 是否用于导出 |
|||
// 需要同时移除数据和对应的HTML元素 |
|||
* @Return {Object} 小工具設置 |
|||
this.gadgets.splice(index, 1); |
|||
*/ |
|||
this.content.removeTabPanels( this.content.getTabPanel( name ) ); |
|||
SettingsDialog.prototype.generateOptions = function(arg, flag) { |
|||
const gadget = this.getObject(arg); |
|||
return $.extend( getValues( gadget.items ), Object.fromEntries( (gadget.fields || []).map(function(ele) { |
|||
const obj = getValues( ele.items ); |
|||
return [ele.key, flag && $.isEmptyObject( obj ) ? undefined : obj]; |
|||
}) ) ); |
|||
}; |
}; |
||
/** |
/** |
||
* @Description: 保存设置 |
* @Description: 保存设置 |
||
* @Param {String} 小工具名称 |
* @Param {String} 小工具名称(可选),默认为当前小工具 |
||
* @Param { |
* @Param {Object} 小工具数据(可选),默认为当前小工具 |
||
* @Param {Object} 小工具数据 |
|||
*/ |
*/ |
||
SettingsDialog.prototype.saveOptions = function(arg) { |
SettingsDialog.prototype.saveOptions = function(arg) { |
||
const |
const name = this.getName(arg), |
||
settings = this.generateOptions( name ); |
|||
gadgets[ name ] = settings; |
|||
if (gadget.saveOptions) { settings = gadget.saveOptions(); } |
|||
else { settings = this.standardSaveOptions( gadget ); } |
|||
mw.gadgets[ name ] = settings; |
|||
mw.storage.setObject('gadget-' + name, settings); |
mw.storage.setObject('gadget-' + name, settings); |
||
mw.notify(mw.msg( 'gadget-sd-notify' ), {type: 'success', tag: 'gadget-settings'}); |
mw.notify(mw.msg( 'gadget-sd-notify' ), {type: 'success', tag: 'gadget-settings'}); |
||
}; |
|||
/** |
|||
* @Description: 默认的saveOptions函数 |
|||
* @Param {String} 小工具名称 |
|||
* @Param {Number} 小工具序号 |
|||
* @Param {Object} 小工具数据 |
|||
* @Return {Object} 小工具設置 |
|||
*/ |
|||
SettingsDialog.prototype.standardSaveOptions = function(arg) { |
|||
const gadget = this.getObject(arg), |
|||
settings = {}; |
|||
(gadget.items || []).filter(function(ele) { return !ele.widget.isDisabled(); }) |
|||
.forEach(function(ele) { settings[ ele.key ] = ele.widget.getValue() || undefined; }); |
|||
(gadget.fields || []).forEach(function(ele) { |
|||
settings[ ele.key ] = settings[ ele.key ] || {}; |
|||
const obj = settings[ ele.key ]; // 已经是一个对象了 |
|||
ele.items.filter(function(e) { return !e.widget.isDisabled(); }) |
|||
.forEach(function(e) { obj[ e.key ] = e.widget.getValue() || undefined; }); |
|||
}); |
|||
return settings; |
|||
}; |
}; |
||
/** |
/** |
||
* @Description: 还原选项 |
* @Description: 还原选项 |
||
* @Param {String} 小工具名称 |
* @Param {String} 小工具名称(可选),默认为当前小工具 |
||
* @Param { |
* @Param {Object} 小工具数据(可选),默认为当前小工具 |
||
* @Param {Object} 小工具数据 |
|||
*/ |
*/ |
||
SettingsDialog.prototype.clearOptions = function(arg) { |
SettingsDialog.prototype.clearOptions = function(arg) { |
||
const gadget = this.getObject(arg); |
|||
if (gadget.clearOptions) { gadget.clearOptions(); } |
|||
else { this.standardClearOptions( gadget ); } |
|||
}; |
|||
/** |
|||
* @Description: 默认的clearOptions函数 |
|||
* @Param {String} 小工具名称 |
|||
* @Param {Number} 小工具序号 |
|||
* @Param {Object} 小工具数据 |
|||
*/ |
|||
SettingsDialog.prototype.standardClearOptions = function(arg) { |
|||
const gadget = this.getObject(arg), |
const gadget = this.getObject(arg), |
||
settings = gadgets[ gadget.name ]; |
|||
clearWidgets(gadget.items, settings); |
|||
(gadget. |
(gadget.fields || []).forEach(function(ele) { clearWidgets(ele.items, settings[ ele.key ]); }); |
||
(gadget.fields || []).forEach(function(ele) { |
|||
const obj = settings[ ele.key ] || {}; |
|||
ele.items.forEach(function(e) { e.widget.setValue( obj[ e.key ] ); }); |
|||
}); |
|||
}; |
}; |
||
/** |
/** |
||
* @Description: 导出JS格式的设置 |
* @Description: 导出JS格式的设置 |
||
* @Param {String} 小工具名称 |
* @Param {String} 小工具名称(可选),默认为当前小工具 |
||
* @Param {Number} 小工具序号 |
|||
* @Param {Object} 小工具数据 |
|||
* @Return {String} JS格式的设置 |
* @Return {String} JS格式的设置 |
||
*/ |
*/ |
||
SettingsDialog.prototype.export = function( |
SettingsDialog.prototype.export = function(name) { |
||
name = name || this.getName(); |
|||
return 'mw.gadgets = $.extend(mw.gadgets, {' + name + ': ' + |
|||
if (gadget.export) { return gadget.export(); } |
|||
JSON.stringify( this.generateOptions(name, true), null, '\t' ) + ' });'; |
|||
}; |
|||
/** |
|||
* @Description: 默认的export函数 |
|||
* @Param {String} 小工具名称 |
|||
* @Param {Number} 小工具序号 |
|||
* @Param {Object} 小工具数据 |
|||
* @Return {String} JS格式的设置 |
|||
*/ |
|||
SettingsDialog.prototype.standardExport = function(arg) { |
|||
const name = this.getName(arg), |
|||
settings = this.standardSaveOptions(arg); |
|||
return 'mw.gadgets = $.extend(mw.gadgets, {' + name + ': ' + JSON.stringify( settings ) + ' });'; |
|||
}; |
}; |
||
SettingsDialog.static = {name: 'settingsDialog', tagName: 'div', title: mw.msg('gadget-sd-title'), escapable: true, |
SettingsDialog.static = {name: 'settingsDialog', tagName: 'div', title: mw.msg('gadget-sd-title'), escapable: true, |
||
第269行: | 第210行: | ||
{action: 'cancel', label: mw.msg('ooui-dialog-message-reject'), flags: 'safe'}] |
{action: 'cancel', label: mw.msg('ooui-dialog-message-reject'), flags: 'safe'}] |
||
}; |
}; |
||
// 5. 生成SettingsDialog并保存为全局对象 |
|||
dialog = new SettingsDialog(); |
|||
const $body = $(document.body); |
|||
const manager = new OO.ui.WindowManager(); |
|||
if (!mw.windowManager) { |
|||
manager.$element.appendTo( document.body ); |
|||
mw.windowManager = mw.windowmanager || new OO.ui.WindowManager(); |
|||
manager.addWindows( [dialog] ); // 此时已经初始化 |
|||
mw.windowManager.$element.appendTo( $body ); |
|||
mw.settingsDialog = dialog; // 创造一个全局对象 |
|||
} |
|||
mw.windowManager.addWindows( [mw.settingsDialog] ); // 此时已经初始化 |
|||
$body.on('click', '#ca-settingsDialog', function(e) { |
|||
e.preventDefault(); |
|||
const dialog = mw.settingsDialog, |
|||
content = dialog.content, |
|||
name = content.getCurrentTabPanelName(), |
|||
$element = content.getCurrentTabPanel().$element, |
|||
params = dialog.getObject( name ); |
|||
dialog.open().opening.then(function() { buildForm(params, $element); }); |
|||
}); |
|||
//</nowiki> |
//</nowiki> |
||
// [[category:作为模块的小工具]] [[category:桌面版小工具]] [[category:手机版小工具]] [[category:系统工具]] |
// [[category:作为模块的小工具]] [[category:桌面版小工具]] [[category:手机版小工具]] [[category:系统工具]] |
2023年3月17日 (五) 13:20的最新版本
//<nowiki> // 由ResourceLoader直接调用,不可使用ES6语法 /** * @Function: 定义小工具设置对话框 * @Methods: getName: 获取小工具名称 * getObject: 获取小工具对象 * getPanel: 获取小工具标签页 * addTab: 添加小工具 * generateOptions: 生成设置对象 * saveOptions: 将设置保存到localStorage * clearOptions: 还原设置 * export: 导出设置 * @Dependencies: mediawiki.util, mediawiki.storage, oojs-ui-windows, oojs-ui-widgets, ext.gadget.site-lib, user * @Author: [[User:Bhsd]] */ "use strict"; /* global OO, hljs, wgULS */ mw.gadgets = mw.gadgets || {}; // 1. 设置繁简文字信息 mw.messages.set( wgULS({ 'gadget-sd-copy': '请将以下代码添加至您的', 'gadget-sd-notify': '您的设置已保存!新设置将于刷新页面后生效。', 'gadget-sd-help': '您可以在这里修改小工具偏好,修改仅对当前浏览器有效。如果想要修改设置对所有浏览器生效,请查阅', 'gadget-sd-helptext': '帮助页面', 'gadget-sd-exporthelp': '导出代码', 'gadget-sd-js': '用户JS', 'gadget-sd-title': '小工具设置', 'gadget-sd-back': '还原', 'gadget-sd-save': '保存', 'gadget-sd-export': '导出' }, { 'gadget-sd-copy': '請將以下代碼添加至您的', 'gadget-sd-notify': '您的偏好設定已儲存!新設定將於重新載入頁面後生效。', 'gadget-sd-help': '您可以在這裡修改小工具偏好,修改僅對當前瀏覽器有效。如果想要修改設定對所有瀏覽器生效,請查閱', 'gadget-sd-helptext': '說明頁面', 'gadget-sd-exporthelp': '導出代碼', 'gadget-sd-js': '使用者JS', 'gadget-sd-title': '小工具偏好設定', 'gadget-sd-back': '復原', 'gadget-sd-save': '儲存', 'gadget-sd-export': '導出' }) ); // 2. 准备HTML元素 var ready = false, dialog; // 是否是第一次打开对话框 const isUser = mw.config.get( 'wgUserGroups' ).includes( 'user' ), gadgets = mw.gadgets, $helpPage = $('<a>', {target: '_blank', text: mw.msg('gadget-sd-helptext')}), // 需要动态设置href $help = $('<div>', {html: [ mw.msg('gadget-sd-help'), $helpPage, ',或', $('<a>', {href: '#settingsDialog-btns', text: mw.msg('gadget-sd-exporthelp')}), '。' // 链接跳转到“导出”按钮 ]}), $block = $('<pre>', {class: 'javascript'}), $code = $('<div>', {id: 'settingsDialog-code', html: [ mw.msg('gadget-sd-copy'), $('<a>', {href: '/zh/special:mypage/common.js', target: '_blank', text: mw.msg('gadget-sd-js')}), ':', $block ]}), $btns = $('<div>', {id: 'settingsDialog-btns', html: [ new OO.ui.ButtonWidget({label: mw.msg('gadget-sd-back'), flags: 'destructive'}) .on('click', function() { dialog.clearOptions(); }).$element, new OO.ui.ButtonWidget({label: mw.msg('gadget-sd-export'), flags: 'progressive', disabled: !isUser}) .on('click', function() { const $panel = $btns.parent(); $block.text( dialog.export() ); if (window.hljs) { hljs.highlightBlock( $block[0] ); } $code.show(); $panel.animate({scrollTop: $panel.prop( 'scrollHeight' )}, 'slow'); }).$element, $code ]}), // 3. 准备私有工具函数 deleteKeys = function(arr, obj) { arr.forEach(function(ele) { delete obj[ele]; }); }, buildWidget = function(obj, settings) { // 生成单个OOUI widget obj.widget = new OO.ui[obj.type + 'InputWidget']( $.extend({value: (settings || {})[ obj.key ]}, obj.config) ); const layout = new OO.ui.FieldLayout(obj.widget, {label: mw.msg( obj.label ), help: obj.help}); deleteKeys(['config', 'label', 'help'], obj); return layout; }, clearWidgets = function(arr, settings) { // 还原一组OOUI widget (arr || []).forEach(function(ele) { ele.widget.setValue( settings ? settings[ele.key] || '' : '' ); }); }, getValues = function(arr) { // 获取一组OOUI widget的值 return Object.fromEntries( (arr || []).map(function(ele) { return [ele.key, !ele.widget.isDisabled() && ele.widget.getValue()]; }).filter(function(ele) { return ele[1]; }) ); }, buildForm = function(params, $element) { if (!params.ready) { // 生成表单,只需要执行一次,不用写成SettingsDialog的内置方法 const settings = gadgets[ params.name ]; $element.append( (params.items || []).map(function(ele) { return buildWidget(ele, settings).$element; }) ); $element.append( (params.fields || []).map(function(ele) { const field = new OO.ui.FieldsetLayout({ label: mw.msg( ele.label ), help: ele.help, helpInline: true, items: (ele.items || []).map(function(e) { return buildWidget(e, settings[ ele.key ]); }) }); deleteKeys(['label', 'help'], ele); return field.$element; }) ); params.ready = true; mw.hook( 'settings.dialog' ).fire( params ); // 生成一个Hook } // 切换标签时添加帮助和按钮,不用写成SettingsDialog的内置方法 $helpPage.attr('href', mw.util.getUrl( 'Help:小工具/' + params.help )); $element.prepend( $help ).append( $btns ); $code.hide(); }, openDialog = function(e) { e.preventDefault(); $(document.body).removeClass( 'navigation-enabled primary-navigation-enabled' ); dialog.open().opening.then(function() { buildForm(dialog.getObject(), dialog.getPanel().$element); }); }; // 4. 定义SettingsDialog类 function SettingsDialog() { // constructor只添加一个id,剩下的交给addTab方法逐一添加小工具 SettingsDialog.super.call(this, {id: 'settingsDialog'}); this.gadgets = []; } OO.inheritClass(SettingsDialog, OO.ui.ProcessDialog); SettingsDialog.prototype.initialize = function() { // 只创建一个OO.ui.IndexLayout对象,剩下的交给addTab方法填入内容 SettingsDialog.super.prototype.initialize.apply(this, arguments); this.content = new OO.ui.IndexLayout(); this.$body.append( this.content.$element ); }; SettingsDialog.prototype.getActionProcess = function(action) { const dialog = this, // ES5不允许箭头函数,无法直接使用this关键字 gadget = this.gadgets.filter(function(ele) { return ele.ready; }); // 忽略未加载的小工具 if (action == 'save') { gadget.forEach(function(ele) { dialog.saveOptions( ele ); }); } else { gadget.forEach(function(ele) { dialog.clearOptions( ele ); }); } this.close(); return new OO.ui.Process(); }; /** * @Description: 同时添加数据和HTML,其中HTML会延后 * @Param {Object} 数据对象 */ SettingsDialog.prototype.addTab = function(params) { const panel = new OO.ui.TabPanelLayout( params.name, {label: mw.msg( params.label )} ); delete params.label; this.content.addTabPanels( [panel] ); this.gadgets.push( params ); // 必要时才开始加载表单 panel.on('active', function() { buildForm(params, panel.$element); }); if (ready) { return; } // 添加按钮,注意手机版的执行时机 if (mw.config.get('skin') == 'minerva') { $(mw.addMobileLinks( {icon: 'user-cog', msg: 'gadget-sd-title'} )).click( openDialog ) .appendTo( $('#mw-mf-page-left').find('ul:not(.hlist)').last() ); } else { $( mw.util.addPortletLink('p-cactions', '#', mw.msg('gadget-sd-title')) ).click( openDialog ); } ready = true; }; /** * @Description: 获取小工具名称 * @Param {Object} 小工具数据(可选),默认为当前小工具 * @Return {String} 小工具名称 */ SettingsDialog.prototype.getName = function(arg) { return arg ? arg.name || arg : this.content.getCurrentTabPanelName(); }; /** * @Description: 获取小工具数据 * @Param {String} 小工具名称(可选),默认为当前小工具 * @Return {Object} 小工具数据 */ SettingsDialog.prototype.getObject = function(arg) { if (typeof arg == 'object') { return arg; } const name = arg || this.getName(); return this.gadgets.find(function(ele) { return ele.name == name; }); }; /** * @Description: 获取小工具标签页 * @Param {String} 小工具名称(可选),默认为当前小工具 * @Param {Object} 小工具数据(可选),默认为当前小工具 * @Return {OO.ui.TabPanelLayout} 小工具标签页 */ SettingsDialog.prototype.getPanel = function(arg) { return arg ? this.content.getTabPanel( arg.name || arg ) : this.content.getCurrentTabPanel(); }; /** * @Description: 生成设置对象 * @Param {String} 小工具名称(可选),默认为当前小工具 * @Param {Object} 小工具数据(可选),默认为当前小工具 * @Param {Boolean} 是否用于导出 * @Return {Object} 小工具設置 */ SettingsDialog.prototype.generateOptions = function(arg, flag) { const gadget = this.getObject(arg); return $.extend( getValues( gadget.items ), Object.fromEntries( (gadget.fields || []).map(function(ele) { const obj = getValues( ele.items ); return [ele.key, flag && $.isEmptyObject( obj ) ? undefined : obj]; }) ) ); }; /** * @Description: 保存设置 * @Param {String} 小工具名称(可选),默认为当前小工具 * @Param {Object} 小工具数据(可选),默认为当前小工具 */ SettingsDialog.prototype.saveOptions = function(arg) { const name = this.getName(arg), settings = this.generateOptions( name ); gadgets[ name ] = settings; mw.storage.setObject('gadget-' + name, settings); mw.notify(mw.msg( 'gadget-sd-notify' ), {type: 'success', tag: 'gadget-settings'}); }; /** * @Description: 还原选项 * @Param {String} 小工具名称(可选),默认为当前小工具 * @Param {Object} 小工具数据(可选),默认为当前小工具 */ SettingsDialog.prototype.clearOptions = function(arg) { const gadget = this.getObject(arg), settings = gadgets[ gadget.name ]; clearWidgets(gadget.items, settings); (gadget.fields || []).forEach(function(ele) { clearWidgets(ele.items, settings[ ele.key ]); }); }; /** * @Description: 导出JS格式的设置 * @Param {String} 小工具名称(可选),默认为当前小工具 * @Return {String} JS格式的设置 */ SettingsDialog.prototype.export = function(name) { name = name || this.getName(); return 'mw.gadgets = $.extend(mw.gadgets, {' + name + ': ' + JSON.stringify( this.generateOptions(name, true), null, '\t' ) + ' });'; }; SettingsDialog.static = {name: 'settingsDialog', tagName: 'div', title: mw.msg('gadget-sd-title'), escapable: true, actions: [{action: 'save', label: mw.msg('gadget-sd-save'), flags: ['primary', 'progressive']}, {action: 'cancel', label: mw.msg('ooui-dialog-message-reject'), flags: 'safe'}] }; // 5. 生成SettingsDialog并保存为全局对象 dialog = new SettingsDialog(); const manager = new OO.ui.WindowManager(); manager.$element.appendTo( document.body ); manager.addWindows( [dialog] ); // 此时已经初始化 mw.settingsDialog = dialog; // 创造一个全局对象 //</nowiki> // [[category:作为模块的小工具]] [[category:桌面版小工具]] [[category:手机版小工具]] [[category:系统工具]] // {{DEFAULTSORT:SettingsDialog.js}}