/*<nowiki>
COI Request Tool
Created by: Terasail
*/
var nonResponseCOI = [
{label: "Close", title: "Close request", summary: "Closed edit request", parameter: "answered=yes", response: "", icon: "unFlag", flags: "", text: ""},
{label: "Open", title: "Reopen request", summary: "Reopened edit request", parameter: "answered=no", response: "", icon: "flag", flags: "", text: ""},
{label: "Remove", title: "Remove entire section", summary: "Removed COI request", parameter: "", response: "", icon: "trash", flags: ["primary", "destructive"], text: ""}
];
var responseCOI = [
{label: "Done", title: "Mark request as done", summary: "Marked COI request as done", parameter: "answered=yes", response: "d", icon: "checkAll", flags: ["primary", "progressive"], text: "Done"},
{label: "Partly done", title: "Mark request as partly done", summary: "Marked COI request as partly done", parameter: "P", response: "pd", icon: "check", flags: "", text: "Partly done:"},
{label: "Already done", title: "Mark request as already done", summary: "Marked COI request as already done", parameter: "answered=yes", response: "a", icon: "clock", flags: "", text: "Already done:"},
{label: "Note", title: "Add a note", summary: "Added a note", parameter: "", response: "note", icon: "ellipsis", flags: "", text: "Note:"},
{label: "Question", title: "Add a question", summary: "Added a question", parameter: "", response: "q", icon: "helpNotice", flags: "", text: "Question:"},
{label: "Go ahead", title: "Go ahead", summary: "User may go ahead and edit themselves", parameter: "G", response: "g", icon: "edit", flags: "", text: "Go ahead: I have reviewed these proposed changes and suggest that you go ahead and make the proposed changes to the page."},
{label: "Not done", title: "Decline request", summary: "Declined COI request", parameter: "D", response: "n", icon: "notice", flags: "", text: "Not done:"},
{label: "Not done for now", title: "Decline request for now", summary: "Declined request for now", parameter: "D", response: "nfn", icon: "notice", flags: "", text: "Not done for now:"},
{label: "Promotional", title: "Decline promotional request", summary: "Declined promotional request", parameter: "D|ADV", response: "mpro", icon: "signature", flags: "", text: "Not done: A majority of the requested changes are currently written in a promotional tone. Please review WP:Neutral point of view and ensure you follow this before submitting any edit requests."},
{label: "No consensus", title: "No consensus for the change", summary: "Declined request with no consensus for the change", parameter: "D|C", response: "nc", icon: "userGroup", flags: "", text: "Not done: No consensus could be obtained for making the requested change."},
{label: "Needs reliable sources", title: "Close request pending reliable sources", summary: "COI request declined: Change requires reliable sources", parameter: "D|V", response: "rs", icon: "quotes", flags: "", text: "Not done: please provide reliable sources that support the change you want to be made."},
{label: "Removing content", title: "Decline request removing well-cited content", summary: "Declined request removing well-cited content", parameter: "D|R", response: "rm", icon: "restore", flags: "", text: "Not done: The proposed changes are removing content that is well-cited or where sources exist."},
{label: "Partly promotional", title: "Decline partly promotional request for now", summary: "Declined partly promotional request for now", parameter: "D|ADV", response: "pro", icon: "signature", flags: "", text: "Not done for now: Some of the requested changes are currently written in a promotional tone. Please review WP:Neutral point of view and make changes where appropriate to follow this before reopening the request."},
{label: "Needs consensus", title: "Close request pending consensus", summary: "COI request declined: Change requires consensus first", parameter: "D|D", response: "c", icon: "userGroup", flags: "", text: "Please establish a consensus with editors engaged in the subject area before using the {{Edit COI}} template for this proposed change."},
{label: "Unclear request", title: "Decline and mark as unclear", summary: "COI request closed as it is unclear what change is requested", parameter: "D|Unclear request", response: "xy", icon: "helpNotice", flags: "", text: "it's not clear what changes you want to be made. Please mention the specific changes in a \"change X to Y\" format."},
{label: "Unspecific", title: "Decline unspecific request", summary: "Declined unspecific request", parameter: "D|S", response: "s", icon: "speechBubbles", flags: "", text: "Not done for now: The current request is not specific enough to make changes to the page. Consider developing changes in a new talk section or visit the conflict of interest noticeboard for serious issues."},
{label: "Balance issues", title: "Decline request with balance issues", summary: "Declined request with balance issues", parameter: "D|O", response: "b", icon: "notice", flags: "", text: "Not done for now: The proposed changes create some balance issues with the article. These will need to be addressed before any changes can be made."},
{label: "Partly undo", title: "Partly undo request", summary: "COI request has been partly undone", parameter: "P|The requested edit has been partially undone", response: "udp", icon: "undo", flags: "", text: "Undone: This request has been partially undone."},
{label: "Undo", title: "Undo request", summary: "COI request has been undone", parameter: "D|The requested edit has been undone", response: "ud", icon: "undo", flags: "", text: "Undone: This request has been undone."}
];
var editRequests = $('.editrequest');
var COIRequests = [];
for (let i = 0; i < editRequests.length; i ) {
if (typeof(editRequests[i].attributes['data-origlevel']) == 'undefined') {
$(editRequests[i].children[0]).append('<tr><td colspan="2" class="response-cell" style="text-align:center;"></td></tr>');
COIRequests.push(editRequests[i]);
}
}
if (COIRequests.length > 0) {
mw.loader.using(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-windows"]).done(function() {
mw.loader.load(["oojs-ui.styles.icons-alerts", "oojs-ui.styles.icons-interactions", "oojs-ui.styles.icons-moderation", "oojs-ui.styles.icons-editing-core", "oojs-ui.styles.icons-editing-advanced", "oojs-ui.styles.icons-user"]);
loadCOITool();
});
}
async function loadCOITool() {
// Get page watchers, visitors and user watch status.
let watchStatus = [];
let watchQuery = await ApiGetCOI({
action: "query",
prop: "info",
pageids: mw.config.get("wgArticleId"),
inprop: "watchers|visitingwatchers|watched",
format: "json"
});
let watchData = watchQuery.query.pages[mw.config.get("wgArticleId")];
let watched = watchData.watched;
let expiry = watchData.watchlistexpiry;
if (expiry) {
watched = Math.ceil((new Date(expiry).getTime() - Date.now()) / 1000 / 60 / 60 / 24) " days";
}
if (watched == undefined && typeof(autoWatchRequests) != "undefined" && autoWatchRequests == true) {
watched = '';
}
watchStatus.push(watchData.watchers || "less than 30", watchData.visitingwatchers || "<30", watched);
//Increment through all COI requests & add respond button
for (let i = 0; i < COIRequests.length; i ) {
let respondButton = new OO.ui.ButtonWidget({
icon: "edit",
label: "Respond",
flags: "progressive",
title: "Open the response menu for this request"
}).on("click", function() {
loadCOIResponse(COIRequests[i], respondButton, watchStatus);
respondButton.setDisabled(true);
});
respondButton.$element[0].style = "margin:5px";
$($('.response-cell')[i]).append(respondButton.$element);
}
}
function loadCOIResponse(COIRequest, respondButton, watchStatus) {
let responseBoxHTML = '<table class="response-box" style="border:1px solid #A2A9B1; border-radius:2px; padding:10px 16px 0; margin:auto; max-width:55em; width:100%; clear:both;"><tr><td><div style="font-style:italic; margin-left:1em;">There are currently ' watchStatus[0] ' users watching this page (' watchStatus[1] ' have viewed recent edits).</div><div>Quick options:</div></td></tr><tr style="display: flex; justify-content: center;"><td class="response-quick"></td></tr><tr><td>Custom response:</td></tr><tr style="text-align:center;"><td class="response-custom"></td></tr><tr style="background:#F6F6F6;"><td class="response-preview" style="display:none;"><div>Preview:</div><div></div></td></tr><tr style="display: flex; justify-content: right;"><td class="response-controls"></td></tr></table>';
$(responseBoxHTML).insertAfter(COIRequest, respondButton);
let responseBox = COIRequest.nextElementSibling;
let responseQuick = $(responseBox).find('.response-quick')[0];
let responseCustom = $(responseBox).find('.response-custom')[0];
let responsePreview = $(responseBox).find('.response-preview')[0];
let responseControls = $(responseBox).find('.response-controls')[0];
//Quick Responses
//Create a HorizontalLayout & Fieldset for quick responses
let quickLayout = new OO.ui.HorizontalLayout();
let quickFieldset = new OO.ui.FieldsetLayout();
quickFieldset.addItems([new OO.ui.FieldLayout(new OO.ui.Widget({content: [quickLayout]}), {align: 'top'})]);
$(responseQuick).append(quickFieldset.$element);
let quickNonResponses = [2];//Remove button
if ($(COIRequest).find('hr').length > 0) {//If request is closed
quickNonResponses.push(0);//Close button
} else {
quickNonResponses.push(1);//Open button
}
for (let i = 0; i < quickNonResponses.length; i ) {
let tempVal = quickNonResponses[i];
let tempButton = new OO.ui.ButtonWidget({
flags: nonResponseCOI[tempVal].flags,
icon: nonResponseCOI[tempVal].icon,
title: nonResponseCOI[tempVal].title,
invisibleLabel: true
}).on("click", function () {
saveResponseCOI([COIRequest, responseQuick, responsePreview, responseControls], nonResponseCOI[tempVal], "", "nochange", undefined);
});
quickLayout.addItems([tempButton]);
}
let quickResponses = [0, 5, 8, 10];//Done, Go ahead, Consensus, Unclear
for (let i = 0; i < quickResponses.length; i ) {
let tempVal = quickResponses[i];
let tempButton = new OO.ui.ButtonWidget({
flags: responseCOI[tempVal].flags,
label: responseCOI[tempVal].label,
title: responseCOI[tempVal].title
}).on("click", function () {
saveResponseCOI([COIRequest, responseQuick, responsePreview, responseControls], responseCOI[tempVal], "", "nochange", undefined);
});
quickLayout.addItems([tempButton]);
}
//Custom Responses
//Response dropdown
let responseDropdown = new OO.ui.DropdownWidget({
label: "Select reply option - Add additional text below",
menu: {items: []}
}).on("labelChange", function () {
submitButton.setDisabled(false);
previewCOI(responseDropdown.menu.findSelectedItem().getData(), responseText.value, responsePreview);
});
for (let i = 0; i < responseCOI.length; i ) {
let tempWidget = new OO.ui.MenuOptionWidget({
label: responseCOI[i].text,
icon: responseCOI[i].icon,
data: responseCOI[i]
});
responseDropdown.menu.addItems([tempWidget]);
}
responseDropdown.$element[0].style = "margin:auto; text-align:left;";
$(responseCustom).append(responseDropdown.$element);
//Response text
var responseText = new OO.ui.MultilineTextInputWidget({
autosize: true, rows: 4, label: "Additional text"
}).on("change", function () {
if (responseDropdown.menu.findSelectedItem()) {
previewCOI(responseDropdown.menu.findSelectedItem().getData(), responseText.value, responsePreview);
}
});
responseText.$element[0].style = "margin:5px auto;";
$(responseCustom).append(responseText.$element);
//Response Controls
//Create a HorizontalLayout & Fieldset for response controls
let controlsLayout = new OO.ui.HorizontalLayout();
let controlsFieldset = new OO.ui.FieldsetLayout();
controlsFieldset.addItems([new OO.ui.FieldLayout(new OO.ui.Widget({content: [controlsLayout]}), {align: 'top'})]);
$(responseControls).append(controlsFieldset.$element);
//Cancel Button
let cancelButton = new OO.ui.ButtonWidget({
icon: "cancel",
flags: "destructive",
label: "Cancel",
framed: false,
title: "Cancel the response & close this menu"
}).on("click", function () {
respondButton.setDisabled(false);
responseBox.remove();
});
controlsLayout.addItems([cancelButton]);
//Watchlist dropdown
let watchOptions = [{data: "infinite", label: "Permanent"}, {data: "1 day", label: "1 day"}, {data: "3 days", label: "3 days"}, {data: "1 week", label: "1 week"}, {data: "1 month", label: "1 month"}];
let watchValue = "infinite";
if (!!watchStatus[2]) {
watchOptions.unshift({data: "nochange", label: watchStatus[2]});
watchValue = "nochange";
}
let watchlistLayout = new OO.ui.HorizontalLayout();
let watchlistDropdown = new OO.ui.DropdownInputWidget({
value: watchValue,
options: watchOptions,
disabled: (watchStatus[2] == undefined)
});
watchlistLayout.addItems([watchlistDropdown]);
//Watchlist checkbox & label
let watchlistCheckbox = new OO.ui.CheckboxInputWidget({
selected: (watchStatus[2] != undefined)
}).on("change", function (newStatus) {
watchlistDropdown.setDisabled(!newStatus);
});
let watchlistLabel = new OO.ui.LabelWidget({label: "Watch this page"});
//Submit Button
let submitButton = new OO.ui.ButtonWidget({
icon: "checkAll",
flags: ["primary", "progressive"],
label: "Submit",
title: "Submit the response",
disabled: true
}).on("click", function () {
saveResponseCOI([COIRequest, responseQuick, responsePreview, responseControls], responseDropdown.menu.findSelectedItem().getData(), responseText.value, watchlistCheckbox.selected, watchlistDropdown.value);
});
controlsLayout.addItems([cancelButton, watchlistCheckbox, watchlistLabel, watchlistLayout, submitButton]);
}
function previewCOI(responseOption, responseText, tableCell) {
let restTransform = "https://en.wikipedia.org/api/rest_v1/transform/wikitext/to/html/" encodeURI(mw.config.get("wgPageName"));
if (responseOption.response != "") {
responseText = "{{ECOI|" responseOption.response "}} " responseText;
}
if (responseText != "") {
let nickname = " " mw.user.options.values.nickname;
if (nickname == " ") {//Create default signature if no nickname
nickname = mw.user.getName();
nickname = " [[User:" nickname "|" nickname "]] ([[User talk:" nickname "|talk]])";
}
let dateObj = new Date();
let dateNow = dateObj.toLocaleDateString('en-GB', {
timeZone: 'UTC',
year: 'numeric',
month: 'long',
day: 'numeric'
});
let timeNow = dateObj.toLocaleTimeString('en-GB', {timeZone: 'UTC', hour: '2-digit', minute: '2-digit'});
responseText = responseText nickname " " timeNow ", " dateNow " (UTC)";
responseText = responseText.replaceAll(/{{subst:/gi, "{{");
responseText = responseText.replaceAll(/\s*~~~~\s*/g, "");
$.post(restTransform, 'wikitext=' encodeURIComponent(responseText) '&body_only=true',
function (html) {
tableCell.style = "padding:8px 1em 2px;";
tableCell.children[1].innerHTML = html;
}
);
} else {
tableCell.style = "display:none;";
}
}
async function saveResponseCOI(requestBox, responseOption, responseText, watchPage, watchValue) {
await new Promise(function(resolve) {
OO.ui.confirm("Confirm in order to reply to this edit request.").done(function(confirmed) { if (confirmed) {
resolve();
} else {
return;
}});
});
//Create label box & remove quick actions
requestBox[1].innerHTML = "";
requestBox[3].remove();
let statusMessage = new OO.ui.MessageWidget({
icon: 'pageSettings',
type: 'notice',
label: 'Processing request — Edit request starting, getting section data to edit.'
});
statusMessage.$element[0].style = "margin:5px 0; max-width:50em";
$(requestBox[1]).append(statusMessage.$element);
//Create progress bar
let progressBar = new OO.ui.ProgressBarWidget({
progress: false
});
$(requestBox[1]).append(progressBar.$element);
//Set preview for output
previewCOI(responseOption, responseText, requestBox[2]);
// Find header
let header = "";
let sectionIndex = 0;
let tempElement = requestBox[0];
let sectionQuery = await ApiGetCOI({
action: "parse",
page: mw.config.get("wgPageName"),
prop: "sections"
});
let sections = sectionQuery.parse.sections;
do {
tempElement = tempElement.previousElementSibling;
if (tempElement.classList.contains("mw-heading")) {
if (tempElement.parentElement.tagName == "SECTION") { //Need to support both while new parser is being implemented
header = $(tempElement).find("h1,h2,h3,h4,h5,h6")[0].id;
sectionIndex = parseInt(tempElement.parentElement.dataset.mwSectionId);
} else {
if (tempElement.getElementsByClassName("mw-headline").length > 0) { //Vector 2022
header = tempElement.getElementsByClassName("mw-headline")[0].id;
} else { //Vector Legacy
header = $(tempElement).find("h1,h2,h3,h4,h5,h6")[0].id;
}
for (let i = 0; i < sections.length; i ) {
if (sections[i].anchor == header) {
sectionIndex = parseInt(sections[i].index);
}
}
}
}
}
while (header == "");
statusMessage.setLabel("Processing request — Making changes to the edit request");
let editSummary = "/* " header.replaceAll("_", " ") " */ " responseOption.summary " ([[User:Terasail/COI_Request_Tool|COI Request Tool]])";
let wikitextQuery = await ApiGetCOI({
action: "parse",
page: mw.config.get("wgPageName"),
section: sectionIndex,
prop: "wikitext|revid"
});
let wikitext = wikitextQuery.parse.wikitext["*"];
let latestRevision = wikitextQuery.parse.revid;
if (responseOption.parameter != "") {
let template = "{{Edit COI|" responseOption.parameter "}}";
wikitext = wikitext.replace(/{{ *(Edit[ _])?COI(-protected|([ _](edit|request)){2})?( *\| *([=A-Z])*)* *}}/i, template);
}
if (responseOption.response != "") {
wikitext = "\n:{{subst:ECOI|" responseOption.response "}}";
wikitext = responseText.replaceAll(/\s*~~~~\s*/g, "") " ~~~~";
}
if (responseOption.label == "Remove") {
wikitext = "";
editSummary = editSummary.replace(/[^] \*\/ /, "");
}
statusMessage.setType("success");
statusMessage.setLabel("Processing request — Saving changes to the talk page.");
if (latestRevision != mw.config.values.wgRevisionId) {
await new Promise(function(resolve) {
OO.ui.confirm("There has been a new revision to the page, do you wish to continue?").done(function(confirmed) { if (confirmed) {
resolve();
} else {
return;
}});
});
}
if (watchPage) {
if (watchPage != "nochange") {
watchPage = "watch";
}
} else {
watchPage = "unwatch";
}
let apiParams = {
action: 'edit',
title: mw.config.get("wgPageName"),
text: wikitext,
section: sectionIndex,
summary: editSummary,
watchlist: watchPage
};
if (watchPage == "watch") {
apiParams.watchlistexpiry = watchValue;
}
let reloadURL = "/w/index.php?title=" encodeURI(mw.config.get("wgPageName")) "&type=revision&diff=cur&oldid=prev";
new mw.Api().postWithEditToken(apiParams).done(function () {
window.location = reloadURL;
});
}
function ApiGetCOI(params) {
return new Promise(function(resolve) {
new mw.Api().get(params)
.done(function (data) {resolve(data);})
.fail(function (data) {console.error(data);});
});
}
//</nowiki>[[Category:Wikipedia scripts]]