打开/关闭菜单
228
885
35
2802
植物大战僵尸杂交版Wiki
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

MediaWiki:Common.js:修订间差异

MediaWiki界面页面
无编辑摘要
无编辑摘要
第21行: 第21行:
});
});
$(function () {
$(function () {
     // ==================== 样式注入 ====================
     // ==================== 动态注入彩虹样式(无星星伪元素) ====================
    // 彩虹用户样式
     var rainbowStyle = document.createElement('style');
     var rainbowStyle = document.createElement('style');
     rainbowStyle.textContent =
     rainbowStyle.textContent =
第31行: 第30行:
             '-webkit-text-fill-color: transparent;' +
             '-webkit-text-fill-color: transparent;' +
             'background-clip: text;' +
             'background-clip: text;' +
            'color: #FFD700;' +
        '}' +
        '.rainbow-user::after {' +
            'content: "⭐⭐⭐⭐⭐";' +
            'margin-left: 2px;' +
            'font-weight: normal;' +
            '-webkit-text-fill-color: initial;' +
            'color: #FFD700;' +
         '}';
         '}';
     document.head.appendChild(rainbowStyle);
     document.head.appendChild(rainbowStyle);
    // 状态圆点样式
    var statusStyle = document.createElement('style');
    statusStyle.textContent =
        '.user-status-dot {' +
            'display: inline-block;' +
            'width: 8px;' +
            'height: 8px;' +
            'border-radius: 50%;' +
            'margin-left: 4px;' +
            'vertical-align: middle;' +
        '}' +
        '.status-online  { background-color: #4CAF50; }' +
        '.status-away    { background-color: #FF9800; }' +
        '.status-offline { background-color: #9E9E9E; }';
    document.head.appendChild(statusStyle);
    // 师徒标签样式
    var tagStyle = document.createElement('style');
    tagStyle.textContent =
        '.user-tag {' +
            'display: inline-block;' +
            'font-size: 0.75em;' +
            'padding: 0px 4px;' +
            'margin-left: 4px;' +
            'border-radius: 3px;' +
            'vertical-align: middle;' +
            'font-weight: normal;' +
        '}' +
        '.user-tag-mentor { background: #4CAF50; color: white; }' +  // 导师绿色
        '.user-tag-newbie { background: #FF9800; color: white; }';    // 新手橙色
    document.head.appendChild(tagStyle);


     // ==================== 配置区 ====================
     // ==================== 配置区 ====================
    // 手动列出导师用户名(区分大小写,和页面上显示的名字完全一致)
     var mentorList = ['愤怒的郎朗', 'Yuyaabc','虚位以待','知更鸟头号粉丝'];   // 手动配置导师用户名
     var mentorList = ['愤怒的郎朗', 'Yuyaabc','虚位以待','知更鸟头号粉丝'];  
     var newbieEditThreshold = 25;                 // 编辑数 ≤ 25 自动标记为新手
    // 新手编辑数阈值(≤此值自动判定为新手)
     var newbieEditThreshold = 25;


     // ==================== 辅助函数 ====================
     // ==================== 辅助函数 ====================
第91行: 第48行:
     }
     }


     // 核心:上色 + 状态 + 师徒标签
     // 计算等级图标字符串
    function getLevelIcons(editcount) {
        var totalStars = Math.floor(editcount / 100);
        if (totalStars === 0) return '';  // 不够100次不显示
 
        var crowns = Math.floor(totalStars / 125);      // 5太阳 = 125星
        var remaining = totalStars % 125;
        var suns = Math.floor(remaining / 25);          // 5月亮 = 25星
        remaining %= 25;
        var moons = Math.floor(remaining / 5);          // 5星 = 1月亮
        var stars = remaining % 5;
 
        var icons = '';
        // 用 repeat 生成对应数量图标
        if (crowns > 0) icons += '👑'.repeat(crowns);
        if (suns > 0)  icons += '☀️'.repeat(suns);
        if (moons > 0)  icons += '🌙'.repeat(moons);
        if (stars > 0)  icons += '⭐'.repeat(stars);
        return icons;
    }
 
    // 更新或创建等级图标元素
    function updateLevelIcons($link, editcount) {
        var iconStr = getLevelIcons(editcount);
        var $iconSpan = $link.next('.user-level-icons');
 
        if (iconStr === '') {
            // 编辑数不够,移除图标
            $iconSpan.remove();
            return;
        }
 
        if ($iconSpan.length === 0) {
            $iconSpan = $('<span class="user-level-icons"></span>');
            $link.after($iconSpan);
        }
        $iconSpan.text(iconStr);
    }
 
    // ==================== 核心处理流程 ====================
     function colorizeAndStatus($links) {
     function colorizeAndStatus($links) {
         if ($links.length === 0) return;
         if ($links.length === 0) return;
第111行: 第107行:
         });
         });


         // 1. 应用颜色(所有用户链接,包括卡片)
         // 1. 批量查询编辑数(用于颜色 + 等级图标)
         var batchSize = 50;
         var batchSize = 50;
         var batches = [];
         var batches = [];
第118行: 第114行:
         }
         }


         var processColorBatch = function (batch) {
         var processBatch = function (batch) {
             var api = new mw.Api();
             var api = new mw.Api();
             return api.get({
             return api.get({
第127行: 第123行:
             }).then(function (data) {
             }).then(function (data) {
                 var classMap = {};
                 var classMap = {};
                var editCountMap = {};
                 if (data.query && data.query.users) {
                 if (data.query && data.query.users) {
                     data.query.users.forEach(function (u) {
                     data.query.users.forEach(function (u) {
                         var ec = u.editcount || 0;
                         var ec = u.editcount || 0;
                        editCountMap[u.name] = ec;
                        // 颜色等级判定
                         if (ec >= 5000) classMap[u.name] = 'rainbow-user';
                         if (ec >= 5000) classMap[u.name] = 'rainbow-user';
                         else if (ec >= 2000) classMap[u.name] = 'gold-user';
                         else if (ec >= 2000) classMap[u.name] = 'gold-user';
第137行: 第136行:
                     });
                     });
                 }
                 }
                // 应用颜色和等级图标
                 $fresh.each(function () {
                 $fresh.each(function () {
                     var $this = $(this);
                     var $this = $(this);
第144行: 第144行:
                         $this.removeClass('bronze-user silver-user platinum-user gold-user rainbow-user');
                         $this.removeClass('bronze-user silver-user platinum-user gold-user rainbow-user');
                         $this.addClass(cls);
                         $this.addClass(cls);
                    }
                    // 更新等级图标
                    var ec = editCountMap[name];
                    if (typeof ec !== 'undefined') {
                        updateLevelIcons($this, ec);
                     }
                     }
                 });
                 });
第152行: 第157行:
         batches.forEach(function (batch) {
         batches.forEach(function (batch) {
             colorPromise = colorPromise.then(function () {
             colorPromise = colorPromise.then(function () {
                 return processColorBatch(batch);
                 return processBatch(batch);
             });
             });
         });
         });


         // 2. 非卡片用户:添加状态圆点 + 师徒标签
         // 2. 非卡片区域:状态圆点 + 师徒标签
         $fresh.each(function () {
         $fresh.each(function () {
             if (isUserLink(this)) {
             if (isUserLink(this)) {
第169行: 第174行:
     }
     }


     // 状态圆点(同之前)
     // ==================== 状态圆点(不变) ====================
     function addStatusDot($link, username) {
     function addStatusDot($link, username) {
         if ($link.data('status-dot-added')) return;
         if ($link.data('status-dot-added')) return;
         $link.data('status-dot-added', true);
         $link.data('status-dot-added', true);


         var $dot = $('<span class="user-status-dot status-offline" title="离线">');
         var $dot = $('<span class="user-status-dot status-offline" title="离线"></span>');
         $link.after($dot);
         $link.after($dot); // 会插入在等级图标之后,无所谓顺序


         var cacheKey = 'mw_user_status_' + mw.config.get('wgDBname') + '_' + username;
         var cacheKey = 'mw_user_status_' + mw.config.get('wgDBname') + '_' + username;
第230行: 第235行:
     }
     }


     // 师徒标签(新增)
     // ==================== 师徒标签 ====================
     function addMentorTag($link, username) {
     function addMentorTag($link, username) {
         if ($link.data('mentor-tag-added')) return;
         if ($link.data('mentor-tag-added')) return;
        // 查找是否已存在标签(防止重复)
         if ($link.next('.user-tag').length) return;
         if ($link.next('.user-tag').length) return;


        var tagType = null;
         if (mentorList.indexOf(username) !== -1) {
         if (mentorList.indexOf(username) !== -1) {
             tagType = 'mentor';
             $link.data('mentor-tag-added', true);
        } else {
             var $tag = $('<span class="user-tag user-tag-mentor">导师</span>');
             // 新手判定:从缓存或API拿编辑数。这里复用之前已查询的编辑数?
             $link.after($tag);
             // 为了不增加额外API,我们将新手判定延迟到颜色API返回后进行。
            // 简单做法:在colorizeAndStatus流程中,颜色API已经获得了所有用户的编辑数,
            // 我们可以把编辑数保存起来供标签使用。
            // 重构:将classMap扩展为包含editcount的map。
            // 但由于colorizeAndStatus中$fresh和users的作用域,我们需要调整结构。
            // 简便方案:单独用一次小查询获取编辑数(带缓存)。
            // 为了性能,利用之前已经有的颜色查询结果是最佳,但需要较大改动。
            // 这里提供一个折中方案:给新手标签也使用API+缓存,因为需要编辑数。
            addNewbieTagIfNeeded($link, username);
             return;
             return;
         }
         }
        $link.data('mentor-tag-added', true);
        var $tag = $('<span class="user-tag user-tag-mentor">导师</span>');
        $link.after($tag);
    }


    // 新手标签(带缓存)
        // 新手判定(带缓存)
    function addNewbieTagIfNeeded($link, username) {
         if ($link.data('newbie-tag-checked')) return;
         if ($link.data('newbie-tag-checked')) return;
         $link.data('newbie-tag-checked', true);
         $link.data('newbie-tag-checked', true);
第268行: 第257行:
             try {
             try {
                 var data = JSON.parse(cached);
                 var data = JSON.parse(cached);
                // 缓存1小时,因为编辑数变化较慢
                 if (now - data.timestamp < 60 * 60 * 1000) {
                 if (now - data.timestamp < 60 * 60 * 1000) {
                     applyNewbieTag($link, data.editcount);
                     if (data.editcount <= newbieEditThreshold) {
                        var $tag = $('<span class="user-tag user-tag-newbie">新手</span>');
                        $link.after($tag);
                    }
                     return;
                     return;
                 }
                 }
第291行: 第282行:
                 timestamp: now
                 timestamp: now
             }));
             }));
             applyNewbieTag($link, editcount);
             if (editcount <= newbieEditThreshold) {
                if ($link.next('.user-tag-newbie').length === 0) {
                    var $tag = $('<span class="user-tag user-tag-newbie">新手</span>');
                    $link.after($tag);
                }
            }
         }).fail(function () {});
         }).fail(function () {});
     }
     }


    function applyNewbieTag($link, editcount) {
     // ==================== 启动 ====================
        if (editcount <= newbieEditThreshold) {
            // 避免重复添加
            if ($link.next('.user-tag-newbie').length) return;
            var $tag = $('<span class="user-tag user-tag-newbie">新手</span>');
            $link.after($tag);
        }
    }
 
     // ==================== 执行入口 ====================
     var linkSelector = 'a.mw-userlink, .citizen-menu_card-content a, .citizen-userMenu a';
     var linkSelector = 'a.mw-userlink, .citizen-menu_card-content a, .citizen-userMenu a';



2026年5月31日 (日) 10:04的版本

/* 这里的任何JavaScript将为所有用户在每次页面加载时加载。 */

// 自动加载 MediaWiki:Footer 页面内容,并插入到每个页面底部

$(document).ready(function() {
    const namespace = mw.config.get('wgNamespaceNumber');
    const action = mw.config.get('wgAction');
    
    if (namespace !== 0 || action !== 'view') {
        return;
    }

    fetch("/api.php?action=parse&page=MediaWiki:Footer&format=json")
        .then(res => res.json())
        .then(data => {
            if (data.parse && data.parse.text) {
                const html = data.parse.text['*'];
                $('#mw-content-text').append('<div class="global-footer">' + html + '</div>');
            }
        });
});
$(function () {
    // ==================== 动态注入彩虹样式(无星星伪元素) ====================
    var rainbowStyle = document.createElement('style');
    rainbowStyle.textContent =
        '.rainbow-user {' +
            'font-weight: bold;' +
            'background: repeating-linear-gradient(90deg, red 0px, orange 10px, yellow 20px, green 30px, blue 40px, indigo 50px, violet 60px);' +
            '-webkit-background-clip: text;' +
            '-webkit-text-fill-color: transparent;' +
            'background-clip: text;' +
        '}';
    document.head.appendChild(rainbowStyle);

    // ==================== 配置区 ====================
    var mentorList = ['愤怒的郎朗', 'Yuyaabc','虚位以待','知更鸟头号粉丝'];    // 手动配置导师用户名
    var newbieEditThreshold = 25;                  // 编辑数 ≤ 25 自动标记为新手

    // ==================== 辅助函数 ====================
    function getUserName(link) {
        var $span = $(link).find('span').first();
        if ($span.length) return $span.text().trim();
        return $(link).text().trim();
    }

    function isUserLink(link) {
        return $(link).is('a.mw-userlink') || $(link).find('span').length > 0;
    }

    // 计算等级图标字符串
    function getLevelIcons(editcount) {
        var totalStars = Math.floor(editcount / 100);
        if (totalStars === 0) return '';   // 不够100次不显示

        var crowns = Math.floor(totalStars / 125);      // 5太阳 = 125星
        var remaining = totalStars % 125;
        var suns = Math.floor(remaining / 25);          // 5月亮 = 25星
        remaining %= 25;
        var moons = Math.floor(remaining / 5);          // 5星 = 1月亮
        var stars = remaining % 5;

        var icons = '';
        // 用 repeat 生成对应数量图标
        if (crowns > 0) icons += '👑'.repeat(crowns);
        if (suns > 0)   icons += '☀️'.repeat(suns);
        if (moons > 0)  icons += '🌙'.repeat(moons);
        if (stars > 0)  icons += '⭐'.repeat(stars);
        return icons;
    }

    // 更新或创建等级图标元素
    function updateLevelIcons($link, editcount) {
        var iconStr = getLevelIcons(editcount);
        var $iconSpan = $link.next('.user-level-icons');

        if (iconStr === '') {
            // 编辑数不够,移除图标
            $iconSpan.remove();
            return;
        }

        if ($iconSpan.length === 0) {
            $iconSpan = $('<span class="user-level-icons"></span>');
            $link.after($iconSpan);
        }
        $iconSpan.text(iconStr);
    }

    // ==================== 核心处理流程 ====================
    function colorizeAndStatus($links) {
        if ($links.length === 0) return;

        var $fresh = $links.filter(function () {
            return !$(this).data('user-status-processed');
        });
        if ($fresh.length === 0) return;

        var users = [];
        $fresh.each(function () {
            var name = getUserName(this);
            if (name && users.indexOf(name) === -1) users.push(name);
        });
        if (users.length === 0) return;

        $fresh.each(function () {
            $(this).data('user-status-processed', true);
        });

        // 1. 批量查询编辑数(用于颜色 + 等级图标)
        var batchSize = 50;
        var batches = [];
        for (var i = 0; i < users.length; i += batchSize) {
            batches.push(users.slice(i, i + batchSize));
        }

        var processBatch = function (batch) {
            var api = new mw.Api();
            return api.get({
                action: 'query',
                list: 'users',
                ususers: batch.join('|'),
                usprop: 'editcount'
            }).then(function (data) {
                var classMap = {};
                var editCountMap = {};
                if (data.query && data.query.users) {
                    data.query.users.forEach(function (u) {
                        var ec = u.editcount || 0;
                        editCountMap[u.name] = ec;
                        // 颜色等级判定
                        if (ec >= 5000) classMap[u.name] = 'rainbow-user';
                        else if (ec >= 2000) classMap[u.name] = 'gold-user';
                        else if (ec >= 1000) classMap[u.name] = 'platinum-user';
                        else if (ec >= 500) classMap[u.name] = 'silver-user';
                        else if (ec >= 1) classMap[u.name] = 'bronze-user';
                    });
                }
                // 应用颜色和等级图标
                $fresh.each(function () {
                    var $this = $(this);
                    var name = getUserName(this);
                    var cls = classMap[name];
                    if (cls) {
                        $this.removeClass('bronze-user silver-user platinum-user gold-user rainbow-user');
                        $this.addClass(cls);
                    }
                    // 更新等级图标
                    var ec = editCountMap[name];
                    if (typeof ec !== 'undefined') {
                        updateLevelIcons($this, ec);
                    }
                });
            });
        };

        var colorPromise = $.Deferred().resolve();
        batches.forEach(function (batch) {
            colorPromise = colorPromise.then(function () {
                return processBatch(batch);
            });
        });

        // 2. 非卡片区域:状态圆点 + 师徒标签
        $fresh.each(function () {
            if (isUserLink(this)) {
                var isInsideCard = $(this).closest('.citizen-menu_card-content, .citizen-userMenu').length > 0;
                if (!isInsideCard) {
                    var username = getUserName(this);
                    addStatusDot($(this), username);
                    addMentorTag($(this), username);
                }
            }
        });
    }

    // ==================== 状态圆点(不变) ====================
    function addStatusDot($link, username) {
        if ($link.data('status-dot-added')) return;
        $link.data('status-dot-added', true);

        var $dot = $('<span class="user-status-dot status-offline" title="离线"></span>');
        $link.after($dot);  // 会插入在等级图标之后,无所谓顺序

        var cacheKey = 'mw_user_status_' + mw.config.get('wgDBname') + '_' + username;
        var cached = localStorage.getItem(cacheKey);
        var now = Date.now();
        if (cached) {
            try {
                var data = JSON.parse(cached);
                if (now - data.timestamp < 5 * 60 * 1000) {
                    updateDotStyle($dot, data.lastEditTime);
                    return;
                }
            } catch (e) {}
        }

        var api = new mw.Api();
        api.get({
            action: 'query',
            list: 'usercontribs',
            ucuser: username,
            uclimit: 1,
            ucprop: 'timestamp'
        }).then(function (data) {
            var lastEditTime = null;
            if (data.query && data.query.usercontribs && data.query.usercontribs.length > 0) {
                lastEditTime = data.query.usercontribs[0].timestamp;
            }
            localStorage.setItem(cacheKey, JSON.stringify({
                lastEditTime: lastEditTime,
                timestamp: now
            }));
            updateDotStyle($dot, lastEditTime);
        }).fail(function () {});
    }

    function updateDotStyle($dot, lastEditTime) {
        if (!lastEditTime) {
            $dot.attr('title', '离线');
            $dot.removeClass('status-online status-away').addClass('status-offline');
            return;
        }
        var last = new Date(lastEditTime).getTime();
        var diffMinutes = (Date.now() - last) / 60000;
        if (diffMinutes < 15) {
            $dot.attr('title', '在线(15分钟内活跃)');
            $dot.removeClass('status-offline status-away').addClass('status-online');
        } else if (diffMinutes < 60) {
            $dot.attr('title', '近期活跃(1小时内)');
            $dot.removeClass('status-offline status-online').addClass('status-away');
        } else {
            $dot.attr('title', '离线');
            $dot.removeClass('status-online status-away').addClass('status-offline');
        }
    }

    // ==================== 师徒标签 ====================
    function addMentorTag($link, username) {
        if ($link.data('mentor-tag-added')) return;
        if ($link.next('.user-tag').length) return;

        if (mentorList.indexOf(username) !== -1) {
            $link.data('mentor-tag-added', true);
            var $tag = $('<span class="user-tag user-tag-mentor">导师</span>');
            $link.after($tag);
            return;
        }

        // 新手判定(带缓存)
        if ($link.data('newbie-tag-checked')) return;
        $link.data('newbie-tag-checked', true);

        var cacheKey = 'mw_newbie_check_' + mw.config.get('wgDBname') + '_' + username;
        var cached = localStorage.getItem(cacheKey);
        var now = Date.now();
        if (cached) {
            try {
                var data = JSON.parse(cached);
                if (now - data.timestamp < 60 * 60 * 1000) {
                    if (data.editcount <= newbieEditThreshold) {
                        var $tag = $('<span class="user-tag user-tag-newbie">新手</span>');
                        $link.after($tag);
                    }
                    return;
                }
            } catch (e) {}
        }

        var api = new mw.Api();
        api.get({
            action: 'query',
            list: 'users',
            ususers: username,
            usprop: 'editcount'
        }).then(function (data) {
            var editcount = 0;
            if (data.query && data.query.users && data.query.users.length > 0) {
                editcount = data.query.users[0].editcount || 0;
            }
            localStorage.setItem(cacheKey, JSON.stringify({
                editcount: editcount,
                timestamp: now
            }));
            if (editcount <= newbieEditThreshold) {
                if ($link.next('.user-tag-newbie').length === 0) {
                    var $tag = $('<span class="user-tag user-tag-newbie">新手</span>');
                    $link.after($tag);
                }
            }
        }).fail(function () {});
    }

    // ==================== 启动 ====================
    var linkSelector = 'a.mw-userlink, .citizen-menu_card-content a, .citizen-userMenu a';

    colorizeAndStatus($(linkSelector));

    var observer = new MutationObserver(function () {
        colorizeAndStatus($(linkSelector));
    });
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    setInterval(function () {
        colorizeAndStatus($(linkSelector));
    }, 3000);
});