MediaWiki:Gadget-OneClickPatrol.js
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Internet Explorer或Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
- Opera:按 Ctrl-F5。
/* OneClickPatrol — 最近更改 / 监视列表一键巡查 (MediaWiki 1.39)
* 仅对拥有 patrol 权限的用户(sysop / patroller)生效。
* 作用:在每条「未巡查」变更右侧加一个「✓ 巡查」按钮,
* 覆盖核心本不显示按钮的日志/上传类条目;
* 页面顶部另提供「✓ 巡查本页全部未巡查」一键处理整页。
*/
(function () {
'use strict';
var page = mw.config.get('wgCanonicalSpecialPageName');
if (page !== 'Recentchanges' && page !== 'Watchlist') {
return;
}
mw.loader.using(['mediawiki.api', 'mediawiki.util']).done(function () {
var api = new mw.Api();
mw.util.addCSS(
'.mw-ocp-btn{margin-left:6px;padding:0 6px;border:1px solid #a2a9b1;' +
'background:#f8f9fa;color:#202122;border-radius:2px;cursor:pointer;font-size:11px;}' +
'.mw-ocp-btn:hover{background:#eaecf0;}' +
'.mw-ocp-btn:disabled{opacity:.6;cursor:default;}' +
'.mw-ocp-all{margin:6px 0;padding:3px 10px;border:1px solid #14866d;' +
'background:#eaf3ff;color:#14866d;border-radius:2px;cursor:pointer;}'
);
// 从一行的标题链接 + 用户链接构造与 API 一致的 key
function rowKey($li) {
var $title = $li.find('.mw-changeslist-title').first();
var title = '';
if ($title.length) {
var href = $title.attr('href') || '';
var m = href.match(/[?&]title=([^&]+)/) || href.match(/\/([^?]+)$/);
if (m) { title = decodeURIComponent(m[1].replace(/\+/g, ' ')); }
}
var $user = $li.find('.mw-userlink').first();
var user = '';
if ($user.length) {
var uh = $user.attr('href') || '';
var um = uh.match(/User:([^?&]+)/);
if (um) { user = decodeURIComponent(um[1].replace(/_/g, ' ')); }
}
return title + '|' + user;
}
function patrol(rcid, $btn, $li) {
$btn.prop('disabled', true).text('巡查中…');
api.postWithToken('patrol', {
action: 'patrol',
rcid: String(rcid),
formatversion: 2
}).done(function () {
$li.removeClass('unpatrolled').addClass('mw-patrolled-ok');
$btn.text('✓ 已巡查').css({ color: '#14866d', borderColor: '#14866d' });
}).fail(function (code, data) {
var msg = (data && data.error && data.error.info) ? data.error.info : (code || '失败');
$btn.prop('disabled', false).text('✗ 失败').attr('title', msg);
});
}
function addButtons(map) {
$('#mw-content-text .mw-changeslist').find('li').each(function () {
var $li = $(this);
if ($li.data('ocp-done')) { return; }
var key = rowKey($li);
var rcid = null;
// 1) 核心已渲染的巡逻链接(他人普通编辑/新建)
var $patrol = $li.find('a[href*="action=patrol"]').first();
if ($patrol.length) {
var pm = $patrol.attr('href').match(/rcid=(\d+)/);
if (pm) { rcid = pm[1]; }
}
// 2) 通过 API 未巡查列表匹配(覆盖日志/上传等核心不给按钮的条目)
if (!rcid && map[key]) { rcid = map[key]; }
if (!rcid) { return; }
$li.data('ocp-done', true);
var $btn = $('<button>')
.addClass('mw-ocp-btn')
.attr('type', 'button')
.text('✓ 巡查')
.on('click', function (e) {
e.preventDefault();
patrol(rcid, $btn, $li);
return false;
});
var $box = $li.find('.mw-changeslist-buttons, .mw-changeslist-links').first();
if ($box.length) {
$box.append($('<span> </span>').append($btn));
} else {
$li.append($('<span> </span>').append($btn));
}
});
}
function buildMap() {
return api.get({
action: 'query',
list: 'recentchanges',
rcprop: 'ids|title|user',
rcshow: '!patrolled',
rclimit: 100,
formatversion: 2
}).then(function (data) {
var map = {};
var list = (data && data.query && data.query.recentchanges) || [];
list.forEach(function (rc) {
map[rc.title + '|' + rc.user] = rc.rcid;
});
return map;
}, function () { return {}; });
}
$(function () {
buildMap().then(function (map) {
addButtons(map);
mw.hook('wikipage.content').add(function () { addButtons(map); });
var $all = $('<button>')
.addClass('mw-ocp-all')
.attr('type', 'button')
.text('✓ 巡查本页全部未巡查')
.on('click', function () {
$('#mw-content-text .mw-changeslist').find('button.mw-ocp-btn').each(function () {
var $b = $(this);
if ($b.text() === '✓ 巡查') { $b.click(); }
});
});
$('#firstHeading').after($all);
});
});
});
})();