MediaWiki:Gadget-site-js.js:修订间差异
MediaWiki界面页面
更多操作
第7行: | 第7行: | ||
} | } | ||
if (isMobileDevice() && !localStorage.getItem('disableVConsole')) { | if (isMobileDevice() && !window.localStorage.getItem('disableVConsole')) { | ||
const vConsoleScript = document.createElement('script'); | const vConsoleScript = document.createElement('script'); | ||
vConsoleScript.src = 'https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.1/vconsole.min.js'; | vConsoleScript.src = 'https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.1/vconsole.min.js'; | ||
vConsoleScript.onload = () | vConsoleScript.onload = function() { | ||
try { | try { | ||
new VConsole(); | if (window.VConsole) { | ||
new window.VConsole(); | |||
} | |||
} catch (e) { | } catch (e) { | ||
alert('调试工具初始化失败,请重试或联系管理员'); | alert('调试工具初始化失败,请重试或联系管理员'); | ||
第20行: | 第22行: | ||
}; | }; | ||
vConsoleScript.onerror = () | vConsoleScript.onerror = function() { | ||
alert('调试工具加载失败,请检查网络连接'); | alert('调试工具加载失败,请检查网络连接'); | ||
console.error('vConsole failed to load'); | console.error('vConsole failed to load'); | ||
}; | }; | ||
document.body.appendChild(vConsoleScript); | document.body.appendChild(vConsoleScript); | ||
} | } | ||
第38行: | 第39行: | ||
function parseHex(hex) { | function parseHex(hex) { | ||
hex = hex.replace(/^#/, ''); | hex = hex.replace(/^#/, ''); | ||
if (hex.length === 3) hex = hex.split('').map(c | if (hex.length === 3) { | ||
hex = hex.split('').map(function(c) { return c + c; }).join(''); | |||
} | |||
if (hex.length !== 6) return '0, 0, 0'; | if (hex.length !== 6) return '0, 0, 0'; | ||
var r = parseInt(hex.substring(0, 2), 16); | |||
return | var g = parseInt(hex.substring(2, 4), 16); | ||
var b = parseInt(hex.substring(4, 6), 16); | |||
return r + ', ' + g + ', ' + b; | |||
} | } | ||
function update() { | function update() { | ||
var root = document.documentElement; | |||
var hex = getComputedStyle(root).getPropertyValue(OBS_VAR).trim(); | |||
var rgb = parseHex(hex || '#000'); | |||
if (rgb !== cachedRgb) { | if (rgb !== cachedRgb) { | ||
root.style.setProperty('--background-color-rgb', rgb); | root.style.setProperty('--background-color-rgb', rgb); | ||
第55行: | 第60行: | ||
update(); | update(); | ||
var mo = new MutationObserver(update); | |||
mo.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] }); | mo.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] }); | ||
return { | return { | ||
destroy() { mo.disconnect(); } | destroy: function() { mo.disconnect(); } | ||
}; | }; | ||
})(); | })(); | ||
第66行: | 第71行: | ||
* 模块 2:上传页引导弹窗 | * 模块 2:上传页引导弹窗 | ||
**********************/ | **********************/ | ||
if (mw | // 修复可选链操作符问题 | ||
if (window.mw && mw.config && mw.config.get('wgCanonicalSpecialPageName') === 'Upload') { | |||
var KEY = 'uploadPreference'; | |||
var pref = mw.storage.get(KEY); | |||
if (pref === 'wizard') window.location = mw.util.getUrl('Special:UploadWizard'); | if (pref === 'wizard') { | ||
if (pref === 'classic') ; | window.location.href = mw.util.getUrl('Special:UploadWizard'); | ||
return; | |||
} | |||
if (pref === 'classic') return; | |||
function initDialog() { | |||
document.removeEventListener('click', initDialog); | document.removeEventListener('click', initDialog); | ||
mw.loader.using(['oojs-ui-core', 'oojs-ui-widgets']).then(() = | mw.loader.using(['oojs-ui-core', 'oojs-ui-widgets']).then(function() { | ||
var UploadDialog = function() {}; | |||
UploadDialog.static = { | |||
name: 'UploadDialog', | |||
title: '请选择上传方式', | |||
actions: [{ action: 'classic', label: '❌ 传统方式', flags: ['safe'] }] | |||
}; | |||
UploadDialog.prototype.initialize = function() { | |||
OO.ui.ProcessDialog.prototype.initialize.apply(this, arguments); | |||
this._remember = new OO.ui.CheckboxInputWidget(); | |||
var wizardBtn = new OO.ui.ButtonWidget({ | |||
label: '✅ 上传向导', | |||
flags: ['primary'], | |||
href: mw.util.getUrl('Special:UploadWizard'), | |||
target: '_self' | |||
}); | |||
wizardBtn.on('click', function() { | |||
if (this._remember.isSelected()) { | |||
}); | mw.storage.set(KEY, 'wizard'); | ||
} | |||
}.bind(this)); | |||
var $body = this.$body; | |||
$body.append( | |||
$('<p>').text('请选择上传方式:'), | |||
wizardBtn.$element, | |||
new OO.ui.FieldLayout(this._remember, { | |||
label: '记住选择', | |||
align: 'inline' | |||
}).$element | |||
); | |||
}; | |||
UploadDialog.prototype.getActionProcess = function(action) { | |||
if (action === 'classic') { | |||
if (this._remember.isSelected()) { | |||
mw.storage.set(KEY, 'classic'); | |||
} | } | ||
return | return new OO.ui.Process(function() { | ||
this.close(); | |||
}.bind(this)); | |||
} | } | ||
} | return OO.ui.ProcessDialog.prototype.getActionProcess.apply(this, arguments); | ||
}; | |||
var wm = new OO.ui.WindowManager(); | |||
document.body.appendChild(wm.$element); | document.body.appendChild(wm.$element); | ||
wm.addWindows([new UploadDialog()]); | wm.addWindows([new UploadDialog()]); | ||
wm.openWindow('UploadDialog'); | wm.openWindow('UploadDialog'); | ||
}); | }); | ||
}); | } | ||
document.addEventListener('click', initDialog); | |||
} | } | ||
第120行: | 第143行: | ||
* 模块 3:加载指示器 | * 模块 3:加载指示器 | ||
**********************/ | **********************/ | ||
var LoadingIndicator = (function () { | |||
var defaultConfig = { | |||
imageUrl: 'https://wiki.ottohub.cn/images/0/02/Loading.png', | imageUrl: 'https://wiki.ottohub.cn/images/0/02/Loading.png', | ||
position: { bottom: '20px', right: '20px' }, | position: { bottom: '20px', right: '20px' }, | ||
第130行: | 第153行: | ||
}; | }; | ||
var indicator = null; | |||
var timerId = null; | |||
var currentConfig = Object.assign({}, defaultConfig); | |||
function createIndicator() { | function createIndicator() { | ||
var div = document.createElement('div'); | |||
div.style. | div.style.position = 'fixed'; | ||
div.style.width = currentConfig.size; | |||
div.style.height = currentConfig.size; | |||
div.style.bottom = currentConfig.position.bottom; | |||
div.style.right = currentConfig.position.right; | |||
div.style.zIndex = currentConfig.zIndex; | |||
div.style.background = 'url(\'' + currentConfig.imageUrl + '\') center/contain no-repeat'; | |||
div.style.opacity = '0'; | |||
div.style.transition = 'opacity ' + currentConfig.fadeDuration + 'ms'; | |||
div.style.pointerEvents = 'none'; | |||
return div; | return div; | ||
} | } | ||
第157行: | 第178行: | ||
document.body.appendChild(indicator); | document.body.appendChild(indicator); | ||
setTimeout(() | setTimeout(function() { | ||
indicator.style.opacity = '1'; | indicator.style.opacity = '1'; | ||
}, 10); | }, 10); | ||
第168行: | 第189行: | ||
indicator.style.opacity = '0'; | indicator.style.opacity = '0'; | ||
setTimeout(() | setTimeout(function() { | ||
indicator. | if (indicator && indicator.parentNode) { | ||
indicator.parentNode.removeChild(indicator); | |||
} | |||
indicator = null; | indicator = null; | ||
}, currentConfig.fadeDuration); | }, currentConfig.fadeDuration); | ||
第177行: | 第200行: | ||
function updateConfig(newConfig) { | function updateConfig(newConfig) { | ||
currentConfig = { | currentConfig = Object.assign({}, defaultConfig, newConfig); | ||
} | } | ||
第184行: | 第207行: | ||
return { | return { | ||
show, | show: show, | ||
hide, | hide: hide, | ||
updateConfig | updateConfig: updateConfig | ||
}; | }; | ||
})(); | })(); |
2025年6月21日 (六) 08:25的版本
/**********************
* 模块 0:vConsole 加载(移动端专用)
**********************/
// 检测是否为移动设备
function isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
if (isMobileDevice() && !window.localStorage.getItem('disableVConsole')) {
const vConsoleScript = document.createElement('script');
vConsoleScript.src = 'https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.1/vconsole.min.js';
vConsoleScript.onload = function() {
try {
if (window.VConsole) {
new window.VConsole();
}
} catch (e) {
alert('调试工具初始化失败,请重试或联系管理员');
console.error('vConsole init error:', e);
}
};
vConsoleScript.onerror = function() {
alert('调试工具加载失败,请检查网络连接');
console.error('vConsole failed to load');
};
document.body.appendChild(vConsoleScript);
}
/**********************
* 模块 1:CSS 变量 RGB 转换
**********************/
const ColorUtil = (function () {
const OBS_VAR = '--background-color-base';
let cachedRgb = '';
function parseHex(hex) {
hex = hex.replace(/^#/, '');
if (hex.length === 3) {
hex = hex.split('').map(function(c) { return c + c; }).join('');
}
if (hex.length !== 6) return '0, 0, 0';
var r = parseInt(hex.substring(0, 2), 16);
var g = parseInt(hex.substring(2, 4), 16);
var b = parseInt(hex.substring(4, 6), 16);
return r + ', ' + g + ', ' + b;
}
function update() {
var root = document.documentElement;
var hex = getComputedStyle(root).getPropertyValue(OBS_VAR).trim();
var rgb = parseHex(hex || '#000');
if (rgb !== cachedRgb) {
root.style.setProperty('--background-color-rgb', rgb);
cachedRgb = rgb;
}
}
update();
var mo = new MutationObserver(update);
mo.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] });
return {
destroy: function() { mo.disconnect(); }
};
})();
/**********************
* 模块 2:上传页引导弹窗
**********************/
// 修复可选链操作符问题
if (window.mw && mw.config && mw.config.get('wgCanonicalSpecialPageName') === 'Upload') {
var KEY = 'uploadPreference';
var pref = mw.storage.get(KEY);
if (pref === 'wizard') {
window.location.href = mw.util.getUrl('Special:UploadWizard');
return;
}
if (pref === 'classic') return;
function initDialog() {
document.removeEventListener('click', initDialog);
mw.loader.using(['oojs-ui-core', 'oojs-ui-widgets']).then(function() {
var UploadDialog = function() {};
UploadDialog.static = {
name: 'UploadDialog',
title: '请选择上传方式',
actions: [{ action: 'classic', label: '❌ 传统方式', flags: ['safe'] }]
};
UploadDialog.prototype.initialize = function() {
OO.ui.ProcessDialog.prototype.initialize.apply(this, arguments);
this._remember = new OO.ui.CheckboxInputWidget();
var wizardBtn = new OO.ui.ButtonWidget({
label: '✅ 上传向导',
flags: ['primary'],
href: mw.util.getUrl('Special:UploadWizard'),
target: '_self'
});
wizardBtn.on('click', function() {
if (this._remember.isSelected()) {
mw.storage.set(KEY, 'wizard');
}
}.bind(this));
var $body = this.$body;
$body.append(
$('<p>').text('请选择上传方式:'),
wizardBtn.$element,
new OO.ui.FieldLayout(this._remember, {
label: '记住选择',
align: 'inline'
}).$element
);
};
UploadDialog.prototype.getActionProcess = function(action) {
if (action === 'classic') {
if (this._remember.isSelected()) {
mw.storage.set(KEY, 'classic');
}
return new OO.ui.Process(function() {
this.close();
}.bind(this));
}
return OO.ui.ProcessDialog.prototype.getActionProcess.apply(this, arguments);
};
var wm = new OO.ui.WindowManager();
document.body.appendChild(wm.$element);
wm.addWindows([new UploadDialog()]);
wm.openWindow('UploadDialog');
});
}
document.addEventListener('click', initDialog);
}
/**********************
* 模块 3:加载指示器
**********************/
var LoadingIndicator = (function () {
var defaultConfig = {
imageUrl: 'https://wiki.ottohub.cn/images/0/02/Loading.png',
position: { bottom: '20px', right: '20px' },
size: '256px',
timeout: 15000,
zIndex: '99999',
fadeDuration: 300
};
var indicator = null;
var timerId = null;
var currentConfig = Object.assign({}, defaultConfig);
function createIndicator() {
var div = document.createElement('div');
div.style.position = 'fixed';
div.style.width = currentConfig.size;
div.style.height = currentConfig.size;
div.style.bottom = currentConfig.position.bottom;
div.style.right = currentConfig.position.right;
div.style.zIndex = currentConfig.zIndex;
div.style.background = 'url(\'' + currentConfig.imageUrl + '\') center/contain no-repeat';
div.style.opacity = '0';
div.style.transition = 'opacity ' + currentConfig.fadeDuration + 'ms';
div.style.pointerEvents = 'none';
return div;
}
function show() {
if (indicator) return;
indicator = createIndicator();
document.body.appendChild(indicator);
setTimeout(function() {
indicator.style.opacity = '1';
}, 10);
timerId = setTimeout(hide, currentConfig.timeout);
}
function hide() {
if (!indicator) return;
indicator.style.opacity = '0';
setTimeout(function() {
if (indicator && indicator.parentNode) {
indicator.parentNode.removeChild(indicator);
}
indicator = null;
}, currentConfig.fadeDuration);
clearTimeout(timerId);
}
function updateConfig(newConfig) {
currentConfig = Object.assign({}, defaultConfig, newConfig);
}
document.addEventListener('DOMContentLoaded', show);
window.addEventListener('load', hide);
return {
show: show,
hide: hide,
updateConfig: updateConfig
};
})();