User:Thundercraft5/global.js/Ace.js

/* jshint esversion: 6, forin: true, immed: true, indent: 4, latedef: true, newcap: true, noarg: true, undef: true, undef: true, unused: true, browser: true, jquery: true, onevar: true, eqeqeq: true, multistr: true, maxerr: 99999, -W082, -W084 /* global ace, mw, loadModules */

/** Example of registering a snippet: * * ace.registerSnippet([ *		{ *			content: [ *				"${M2?${M3?:table}:table}.sort(${1:t}$0)",	 *			], *			guard: '((t(able)?)\\.|(?:(?:\\s*|[({[])|^)\\.)', *			endTrigger: '\\)?', *			tabTrigger: 'sort', *			trigger: 't?\\.?sort\\(?\\s*', *			scope: 'lua', *		}, * ]); */ "use strict"; var count = 0; $(function { var inter = setInterval(function { var el; if (document.getElementsByClassName('editor').length) {	el = document.getElementsByClassName('editor')[0];	// Remove unwanted elements that slow the page when editing code	if (!mw.util.getParamValue('showpreview'))		$('.mw-editTools, #wikiPreview, .hiddencats, .limitreport, .templatesUsed').remove;	clearInterval(inter); } else {	if (count > 1000) clearInterval(inter);	return; } if ( mw.config.get('wgPageName').match(/(^Module:|\.(\w+)$)/) && ['submit', 'edit', 'editredlink'].includes(mw.config.get('wgAction')) ) { el.id = 'aceEditor';

// Get CSS $.getStyle('u:community:User:Thundercraft5/global.css/EditorToolbar.css');

/*** ACE Globals ***/ window.ace.editor = ace.edit('aceEditor'); window.ace.snippetsManager = ace.require('ace/snippets').snippetManager; window.ace.registerSnippet = function(snippets, scope) { function parseSnippet(v) { v.content = Array.isArray(v.content) ? v.content.join('\n') : v.content; v.guard = v.guard || "\\b|^\\s*"; v.scope = v.scope || scope; v.tabTrigger = v.tabTrigger || v.trigger; v.name = v.name || v.tabTrigger; return v;	} if (Array.isArray(snippets)) { snippets.forEach(function(v, i, arr) {			arr[i] = parseSnippet(v);		}); } else { snippets = parseSnippet(snippets); }	ace.snippetsManager.register(snippets); };

window.ace.insertSnippet = ace.snippetsManager.insertSnippet.bind(ace.snippetsManager); window.ace.codeEditorLang = function getLang(search) { if (!Array.isArray(search)) { if (mw.config.get('wgPageName').match(/^Module:|\.lua$/)) { return "lua"; } else if (mw.config.get('wgPageName').match(/\.(js|javascript)$/)) { return "js"; } else { return mw.config.get('wgPageName').match(/\.(.+?)$/)?.[1] // jshint ignore:line }	} else { for (var k in search) { if (search.hasOwnProperty(k)) { var v = search[k]; if (getLang === v) return true; }		}		return false; } }; window.ace.TokenIterator = ace.require('ace/token_iterator').TokenIterator; window.ace.Range = ace.require('ace/range').Range; window.ace.oop = ace.require('ace/lib/oop'); window.ace.Tokenizer = ace.require('ace/tokenizer').Tokenizer;

if (ace.codeEditorLang !== "lua") { ace.editor.setOptions({		enableLiveAutocompletion: true,	}); }

$('.ui-resizable').css({ height: '800px' }); ace.editor.resize;

/*** Keybindings ***/ $(document.body).on('keydown', function(e) {	// suppress default mediawiki keybinding	if (e.key.toLowerCase === "s" && e.ctrlKey) {		e.preventDefault;		e.stopImmediatePropagation;	} });

// Fix tabs ace.editor.commands.addCommand({	name: "tab",	bindKey: { win: "Tab" },	multiSelectAction: "forEach",	scrollIntoView: "cursor",	exec: function(editor) {		!ace.editor.commands.commands.expandSnippet.exec(ace.editor) && editor.indent;	}, });

// Toggle enableLiveAutocompletion (Ctrl-S) ace.editor.commands.addCommand({	name: 'toggleAutocomplete',	bindKey: {win: 'Ctrl-S'},	exec: function(editor) {		var on = editor.$enableLiveAutocompletion === true;		editor.setOptions({ enableLiveAutocompletion: !editor.$enableLiveAutocompletion, });		if (on) editor.completer?.detach; // jshint ignore:line	} });

// Replace Spaces (Ctrl-Shift-S) ace.editor.commands.addCommand({	name: 'replaceSpaces',	bindKey: {win: 'Ctrl-Shift-S'},	exec: function(editor) {		var pos = editor.getCursorPosition;

editor.find('	'); editor.replaceAll('\t'); editor.moveCursorToPosition(pos); } });

if (ace.codeEditorLang === "js") { // Add jshint ignore line (Ctrl-I) ace.editor.commands.addCommand({		name: 'addIgnore',		bindKey: {win: 'Ctrl-I'},		multiSelectAction: "forEachLine",		exec: function(editor) {			editor.insert('// jshint ignore:line');		}	}); }

// Toggle Folds recusrively command ace.editor.commands.addCommand({	name: 'recusivelyToggleFolds',	bindKey: {win: 'Alt-F'},	multiSelectAction: "forEachLine",	exec: function {		var selection = this.selection;		var range = selection.getRange;		var fold;		var bracketPos;		if (range.isEmpty) {			var cursor = range.start;			fold = this.getFoldAt(cursor.row, cursor.column);

if (fold) { this.unfold(fold.range, true); return "unfold"; } else if (bracketPos = this.findMatchingBracket(cursor)) { if (range.comparePoint(bracketPos) === 1) { range.end = bracketPos; } else { range.start = bracketPos; range.start.column++; range.end.column--; }			} else if (bracketPos = this.findMatchingBracket({ row: cursor.row, column: cursor.column + 1 })) {				if (range.comparePoint(bracketPos) === 1) range.end = bracketPos; else range.start = bracketPos; range.start.column++; } else { range = this.getCommentFoldRange(cursor.row, cursor.column) || range; }		} else { var folds = this.getFoldsInRange(range); if (folds.length) { folds.forEach(v => this.unfold(v.range, true), this); return 'unfold'; } else if (folds.length === 1) { fold = folds[0]; }		}		if (!fold) fold = this.getFoldAt(range.start.row, range.start.column); if (fold && fold.range.toString === range.toString) { this.unfold(fold.range, true); return "unfold"; }

var placeholder = "..."; if (!range.isMultiLine) { placeholder = this.getTextRange(range); if (placeholder.length < 4) return "unfold"; placeholder = placeholder.trim.substring(0, 2) + ".."; }		this.foldAll(range.start.row, range.end.row); if (!this.getFoldAt(range.start.row, range.start.column) && !folds) this.addFold(placeholder, range); return "fold";

}.bind(ace.editor.session), });

// Fix lua comments/Load custom lua rules if (ace.codeEditorLang === "lua") { var o = ace.editor.session.$mode.blockComment; o.start = "-- ";	o.end = " --"; loadModules(['LuaMode.js']); if (mw.config.get('wgPageName').match(/(data|config|storage|items|list)$/i)) { ace.editor.execCommand('foldall'); var pos = ace.editor.find('^}\\s*$',{			regExp: true,			backwards: true,		})?.start; // jshint ignore:line ace.editor.session.expandFold(ace.editor.session.getFoldAt(pos.row, pos.column)); } }

// Go to line based on URL hash (`mw-ce-l `) if (location.href.match(/#mw-ce-l(\d+)$/)) { ace.editor.gotoLine(Number(location.href.match(/#mw-ce-l(\d+)$/)[1])); }

$(window).on('popstate', function {	if (location.href.match(/#mw-ce-l(\d+)$/)) {		ace.editor.gotoLine(Number(location.href.match(/#mw-ce-l(\d+)$/)[1]));	} });

/*** Lua snippets ***/ ace.registerSnippet([	{		content: [			"if ${1:true} then",			"	${2:${SELECTED_TEXT:-- code}}",			"end",		],		tabTrigger: 'if',	},	{		content: [			"if ${1:true} then",			"	${2:${SELECTED_TEXT:-- code}}",			"else",			"	${3:-- code}",			"end",		],		trigger: "ifel?s?e?",		tabTrigger: 'ife',	},	{		content: [			"elseif ${1:true} then",			"	${2:${SELECTED_TEXT:-- code}}",		],		trigger: "el?s?e?if",		tabTrigger: 'elseif',	},	{		content: [			"-",			"-- function: ${1:name}(${2:parameters})",			"-- ",			"-- ",			"-",			"function p.${1:name}(${2:paramters})",			"	${3:${SELECTED_TEXT:-- code}}",			"end",		],		tabTrigger: 'fc',	},	{		content: [			"-",			"-- function: ${1:name}(${2:parameters})",			"-- ",			"-- ",			"-",			"function p.${1:name}(...)",			"	local ${2:paramters} = checkArgs({ '${3:string}' }, ...)",			"	${0:${SELECTED_TEXT:-- code}}",			"end",		],		tabTrigger: 'fca',	},	{		content: [			"-", "-- Template: ${0:name}", "-- ",			"-- ",			"-",			"function p._${1:name}(frame)", "	local args = getArgs(frame)", "	local ${2:value} = args[1]", "",			"	${0:${SELECTED_TEXT:-- code}}", "	return p.${1:name}(${2:value})", "end", ],		tabTrigger: 'ff', },	{		content: [ "function${M2?:${M3?: ${M4?:${1:name}}}}(${2:parameters})", "	${0:${SELECTED_TEXT:-- code}}", "end${M5?:${M3?,:${M2?;}}}", ],		endGuard: '(\\))?',		guard: "((=)\\s*|([;,])\\s*|([\\{\\(])\\s*|\\b)", tabTrigger: 'f', },	{		content: [ "${M2?:local }${1:methodname} = function(${2:parameters})", "	${0:${SELECTED_TEXT:-- code}}", "end${M2?,}", ],		guard: "(([;,\\{])|^)\\s*", tabTrigger: '=f', },	{		content: [ "${M2?:local }${1:methodname} = function(self, ${2:parameters})", "	${0:${SELECTED_TEXT:-- code}}", "end${M2?,}", ],		guard: "(([;,\\{])|^)\\s*", tabTrigger: '=fs', },	{		content: [ "function ${1:Class}.prototype:${2:name}(${3:parameters})", "	${0:${SELECTED_TEXT:-- code}}", "end${M2?,}", ],		guard: "^\\s*", tabTrigger: 'proto', },	{		content: "local ${1:${M2?$M2:value}} = require('Module:${2:Name}')${M2?.:${M1?.}${0:${M2?$M2:${M1?value}}}", guard: "^\\s*", tabTrigger: '=require', trigger: '=require(\\.(.+?)?)?', },	{		content: [ "checkType(${1:1}, ${2:value}, { '${3:string}' }$0)", ],		tabTrigger: 'checkType', trigger: 'check([tT]ype)?', },	{		content: [ "return ${1:${SELECTED_TEXT:value}}", ],		tabTrigger: 'ret', },	{		content: [ "while ${1:condition} do", "	${0:-- code}", "end" ],		tabTrigger: "while", },	{		content: [ "repeat", "	${1:${SELECTED_TEXT:-- code}}", "until(${2:condition})", ],		tabTrigger: "repeat", },	{		content: [ "for ${1:match} in ${2:str}:gmatch('${3:pattern}') do", "	${0:${SELECTED_TEXT:-- code}}", "end" ],		tabTrigger: "forgm", trigger: "forgma?t?c?h?", },	{		content: [ "type(${1:value}) == '${2:type}' $0", ],		endTrigger: "\\)?",		trigger: "t(p|yp?e?)\\(?", tabTrigger: "type", },	{		content: [ "type(${1:value}) ~= '${2:type}' $0", ],		endTrigger: "\\)?",		trigger: "t(p|yp?e?)n\\(?", tabTrigger: "typen", },	{		content: [ "local function ${1:name}(${2:parameters})", "	${0:${SELECTED_TEXT:-- code}}", "end", ],		tabTrigger: 'lf', trigger: "lo?c?a?l? ?fu?n?c?", },	{		content: [ "(function(${1})",			"	${0:-- code}",			"end)(${1})" ],		endTrigger: '\\)?',		tabTrigger: 'f(', trigger: "\\(?f\\(", },	{		content: [ "function ${1:table}:${2:name}(${3:parameters})", "	${0:${SELECTED_TEXT:-- code}}", "end", ],		tabTrigger: 'm', trigger: "me?t?h?o?d?", },	{		content: [ "['${1:name}'] = ${2:value},", "$0",		],		tabTrigger: 'index', trigger: '\\.?in?de?x?', },	{		content: [ "${M1?$M1:${M2?$M2.:string.}}gsub(${M1?:${1:str}, }'${2:pattern}', '${3:replace}'$0)", ],		guard: '(?:^\\s*|\\b)', endTrigger: '\\)?',		tabTrigger: '.gsub',		trigger: '(?:s(?:tring)?\\.||(\\)))gsub\\(?\\s*',	},	{		content: [			"${M2?:${M5?.:${M3?${M4?:string}.:string.}}}match(${M2?:${1:str}, }'${2:pattern}'$0)",			],		guard: '((\\:)\\s*|(s(?:tring)?)\\.||(\\))\\s*|(?:\\s*|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'match', 		trigger: 's?\\.?match\\(?\\s*', },	{		content: [ "${M2?:${M5?.:${M3?${M4?:string}.:string.}}}find(${M2?:${1:str}, }'${2:pattern}'$0)", ],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)',		endTrigger: '\\)?', tabTrigger: 'find', trigger: 's?\\.?find\\(?\\s*',	},		{		content: [			"${M2?:${M5?.:${M3?${M4?:string}.:string.}}}char(${M2?:${1:characters}, }$0)",			],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'char', 		trigger: 's?\\.?char\\(?\\s*', },	{		content: [ "${M2?:${M5?.:${M3?${M4?:string}.:string.}}}byte(${M2?:${1:str}, }${2:i}${2:, j})", ],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)',		endTrigger: '\\)?', tabTrigger: 'byte', trigger: 's?\\.?byte\\(?\\s*',	},	{		content: [			"${M2?:${M5?.:${M3?${M4?:string}.:string.}}}format(${M2?:${1:str}, }'${2:subsitutions}')",			],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'format', 		trigger: 's?\\.?format\\(?\\s*', },	{		content: [ "${M2?:${M5?.:${M3?${M4?:string}.:string.}}}len(${M2?:${1:str}})", ],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)',		endTrigger: '\\)?', tabTrigger: 'len', trigger: 's?\\.?len\\(?\\s*',	},	{		content: [			"${M2?:${M5?.:${M3?${M4?:string}.:string.}}}gmatch(${M2?:${1:str}, }'${2:pattern}')",			],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'gmatch', 		trigger: 's?\\.?gmatch\\(?\\s*', },	{		content: [ "${M2?:${M5?.:${M3?${M4?:string}.:string.}}}rep(${M2?:${1:str}, }${2:number})", ],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)',		endTrigger: '\\)?', tabTrigger: 'rep', trigger: 's?\\.?rep\\(?\\s*',	},	{		content: [			"${M2?:${M5?.:${M3?${M4?:string}.:string.}}}sub(${M2?:${1:str}, }${2:i}${3:, j})",			],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'sub', 		trigger: 's?\\.?sub\\(?\\s*', },	{		content: [ "${M2?:${M5?.:${M3?${M4?:string}.:string.}}}reverse(${M2?:${1:str}})", ],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)',		endTrigger: '\\)?', tabTrigger: 'reverse', trigger: 's?\\.?reverse\\(?\\s*',	},	{		content: [			"${M2?:${M5?.:${M3?${M4?:string}.:string.}}}lower(${M2?:${1:str}})",			],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'lower', 		trigger: 's?\\.?lower\\(?\\s*', },	{		content: [ "${M2?:${M5?.:${M3?${M4?:string}.:string.}}}upper(${M2?:${1:str}})", ],		guard: '((\\:)\\s*|(s(tring)?)\\.|(\\))\\s*|(?:\\s*|^)\\.)',		endTrigger: '\\)?', tabTrigger: "upper", trigger: 's?\\.?upper\\(?\\s*',	},	{		content: [			"${M2?${M3?:table}:table}.concat(${1:t}, \"${2:sep}\")",			],		guard: '((t(able)?)\\.|(?:(?:\\s*|[({[])|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'concat',		trigger: 't?\\.?concat\\(?\\s*', },	{		content: [ "${M2?${M3?:table}:table}.insert(${1:t}, ${2:value})", ],		guard: '((t(able)?)\\.|(?:(?:\\s*|[({[])|^)\\.)',		endTrigger: '\\)?', tabTrigger: 'insert', trigger: 't?\\.?insert\\(?\\s*', 	},	{		content: [			"${M2?${M3?:table}:table}.remove(${1:t}, ${2:index})",			],		guard: '((t(able)?)\\.|(?:(?:\\s*|[({[])|^)\\.)', endTrigger: '\\)?',		tabTrigger: 'remove',		trigger: 't?\\.?remove\\(?\\s*', },	{		content: [ "${M2?${M3?:table}:table}.sort(${1:t}$0)", ],		guard: '((t(able)?)\\.|(?:(?:\\s*|[({[])|^)\\.)',		endTrigger: '\\)?', tabTrigger: 'sort', trigger: 't?\\.?sort\\(?\\s*', 	},	{		content: [			"getArgs(frame)",			],		guard: "[^=]\\b|^\\s*",		trigger: "get[Aa]r?g?s?",		// tabTrigger: 'getArgs',	},	{		content: [			"local getArgs = require('Module:Arguments').getArgs",			],		tabTrigger: "r=getArgs",	},	{		content: [			"local args = getArgs(frame)",			],		guard: "[^re]\\b|^\\s*",		tabTrigger: '=getArgs',	},	{		content: [			"${1:t}[#${1:t}+1] = ${2:value}",			],		tabTrigger: '=t',	},	{		content: [			"error(${1:msg}, ${2:level})",			],		tabTrigger: 'error',		trigger: "er?r?o?r?\\(?", },	{		content: [ "${M1?local ${1:mt} = }getmetatable(${2:table})", ],		guard: "(?:\\b|^\\s*)", trigger: "get", tabTrigger: '(\\=)?getm?e?t?a?', },	{		content: [ "setmetatable(${2:table}, mt)", ],		trigger: "set", tabTrigger: 'setm?e?t?a?', },	{		content: [ "${1:name} = ${2:value}", "$0",		],		guard: "^\\s*", tabTrigger: "=", },	{		content: [ "${1:condition} and ${2:a} or ${3:b}", ],		tabTrigger: 'ter', },	{		content: [ "table.concat{ \"$1\", $0 }", ],		endTrigger: "\\}?", trigger: "(t|table)?\\.concat\\{", tabTrigger: 'concat{', },	{		content: [ "-",			"-- ${1:description}", "-- $0",			"-- ",			"-",			],		tabTrigger: '---', },	{		content: [ "select(\"#\", ...)", ],		endTrigger: "\\)?",		trigger: "sele?c?t?\\(?", tabTrigger: "select", }, /*	{		content: [ "",			],		guard: "", trigger: "", tabTrigger: '', },*/ ], 'lua');

function makeMethodCBSnippet({ name, beforeParams, params, extras, code }) { return { content: [ `.${name}(${$.joinIfArray(beforeParams) || ""}function(\${1:${$.joinIfArray(params) || ''}}) {`,			`	${ code 				? (Array.isArray(code) ? code.join() : code)				:  			}` + (!code ? '	' : '') + '${0:${SELECTED_TEXT:/* code */}}',			"})", ],		guard: '\\S\\s*|^\\s*', endTrigger: '\\)?',		tabTrigger: '.' + name,		trigger: `\\.${name + (extras || '')}\\(?\\s*`, }; }

function makeEventSnippet(name) { return makeMethodCBSnippet({ 		name: name, 		extras: '(e)?(s)?',		params: '${M1|M2?e}',		code: [			'${2:${M1?e.preventDefault;\n	}${M2?e.stopImmediatePropagation;\n	}}',		],	}); }

/*** JS Snippets ***/ ace.registerSnippet([	{		content: [			"/* jshint",			"	esversion: 6, forin: true, ",			"	immed: true, indent: 4, ",			"	latedef: true, newcap: true,",			"	noarg: true, undef: true,",			"	undef: true, unused: true,",			"	browser: true, jquery: true,",			"	onevar: true, eqeqeq: true,",			"	multistr: true, maxerr: 999999,",			"	-W082, -W084",			"*/",			],		tabTrigger: '/jshintconfig',	},	{		content: [			"/* global ${1:variables} */",			],		tabTrigger: '/global',	},	{		content: [			"/* jshint ignore:start */",			],		tabTrigger: "/ignore-s",	},	{		content: [			"/* jshint ignore:end */",			],		tabTrigger: "/ignore-e",	},	{		content: [			"/* jshint ${1:options} */",			],		tabTrigger: '/jshint',	},	{		content: [			'"use strict";',			],		tabTrigger: '/strict',	},	{		content: [			"$(function {", "	${0:${SELECTED_TEXT:/* code */}}", "})",		],		tabTrigger: "$f",	},	{		content: [			'{',			'	content: [',			'		"${1:content}",',			'	],',			'	guard: "${2:guard}",',			'	trigger: "${3:trigger}",',			'	tabTrigger: "${4:tab trigger}",',			'},',			'$0',		],		tabTrigger: '/snippetObj',	},	// jQuery event snippets	...[		'click',		'submit',		'load',		'unload',		'blur',		'keydown',		'keyup',		'mousedown',		'mouseenter',		'mouseleave',		'mousemove',		'mouseout',		'mouseover',		'mouseup',		'resize',		'ready',		'scroll',		'select',		'error',	].map(makeEventSnippet),

makeMethodCBSnippet({		beforeParams: "${1:'eventName'}, ${2:'selector', }",		params: '${M1?e}',		name: "on",		code: [			'${2:${M1?e.preventDefault;\n	}${M2?e.stopImmediatePropagation;\n	}}',		],	}), {		content: [ "/*** ${1:section name} ***/", "$0",		],		tabTrigger: "/***", },		{		content: [ "/**",			" * ${1:ScriptName}", " * ",			" * ${2:description}", " * ",			" * @author			Thundercraft5 (https://dev.fandom.com/wiki/User:Thundercraft5)", " * @version			0.1", " * @license			CC-BY-SA 3.0", " * @creation ${3:creation_date} Thundercraft5", " */",			"",			"/* jshint", "	esversion: 6, forin: true,", "	immed: true, indent: 4,", "	latedef: true, newcap: true,", "	noarg: true, undef: true,", "	undef: true, unused: true,", "	browser: true, jquery: true,", "	onevar: true, eqeqeq: true,", "	multistr: true, maxerr: 999999,", "	-W082, -W084", "*/",			"/* global mw, importArticles, ${1:ScriptName} */", "",			"mw.loader.using(['${4:mw_dependencies}', ]).then(function {",			"	\"use strict\";",			"	if (window.${1:ScriptName} && window.${1:ScriptName}.loaded) {",			"		return window.${1:ScriptName}.warn('Script double loaded, exiting...');",			"	}",			"",			"	/**",			"	 * Main Script Class",			"	 * ",			"	 * @class				${1:ScriptName}",			"	 * @init				hooks",			"	 * @loadcondition		canRun",			"	 */",			"	window.${1:ScriptName} = $.extend({", "		// Variable for double load protection", "		loaded: true,", "",			"		/**#====================================================================#",			"		 * Default configuration options", "		 * ",			"		 * These fields contain any default configuration variables.", "		 **#=====================================================================#",			"		 */",			"		",			"		/**#====================================================================#",			"		 * Global Variables", "		 * ",			"		 * These fields contain all data used by this script.", "		 **#=====================================================================#",			"		 */",			"		wg: mw.config.get([",			"			'wgPageName',",			"			'wgArticlePath',",			"			'wgUserGroups',",			"			'wgNamespaceNumber',",			"		]),", "		isUCP: parseFloat(mw.config.get('wgVersion')) > 1.19,", "		namespaces: mw.config.get('wgFormattedNamespaces'),", "		csrfToken: mw.user.tokens.values.csrfToken,", "		version: 0.1,", "		hooksCount: 0,", "",			"		/**",			"		 * Data object for Hooks fired by this script", "		 * ",			"		 * @data		Hooks for this script", "		 * @field		hook", "		 * @used		", "		 */",			"		hook: Object.freeze({",			"			loaded: mw.hook('dev.${1:ScriptName}.loaded'),",			"		}),", "		/**",			"		 * Data object for All external dependencies/waitfor's data", "		 *",			"		 * @field		imports", "		 * @data		All external dependencies/waitfor's data", "		 * @used		import", "		 */",			"		imports: Object.freeze({",			"			scripts: Object.freeze([", "				'u:dev:MediaWiki:UI-js/code.js',", "				'u:dev:MediaWiki:I18n-js/code.js',", "			]),",			"			style: Object.freeze([", "				'u:dev:MediaWiki:${1:ScriptName}.css',", "			]),",			"			hooks: Object.freeze([", "				'dev.i18n',", "				'dev.ui',", "			]),",			"			await: Object.freeze([", "				'mediawiki.api',", "				'mediawiki.notify',", "				'mediawiki.util',", "			]),",			"			otherOnloadPromises: [",			"			],",			"		}),", "",			"		/**",			"		 * User rights level object.", "		 * Stores data about the necessary rights to preform an action.", "		 *",			"		 * @field				rights", "		 * @parent				${1:ScriptName}", "		 * @used				getRights", "		 */",			"		rights: Object.freeze({",			"			\"global\": Object.freeze([", "				'staff',", "				'helper',", "				'global-discussions-moderator',", "				'wiki-manager',", "				'soap',", "			]),",			"",			"			\"checkuser\": Object.freeze([", "				'soap',", "				'helper',", "				'staff',", "				'wiki-manager',", "				'content-team-member',", "				'checkuser',", "				'util',", "			]),",			"",			"			\"block\": Object.freeze([", "				'sysop',", "				'staff',", "				'helper',", "				'bureaucrat',", "				'global-discussions-moderator',", "				'wiki-manager',", "				'soap',", "			]),",			"",			"			\"delete\": Object.freeze([", "				'content-moderator',", "				'threadmoderator',", "				'sysop',", "				'soap',", "				'staff',", "				'helper',", "				'global-discussions-moderator',", "				'wiki-manager',", "				'content-team-member',", "				'util',", "			]),",			"",			"			\"move\": Object.freeze([", "				\"user\",", "			]),",			"		}),",			"",			"		/**#====================================================================#",			"		 * Loader functions", "		 * ",			"		 * These functions initialize the script and add the event handlers", "		 * to the page.", "		 **#=====================================================================#",			"		 */",			"",			"		/**",			"		 * Main initializer script function.", "		 * Adds the hooks the imported scripts fire.", "		 * Then, it loads them.", "		 *",			"		 * @method		hooks", "		 * @class		${1:ScriptName}", "		 */",			"		hooks: function {", "			this.imports.hooks.forEach(function(v) {",			"				mw.hook(v).add(this.onHook.bind(this, v));",			"			}.bind(this));", "			this.import;", "		},",			"",			"		/**",			"		 * Function for when a hook is loaded.", "		 * This is function is called 3 times. When the hooks count reach 3, it adds the click event handlers.", "		 *",			"		 * @method		onHook", "		 * @class		${1:ScriptName}", "		 */",			"		onHook: function(value, arg) {", "			// Increment Hook count", "			++this.hooksCount;", "",			"			// Switch hook value", "			switch (value) {", "				case (\"dev.i18n\"):", "					this.i18n = arg;", "					break;", "",			"				case ('dev.ui'):", "					this.ui = arg;", "					break;", "			}",			"",			"			// When hooks count reach 3, load the script", "			if (this.hooksCount === 3) {", "				this.i18n.loadMessages('${1:ScriptName}', { language: this.lang }).then(this.init.bind(this));", "			} else return;", "		},",			"",			"		/**",			"		 * Dependency importer.", "		 * This method imports any external scripts used by this one.", "		 * ",			"		 * @method		import", "		 * @class		${1:ScriptName}", "		 */",			"		import: function {", "			this.log('importing...');", "",			"			if (!this.isUCP) this.imports.await[1] = 'ext.bannerNotifications';", "",			"			// Add necessary imports on top of other promises", "			this.imports.otherOnloadPromises.push(",			"				mw.loader.using(this.imports.await),",			"				importArticles({", "					type: \"script\",", "					articles: this.imports.scripts,", "				}),",			"				importArticles({", "					type: \"style\",", "					articles: this.imports.style,", "				})",			"			);",			"",			"			// Load all imports", "			$.when.apply($, this.imports.otherOnloadPromises);", "		},",			"",			"		/**",			"		 * Actual script initializer.", "		 * This function sets up the event handlers on the page ", "		 * and sets the variables that cannot be loaded beforehand.", "		 *",			"		 * @method		init", "		 * @class		${1:ScriptName}", "		 */",			"		init: function(i18n) {", "			this.api = new mw.Api;", "			this.i18n = i18n;", "			this.wg.wgArticlePath = this.wg.wgArticlePath.replace('$1', ''),", "			this.getParamValue = mw.util.getParamValue;", "",			"			Object.freeze(this.wg);", "			this.log('Ready');", "",			"			// Fire any hooks attached to this script", "			this.hook.loaded.fire;", "			this.i18n.useUserLang;", "		},",			"",			"		/**#====================================================================#",			"		 * Utility functions", "		 * ",			"		 * These functions preform utilities for the script.", "		 **#=====================================================================#",			"		 */",			"",			"		/**",			"		 * Rights data function.", "		 * Returns an array of user groups for the requested action.", "		 * ",			"		 * @method					getRights", "		 * @class					${1:ScriptName}", "		 * @returns	{Array}			An Array of user groups for the requested action", "		 * @param {String} action	The action to request", "		 */",			"		getRights: function(action) {", "			action = action.toLowerCase;", "",			"			switch (action.toLowerCase) {", "				case (\"global\"):", "					return this.rights[action];", "				case (\"checkuser\"):", "					return this.rights[action];", "				case (\"block\"):", "					return this.rights[action];", "				case (\"protect\"):", "				case (\"delete\"):", "					return this.rights[\"delete\"];", "				case (\"move\"):", "					return this.rights[action];", "			}",			"		},",			"",			"		/**",			"		 * User groups rights checker function.", "		 * Checks if the user has the groups for the requested level.", "		 *",			"		 * @method					hasRights", "		 * @class				  ${1:ScriptName}", "		 * @returns {Boolean}		Whether the user has the requested rights", "		 * @param {String} level	The action to request", "		 */",			"		hasRights: function(level) {", "			var rights = this.getRights(level),", "				len = rights.length;", "",			"			while (len--) {", "				if (this.wg.wgUserGroups.indexOf(rights[len]) !== -1) {", "					return true;", "				}",			"			}",			"",			"			return false;", "		},",			"",			"		/**",			"		 * Function to check whether the script can run.", "		 * Used outside the class.", "		 * ",			"		 * @method		canRun", "		 * @class		${1:ScriptName}", "		 */",			"		canRun: function {", "			return this.hasRights(\"move\");", "		},",			"",			"		/**",			"		 * Function to load an `i18-js` message.", "		 * ",			"		 * @method				msg", "		 * @class				${1:ScriptName}", "		 * @param {String} 1	the message code", "		 * @param {*} arguments arguments to the message", "		 * @return {String} 	The message's contents", "		 */",			"		msg: function {", "			return this.i18n.msg.apply(null, arguments).plain;", "		},",			"",			"		/**",			"		 * Function to check if a value is nullish as this software ", "		 * does not support the `??` operator.", "		 *",			"		 * @method				isNullish", "		 * @class				${1:ScriptName}", "		 * @param {*} v 		The value to check ", "		 * @returns {Boolean}	Whether not the value is nullish", "		 */",			"		isNullish: function(v) {", "			return v === null || v === undefined;", "		},",			"",			"		/**",			"		 * Function to set up a nullish default as this software ", "		 * does not support the `??` operator.", "		 * ",			"		 * @method				nullishDefault", "		 * @class				${1:ScriptName}", "		 * @param {*} v			The value to check and return if it is not nullish", "		 * @param {*} _default	The value to return if `v` is nullish", "		 * @returns {*} 		`v` if it is not nullish and `$default` if it is", "		 */",			"		nullishDefault: function(v, _default) {", "			return this.isNullish(v) ? _default : v;", "		},",			"",			"		/**",			"		 * Function to create a logging method in the class", "		 * ",			"		 * @method		 logBuilder", "		 * @class		  ${1:ScriptName}", "		 * @param {String} level - The level to log at.", "		 * @param {Arguments} args - The function arguments to call the logging function with.", "		 * @return {String} - The message that was passed to the logging function.", "		 */",			"		logBuilder: function(level, args) {", "			args = Array.from(args);", "			console[level.toLowerCase].apply(null, ['[${1:ScriptName} v' + this.version + ']: '[' + level.toUpperCase + ']'].concat(args));", "			return args.join(' ');", "		},",			"",			"		/**",			"		 * Function to log a error message with the script's name.", "		 * ",			"		 * @method		 error", "		 * @class		  ${1:ScriptName}", "		 * @param {*} arguments - The arguments to pass to the logging function. ", "		 * @return {String} - The message that was passed to the logging function.", "		 */",			"		error: function {", "			return this.logBuilder('warn', arguments);", "		},",			"",			"		/**",			"		 * Function to log a warning message with the script's name.", "		 * ",			"		 * @method		 warn", "		 * @class		  ${1:ScriptName}", "		 * @param {*} arguments - The arguments to pass to the logging function. ", "		 * @return {String} - The message that was passed to the logging function.", "		 */",			"		warn: function {", "			return this.logBuilder('warn', arguments);", "		},",			"",			"		/**",			"		 * Function to log a debug message with the script's name.", "		 * ",			"		 * @method			log", "		 * @class		  ${1:ScriptName}", "		 * @param {*} arguments - The arguments to pass to the logging function. ", "		 * @return {String} - The message that was passed to the logging function.", "		 */",			"		log: function {", "			return this.logBuilder('log', arguments);", "		},",			"",			"		/**",			"		 * Function to convert a value into a string.", "		 * ",			"		 * @param {*} value	- The value to convert.", "		 * @returns {String} - The converted value", "		 * @method			log", "		 * @class		  ${1:ScriptName}", "		 */",			"		string: function(value) {", "			if (Array.isArray(value)) {", "				return value.join('');", "			} else {", "				return String(value);", "			}",			"		},",			"",			"		/**",			"		 * Function to create a link.", "		 * ",			"		 * @method			makeLink", "		 * @class			${1:ScriptName}", "		 * @param {page}	The page to link to.", "		 * @param {alt}		The alternate text for the link", "		 * @param {attrs}	The attributes for the link element.", "		 * @return {HTMLAnchorElement} - The link that was passed to the arguments.", "		 */",			"		makeLink: function(page, alt, attrs) {", "			var page = page || this.wg.wgPageName;", "			var origPage = page;", "			var attrs = attrs || {};", "			",			"			var wiki, specials = {", "				'^(m|meta):': 'meta.wikimedia.org',", "				'^(mw):': 'mediawiki.org',", "				'^(ucp):': 'ucp.fandom.com',", "				'^(wp|wikipedia):': 'en.wikipedia.org',", "				'^(w|wikia):(?!c|community)': 'community.fandom.com',", "				'^(dev):': 'dev.fandom.com',", "				'^(?:w|wikia):(?:c|community):([a-z]+)?\\.([a-z_\\-0-9A-Z]+):': function(match) {", "					var community = match[2],", "						lang = match[1];", "		",			"					return \"https://\" + community + \".fandom.com\" + lang ? '/' + lang : '';", "				}",			"			};",			"		",			"			if ((/^(.+?):/).test(page)) {", "				for (var k in specials) {", "					if (specials.hasOwnProperty(k)) {", "						var v = specials[k];", "			",			"						if (new RegExp(k, 'i').test(page)) {", "							if (typeof(v) === \"string\") {", "								wiki = v;", "							} else if (typeof(v) === \"function\") {", "								wiki = v(page.match(k));", "							}",			"							page = page.replace(new RegExp(k), '');", "							break;", "						}",			"					}",			"				}",			"			}",			"",			"		/**#=====================================================================#",			"		 * Main functions", "		 * ",			"		 * These functions do the main work when running this script.", "		 **#=====================================================================#",			"		 */",			"",			"	}, window.${1:ScriptName});",			"",			"	if (!${1:ScriptName}.canRun) return this.log('User does not have necessary rights, exiting...');",			"",			"	${1:ScriptName}.hooks;",			"});" ],		tabTrigger: "devwikiscript", },	/*{		content: [ "",			],		guard: "", trigger: "", tabTrigger: '', },*/	/*{		content: [ "",			],		guard: "", trigger: "", tabTrigger: '', },	{		content: [ "",			],		guard: "", trigger: "", tabTrigger: '', },	{		content: [ "",			],		guard: "", trigger: "", tabTrigger: '', },	{		content: [ "",			],		guard: "", trigger: "", tabTrigger: '', },*/ /*	{		content: [ "",			],		guard: "", trigger: "", tabTrigger: '', },*/ ], 'javascript');

/*** JS Code evaluator ***/ if (mw.config.get('wgPageName').endsWith('.js')) { function evaluate(editor) { // jshint ignore: line var text = editor.getValue; var result, error; var errorRE = /^(.*?)(Error|Exception)/g; // jshint ignore: line function truncate(s) { // jshint ignore: line var len = s.length; if (s.length > 40) { var s1 = s.substr(0, 20); var s2 = s.substr(len-20, len-1); }			return s1 ? s1 + '...' + s2 : s; // jshint ignore: line }		function trimStack(s) { return s.replace(/\n(?:	| {4})at eval \( \)[^\0]*$/, '').replaceAll(/(\n(?:	| {4}))at (.+?) \(eval at (?:.+?) \((?:.+?)\), (.+?)\)/g, function(_, $1, $2, $3) {					return `${$1}at ${$2 === "eval" ? $3 : $2}${ $2 === "eval" ? "" : " (" + $3 + ")" }`;				}); }		try { result = eval.call(window, text); } catch(e) { e = e !== null && e !== undefined ? (e.stack || e).toString : String(e); // jshint ignore: line console.warn(trimStack(e)); error = e;		} finally { var res = error // jshint ignore: line /* jshint ignore:start */ ? ((error?.toString.match(errorRE) || 'Error: ') + trimStack(error.replace(errorRE, ''))) .replace(/${truncate($1)}`; })				: (result?.toString || String(result))				/* jshint ignore: end */			$('#codeEditor-eval-output').append($(' ', {				html: $(error ? '' : ' ', { class: error ? "error" : null, style: "font-size: inherit !important", html: res, }),			}));			!error && console.log(result);		}	}	ace.editor.commands.addCommand({ name: 'eval', bindKey: {win: 'Ctrl-M'}, exec: evaluate.bind(ace.editor), });	$(".codeEditor-status").after($(' ', {		class: "codeEditor-eval",		html: $(' ', { html: [ $(' ', { text: "Editor code evaluator" }), $('', {					css: {						"list-style": "square",						"margin": "0.4em 0px 0.5em 2.5em",					},					html: $('', { text: "Press 'Ctrl + M' to evaluate the code in the editor above.", }),				}),				$(' ', {					id: "codeEditor-eval-output",					class: "mw-scribunto-input",				}), $(' ', {					text: "Clear output",					id: "clearOutput",				}), $(' ', {					text: "Evaluate",					id: "evaluate",				}), ]		}),	}));	$('#clearOutput').click(function(e) { e.preventDefault; e.stopImmediatePropagation; $('#codeEditor-eval-output').empty; });	$('#evaluate').click(function(e) { e.preventDefault; e.stopImmediatePropagation; evaluate(ace.editor); }); }

/*** Lua Debug console status worker (WIP) ***/ /*function setupStatusBar { var shouldUpdateAnnotations, shouldUpdateSelection, shouldUpdateLineInfo, nextAnnotation, delayedUpdate, editor = debugConsole, lang = ace.require('ace/lib/lang'), $errors = $(' ').addClass('codeEditor-status-worker-cell ace_gutter-cell ace_error').text('0'), $warnings = $(' ').addClass('codeEditor-status-worker-cell ace_gutter-cell ace_warning').text('0'), $infos = $(' ').addClass('codeEditor-status-worker-cell ace_gutter-cell ace_info').text('0'), $message = $(' ').addClass('codeEditor-status-message'), $lineAndMode = $(' ').addClass('codeEditor-status-line'), $workerStatus = $(' ') .addClass('codeEditor-status-worker') .attr('title', mw.msg('codeeditor-next-annotation')) .append($errors) .append($warnings) .append($infos);

var $statusBar = $(' ') .addClass('codeEditor-status') .append($workerStatus) .append($message) .append($lineAndMode);

// Helper function to concatenate strings with different separators function addToStatus(status, str, separator) { if (str) { status.push(str, separator || '|'); }	}

/**	 * Update all the information in the status bar *\/	function updateStatusBar { var i, c, r,			status, annotation, errors = 0, warnings = 0, infos = 0, distance, shortestDistance = Infinity, closestAnnotation, currentLine = editor.selection.learow, annotations = editor.getSession.getAnnotations, closestType;

// Reset the next annotation nextAnnotation = null;

for (i = 0; i < annotations.length; i++) { annotation = annotations[ i ]; distance = Math.abs(currentLine - annotation.row);

if (distance < shortestDistance) { shortestDistance = distance; closestAnnotation = annotation; }			if (nextAnnotation === null && annotation.row > currentLine) { nextAnnotation = annotation; }

switch (annotations[ i ].type) { case 'error': errors++; break; case 'warning': warnings++; break; case 'info': infos++; break; }		}		// Wrap around to the beginning for nextAnnotation if (nextAnnotation === null && annotations.length > 0) { nextAnnotation = annotations[ 0 ]; }		// Update the annotation counts if (shouldUpdateAnnotations) { $errors.text(errors); $warnings.text(warnings); $infos.text(infos); }

// Show the message of the current line, if we have not already done so		if (closestAnnotation &&				currentLine === closestAnnotation.row &&				closestAnnotation !== $message.data('annotation')) { $message.data('annotation', closestAnnotation); closestType = closestAnnotation.type.charAt(0).toUpperCase + closestAnnotation.type.slice(1);

$message.text(closestType + ': ' + closestAnnotation.text); } else if (				$message.data('annotation') !== null &&				(!closestAnnotation || currentLine !== closestAnnotation.row)			) { // If we are on a different line without an annotation, then blank the message $message.data('annotation', null); $message.text(''); }

// The cursor position has changed if (shouldUpdateSelection || shouldUpdateLineInfo) { // Adapted from Ajax.org's ace/ext/statusbar module status = [];

if (editor.$vimModeHandler) { addToStatus(status, editor.$vimModeHandler.getStatusText); } else if (editor.commands.recording) { addToStatus(status, 'REC'); }

c = editor.selection.lead; addToStatus(status, (c.row + 1) + ':' + c.column, ''); if (!editor.selection.isEmpty) { r = editor.getSelectionRange; addToStatus(status, '(' + (r.enrow - r.start.row) + ':' + (r.encolumn - r.start.column) + ')'); }			status.pop; $lineAndMode.text(status.join('')); }

shouldUpdateLineInfo = shouldUpdateSelection = shouldUpdateAnnotations = false; }

// Function to delay/debounce updates for the StatusBar delayedUpdate = lang.delayedCall(function {		updateStatusBar(editor);	});

/**	 * Click handler that allows you to skip to the next annotation *\/	$workerStatus.on('click', function (e) {		if (nextAnnotation) {			debugConsole.navigateTo(nextAnnotation.row, nextAnnotation.column);			// Scroll up a bit to give some context			debugConsole.scrollToRow(nextAnnotation.row - 3);			e.preventDefault;		}	});

editor.getSession.on('changeAnnotation', function {		shouldUpdateAnnotations = true;		delayedUpdate.schedule(100);	}); editor.on('changeStatus', function {		shouldUpdateLineInfo = true;		delayedUpdate.schedule(100);	}); editor.on('changeSelection', function {		shouldUpdateSelection = true;		delayedUpdate.schedule(100);	});

// Force update shouldUpdateLineInfo = shouldUpdateSelection = shouldUpdateAnnotations = true; updateStatusBar(editor);

$statusBar.insertAfter($('.wikiEditor-ui-view-wikitext .wikiEditor-ui-bottom')); }*/ }}, 10) });