User:KokoroSenshi/common.js

/** * Autocomplete/Dropdown list * Uses https://yuku-t.com/textcomplete/ * * Notes: * - Won't work with CodeEditor since it doesn't use a textarea but that's fine *  since CodeEditor won't be used for wikitext * - $.getScript is used since mw.loader.load doesn't wait for the code to load *  mw.loader.load('https://unpkg.com/textcomplete@0.13.1/dist/textcomplete.min.js'); * Bugs: * */

if (mw.config.get("wgAction") == "edit") { /** Global Variables */ strategies = []; // Array of strategies templates = {}; // Contains all the parameter arrays/definitions autoComplete = {}; // Contains supporting variables, e.g. initialismsArray, createTemplateStrategy /** */	templates.Color = {}; $.get( "https://zelda.gamepedia.com/Template:Color?action=raw", function( data ) {		var colorsArray = [];		data.split(" ")[0]			.split("#switch:")[1]			.split("\|#default")[0]			.match(/\|[a-zA-Z0-9 ]*/g)			.forEach(function(value, index){ var name = value.slice(1).trim; colorsArray.push(name); });		templates.Color = {			"1": colorsArray		};	}); templates.KSTest = { "1": ["testparam1value1","testparam1value2","testparam1value3"], "2": ["testparam2value1","testparam2value2","testparam2value3"], "3": ["testparam3value1","testparam3value2","testparam3value3"] };	templates.Icon = {}; $.get( "https://zelda.gamepedia.com/Template:Icon?action=raw", function( data ) {		var iconsArray = [];		data.split(" ")[0]			.split("\|#default")[0]			.match(/\n\|[a-zA-Z0-9-+ ]*/g)			.forEach(function(value, index){ var name = value.slice(2).trim; iconsArray.push(name); });		templates.Icon = {			"1": iconsArray		};	}); autoComplete.initialismsArray = []; var readInitialisms = function(callback) { $.get( "https://zelda.gamepedia.com/Template:Zelda?action=raw", function( data ) {			var initialisms = [];			data.split(" ")[1]				.match(/\|\|[a-zA-Z0-9-+& ]*\n/g)				.forEach(function(value, index){ var name = value.slice(2).trim; initialisms.push(name); });			autoComplete.initialismsArray = initialisms; // Leave autoComplete.initialismsArray empty until fully filled			if (typeof callback === "function") callback;		}); };	/** Initialisms-dependent templates: */ readInitialisms; /* // Won't really need this callback version of the function call? readInitialisms(function {		// Exp Game uses a function, which will get the latest definition of initialismsArray, so isn't needed in this callback	}); */	templates["Exp Game"] = {}; templates["Exp Game"].getParams = function(paramNum) { if (paramNum > 0) // No need to check paramNum, really... return autoComplete.initialismsArray; else return []; };	// Getting a list of every template in the wiki is non-trivial... autoComplete.currentHeader = ""; // An attempt to generate a dropdown menu header to describe the parameter in some way, to accompany choices, or when there are no preset choices. autoComplete.getTextcompleteScript = function { console.log( "Loading textcomplete..." ); $.getScript( "https://unpkg.com/textcomplete/dist/textcomplete.min.js", function( data, textStatus, jqxhr ) {			console.log( [ data, textStatus, jqxhr.status ] ); // Data returned, Success, 200			console.log( "Loaded textcomplete. (Warning: May not be executed yet)" );			// Textarea object: https://github.com/yuku-t/textcomplete/issues/114#issuecomment-318352383			Textarea = Textcomplete.editors.Textarea; // Global variable			autoComplete.registerStrategies;		}); };	/* Note: The param arrays need ont exist before strategy is registered */ autoComplete.registerStrategies = function { var editor = new Textarea(document.getElementById("wpTextbox1")) , options = { dropdown: { maxCount: 500, header: function { return autoComplete.currentHeader }, style: { "margin-top": (-parseFloat($("body").css("margin-top")))+"px" } }			}		, textcomplete = new Textcomplete(editor, options); /** Register strategies */ strategies.push(autoComplete.createTemplateStrategy); textcomplete.register(strategies); };	autoComplete.createTemplateStrategy = function { console.log("createTemplateStrategy start"); var getBeforeCursor = function(/**textarea*/) { // Like https://github.com/yuku-t/textcomplete/blob/6f07195c47ace5e787cf7b46604b37a8bd5c6d30/src/textarea.js#L82 textarea = document.getElementById("wpTextbox1"); return textarea.selectionStart !== textarea.selectionEnd ? null : textarea.value.substring(0, textarea.selectionEnd); };		var getLastTemplateOpenBracketPos = function(text) { // Assumes no "" (perhaps ok even with these, anyway?), nor tags that would render "" escaped/inactive, var count = 0; var index = text.length-2; while (index >= 0) { var chars = [text.charAt(index),text.charAt(index+1)]; console.log(chars); var foundBracketPair = false; if (chars[0] === '}' && chars[1] === '}') { count++; foundBracketPair = true; } else if (chars[0] === '{' && chars[1] === '{') { count--; foundBracketPair = true; }				if (count < 0) return index; foundBracketPair ? index -= 2 : index -= 1; foundBracketPair = false; }			return -1; };		var templateStrategy = {			id: "Templates", match: /(\|)([^\|]*)$/, search: function (term, callback) { console.log("Start identification of parameter choices"); var text = getBeforeCursor; console.log("Text before cursor:: " + text); text = text.slice(0, text.length - term.length); //stuff before the term but including the "|" console.log("Text before term:: " + text); var templateStartPos = getLastTemplateOpenBracketPos(text); var templateBody = text.slice(templateStartPos + "{{".length); console.log("templateBody:: " + templateBody); var templateName = templateBody.slice(0,templateBody.indexOf("|")); // Assumes stuff like {{Test|, not {{Test{{aTemplate}}| console.log("templateName:: " + templateName); // Loop regex to remove the templates [TODO: and tables] (there should be no unmatched braces?) (OR could assume none) // Not sure that this always works, and maybe also inefficient var templateBodyTrimmed = templateBody; while (templateBodyTrimmed != (templateBodyTrimmed = templateBodyTrimmed.replace(/\{\{[^]*?\}\}/g, function (match) { //use "?" in the regex to lazy match, or else it matches the biggest {{...}}, which is unhelpful to the following method						var matchInner = match.slice(2, match.length-2);						if (matchInner.includes("{{") /*|| matchInner.includes("}}")*/) { // The match will only have one "}}" at the end, since regex searches ltr?							// Remove the last pair of "{{" and "}}"							return match.split("").reverse.join("")									.replace(/\}\}[^]*?\{\{/, "") // Pairs become "}}...{{" when the string is reversed									.split("").reverse.join(""); 						} else {							return "";						}					}) ));				// Count the number of "|" in text to determine which parameter (since it's e.g. "{{templateName|param1|param2|currentparam" ) var paramNum = 0; for (var i=0; i<templateBodyTrimmed.length; i++) if (templateBodyTrimmed.charAt(i) == '|') paramNum++; console.log(paramNum); var paramArray = []; if (templates[templateName] !== undefined) { if (typeof templates[templateName].getParams === "function") { paramArray = templates[templateName].getParams(paramNum); } else { paramArray = templates[templateName][paramNum]; }				}				console.log(paramArray); autoComplete.currentHeader = templateName + " " + paramNum; // testing out header var nameArray = paramArray.filter(function(currentValue) { return currentValue.startsWith(term); }); callback(nameArray); // List of possible completions ("names") },			template: function (name) { var displayName = name; return displayName; // What to display in the list },			replace: function (name) { var replacementString = "$1" + name; return replacementString; // What to replace the matched typed text with }		};		console.log("createTemplateStrategy end"); return templateStrategy; };	/* Load Textcomplete then register the strategies */ $(document).ready(autoComplete.getTextcompleteScript); }