MediaWiki:Gadget-site-js.js:修订间差异
MediaWiki界面页面
更多操作
第1行: | 第1行: | ||
const | (function () { | ||
const | /* -------------------- 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 }; | |||
})(); | |||
})(); | })(); |
2025年5月18日 (日) 14:12的版本
(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 };
})();
})();