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

出自Quickpedia wiki
無編輯摘要
無編輯摘要
第1行: 第1行:
/**
/**
  * 所有用戶在加載任何頁面時,這裡的JavaScript都會加載
  * MediaWiki:Common.js(強化完整版)
* 功能:
* - 語言切換(簡 / 繁)
* - 自動暫存(24小時)
* - 深色模式
* - 右上角時鐘
  */
  */


mw.log.deprecate(window, 'JSConfig', {});
mw.loader.using(['mediawiki.util', 'mediawiki.Uri']).then(function () {


mw.loader.using(['ext.gadget.site-lib', 'mediawiki.util']).then(function() {
    $(function () {


    if (mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' || mw.config.get('wgCanonicalSpecialPageName') === 'Search') {
        /* =========================
        /* scripts specific to editing pages */
        * ① 語言切換(簡 / 繁)
         importScript('MediaWiki:Common.js\/edit.js');
        * ========================= */
    } else {
 
        mw.loader.using('ext.visualEditor.desktopArticleTarget.init', function() {
         var variants = [
             mw.libs.ve.addPlugin(function() {
            { code: 'zh-tw', label: '繁體' },
                importScript('MediaWiki:Common.js\/edit.js');
             { code: 'zh-cn', label: '简体' }
            });
         ];
         });
    }


    /**
        var current =
    * Helper script for.hlist class in Common.css
            mw.config.get('wgUserVariant') ||
    * Add pseudo-selector class to last-child list items in IE8
            mw.util.getParamValue('variant') ||
    * @source mediawiki.org/wiki/Snippets/Horizontal_lists
             'zh-tw';
    * @revision 6 (2014-08-23)
    * @author [[User:Edokter]]
    */
    var profile = $.client.profile();
    if (profile.name === 'msie' && profile.versionNumber === 8) {
        mw.hook('wikipage.content').add(function($content) {
             $content.find('.hlist').find('dd:last-child, dt:last-child, li:last-child').addClass('hlist-last-child');
        });
    }


    /* 避免在主條目的註腳中出現捲軸框 */
         var $langMenu = $('<span>').css({
    if (!mw.config.get('wgCanonicalNamespace')) {
            marginLeft: '10px',
         $(function() {
            fontWeight: 'bold'
            $('div#mw-content-text ol.references').each(function() {
                var needobjs=[], $curobj=$(this);
                do {
                    $curobj=$curobj.parent();
                    if (!$curobj) break;
                    if ($curobj.attr('id') === 'mw-content-text' || $curobj.prop('tagName').toLowerCase() === 'body') break;
                    if ($curobj.css('overflow').match(/(?: auto|scroll)/i) || $curobj.css('overflow-x').match(/(?:auto|scroll)/i) || $curobj.css('overflow-y').match(/(?:auto|scroll)/i)) {
                        /* null */
                    } else continue;
                    if ((''+$curobj.attr('class')).split(' ').indexOf('noprint') >= 0) return;
                    needobjs.push($curobj.get(0));
                } while (true);
                $(needobjs)
                  .css('overflow', 'visible')
                  .css('overflow-x', 'visible')
                  .css('overflow-y', 'visible')
                  .css('border', '')
                  .css('height', '')
                  .css('max-height', '');
            });
         });
         });
    }


    /**
        variants.forEach(function (v, i) {
    * metaBox
             var $link = $('<a>')
    * Funcionament de la Plantilla:Metacaixa
                .text(v.label)
    * Implementat per: Usuari:Peleguer.
                .css({
    * Actualitzat per Joanjoc seguint les indicacions d'en Martorell
                    cursor: 'pointer',
    */
                    margin: '0 4px',
    function MetaCaixaInit() {
                    color: v.code === current ? '#000' : '#0645ad',
        // S'executa al carregar-se la pàgina, si hi ha metacaixes,
                    textDecoration: v.code === current ? 'underline' : 'none'
        // s'assignen els esdeveniments als botons
                })
        //alert('MetaCaixaInit');
                .on('click', function () {
        var i = 0; // Inicialitzem comptador de caixes
                    var url = new mw.Uri(window.location.href);
        for (i = 0; i <= 9; i++) {
                    url.query.variant = v.code;
             var vMc = document.getElementById('mc' + i);
                    window.location.href = url.toString();
            if (!vMc) break;
                 });
            //alert('MetaCaixaInit, trobada Metacaixa mc' + i);
            var j = 1, // Inicialitzem comptador de botons dins de la caixa
                vPsIni = 0; // Pestanya visible inicial
            for (j = 1; j <= 9; j++) {
                var vBt = document.getElementById('mc' + i + 'bt' + j);
                if (!vBt) break;
                //alert('MetaCaixaInit, trobat botó mc' + i + 'bt' + j);
                vBt.onclick = MetaCaixaMostraPestanya; // A cada botó assignem l'esdeveniment onclick
                //alert(vBt.className);
                if (vBt.className === 'mcBotoSel') vPsIni = j; // Si tenim un botó seleccionat, en guardem l'index
            }
            //alert('mc=' + i + ', ps=' + j + ', psini=' + vPsIni);
            if (vPsIni === 0) { // Si no tenim cap botó seleccionat, n'agafem un aleatòriament
                vPsIni = 1 + Math.floor((j - 1) * Math.random());
                //alert('Activant Pestanya a l\'atzar; _mc' + i + 'bt' + vPsIni + '_');
                try {
                document.getElementById('mc' + i + 'ps' + vPsIni).style.display = 'block';
            document.getElementById('mc' + i + 'ps' + vPsIni).style.visibility = 'visible';
            document.getElementById('mc' + i + 'bt' + vPsIni).className = 'mcBotoSel';
                 } catch(e) {
                // TypeError: null is not an object (evaluating 'document.getElementById('mc'+i+'ps'+vPsIni).style')
                }
            }
        }
    }


    function MetaCaixaMostraPestanya() {
             $langMenu.append($link);
        // S'executa al clicar una pestanya,
             if (i < variants.length - 1) {
        // aquella es fa visible i les altres s'oculten
                 $langMenu.append(' / ');
        var vMcNom = this.id.substr(0, 3), // A partir del nom del botó, deduïm el nom de la caixa
             vIndex = this.id.substr(5, 1), // I l'index
            i = 1;
        for (i = 1; i <= 9; i++) { // busquem totes les pestanyes d'aquella caixa
            //alert(vMcNom + 'ps' + i);
            var vPsElem = document.getElementById(vMcNom + 'ps' + i);
             if (!vPsElem) break;
            if (vIndex == i) { // Si és la pestanya bona la mostrem i canviem la classe de botó
                vPsElem.style.display = 'block';
                vPsElem.style.visibility = 'visible';
                document.getElementById(vMcNom + 'bt' + i).className = 'mcBotoSel';
            } else { // Sinó, l'ocultem i canviem la classe de botó
                 vPsElem.style.display = 'none';
                vPsElem.style.visibility = 'hidden';
                document.getElementById(vMcNom + 'bt' + i).className = 'mcBoto';
            }
        }
        return false; // evitem la recàrrega de la pàgina
    }
    $(MetaCaixaInit);
 
    if (!+mw.user.options.get('discussiontools-newtopictool') ||!+mw.user.options.get('discussiontools-betaenable')) {
        /* 智能讨论页编辑(新建) */
        $(function() {
            var catalk = $('#ca-talk');
            if (catalk.hasClass('new') && mw.config.get('wgNamespaceNumber')!= 2) {
                var a = $('a:first', catalk);
                a.attr('href', a.attr('href') + '&section=new');
             }
             }
         });
         });
    }


    /**
         mw.util.addPortletLink(
    * Magic editintros
             'p-personal',
    * Description: Adds editintros on disambiguation pages, BLP pages, policy pages and guidlines.
            '#',
    * Maintainers: [[User:RockMFR]]
             $langMenu.prop('outerHTML'),
    */
             'pt-lang-switch',
    function addEditIntro(name) {
             '語言切換'
         $('.mw-editsection, #ca-edit').find('a').each(function(i, el) {
         );
             el.href = $(this).attr('href') + '&editintro=' + name;
        });
    }
    if (mw.config.get('wgNamespaceNumber') === 0) {
        $(function() {
             if (document.getElementById('disambigbox')) addEditIntro('Template:Disambig_editintro');
        });
        $(function() {
            var cats = mw.config.get('wgCategories');
            if (!cats) return;
             if ($.inArray('在世人物', cats)!== -1) addEditIntro('Template:BLP_editintro');
            if (cats.some(function(cat){return /\d{4}年台灣電視劇集/.test(cat)})) addEditIntro('Template:TVdrama_editintro');
        });
    } else if (mw.config.get('wgNamespaceNumber') === 4) {
        $(function() {
             var cats = mw.config.get('wgCategories');
            if (!cats) return;
            if ($.inArray('維基百科方針與指引完整列表', cats)!== -1) addEditIntro('Template:Policy editintro');
         });
    }


    /**
    * &withCSS= and &withJS= URL parameters
    * Allow to try custom scripts from MediaWiki space
    * without editing personal.css or.js files
    * @source www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
    * @rev 6
    */
    var extraCSS = mw.util.getParamValue('withCSS'),
        extraJS = mw.util.getParamValue('withJS');
    if (extraCSS) {
        if (extraCSS.match(/^MediaWiki:[^&<>=%#]*\.css$/)) {
            importStylesheet(extraCSS);
        } else {
            mw.notify('只允许从MediaWiki命名空间加载。', {title: '无效的withCSS值'});
        }
    }
    if (extraJS) {
        if (extraJS.match(/^MediaWiki:[^&<>=%#]*\.js$/)) {
            importScript(extraJS);
        } else {
            mw.notify('只允许从MediaWiki命名空间加载。', {title: '无效的withJS值'});
        }
    }


    /* 页面历史加&hilight=高亮 */
        /* =========================
    var hilight = mw.util.getParamValue('hilight');
        * ② 深色模式
    if (mw.config.get('wgAction') === 'history' && hilight) {
        * ========================= */
        $.each(hilight.split(','), function(_, v) {
            $('input[name=oldid][value=' + v + ']').parent().addClass('not-patrolled');
        });
    }


    /* Main page hacks */
        var darkBtn = mw.util.addPortletLink(
    if (mw.config.get('wgIsMainPage') && mw.config.get('wgAction') === 'view') {
            'p-personal',
        /* Remove red links */
            '#',
        $('#mw-content-text a.new').contents().unwrap();
            '深色模式',
    }
            'pt-darkmode'
});
        );


$(function() {
        $(darkBtn).on('click', function (e) {
    /* 修正摺疊後定位變化 */
            e.preventDefault();
    if (location.hash) location.href = location.hash;
            $('body').toggleClass('dark-mode');


    /* 引用錯誤標籤名字解碼 */
            var isDark = $('body').hasClass('dark-mode');
    $('.anchordecodeme').each(function() {
            localStorage.setItem('dark-mode', isDark ? '1' : '0');
        $(this).text(decodeURIComponent($(this).text().replace(/\.([0-9A-F]{2})/g, '%$1')));
        });
    });


    /* Check for any client-side simplified/traditional Chinese conversion */
        if (localStorage.getItem('dark-mode') === '1') {
    /* This routine must be placed here to make sure the field is inserted in time */
            $('body').addClass('dark-mode');
    $('#antispam-container').append(
         }
        $('<input type="text" />').attr({
            id: 'wpAntiConv',
            value: '\u6c49\u6f22'
         })
    );


});


// per [[Special:Diff/64919534/64925950]],展开折叠按钮的颜色
        /* =========================
$(function collapseButtonColor() {
        * ③ 右上角時鐘
    var $toggle = $('.mw-collapsible-toggle');
        * ========================= */
    if ($toggle.length > 0) {
        if ($toggle.parent()[0].style.color) $toggle.find('a').css('color', 'inherit');
    }
});


if (mw.config.get('wgUserName') === null) {
        function updateClock() {
mw.loader.load('ext.gadget.preserve-variant');
            var now = new Date();
}
            return now.toLocaleTimeString('zh-TW', { hour12: false });
(function() {
        }
    function showClock() {
        var now = new Date();
        return now.toLocaleTimeString('zh-TW', { hour12: false });
    }


    function insertClock() {
        var $clock = $('<span>')
        if (document.getElementById('mw-header-clock')) return;
            .attr('id', 'mw-clock')
            .css({
                marginLeft: '10px',
                fontWeight: 'bold',
                fontFamily: 'monospace'
            })
            .text(updateClock());


         var header = document.querySelector('#mw-panel + #mw-head.vector-user-links')
         $('#p-personal').append($clock);
                    || document.querySelector('#p-personal'); // 找 Vector 右上用戶選單
        if (!header) return;


         var span = document.createElement('span');
         setInterval(function () {
        span.id = 'mw-header-clock';
            $clock.text(updateClock());
        span.style.fontFamily = 'monospace';
         }, 1000);
         span.style.fontWeight = 'bold';
        span.style.marginLeft = '0.5em';
        span.style.color = '#000';
        span.innerText = showClock();


        header.appendChild(span);


         // 每秒更新
         /* =========================
        setInterval(function() {
        * ④ 自動暫存(24小時)
            span.innerText = showClock();
        * ========================= */
        }, 1000);
    }


    mw.loader.using('mediawiki.util', function() {
         if (mw.config.get('wgAction') === 'edit') {
        // 等待頁面元素加載
         document.addEventListener('DOMContentLoaded', insertClock);
        setTimeout(insertClock, 500); // 再保險一次
    });
})();
/**
* 在右上角個人選單中增加「深色模式」切換按鈕
* 插入位置:偏好設定 (pt-preferences) 之後
*/
mw.loader.using('mediawiki.util').then(function() {
    $(function() {
        // 1. 建立選單項目
        var portletLink = mw.util.addPortletLink(
            'p-personal', // 目標:個人選單
            '#', // 連結路徑
            '切換深色模式', // 顯示文字
            'pt-darkmode', // 項目 ID
            '開啟或關閉深色模式', // 懸停提示
            '', // 快捷鍵
            '#pt-watchlist' // 插入在「監視清單」之前 = 「偏好設定」之後
        );


        // 2. 定義點擊後的動作
             var interval = 600000; // 10分鐘
        $(portletLink).on('click', function(e) {
             var expire = 24 * 60 * 60 * 1000;
             e.preventDefault();
           
            // 這裡假設您是透過切換 <body> 的 class 來實現深色模式
            // 如果您是使用特定的 Darkmode 擴展,請將下方邏輯換成該擴展的 API
            $('body').toggleClass('dark-mode-active');
           
            // 存儲狀態到本地,讓重新整理後依然有效
             var isDark = $('body').hasClass('dark-mode-active');
            localStorage.setItem('user-dark-mode', isDark? 'on' : 'off');
        });


        // 3. 頁面加載時檢查之前的設定
            function getKey() {
        if (localStorage.getItem('user-dark-mode') === 'on') {
                return 'autosave_' + mw.config.get('wgPageName');
            $('body').addClass('dark-mode-active');
            }
        }
    });
});


// 沒登入的訪客自動切換成 zh,修正版
            setInterval(function () {
// 只在 view 頁面、特殊頁面排除登入頁,避免無限跳轉
                var text = $('#wpTextbox1').val();
mw.loader.using('mediawiki.util', function() {
                if (!text) return;
    var isAnon = mw.config.get('wgUserName') === null;
    var isView = mw.config.get('wgAction') === 'view';
    var noUselang =!mw.util.getParamValue('uselang');
    var notLoginPage = mw.config.get('wgCanonicalSpecialPageName')!== 'Userlogin';
    var notCreateAccount = mw.config.get('wgCanonicalSpecialPageName')!== 'CreateAccount';


    if (isAnon && isView && noUselang && notLoginPage && notCreateAccount) {
                var data = {
        var newUrl = new URL(location.href);
                    value: text,
        newUrl.searchParams.set('uselang', 'zh-tw');
                    time: Date.now()
        window.location.replace(newUrl.toString());
                };
    }
});
mw.loader.using(['mediawiki.storage', 'mediawiki.util'], function () {
    var interval = 600000; // 每10分鐘存一次(可自行調整)
    var expireTime = 24 * 60 * 60 * 1000; // 24小時(毫秒)


    setInterval(function () {
                 localStorage.setItem(getKey(), JSON.stringify(data));
        var text = $('#wpTextbox1').val();
                console.log('已自動暫存');
        if (text) {
            }, interval);
            var data = {
                 value: text,
                time: Date.now()
            };
            localStorage.setItem('wiki_autosave', JSON.stringify(data));
            console.log('已自動暫存(24小時有效)');
        }
    }, interval);


    $(document).ready(function () {
            var saved = localStorage.getItem(getKey());
        var saved = localStorage.getItem('wiki_autosave');


        if (saved) {
            if (saved) {
            try {
                try {
                var data = JSON.parse(saved);
                    var data = JSON.parse(saved);
                var now = Date.now();
                    if (Date.now() - data.time < expire) {
 
                        if (!$('#wpTextbox1').val()) {
                if ((now - data.time) < expireTime) {
                            $('#wpTextbox1').val(data.value);
                    if (!$('#wpTextbox1').val()) {
                            console.log('已還原暫存');
                        $('#wpTextbox1').val(data.value);
                        }
                        console.log('已還原暫存(未過期)');
                    } else {
                        localStorage.removeItem(getKey());
                     }
                     }
                 } else {
                 } catch (e) {}
                    localStorage.removeItem('wiki_autosave');
                    console.log('暫存已過期(超過24小時)');
                }
            } catch (e) {
                console.log('暫存資料錯誤');
             }
             }
         }
         }
    });
});
mw.loader.using('mediawiki.util', function () {
    var portlet = mw.util.addPortletLink(
        'p-personal',
        '#',
        '简 / 繁',
        'ca-lang-switch'
    );


    $(portlet).on('click', function () {
        var current = mw.config.get('wgUserVariant');
        var target = current === 'zh-tw' ? 'zh-cn' : 'zh-tw';


         var url = new mw.Uri(window.location.href);
         /* =========================
        url.query.variant = target;
        * ⑤ 訪客預設語言(不干擾轉換)
        * ========================= */
 
        var isAnon = mw.config.get('wgUserName') === null;
 
        if (isAnon && !mw.util.getParamValue('variant')) {
            var url = new mw.Uri(window.location.href);
            url.query.variant = 'zh-tw';
            window.location.replace(url.toString());
        }


        window.location.href = url.toString();
     });
     });
});
});

於 2026年4月25日 (六) 06:18 的修訂

/**
 * MediaWiki:Common.js(強化完整版)
 * 功能:
 * - 語言切換(簡 / 繁)
 * - 自動暫存(24小時)
 * - 深色模式
 * - 右上角時鐘
 */

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

    $(function () {

        /* =========================
         * ① 語言切換(簡 / 繁)
         * ========================= */

        var variants = [
            { code: 'zh-tw', label: '繁體' },
            { code: 'zh-cn', label: '简体' }
        ];

        var current =
            mw.config.get('wgUserVariant') ||
            mw.util.getParamValue('variant') ||
            'zh-tw';

        var $langMenu = $('<span>').css({
            marginLeft: '10px',
            fontWeight: 'bold'
        });

        variants.forEach(function (v, i) {
            var $link = $('<a>')
                .text(v.label)
                .css({
                    cursor: 'pointer',
                    margin: '0 4px',
                    color: v.code === current ? '#000' : '#0645ad',
                    textDecoration: v.code === current ? 'underline' : 'none'
                })
                .on('click', function () {
                    var url = new mw.Uri(window.location.href);
                    url.query.variant = v.code;
                    window.location.href = url.toString();
                });

            $langMenu.append($link);
            if (i < variants.length - 1) {
                $langMenu.append(' / ');
            }
        });

        mw.util.addPortletLink(
            'p-personal',
            '#',
            $langMenu.prop('outerHTML'),
            'pt-lang-switch',
            '語言切換'
        );


        /* =========================
         * ② 深色模式
         * ========================= */

        var darkBtn = mw.util.addPortletLink(
            'p-personal',
            '#',
            '深色模式',
            'pt-darkmode'
        );

        $(darkBtn).on('click', function (e) {
            e.preventDefault();
            $('body').toggleClass('dark-mode');

            var isDark = $('body').hasClass('dark-mode');
            localStorage.setItem('dark-mode', isDark ? '1' : '0');
        });

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


        /* =========================
         * ③ 右上角時鐘
         * ========================= */

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

        var $clock = $('<span>')
            .attr('id', 'mw-clock')
            .css({
                marginLeft: '10px',
                fontWeight: 'bold',
                fontFamily: 'monospace'
            })
            .text(updateClock());

        $('#p-personal').append($clock);

        setInterval(function () {
            $clock.text(updateClock());
        }, 1000);


        /* =========================
         * ④ 自動暫存(24小時)
         * ========================= */

        if (mw.config.get('wgAction') === 'edit') {

            var interval = 600000; // 10分鐘
            var expire = 24 * 60 * 60 * 1000;

            function getKey() {
                return 'autosave_' + mw.config.get('wgPageName');
            }

            setInterval(function () {
                var text = $('#wpTextbox1').val();
                if (!text) return;

                var data = {
                    value: text,
                    time: Date.now()
                };

                localStorage.setItem(getKey(), JSON.stringify(data));
                console.log('已自動暫存');
            }, interval);

            var saved = localStorage.getItem(getKey());

            if (saved) {
                try {
                    var data = JSON.parse(saved);
                    if (Date.now() - data.time < expire) {
                        if (!$('#wpTextbox1').val()) {
                            $('#wpTextbox1').val(data.value);
                            console.log('已還原暫存');
                        }
                    } else {
                        localStorage.removeItem(getKey());
                    }
                } catch (e) {}
            }
        }


        /* =========================
         * ⑤ 訪客預設語言(不干擾轉換)
         * ========================= */

        var isAnon = mw.config.get('wgUserName') === null;

        if (isAnon && !mw.util.getParamValue('variant')) {
            var url = new mw.Uri(window.location.href);
            url.query.variant = 'zh-tw';
            window.location.replace(url.toString());
        }

    });

});