User:Terasail/Edit Request Test.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Terasail/Edit Request Test. |
//<nowiki>
/*jshint esversion: 6*/
var editRequestBoxes = document.getElementsByClassName("plainlinks tmbox tmbox-notice editrequest");
var pageWatchers = "There are currently ";
var watchStatus;
var dataERT;
var commentERT;
var api = new mw.Api();
var pageNameERT = mw.config.values.wgPageName;
var encodePageName = encodeURIComponent(pageNameERT);
function postEdit(wikitext, editSummary, secIndx, changeWatch, watchlist) {
let apiParams = {
action: 'edit',
title: pageNameERT,
text: wikitext,
section: secIndx,
summary: editSummary,
watchlist: changeWatch
};
let reloadURL = "/w/index.php?title=" + encodePageName + "&type=revision&diff=cur&oldid=prev";
if (changeWatch == "watch") {
apiParams.watchlistexpiry = watchlist;
}
if (wikitext == "") {
if (typeof(commentERT) != 'undefined' && commentERT.search(/-(?=[0-9]{14}","type)/) != -1) {
OO.ui.confirm("Do you want to add an empty edit request notice to the users talk page?").done(function(confirmed) {
if (confirmed) {
let commenter = commentERT.slice(commentERT.indexOf('"name"') + 10, commentERT.search(/-(?=[0-9]{14}","type)/));
let talkParams = dataERT.emptyNotice;
talkParams.title = "User talk:" + commenter;
talkParams.sectiontitle += pageNameERT;
talkParams.text = talkParams.text.replace("```", pageNameERT);
talkParams.summary = talkParams.summary.replace("```", pageNameERT);
api.postWithEditToken(talkParams).done(function(result) {
//Do something here?
});
}
api.postWithEditToken(apiParams).done(function(result) { window.location = reloadURL; });
});
}
} else {
api.postWithEditToken(apiParams).done(function(result) { window.location = reloadURL; });
}
}
function execute(responseTable, dataERT, replyOption, inputText, answered, boxType, targets, changeWatch, watchlist) {
OO.ui.confirm("Confirm in order to reply to this edit request.").done(function(confirmed) {
if (confirmed) {
//Create label box & remove action buttons
let firstRow = responseTable.children[1].children[0];
firstRow.innerHTML = "";
responseTable.children[5].children[0].remove();
let infoBox = new OO.ui.MessageWidget( {
icon: 'pageSettings',
type: 'notice',
label: 'Processing request — Edit request starting, getting section data to edit.'
});
infoBox.$element[0].style = "margin:5px 0; max-width:50em";
$(firstRow).append(infoBox.$element);
//Create loading bar
let progressBar = new OO.ui.ProgressBarWidget( {
progress: false
});
$(firstRow).append(progressBar.$element);
//Set preview for output
if (replyOption[0] != "") {//Don't preview a non-response
showOutput(inputText, replyOption, responseTable.children[4].children[0], dataERT, boxType);
}
//Find header
let header = "";
let curElement = responseTable.parentNode;
do {
curElement = curElement.previousElementSibling;
if (curElement.getElementsByClassName("mw-headline").length == 1) {
header = curElement.getElementsByClassName("mw-headline")[0].id;
}
}
while (header == "");
api.get( {
action: "parse",
page: pageNameERT,
prop: "sections"
}).done(function(data) {
infoBox.setLabel("Processing request — Making changes to the edit request");
let editTemplate = "{{Edit " + boxType + "-protected";
if (answered) { answered = "yes"; } else { answered = "no"; }
for (let c3 = 0; c3 < targets.length; c3++) {
editTemplate += "|" + targets[c3];
}
editTemplate += "|answered=" + answered;
let sections = data.parse.sections;
let secIndx = sections[0];
for (let j = 0; j < sections.length; j++) {
if (sections[j].anchor == header) {
secIndx = parseInt(sections[j].index);
}
}
api.get( {
action: "parse",
page: pageNameERT,
section: secIndx,
prop: "wikitext|revid"
}).done(function(data) {
let wikitext = data.parse.wikitext["*"];
let newRev = data.parse.revid;
wikitext = wikitext.replace(/{{ *([SETFI]PER|Edit([ -]?[A-Z]+[ -]?|[- ])Protected)\s*[^}}]*/i, editTemplate);
let editSummary = "/* " + header.replaceAll("_", " ") + " */ " + replyOption[2] + " ([[User:Terasail/Edit_Request_Tool|Edit Request Tool]])";
if (replyOption[1] != "Close") {
wikitext = wikitext.trim() + "\n:";
if (replyOption[0] != "") { wikitext += "{{subst:" + dataERT.protections[boxType][1] + replyOption[0] + "}} "; }
if (inputText != "") { wikitext += inputText.replaceAll(/\s*~~~~\s*/g, "") + " "; }
wikitext += "~~~~";
if (replyOption[1] == "Remove") {
commentERT = document.getElementById(header).dataset.mwComment;
wikitext = "";
editSummary = editSummary.replace(/[^]+\*\/ /, "");
}
}
infoBox.setType("success");
infoBox.setLabel("Processing request — Saving changes to the talk page.");
if (newRev == mw.config.values.wgRevisionId) {
postEdit(wikitext, editSummary, secIndx, changeWatch, watchlist);
} else {
OO.ui.confirm("There has been a new revision to the page, do you wish to continue?").done(function(revCon) {
if (revCon) { postEdit(wikitext, editSummary, secIndx, changeWatch, watchlist); }
});
}
});
});
}
});
}
function addButtons(currentBox, replyButton) {
let boxType = currentBox.parentElement.dataset.origlevel;
boxType = boxType.replace("full", "fully");
let tableElem = currentBox.parentElement;
$('<table style="border:1px solid #A2A9B1; border-radius:2px; padding:10px 16px 0; margin:auto; max-width:55em; clear:both;"><tr><td style="color:#808080"><div style="font-style:italic; margin-left:1em;">' + pageWatchers + '</div><div>Quick options:</div></td></tr><tr style="display: flex; justify-content: center;"><td></td></tr><tr><td style="color:#808080">Custom response:</td></tr><tr style="text-align:center;"><td></td></tr><tr style="background:#F6F6F6;"><td style="display:none;"><div style="color:#808080">Preview:</div><div></div></td></tr><tr style="display: flex; justify-content: right;"><td></td></tr></table>').insertAfter(tableElem);
let responseTable = tableElem.nextElementSibling.children[0];
let firstRow = responseTable.children[1].children[0];
let secondRow = responseTable.children[3].children[0];
let thirdRow = responseTable.children[4].children[0];
let fourthRow = responseTable.children[5].children[0];
let protections = Object.entries(dataERT.protections);
let responses = Object.entries(dataERT.response);
let quickResponses = Object.entries(dataERT.quickResponse);
let nonResponses = dataERT.nonResponse;
//Create type change dropdown
let tcOptions = [];
for (let i = 0; i < protections.length; i++) {
tcOptions.push({data: protections[i][0], label: protections[i][1][0]});
}
let typeChange = new OO.ui.DropdownInputWidget( {
value: boxType,
options: tcOptions
});
typeChange.on("change", function() {
submitB.setDisabled(false);
});
typeChange.$element[0].style = "text-align:left; margin:auto";
$(secondRow).append(typeChange.$element);
//Create target page list
let boxLinks = currentBox.getElementsByClassName("mbox-text")[0].getElementsByClassName("external text");
let pageLinks = [];
if (boxLinks.length > 0) {//Open request
for(let c1 = 0; c1 < boxLinks.length; c1++) {
if (boxLinks[c1].parentElement.tagName == "LI" || boxLinks[c1].parentElement.tagName == "B") {
pageLinks[pageLinks.length] = boxLinks[c1].innerHTML;
}
}
} else {//Closed request
boxLinks = currentBox.getElementsByClassName("mbox-text")[0].getElementsByTagName("A");
for(let c2 = 1; c2 < boxLinks.length; c2++) {
pageLinks[pageLinks.length] = boxLinks[c2].title;
}
if (pageLinks.length == 0) {
pageLinks = pageNameERT.replace(/(_talk|Talk:)/, "").replaceAll("_", " ");
}
}
let targetPages = new OO.ui.TagMultiselectWidget( {
placeholder: 'Target Pages',
allowArbitrary: true,
selected: pageLinks
});
targetPages.on("change", function() {
submitB.setDisabled(false);
});
targetPages.$element[0].style = "text-align:left; margin:5px auto";
$(secondRow).append(targetPages.$element);
//Create dropdown menu
let dropMenu = new OO.ui.DropdownWidget( {
label: "Select reply option - Add additional text below",
menu: {items: []}
});
for (let count = 0; count < responses.length; count++) {
let newOption = new OO.ui.MenuOptionWidget({
label: responses[count][0],
icon: responses[count][1][1]
});
dropMenu.menu.addItems([newOption]);
}
responses = dataERT.response;
dropMenu.$element[0].style = "text-align:left; margin:0px";
$(secondRow).append(dropMenu.$element);
dropMenu.on("labelChange", function() {
submitB.setDisabled(false);
showOutput(inputText, responses[dropMenu.getLabel()], thirdRow, dataERT, typeChange.value);
});
//Create input box
let inputText = new OO.ui.MultilineTextInputWidget({autosize: true, rows:4, label: "Additional text"});
inputText.$element[0].style = "margin:5px auto";
$(secondRow).append(inputText.$element);
inputText.on("change", function(newText) {
showOutput(inputText, responses[dropMenu.getLabel()], thirdRow, dataERT, typeChange.value);
});
//Create top horizontal layout
let hzLayoutT = new OO.ui.HorizontalLayout();
//Create firstrow fieldset
let fieldsetT = new OO.ui.FieldsetLayout();
fieldsetT.addItems([new OO.ui.FieldLayout(new OO.ui.Widget({content:[hzLayoutT]}), {align: 'top' })]);
$(firstRow).append(fieldsetT.$element);
//Remove button
let remove = new OO.ui.ButtonWidget( {
icon: "trash",
flags: ["primary", "destructive"],
invisibleLabel: true,
title: "Delete entire section!"
});
remove.on("click", function() {
execute(responseTable, dataERT, nonResponses.Remove, "", null, typeChange.defaultValue, targetPages.getValue(), "nochange", "");
});
hzLayoutT.addItems([remove]);
//Open & Close button
if (currentBox.parentElement.attributes[2].localName != "data-origlevel") {
let closeB = new OO.ui.ButtonWidget( {
icon: "unFlag",
invisibleLabel: true,
title: "Mark as answered"
});
closeB.on("click", function() {
execute(responseTable, dataERT, nonResponses.Close, "", true, typeChange.defaultValue, targetPages.getValue(), "nochange", "");
});
hzLayoutT.addItems([closeB]);
} else {
let openB = new OO.ui.ButtonWidget( {
icon: "flag",
invisibleLabel: true,
title: "Mark as unanswered"
});
openB.on("click", function() {
execute(responseTable, dataERT, nonResponses.Open, "", false, typeChange.defaultValue, targetPages.getValue(), "nochange", "");
});
hzLayoutT.addItems([openB]);
}
//Create quick response buttons
for (let i = 0; i < quickResponses.length; i++) {
let newButton = new OO.ui.ButtonWidget({
label: quickResponses[i][1][0],
flags: quickResponses[i][1][1],
title: quickResponses[i][1][2]
});
newButton.on("click", function() {
execute(responseTable, dataERT, responses[quickResponses[i][0]], "", toggleAns.selected, typeChange.defaultValue, targetPages.getValue(), "nochange", "");
});
hzLayoutT.addItems([newButton]);
}
//Toggle answer button
let toggleAns = new OO.ui.CheckboxInputWidget({selected: true});
hzLayoutT.addItems([toggleAns, new OO.ui.LabelWidget({label: "Answered"})]);
//Create lastrow horizontal layout
let hzLayoutB = new OO.ui.HorizontalLayout();
//hzLayoutB.$element[0].style = "display: flex;";
//Create lastrow fieldset
let fieldsetB = new OO.ui.FieldsetLayout();
fieldsetB.addItems([new OO.ui.FieldLayout(new OO.ui.Widget({content:[hzLayoutB]}), {align: 'top' })]);
$(fourthRow).append(fieldsetB.$element);
//Cancel response button
let cancelB = new OO.ui.ButtonWidget( {
icon: "cancel",
flags: ["destructive"],
label: "Cancel",
framed: false,
title: "Cancel the response & close menu"
});
cancelB.on("click", function() {
replyButton.setDisabled(false);
responseTable.parentElement.remove();
});
hzLayoutB.addItems([cancelB]);
let isWatched = (typeof(watchStatus[0]) != "undefined");
//Watch list//Toggle answer button
let toggleWL = new OO.ui.CheckboxInputWidget({selected: isWatched});
let toggleWLLable = new OO.ui.LabelWidget({label: "Watch this page"});
toggleWL.on("change", function(newStatus) {
watchDropdown.setDisabled(!newStatus);
});
toggleWLLable.$element[0].style = "white-space: nowrap;";
hzLayoutB.addItems([toggleWL, toggleWLLable]);
let watchValue = "never";
let watchOptions = [{data: "never", 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 wlExpiry = watchStatus[1];
if (typeof(wlExpiry) != "undefined") {
let daysDif = Math.ceil((new Date(wlExpiry).getTime() - Date.now())/1000/60/60/24);
watchOptions.unshift({data: "nochange", label: daysDif + " days"});
watchValue = wlExpiry;
}
//Create WLDropdown horizontal layout
let hzLayoutWLD = new OO.ui.HorizontalLayout();
hzLayoutB.addItems([hzLayoutWLD]);
//Watchlist dropdown
let watchDropdown = new OO.ui.DropdownInputWidget( {
value: watchValue,
options: watchOptions,
disabled: !isWatched
});
hzLayoutWLD.addItems([watchDropdown]);
//Submit response button
let submitB = new OO.ui.ButtonWidget( {
icon: "checkAll",
flags: ["primary", "progressive"],
label: "Submit",
title: "Submit the response",
disabled: true
});
submitB.on("click", function() {
let newResponse = responses[dropMenu.getLabel()];
let newText = inputText.value;
let isAns = toggleAns.selected;
let newType = typeChange.value;
let newTargets = targetPages.getValue();
let targets = targetPages.items;
let targetChange = false;
let wlChange = toggleWL.selected;
let wlVals = watchDropdown.value;
if (wlChange) {
wlChange = "watch";
if (wlVals == "nochange") {
wlChange = "nochange";
}
} else {
wlChange = "unwatch";
}
if (typeof(newResponse) != "undefined") {
execute(responseTable, dataERT, newResponse, newText, isAns, newType, newTargets, wlChange, wlVals);
} else if (typeChange.value != typeChange.defaultValue) {
execute(responseTable, dataERT, nonResponses.ChangeLevel, "", isAns, newType, newTargets, wlChange, wlVals);
}
if (targets.length == pageLinks.length) {
for(let item = 0; item < targets.length; item++) {
if (targets[item].data != pageLinks[item]) { targetChange = true; }
}
} else {
targetChange = true;
}
if (targetChange) {
execute(responseTable, dataERT, nonResponses.ChangeTarget, "", isAns, newType, newTargets, wlChange, wlVals);
}
});
hzLayoutB.addItems([submitB]);
}
function showOutput(inputText, replyOption, tableRow, dataERT, template) {
var restTransform = "http://en.wiki.x.io/api/rest_v1/transform/wikitext/to/html/" + encodePageName;
let preview = "";
let newText = inputText.value;
if (typeof(inputText) == 'string') {
newText = inputText;
}
template = dataERT.protections[template][1];
if (typeof(replyOption) != "undefined") {
preview += "{{" + template + replyOption[0] + "}} ";
}
if (newText != "" && typeof(newText) != "undefined") { preview += newText + " "; }
if (preview != "") {
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' });
preview += nickname + " " + timeNow + ", " + dateNow + " (UTC)";
preview = preview.replaceAll(/{{subst:/gi, "{{");
$.post(restTransform, 'wikitext=' + encodeURIComponent(preview) + '&body_only=true',
function(html) {
if (inputText.value != "" || typeof(replyOption) != "undefined") {//Stops preview appearing with empty input box
tableRow.style = "padding:8px 1em 2px;";
tableRow.children[1].innerHTML = html;
}
}
);
} else {
tableRow.style = "display:none;";
}
}
if (editRequestBoxes.length != 0) {
let pageID = mw.config.values.wgArticleId;
api.get({
action: "query",
prop: "info",
pageids: pageID,
inprop: "watchers|visitingwatchers|watched",
format: "json"
}).done(function(data) {
data = data.query.pages[pageID];
let watchers = data.watchers;
let visiting = data.visitingwatchers;
watchStatus = [data.watched, data.watchlistexpiry];
if (typeof(watchers) == "undefined") {
pageWatchers += "less than 30";
} else {
pageWatchers += watchers;
}
pageWatchers += " users watching this page (";
if (typeof(visiting) == "undefined") {
pageWatchers += "0";
} else {
pageWatchers += visiting;
}
pageWatchers += " have viewed recent edits).";
});
var jsonERTURL = "http://en.wiki.x.io/w/index.php?title=User:Terasail/Edit_Request_Test.json&action=raw&ctype=text/json";
$.getJSON(jsonERTURL, function(newData) {
dataERT = newData;
mw.loader.load(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-windows"]);
mw.loader.load(["oojs-ui.styles.icons-interactions", "oojs-ui.styles.icons-moderation", "oojs-ui.styles.icons-user", "oojs-ui.styles.icons-content", "oojs-ui.styles.icons-editing-core", "oojs-ui.styles.icons-editing-advanced"]);
});
for (let i = 0; i < editRequestBoxes.length; i++) {
let currentBox = editRequestBoxes[i].children[0]; //The tbody tag for the box
if (typeof(currentBox.parentElement.dataset.origlevel) != "undefined") {
let isSmall = false;
if (editRequestBoxes[i].id == "") {
isSmall = true;
}
let replyButton = new OO.ui.ButtonWidget( {
icon: "edit",
flags: ["progressive"],
label: "Respond",
invisibleLabel: isSmall,
title: "Respond to the edit request."
});
replyButton.on("click", function() {
addButtons(currentBox, replyButton);
replyButton.setDisabled(true);
});
replyButton.$element[0].style = "margin:2px 0";
if (isSmall) {
$(currentBox.children[0].children[0]).append(replyButton.$element);
} else {
$(currentBox).append('<tr><td colspan=2><div style="display: flex; justify-content: center;"></div></td></tr>');
$(currentBox.children[1].children[0].children[0]).append(replyButton.$element);
}
}
}
}
//</nowiki>[[Category:Wikipedia scripts]]