注意:在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。
?_=1来访问最新页面。https://zh.moegirl.org.cn/User:%E5%85%AC%E7%9A%84%E9%A9%B1%E9%80%90%E8%88%B0/ak_index_supplement.js?_=1/* global mw, $ */
"use strict";
window.RLQ = window.RLQ || [];
window.RLQ.push(async () => {
await mw.loader.using(["mediawiki.notification", "mw.Api"]);
const api = new mw.Api();
const dic = {};
const eliteType = ["1+", "2", "3"];
const thumbCache = {};
//函数:检查半身像是否存在
const ifexist = async (opName, type) => {
for (let retryTimes = 0; retryTimes < 3; retryTimes++) {
try {
const result = (await api.post({
action: "query",
titles: `Media:半身像_${opName}_${type}.png`,
prop: "info",
})).query.pages["-1"];
return !("missing" in result || "invalid" in result);
} catch (e) {
console.error("ifexist", e);
}
}
return false;
};
//函数:获取指定的缩略图链接
const getThumb = async (files) => {
const postInfo = {};
files.forEach(([filename, thumbWidth]) => {
(postInfo[thumbWidth] = postInfo[thumbWidth] || new Set()).add(filename);
});
return Object.fromEntries(await Promise.all(Object.entries(postInfo).map(async ([thumbWidth, filenames]) => {
const result = {};
if (!(thumbWidth in thumbCache)) {
thumbCache[thumbWidth] = {};
}
for (const filename of filenames) {
if (filename in thumbCache[thumbWidth]) {
result[filename] = thumbCache[thumbWidth][filename];
filenames.delete(filename);
}
}
if (filenames.size === 0) {
return [thumbWidth, result];
}
for (let retryTimes = 0; retryTimes < 3; retryTimes++) {
try {
const data = await api.post({
action: "query",
titles: Array.from(filenames.values()).join("|"),
prop: "imageinfo",
iiprop: "url",
iiurlwidth: thumbWidth,
});
const normalized = Object.fromEntries(data.query.normalized.map(({ from, to }) => [to, from]));
Object.entries(data.query.pages).forEach(([, { title, imageinfo: [{ thumburl }] }]) => {
thumbCache[thumbWidth][normalized[title]] = result[normalized[title]] = thumburl;
});
return [thumbWidth, result];
} catch (e) {
console.info("getThumb", e, files);
}
}
return [thumbWidth, result];
})));
};
//函数:初始化词典
const init = async (opName) => {
if (!Array.isArray(dic[opName])) {
dic[opName] = [];
}
//检查半身像词典是否包含无精;如果没有的话词典应当是空的,写词典
if (!dic[opName].includes("1")) {
dic[opName].push("1");
if (await ifexist(opName, "1+")) {
dic[opName].push("1+");
}
if (await ifexist(opName, "2")) {
dic[opName].push("2");
}
//如果有精三、四,etc. 的话加在这里
for (let i = 1; await ifexist(opName, `skin${i}`); i++) {
dic[opName].push(`skin${i}`);
}
}
};
//函数:变更半身像的HTML元素(加载新半身像)
const changeImage = async (root, opName, typeId) => {
const layer2Filename = `File:半身像_${opName}_${typeId}.png`;
const layer6Filename = `File:精英${eliteType.includes(typeId) ? typeId : "1"}_图标.png`;
const thumbInfos = await getThumb([
[layer2Filename, 180],
[layer6Filename, 67],
]);
root.find(".akIllLayer2 > img").removeAttr("height srcset").attr("src", thumbInfos[180][layer2Filename]);
root.find(".akIllLayer6 > img").removeAttr("height srcset").attr("src", thumbInfos[67][layer6Filename]);
};
//函数:步进半身像
const change = async (root, opName, showBubble = true) => {
root.data("supplement_running", true);
dic[opName] = dic[opName] || [];
if (showBubble) {
mw.notify(`正在加载${opName}的下一张立绘……`, {
title: "明日方舟:图鉴切换",
tag: `akIll_supplement_${Object.keys(dic).indexOf(opName)}`,
});
}
await init(opName);
const info = dic[opName];
const currentType = `${root.data("type") || "1"}`;
if (info.length !== 1) {
//下一个半身像的顺位
const nextId = (info.indexOf(currentType) + 1) % info.length;
//准备下一套图片
const nextType = info[nextId];
await changeImage(root, opName, nextType);
root.data({
supplement_running: false,
type: nextType,
});
} else {
if (showBubble) {
mw.notify(`${opName}只有这一张立绘……`, {
title: "明日方舟:图鉴切换",
tag: `akIll_supplement_${Object.keys(dic).indexOf(opName)}`,
});
}
root.data("supplement_running", false);
}
};
//函数:切换到指定半身像
const changeTo = async (root, opName, typeId, showBubble = true) => {
root.data("supplement_running", true);
dic[opName] = dic[opName] || [];
//准备可读半身像类型,顺带检查type是否合法;不合法则强制bubble报错
let readableType;
switch (typeId) {
case "1":
readableType = "无精英立绘";
break;
case "1+":
readableType = "精英一立绘";
break;
case "2":
readableType = "精英二立绘";
break;
default:
if (typeId.startsWith("skin")) {
readableType = `时装 ${typeId.substring(4)}`;
} else {
mw.notify(`无法加载${opName}的图鉴“${typeId}”:图鉴名称不合法`, {
title: "明日方舟:图鉴切换",
tag: `akIll_supplement_${Object.keys(dic).indexOf(opName)}`,
});
root.data("supplement_running", false);
return false;
}
}
if (showBubble) {
mw.notify(`正在尝试加载${opName}的${readableType}……`, {
title: "明日方舟:图鉴切换",
tag: `akIll_supplement_${Object.keys(dic).indexOf(opName)}`,
});
}
await init(opName);
const info = dic[opName];
//目标半身像的顺位
if (!info.includes(typeId)) {
if (showBubble) {
mw.notify(`无法加载${opName}的${readableType}:该图鉴不存在`, {
title: "明日方舟:图鉴切换",
tag: `akIll_supplement_${Object.keys(dic).indexOf(opName)}`,
});
}
root.data("supplement_running", false);
return false;
}
//准备下一套图片
await changeImage(root, opName, typeId);
root.data({
supplement_running: false,
type: typeId,
});
};
//点击一键无精按钮的事件
$("#button-IndexAllE0").css("cursor", "pointer").on("click", () => {
console.log("AllE0 button triggered");
mw.notify("正在加载所有干员的无精英立绘……", {
title: "明日方舟:图鉴切换",
tag: "akIll_supplement_AllE0",
});
$(".akIll").each((_, ele) => {
changeTo($(ele), ele.dataset.operatorName, "1", false);
});
});
//点击一键精二按钮的事件
$("#button-IndexAllE2").css("cursor", "pointer").on("click", () => {
console.log("AllE2 button triggered");
mw.notify("正在加载四星及以上干员的精英二立绘……", {
title: "明日方舟:图鉴切换",
tag: "akIll_supplement_AllE2",
});
$(".akIll").each((_, ele) => {
changeTo($(ele), ele.dataset.operatorName, "2", false);
});
});
//点击一键服装按钮的事件
$("#button-IndexAllSkin1").css("cursor", "pointer").on("click", () => {
console.log("AllSkin1 button triggered");
mw.notify("正在加载拥有时装的干员的第一套时装……", {
title: "明日方舟:图鉴切换",
tag: "akIll_supplement_AllSkin1",
});
$(".akIll").each((_, ele) => {
changeTo($(ele), ele.dataset.operatorName, "skin1", false);
});
});
//点击图鉴模板的事件
$(".akIll").css("cursor", "pointer").on("click", ({
target,
}) => {
if ($(target).closest(".akIll a").length > 0) {
return true;
}
const root = $(target).closest(".akIll");
if (root.data("supplement_running")) {
return false;
}
const opName = root.attr("data-operator-name");
change(root, opName);
return false;
});
});