跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
分类索引
最近更改
随机页面
灵兰秘典
帮助
帮助
联系我们
捐助本站
关于本站
MediaWiki帮助
中医百科
搜索
搜索
外观
登录
个人工具
登录
查看“︁MediaWiki:Gadget-MoreMenu.js”︁的源代码
系统消息
讨论
English
阅读
查看源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
查看源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
Cargo数据
外观
移至侧栏
隐藏
←
MediaWiki:Gadget-MoreMenu.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
/** * MoreMenu gadget for test.zybkcn.com * Loader: ResourceLoader * Dependencies: mediawiki.api, mediawiki.util, mediawiki.Title, mediawiki.user, mediawiki.storage, user.options */ /** * WARNING: GLOBAL GADGET FILE * MoreMenu — 为 MediaWiki 添加 Page/User 下拉菜单 * * Version: 5.2.2 (merged single-file for test.zybkcn.com) * Author: MusikAnimal * License: MIT * GitHub: https://github.com/wikimedia-gadgets/MoreMenu * Skins: Vector, Timeless, Monobook, Modern * * 本文件合并自: * - MoreMenu.js (主引擎) * - MoreMenu.messages.en.js → 内置简繁中文翻译 * - MoreMenu.page.js (精简版,仅保留本站链接) * - MoreMenu.user.js (精简版,仅保留本站链接) **/ "use strict"; (function () { var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (o) { return typeof o; } : function (o) { return o && typeof Symbol === "function" && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }; /** * 内置翻译表:中文(简繁) * 根据 wgUserLanguage 自动选择 */ var translations = (function () { var lang = mw.config.get('wgUserLanguage') || 'zh'; // 检测是否繁体 var isHant = /hant|tw|hk|mo/i.test(lang); // 简繁对照表 var strings = { page: ['页面', '頁面'], user: ['用户', '用戶'], 'page-logs': ['页面日志', '頁面日誌'], 'user-logs': ['用户日志', '用戶日誌'], 'all-logs': ['所有日志', '所有日誌'], 'abusefilter-log': ['滥用过滤器日志', '濫用過濾器日誌'], 'deletion-log': ['删除日志', '刪除日誌'], 'move-log': ['移动日志', '移動日誌'], 'protection-log': ['保护日志', '保護日誌'], 'spam-blacklist-log': ['垃圾链接黑名单日志', '垃圾連結黑名單日誌'], 'block-log': ['封禁日志', '封禁日誌'], 'checkuser-log': ['用户查核日志', '用戶查核日誌'], 'global-account-log': ['全域账号日志', '全域帳號日誌'], 'global-block-log': ['全域封禁日志', '全域封禁日誌'], 'mass-message-log': ['大量消息日志', '大量訊息日誌'], 'rename-log': ['重命名日志', '重新命名日誌'], 'review-log': ['审核日志', '審核日誌'], 'suppression-log': ['监督日志', '監督日誌'], 'thanks-log': ['感谢日志', '感謝日誌'], 'upload-log': ['上传日志', '上傳日誌'], 'user-creation-log': ['用户创建日志', '用戶建立日誌'], 'user-rights-log': ['用户权限日志', '用戶權限日誌'], 'blocks': ['封禁', '封禁'], 'block-user': ['封禁用户', '封禁用戶'], 'change-block': ['更改封禁', '變更封禁'], 'unblock-user': ['解除封禁', '解除封禁'], 'view-block': ['查看封禁', '檢視封禁'], 'view-block-log': ['查看封禁日志', '檢視封禁日誌'], 'analysis': ['分析', '分析'], 'basic-statistics': ['基本信息', '基本資訊'], 'transclusions': ['嵌入情况', '嵌入情況'], 'search': ['搜索', '搜尋'], 'latest-diff': ['最新差异', '最新差異'], 'search-subpages': ['搜索子页面', '搜尋子頁面'], 'delete-page': ['删除', '刪除'], 'undelete-page': ['恢复', '還原'], 'move-page': ['移动', '移動'], 'protect-page': ['保护', '保護'], 'change-protection': ['更改保护', '變更保護'], 'purge-cache': ['清除缓存', '清除快取'], 'subpages': ['子页面', '子頁面'], 'edit-intro': ['编辑导言', '編輯導言'], 'history': ['历史', '歷史'], 'watch': ['监视', '監視'], 'merge-page': ['合并', '合併'], 'change-model': ['更改内容模型', '變更內容模型'], 'contributions': ['贡献', '貢獻'], 'deleted-contributions': ['已删除贡献', '已刪除貢獻'], 'suppressed-contribs': ['被监督的贡献', '被監督的貢獻'], 'email-user': ['电邮用户', '電郵用戶'], 'change-rights': ['更改用户权限', '變更用戶權限'], 'checkuser': ['用户查核', '用戶查核'], 'uploads': ['上传记录', '上傳記錄'], 'user-groups': ['用户组', '用戶組'], 'sul': ['全域账户', '全域帳戶'], 'user-thanks-received': ['收到的感谢', '收到的感謝'], 'tools': ['工具', '工具'] }; var result = {}; Object.keys(strings).forEach(function (key) { result[key] = isHant ? strings[key][1] : strings[key][0]; }); return result; })(); /** ============================================================ * 页面菜单定义 (MoreMenu.page) — 精简版 * ============================================================ */ var pageMenu = function (config) { return { page: (function () { var items = {}; // page-logs 子菜单 items['page-logs'] = { 'all-logs': { url: mw.util.getUrl('Special:Log', { page: config.page.name }), insertAfter: false }, 'abusefilter-log': { url: mw.util.getUrl('Special:AbuseLog', { wpSearchTitle: config.page.name }) }, 'deletion-log': { url: mw.util.getUrl('Special:Log', { page: config.page.name, type: 'delete' }) }, 'move-log': { url: mw.util.getUrl('Special:Log', { page: config.page.name, type: 'move' }) }, 'protection-log': { url: mw.util.getUrl('Special:Log', { page: config.page.name, type: 'protect' }) }, 'spam-blacklist-log': { url: mw.util.getUrl('Special:Log', { page: config.page.name, type: 'spamblacklist' }) } }; // analysis 子菜单 — 仅保留本站链接 items['analysis'] = { 'basic-statistics': { url: mw.util.getUrl(config.page.name, { action: 'info' }), pageExists: true, insertAfter: false }, 'transclusions': { url: 'https://' + config.project.domain + '/w/index.php?title=Special:WhatLinksHere/' + config.page.encodedName + '&hidelinks=1&hideredirs=1', namespaceRestrict: [2, 4, 5, 10, 11, 12, 13, 100, 101] } }; // search 子菜单 — 仅保留本站链接 items['search'] = { 'latest-diff': { url: mw.util.getUrl(config.page.name, { diff: 'cur', oldid: 'prev' }), pageExists: true, insertAfter: false }, 'search-subpages': { url: mw.util.getUrl('Special:Search', { sort: 'relevance', prefix: config.page.name }) } }; // 操作项 items['change-model'] = { url: mw.util.getUrl('Special:ChangeContentModel/' + config.page.name), currentUserRights: ['editcontentmodel'], pageExists: true, namespaceRestrict: [2, 4, 8, 100, 108, 828] }; items['delete-page'] = { url: mw.util.getUrl(config.page.name, { action: 'delete', wpReason: (function () { try { return decodeURIComponent($('#delete-reason').text()).replace(/\+/g, ' '); } catch (e) { return undefined; } })() }), currentUserRights: ['delete'], pageExists: true, visible: !mw.config.get('wgIsMainPage') }; items['edit-intro'] = { url: '//' + config.project.domain + '/w/index.php?title=' + config.page.encodedName + '&action=edit§ion=0', namespaceRestrict: [0, 1, 2, 3, 4, 5, 118], pageExists: true, visible: mw.user.options.get('gadget-edittop') !== '1' && $('.mw-editsection').length }; // Monobook/Modern 历史占位符 items['history'] = { url: '#', visible: ['monobook', 'modern'].indexOf(config.currentUser.skin) !== -1 }; items['merge-page'] = { url: mw.util.getUrl('Special:MergeHistory', { target: config.page.name }), currentUserRights: ['mergehistory'], pageExists: true, visible: !mw.config.get('wgIsMainPage') }; items['move-page'] = { url: mw.util.getUrl('Special:MovePage/' + config.page.name), currentUserRights: ['move'], pageExists: true, pageMovable: true }; // 保护/更改保护(动态 key) items[config.page.protected ? 'change-protection' : 'protect-page'] = { url: mw.util.getUrl(config.page.name, { action: 'protect' }), currentUserRights: ['protect', 'stablesettings'] }; items['purge-cache'] = { url: mw.util.getUrl(config.page.name, { action: 'purge', forcelinkupdate: true }), pageExists: true }; items['subpages'] = { url: mw.util.getUrl('Special:PrefixIndex/' + config.page.name + '/') }; items['undelete-page'] = { url: mw.util.getUrl('Special:Undelete/' + config.page.name), currentUserRights: ['undelete'], pageDeleted: true }; // Monobook/Modern 监视占位符 items['watch'] = { url: '#', visible: ['monobook', 'modern'].indexOf(config.currentUser.skin) !== -1 }; return items; })() }; }; /** ============================================================ * 用户菜单定义 (MoreMenu.user) — 精简版 * ============================================================ */ var userMenu = function (config) { return { user: (function () { var items = {}; // user-logs 子菜单 items['user-logs'] = { 'all-logs': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name }), insertAfter: false }, 'abusefilter-log': { url: mw.util.getUrl('Special:AbuseLog', { wpSearchUser: config.targetUser.name }) }, 'block-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'block' }), targetUserRights: ['block'] }, 'checkuser-log': { url: mw.util.getUrl('Special:CheckUserLog', { cuSearch: config.targetUser.name, cuSearchType: 'initiator' }), targetUserRights: ['checkuser-log'], currentUserRights: ['checkuser-log'] }, 'deletion-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'delete' }), targetUserRights: ['delete'] }, 'global-account-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'globalauth' }), targetUserRights: ['centralauth-lock'] }, 'global-block-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'gblblock' }), targetUserRights: ['globalblock'] }, 'mass-message-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'massmessage' }), targetUserRights: ['massmessage'] }, 'move-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'move' }), targetUserRights: ['move'] }, 'protection-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'protect' }), targetUserRights: ['protect'] }, 'spam-blacklist-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'spamblacklist' }) }, 'suppression-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'suppress' }), targetUserRights: ['suppressrevision'], currentUserRights: ['suppressionlog'] }, 'thanks-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'thanks' }), targetUserGroups: ['user'] }, 'upload-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'upload' }), targetUserRights: ['upload'] }, 'user-creation-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'newusers' }), targetUserGroups: ['user'] }, 'user-rights-log': { url: mw.util.getUrl('Special:Log', { user: config.targetUser.name, type: 'rights' }), targetUserChangeGroups: true } }; // blocks 子菜单 — 删除了 block-globally 和 central-auth items['blocks'] = { 'block-user': { url: mw.util.getUrl('Special:Block/' + config.targetUser.name), currentUserRights: 'block', targetUserBlocked: false }, 'change-block': { url: mw.util.getUrl('Special:Block/' + config.targetUser.name), currentUserRights: 'block', targetUserBlocked: true }, 'unblock-user': { url: mw.util.getUrl('Special:Unblock/' + config.targetUser.name), targetUserBlocked: true, currentUserRights: 'block' }, 'view-block': { url: mw.util.getUrl('Special:BlockList', { wpTarget: config.targetUser.name }), targetUserBlocked: true, style: 'color:#EE1111' }, 'view-block-log': { url: mw.util.getUrl('Special:Log', { page: config.targetUser.name, type: 'block' }) } }; // analysis 子菜单 — 仅保留 SUL items['analysis'] = { 'sul': { url: mw.util.getUrl('Special:CentralAuth/' + config.targetUser.name), targetUserGroups: ['user'], insertAfter: false } }; // 操作项 items['change-rights'] = { url: mw.util.getUrl('Special:UserRights', { user: 'User:' + config.targetUser.name }), targetUserGroups: ['user'], currentUserChangeGroups: true }; items['checkuser'] = { url: mw.util.getUrl('Special:CheckUser/' + config.targetUser.name), currentUserRights: ['checkuser'] }; items['contributions'] = { url: mw.util.getUrl('Special:Contributions/' + config.targetUser.name) }; items['deleted-contributions'] = { url: mw.util.getUrl('Special:DeletedContributions/' + config.targetUser.name), currentUserRights: ['deletedhistory', 'deletedtext'], insertAfter: 'contributions' }; items['suppressed-contribs'] = { url: mw.util.getUrl('Special:Log/suppress', { offender: config.targetUser.name }), currentUserRights: ['suppressionlog'], insertAfter: 'deleted-contributions' }; items['email-user'] = { url: mw.util.getUrl('Special:EmailUser/' + config.targetUser.name), targetUserGroups: ['user'], visible: undefined !== config.targetUser.emailable }; items['uploads'] = { url: mw.util.getUrl('Special:ListFiles', { user: config.targetUser.name, ilshowall: '1' }), targetUserGroups: ['user'] }; items['user-groups'] = { url: mw.util.getUrl('Special:ListUsers', { limit: 1, username: config.targetUser.name }), targetUserGroups: ['user'] }; items['user-thanks-received'] = { url: mw.util.getUrl('Special:Log', { user: '', page: 'User:' + config.targetUser.name, type: 'thanks' }), targetUserGroups: ['user'] }; return items; })() }; }; /** ============================================================ * MoreMenu 主引擎 * ============================================================ */ $(function () { window.MoreMenu = window.MoreMenu || {}; window.MoreMenu.messages = translations; // 注入内置翻译 if (window.moreMenuDebug) { console.info('[MoreMenu] Debugging enabled.'); } var api = new mw.Api(); var ignoreI18nWarnings = false; var isRtl = $('html').prop('dir') === 'rtl'; var leftKey = isRtl ? 'right' : 'left'; var rightKey = isRtl ? 'left' : 'right'; /** 配置对象 */ var config = new function () { this.project = { domain: mw.config.get('wgServerName'), siteName: mw.config.get('wgSiteName'), dbName: mw.config.get('wgDBname'), noticeProject: mw.config.get('wgNoticeProject'), contentLanguage: mw.config.get('wgContentLanguage') }; this.page = { name: mw.config.get('wgPageName'), nsId: mw.config.get('wgNamespaceNumber'), protected: !!mw.config.get('wgRestrictionEdit') && mw.config.get('wgRestrictionEdit').length || !!mw.config.get('wgRestrictionCreate') && mw.config.get('wgRestrictionCreate').length, id: mw.config.get('wgArticleId'), movable: !mw.config.get('wgIsMainPage') && !!$('#ca-move').length }; // 特殊页面处理 if (this.page.nsId === -1 && mw.config.get('wgRelevantPageName') && this.page.name !== mw.config.get('wgRelevantPageName')) { this.page.name = mw.config.get('wgRelevantPageName'); this.page.id = mw.config.get('wgRelevantArticleId'); this.page.nsId = mw.Title.newFromText(this.page.name).namespace; } this.page.escapedName = this.page.name.replace(/[?!'"()*]/g, escape); this.page.encodedName = encodeURIComponent(this.page.name); this.currentUser = { skin: mw.config.get('skin'), groups: mw.config.get('wgUserGroups'), groupsData: {}, rights: [] }; this.targetUser = { name: mw.config.get('wgRelevantUserName') || '', groups: [], rights: [], blocked: false, ipRange: false }; // IP 范围处理 if (!this.targetUser.name && mw.config.get('wgCanonicalSpecialPageName') === 'Contributions' && !$('.mw-userpage-userdoesnotexist')[0]) { this.targetUser.name = mw.config.get('wgTitle').split('/').slice(1).join('/'); this.targetUser.ipRange = true; this.targetUser.ipv4Range = mw.util.isIPv4Address(this.targetUser.name.split('/')[0]); } this.targetUser.escapedName = this.targetUser.name.replace(/[?!'"()*]/g, escape); this.targetUser.encodedName = encodeURIComponent(this.targetUser.name); }(); function log(message, level) { level = level || 'debug'; if (!(window.moreMenuDebug || level !== 'debug')) return; message = '[MoreMenu] ' + message; if (['warn', 'error'].indexOf(level) >= 0) { message += '\nSee https://w.wiki/9Se for documentation.'; } console[level](message); } function msg(key, ignore) { var translation = translations[key]; if (!translation && !ignore && !ignoreI18nWarnings) { log('Missing translation for "' + key + '"', 'warn'); } return translation || key; } function msgExists(key) { return translations[key] !== undefined; } function normalizeId(id) { return id.toLowerCase().replace(/\s+/g, '-'); } function getItemId(parentKey, itemKey, submenuKey) { return 'mm-' + normalizeId(parentKey) + (submenuKey ? '-' + normalizeId(submenuKey) : '') + (typeof itemKey === 'string' ? '-' + normalizeId(itemKey) : ''); } /** 翻译已内置,直接 resolve */ function loadTranslations() { return $.Deferred().resolve(); } function canAddRemoveGroups(groups, rights) { if (rights && rights.indexOf('userrights') >= 0) return true; var valid = groups.some(function (group) { return config.currentUser.groupsData[group] && config.currentUser.groupsData[group].canAddRemoveGroups; }); if (!valid) mw.storage.remove('metaUserGroups'); return valid; } function hasConditional(permitted, given) { permitted = $.makeArray(permitted); given = $.makeArray(given); if (!permitted.length) return true; if (!given.length) return false; return given.some(function (item) { return permitted.indexOf(item) >= 0; }); } function getItemHtml(parentKey, itemKey, itemData, submenuKey) { var namespaceExclusion = itemData.namespaceExclude ? !hasConditional(itemData.namespaceExclude, config.page.nsId) : true; var databaseExclusion = itemData.databaseExclude ? !hasConditional(itemData.databaseExclude, config.page.dbName) : true; var conditions = { noticeProject: hasConditional(itemData.noticeProjectRestrict, config.project.noticeProject), database: hasConditional(itemData.databaseRestrict, config.project.dbName) && databaseExclusion, namespaceRestrict: hasConditional(itemData.namespaceRestrict, config.page.nsId) && namespaceExclusion, pageExists: itemData.pageExists && config.page.id > 0 || !itemData.pageExists, pageDeleted: itemData.pageDeleted ? !config.page.id : true, pageProtected: itemData.pageProtected ? config.page.protected : true, pageMovable: itemData.pageMovable ? config.page.movable : true, currentUserGroups: hasConditional(itemData.currentUserGroups, config.currentUser.groups), currentUserRights: hasConditional(itemData.currentUserRights, config.currentUser.rights), currentUserChangeGroups: itemData.currentUserChangeGroups ? canAddRemoveGroups(config.currentUser.groups, config.currentUser.rights) : true, visibility: itemData.visible !== undefined ? !!itemData.visible : true }; if (config.targetUser.name) { conditions.targetUserGroups = hasConditional(itemData.targetUserGroups, config.targetUser.groups); conditions.targetUserRights = hasConditional(itemData.targetUserRights, config.targetUser.rights); conditions.targetUserBlocked = itemData.targetUserBlocked !== undefined ? config.targetUser.blocked === itemData.targetUserBlocked : true; conditions.targetUserChangeGroups = itemData.targetUserChangeGroups ? canAddRemoveGroups(config.targetUser.groups, config.targetUser.rights) : true; conditions.targetUserIp = itemData.targetUserIp ? mw.util.isIPAddress(config.targetUser.name) || (config.targetUser.ipRange && itemData.targetUserIpRange) : true; conditions.targetUserIpRange = config.targetUser.ipRange ? itemData.targetUserIpRange : true; } for (var c in conditions) { if (!conditions[c]) { log(parentKey + '/' + itemKey + ' failed on ' + c); return ''; } } var titleAttr = (msgExists(itemKey + '-desc') || itemData.description) ? ' title="' + (itemData.description || msg(itemKey + '-desc')) + '"' : ''; var styleAttr = itemData.style ? ' style="' + itemData.style + '"' : ''; return '\n<li id="' + getItemId(parentKey, itemKey, submenuKey) + '" class="mm-item mw-list-item">' + '<a href="' + itemData.url + '"' + titleAttr + styleAttr + '>' + '<span>' + msg(itemData.title || itemKey) + '</span></a></li>'; } function addCSS() { switch (config.currentUser.skin) { case 'vector': return mw.util.addCSS( '.mm-tab .vector-menu-content{height:initial;overflow:initial!important}' + '.mm-menu .mw-list-item{white-space:nowrap}' + '.mm-submenu{background:var(--background-color-base,#fff);border:1px solid #a2a9b1;min-width:120px!important;' + rightKey + ':inherit!important;top:-1px!important}' + '#p-views{padding-left:inherit!important;padding-right:inherit!important}' + '#p-views .vector-menu-content::after,.rtl #p-views .vector-menu-content::before{display:none!important}' + '.mm-submenu .mm-item{font-size:inherit!important}' ); case 'vector-2022': return mw.util.addCSS( '#p-page-dropdown .vector-dropdown-content,#p-user-dropdown .vector-dropdown-content{height:initial;overflow-x:initial!important;overflow-y:initial!important;top:35px!important}' + '#p-page-dropdown .vector-dropdown-content::after,#p-user-dropdown .vector-dropdown-content::after{display:none!important}' + '.mm-menu .mw-list-item{white-space:nowrap}' + '.mm-submenu{background:var(--background-color-base,#fff);box-shadow:0 2px 6px -1px rgba(0,0,0,.2);min-width:120px!important;padding:1px 10px;top:-1px!important}' + '#p-views{padding-left:inherit!important;padding-right:inherit!important}' ); case 'timeless': return mw.util.addCSS( '.mm-submenu-wrapper{cursor:default}' + '.mm-submenu{background:#f8f9fa;border:1px solid #c8ccd1;box-shadow:0 2px 3px 1px rgba(0,0,0,.05);padding:1.2em 1.5em!important;top:-1.2em;white-space:nowrap;z-index:95}' + '.mm-submenu::after{border-bottom:8px solid transparent;border-top:8px solid transparent;border-' + leftKey + ':8px solid #c8ccd1;content:"";height:0;padding-' + rightKey + ':4px;position:absolute;top:20px;width:0;' + rightKey + ':-13px}' + '@media screen and (max-width:1339px) and (min-width:1100px){.mm-submenu::after{border-' + leftKey + ':none;border-' + rightKey + ':8px solid #c8ccd1;padding-' + leftKey + ':4px;padding-' + rightKey + ':inherit;' + rightKey + ':inherit;' + leftKey + ':-35px}}' + '@media screen and (max-width:850px){.mm-submenu{top:-2.2em}}' ); case 'monobook': return mw.util.addCSS( '.mm-tab{position:relative}' + '.mm-menu{background:#fff;border-bottom:1px solid #aaa;' + leftKey + ':-1px;margin:0;position:absolute;z-index:99}' + '.mm-menu~a{z-index:99!important}' + '.mm-submenu{background:#fff;border-bottom:1px solid #aaa;border-top:1px solid #aaa;font-size:inherit;margin:0;min-width:75px;top:-1px;z-index:95}' + '.mm-item,.mm-submenu-wrapper{background:#fff!important;border-top:0!important;display:block!important;margin:0!important;padding:0!important;width:100%}' + '.mm-item a,.mm-submenu-wrapper a{background:transparent!important;text-transform:none!important}' + '.mm-menu a:hover{text-decoration:underline!important}' ); case 'modern': return mw.util.addCSS( '.mm-menu,.mm-submenu{background:#f0f0f0!important;border:solid 1px #666}' + '.mm-menu{border-top:none;position:absolute;z-index:99}' + '.mm-submenu-wrapper>a{cursor:default!important}' + '.mm-item,.mm-submenu-wrapper{display:block!important;float:none!important;height:inherit!important;margin:0!important;padding:0!important}' + '.mm-menu a{display:inline-block;padding:3px 10px!important;text-transform:none!important;text-decoration:none!important;white-space:nowrap;width:100%}' + '.mm-menu a:hover{text-decoration:underline!important}' + '.mm-submenu{' + leftKey + ':100%;min-width:120px!important;top:0}' ); default: return null; } } function getSubmenuCss($element) { switch (config.currentUser.skin) { case 'vector': case 'vector-2022': var css = {}; css[leftKey] = $element.outerWidth(); return css; case 'timeless': var css2 = {}; css2[$(window).width() <= 1339 && $(window).width() >= 1100 ? leftKey : rightKey] = $element.outerWidth() + 11; return css2; case 'monobook': var css3 = {}; css3[leftKey] = $element.outerWidth() - 2; return css3; default: return {}; } } function addListeners() { $('.mm-submenu-wrapper').each(function () { var $this = $(this); $this.off('mouseenter mouseleave'); $this.on('mouseenter', function () { $(this).find('.mm-submenu').css(getSubmenuCss($(this))).show(); }).on('mouseleave', function () { $(this).find('.mm-submenu').hide(); }); }); } function sortByTranslation(i18nKeys) { return i18nKeys.sort(function (a, b) { var nameA = msg(a).toLowerCase(); var nameB = msg(b).toLowerCase(); return nameA < nameB ? -1 : nameA > nameB ? 1 : 0; }); } function sortItems(items) { var itemKeys = Object.keys(items); var submenus = itemKeys.filter(function (k) { return !items[k].url; }); var sortedItemKeys = sortByTranslation(itemKeys.filter(function (k) { return !!items[k].url; })); var newItemKeys = sortedItemKeys.slice(); sortedItemKeys.forEach(function (itemKey) { var target = items[itemKey].insertAfter; var newIndex; if (target === false) newIndex = 0; else if (target === true) newIndex = itemKeys.length; else if (!target) return; else { newIndex = newItemKeys.indexOf(target); newIndex = newIndex === -1 ? newItemKeys.length : newIndex + 1; } newItemKeys.splice(newItemKeys.indexOf(itemKey), 1); newItemKeys.splice(newIndex, 0, itemKey); }); return submenus.concat(newItemKeys); } function getMenuHtml(parentKey, items, submenuKey) { var html = ''; var submenuClasses = (config.currentUser.skin === 'vector' || config.currentUser.skin === 'vector-2022') ? 'vector-menu-content-list' : ''; sortItems(items).forEach(function (itemKey) { var item = items[itemKey]; var itemHtml = ''; if (!item.url) { // 子菜单 itemHtml = '\n<li style="position:relative;" id="' + getItemId(parentKey, itemKey) + '" class="mm-submenu-wrapper mw-list-item">' + '<a style="font-weight:bold"><span>' + msg(itemKey) + '…</span></a>' + '<ul class="menu mm-submenu ' + submenuClasses + '" style="display:none;position:absolute">'; sortItems(item).forEach(function (subItemKey) { itemHtml += getItemHtml(parentKey, subItemKey, item[subItemKey], itemKey); }); itemHtml += '</ul></li>'; if ($(itemHtml).find('.mm-submenu li').length === 0) itemHtml = ''; } else { itemHtml = getItemHtml(parentKey, itemKey, item, submenuKey); } html += itemHtml; }); return html; } function drawMenuVector(parentKey, html) { var menu = mw.util.addPortlet('p-' + parentKey, msg(parentKey), '#p-cactions'); menu.classList.add('mm-' + parentKey, 'mm-tab'); mw.util.addPortletLink('p-' + parentKey, '#', 'temp'); var menuContent = menu.querySelector('ul'); menuContent.innerHTML = html; menuContent.classList.add('mm-menu'); } function drawMenuTimeless(parentKey, html) { html = '<div role="navigation" class="mw-portlet mm-' + parentKey + ' mm-tab" id="p-' + parentKey + '" aria-labelledby="p-' + parentKey + '-label">' + '<h3 id="p-' + parentKey + '-label">' + msg(parentKey) + '</h3>' + '<div class="mw-portlet-body"><ul class="mm-menu">' + html + '</ul></div></div>'; if ($('#p-cactions').length) $(html).insertBefore($('#p-cactions')); else $('#page-tools .sidebar-inner').prepend(html); } function drawMenuMonobook(parentKey, html) { html = '<li id="ca-' + parentKey + '" class="mm-' + parentKey + ' mm-tab">' + '<a href="javascript:void(0)">' + msg(parentKey) + '</a>' + '<ul class="mm-menu" style="display:none">' + html + '</ul></li>'; var $tab = $(html).insertAfter($('#ca-nstab-special, #ca-edit, #ca-ve-edit, #ca-page, #ca-viewsource, #ca-talk').last()); var $menu = $tab.find('.mm-menu'); $tab.on('mouseenter', function () { $menu.show(); $tab.find('> a').css('z-index', 99); }) .on('mouseleave', function () { $menu.hide(); $tab.find('> a').css('z-index', 'inherit'); }); } function drawMenuModern(parentKey, html) { html = '<li id="ca-' + parentKey + '" class="mm-' + parentKey + ' mm-tab">' + '<a href="javascript:void(0)">' + msg(parentKey) + '</a>' + '<ul class="mm-menu" style="display:none">' + html + '</ul></li>'; var $tab = $(html).insertAfter($('#ca-nstab-special, #ca-edit, #ca-ve-edit, #ca-page, #ca-viewsource, #ca-talk').last()); var $menu = $tab.find('.mm-menu'); $menu.css({ left: isRtl ? $tab.position().left - $menu.width() + $tab.width() + 7 : $tab.position().left, top: $tab.offset().top + $tab.outerHeight() }); $tab.on('mouseenter', function () { $menu.show(); }).on('mouseleave', function () { $menu.hide(); }); } function drawMenus() { var menus = {}; if (config.page.nsId >= 0) $.extend(menus, pageMenu(config)); if (config.targetUser.name) $.extend(menus, userMenu(config)); addCSS(); Object.keys(menus).forEach(function (key) { var html = getMenuHtml(key, menus[key]); switch (config.currentUser.skin) { case 'vector-2022': case 'vector': drawMenuVector(key, html); break; case 'monobook': drawMenuMonobook(key, html); break; case 'modern': drawMenuModern(key, html); break; case 'timeless': drawMenuTimeless(key, html); break; default: log("'" + config.currentUser.skin + "' is not a supported skin.", 'error'); } }); addListeners(); } function handleHistoryAndWatchLinks(replace) { replace = replace || false; var monobookModern = ['monobook', 'modern'].indexOf(config.currentUser.skin) !== -1; var $histLink = $('#ca-history'); var $watchLink = $('.mw-watchlink'); var $moveLink = $('#ca-move'); if (replace) { if (monobookModern) { $('#mm-page-watch').replaceWith($watchLink.addClass('mm-item').prop('id', 'mm-page-watch').show()); $('#mm-page-history').replaceWith($histLink.addClass('mm-item').prop('id', 'mm-page-history').show()); } $('#mm-page-move-page').replaceWith($moveLink.addClass('mm-item').prop('id', 'mm-page-move-page').show()); return; } translations.watch = $watchLink.text() || 'watch'; translations.history = $histLink.text() || 'history'; if (monobookModern) { $watchLink.hide(); $histLink.hide(); } $moveLink.hide(); } function addMutationObserver(ids) { if (typeof ids === 'string') ids = [ids]; ids.forEach(function (id) { var $parent = $(id); if (!$parent.length) return; var $menu = $parent.find('ul'); var menuIsEmpty = function () { return $menu.html().trim() === ''; }; if (menuIsEmpty()) $parent.hide(); new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { if (mutation.addedNodes.length) $parent.show(); else if (mutation.removedNodes.length && menuIsEmpty()) $parent.hide(); }); }).observe($menu.get(0), { childList: true }); }); } function observeCactionsMenu() { var reAddCount = parseInt(mw.storage.get('mmNativeMenuUsage'), 10) || 0; if (['vector', 'vector-2022', 'timeless'].indexOf(config.currentUser.skin) === -1 || window.MoreMenu.disableAutoRemoval || reAddCount >= 5) return; addMutationObserver('#p-cactions'); setTimeout(function () { if ($('#p-cactions').find('li').length) { mw.storage.set('mmNativeMenuUsage', reAddCount + 1, 60 * 60 * 24); } }, 5000); } function removeNativeLinks() { var linksToRemove = ['#ca-protect', '#ca-unprotect', '#ca-delete', '#ca-undelete']; if (config.currentUser.skin === 'timeless') { linksToRemove = linksToRemove.concat(['#t-contributions', '#t-log', '#t-blockip', '#t-emailuser', '#t-userrights', '#t-info', '#t-pagelog']); } $(linksToRemove.join(',')).remove(); handleHistoryAndWatchLinks(); observeCactionsMenu(); if (config.currentUser.skin === 'timeless') addMutationObserver('#p-userpagetools'); } function removeBlockLogLink() { api.get({ action: 'query', list: 'logevents', letype: 'block', letitle: 'User:' + config.targetUser.name, lelimit: 1 }).done(function (data) { if (!data.query.logevents.length) $('#mm-user-blocks-view-block-log').remove(); }); } function removeUnneededLinks() { handleHistoryAndWatchLinks(true); if (!config.targetUser.name) return; removeBlockLogLink(); addMutationObserver(['#mm-page-analysis', '#mm-page-search', '#mm-user-blocks', '#mm-user-analysis']); if (config.targetUser.ipRange) { $('#mm-user-user-logs').remove(); $('#mm-user-deleted-contributions').remove(); $('#mm-user-suppressed-contributions').remove(); } } function getPromises() { var promises = new Array(4); if (config.targetUser.name && !config.targetUser.ipv4Range) { promises[0] = api.get({ action: 'query', list: 'users|blocks', ususers: config.targetUser.name, bkusers: config.targetUser.name, usprop: 'blockinfo|groups|rights|emailable', bkprop: 'id' }); } config.currentUser.rights = JSON.parse(mw.storage.session.getObject('mmUserRights')); if (!config.currentUser.rights) promises[1] = mw.user.getRights(); config.currentUser.groupsData = JSON.parse(mw.storage.session.getObject('mmMetaUserGroups')); if (!config.currentUser.groupsData) { promises[2] = api.get({ action: 'query', meta: 'siteinfo', siprop: 'usergroups' }); } promises[3] = loadTranslations(); return promises; } function init() { $.when.apply(this, getPromises()).done(function (targetUserData, userRightsData, metaData) { if (targetUserData) { $.extend(config.targetUser, targetUserData.query ? targetUserData.query.users[0] : targetUserData[0].query.users[0]); var blocks = targetUserData.query ? targetUserData.query.blocks : targetUserData[0].query.blocks; if (blocks.length) { config.targetUser.blocked = true; config.targetUser.blockid = blocks[0].id; } } if (userRightsData) { var rights = userRightsData.query ? userRightsData : userRightsData.slice ? userRightsData : userRightsData[0]; if (rights.slice) { mw.storage.session.setObject('mmUserRights', JSON.stringify(rights)); config.currentUser.rights = rights.slice(); } } if (metaData) { config.currentUser.groupsData = {}; var groups = metaData.query ? metaData.query.usergroups : metaData[0].query.usergroups; groups.forEach(function (el) { config.currentUser.groupsData[el.name] = { rights: el.rights, canAddRemoveGroups: !!el.add || !!el.remove }; }); mw.storage.session.setObject('mmMetaUserGroups', JSON.stringify(config.currentUser.groupsData)); } removeNativeLinks(); drawMenus(); removeUnneededLinks(); mw.hook('moremenu.ready').fire(config); }); } /** 公开 API */ MoreMenu.addItemCore = function (menu, items, insertAfter, submenu) { if (!$('.mm-' + menu).length) return; var menuId = submenu ? '#mm-' + menu + '-' + submenu : '.mm-' + menu; var $menu = $(menuId); if (!$menu.length) { log("'" + menu + (submenu ? ' ' + submenu : '') + "' not found.", 'warn'); return; } ignoreI18nWarnings = true; if (Object.keys(items).length !== 1) { log('Multiple items given, ignoring all but the first.', 'warn'); items = items[Object.keys(items)[0]]; } var $html = $(getMenuHtml(menu, items, submenu)); var $beforeItem = (function () { var id = getItemId(menu, insertAfter || '', submenu); return $('#' + $.escapeSelector(id)); })(); var isSubmenuItem = $beforeItem.parents('.mm-submenu').length; if ($beforeItem.length && (!submenu || (submenu && isSubmenuItem))) { $beforeItem.after($html); } else { var newI18nKey = normalizeId(Object.keys(items)[0]); var newId = getItemId(menu, newI18nKey, submenu); var $topItems = submenu ? $(menuId).find('.mm-submenu > .mm-item') : $(menuId).find('.mm-menu > .mm-item'); if (insertAfter === true) { $topItems.last().after($html); ignoreI18nWarnings = false; addListeners(); return; } if (insertAfter === false) { $topItems.first().before($html); ignoreI18nWarnings = false; addListeners(); return; } if (!$beforeItem.length && insertAfter) log('Invalid insertAfter.', 'warn'); var ids = $topItems.toArray().map(function (el) { return el.id; }).concat([newId]); var i18nKeys = sortByTranslation(ids.map(function (id) { return id.replace(new RegExp('^mm-' + menu + '-' + (submenu ? submenu + '-' : '')), ''); })); var idx = i18nKeys.indexOf(newI18nKey) - 1; if (idx < 0) $('#' + $.escapeSelector(ids[0])).before($html); else $('#' + $.escapeSelector(getItemId(menu, i18nKeys[idx], submenu))).after($html); } addListeners(); ignoreI18nWarnings = false; }; MoreMenu.addItem = function (menu, name, data, insertAfter) { var item = {}; item[name] = data; MoreMenu.addItemCore(menu, item, insertAfter); }; MoreMenu.addSubmenuItem = function (menu, submenu, name, data, insertAfter) { var item = {}; item[name] = data; MoreMenu.addItemCore(menu, item, insertAfter, submenu); }; MoreMenu.addSubmenu = function (menu, name, items, insertAfter) { var item = {}; item[name] = items; MoreMenu.addItemCore(menu, item, insertAfter); }; MoreMenu.addLink = function (menu, name, url, insertAfter) { var item = {}; item[name] = { url: url }; MoreMenu.addItemCore(menu, item, insertAfter); }; MoreMenu.addSubmenuLink = function (menu, submenu, name, url, insertAfter) { var item = {}; item[name] = { url: url }; MoreMenu.addItemCore(menu, item, insertAfter, submenu); }; init(); }); })();
返回
MediaWiki:Gadget-MoreMenu.js
。