User:Former User aDB0haVymg/gadgets/close-anx.js
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/**
* <nowiki>
*
* Close-ANX.js
* A simple gadget for Chinese Wikipedia
*
* ----
*
* Based on close-vip.js by User:Xiplus
*
* ----
*
* @author User:Classy_Melissa @ zh.wikipedia.org
* @license CC BY-SA (under protest)
* @version 3
* @since 2020-07-17
*
*/
"use strict";
(function () {
let ScriptConfig;
if (typeof ScriptConfig == 'undefined')
ScriptConfig = {};
if (typeof ScriptConfig.summary == 'undefined') {
ScriptConfig.summary = '關閉報告 via [[User:Classy_Melissa/gadgets/close-anx.js|close-anx]]';
}
// Melissa's Very Own Tunable Constants
const POSSIBLE_PAGES = ["Wikipedia:管理员布告板/其他", "Wikipedia:管理员布告板/3RR"];
// figure out targetPageTitle
let targetPageTitle = "none";
const currentPageTitle = mw.config.get("wgPageName");
for (const thisPossiblePage of POSSIBLE_PAGES) {
if (thisPossiblePage === currentPageTitle) {
targetPageTitle = thisPossiblePage;
break;
}
}
// sanity check
if (targetPageTitle === "none"
|| mw.config.get('wgAction') !== 'view'
|| mw.config.get('wgRevisionId') !== mw.config.get('wgCurRevisionId')) {
return;
}
const fetchPageContentPromise = new Promise(function (resolve, reject) {
new mw.Api().get({
action: 'query',
prop: 'revisions',
rvprop: ['content', 'timestamp'],
titles: targetPageTitle,
formatversion: '2',
curtimestamp: true
}).then(function (data) {
var page, revision;
if (!data.query || !data.query.pages) {
mw.notify('未能抓取頁面內容(unknown)');
reject('unknown');
}
page = data.query.pages[0];
if (!page || page.invalid) {
mw.notify('未能抓取頁面內容(invalidtitle)');
reject('invalidtitle');
}
if (page.missing) {
mw.notify('未能抓取頁面內容(nocreate-missing)');
reject('nocreate-missing');
}
revision = page.revisions[0];
var content = revision.content;
var basetimestamp = revision.timestamp;
var curtimestamp = data.curtimestamp;
resolve({
content: content,
basetimestamp: basetimestamp,
curtimestamp: curtimestamp
});
})
}
);
/**
* Shows the [close] buttons on each header
*/
function showHeaderButtons() {
const allContentH3s = document.querySelectorAll("#bodyContent h3");
const getColouredSpan = function (color, content) {
var span = document.createElement('span');
span.style.color = color;
span.appendChild(document.createTextNode(content));
return span;
};
const buttonNodePrototype = document.createElement('strong');
const closeLinkPrototype = document.createElement('a');
closeLinkPrototype.appendChild(getColouredSpan('Black', '['));
closeLinkPrototype.appendChild(getColouredSpan('Red', wgULS('关闭', '關閉')));
closeLinkPrototype.appendChild(getColouredSpan('Black', ']'));
buttonNodePrototype.setAttribute('class', 'CloseVipBtn');
buttonNodePrototype.appendChild(closeLinkPrototype);
allContentH3s.forEach(function (thisH3, thisKey) {
const node = thisH3.getElementsByClassName('mw-headline')[0];
const headlineChildren = $(thisH3).find('.mw-headline').children();
if (headlineChildren.length === 0) {
return;
}
let title = headlineChildren[0].id;
title = title.replace(/{{vandal\|(.*?)}}/, '$1');
const tmpNode = buttonNodePrototype.cloneNode(true);
$(tmpNode.firstChild).click(function () {
showCloseDialog(thisKey, title);
return false;
});
node.appendChild(tmpNode);
});
}
// ⚠ XSS Hot Spot
function getHTMLTemplateCode() {
let html = '<div>';
// shorthand to append HTML
const $ac = (str) => {
html += str;
html += "\n";
};
// shorthand to append warning option
const $aw = (word) => {
$ac(`<option value="{{警告}}: ${word}">警告: ${word}</option>"`);
}
// shorthand to append refuse option
const $ar = (word) => {
$ac(`<option value="{{VIP|dc}}: ${word}">拒絕: ${word}</option>`);
}
$ac('以{{VIP}}通告<br />');
$ac('<select id="vip" onchange="$(this.parentElement).find(\'#comment\')[0].value += this.value; this.value = \'\';">');
$ac('<option value="">選擇</option>');
$ac('<option value="{{VIP|chk}}">檢查中</option>');
$ac('<option value="{{VIP|m}}">將關注此用戶</option>');
$ac('<option value="{{VIP|w}}">用戶已獲警告</option>');
$ac('<option value="{{VIP|dc}}">拒絕</option>');
$ac('<option value="{{VIP|n}}">注意</option>');
$ac('<option value="{{VIP|e|X}}">陳舊報告,用戶已停止編輯/用戶近期已沒有編輯X</option>');
$ac('<option value="{{VIP|q}}">問題</option>');
$ar("請通過溝通解決爭議");
$ar("未發出足夠警告");
$ar("未違反任何方針");
$aw("請勿再人身攻擊");
$aw("請勿再發表不文明的言論");
$aw("請勿再刪改他人留言");
$aw("請勿再假定惡意");
$aw("請勿再發表不實言論");
$ac('</select><br />');
$ac('{{Block}}<br />');
$ac('<select id="block" onchange="$(this.parentElement).find(\'#comment\')[0].value += this.value; this.value = \'\';">');
$ac('<option value="">選擇</option>');
$ac('<option value="{{Blocked|1天}}">1天</option>');
$ac('<option value="{{Blocked|1週}}">1週</option>');
$ac('<option value="{{Blocked|1個月}}">1個月</option>');
$ac('<option value="{{Blocked|1年}}">1年</option>');
$ac('<option value="{{Blocked|indef}}">不限期封禁</option>');
$ac('<option value="{{Blocked|ad=Example|1年}}">已由管理員Example執行封禁1年</option>');
$ac('</select><br />');
$ac('留言<br />');
$ac('<input type="text" id="comment" size="40">');
$ac('</div>');
return html;
}
/**
* Show a jQuery dialog to close a section.
* @param key {number} the index of the section to close
* @param title {string} the section's title. Supposed to be the username.
*/
function showCloseDialog(key, title) {
mw.loader.using(['jquery.ui'], function () {
const dialogUIHTML = getHTMLTemplateCode();
$(dialogUIHTML).dialog({
title: '關閉報告 - ' + title,
minWidth: 515,
minHeight: 150,
buttons: [
{
text: '確定',
click: function () {
if ($(this).find('#comment').val().trim() !== '') {
doCloseSection(key, title, $(this).find('#comment').val());
} else {
mw.notify('動作已取消');
}
$(this).dialog('close');
}
}, {
text: '取消',
click: function () {
$(this).dialog('close');
}
}
]
});
});
}
/**
* Do close one section
* @param key {number} the index of the section to close
* @param title {string} the section's title
* @param comment {string} comment to insert
*/
function doCloseSection(key, title, comment) {
new mw.Api().edit(targetPageTitle, function (revision) {
const oldContent = revision.content;
let contentSections = oldContent.split(/^===/gm);
// remove the first section for now
const firstSection = contentSections.shift();
// add the ===s back to the strings
contentSections = contentSections.map((section) => "===" + section);
// do mutate contentSections as needed
contentSections[key] = contentSections[key].trim();
comment = comment.trim();
if (comment !== '') {
if (comment.search(/[.?!;。?!;]$/) === -1) {
comment += '。';
}
if (contentSections[key].match(/^\*\s*处理:[ \t]*(<!-- 非管理員僅可標記已執行的封禁,針對提報的意見請放在下一行 -->)?[ \t]*$/m)) {
contentSections[key] = contentSections[key].replace(/^(\*\s*处理:)[ \t]*(<!-- 非管理員僅可標記已執行的封禁,針對提報的意見請放在下一行 -->)?[ \t]*$/m, '$1' + comment + '--~~~~');
} else {
contentSections[key] += '\n* 处理:' + comment + '--~~~~';
}
}
contentSections[key] += '\n\n';
let newContent = contentSections.join("");
// re-insert the content of first section into newContent
newContent = firstSection + newContent;
// grey out the corresponding close button
$($('#bodyContent').find('h3')[key - 1]).find('.CloseVipBtn span').css('color', 'grey');
// done
return {
text: newContent,
basetimestamp: revision.timestamp,
summary: ScriptConfig.summary,
minor: true
};
}).then(function () {
mw.notify('已關閉 ' + title);
}, function (e) {
// handle errors from the API
if (e === 'editconflict') {
mw.notify('關閉 ' + title + ' 時發生編輯衝突');
} else {
mw.notify('關閉 ' + title + ' 時發生未知錯誤:' + e);
}
});
}
fetchPageContentPromise.then(function (result) {
window.content = result.content;
const lenintext = result.content.split(/^===/gm).length - 1;
const leninhtml = $('#bodyContent').find('h3').length;
if (leninhtml !== lenintext) {
mw.notify('抓取章節錯誤,在HTML找到 ' + leninhtml + ' 個章節,在原始碼找到 ' + lenintext + ' 個章節');
} else {
showHeaderButtons();
}
});
})();
// </nowiki>