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

MediaWiki:Gadget-MarkRights.js

MediaWiki界面页面

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

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
/**
 * MediaWiki:Gadget-MarkRights.js
 *
 * 在页面上以特殊格式显示有特殊权限的用户
 *
 * [Final Production Version - DEBUG ENABLED]
 * This version exclusively targets official user link classes (.mw-userlink, .cs-comment-author)
 * and filters out links pointing to user subpages for maximum precision.
 * Full logging is re-enabled for troubleshooting.
 */

$(function () {
    console.log('[MarkRights Debug] Gadget loaded and DOM is ready.');

    var groups = {
        // ... (您的用户组配置保持不变) ...
        // 全站管理型权限
        bureaucrat: {list: [], class: "markrights-bureaucrat"},
        checkuser: {list: [], class: "markrights-checkuser"},
        suppress: {list: [], class: "markrights-suppress"},
        sysop: {list: [], class: "markrights-sysop"},
        'interface-admin': {list: [], class: "markrights-interface-admin"},
        templateeditor: {list: [], class: "markrights-templateeditor"},
        transwiki: {list: [], class: "markrights-transwiki"},
        'ipblock-exempt-grantor': {list: [], class: "markrights-ipblock-exempt-grantor"},
        'temporary-account-viewer': {list: [], class: "markrights-temporary-account-viewer"},
        // 页面管理型权限
		'abusefilter-helper': {list: [], class: "markrights-abusefilter-helper"},
		'abusefilter': {list: [], class: "markrights-abusefilter"},
        patroller: {list: [], class: "markrights-patroller"},
        rollbacker: {list: [], class: "markrights-rollbacker"},
        autoreviewer: {list: [], class: "markrights-autoreviewer"},
        'event-organizer': {list: [], class: "markrights-event-organizer"},
        // 大量操作型权限
        accountcreator: {list: [], class: "markrights-accountcreator"},
        'massmessage-sender': {list: [], class: "markrights-massmessage-sender"},
        // 确认权限
        confirmed: {list: [], class: "markrights-confirmed"},
        autoconfirmed: {list: [], class: "markrights-autoconfirmed"},
        extendedconfirmed: {list: [], class: "markrights-extendedconfirmed"},
        // 机器权限
        bot: {list: [], class: "markrights-bot"},
        flood: {list: [], class: "markrights-flood"},
        // IPBE
        'ipblock-exempt': {list: [], class: "markrights-ipblock-exempt"},
		// arbcom
		arbcom: {list: [], class: "markrights-arbcom"},
		// 安全投票相关权限
		electionclerk: {list: [], class: "markrights-electionclerk"},
		scrutineer: {list: [], class: "markrights-scrutineer"},
    };
    console.log('[MarkRights Debug] Initial groups configuration:', JSON.parse(JSON.stringify(groups)));

    var userLinkSelector = 'a.mw-userlink, a.cs-comment-author';

    var markRightsInProgress = false;
    var debounceTimeout;

    var markUG = function () {
        if (markRightsInProgress) { return; }
        markRightsInProgress = true;
        
        console.log('[MarkRights Debug] Step 2: markUG function has been called for a global scan.');

        var getUsernameFromUrl = function(url) {
            if (!url) return null;
            var match;
            match = url.match(/\/(wiki\/)?User:([^/?#]+)/);
            if (match && match[2]) {
                try { return decodeURIComponent(match[2].replace(/_/g, ' ')); } catch (e) { return match[2].replace(/_/g, ' '); }
            }
            match = url.match(/title=User(?:%3A|:)([^&/#]+)/);
            if (match && match[1]) {
                try { return decodeURIComponent(match[1].replace(/_/g, ' ')); } catch (e) { return match[1].replace(/_/g, ' '); }
            }
            return null;
        };

        var done = function (isPreScan) {
            var markedCount = 0;
            $(userLinkSelector).each(function (i, el) {
                var username = getUsernameFromUrl(el.href);
                if (username) {
                    for (var group in groups) {
                        if (groups.hasOwnProperty(group) && groups[group].list.indexOf(username) > -1) {
                            if ($(el).children('sup.' + groups[group].class).length === 0) {
                                $(el).append('<sup class="' + groups[group].class + '"></sup>');
                                markedCount++;
                            }
                        }
                    }
                }
            });
             if (markedCount > 0 && !isPreScan) {
                 console.log('[MarkRights Final Scan] Applied ' + markedCount + ' marks.');
             }
        };

        var n;
        var process = function (data) {
            console.log('[MarkRights Debug] Step 7: Received API response.', data);
            var users;
            if (data.query && data.query.users) { users = data.query.users; } else { users = []; }
            for (var i = 0; i < users.length; i++) {
                var user = users[i];
                if (user.groups) {
                    for (var group in groups) {
                        if (groups.hasOwnProperty(group) && user.groups.indexOf(group) > -1 && groups[group].list.indexOf(user.name) === -1) {
                            groups[group].list.push(user.name);
                        }
                    }
                }
            }
            n--;
            if (n <= 0) {
                console.log('[MarkRights Debug] Step 8: All API requests complete. Starting final marking process.');
                done(false);
                markRightsInProgress = false;
            }
        };
        
        var $users = $(userLinkSelector).not('.markrights-processed');
        console.log('[MarkRights Debug] Step 3: Found ' + $users.length + ' new, unprocessed user links using strict selector.');

        if ($users.length === 0) {
            markRightsInProgress = false;
            return;
        }
        
        var usersToQuery = {};
        $users.each(function (index, link) {
            $(link).addClass('markrights-processed');
            
            var username = getUsernameFromUrl(link.href);
            console.log('--- Checking link: ' + link.href + ' --- Parsed username: ' + username);
            
            if (username && !username.includes('/')) {
                console.log('Result: VALID. Adding to query list.');
                 if (!groups.autoconfirmed.list.includes(username)) {
                    usersToQuery[username] = true;
                 }
            } else {
                 console.log('Result: SKIPPED. Reason: ' + (username ? 'Is a subpage' : 'Could not parse username'));
            }
        });

        done(true);

        var userCount = Object.keys(usersToQuery).length;
        console.log('[MarkRights Debug] Step 4: Collected ' + userCount + ' unique new usernames for API query.', Object.keys(usersToQuery));
        
        if (userCount === 0) {
            markRightsInProgress = false;
            return;
        }

        var queue1 = [], queue2 = [], i = 0;
        n = 0;
        for (var user in usersToQuery) {
            queue1.push(user);
            i++;
            if (i === 50) { queue2.push(queue1); queue1 = []; n++; i = 0; }
        }
        if (queue1.length > 0) { queue2.push(queue1); n++; }
        console.log('[MarkRights Debug] Step 5: New usernames batched into ' + n + ' API requests.', queue2);
        
        var api = new mw.Api({ userAgent: 'Gadget-MarkRights' });
        for (var j = 0; j < queue2.length; j++) {
            console.log('[MarkRights Debug] Step 6: Sending API request for batch ' + (j + 1) + '/' + queue2.length);
            api.get({ format: 'json', action: 'query', list: 'users', usprop: 'groups', ususers: queue2[j].join('|') }).done(process).fail(function() { n--; if (n <= 0) { done(false); markRightsInProgress = false; } });
        }
    };

    var triggerMarkUG = function() {
        clearTimeout(debounceTimeout);
        debounceTimeout = setTimeout(markUG, 100);
    };

    mw.hook('wikipage.content').add(function() {
        console.log('[MarkRights Debug] Event: wikipage.content hook triggered.');
        triggerMarkUG();
    });
    
    mw.hook('CommentStream.afterLoad').add(function() {
        console.log('[MarkRights Debug] Event: CommentStream.afterLoad hook triggered!');
        triggerMarkUG();
    });
});