打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

MediaWiki:Gadget-site-js.js

MediaWiki界面页面
棍牧典留言 | 贡献2025年6月21日 (六) 08:14的版本

注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
/********************** 
 * 模块 0:vConsole 加载(移动端专用)
 **********************/
// 检测是否为移动设备
function isMobileDevice() {
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}

if (isMobileDevice() && !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 = () => {
    try {
      new VConsole();
    } catch (e) {
      alert('调试工具初始化失败,请重试或联系管理员');
      console.error('vConsole init error:', e);
    }
  };
  
  vConsoleScript.onerror = () => {
    alert('调试工具加载失败,请检查网络连接');
    console.error('vConsole failed to load');
  };
  
  // 添加到 body 底部确保不阻塞渲染
  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(c => c + c).join('');
    if (hex.length !== 6) return '0, 0, 0';
    const [r, g, b] = [0, 2, 4].map(i => parseInt(hex.substring(i, i + 2), 16));
    return `${r}, ${g}, ${b}`;
  }

  function update() {
    const root = document.documentElement;
    const hex = getComputedStyle(root).getPropertyValue(OBS_VAR).trim();
    const rgb = parseHex(hex || '#000');
    if (rgb !== cachedRgb) {
      root.style.setProperty('--background-color-rgb', rgb);
      cachedRgb = rgb;
    }
  }

  update();
  const mo = new MutationObserver(update);
  mo.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] });

  return {
    destroy() { mo.disconnect(); }
  };
})();

/**********************
 * 模块 2:上传页引导弹窗
 **********************/
if (mw?.config?.get('wgCanonicalSpecialPageName') === 'Upload') {
  const KEY = 'uploadPreference';
  const pref = mw.storage.get(KEY);

  if (pref === 'wizard') window.location = mw.util.getUrl('Special:UploadWizard');
  if (pref === 'classic') ;

  document.addEventListener('click', function initDialog() {
    document.removeEventListener('click', initDialog);
    mw.loader.using(['oojs-ui-core', 'oojs-ui-widgets']).then(() => {
      class UploadDialog extends OO.ui.ProcessDialog {
        static name = 'UploadDialog';
        static title = '请选择上传方式';
        static actions = [{ action: 'classic', label: '❌ 传统方式', flags: ['safe'] }];

        initialize() {
          super.initialize();
          this._remember = new OO.ui.CheckboxInputWidget();
          const wizardBtn = new OO.ui.ButtonWidget({
            label: '✅ 上传向导',
            flags: ['primary'],
            href: mw.util.getUrl('Special:UploadWizard'),
            target: '_self'
          });
          wizardBtn.on('click', () => {
            if (this._remember.isSelected()) mw.storage.set(KEY, 'wizard');
          });
          this.$body.append(
            $('<p>').text('请选择上传方式:'),
            wizardBtn.$element,
            new OO.ui.FieldLayout(this._remember, { label: '记住选择', align: 'inline' }).$element
          );
        }

        getActionProcess(action) {
          if (action === 'classic') {
            if (this._remember.isSelected()) mw.storage.set(KEY, 'classic');
            return new OO.ui.Process(() => this.close());
          }
          return super.getActionProcess(action);
        }
      }

      const wm = new OO.ui.WindowManager();
      document.body.appendChild(wm.$element);
      wm.addWindows([new UploadDialog()]);
      wm.openWindow('UploadDialog');
    });
  });
}

/**********************
 * 模块 3:加载指示器
 **********************/
const LoadingIndicator = (function () {
  const defaultConfig = {
    imageUrl: 'https://wiki.ottohub.cn/images/0/02/Loading.png',
    position: { bottom: '20px', right: '20px' },
    size: '256px',
    timeout: 15000,
    zIndex: '99999',
    fadeDuration: 300
  };

  let indicator = null;
  let timerId = null;
  let currentConfig = { ...defaultConfig };

  function createIndicator() {
    const div = document.createElement('div');
    div.style.cssText = `
      position: fixed;
      width: ${currentConfig.size};
      height: ${currentConfig.size};
      bottom: ${currentConfig.position.bottom};
      right: ${currentConfig.position.right};
      z-index: ${currentConfig.zIndex};
      background: url('${currentConfig.imageUrl}') center/contain no-repeat;
      opacity: 0;
      transition: opacity ${currentConfig.fadeDuration}ms;
      pointer-events: none;
    `;
    return div;
  }

  function show() {
    if (indicator) return;
    
    indicator = createIndicator();
    document.body.appendChild(indicator);
    
    setTimeout(() => {
      indicator.style.opacity = '1';
    }, 10);
    
    timerId = setTimeout(hide, currentConfig.timeout);
  }

  function hide() {
    if (!indicator) return;
    
    indicator.style.opacity = '0';
    setTimeout(() => {
      indicator.remove();
      indicator = null;
    }, currentConfig.fadeDuration);
    
    clearTimeout(timerId);
  }

  function updateConfig(newConfig) {
    currentConfig = { ...defaultConfig, ...newConfig };
  }

  document.addEventListener('DOMContentLoaded', show);
  window.addEventListener('load', hide);

  return {
    show,
    hide,
    updateConfig
  };
})();