Zelda Wiki

Want to contribute to this wiki?
Sign up for an account, and get started!

Come join the Zelda Wiki community Discord server!

READ MORE

Zelda Wiki
Advertisement

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/**
 * 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 strategies to add */
	var templates = {};
	templates.Color = {};
	$.get( "https://zelda.gamepedia.com/Template:Color?action=raw", function( data ) {
		var colorsArray = [];
		data.split("</includeonly>")[0]
			.split("#switch:{{{1\|}}}")[1]
			.split("\|#default")[0]
			.match(/\|[a-zA-Z0-9 ]*/g)
			.forEach(function(value, index){
				var name = value.slice(1).trim();
				colorArray.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("</includeonly>")[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
		};
	});
	var initialismsArray = [];
	var readInitialisms = function(callback) {
		$.get( "https://zelda.gamepedia.com/Template:Zelda?action=raw", function( data ) {
			var initialisms = [];
			data.split("<noinclude>")[1]
				.match(/\|\|[a-zA-Z0-9-+& ]*\n/g)
				.forEach(function(value, index){
				var name = value.slice(2).trim();
				initialisms.push(name);
			});
			initialismsArray = initialisms;
			callback();
		});
	};
	
	/** Initialisms-dependent templates: */
	templates["Exp Game"] = {};
	readInitialisms(function() {
		templates["Exp Game"] = {
			"1": initialismsArray
		};
	});
	
	// Getting a list of every template in the wiki is non-trivial...
	
	/* Load Textcomplete then register the strategies */
	$(document).ready(getTextcompleteScript);
	
	var 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
			registerStrategies();
		});
	};
	/* Note: The param arrays need ont exist before strategy is registered */
	var registerStrategies = function() {
		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);
		/** Register strategies */
		textcomplete.register(templateStrategy);
	};
	
	var getBeforeCursor = function(el) { // Borrowed from https://github.com/yuku-t/textcomplete/blob/6f07195c47ace5e787cf7b46604b37a8bd5c6d30/src/textarea.js#L82
		if (el === null) el = document.getElementById('wpTextbox1');
		return el.selectionStart !== el.selectionEnd ? null : el.value.substring(0, el.selectionEnd);
	};
	
	var getTemplateStartPos = function(text) { // Assumes no "{{{" and "}}}" (perhaps ok even with these, anyway?), nor <nowiki> tags that would render "{{" or "}}" escaped/inactive,
		var count = 0;
		var index = text.length-2;
		while (index >= 0) {
			var char1 = text.charAt(index);
			var char2 = text.charAt(index+1);
			if (char1 === '}' && char2 === '}') {
				count++;
				index -= 2;
			} else if (char1 === '{' && char2 === '{') {
				count--;
				index -= 2;
			} else {
				index -= 1;
			}
			if (count < 0) return index;
		}
		return -1;
	};
	
	var templateStrategy =
	{
		id: "Templates",
		match: /(\|)([^\|]*)$/,
		search: function (term, callback) {
			// term should be the stuff after the latest "|"
			var text = getBeforeCursor(el); //the text before the cursor
			text = text.slice(0,text.length-term.length); //stuff before the term but including the "|"
			var templateStartPos = getTemplateStartPos(text);
			var templateName = text.slice(templateStartPos + 2);
			//loop regex to remove the templates and tables (there should be no unmatched braces?) OR assume none
			templateName = templateName.slice(0,text.indexOf("|"));
			//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<templateName.length; i++) if (templateName.charAt(i) == '|') paramNum++;
			paramArray = templates[templateName][paramNum];
			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
		}
	};
}
Advertisement