「MediaWiki:Common.js」:修訂間差異

出自Quickpedia wiki
無編輯摘要
無編輯摘要
第1行: 第1行:
/**
/**
  * MediaWiki:Common.js 強化完整版
  * MediaWiki:Common.js 強化完整版
  * 適用對象:維基家族 wiki
  * 適用對象:維基家族 wiki / Quickpedia
  * 功能:語言切換、自動暫存、深色模式、右上角時鐘
  * 功能:語系導向、簡繁手動修正、自動暫存(防斷線)、深色模式、即時時鐘
  */
  */


第10行: 第10行:


         /* ============================================================
         /* ============================================================
         * ① 語系自動導向與切換 (針對訪客預設 zh-tw)
         * ① 語系自動導向與切換
         * ============================================================ */
         * ============================================================ */
         var isAnon = mw.config.get('wgUserName') === null;
         var isAnon = mw.config.get('wgUserName') === null;
         var currentVariant = mw.util.getParamValue('variant');
         var currentVariant = mw.util.getParamValue('variant') || mw.config.get('wgUserVariant');


         // 如果是訪客且網址沒帶語系參數,自動導向繁體中文 (避免搜尋引擎抓到英文版)
         // 訪客預設導向繁體中文 (zh-tw)
         if (isAnon && !currentVariant && mw.config.get('wgAction') === 'view') {
         if (isAnon && !currentVariant && mw.config.get('wgAction') === 'view') {
             var url = new mw.Uri(window.location.href);
             var url = new mw.Uri(window.location.href);
第29行: 第29行:
         ];
         ];


         var $langMenu = $('<span>').css({ marginLeft: '10px', fontSize: '0.9em' });
         var $langContainer = $('<span>').attr('id', 'custom-variant-switches');
         variants.forEach(function (v, i) {
         variants.forEach(function (v, i) {
             var $link = $('<a>')
             var $link = $('<a>')
第35行: 第35行:
                 .css({
                 .css({
                     cursor: 'pointer',
                     cursor: 'pointer',
                     padding: '0 2px',
                     padding: '0 5px',
                     color: currentVariant === v.code ? '#000' : '#0645ad',
                     color: currentVariant === v.code ? '#000' : '#0645ad',
                     fontWeight: currentVariant === v.code ? 'bold' : 'normal'
                     fontWeight: currentVariant === v.code ? 'bold' : 'normal'
                 })
                 })
                 .on('click', function () {
                 .on('click', function (e) {
                    e.preventDefault();
                     var url = new mw.Uri(window.location.href);
                     var url = new mw.Uri(window.location.href);
                     url.query.variant = v.code;
                     url.query.variant = v.code;
                     window.location.href = url.toString();
                     window.location.href = url.toString();
                 });
                 });
             $langMenu.append($link);
             $langContainer.append($link);
             if (i < variants.length - 1) $langMenu.append('|');
             if (i < variants.length - 1) $langContainer.append('|');
         });
         });


         mw.util.addPortletLink('p-personal', '#', $langMenu.prop('outerHTML'), 'pt-variant-switch', '切換語系', '#pt-logout');
         mw.util.addPortletLink('p-personal', '#', '', 'pt-variant-switch', '切換語系', '#pt-logout');
        $('#pt-variant-switch').append($langContainer);




         /* ============================================================
         /* ============================================================
         * ② 自動暫存功能 (應對 Cloudflare 驗證中斷)
         * ② 手動字詞轉換修正 (針對「維基家族」與 Quickpedia)
        * ============================================================ */
        function applyManualTranslation() {
            var v = mw.util.getParamValue('variant') || mw.config.get('wgUserVariant') || mw.config.get('wgUserLanguage');
            if (v === 'zh-hans' || v === 'zh-cn') {
                // 修正標題與站名
                $('h1#firstHeading, #p-logo-text, .mw-wiki-title, title').each(function() {
                    var t = $(this).text();
                    $(this).text(t.replace(/維基家族/g, '维基家族').replace(/快速百科/g, '快速百科'));
                });
                // 修正自定義按鈕文字
                $('#pt-darkmode a').text('深色模式');
            }
        }
        applyManualTranslation();
 
 
        /* ============================================================
        * ③ 自動暫存功能 (應對 Cloudflare 驗證中斷)
         * ============================================================ */
         * ============================================================ */
         if (['edit', 'submit'].indexOf(mw.config.get('wgAction')) !== -1) {
         if (['edit', 'submit'].indexOf(mw.config.get('wgAction')) !== -1) {
第59行: 第79行:
             var $textbox = $('#wpTextbox1');
             var $textbox = $('#wpTextbox1');


             // 1. 每 30 秒自動存檔一次 (縮短間隔以防 Cloudflare 突然跳出)
             // 每 30 秒自動存檔一次
             setInterval(function () {
             setInterval(function () {
                 var content = $textbox.val();
                 var content = $textbox.val();
                 if (content && content.length > 10) {
                 if (content && content.length > 10) {
                     var cacheData = {
                     localStorage.setItem(storageKey, JSON.stringify({
                         text: content,
                         text: content,
                         timestamp: Date.now()
                         timestamp: Date.now()
                     };
                     }));
                    localStorage.setItem(storageKey, JSON.stringify(cacheData));
                    console.log('草稿已暫存於瀏覽器: ' + new Date().toLocaleTimeString());
                 }
                 }
             }, 30000);  
             }, 30000);  


             // 2. 進入編輯頁面時,檢查是否有未儲存的草稿
             // 檢查是否有草稿
             var savedCache = localStorage.getItem(storageKey);
             var savedCache = localStorage.getItem(storageKey);
             if (savedCache) {
             if (savedCache) {
                 var data = JSON.parse(savedCache);
                 var data = JSON.parse(savedCache);
                // 如果暫存是在 24 小時內,且目前編輯框是空的或只有基礎內容
                 if (Date.now() - data.timestamp < 86400000 && $textbox.val().length < 50) {
                 if (Date.now() - data.timestamp < 86400000 && $textbox.val().length < 50) {
                     var confirmRecover = confirm('偵測到此頁面有未儲存的草稿(可能因 Cloudflare 驗證而中斷),是否還原內容?');
                     if (confirm('偵測到此頁面有未儲存的草稿(可能因 Cloudflare 跳轉而中斷),是否還原內容?')) {
                    if (confirmRecover) {
                         $textbox.val(data.text);
                         $textbox.val(data.text);
                     }
                     }
第85行: 第101行:
             }
             }


             // 3. 按下儲存按鈕後,清除該頁面的暫存
             // 儲存後清除暫存
             $('#wpSave, #wpSaveWidget').on('click', function() {
             $('#wpSave, #wpSaveWidget, input#wpSave').on('click', function() {
                 localStorage.removeItem(storageKey);
                 localStorage.removeItem(storageKey);
             });
             });
第93行: 第109行:


         /* ============================================================
         /* ============================================================
         * ③ 深色模式切換
         * ④ 深色模式切換
         * ============================================================ */
         * ============================================================ */
         var darkBtn = mw.util.addPortletLink('p-personal', '#', '深色模式', 'pt-darkmode', '切換深色/淺色模式');
         var darkBtn = mw.util.addPortletLink('p-personal', '#', '深色模式', 'pt-darkmode', '切換深色模式', '#pt-variant-switch');
         $(darkBtn).on('click', function (e) {
         $(darkBtn).on('click', function (e) {
             e.preventDefault();
             e.preventDefault();
             $('body').toggleClass('dark-mode');
             $('body').toggleClass('dark-mode');
             var isDark = $('body').hasClass('dark-mode');
             localStorage.setItem('wiki-dark-mode', $('body').hasClass('dark-mode') ? '1' : '0');
            localStorage.setItem('wiki-dark-mode', isDark ? '1' : '0');
         });
         });


        // 頁面載入時檢查狀態
         if (localStorage.getItem('wiki-dark-mode') === '1') {
         if (localStorage.getItem('wiki-dark-mode') === '1') {
             $('body').addClass('dark-mode');
             $('body').addClass('dark-mode');
第110行: 第124行:


         /* ============================================================
         /* ============================================================
         * ④ 右上角即時時鐘 (顯示伺服器/本地時間)
         * ⑤ 右上角即時時鐘
         * ============================================================ */
         * ============================================================ */
         var $clock = $('<li>').attr('id', 'pt-clock').css({
         var $clock = $('<li>').attr('id', 'pt-clock').css({
             fontWeight: 'bold',
             fontWeight: 'bold',
            color: '#54595d',
             marginLeft: '10px',
             marginLeft: '10px',
             display: 'inline-block',
             color: '#54595d'
            verticalAlign: 'middle'
         });
         });


         function tick() {
         function updateClock() {
             var now = new Date();
             var now = new Date();
             var timeStr = now.toLocaleTimeString('zh-TW', { hour12: false });
             $clock.text(now.toLocaleTimeString('zh-TW', { hour12: false }));
            $clock.text(timeStr);
         }
         }


         $('#p-personal ul').append($clock);
         $('#p-personal ul').append($clock);
         setInterval(tick, 1000);
         setInterval(updateClock, 1000);
         tick();
         updateClock();


     });
     });
});
});
/* 簡單的手動轉換邏輯範例 */
(function() {
    // 這裡可以載入外部的轉換函式庫,例如引用維基百科的字詞轉換邏輯
    // 或者針對特定按鈕觸發執行
    if (mw.config.get('wgUserLanguage') === 'zh-hans') {
        // 執行轉換邏輯
        applyTranslationToSimplified();
    }
})();

於 2026年4月29日 (三) 03:39 的修訂

/**
 * MediaWiki:Common.js 強化完整版
 * 適用對象:維基家族 wiki / Quickpedia
 * 功能:語系導向、簡繁手動修正、自動暫存(防斷線)、深色模式、即時時鐘
 */

mw.loader.using(['mediawiki.util', 'mediawiki.Uri']).then(function () {

    $(function () {

        /* ============================================================
         * ① 語系自動導向與切換
         * ============================================================ */
        var isAnon = mw.config.get('wgUserName') === null;
        var currentVariant = mw.util.getParamValue('variant') || mw.config.get('wgUserVariant');

        // 訪客預設導向繁體中文 (zh-tw)
        if (isAnon && !currentVariant && mw.config.get('wgAction') === 'view') {
            var url = new mw.Uri(window.location.href);
            url.query.variant = 'zh-tw';
            window.location.replace(url.toString());
            return; 
        }

        // 建立右上角切換按鈕
        var variants = [
            { code: 'zh-tw', label: '繁體' },
            { code: 'zh-cn', label: '简体' }
        ];

        var $langContainer = $('<span>').attr('id', 'custom-variant-switches');
        variants.forEach(function (v, i) {
            var $link = $('<a>')
                .text(v.label)
                .css({
                    cursor: 'pointer',
                    padding: '0 5px',
                    color: currentVariant === v.code ? '#000' : '#0645ad',
                    fontWeight: currentVariant === v.code ? 'bold' : 'normal'
                })
                .on('click', function (e) {
                    e.preventDefault();
                    var url = new mw.Uri(window.location.href);
                    url.query.variant = v.code;
                    window.location.href = url.toString();
                });
            $langContainer.append($link);
            if (i < variants.length - 1) $langContainer.append('|');
        });

        mw.util.addPortletLink('p-personal', '#', '', 'pt-variant-switch', '切換語系', '#pt-logout');
        $('#pt-variant-switch').append($langContainer);


        /* ============================================================
         * ② 手動字詞轉換修正 (針對「維基家族」與 Quickpedia)
         * ============================================================ */
        function applyManualTranslation() {
            var v = mw.util.getParamValue('variant') || mw.config.get('wgUserVariant') || mw.config.get('wgUserLanguage');
            if (v === 'zh-hans' || v === 'zh-cn') {
                // 修正標題與站名
                $('h1#firstHeading, #p-logo-text, .mw-wiki-title, title').each(function() {
                    var t = $(this).text();
                    $(this).text(t.replace(/維基家族/g, '维基家族').replace(/快速百科/g, '快速百科'));
                });
                // 修正自定義按鈕文字
                $('#pt-darkmode a').text('深色模式');
            }
        }
        applyManualTranslation();


        /* ============================================================
         * ③ 自動暫存功能 (應對 Cloudflare 驗證中斷)
         * ============================================================ */
        if (['edit', 'submit'].indexOf(mw.config.get('wgAction')) !== -1) {
            var pageName = mw.config.get('wgPageName');
            var storageKey = 'edit_cache_' + pageName;
            var $textbox = $('#wpTextbox1');

            // 每 30 秒自動存檔一次
            setInterval(function () {
                var content = $textbox.val();
                if (content && content.length > 10) {
                    localStorage.setItem(storageKey, JSON.stringify({
                        text: content,
                        timestamp: Date.now()
                    }));
                }
            }, 30000); 

            // 檢查是否有草稿
            var savedCache = localStorage.getItem(storageKey);
            if (savedCache) {
                var data = JSON.parse(savedCache);
                if (Date.now() - data.timestamp < 86400000 && $textbox.val().length < 50) {
                    if (confirm('偵測到此頁面有未儲存的草稿(可能因 Cloudflare 跳轉而中斷),是否還原內容?')) {
                        $textbox.val(data.text);
                    }
                }
            }

            // 儲存後清除暫存
            $('#wpSave, #wpSaveWidget, input#wpSave').on('click', function() {
                localStorage.removeItem(storageKey);
            });
        }


        /* ============================================================
         * ④ 深色模式切換
         * ============================================================ */
        var darkBtn = mw.util.addPortletLink('p-personal', '#', '深色模式', 'pt-darkmode', '切換深色模式', '#pt-variant-switch');
        $(darkBtn).on('click', function (e) {
            e.preventDefault();
            $('body').toggleClass('dark-mode');
            localStorage.setItem('wiki-dark-mode', $('body').hasClass('dark-mode') ? '1' : '0');
        });

        if (localStorage.getItem('wiki-dark-mode') === '1') {
            $('body').addClass('dark-mode');
        }


        /* ============================================================
         * ⑤ 右上角即時時鐘
         * ============================================================ */
        var $clock = $('<li>').attr('id', 'pt-clock').css({
            fontWeight: 'bold',
            marginLeft: '10px',
            color: '#54595d'
        });

        function updateClock() {
            var now = new Date();
            $clock.text(now.toLocaleTimeString('zh-TW', { hour12: false }));
        }

        $('#p-personal ul').append($clock);
        setInterval(updateClock, 1000);
        updateClock();

    });
});