跳转到内容
打开/关闭搜索
搜索
打开/关闭菜单
1
条目
2
文件
8
用户
635
编辑
ANACHRONISM
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
打开/关闭外观设置菜单
无法加载外观设置。请检查您的网络连接并重试。
重试
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
个人工具
登录
请求账号
查看“︁MediaWiki:Common.js”︁的源代码
MediaWiki界面页面
查看
阅读
查看源代码
查看历史
相关页面
系统消息
讨论
更多操作
更多
工具
链入页面
相关更改
页面信息
←
MediaWiki:Common.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
旅人
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
/* ============================================ 侧边工具栏 Rail 管理器 ============================================ */ window.Rail = (function () { var items = []; var activeId = null; var panelEl, overlayEl, buttonsEl, contentEl, titleEl; function ensureDOM() { if (document.getElementById('rail-container')) return; buttonsEl = document.createElement('div'); buttonsEl.id = 'rail-container'; buttonsEl.className = 'rail-container'; overlayEl = document.createElement('div'); overlayEl.id = 'rail-overlay'; overlayEl.className = 'rail-overlay'; panelEl = document.createElement('aside'); panelEl.id = 'rail-panel'; panelEl.className = 'rail-panel'; panelEl.innerHTML = [ '<div class="rail-panel__header">', ' <span class="rail-panel__title"></span>', ' <button class="rail-panel__close" type="button" aria-label="关闭">×</button>', '</div>', '<div class="rail-panel__content" id="rail-panel-content"></div>' ].join(''); titleEl = panelEl.querySelector('.rail-panel__title'); contentEl = panelEl.querySelector('#rail-panel-content'); document.body.appendChild(overlayEl); document.body.appendChild(panelEl); document.body.appendChild(buttonsEl); panelEl.querySelector('.rail-panel__close').addEventListener('click', close); overlayEl.addEventListener('click', close); document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); }); } function createButton(item) { var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'rail-button fx-swap fx-pulse'; btn.setAttribute('data-rail-id', item.id); btn.setAttribute('aria-label', item.label); btn.setAttribute('title', item.label); var iconDefault = item.icon || '●'; var iconActive = item.iconActive || iconDefault; btn.innerHTML = '<span class="fx-swap__a rail-button__icon fx-text-glow">' + iconDefault + '</span>' + '<span class="fx-swap__b rail-button__icon fx-text-glow">' + iconActive + '</span>'; btn.addEventListener('click', function () { if (activeId === item.id) { close(); } else { open(item); } }); return btn; } function highlightButtons() { var all = buttonsEl.querySelectorAll('.rail-button'); for (var i = 0; i < all.length; i++) { var id = all[i].getAttribute('data-rail-id'); all[i].classList.toggle('is-active', id === activeId); } } function open(item) { activeId = item.id; titleEl.textContent = item.label; contentEl.innerHTML = '<p class="rail-panel__loading">加载中…</p>'; highlightButtons(); document.body.classList.add('rail-open'); if (item.html) { contentEl.innerHTML = item.html; return; } if (item.template) { var api = new mw.Api(); api.get({ action: 'parse', page: item.template, prop: 'text', formatversion: '2' }).done(function (data) { if (activeId !== item.id) return; if (data && data.parse && data.parse.text) { contentEl.innerHTML = data.parse.text; } else { contentEl.innerHTML = '<p>加载失败。</p>'; } }).fail(function () { if (activeId !== item.id) return; contentEl.innerHTML = '<p>加载失败。</p>'; }); } else { contentEl.innerHTML = '<p>未配置内容。</p>'; } } function close() { activeId = null; document.body.classList.remove('rail-open'); if (buttonsEl) highlightButtons(); } function init() { ensureDOM(); buttonsEl.innerHTML = ''; items.forEach(function (item) { buttonsEl.appendChild(createButton(item)); }); } return { register: function (id, options) { options = options || {}; items.push({ id: id, icon: options.icon || '●', label: options.label || id, html: options.html || null, template: options.template || null }); }, init: init, open: open, close: close }; })(); /* ============================================ 注册工具栏按钮 ============================================ */ Rail.register('navigation', { icon: '☰', label: '导航', template: 'Template:工具栏导航' }); Rail.register('claim', { icon: '!', label: '公告', template: 'Template:工具栏公告' }); Rail.register('help', { icon: '?', label: '帮助', template: 'Template:工具栏帮助' }); Rail.register('settings', { icon: '⚙', label: '设置', template: 'Template:工具栏设置' }); /* ============================================ Rail 初始化 ============================================ */ if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function () { Rail.init(); }); } else { Rail.init(); } /* ============================================ 工具栏账户信息动态填充 ============================================ */ (function () { // 不显示的隐式用户组 var HIDDEN_GROUPS = ['*', 'user', 'autoconfirmed', 'emailconfirmed']; // 系统消息未加载时的中文兜底 var GROUP_NAME_FALLBACK = { 'sysop': '策展人', 'bureaucrat': '行政员', 'interface-admin': '织界者', 'interface_admin': '织界者', 'allowguest': '观察者' }; function formatDate(ms) { if (!ms) return '—'; var d = new Date(ms); return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0'); } function isMissing(msg) { if (!msg) return true; return msg.indexOf('\u29FC') !== -1 || msg.indexOf('⧼') !== -1; } function getGroupName(g) { var txt = mw.msg('group-' + g + '-member'); if (!isMissing(txt)) return txt; return GROUP_NAME_FALLBACK[g] || g; } function getGroupUrl(g) { var page = mw.msg('grouppage-' + g); if (!isMissing(page)) { return mw.util.getUrl(page); } return mw.util.getUrl('Anachronism:' + getGroupName(g)); } function getGroupHtml(groups) { var visible = groups.filter(function (g) { return HIDDEN_GROUPS.indexOf(g) === -1; }); if (!visible.length) return '无'; return visible.map(function (g) { var name = getGroupName(g); var url = getGroupUrl(g); return '<a href="' + url + '" class="rail-group-tag">' + name + '</a>'; }).join(''); } function renderGuest(box) { box.innerHTML = [ '<div class="rail-account-title">账户</div>', '<p class="rail-account-guest">您的身份是访客</p>', '<div class="rail-account-actions">', ' <a href="' + mw.util.getUrl('Special:UserLogin') + '" class="rail-action-button">登录</a>', ' <a href="' + mw.util.getUrl('Special:CreateAccount') + '" class="rail-action-button">创建账户</a>', '</div>' ].join(''); } function renderUser(box) { var userName = mw.config.get('wgUserName'); var groups = mw.config.get('wgUserGroups') || []; var editCount = mw.config.get('wgUserEditCount'); var regTime = mw.config.get('wgUserRegistration'); box.innerHTML = [ '<div class="rail-account-title">账户:' + userName + '</div>', '<div class="rail-account-groups"><span class="rail-account-groups__label">权限组:</span>' + getGroupHtml(groups) + '</div>', '<div class="rail-account-actions">', ' <a href="' + mw.util.getUrl('Special:Contributions/' + userName) + '" class="rail-action-button">贡献</a>', ' <a href="' + mw.util.getUrl('Special:Watchlist') + '" class="rail-action-button">监视列表</a>', ' <a href="' + mw.util.getUrl('User talk:' + userName) + '" class="rail-action-button">用户讨论</a>', '</div>', '<div class="rail-account-stats">', ' <span>编辑数:' + (editCount != null ? editCount : '—') + '</span>', ' <span>加入时间:' + formatDate(regTime) + '</span>', '</div>', '<div class="rail-account-logout">', ' <a href="' + mw.util.getUrl('Special:UserLogout') + '" class="rail-action-button rail-action-button--danger">退出登录</a>', '</div>' ].join(''); } function fillAccountInfo() { var box = document.getElementById('rail-account-info'); if (!box || box.dataset.filled === '1') return; box.dataset.filled = '1'; if (mw.config.get('wgUserName')) { renderUser(box); } else { renderGuest(box); } } function observeRailPanel() { var target = document.getElementById('rail-panel-content'); if (!target) return; var observer = new MutationObserver(fillAccountInfo); observer.observe(target, { childList: true, subtree: true }); fillAccountInfo(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', observeRailPanel); } else { observeRailPanel(); } })(); /* ============================================ 在 rail 面板中触发 Citizen 偏好设置面板 ============================================ */ (function () { function bindRailPreferences() { var trigger = document.getElementById('rail-open-preferences'); if (!trigger || trigger.dataset.bound === '1') return; trigger.dataset.bound = '1'; trigger.addEventListener('click', function () { if (window.Rail && typeof Rail.close === 'function') { Rail.close(); } var details = document.getElementById('citizen-preferences-details'); if (details) { details.open = true; } document.body.classList.add('citizen-preferences-shown'); // 插入关闭按钮(只插一次) var card = document.getElementById('citizen-preferences-dropdown__card'); if (card && !card.querySelector('.citizen-preferences-close')) { var closeBtn = document.createElement('button'); closeBtn.className = 'citizen-preferences-close'; closeBtn.type = 'button'; closeBtn.textContent = '×'; closeBtn.setAttribute('aria-label', '关闭'); closeBtn.addEventListener('click', function () { document.body.classList.remove('citizen-preferences-shown'); var d = document.getElementById('citizen-preferences-details'); if (d) d.open = false; }); card.insertBefore(closeBtn, card.firstChild); } }); } // 点击面板外部关闭 document.addEventListener('click', function (e) { if (!document.body.classList.contains('citizen-preferences-shown')) return; var card = document.getElementById('citizen-preferences-dropdown__card'); var trigger = document.getElementById('rail-open-preferences'); if (!card) return; if (card.contains(e.target)) return; if (trigger && trigger.contains(e.target)) return; document.body.classList.remove('citizen-preferences-shown'); var details = document.getElementById('citizen-preferences-details'); if (details) details.open = false; }); // Esc 关闭 document.addEventListener('keydown', function (e) { if (e.key !== 'Escape') return; if (!document.body.classList.contains('citizen-preferences-shown')) return; document.body.classList.remove('citizen-preferences-shown'); var details = document.getElementById('citizen-preferences-details'); if (details) details.open = false; }); var observer = new MutationObserver(bindRailPreferences); observer.observe(document.body, { childList: true, subtree: true }); bindRailPreferences(); })(); /* ============================================ 评论区重定位:从主内容中移出,成为页面级独立块 ============================================ */ (function () { var MAX_ATTEMPTS = 100; var INTERVAL_MS = 100; var attempts = 0; function tryRelocate() { attempts++; var existing = document.querySelector('.comments-body'); if (existing && existing.dataset.relocated === '1') { return true; } var comments = document.querySelector('.mw-parser-output .comments-body'); if (!comments) return false; var mwBody = document.querySelector('.mw-body'); if (!mwBody || !mwBody.parentNode) return false; comments.dataset.relocated = '1'; comments.classList.add('comments-body--page-level'); mwBody.parentNode.insertBefore(comments, mwBody.nextSibling); return true; } function startWatch() { if (tryRelocate()) return; var timer = setInterval(function () { if (tryRelocate() || attempts >= MAX_ATTEMPTS) { clearInterval(timer); } }, INTERVAL_MS); var observer = new MutationObserver(function () { if (tryRelocate()) { observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(function () { observer.disconnect(); clearInterval(timer); }, 15000); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startWatch); } else { startWatch(); } })(); /* ============================================ 评论区:把回复嵌套到父评论内部 Comments 扩展渲染的 DOM 是扁平的: .c-item.full ← 顶层评论 .c-item.reply ← 回复(和 full 平级) 这里用 JS 把 .reply 移到前面最近一个 .full 的 .c-container 内部,形成真正的 DOM 嵌套。 ============================================ */ (function () { var MAX_ATTEMPTS = 100; var INTERVAL_MS = 100; var attempts = 0; function nestReplies() { var body = document.querySelector('.comments-body'); if (!body) return false; if (body.dataset.repliesNested === '1') return true; var items = Array.prototype.slice.call(body.querySelectorAll('.c-item')); if (!items.length) return false; var currentFull = null; items.forEach(function (item) { if (item.classList.contains('full')) { currentFull = item; } else if (item.classList.contains('reply') && currentFull) { var targetContainer = currentFull.querySelector('.c-container'); if (targetContainer && item.parentElement !== targetContainer) { targetContainer.appendChild(item); item.classList.add('nested-in-parent'); } } }); body.dataset.repliesNested = '1'; return true; } function start() { if (nestReplies()) return; var timer = setInterval(function () { if (nestReplies() || attempts++ >= MAX_ATTEMPTS) { clearInterval(timer); } }, INTERVAL_MS); var observer = new MutationObserver(function () { if (nestReplies()) observer.disconnect(); }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(function () { observer.disconnect(); clearInterval(timer); }, 15000); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); } })(); /* ============================================ 隐藏 Special:ListGroupRights 里的"常客"行 (autoconfirmed 是核心隐式组,无法通过配置移除) ============================================ */ (function () { var HIDE_GROUP_NAMES = ['常客']; function hideRows() { var table = document.querySelector('.mw-listgrouprights-table'); if (!table) return; table.querySelectorAll('tr').forEach(function (tr) { var link = tr.querySelector('a'); if (!link) return; var text = (link.textContent || '').trim(); if (HIDE_GROUP_NAMES.indexOf(text) !== -1) { tr.style.display = 'none'; } }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', hideRows); } else { hideRows(); } })();
返回
MediaWiki:Common.js
。
查看“︁MediaWiki:Common.js”︁的源代码
MediaWiki界面页面