MediaWiki:Common.js:修订间差异
MediaWiki界面页面
更多操作
无编辑摘要 |
无编辑摘要 |
||
| (未显示同一用户的13个中间版本) | |||
| 第2行: | 第2行: | ||
// 自动加载 MediaWiki:Footer 页面内容,并插入到每个页面底部 | // 自动加载 MediaWiki:Footer 页面内容,并插入到每个页面底部 | ||
$(document).ready(function() { | $(document).ready(function() { | ||
const namespace = mw.config.get('wgNamespaceNumber'); | const namespace = mw.config.get('wgNamespaceNumber'); | ||
| 第20行: | 第19行: | ||
}); | }); | ||
}); | }); | ||
// 用户颜色、图标、状态、师徒、植物/僵尸筛选 主逻辑 | |||
$(function () { | $(function () { | ||
// 动态注入彩虹样式 | // ==================== 动态注入彩虹样式 ==================== | ||
var rainbowStyle = document.createElement('style'); | var rainbowStyle = document.createElement('style'); | ||
rainbowStyle.textContent = | rainbowStyle.textContent = | ||
| 第30行: | 第31行: | ||
'-webkit-text-fill-color: transparent;' + | '-webkit-text-fill-color: transparent;' + | ||
'background-clip: text;' + | 'background-clip: text;' + | ||
'}'; | '}'; | ||
document.head.appendChild(rainbowStyle); | document.head.appendChild(rainbowStyle); | ||
// | // ==================== 配置区 ==================== | ||
var | var mentorList = ['愤怒的郎朗', 'Yuyaabc', '虚位以待', '知更鸟头号粉丝', '凌玥']; // 导师名单 | ||
var newbieEditThreshold = 25; // 新手编辑数 ≤ 25 | |||
// | // ==================== 辅助函数 ==================== | ||
function getUserName(link) { | function getUserName(link) { | ||
var $span = $(link).find('span').first(); | var $span = $(link).find('span').first(); | ||
| 第64行: | 第45行: | ||
} | } | ||
// | 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 ''; | |||
var crowns = Math.floor(totalStars / 125); // 5太阳 = 125星 = 1王冠 | |||
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 = ''; | |||
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; | ||
var $fresh = $links.filter(function () { | var $fresh = $links.filter(function () { | ||
return !$(this).data('user-status-processed'); | return !$(this).data('user-status-processed'); | ||
| 第74行: | 第92行: | ||
if ($fresh.length === 0) return; | if ($fresh.length === 0) return; | ||
var users = []; | var users = []; | ||
$fresh.each(function () { | $fresh.each(function () { | ||
| 第82行: | 第99行: | ||
if (users.length === 0) return; | if (users.length === 0) return; | ||
$fresh.each(function () { | $fresh.each(function () { | ||
$(this).data('user-status-processed', true); | $(this).data('user-status-processed', true); | ||
}); | }); | ||
// | // 批量查询编辑数 | ||
var batchSize = 50; | var batchSize = 50; | ||
var batches = []; | var batches = []; | ||
| 第94行: | 第110行: | ||
} | } | ||
var | var processBatch = function (batch) { | ||
var api = new mw.Api(); | var api = new mw.Api(); | ||
return api.get({ | return api.get({ | ||
| 第103行: | 第119行: | ||
}).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 >= | else if (ec >= 2500) classMap[u.name] = 'gold-user'; | ||
else if (ec >= 1000) classMap[u.name] = 'platinum-user'; | else if (ec >= 1000) classMap[u.name] = 'platinum-user'; | ||
else if (ec >= 500) classMap[u.name] = 'silver-user'; | else if (ec >= 500) classMap[u.name] = 'silver-user'; | ||
| 第120行: | 第138行: | ||
$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); | |||
} | } | ||
}); | }); | ||
| 第128行: | 第150行: | ||
batches.forEach(function (batch) { | batches.forEach(function (batch) { | ||
colorPromise = colorPromise.then(function () { | colorPromise = colorPromise.then(function () { | ||
return | return processBatch(batch); | ||
}); | }); | ||
}); | }); | ||
// | // 非卡片区域:状态圆点 + 师徒标签 | ||
$fresh.each(function () { | $fresh.each(function () { | ||
var | 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) { | 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="离线"></span>'); | |||
var $dot = $('<span class="user-status-dot status-offline" title="离线">'); | |||
$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; | ||
var cached = localStorage.getItem(cacheKey); | var cached = localStorage.getItem(cacheKey); | ||
| 第157行: | 第181行: | ||
try { | try { | ||
var data = JSON.parse(cached); | var data = JSON.parse(cached); | ||
if (now - data.timestamp < 5 * 60 * 1000) { | if (now - data.timestamp < 5 * 60 * 1000) { | ||
updateDotStyle($dot, data.lastEditTime); | updateDotStyle($dot, data.lastEditTime); | ||
| 第165行: | 第188行: | ||
} | } | ||
var api = new mw.Api(); | var api = new mw.Api(); | ||
api.get({ | api.get({ | ||
| 第178行: | 第200行: | ||
lastEditTime = data.query.usercontribs[0].timestamp; | lastEditTime = data.query.usercontribs[0].timestamp; | ||
} | } | ||
localStorage.setItem(cacheKey, JSON.stringify({ | localStorage.setItem(cacheKey, JSON.stringify({ | ||
lastEditTime: lastEditTime, | lastEditTime: lastEditTime, | ||
| 第184行: | 第205行: | ||
})); | })); | ||
updateDotStyle($dot, lastEditTime); | updateDotStyle($dot, lastEditTime); | ||
}).fail(function () { | }).fail(function () {}); | ||
} | } | ||
function updateDotStyle($dot, lastEditTime) { | function updateDotStyle($dot, lastEditTime) { | ||
if (!lastEditTime) { | if (!lastEditTime) { | ||
| 第197行: | 第215行: | ||
} | } | ||
var last = new Date(lastEditTime).getTime(); | var last = new Date(lastEditTime).getTime(); | ||
var | var diffMinutes = (Date.now() - last) / 60000; | ||
if (diffMinutes < 15) { | if (diffMinutes < 15) { | ||
$dot.attr('title', '在线(15分钟内活跃)'); | $dot.attr('title', '在线(15分钟内活跃)'); | ||
| 第211行: | 第228行: | ||
} | } | ||
// | // ==================== 师徒标签(已修复 $tag 重复声明) ==================== | ||
function addMentorTag($link, username) { | |||
if ($link.data('mentor-tag-added')) return; | |||
if ($link.next('.user-tag').length) return; | |||
var $tag; // 统一声明一次 | |||
if (mentorList.indexOf(username) !== -1) { | |||
$link.data('mentor-tag-added', true); | |||
$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) { | |||
$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) { | |||
$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'; | var linkSelector = 'a.mw-userlink, .citizen-menu_card-content a, .citizen-userMenu a'; | ||
colorizeAndStatus($(linkSelector)); | colorizeAndStatus($(linkSelector)); | ||
var observer = new MutationObserver(function () { | var observer = new MutationObserver(function () { | ||
colorizeAndStatus($(linkSelector)); | colorizeAndStatus($(linkSelector)); | ||
| 第226行: | 第297行: | ||
}); | }); | ||
setInterval(function () { | setInterval(function () { | ||
colorizeAndStatus($(linkSelector)); | colorizeAndStatus($(linkSelector)); | ||
}, 3000); | }, 3000); | ||
}); | |||
// ==================== 植物卡片筛选 ==================== | |||
if ($('#pf-name').length) { | |||
var $cards = $('.pvzhe-card'); | |||
var $name = $('#pf-name'); | |||
var $sunMax = $('#pf-sun-max'); | |||
var $cdMax = $('#pf-cd-max'); | |||
var $type = $('#pf-type'); | |||
var $reset = $('#pf-reset'); | |||
function filterPlants() { | |||
var name = $name.val().toLowerCase(); | |||
var sunRaw = $sunMax.val().trim(); | |||
var cdRaw = $cdMax.val().trim(); | |||
var sunTarget = sunRaw !== '' ? parseFloat(sunRaw) : null; | |||
var cdTarget = cdRaw !== '' ? parseFloat(cdRaw) : null; | |||
var type = $type.val(); | |||
$cards.each(function () { | |||
var $card = $(this); | |||
var n = $card.find('.pvzhe-card-name').text().toLowerCase(); | |||
var sun = parseFloat($card.data('sun')) || 0; | |||
var cd = parseFloat($card.data('cooldown')) || 0; | |||
var t = ($card.data('type') || '').toString(); | |||
var show = true; | |||
if (name && n.indexOf(name) === -1) show = false; | |||
if (sunTarget !== null && sun !== sunTarget) show = false; | |||
if (cdTarget !== null && cd !== cdTarget) show = false; | |||
if (type) { | |||
var cardTypes = t.split(',').map(function (s) { return s.trim(); }); | |||
if (cardTypes.indexOf(type) === -1) show = false; | |||
} | |||
$card.toggleClass('hidden-card', !show); | |||
}); | |||
} | |||
$name.on('input', filterPlants); | |||
$sunMax.on('input keyup', filterPlants); | |||
$cdMax.on('input keyup', filterPlants); | |||
$type.on('change', filterPlants); | |||
$reset.on('click', function () { | |||
$name.val(''); | |||
$sunMax.val(''); | |||
$cdMax.val(''); | |||
$type.val(''); | |||
filterPlants(); | |||
}); | |||
} | |||
// ==================== 僵尸卡片筛选(分开的防具与血量) ==================== | |||
// 辅助:提取防具数组(无“+”返回空数组) | |||
function getArmorArray(healthStr) { | |||
if (!healthStr || healthStr.indexOf('+') === -1) return []; | |||
var armorPart = healthStr.split('+')[0].trim(); | |||
return armorPart.split(',').map(function(s) { return s.trim(); }); | |||
} | |||
// 辅助:提取本体血量(最后一个数字) | |||
function extractHealth(healthStr) { | |||
var matches = healthStr.match(/\d+/g); | |||
if (matches && matches.length > 0) { | |||
return parseFloat(matches[matches.length - 1]) || 0; | |||
} | |||
return 0; | |||
} | |||
if ($('#zf-name').length) { | |||
var $zcards = $('.pvzhe-card'); | |||
var $zname = $('#zf-name'); | |||
var $healthMin = $('#zf-health-min'); | |||
var $armor = $('#zf-armor'); | |||
var $speed = $('#zf-speed'); | |||
var $ztype = $('#zf-type'); | |||
var $zreset = $('#zf-reset'); | |||
function filterZombies() { | |||
var name = $zname.val().toLowerCase(); | |||
var healthRaw = $healthMin.val().trim(); | |||
var healthTarget = healthRaw !== '' ? parseFloat(healthRaw) : null; | |||
var armor = $armor.val(); | |||
var speed = $speed.val(); | |||
var type = $ztype.val(); | |||
$zcards.each(function () { | |||
var $card = $(this); | |||
var n = $card.find('.pvzhe-card-name').text().toLowerCase(); | |||
var t = ($card.data('type') || '').toString(); | |||
var s = ($card.data('speed') || '').toString(); | |||
var healthStr = ($card.data('health') || '').toString(); | |||
var health = extractHealth(healthStr); | |||
var armors = getArmorArray(healthStr); | |||
var show = true; | |||
if (name && n.indexOf(name) === -1) show = false; | |||
if (healthTarget !== null && health !== healthTarget) show = false; | |||
// 防具筛选 | |||
if (armor === 'none') { | |||
// 只显示无防具的僵尸(armors 为空) | |||
if (armors.length > 0) show = false; | |||
} else if (armor) { | |||
// 选择了具体防具,数组中必须包含该防具 | |||
if (armors.indexOf(armor) === -1) show = false; | |||
} | |||
if (speed) { | |||
var cardSpeeds = s.split(',').map(function (v) { return v.trim(); }); | |||
if (cardSpeeds.indexOf(speed) === -1) show = false; | |||
} | |||
if (type) { | |||
var cardTypes = t.split(',').map(function (v) { return v.trim(); }); | |||
if (cardTypes.indexOf(type) === -1) show = false; | |||
} | |||
$card.toggleClass('hidden-card', !show); | |||
}); | |||
} | |||
$zname.on('input', filterZombies); | |||
$healthMin.on('input keyup', filterZombies); | |||
$armor.on('change', filterZombies); | |||
$speed.on('change', filterZombies); | |||
$ztype.on('change', filterZombies); | |||
$zreset.on('click', function () { | |||
$zname.val(''); | |||
$healthMin.val(''); | |||
$armor.val(''); | |||
$speed.val(''); | |||
$ztype.val(''); | |||
filterZombies(); | |||
}); | |||
} | |||
}); // 结束主 $(function () { ... }) | |||
2026年6月1日 (一) 10:20的最新版本
/* 这里的任何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 '';
var crowns = Math.floor(totalStars / 125); // 5太阳 = 125星 = 1王冠
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 = '';
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);
});
// 批量查询编辑数
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 >= 2500) 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);
});
});
// 非卡片区域:状态圆点 + 师徒标签
$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');
}
}
// ==================== 师徒标签(已修复 $tag 重复声明) ====================
function addMentorTag($link, username) {
if ($link.data('mentor-tag-added')) return;
if ($link.next('.user-tag').length) return;
var $tag; // 统一声明一次
if (mentorList.indexOf(username) !== -1) {
$link.data('mentor-tag-added', true);
$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) {
$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) {
$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);
// ==================== 植物卡片筛选 ====================
if ($('#pf-name').length) {
var $cards = $('.pvzhe-card');
var $name = $('#pf-name');
var $sunMax = $('#pf-sun-max');
var $cdMax = $('#pf-cd-max');
var $type = $('#pf-type');
var $reset = $('#pf-reset');
function filterPlants() {
var name = $name.val().toLowerCase();
var sunRaw = $sunMax.val().trim();
var cdRaw = $cdMax.val().trim();
var sunTarget = sunRaw !== '' ? parseFloat(sunRaw) : null;
var cdTarget = cdRaw !== '' ? parseFloat(cdRaw) : null;
var type = $type.val();
$cards.each(function () {
var $card = $(this);
var n = $card.find('.pvzhe-card-name').text().toLowerCase();
var sun = parseFloat($card.data('sun')) || 0;
var cd = parseFloat($card.data('cooldown')) || 0;
var t = ($card.data('type') || '').toString();
var show = true;
if (name && n.indexOf(name) === -1) show = false;
if (sunTarget !== null && sun !== sunTarget) show = false;
if (cdTarget !== null && cd !== cdTarget) show = false;
if (type) {
var cardTypes = t.split(',').map(function (s) { return s.trim(); });
if (cardTypes.indexOf(type) === -1) show = false;
}
$card.toggleClass('hidden-card', !show);
});
}
$name.on('input', filterPlants);
$sunMax.on('input keyup', filterPlants);
$cdMax.on('input keyup', filterPlants);
$type.on('change', filterPlants);
$reset.on('click', function () {
$name.val('');
$sunMax.val('');
$cdMax.val('');
$type.val('');
filterPlants();
});
}
// ==================== 僵尸卡片筛选(分开的防具与血量) ====================
// 辅助:提取防具数组(无“+”返回空数组)
function getArmorArray(healthStr) {
if (!healthStr || healthStr.indexOf('+') === -1) return [];
var armorPart = healthStr.split('+')[0].trim();
return armorPart.split(',').map(function(s) { return s.trim(); });
}
// 辅助:提取本体血量(最后一个数字)
function extractHealth(healthStr) {
var matches = healthStr.match(/\d+/g);
if (matches && matches.length > 0) {
return parseFloat(matches[matches.length - 1]) || 0;
}
return 0;
}
if ($('#zf-name').length) {
var $zcards = $('.pvzhe-card');
var $zname = $('#zf-name');
var $healthMin = $('#zf-health-min');
var $armor = $('#zf-armor');
var $speed = $('#zf-speed');
var $ztype = $('#zf-type');
var $zreset = $('#zf-reset');
function filterZombies() {
var name = $zname.val().toLowerCase();
var healthRaw = $healthMin.val().trim();
var healthTarget = healthRaw !== '' ? parseFloat(healthRaw) : null;
var armor = $armor.val();
var speed = $speed.val();
var type = $ztype.val();
$zcards.each(function () {
var $card = $(this);
var n = $card.find('.pvzhe-card-name').text().toLowerCase();
var t = ($card.data('type') || '').toString();
var s = ($card.data('speed') || '').toString();
var healthStr = ($card.data('health') || '').toString();
var health = extractHealth(healthStr);
var armors = getArmorArray(healthStr);
var show = true;
if (name && n.indexOf(name) === -1) show = false;
if (healthTarget !== null && health !== healthTarget) show = false;
// 防具筛选
if (armor === 'none') {
// 只显示无防具的僵尸(armors 为空)
if (armors.length > 0) show = false;
} else if (armor) {
// 选择了具体防具,数组中必须包含该防具
if (armors.indexOf(armor) === -1) show = false;
}
if (speed) {
var cardSpeeds = s.split(',').map(function (v) { return v.trim(); });
if (cardSpeeds.indexOf(speed) === -1) show = false;
}
if (type) {
var cardTypes = t.split(',').map(function (v) { return v.trim(); });
if (cardTypes.indexOf(type) === -1) show = false;
}
$card.toggleClass('hidden-card', !show);
});
}
$zname.on('input', filterZombies);
$healthMin.on('input keyup', filterZombies);
$armor.on('change', filterZombies);
$speed.on('change', filterZombies);
$ztype.on('change', filterZombies);
$zreset.on('click', function () {
$zname.val('');
$healthMin.val('');
$armor.val('');
$speed.val('');
$ztype.val('');
filterZombies();
});
}
}); // 结束主 $(function () { ... })