MediaWiki:Gadget-ShowContributors.js:修订间差异
MediaWiki界面页面
更多操作
![]() OctoberSama(留言 | 贡献) 小 |
![]() OctoberSama(留言 | 贡献) 小 |
||
第1行: | 第1行: | ||
(() | (function() { | ||
"use strict"; | "use strict"; | ||
mw.hook("wikipage.content").add(() => { | |||
console.log("ShowContributors.js 开始执行", { | |||
mediaWikiVersion: mw.config.get("wgVersion"), | |||
skin: mw.config.get("skin"), | |||
namespace: mw.config.get("wgNamespaceNumber"), | |||
action: mw.config.get("wgAction"), | |||
articleId: mw.config.get("wgArticleId") | |||
}); | |||
if ( | if ( | ||
![0, 2, 4, 10, 12, 14, 828, 274].includes(mw.config.get("wgNamespaceNumber")) || | ![0, 2, 4, 10, 12, 14, 828, 274].includes(mw.config.get("wgNamespaceNumber")) || | ||
0 === mw.config.get("wgArticleId") || | 0 === mw.config.get("wgArticleId") || | ||
!["view", "history"].includes(mw.config.get("wgAction")) | !["view", "history"].includes(mw.config.get("wgAction")) | ||
) | ) { | ||
console.log("脚本因条件不满足退出"); | |||
return; | return; | ||
} | |||
mw.loader.addStyleTag(` | mw.loader.addStyleTag(` | ||
#show-contributor-button { | #show-contributor-button { | ||
第71行: | 第81行: | ||
`); | `); | ||
mw.loader.using([ | |||
"mediawiki.api", | "mediawiki.api", | ||
"mediawiki.notification", | "mediawiki.notification", | ||
第77行: | 第87行: | ||
"oojs-ui.styles.icons-interactions", | "oojs-ui.styles.icons-interactions", | ||
"jquery.tablesorter" | "jquery.tablesorter" | ||
]); | ]).then(() => { | ||
console.log("依赖模块加载成功"); | |||
class ShowContributorDialog extends OO.ui.Dialog { | |||
constructor(config) { | |||
super(config); | |||
this.$table = $('<table id="show-contributor-table" class="wikitable" />'); | |||
this.$tbody = $("<tbody />"); | |||
this.got = false; | |||
} | |||
static name = "ShowContributor"; | |||
static tagName = "div"; | |||
initialize() { | |||
super.initialize(); | |||
this.$body.append( | |||
$('<div id="show-contributor-header" />').append( | |||
$('<div id="show-contributor-headline">本页贡献统计</div>'), | |||
new OO.ui.IconWidget({ icon: "close", id: "show-contributor-close" }).$element.on("click", () => this.close()) | |||
), | |||
this.$table.append( | |||
$("<thead><th>用户</th><th>编辑数</th><th>增加字节数</th><th>删减字节数</th></thead>"), | |||
this.$tbody | |||
) | |||
); | |||
return this; | |||
} | |||
getContributors = async () => { | |||
console.log("开始获取贡献者数据"); | |||
const api = new mw.Api(); | |||
const contributors = {}; | |||
let continueToken = ""; | |||
let prevSize = 0; | |||
const params = { | |||
action: "query", | |||
format: "json", | |||
prop: "revisions", | |||
titles: mw.config.get("wgPageName"), | |||
rvprop: "user|size", | |||
rvlimit: "max", | |||
rvdir: "newer" | |||
}; | |||
do { | |||
if (continueToken) params.rvcontinue = continueToken; | |||
try { | |||
const response = await api.get(params); | |||
continueToken = response.continue?.rvcontinue; | |||
for (const { user, size } of Object.values(response.query.pages)[0].revisions) { | |||
contributors[user] = contributors[user] || []; | |||
contributors[user].push(size - prevSize); | |||
prevSize = size; | |||
} | |||
} catch (error) { | |||
console.error("API 请求失败:", error); | |||
mw.notify(`获取编辑记录失败:${error}`, { type: "error" }); | |||
} | |||
} while (continueToken); | |||
console.log("贡献者数据:", contributors); | |||
return contributors; | |||
}; | |||
addRow = (tbody, { user, count, add, remove }) => { | |||
tbody.append( | |||
$("<tr />").append( | |||
$("<td />").append( | |||
$(`<a href="${mw.config.get("wgArticlePath").replace("$1", `User:${user}`)}" />`).text(user) | |||
), | |||
`<td>${count}</td>`, | |||
`<td>${add}</td>`, | |||
`<td>${remove}</td>` | |||
) | |||
); | |||
}; | }; | ||
showContributors = (contributors) => { | |||
this.$tbody.empty(); | |||
for (const user in contributors) { | |||
this.addRow(this.$tbody, { | |||
user, | |||
count: contributors[user].length, | |||
add: contributors[user].reduce((s, n) => n > 0 ? s + n : s, 0), | |||
remove: contributors[user].reduce((s, n) => n < 0 ? s + n : s, 0) | |||
}); | |||
} | } | ||
this.got = true; | |||
}; | |||
} | } | ||
const windowManager = new OO.ui.WindowManager({ id: "show-contributor" }); | |||
$(document.body).append(windowManager.$element); | |||
const dialog = new ShowContributorDialog({ size: "large" }); | |||
windowManager.addWindows([dialog]); | |||
const button = new OO.ui.ButtonWidget({ | |||
label: "本页贡献者", | |||
icon: "search", | |||
flags: "progressive", | |||
id: " postcode://show-contributor-button" | |||
}); | |||
const insertButton = () => { | |||
$("#show-contributor-button").detach(); | |||
const skin = mw.config.get("skin"); | |||
console.log("插入按钮,当前皮肤:", skin); | |||
if (skin === "citizen") { | |||
if (window.innerWidth >= 1120) { | |||
if ($(".page-actions").length) { | |||
$(".page-actions").prepend(button.$element); | |||
} else { | |||
console.error("未找到 .page-actions 容器"); | |||
} | |||
} else { | |||
if ($(".firstHeading-container").length) { | |||
$(".firstHeading-container").append(button.$element); | |||
} else { | |||
console.error("未找到 .firstHeading-container 容器"); | |||
} | |||
} | |||
} else if (skin === "vector-2022") { | |||
if ($("header.mw-body-header.vector-page-titlebar").length) { | |||
$("header.mw-body-header.vector-page-titlebar").append(button.$element); | |||
} else { | |||
console.error("未找到 header.mw-body-header.vector-page-titlebar 容器"); | |||
} | |||
} else { | } else { | ||
$(". | if ($("#bodyContent").length) { | ||
$("#bodyContent").prepend(button.$element); | |||
} else { | |||
console.error("未找到 #bodyContent 容器"); | |||
} | |||
} | } | ||
console.log("按钮是否存在:", $("#show-contributor-button").length); | |||
}; | |||
} | |||
insertButton(); | |||
let isWide = window.innerWidth >= 1120; | |||
$(window).on("resize", () => { | |||
clearTimeout(window.__showContributorResizeTimer); | |||
window.__showContributorResizeTimer = setTimeout(() => { | |||
const nowWide = window.innerWidth >= 1120; | |||
if (nowWide !== isWide && mw.config.get("skin") === "citizen") { | |||
isWide = nowWide; | |||
insertButton(); | |||
} | |||
}, 200); | |||
}); | |||
button.on("click", async () => { | |||
console.log("按钮点击,尝试打开窗口"); | |||
if (!dialog.got) { | |||
button.setLabel("正在查询"); | |||
const contributors = await dialog.getContributors(); | |||
dialog.showContributors(contributors); | |||
dialog.$table.tablesorter(); | |||
button.setLabel("本页贡献者"); | |||
} | } | ||
windowManager.openWindow(dialog); | |||
console.log("窗口打开状态:", windowManager); | |||
}); | |||
}).catch(err => { | |||
console.error("模块加载失败:", err); | |||
}); | }); | ||
}) | }); | ||
})(); | })(); |
2025年6月17日 (二) 17:26的版本
(function() { "use strict"; mw.hook("wikipage.content").add(() => { console.log("ShowContributors.js 开始执行", { mediaWikiVersion: mw.config.get("wgVersion"), skin: mw.config.get("skin"), namespace: mw.config.get("wgNamespaceNumber"), action: mw.config.get("wgAction"), articleId: mw.config.get("wgArticleId") }); if ( ![0, 2, 4, 10, 12, 14, 828, 274].includes(mw.config.get("wgNamespaceNumber")) || 0 === mw.config.get("wgArticleId") || !["view", "history"].includes(mw.config.get("wgAction")) ) { console.log("脚本因条件不满足退出"); return; } mw.loader.addStyleTag(` #show-contributor-button { float: right; margin-left: .5em; margin-right: 0; } #show-contributor-header { background: #fff; border-bottom: 1px solid #aaa; font-weight: 600; padding: .3em; position: sticky; text-align: center; top: 0; } #show-contributor-headline { font-size: 1.3em; } #show-contributor-close { border-radius: 50%; cursor: pointer; position: absolute; right: 5px; top: 5px; } #show-contributor-close:hover { background-color: #eee; } #show-contributor-table { margin: 0; width: 100%; } #show-contributor-table .user-avatar { border-radius: 50%; height: 20px; width: 20px; } .skin-citizen #show-contributor-button { float: none; margin: 0 0.5em 0 0; display: inline-flex; align-items: center; vertical-align: middle; } @media (min-width: 1120px) { .skin-citizen .citizen-page-header-inner { display: flex; justify-content: space-between; align-items: center; } .skin-citizen .citizen-page-heading { flex-grow: 1; } } @media (max-width: 1119px) { .skin-citizen #show-contributor-button { margin: 0.5em 0; display: block; } } `); mw.loader.using([ "mediawiki.api", "mediawiki.notification", "oojs-ui", "oojs-ui.styles.icons-interactions", "jquery.tablesorter" ]).then(() => { console.log("依赖模块加载成功"); class ShowContributorDialog extends OO.ui.Dialog { constructor(config) { super(config); this.$table = $('<table id="show-contributor-table" class="wikitable" />'); this.$tbody = $("<tbody />"); this.got = false; } static name = "ShowContributor"; static tagName = "div"; initialize() { super.initialize(); this.$body.append( $('<div id="show-contributor-header" />').append( $('<div id="show-contributor-headline">本页贡献统计</div>'), new OO.ui.IconWidget({ icon: "close", id: "show-contributor-close" }).$element.on("click", () => this.close()) ), this.$table.append( $("<thead><th>用户</th><th>编辑数</th><th>增加字节数</th><th>删减字节数</th></thead>"), this.$tbody ) ); return this; } getContributors = async () => { console.log("开始获取贡献者数据"); const api = new mw.Api(); const contributors = {}; let continueToken = ""; let prevSize = 0; const params = { action: "query", format: "json", prop: "revisions", titles: mw.config.get("wgPageName"), rvprop: "user|size", rvlimit: "max", rvdir: "newer" }; do { if (continueToken) params.rvcontinue = continueToken; try { const response = await api.get(params); continueToken = response.continue?.rvcontinue; for (const { user, size } of Object.values(response.query.pages)[0].revisions) { contributors[user] = contributors[user] || []; contributors[user].push(size - prevSize); prevSize = size; } } catch (error) { console.error("API 请求失败:", error); mw.notify(`获取编辑记录失败:${error}`, { type: "error" }); } } while (continueToken); console.log("贡献者数据:", contributors); return contributors; }; addRow = (tbody, { user, count, add, remove }) => { tbody.append( $("<tr />").append( $("<td />").append( $(`<a href="${mw.config.get("wgArticlePath").replace("$1", `User:${user}`)}" />`).text(user) ), `<td>${count}</td>`, `<td>${add}</td>`, `<td>${remove}</td>` ) ); }; showContributors = (contributors) => { this.$tbody.empty(); for (const user in contributors) { this.addRow(this.$tbody, { user, count: contributors[user].length, add: contributors[user].reduce((s, n) => n > 0 ? s + n : s, 0), remove: contributors[user].reduce((s, n) => n < 0 ? s + n : s, 0) }); } this.got = true; }; } const windowManager = new OO.ui.WindowManager({ id: "show-contributor" }); $(document.body).append(windowManager.$element); const dialog = new ShowContributorDialog({ size: "large" }); windowManager.addWindows([dialog]); const button = new OO.ui.ButtonWidget({ label: "本页贡献者", icon: "search", flags: "progressive", id: " postcode://show-contributor-button" }); const insertButton = () => { $("#show-contributor-button").detach(); const skin = mw.config.get("skin"); console.log("插入按钮,当前皮肤:", skin); if (skin === "citizen") { if (window.innerWidth >= 1120) { if ($(".page-actions").length) { $(".page-actions").prepend(button.$element); } else { console.error("未找到 .page-actions 容器"); } } else { if ($(".firstHeading-container").length) { $(".firstHeading-container").append(button.$element); } else { console.error("未找到 .firstHeading-container 容器"); } } } else if (skin === "vector-2022") { if ($("header.mw-body-header.vector-page-titlebar").length) { $("header.mw-body-header.vector-page-titlebar").append(button.$element); } else { console.error("未找到 header.mw-body-header.vector-page-titlebar 容器"); } } else { if ($("#bodyContent").length) { $("#bodyContent").prepend(button.$element); } else { console.error("未找到 #bodyContent 容器"); } } console.log("按钮是否存在:", $("#show-contributor-button").length); }; insertButton(); let isWide = window.innerWidth >= 1120; $(window).on("resize", () => { clearTimeout(window.__showContributorResizeTimer); window.__showContributorResizeTimer = setTimeout(() => { const nowWide = window.innerWidth >= 1120; if (nowWide !== isWide && mw.config.get("skin") === "citizen") { isWide = nowWide; insertButton(); } }, 200); }); button.on("click", async () => { console.log("按钮点击,尝试打开窗口"); if (!dialog.got) { button.setLabel("正在查询"); const contributors = await dialog.getContributors(); dialog.showContributors(contributors); dialog.$table.tablesorter(); button.setLabel("本页贡献者"); } windowManager.openWindow(dialog); console.log("窗口打开状态:", windowManager); }); }).catch(err => { console.error("模块加载失败:", err); }); }); })();