MediaWiki:Gadget-WikitextAutocompleter.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') { /* Make the strategy/ies to add */ var Strategies = {}; Strategies.Templates = []; Strategies.Templates.push(new TemplateStrategy( "Color", function { var self = this; $.get( "https://zelda.gamepedia.com/Template:Color?action=raw", function( data ) {				/** Store parameter options in instance variable */				self.params["1"] = readArrayFromString(data);				/** Callback */				self.registerStrategies;			}); var readArrayFromString = function(text) { var array = []; text.split(" ")[0] .split("#switch:")[1] .split("\|#default")[0] .match(/\|[a-zA-Z0-9 ]*/g) .forEach(function(value, index){					var name = value.slice(1).trim;					array.push(name);				}); return array; };		}	));	Strategies.Templates.push(new TemplateStrategy( "KSTest", function { // Need to have self/this for params and registerStrategies var self = this; /** Store parameter options in instance variable */ self.params["1"] = ["testparam1value1","testparam1value2","testparam1value3"]; self.params["2"] = ["testparam2value1","testparam2value2","testparam2value3"]; self.params["3"] = ["testparam3value1","testparam3value2","testparam3value3"];

/** Callback */ self.registerStrategies; }	));	Strategies.Templates.push(new TemplateStrategy( "Icon", function { var self = this; $.get( "https://zelda.gamepedia.com/Template:Icon?action=raw", function( data ) {				/** Store parameter options in instance variable */				self.params["1"] = readArrayFromString(data);				/** Callback */				self.registerStrategies;			}); var readArrayFromString = function(text) { var array = []; text.split(" ")[0] .split("\|#default")[0] .match(/\n\|[a-zA-Z0-9-+ ]*/g) .forEach(function(value, index){					var name = value.slice(2).trim;					array.push(name);				}); return array; };		}	));	var readInitialismsArrayFromString = function(callback) { $.get( "https://zelda.gamepedia.com/Template:Zelda?action=raw", function( data ) {			var initialismsArray = [];			data.split(" ")[1]				.match(/\|\|[a-zA-Z0-9-+& ]*\n/g)				.forEach(function(value, index){ var name = value.slice(2).trim; initialismsArray.push(name); });			callback(initialismsArray);		}); };	readInitialismsArrayFromString(function(initialismsArray) {		Strategies.Templates.push(new TemplateStrategy(			"Exp Game",			function {				var self = this;

/** Store parameter options in instance variable */ self.params["1"] = initialismsArray;

/** Callback */ self.registerStrategies;

}		));

});	// Getting a list of every template in the wiki is non-trivial...	/* Load Textcomplete then register the strategy/ies */	$(document).ready(function { getTextcompleteScript(			Strategies.Templates // Array of TemplateStrategy objects to register each of		); } ); }

function getTextcompleteScript(templateStrategyArray) { 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)" );		// (Global) Textarea object: https://github.com/yuku-t/textcomplete/issues/114#issuecomment-318352383		Textarea = Textcomplete.editors.Textarea;		templateStrategyArray.forEach(function(templateStrategy){ templateStrategy.register; });	}); }

// Been going over OOP in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Example

/** * Strategy Object */

/** * Constructor (and non-prototype definitions) * (instance variables can't be accessed without "this." etc.) */ function TemplateStrategy(templateName, getParametersFunction) { var self = this; /*********************	** Public variables ** **********************/	this.templateName = templateName; this.params = {}; // params. = array of options // should each param have a 'description' variable too? applicable to both preset options and open-ended this.strategies = []; /********************	** Public methods ** ********************/	/**	 * register method */	this.register = function { self.getParameters; // Must have callback to registerStrategies };	this.getParameters = getParametersFunction; this.registerStrategies = function { var params = self.params; var strategies = self.strategies; /** Validate parameters */ console.log("params: "); console.log(params); /**		 * Turn each parameter into a strategy; assume no named parameters for now */		for (var paramName in params) { if (params.hasOwnProperty(paramName)) { console.log(paramName + " -> " + params[paramName]); // Assume paramName is a number (as a String) var precedingParamRegex = ""; var paramNum = parseInt(paramName); for (var i = 1; i < paramNum; i++) { precedingParamRegex += "\\|[^\\|]*"; }				var strategy = self.createStrategy(					templateName,					paramName,					new RegExp("(' for generality for now; maybe will make exceptions for single or no parameter templates?				);				strategies.push(strategy);			}		}		var editor = new Textarea(document.getElementById('wpTextbox1'))		, options = {				dropdown: {					maxCount: 500,					style: { 'margin-top': (-parseFloat($('body').css('margin-top')))+'px' }				}			}		  , textcomplete = new Textcomplete(editor, options);		textcomplete.register(strategies);	};	this.createStrategy = function(name, param, match, paramArray, template, replace) {		var strategy =			{				id: "Template:" + name + "_" + param,				match: match,				search: function (term, callback) { // term is probably the 2nd capture group of the match regexp					var nameArray = paramArray.filter(function(currentValue) { return currentValue.startsWith(term); });					callback(nameArray); // List of possible completions ('names') },				template: function (name) { var displayName = template(name); return displayName; // What to display in the list },				replace: function (name) { var replacementString = replace(name); return replacementString; // What to replace the matched typed text with }			};		return strategy; }; }