跳转到内容

MediaWiki:Gadget-usergroup.js:修订间差异

来自萌娘共享
代码变动:103d1a56 - feat: rename (#594) by U:AnnAngela, co-authored-by: GH:github-actions[bot]
标签由机器人或全自动脚本执行的操作
代码变动:103d1a56 - feat: rename (#594) by U:AnnAngela, co-authored-by: GH:github-actions[bot]
标签由机器人或全自动脚本执行的操作
第8行: 第8行:
/* <pre> */
/* <pre> */


"use strict";
"use strict";(async()=>{await $.ready;const t=new LocalObjectStorage("usergroup"),e=[["staff","#198754"],["bureaucrat","#6610f2"],["checkuser","#673ab7"],["suppress","#9c27b0"],["sysop","#ec407a"],["interface-admin","#f55b42"],["patroller","#f77f38"],["honoredmaintainer","#febd45"],["techeditor","#3f51b5"],["file-maintainer","#039be5"],["bot","#1e88e5"],["flood","#1e88e5"],["ipblock-exempt","#29b6f6"],["extendedconfirmed","#57c2c3"],["manually-confirmed","#009688"],["goodeditor","#1aa179"],["special-contributor","#595c5f"]].reverse(),o={bureaucrat:{zh:"行"},checkuser:{zh:"查"},suppress:{zh:"监","zh-hant":"監","zh-tw":"監","zh-hk":"監"},sysop:{zh:"管"},patroller:{zh:"维","zh-hant":"維","zh-tw":"維","zh-hk":"維"},bot:{zh:"机","zh-hant":"機","zh-tw":"機","zh-hk":"機"},flood:{zh:"机","zh-hant":"機","zh-tw":"機","zh-hk":"機"},goodeditor:{zh:"优","zh-hant":"優","zh-tw":"優","zh-hk":"優"},honoredmaintainer:{zh:"荣","zh-hant":"榮","zh-tw":"榮","zh-hk":"榮"},"file-maintainer":{zh:"档","zh-hant":"檔","zh-tw":"檔","zh-hk":"檔"},"interface-admin":{zh:"界","zh-hant":"介","zh-tw":"介","zh-hk":"介"},techeditor:{zh:"技"},"ipblock-exempt":{zh:"免"},"manually-confirmed":{zh:"手"},extendedconfirmed:{zh:"延"},staff:{zh:"职","zh-hant":"職","zh-tw":"職","zh-hk":"職"},"special-contributor":{zh:"特"}},n=e.map(([t])=>t),r=Object.entries({anononly:wgULS("仅封禁匿名用户","僅封鎖匿名使用者",null,null,"僅封鎖匿名用戶"),nocreate:wgULS("阻止创建新账号","防止建立新帳號"),autoblock:wgULS("自动封禁该用户最后使用的IP地址,以及其随后试图用于编辑的所有IP地址","自動封鎖最後使用的IP位址,以及在這之後嘗試登入的所有IP位址。"),noemail:wgULS("阻止用户发送电子邮件","阻止使用者發送電子郵件",null,null,"阻止用戶發送電子郵件"),nousertalk:wgULS("阻止用户在封禁期间编辑自己的讨论页","阻止使用者在封鎖期間編輯自己的對話頁",null,null,"阻止用戶在封鎖期間編輯自己的討論頁"),hiddenname:wgULS("隐藏用户名","隱藏使用者名稱",null,null,"隱藏用戶名")}),a=mw.config.get("wgUserName");let s;const c=new mw.Api,h=Symbol(),fixZero=(t,e=2)=>`${t}`.padStart(e,"0"),toLocalTimeZoneString=(t=new Date)=>`${t.getFullYear()}/${fixZero(t.getMonth()+1)}/${fixZero(t.getDate())} ${fixZero(t.getHours())}:${fixZero(t.getMinutes())}:${fixZero(t.getSeconds())}.${fixZero(t.getMilliseconds(),3)}`;try{if(s=t.getItem("cache"),!s||"number"!=typeof s.timestamp||s.timestamp<(new Date).getTime()-18e5||!s.groups)throw new Error;for(const t of n)if(!Array.isArray(s.groups[t]))throw new Error}catch{const t=Object.fromEntries(n.map(t=>[t,[]]));let e;for(;e!==h;){const o=await c.post({action:"query",assertuser:a,list:"allusers",augroup:n.join("|"),aulimit:"max",auprop:"groups",aufrom:e});e=o.continue?o.continue.aufrom:h,o.query.allusers.forEach(({name:e,groups:o})=>{o.forEach(o=>{n.includes(o)&&(t[o]||(t[o]=[]),t[o].includes(e)||t[o].push(e))})})}s={timestamp:(new Date).getTime(),groups:t}}t.setItem("cache",s);const i=t.getItem("blockCache",{}),l=Date.now();for(const[t,{timestamp:e,isBlocked:o}]of Object.entries(i))("string"!=typeof t||"number"!=typeof e||"boolean"!=typeof o||l-e>18e5)&&Reflect.deleteProperty(i,t);t.setItem("blockCache",i);const querySelectorAll=t=>[...document.querySelectorAll(t)],markBlocked=(t,e)=>{if(t.classList.add("markBlockInfo"),t.classList.remove("unknownBlockInfo"),e.isBlocked){t.style.textDecoration="underline wavy";const o=document.createElement("sup");o.classList.add("detailedBlockInfo"),o.title=e.info,o.textContent="[封+]",t.after(o)}},hook=async()=>{const e=new Set;for(const t of querySelectorAll("a.mw-userlink:not(.markrights), .userlink > a:not(.markrights)")){let o=t.parentElement,r=!1;for(;o;){if(o.classList.contains("navbox")){r=!0;break}o=o.parentElement}if(r)continue;t.classList.add("markrights");const a=new URL(new mw.Uri(t.href));let c;const h=decodeURIComponent(a.pathname),l=a.searchParams.get("title");if(/^\/User:[^/=%]+/.test(h)?c=h.match(/^\/User:([^/=%]+)/)[1].replace(/_/g," "):/^User:[^/=%]+/.test(l)&&(c=l.match(/^User:([^/=%]+)/)[1].replace(/_/g," ")),c){t.dataset.username=c;for(const e of n)if(s.groups[e].includes(c)){const o=document.createElement("sup");o.classList.add(`markrights-${e}`),t.after(o)}if(!t.classList.contains("markBlockInfo")){const o=i[c];o&&o.timestamp?markBlocked(t,o):(t.classList.add("unknownBlockInfo"),e.add(c))}}}if(e.size>0){const o=(await mw.user.getRights()).includes("apihighlimits")?500:50,n=[...e.values()];for(let t=0,e=Math.ceil(n.length/o);t<e;t++){let e;const s=n.slice(t*o,(t+1)*o),l=[],f=Date.now();for(;e!==h;){const t=await c.post({action:"query",assertuser:a,list:"blocks",bkusers:s,bklimit:"max",bkprop:"id|user|by|timestamp|expiry|reason|flags",bkcontinue:e});e=t.continue?t.continue.aufrom:h,t.query.blocks.forEach(t=>{l.push(t.user);let e=`${t.id} - \n    被U:${t.by}${wgULS("封禁","封鎖")}于${toLocalTimeZoneString(new Date(t.timestamp))},`;moment(t.expiry).isValid()?e+=`${wgULS("持续","持續")}至${toLocalTimeZoneString(new Date(t.expiry))}`:e+=wgULS("持续时间为无限期","持續時間為不限期"),e+=`\n    ${wgULS("额外限制","額外限制")}:`,Reflect.has(t,"allowusertalk")||(t.nousertalk=!0);const o=[];for(const[e,n]of r)Reflect.has(t,e)&&o.push(n);0===o.length&&o.push(wgULS("(无)","(無)")),e+=o.join("、"),e+=`\n    ${wgULS("理由","緣由")}:${t.reason}`,i[t.user]={timestamp:f,isBlocked:!0,info:e}})}for(const t of s.filter(t=>!l.includes(t)))i[t]={timestamp:f,isBlocked:!1}}for(const t of querySelectorAll(".unknownBlockInfo")){const{username:e}=t.dataset,o=i[e];o&&o.timestamp&&markBlocked(t,o)}t.setItem("blockCache",i)}for(const t of n)for(const e of querySelectorAll(`.markrights-${t}`)){let{nextElementSibling:o}=e;for(;o&&[...o.classList].filter(t=>t.startsWith("markrights-")).length>0;){const e=o.nextElementSibling;o.classList.contains(`.markrights-${t}`)&&o.remove(),o=e}}};hook(),mw.hook("wikipage.content").add(hook),mw.hook("anntools.usergroup").add(hook),"complete"!==document.readyState&&$(window).on("load",hook);const f=["sup[class^=markrights-]+sup[class^=markrights-] { margin-left: 2px; }"];for(const[t,o]of e)f.push(`.markrights-${t} { color: ${o}; }`);for(const[t,e]of Object.entries(o)){f.push(`html .markrights-${t}::after { content: "${e.zh}"; }`);for(const[o,n]of Object.entries(e))f.push(`html[lang=${o.toLowerCase()} i] .markrights-${t}::after { content: "${n}"; }`)}mw.loader.addStyleTag(f.join("\n"))})();  
(async () => {
    await $.ready;
    const localObjectStorage = new LocalObjectStorage("usergroup");
    const groups = [
        ["staff", "#198754"],
        ["bureaucrat", "#6610f2"],
        ["checkuser", "#673ab7"],
        ["suppress", "#9c27b0"],
        ["sysop", "#ec407a"],
        ["interface-admin", "#f55b42"],
        ["patroller", "#f77f38"],
        ["honoredmaintainer", "#febd45"],
        ["techeditor", "#3f51b5"],
        ["file-maintainer", "#039be5"],
        ["bot", "#1e88e5"],
        ["flood", "#1e88e5"],
        ["ipblock-exempt", "#29b6f6"],
        ["extendedconfirmed", "#57c2c3"],
        ["manually-confirmed", "#009688"],
        ["goodeditor", "#1aa179"],
        ["special-contributor", "#595c5f"],
    ].reverse();
    const groupStr = {
        bureaucrat: {
            zh: "行",
        },
        checkuser: {
            zh: "查",
        },
        suppress: {
            zh: "监",
            "zh-hant": "監",
            "zh-tw": "監",
            "zh-hk": "監",
        },
        sysop: {
            zh: "管",
        },
        patroller: {
            zh: "维",
            "zh-hant": "維",
            "zh-tw": "維",
            "zh-hk": "維",
        },
        bot: {
            zh: "机",
            "zh-hant": "機",
            "zh-tw": "機",
            "zh-hk": "機",
        },
        flood: {
            zh: "机",
            "zh-hant": "機",
            "zh-tw": "機",
            "zh-hk": "機",
        },
        goodeditor: {
            zh: "优",
            "zh-hant": "優",
            "zh-tw": "優",
            "zh-hk": "優",
        },
        honoredmaintainer: {
            zh: "荣",
            "zh-hant": "榮",
            "zh-tw": "榮",
            "zh-hk": "榮",
        },
        "file-maintainer": {
            zh: "档",
            "zh-hant": "檔",
            "zh-tw": "檔",
            "zh-hk": "檔",
        },
        "interface-admin": {
            zh: "界",
            "zh-hant": "介",
            "zh-tw": "介",
            "zh-hk": "介",
        },
        techeditor: {
            zh: "技",
        },
        "ipblock-exempt": {
            zh: "免",
        },
        "manually-confirmed": {
            zh: "手",
        },
        extendedconfirmed: {
            zh: "延",
        },
        staff: {
            zh: "职",
            "zh-hant": "職",
            "zh-tw": "職",
            "zh-hk": "職",
        },
        "special-contributor": {
            zh: "特",
        },
    };
    const groupsKey = groups.map(([group]) => group);
    const blocklogFlags = Object.entries({
        anononly: wgULS("仅封禁匿名用户", "僅封鎖匿名使用者", null, null, "僅封鎖匿名用戶"),
        nocreate: wgULS("阻止创建新账号", "防止建立新帳號"),
        autoblock: wgULS("自动封禁该用户最后使用的IP地址,以及其随后试图用于编辑的所有IP地址", "自動封鎖最後使用的IP位址,以及在這之後嘗試登入的所有IP位址。"),
        noemail: wgULS("阻止用户发送电子邮件", "阻止使用者發送電子郵件", null, null, "阻止用戶發送電子郵件"),
        nousertalk: wgULS("阻止用户在封禁期间编辑自己的讨论页", "阻止使用者在封鎖期間編輯自己的對話頁", null, null, "阻止用戶在封鎖期間編輯自己的討論頁"),
        hiddenname: wgULS("隐藏用户名", "隱藏使用者名稱", null, null, "隱藏用戶名"),
    });
    const wgUserName = mw.config.get("wgUserName");
    let cache;
    const api = new mw.Api();
    const eol = Symbol();
    const fixZero = (n, l = 2) => `${n}`.padStart(l, "0");
    const toLocalTimeZoneString = (date = new Date()) => `${date.getFullYear()}/${fixZero(date.getMonth() + 1)}/${fixZero(date.getDate())} ${fixZero(date.getHours())}:${fixZero(date.getMinutes())}:${fixZero(date.getSeconds())}.${fixZero(date.getMilliseconds(), 3)}`;
    try {
        cache = localObjectStorage.getItem("cache");
        if (!cache
            || typeof cache.timestamp !== "number" || cache.timestamp < new Date().getTime() - 30 * 60 * 1000
            || !cache.groups) {
            throw new Error();
        }
        else {
            for (const i of groupsKey) {
                if (!Array.isArray(cache.groups[i])) {
                    throw new Error();
                }
            }
        }
    }
    catch {
        const result = Object.fromEntries(groupsKey.map((n) => [n, []]));
        let aufrom = undefined;
        while (aufrom !== eol) {
            const _result = await api.post({
                action: "query",
                assertuser: wgUserName,
                list: "allusers",
                augroup: groupsKey.join("|"),
                aulimit: "max",
                auprop: "groups",
                aufrom,
            });
            if (_result.continue) {
                aufrom = _result.continue.aufrom;
            }
            else {
                aufrom = eol;
            }
            _result.query.allusers.forEach(({ name, groups, }) => {
                groups.forEach((group) => {
                    if (groupsKey.includes(group)) {
                        result[group] || (result[group] = []);
                        if (!result[group].includes(name)) {
                            result[group].push(name);
                        }
                    }
                });
            });
        }
        cache = {
            timestamp: new Date().getTime(),
            groups: result,
        };
    }
    localObjectStorage.setItem("cache", cache);
    const blockCache = localObjectStorage.getItem("blockCache", {});
    const now = Date.now();
    for (const [username, { timestamp, isBlocked }] of Object.entries(blockCache)) {
        if (typeof username !== "string" || typeof timestamp !== "number" || typeof isBlocked !== "boolean" || now - timestamp > 30 * 60 * 1000) {
            Reflect.deleteProperty(blockCache, username);
        }
    }
    localObjectStorage.setItem("blockCache", blockCache);
    const querySelectorAll = (selector) => [...document.querySelectorAll(selector)];
    const markBlocked = (ele, blockInfo) => {
        ele.classList.add("markBlockInfo");
        ele.classList.remove("unknownBlockInfo");
        if (blockInfo.isBlocked) {
            ele.style.textDecoration = "underline wavy";
            const sup = document.createElement("sup");
            sup.classList.add("detailedBlockInfo");
            sup.title = blockInfo.info;
            sup.textContent = "[封+]";
            ele.after(sup);
        }
    };
    const hook = async () => {
        const unknownUsernames = new Set();
        for (const ele of querySelectorAll("a.mw-userlink:not(.markrights), .userlink > a:not(.markrights)")) {
            let parent = ele.parentElement;
            let inNavbox = false;
            while (parent) {
                if (parent.classList.contains("navbox")) {
                    inNavbox = true;
                    break;
                }
                parent = parent.parentElement;
            }
            if (inNavbox) {
                continue;
            }
            ele.classList.add("markrights");
            const url = new URL(new mw.Uri(ele.href));
            let username;
            const pathname = decodeURIComponent(url.pathname);
            const title = url.searchParams.get("title");
            if (/^\/User:[^/=%]+/.test(pathname)) {
                username = pathname.match(/^\/User:([^/=%]+)/)[1].replace(/_/g, " ");
            }
            else if (/^User:[^/=%]+/.test(title)) {
                username = title.match(/^User:([^/=%]+)/)[1].replace(/_/g, " ");
            }
            if (!username) {
                continue;
            }
            ele.dataset.username = username;
            for (const group of groupsKey) {
                if (cache.groups[group].includes(username)) {
                    const sup = document.createElement("sup");
                    sup.classList.add(`markrights-${group}`);
                    ele.after(sup);
                }
            }
            if (!ele.classList.contains("markBlockInfo")) {
                const blockInfo = blockCache[username];
                if (blockInfo && blockInfo.timestamp) {
                    markBlocked(ele, blockInfo);
                }
                else {
                    ele.classList.add("unknownBlockInfo");
                    unknownUsernames.add(username);
                }
            }
        }
        if (unknownUsernames.size > 0) {
            const hasApihighlimits = (await mw.user.getRights()).includes("apihighlimits");
            const singleRequestLimit = hasApihighlimits ? 500 : 50;
            const targets = [...unknownUsernames.values()];
            for (let i = 0, l = Math.ceil(targets.length / singleRequestLimit); i < l; i++) {
                let bkcontinue = undefined;
                const target = targets.slice(i * singleRequestLimit, (i + 1) * singleRequestLimit);
                const blockedUserName = [];
                const now = Date.now();
                while (bkcontinue !== eol) {
                    const _result = await api.post({
                        action: "query",
                        assertuser: wgUserName,
                        list: "blocks",
                        bkusers: target,
                        bklimit: "max",
                        bkprop: "id|user|by|timestamp|expiry|reason|flags",
                        bkcontinue,
                    });
                    if (_result.continue) {
                        bkcontinue = _result.continue.aufrom;
                    }
                    else {
                        bkcontinue = eol;
                    }
                    _result.query.blocks.forEach((blockInfo) => {
                        blockedUserName.push(blockInfo.user);
                        let info = `${blockInfo.id} - \n    被U:${blockInfo.by}${wgULS("封禁", "封鎖")}于${toLocalTimeZoneString(new Date(blockInfo.timestamp))},`;
                        if (moment(blockInfo.expiry).isValid()) {
                            info += `${wgULS("持续", "持續")}至${toLocalTimeZoneString(new Date(blockInfo.expiry))}`;
                        }
                        else {
                            info += wgULS("持续时间为无限期", "持續時間為不限期");
                        }
                        info += `\n    ${wgULS("额外限制", "額外限制")}:`;
                        if (!Reflect.has(blockInfo, "allowusertalk")) {
                            blockInfo.nousertalk = true;
                        }
                        const flags = [];
                        for (const [flag, comment] of blocklogFlags) {
                            if (Reflect.has(blockInfo, flag)) {
                                flags.push(comment);
                            }
                        }
                        if (flags.length === 0) {
                            flags.push(wgULS("(无)", "(無)"));
                        }
                        info += flags.join("、");
                        info += `\n    ${wgULS("理由", "緣由")}:${blockInfo.reason}`;
                        blockCache[blockInfo.user] = {
                            timestamp: now,
                            isBlocked: true,
                            info,
                        };
                    });
                }
                for (const username of target.filter((username) => !blockedUserName.includes(username))) {
                    blockCache[username] = {
                        timestamp: now,
                        isBlocked: false,
                    };
                }
            }
            for (const ele of querySelectorAll(".unknownBlockInfo")) {
                const { username } = ele.dataset;
                const blockInfo = blockCache[username];
                if (blockInfo && blockInfo.timestamp) {
                    markBlocked(ele, blockInfo);
                }
            }
            localObjectStorage.setItem("blockCache", blockCache);
        }
        for (const group of groupsKey) {
            for (const node of querySelectorAll(`.markrights-${group}`)) {
                let { nextElementSibling } = node;
                while (nextElementSibling && [...nextElementSibling.classList].filter((className) => className.startsWith("markrights-")).length > 0) {
                    const nextNextElementSibling = nextElementSibling.nextElementSibling;
                    if (nextElementSibling.classList.contains(`.markrights-${group}`)) {
                        nextElementSibling.remove();
                    }
                    nextElementSibling = nextNextElementSibling;
                }
            }
        }
    };
    hook();
    mw.hook("wikipage.content").add(hook);
    mw.hook("anntools.usergroup").add(hook);
    if (document.readyState !== "complete") {
        $(window).on("load", hook);
    }
    const style = ["sup[class^=markrights-]+sup[class^=markrights-] { margin-left: 2px; }"];
    for (const [group, color] of groups) {
        style.push(`.markrights-${group} { color: ${color}; }`);
    }
    for (const [group, strList] of Object.entries(groupStr)) {
        style.push(`html .markrights-${group}::after { content: "${strList.zh}"; }`);
        for (const [lang, str] of Object.entries(strList)) {
            style.push(`html[lang=${lang.toLowerCase()} i] .markrights-${group}::after { content: "${str}"; }`);
        }
    }
    mw.loader.addStyleTag(style.join("\n"));
})();  


/* </pre> */
/* </pre> */

2025年7月26日 (六) 00:34的版本

/**
 * -------------------------------------------------------------------------
 * !!! DON'T MODIFY THIS PAGE MANUALLY, YOUR CHANGES WILL BE OVERWRITTEN !!!
 * -------------------------------------------------------------------------
 */
var _addText = '{{GHIACode|page=GHIA:MoegirlPediaInterfaceCodes/blob/master/src/gadgets/usergroup/Gadget-usergroup.js|user=[[U:AnnAngela]]|co-authors=GH:github-actions[bot]|longId=103d1a563ea4ccc8ff29fb55c9bcd88329a56eb5|shortId=103d1a56|summary=feat: rename (#594)|body=<nowiki>Co-authored-by: github-actions[bot] <41898282+github-actions[bot]📧users.noreply.github.com></nowiki>}}'; 

/* <pre> */

"use strict";(async()=>{await $.ready;const t=new LocalObjectStorage("usergroup"),e=[["staff","#198754"],["bureaucrat","#6610f2"],["checkuser","#673ab7"],["suppress","#9c27b0"],["sysop","#ec407a"],["interface-admin","#f55b42"],["patroller","#f77f38"],["honoredmaintainer","#febd45"],["techeditor","#3f51b5"],["file-maintainer","#039be5"],["bot","#1e88e5"],["flood","#1e88e5"],["ipblock-exempt","#29b6f6"],["extendedconfirmed","#57c2c3"],["manually-confirmed","#009688"],["goodeditor","#1aa179"],["special-contributor","#595c5f"]].reverse(),o={bureaucrat:{zh:"行"},checkuser:{zh:"查"},suppress:{zh:"监","zh-hant":"監","zh-tw":"監","zh-hk":"監"},sysop:{zh:"管"},patroller:{zh:"维","zh-hant":"維","zh-tw":"維","zh-hk":"維"},bot:{zh:"机","zh-hant":"機","zh-tw":"機","zh-hk":"機"},flood:{zh:"机","zh-hant":"機","zh-tw":"機","zh-hk":"機"},goodeditor:{zh:"优","zh-hant":"優","zh-tw":"優","zh-hk":"優"},honoredmaintainer:{zh:"荣","zh-hant":"榮","zh-tw":"榮","zh-hk":"榮"},"file-maintainer":{zh:"档","zh-hant":"檔","zh-tw":"檔","zh-hk":"檔"},"interface-admin":{zh:"界","zh-hant":"介","zh-tw":"介","zh-hk":"介"},techeditor:{zh:"技"},"ipblock-exempt":{zh:"免"},"manually-confirmed":{zh:"手"},extendedconfirmed:{zh:"延"},staff:{zh:"职","zh-hant":"職","zh-tw":"職","zh-hk":"職"},"special-contributor":{zh:"特"}},n=e.map(([t])=>t),r=Object.entries({anononly:wgULS("仅封禁匿名用户","僅封鎖匿名使用者",null,null,"僅封鎖匿名用戶"),nocreate:wgULS("阻止创建新账号","防止建立新帳號"),autoblock:wgULS("自动封禁该用户最后使用的IP地址,以及其随后试图用于编辑的所有IP地址","自動封鎖最後使用的IP位址,以及在這之後嘗試登入的所有IP位址。"),noemail:wgULS("阻止用户发送电子邮件","阻止使用者發送電子郵件",null,null,"阻止用戶發送電子郵件"),nousertalk:wgULS("阻止用户在封禁期间编辑自己的讨论页","阻止使用者在封鎖期間編輯自己的對話頁",null,null,"阻止用戶在封鎖期間編輯自己的討論頁"),hiddenname:wgULS("隐藏用户名","隱藏使用者名稱",null,null,"隱藏用戶名")}),a=mw.config.get("wgUserName");let s;const c=new mw.Api,h=Symbol(),fixZero=(t,e=2)=>`${t}`.padStart(e,"0"),toLocalTimeZoneString=(t=new Date)=>`${t.getFullYear()}/${fixZero(t.getMonth()+1)}/${fixZero(t.getDate())} ${fixZero(t.getHours())}:${fixZero(t.getMinutes())}:${fixZero(t.getSeconds())}.${fixZero(t.getMilliseconds(),3)}`;try{if(s=t.getItem("cache"),!s||"number"!=typeof s.timestamp||s.timestamp<(new Date).getTime()-18e5||!s.groups)throw new Error;for(const t of n)if(!Array.isArray(s.groups[t]))throw new Error}catch{const t=Object.fromEntries(n.map(t=>[t,[]]));let e;for(;e!==h;){const o=await c.post({action:"query",assertuser:a,list:"allusers",augroup:n.join("|"),aulimit:"max",auprop:"groups",aufrom:e});e=o.continue?o.continue.aufrom:h,o.query.allusers.forEach(({name:e,groups:o})=>{o.forEach(o=>{n.includes(o)&&(t[o]||(t[o]=[]),t[o].includes(e)||t[o].push(e))})})}s={timestamp:(new Date).getTime(),groups:t}}t.setItem("cache",s);const i=t.getItem("blockCache",{}),l=Date.now();for(const[t,{timestamp:e,isBlocked:o}]of Object.entries(i))("string"!=typeof t||"number"!=typeof e||"boolean"!=typeof o||l-e>18e5)&&Reflect.deleteProperty(i,t);t.setItem("blockCache",i);const querySelectorAll=t=>[...document.querySelectorAll(t)],markBlocked=(t,e)=>{if(t.classList.add("markBlockInfo"),t.classList.remove("unknownBlockInfo"),e.isBlocked){t.style.textDecoration="underline wavy";const o=document.createElement("sup");o.classList.add("detailedBlockInfo"),o.title=e.info,o.textContent="[封+]",t.after(o)}},hook=async()=>{const e=new Set;for(const t of querySelectorAll("a.mw-userlink:not(.markrights), .userlink > a:not(.markrights)")){let o=t.parentElement,r=!1;for(;o;){if(o.classList.contains("navbox")){r=!0;break}o=o.parentElement}if(r)continue;t.classList.add("markrights");const a=new URL(new mw.Uri(t.href));let c;const h=decodeURIComponent(a.pathname),l=a.searchParams.get("title");if(/^\/User:[^/=%]+/.test(h)?c=h.match(/^\/User:([^/=%]+)/)[1].replace(/_/g," "):/^User:[^/=%]+/.test(l)&&(c=l.match(/^User:([^/=%]+)/)[1].replace(/_/g," ")),c){t.dataset.username=c;for(const e of n)if(s.groups[e].includes(c)){const o=document.createElement("sup");o.classList.add(`markrights-${e}`),t.after(o)}if(!t.classList.contains("markBlockInfo")){const o=i[c];o&&o.timestamp?markBlocked(t,o):(t.classList.add("unknownBlockInfo"),e.add(c))}}}if(e.size>0){const o=(await mw.user.getRights()).includes("apihighlimits")?500:50,n=[...e.values()];for(let t=0,e=Math.ceil(n.length/o);t<e;t++){let e;const s=n.slice(t*o,(t+1)*o),l=[],f=Date.now();for(;e!==h;){const t=await c.post({action:"query",assertuser:a,list:"blocks",bkusers:s,bklimit:"max",bkprop:"id|user|by|timestamp|expiry|reason|flags",bkcontinue:e});e=t.continue?t.continue.aufrom:h,t.query.blocks.forEach(t=>{l.push(t.user);let e=`${t.id} - \n    被U:${t.by}${wgULS("封禁","封鎖")}${toLocalTimeZoneString(new Date(t.timestamp))},`;moment(t.expiry).isValid()?e+=`${wgULS("持续","持續")}${toLocalTimeZoneString(new Date(t.expiry))}`:e+=wgULS("持续时间为无限期","持續時間為不限期"),e+=`\n    ${wgULS("额外限制","額外限制")}:`,Reflect.has(t,"allowusertalk")||(t.nousertalk=!0);const o=[];for(const[e,n]of r)Reflect.has(t,e)&&o.push(n);0===o.length&&o.push(wgULS("(无)","(無)")),e+=o.join("、"),e+=`\n    ${wgULS("理由","緣由")}${t.reason}`,i[t.user]={timestamp:f,isBlocked:!0,info:e}})}for(const t of s.filter(t=>!l.includes(t)))i[t]={timestamp:f,isBlocked:!1}}for(const t of querySelectorAll(".unknownBlockInfo")){const{username:e}=t.dataset,o=i[e];o&&o.timestamp&&markBlocked(t,o)}t.setItem("blockCache",i)}for(const t of n)for(const e of querySelectorAll(`.markrights-${t}`)){let{nextElementSibling:o}=e;for(;o&&[...o.classList].filter(t=>t.startsWith("markrights-")).length>0;){const e=o.nextElementSibling;o.classList.contains(`.markrights-${t}`)&&o.remove(),o=e}}};hook(),mw.hook("wikipage.content").add(hook),mw.hook("anntools.usergroup").add(hook),"complete"!==document.readyState&&$(window).on("load",hook);const f=["sup[class^=markrights-]+sup[class^=markrights-] { margin-left: 2px; }"];for(const[t,o]of e)f.push(`.markrights-${t} { color: ${o}; }`);for(const[t,e]of Object.entries(o)){f.push(`html .markrights-${t}::after { content: "${e.zh}"; }`);for(const[o,n]of Object.entries(e))f.push(`html[lang=${o.toLowerCase()} i] .markrights-${t}::after { content: "${n}"; }`)}mw.loader.addStyleTag(f.join("\n"))})(); 

/* </pre> */