MediaWiki:Common.js
外观
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
(function () { /* -------------------- 1⃣ 颜色工具 -------------------- */ (() => { const HEX_VAR = '--background-color-base'; const RGB_VAR = '--background-color-rgb'; // hex -> `r, g, b` const hex2rgb = hex => hex .replace(/^#/, '') .replace(/^([0-9a-f])([0-9a-f])([0-9a-f])$/i, '$1$1$2$2$3$3') // 3 -> 6 位 .match(/.{2}/g) // ["ff","aa","00"] .map(n => parseInt(n, 16)) // [255,170,0] .join(', '); // "255, 170, 0" const root = document.documentElement; const rgb = hex2rgb(getComputedStyle(root).getPropertyValue(HEX_VAR).trim()); root.style.setProperty(RGB_VAR, rgb); // console.debug(`[theme] ${HEX_VAR} -> ${RGB_VAR}:`, rgb); })(); /* -------------------- 2⃣ 上传页跳转弹窗 -------------------- */ (() => { mw.loader.using(['oojs-ui', 'mediawiki.util', 'mediawiki.storage'], () => { if (mw.config.get('wgCanonicalSpecialPageName') !== 'Upload') return; const KEY = 'uploadPreference'; const store = mw.storage || window.localStorage; const choice = store.get(KEY); if (choice === 'wizard') return location.replace(mw.util.getUrl('Special:UploadWizard')); if (choice === 'classic') return; // 直接停留 /* ---- 弹窗 ---- */ class UploadDialog extends OO.ui.ProcessDialog { static static = { name : 'UploadDialog', title : '请选择上传方式', actions: [ { action: 'classic', label: '❌ 使用传统上传(更快)', flags: 'safe' } ] }; initialize() { super.initialize(); const remember = new OO.ui.CheckboxInputWidget(); this._remember = remember; const panel = new OO.ui.PanelLayout({ padded: true }); const wizardBtn = new OO.ui.ButtonWidget({ label : '✅ 使用上传向导(推荐)', flags : ['primary', 'progressive'], href : mw.util.getUrl('Special:UploadWizard'), target : '_self' }); wizardBtn.on('click', () => remember.isSelected() && store.set(KEY, 'wizard')); panel.$element.append( $('<p>').text('请选择要使用的上传方式:'), buildCard('✅ 上传向导(推荐)', [ '支持多文件批量上传', '显示上传进度条', '信息填写更完整' ], wizardBtn.$element), buildCard('⚡️ 传统上传方式', [ '界面更简单', '加载速度快', '适合上传单个文件' ]), new OO.ui.FieldLayout(remember, { label : '记住我的选择,下次不再提示', align : 'inline' }).$element.css('margin-top', '15px') ); this.$body.append(panel.$element); } getActionProcess(action) { if (action === 'classic') { this._remember.isSelected() && store.set(KEY, 'classic'); return new OO.ui.Process(() => this.close()); } return super.getActionProcess(action); } } /* helper – 卡片组件 */ const buildCard = (title, points, extra = null) => $('<div>') .addClass('upload-card') .append( $('<strong>').text(title), $('<ul>').append(points.map(t => $('<li>').text(t))), extra && $('<div>').css('margin-top', '8px').append(extra) ); /* 注入样式 */ mw.util.addCSS(` .upload-card{ margin:12px 0; padding:10px; border-radius:5px; background:#f8f9fa; border:1px solid #ccc; } .upload-card + .upload-card{ background:#fff; border-style:dashed; margin-top:15px; } `); /* 打开弹窗 */ const wm = new OO.ui.WindowManager(); $(document.body).append(wm.$element); wm.openWindow(new UploadDialog()); }); })(); /* -------------------- 3⃣ 全局 Loading 指示器 -------------------- */ (() => { const IMG = 'https://wiki.ottohub.cn/images/0/02/Loading.png'; const TIMEOUT_INIT = 5000; // 首次进入最大等待 const TIMEOUT_CLICK = 15000; // 点链接最大等待 let timer; // 全局移除计时 let visible = false; /* 全局 style 只插一次 */ const styleText = ` #globalLoading{ position:fixed;bottom:20px;right:20px;z-index:99999; width:256px;height:256px;opacity:0;pointer-events:none; transition:opacity .25s; } #globalLoading.show{opacity:1;} `; document.head.insertAdjacentHTML('beforeend', `<style>${styleText}</style>`); const createNode = () => { const div = document.createElement('div'); div.id = 'globalLoading'; div.innerHTML = `<img src="${IMG}" alt="Loading" style="width:100%;height:100%;object-fit:contain">`; return div; }; const show = why => { if (visible) return; visible = true; // console.debug('[loading] show –', why); const node = document.getElementById('globalLoading') || createNode(); node.classList.add('show'); if (!node.isConnected) document.body.appendChild(node); resetTimer(TIMEOUT_CLICK, 'fallback-click'); }; const hide = why => { if (!visible) return; visible = false; // console.debug('[loading] hide –', why); const node = document.getElementById('globalLoading'); node?.classList.remove('show'); resetTimer(); // 清计时 }; const resetTimer = (ms, reason) => { clearTimeout(timer); if (ms) timer = setTimeout(() => hide(reason), ms); }; /* ---- 首次页加载 ---- */ if (document.readyState === 'loading') { show('initial'); window.addEventListener('load', () => hide('window.load'), { once: true }); resetTimer(TIMEOUT_INIT, 'fallback-init'); } /* ---- 链接点击(传统跳转)---- */ document.addEventListener('click', e => { const a = e.target.closest('a'); if (!a || // 非 <a> a.target === '_blank' || // 新窗口 a.href.startsWith('javascript:') || a.href.startsWith('#') || a.href.startsWith('mailto:') || a.href.startsWith('tel:') ) return; show('link'); }, true); /* ---- 暴露给 SPA / AJAX 主动调用 ---- */ window.globalLoading = { show, hide }; })(); })();