跳转到内容

MediaWiki:Gadget-AdvancedSiteNotices.js

维基百科,自由的百科全书

这是本页的一个历史版本,由Shizhao留言 | 贡献2025年1月27日 (一) 10:59编辑。这可能和当前版本存在着巨大的差异。

注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/*  __________________________________________________________________________
 * |                                                                          |
 * |                  === WARNING: GLOBAL GADGET FILE ===                     |
 * |                Changes to this page affect many users.                   |
 * | Please discuss changes on the talk page or on [[WP:VPT]] before editing. |
 * |__________________________________________________________________________|
 *
 * Advanced Site Notices
 * Allow to custom dynamic site notices
 * Maintainer: [[User:PhiLiP]]
 */

$(() => {
    if (window.closeASNForever || $('#siteNotice').length < 0 || mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit') {
        return;
    }

    const { conv } = require('ext.gadget.HanAssist');

    let customASNInterval = window.customASNInterval || 15;
    const COOKIE_NAME = 'dismissASN';
    let cookieVal = parseInt($.cookie(COOKIE_NAME) || '-1');
    let revisionId = 0;
    let timeoutId = null;

    let $asnRoot = $('<div>', { id: 'asn-dismissable-notice' });
    let $asnBody = $('<div>', { id: 'advancedSiteNotices', class: 'mw-parser-output' });
    let $asnClose = $('<button>', {
        title: conv({ hans: '关闭', hant: '關閉' }),
        'aria-label': conv({ hans: '关闭', hant: '關閉' }),
        class: 'asn-close-button',
    });

    $asnRoot.append($asnBody, $asnClose);
    $asnClose.click(() => {
    	$asnClose.prop('disabled', true);
        $.cookie(COOKIE_NAME, revisionId, {
            expires: 30,
            path: '/',
            secure: true
        });
        clearTimeout(timeoutId);
        $asnRoot.fadeOut(() => {
        	$asnRoot.remove();
        });
    });

    let $nts = null;
    let styles = [];

    function matchCriteria(nt) {
        let cache = nt.data('asn-cache');
        if (cache !== undefined) {
            return cache;
        }
        let criteria = nt.attr('data-asn-criteria');
        if (criteria === undefined) {
            criteria = nt.attr('class') ? 'false' : 'true';
            if (nt.hasClass('only_sysop')) {
                criteria += '||in_group("sysop")';
            }
            if (nt.hasClass('only_logged')) {
                criteria += '||in_group("user")';
            }
            if (nt.hasClass('only_anon')) {
                criteria += '||!in_group("user")';
            }
            if (nt.hasClass('only_zh_cn')) {
                criteria += '||only_for("zh-cn")';
            }
            if (nt.hasClass('only_zh_hk')) {
                criteria += '||only_for("zh-hk")';
            }
            if (nt.hasClass('only_zh_sg')) {
                criteria += '||only_for("zh-sg")';
            }
            if (nt.hasClass('only_zh_tw')) {
                criteria += '||only_for("zh-tw")';
            }
        } else {
            criteria = decodeURIComponent(criteria.replace(/\+/g, '%20'));
            criteria = criteria.trim();
        }
        if (criteria === '') {
            criteria = 'true';
        }

        function testCriteria() {
            let in_country = function (country) {
                return window.Geo === undefined || Geo.country === country;
            },
                in_region = function (region) {
                    return window.Geo === undefined || Geo.region === region;
                },
                in_city = function (city) {
                    return window.Geo === undefined || Geo.city === city;
                },
                in_group = function (group) {
                    return $.inArray(group, mw.config.get('wgUserGroups')) > -1;
                },
                only_for = function (userlang) {
                    return userlang === mw.config.get('wgUserLanguage');
                };
            // FIXME: This shouldn't be using eval on data entered in wikitext. If that data is malformed it will throw an exception e.g. criteria = "(false))"
            try {
                return eval(criteria);
            } catch (e) {
                return false;
            }
        }
        cache = testCriteria();

        nt.data('asn-cache', cache);
        return cache;
    }

    let isSetMinHeightCalled = false;

    /**
     * Set ASN's height to be the maximum of all entries to prevent massive layout shift when shuffling.
     */
    function setMinHeight() {
        if (!$nts) {
            return;
        }

        $asnRoot.css({
            'min-height': '',
        });

        let minHeight = -1;
        $nts.each((_, nt) => {
            let $nt = $(nt);
            $asnBody.replaceWith($nt);
            minHeight = Math.max(minHeight, $nt.height());
            $nt.replaceWith($asnBody);
        });

        $asnRoot.css({
            'min-height': `${minHeight}px`,
        });

        if (!isSetMinHeightCalled) {
            isSetMinHeightCalled = true;
            window.addEventListener('resize', mw.util.debounce(setMinHeight, 300));
        }
    }

    function loadNotices(pos) {
        if (!$asnRoot.length) {
            return;
        }

        let nt = null;
        let rt = 0;

        while (rt++ < $nts.length) {
            nt = $($nts[pos]);
            if (matchCriteria(nt)) {
                break;
            }
            pos = (pos + 1) % $nts.length;
        }

        if (rt >= $nts.length) {
            return;
        }

        if (typeof nt.data('asn-style') === 'string') {
            let style = mw.util.addCSS(decodeURIComponent(nt.data('asn-style').replace(/\+/g, '%20')));
            nt.data('asn-style', null);
            nt.data('asn-style-id', styles.length);
            style.disabled = true;
            styles.push(style);
        }
        if (typeof nt.data('asn-html') === 'string') {
            nt.data('asn-html-raw', decodeURIComponent(nt.data('asn-html').replace(/\+/g, '%20')));
            nt.data('asn-html', null);
        }

        let styleId = nt.data('asn-style-id');
        nt = nt.data('asn-html-raw') || nt.html();
        let asnBodyHtml = $asnBody.html();
        if (asnBodyHtml) {
            if (asnBodyHtml !== nt) {
                $asnBody.stop().fadeOut(() => {
                    styles.forEach((style) => {
                        style.disabled = true;
                    })
                    if (styles[styleId]) {
                        styles[styleId].disabled = false;
                    }
                    $asnBody.html(nt);
                    // animation try /catched to avoid TypeError: (Animation.tweeners[prop]||[]).concat is not a function error being seen in production
                    try {
                        $asnBody.fadeIn();
                    } catch (e) { }
                });
            }
        } else if (revisionId === cookieVal) {
            return;
        } else {
            $.cookie(COOKIE_NAME, null);
            $asnRoot.appendTo($('#siteNotice'));
            if (styles[styleId]) {
                styles[styleId].disabled = false;
            }
            setMinHeight();
            $asnBody.html(nt).fadeIn();
        }

        timeoutId = setTimeout(() => {
            loadNotices((pos + 1) % $nts.length);
        }, customASNInterval * 1000);
    }

    new mw.Api({
        ajax: {
            headers: {
                'Api-User-Agent': 'w:zh:MediaWiki:Gadget-AdvancedSiteNotices.js'
            }
        }
    }).get({
        page: 'Template:AdvancedSiteNotices/ajax',
        variant: mw.config.get('wgUserVariant'),
        prop: 'text',
        action: 'parse',
        format: 'json',
        maxage: 3600,
        smaxage: 3600
    }).then((json) => {
        if (!json || !json.parse || !json.parse.text || !json.parse.text['*']) return;
        let $json = $('<div>').html(json.parse.text['*']).find('ul.sitents');
        $nts = $('li', $json);
        revisionId = $json.data('asn-version');

        loadNotices(Math.floor(Math.random() * $nts.length));
    }).catch((e) => {
        console.error('[AdvancedSiteNotices]: error ', e);
    });
});