MediaWiki:Gadget-ShowContributors.js:修订间差异
MediaWiki界面页面
更多操作
![]() OctoberSama(留言 | 贡献) 小 |
![]() OctoberSama(留言 | 贡献) 小 |
||
第6行: | 第6行: | ||
0 === mw.config.get("wgArticleId") || | 0 === mw.config.get("wgArticleId") || | ||
!["view", "history"].includes(mw.config.get("wgAction")) | !["view", "history"].includes(mw.config.get("wgAction")) | ||
) | ) return; | ||
mw.loader.addStyleTag(` | 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; | |||
z-index: 1; | |||
} | |||
#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; | |||
} | |||
/* Citizen 皮肤响应式样式 */ | |||
.skin-citizen #show-contributor-button { | |||
float: none; | |||
margin: 0 0 0 0.5em; | |||
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 .firstHeading-container { | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
} | |||
.skin-citizen #show-contributor-button { | |||
margin: 0; | |||
} | |||
} | |||
`); | `); | ||
await mw.loader.using(["mediawiki.api","mediawiki.notification","oojs-ui","oojs-ui.styles.icons-interactions","jquery.tablesorter"]); | await mw.loader.using([ | ||
"mediawiki.api", | |||
"mediawiki.notification", | |||
"oojs-ui", | |||
"oojs-ui.styles.icons-interactions", | |||
"jquery.tablesorter" | |||
]); | |||
class | class ContributorDialog extends OO.ui.Dialog { | ||
$table = $('<table id="show-contributor-table" class="wikitable" />'); | $table = $('<table id="show-contributor-table" class="wikitable" />'); | ||
$tbody = $("<tbody />"); | $tbody = $("<tbody />"); | ||
got = false; | |||
got = | |||
static static = {...super.static,name:"ShowContributor",tagName:"div"}; | static static = { | ||
...super.static, | |||
name: "ShowContributor", | |||
tagName: "div" | |||
}; | |||
initialize() { | initialize() { | ||
super.initialize(); | |||
this.$body.append( | this.$body.append( | ||
$('<div id="show-contributor-header" />').append( | $('<div id="show-contributor-header" />').append( | ||
$('<div id="show-contributor-headline">本页贡献统计</div>'), | $('<div id="show-contributor-headline">本页贡献统计</div>'), | ||
new OO.ui.IconWidget({icon:"close",id:"show-contributor-close"}).$element.on("click", | new OO.ui.IconWidget({ | ||
icon: "close", | |||
id: "show-contributor-close" | |||
}).$element.on("click", () => this.close()) | |||
), | ), | ||
this.$table.append( | this.$table.append( | ||
第91行: | 第109行: | ||
this.$tbody | this.$tbody | ||
) | ) | ||
) | ); | ||
this | return this; | ||
} | } | ||
getContributors = async () => { | getContributors = async () => { | ||
const | const api = new mw.Api(); | ||
const users = {}; | |||
let | let rvcontinue = "", lastSize = 0; | ||
const params = { | |||
const | action: "query", | ||
action:"query", | format: "json", | ||
format:"json", | prop: "revisions", | ||
prop:"revisions", | titles: mw.config.get("wgPageName"), | ||
titles:mw.config.get("wgPageName"), | rvprop: "user|size", | ||
rvprop:"user|size", | rvlimit: "max", | ||
rvlimit:"max", | rvdir: "newer" | ||
rvdir:"newer" | |||
}; | }; | ||
do { | do { | ||
if (rvcontinue) params.rvcontinue = rvcontinue; | |||
try { | try { | ||
const | const result = await api.get(params); | ||
rvcontinue = result.continue?.rvcontinue; | |||
for (const {user | for (const { user, size } of Object.values(result.query.pages)[0].revisions) { | ||
users[user] ||= []; | |||
users[user].push(size - lastSize); | |||
lastSize = size; | |||
} catch ( | } | ||
mw.notify(`获取编辑记录失败:${ | } catch (err) { | ||
mw.notify(`获取编辑记录失败:${err}`, { type: "error" }); | |||
break; | |||
} | } | ||
} while ( | } while (rvcontinue); | ||
return | |||
return users; | |||
}; | }; | ||
addRow = ( | |||
addRow = ($target, { user, count, add, remove }) => { | |||
$target.append( | |||
$("<tr />").append( | $("<tr />").append( | ||
$("<td />").append( | $("<td />").append( | ||
$(`<a href="${mw.config.get("wgArticlePath").replace("$1",`User:${ | $(`<a href="${mw.config.get("wgArticlePath").replace("$1", `User:${user}`)}" />`).append( | ||
`<img class="user-avatar" src="https://commons.moegirl.org.cn/extensions/Avatar/avatar.php?user=${ | `<img class="user-avatar" src="https://commons.moegirl.org.cn/extensions/Avatar/avatar.php?user=${user}" />`, | ||
user | |||
) | ) | ||
), | ), | ||
`<td>${ | `<td>${count}</td>`, | ||
`<td>${ | `<td>${add}</td>`, | ||
`<td>${ | `<td>${remove}</td>` | ||
) | ) | ||
) | ); | ||
}; | }; | ||
showContributors = | |||
showContributors = (data) => { | |||
this.$tbody.empty(); | this.$tbody.empty(); | ||
for (const | for (const user in data) { | ||
this.addRow(this.$tbody,{ | const edits = data[user]; | ||
user | this.addRow(this.$tbody, { | ||
count: | user, | ||
add: | count: edits.length, | ||
remove: | add: edits.reduce((sum, n) => n > 0 ? sum + n : sum, 0), | ||
remove: edits.reduce((sum, n) => n < 0 ? sum + n : sum, 0) | |||
}); | }); | ||
this.got = | } | ||
} | this.got = true; | ||
}; | |||
} | } | ||
const windowManager = new OO.ui.WindowManager({ id: "show-contributor" }); | |||
const | $(document.body).append(windowManager.$element); | ||
$(document.body).append( | |||
const | const dialog = new ContributorDialog({ size: "large" }); | ||
windowManager.addWindows([dialog]); | |||
const | const button = new OO.ui.ButtonWidget({ | ||
label:"本页贡献者", | label: "本页贡献者", | ||
icon:"search", | icon: "search", | ||
flags:"progressive", | flags: "progressive", | ||
id:"show-contributor-button" | id: "show-contributor-button" | ||
}); | }); | ||
// 响应式插入逻辑 | // 响应式插入逻辑 | ||
const insertButton = () => { | |||
$("#show-contributor-button").detach(); | |||
if (mw.config.get("skin") === "citizen") { | |||
$(".page-actions").prepend( | const width = window.innerWidth; | ||
if (width >= 1120) { | |||
$(".page-actions").prepend(button.$element); | |||
} else { | } else { | ||
$(". | const $heading = $(".firstHeading-container"); | ||
if ($heading.length) { | |||
$heading.append(button.$element); | |||
} | |||
} | } | ||
}; | } else { | ||
$("#bodyContent").prepend(button.$element); | |||
} | |||
}; | |||
} | insertButton(); | ||
$(window).on("resize", () => { | |||
clearTimeout(window.__showContributorResizeTimer); | |||
window.__showContributorResizeTimer = setTimeout(insertButton, 200); | |||
}); | |||
// | // 点击打开对话框 | ||
button.on("click", async () => { | |||
if (! | if (!dialog.got) { | ||
button.setLabel("正在查询"); | |||
const | const data = await dialog.getContributors(); | ||
dialog.showContributors(data); | |||
dialog.$table.tablesorter(); | |||
button.setLabel("本页贡献者"); | |||
} | } | ||
windowManager.openWindow(dialog); | |||
}); | }); | ||
})())) | })())); | ||
})(); | })(); |
2025年6月11日 (三) 12:09的版本
(() => { "use strict"; $((() => (async () => { 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")) ) 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; z-index: 1; } #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; } /* Citizen 皮肤响应式样式 */ .skin-citizen #show-contributor-button { float: none; margin: 0 0 0 0.5em; 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 .firstHeading-container { display: flex; justify-content: space-between; align-items: center; } .skin-citizen #show-contributor-button { margin: 0; } } `); await mw.loader.using([ "mediawiki.api", "mediawiki.notification", "oojs-ui", "oojs-ui.styles.icons-interactions", "jquery.tablesorter" ]); class ContributorDialog extends OO.ui.Dialog { $table = $('<table id="show-contributor-table" class="wikitable" />'); $tbody = $("<tbody />"); got = false; static static = { ...super.static, name: "ShowContributor", 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 () => { const api = new mw.Api(); const users = {}; let rvcontinue = "", lastSize = 0; const params = { action: "query", format: "json", prop: "revisions", titles: mw.config.get("wgPageName"), rvprop: "user|size", rvlimit: "max", rvdir: "newer" }; do { if (rvcontinue) params.rvcontinue = rvcontinue; try { const result = await api.get(params); rvcontinue = result.continue?.rvcontinue; for (const { user, size } of Object.values(result.query.pages)[0].revisions) { users[user] ||= []; users[user].push(size - lastSize); lastSize = size; } } catch (err) { mw.notify(`获取编辑记录失败:${err}`, { type: "error" }); break; } } while (rvcontinue); return users; }; addRow = ($target, { user, count, add, remove }) => { $target.append( $("<tr />").append( $("<td />").append( $(`<a href="${mw.config.get("wgArticlePath").replace("$1", `User:${user}`)}" />`).append( `<img class="user-avatar" src="https://commons.moegirl.org.cn/extensions/Avatar/avatar.php?user=${user}" />`, user ) ), `<td>${count}</td>`, `<td>${add}</td>`, `<td>${remove}</td>` ) ); }; showContributors = (data) => { this.$tbody.empty(); for (const user in data) { const edits = data[user]; this.addRow(this.$tbody, { user, count: edits.length, add: edits.reduce((sum, n) => n > 0 ? sum + n : sum, 0), remove: edits.reduce((sum, n) => n < 0 ? sum + n : sum, 0) }); } this.got = true; }; } const windowManager = new OO.ui.WindowManager({ id: "show-contributor" }); $(document.body).append(windowManager.$element); const dialog = new ContributorDialog({ size: "large" }); windowManager.addWindows([dialog]); const button = new OO.ui.ButtonWidget({ label: "本页贡献者", icon: "search", flags: "progressive", id: "show-contributor-button" }); // 响应式插入逻辑 const insertButton = () => { $("#show-contributor-button").detach(); if (mw.config.get("skin") === "citizen") { const width = window.innerWidth; if (width >= 1120) { $(".page-actions").prepend(button.$element); } else { const $heading = $(".firstHeading-container"); if ($heading.length) { $heading.append(button.$element); } } } else { $("#bodyContent").prepend(button.$element); } }; insertButton(); $(window).on("resize", () => { clearTimeout(window.__showContributorResizeTimer); window.__showContributorResizeTimer = setTimeout(insertButton, 200); }); // 点击打开对话框 button.on("click", async () => { if (!dialog.got) { button.setLabel("正在查询"); const data = await dialog.getContributors(); dialog.showContributors(data); dialog.$table.tablesorter(); button.setLabel("本页贡献者"); } windowManager.openWindow(dialog); }); })())); })();