From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

/*<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(editRequestsi].attributes'data-origlevel']) == 'undefined') {

		$(editRequestsi].children0]).append('<tr><td colspan="2" class="response-cell" style="text-align:center;"></td></tr>');

		COIRequests.push(editRequestsi]);

	}

}



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.pagesmw.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";

	}

	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(COIRequestsi], respondButton, watchStatus);

			respondButton.setDisabled(true);

		});

		respondButton.$element0].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 style="color:#808080"><div style="font-style:italic; margin-left:1em;">There are currently ' + watchStatus0 + ' users watching this page (' + watchStatus1 + ' 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 style="color:#808080">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 style="color:#808080">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 = quickNonResponsesi];

		let tempButton = new OO.ui.ButtonWidget({

			flags: nonResponseCOItempVal].flags,

			icon: nonResponseCOItempVal].icon,

			title: nonResponseCOItempVal].title,

			invisibleLabel: true

		}).on("click", function () {

			saveResponseCOI([COIRequest, responseQuick, responsePreview, responseControls], nonResponseCOItempVal], "", "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 = quickResponsesi];

		let tempButton = new OO.ui.ButtonWidget({

			flags: responseCOItempVal].flags,

			label: responseCOItempVal].label,

			title: responseCOItempVal].title

		}).on("click", function () {

			saveResponseCOI([COIRequest, responseQuick, responsePreview, responseControls], responseCOItempVal], "", "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: responseCOIi].text,

			icon: responseCOIi].icon,

			data: responseCOIi

		});

		responseDropdown.menu.addItems([tempWidget]);

	}

	responseDropdown.$element0].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.$element0].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 (!!watchStatus2]) {

		watchOptions.unshift({data: "nochange", label: watchStatus2]});

		watchValue = "nochange";

	}

	let watchlistLayout = new OO.ui.HorizontalLayout();

	let watchlistDropdown = new OO.ui.DropdownInputWidget({

		value: watchValue,

		options: watchOptions,

		disabled: (watchStatus2 == undefined)

	});

	watchlistLayout.addItems([watchlistDropdown]);

	//Watchlist checkbox & label

	let watchlistCheckbox = new OO.ui.CheckboxInputWidget({

		selected: (watchStatus2 != undefined)

	}).on("change", function (newStatus) {

		watchlistDropdown.setDisabled(!newStatus);

	});

	let watchlistLabel = new OO.ui.LabelWidget({label: "Watch this page"}).on("change", function (newStatus) {



	});

	//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.children1].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

	requestBox1].innerHTML = "";

	requestBox3].remove();

	let statusMessage = new OO.ui.MessageWidget({

		icon: 'pageSettings',

		type: 'notice',

		label: 'Processing request — Edit request starting, getting section data to edit.'

	});

	statusMessage.$element0].style = "margin:5px 0; max-width:50em";

	$(requestBox1]).append(statusMessage.$element);

	//Create progress bar

	let progressBar = new OO.ui.ProgressBarWidget({

		progress: false

	});

	$(requestBox1]).append(progressBar.$element);

	//Set preview for output

	previewCOI(responseOption, responseText, requestBox2]);

	// Find header

	let header = "";

	let sectionIndex = 0;

	let tempElement = requestBox0];

	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 (sectionsi].anchor == header) {

						sectionIndex = parseInt(sectionsi].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 = "/?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]]
From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

/*<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(editRequestsi].attributes'data-origlevel']) == 'undefined') {

		$(editRequestsi].children0]).append('<tr><td colspan="2" class="response-cell" style="text-align:center;"></td></tr>');

		COIRequests.push(editRequestsi]);

	}

}



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.pagesmw.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";

	}

	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(COIRequestsi], respondButton, watchStatus);

			respondButton.setDisabled(true);

		});

		respondButton.$element0].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 style="color:#808080"><div style="font-style:italic; margin-left:1em;">There are currently ' + watchStatus0 + ' users watching this page (' + watchStatus1 + ' 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 style="color:#808080">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 style="color:#808080">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 = quickNonResponsesi];

		let tempButton = new OO.ui.ButtonWidget({

			flags: nonResponseCOItempVal].flags,

			icon: nonResponseCOItempVal].icon,

			title: nonResponseCOItempVal].title,

			invisibleLabel: true

		}).on("click", function () {

			saveResponseCOI([COIRequest, responseQuick, responsePreview, responseControls], nonResponseCOItempVal], "", "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 = quickResponsesi];

		let tempButton = new OO.ui.ButtonWidget({

			flags: responseCOItempVal].flags,

			label: responseCOItempVal].label,

			title: responseCOItempVal].title

		}).on("click", function () {

			saveResponseCOI([COIRequest, responseQuick, responsePreview, responseControls], responseCOItempVal], "", "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: responseCOIi].text,

			icon: responseCOIi].icon,

			data: responseCOIi

		});

		responseDropdown.menu.addItems([tempWidget]);

	}

	responseDropdown.$element0].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.$element0].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 (!!watchStatus2]) {

		watchOptions.unshift({data: "nochange", label: watchStatus2]});

		watchValue = "nochange";

	}

	let watchlistLayout = new OO.ui.HorizontalLayout();

	let watchlistDropdown = new OO.ui.DropdownInputWidget({

		value: watchValue,

		options: watchOptions,

		disabled: (watchStatus2 == undefined)

	});

	watchlistLayout.addItems([watchlistDropdown]);

	//Watchlist checkbox & label

	let watchlistCheckbox = new OO.ui.CheckboxInputWidget({

		selected: (watchStatus2 != undefined)

	}).on("change", function (newStatus) {

		watchlistDropdown.setDisabled(!newStatus);

	});

	let watchlistLabel = new OO.ui.LabelWidget({label: "Watch this page"}).on("change", function (newStatus) {



	});

	//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.children1].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

	requestBox1].innerHTML = "";

	requestBox3].remove();

	let statusMessage = new OO.ui.MessageWidget({

		icon: 'pageSettings',

		type: 'notice',

		label: 'Processing request — Edit request starting, getting section data to edit.'

	});

	statusMessage.$element0].style = "margin:5px 0; max-width:50em";

	$(requestBox1]).append(statusMessage.$element);

	//Create progress bar

	let progressBar = new OO.ui.ProgressBarWidget({

		progress: false

	});

	$(requestBox1]).append(progressBar.$element);

	//Set preview for output

	previewCOI(responseOption, responseText, requestBox2]);

	// Find header

	let header = "";

	let sectionIndex = 0;

	let tempElement = requestBox0];

	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 (sectionsi].anchor == header) {

						sectionIndex = parseInt(sectionsi].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 = "/?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]]

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook