User:Erutuon/scripts/CleanupButtons.js

/*	A framework for inserting scripts that perform repetitive and tedious editing tasks. It inserts buttons above the text box, if certain conditions are fulfilled. Pressing the button executes the function. A variable tracks how many times a change is made, or the original content is saved and compared to the modified version. An edit summary is added if the change was done. If two operations have been performed, their edit summaries are combined in a grammatical way.

/* jshint eqeqeq: true, varstmt: true, unused: true, undef: true */ /* globals $, mw */

(function {

"use strict";

const $textBox = $("#wpTextbox1"); const $minorEditCheck = $("#wpMinoredit"); const $editForm = $("#editform"); const cleanupButtonWrapperId = "wikitext-cleanup-button-wrapper"; const cleanupButtonClass = "wikitext-cleanup-button";

window.importStylesheetURI("//en.wiktionary.org/w/index.php?title=User:Erutuon/styles/wikitext-cleanup.css&action=raw&ctype=text/css");

// Template for button object, the first argument to cleanupButtons.addButton // method. const cleanupButtonTemplate = { condition: false, textBoxIncludes: "", button: { text: "", },	minorEdit: false, func: function (content) {			const oldContent = content; let count = 0; content = content.replace(				//g,				function(wholeMatch)				{					++count;					return wholeMatch;				}			); CleanupButtons.notifyReplacements(count); CleanupButtons.addSummary(count, ""); CleanupButtons.addSummary(content !== oldContent, ""); return content; } };

function newCleanupButton(text, id) { if ( typeof text === "function" ) { text = text($textBox.val); if ( typeof text !== "string" ) throw new TypeError("'text' function should return a string."); }	return $(" ").addClass(cleanupButtonClass).attr("id", id).html(text); }

const CleanupButtons = function {}; window.CleanupButtons = CleanupButtons;

CleanupButtons.prototype = { get $wrapper { let wrapper = $("#" + cleanupButtonWrapperId); if (wrapper.length === 0) wrapper = $(" ").attr("id", cleanupButtonWrapperId).insertBefore($editForm); return wrapper; },	get $buttons { return this.$wrapper.children; }, };

CleanupButtons.prototype.createCallback = function(func, minorEdit) { return function { const oldContent = $textBox.val; try { const newContent = func(oldContent); if ( typeof newContent === "string" ) { $textBox.val(newContent); if ( minorEdit === true && newContent !== oldContent ) $minorEditCheck.prop("checked", true); } else { console.error("Callback did not return a string:", newContent); }		} catch (e) { console.error("Error in callback:", e); }	}; };

CleanupButtons.prototype.addButton = function ({ func, minorEdit, funcName, button: { text, id} }) { const buttonCount = this.$buttons.length; text = text || "button" + (buttonCount + 1); id = id || "button-id-" + (buttonCount + 1); const button = newCleanupButton(text, id); if ( typeof func !== "function" ) throw new TypeError("Expected function"); button.click( this.createCallback(func, minorEdit) ); this.$wrapper.append(button); };

CleanupButtons.evaluateConditions = function (...conditions) { // Conditions may be boolean, undefined, null, strings, or RegExp. if ($textBox.length === 0) { console.info("edit box (#wpTextbox1) not found"); return false; }	const textBoxContent = $textBox.val; if (conditions.length === 0) return false; // ??? // finalResolution is true if all conditions evaluate to true or null or // undefined and at least one condition evaluated to true. let resolvedToTrue = false; return conditions.every((condition, index) => {		let resolution;		switch (typeof condition) {			case "boolean": case "undefined":				resolution = condition;				break;			case "string":				resolution = textBoxContent.includes(condition);				break;			case "function":				resolution = condition($("#wpTextbox1").val);				break;			case "object":				if (condition instanceof RegExp) {					resolution = condition.test(textBoxContent);					break;				} else if (condition === null) {					resolution = undefined;					break;				} /* falls through */			default:				return console.error("Unrecognized type of condition number " + (index + 1) + ": " + typeof condition);		}		if (resolution === true)			resolvedToTrue = true;		return resolution === undefined || resolution === true;	}) && resolvedToTrue; };

CleanupButtons.notifyReplacements = function(count) { if ( typeof count === "number" ) mw.notify(`${ count === 0 ? "No" : count } replacement${ count === 1 ? "" : "s" } made.`); else console.log("The function notifyReplacements failed because its argument is not a number."); };

CleanupButtons.addSummary = function(count, summary) { let changed; switch (typeof count) { case "number": changed = count > 0; break; case "boolean": changed = count; break; default: console.log("Type of count was not recognized: " + typeof count + "."); }	if ( changed ) { $("#wpSummary").val(			function(index, content) {				const afterSectionName = content.match(/^(?:\/\*[^*]+\*\/)?\s*(.*?)$/);				const scriptMention = ", with the help of JavaScript";				let addition;				if ( afterSectionName && afterSectionName[1].length > 0 )				{					if ( content.includes(scriptMention) ) {						content = content.replace(scriptMention, "");						addition = " and " + summary;					} else						addition = "; " + summary;				} else					addition = summary;				if ( !afterSectionName || !content.includes(summary) )					content += addition;				if ( content.includes(summary) && !(content.includes(scriptMention)				|| /\[\^|\+\.js\|/.test(summary) ) )					content += scriptMention;				return content;			}		); }	else console.log("No edit summary added."); };

});