MediaWiki:Gadget-TooltipsEditor.js

/* jshint esversion: 5, 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, ace */

$.when(	$.Deferred(function(def) { $(function { 			def.resolve;		}); }), 	mw.loader.using('mediawiki.util'),	$.Deferred(function(def) { if (mw.libs.QDmodal) { def.resolve(mw.libs.QDmodal); } else { $.ajax({				cache: true,				dataType: "script",				url: "https://dev.fandom.com/load.php?mode=articles&only=scripts&articles=MediaWiki:QDmodal.js"			}).done(function { 				def.resolve(mw.libs.QDmodal);			}); }	}) ).then(function {	if (mw.config.get('wgPageName') !== 'Module:Inventory_slot/Tooltips' || window.TooltipsEditorLoaded) return;	var modal = new mw.libs.QDmodal("TooltipsEditor");	var api = new mw.Api;	var closing;	var actions = [];	window.TooltipsEditorLoaded = true;	console.log('Loading TooltipsEditor...');	function replaceLines(s) {		return s.replaceAll(/(?<!\\)\//g, '\\/').replaceAll(/\n/g, '/');	}	function convertSlashes(s) {		return s.replaceAll(/(?<!\\)\//g, '\n');	}	function reset(confirm) {		if (confirm) {			$("#TooltipsEditor-search").css({ display: "" });			$('#TooltipsEditor-searchResults').empty;			$('#searchResultsMessage, #TooltipsEditor-editor').css({ display: "none" });			$('#TooltipsEditor > section').removeClass('mw-ajax-loader');			ace.tooltipsTextEditor.setValue("");			ace.tooltipsTitleEditor.setValue("");			$("#TooltipsEditor-key, #TooltipsEditor-link").val(""); $('.qdmodal-button').css({ display: "" }); if ($('#TooltipsEditor-searchInput').val.trim !== "") $('#TooltipsEditor-searchInput').keyup; }	}	function searchArray(arr, search) { var splitSearch = function(str) { var pattern = str.split("").map(function(v) {				return "(?=.*" + mw.RegExp.escape(v) + ")";			}).join(""); var regex = new RegExp(pattern, "i"); var match = str.match(regex); return match && match[0]; };	 return arr.filter(function(v) {			return v.toLowerCase.includes(search.toLowerCase) || splitSearch(v.toLowerCase, search.toLowerCase);		}); }	mw.util.addCSS("\	z-index: 99999999 !important; \ }\ \ .ace_format_bold {\	font-weight: bold !important;\ }\ \ .ace_format_italic {\	font-style: italic !important;\ }\ \ .ace_format_underline {\	font-style: italic !important;\	text-decoration: strikethrough, underline;\	text-decoration-color: currentcolor;\ }\ \ .ace_format_strikethrough {\	text-decoration: line-through;\	text-decoration-color: currentcolor;\ }\ \ .ace_escape {\	color: #a1bff5 !important;\	font-weight: bold !important;\ }\ \ .ace_backescape {\	color: #B58900 !important;\	font-weight: bold !important;\ }\ \	width: 700px !important;\ }\ .TooltipsEditor-insertFormat, .TooltipsEditor-insertChar {\	cursor: copy;\ }\ .TooltipsEditor-insertChar {\	margin: 0em 0.3em;\ }\ color: var(--theme-article-text-color) !important;\  font-family: rubik,helvetica,arial,sans-serif !important;\  border: none;\  margin-top: 20px;\  margin-bottom: 20px;\ background-color: var(--theme-accent-color);\ }\	margin-right: 10px;\ }\	background-color: transparent !important;\ text-transform: uppercase;\ }\	background-color: transparent !important;\ cursor: help;\ border: dotted 0.15em !important;\ }\ .TooltipsEditor-editTooltip, .TooltipsEditor-removeTooltip {\ cursor: pointer;\ }\ .TooltipsEditor-previewTooltip {\ cursor: help;\ color: var(--qdmodal-text-color);\ }\	font-style: italic;\ }\ .actions-none {\ color: #808080;\ }\ .actions-add, .actions-modify, .actions-remove {\ font-weight: bold;\ font-size: 13px;\ }\ .actions-add {\ color: lime;\ }\ .actions-modify {\ color: #DAA520;\ }\ .actions-remove {\ color: red;\ }\ .actions-revert {\ color: darkgray;\ font-size: 13px;\ }\ .actions-add::before, .actions-modify::before, .actions-remove::before, .actions-revert::before{\ margin-right: 1.5em;\ }\ .actions-add::before {\ content: '+ ';\ }\ .actions-modify::before {\ content: '≠ ';\ }\ .actions-remove::before {\ content: '– ';\ }\ .actions-revert::before {\ content: '> ';\ margin-left: 0.8em;\ }\ .actions-undo-button, .actions-preview-button {\ text-decoration: underline dotted;\ font-size: 0.8em;\ color: white;\ }\ .actions-undo-button {\ padding: 0em 0.4em;\ margin-left: 0.7em;\ cursor: pointer;\ }\ .actions-preview-button {\ padding: 0em 0.4em;\ cursor: help;\ }\ .noselect {\ -webkit-touch-callout: none;\ -webkit-user-select: none;\ -khtml-user-select: none;\ -moz-user-select: none;\ -ms-user-select: none;\ user-select: none;\ }\	font-style: italic;\ }\	font-weight: bold;\ margin-left: 0.5em;\ }\	".trim);	mw.loader.load(['ext.codeEditor.ace']);	function onClick(tooltips) {		var isInMain = true;		var data;		closing = false;		$(window).on('beforeunload', function {			if (!closing)   			return 'Are you sure you want to exit the page and discard your changes?';		});		modal.show({			title: "Tooltips Editor",			onHide: function {				if (!closing && confirm("Are you sure you want to exit the editor and discard your changes?")) {					closing = true;					return true;				}				else if (closing) return true;				else return false;			},			buttons: [{				text: "Save and Close",				handler: function {					closing = true;					if (confirm('Are you sure you want to save and close the editor?')) modal.hide; else return;					var ret = [];					Object.keys(data).sort.forEach(function(k) {						var v = data[k];						ret.push([							"\t['" + k.replace(/(['"])/g, '\\$1') + "'] = {", v.name ? "name = '" + v.name.replace(/(['"])/g, '\\$1') + "', " : "",							v.title ? "title = '" + v.title.replace(/(['"])/g, '\\$1') + "', " : "", v.text ? "text = '" + v.text.replace(/(['"])/g, '\\$1') + "', " : "",							"},",						].join(""));					});					ret = "return {\n" + ret.join('\n') + "\n}\n".replaceAll('&amp;', '&').replaceAll(/\\/g, '\\\\');					api.postWithEditToken({						action: "edit",						text: ret.replaceAll(/&amp;/g, '&'),						title: mw.config.get('wgPageName'),						summary: "Updating tooltips (TooltipsEditor)",						minor: true,					}).always(console.log);				},			}],		});		$('#TooltipsEditor > section').attr('class', 'mw-ajax-loader');			api.post({			action: 'scribunto-console',			title: mw.config.get('wgPageName'),			question: "=mw.text.jsonEncode(p)",			content: tooltips,		}).then(function(d) {			var json = JSON.parse(d['return'].replaceAll('\\\\', '\\'.repeat(4)));			var oldjson = {};			var editor = $('#TooltipsEditor > section');			data = json;   		var oldjsonkeys = Object.keys(json);	    	function inOldjson(k) { return oldjsonkeys.indexOf(k) !== -1; }	   	function throwOldjson(k) { if (inOldjson(k) && !(k in oldjson)) { oldjson[k] = {}; Object.assign(oldjson[k], json[k]); }   		}			function updateActions(keys) { // calling updateActions without keys will refresh the table without additional change // keys can be an array of strings or one string function updateOne(k) { if (k) { if (inOldjson(k) && !(k in json)) actions[k] = 'remove'; else if (!inOldjson(k) && (k in json)) actions[k] = 'add'; else if (!inOldjson(k) && !(k in json)) { if (k in actions) delete actions[k]; }						else if (oldjson[k].name === json[k].name && oldjson[k].title === json[k].title && oldjson[k].text === json[k].text) { if (k in actions) delete actions[k]; if (k in oldjson) delete oldjson[k]; }						else actions[k] = 'modify'; }				}				function revertAction { var key = $(this).attr("data-value"); if (key in oldjson) { json[key] = {}; Object.assign(json[key], oldjson[key]); delete oldjson[key]; }					else if (key in json) delete json[key]; actions[key] = 'revert'; updateActions; if ($('#TooltipsEditor-searchInput').val.trim !== "") $('#TooltipsEditor-searchInput').keyup; }				if (keys) { if (typeof(keys) === "string") { updateOne(keys); }					else { for (var i = 0; i < keys.length; i++) { var k = keys[i]; updateOne(k); }					}				}				var $log = $("#TooltipsEditor-actionLog"); var len = Object.keys(actions).length; var ls = ],[],[],[; $log.empty; $log.append($('', {text: len ? "Unsaved changes: " : "No changes were made", "class": "actions-none"})); if (len) { Object.keys(actions).sort.forEach(function(k) {						if (actions[k] === "add") {							ls[0].push($('', {							html: [								"Added "+k,								$('', { text: "undo", "class": "actions-undo-button", "data-value": k }).on("click", revertAction),								$(' ', { 'class': "actions-preview-button minetip", text: "preview (current)", 'data-minetip-text': json[k] && json[k].text && json[k].text.replaceAll('&amp;', '&'), 'data-minetip-title': json[k] && json[k].title && json[k].title.replaceAll('&amp;', '&'), })							],							"class": "actions-add"							}));						}						else if (actions[k] === "modify") {							ls[1].push($('', {							html: [								"Modified "+k,								$('', { text: "undo", "class": "actions-undo-button", "data-value": k }).on("click", revertAction),								$(' ', { 'class': "actions-preview-button minetip", text: "preview (undo)", 'data-minetip-text': oldjson[k] && oldjson[k].text && oldjson[k].text.replaceAll('&amp;', '&'), 'data-minetip-title': oldjson[k] && oldjson[k].title && oldjson[k].title.replaceAll('&amp;', '&'), }),								$(' ', {									'class': "actions-preview-button minetip", text: "preview (current)", 'data-minetip-text': json[k] && json[k].text && json[k].text.replaceAll('&amp;', '&'), 'data-minetip-title': json[k] && json[k].title && json[k].title.replaceAll('&amp;', '&'), })							],							"class": "actions-modify"							}));						}						else if (actions[k] === "remove") {							ls[2].push($('', {							html: [								"Removed "+k,								$('', { text: "undo", "class": "actions-undo-button", "data-value": k }).on("click", revertAction),								$(' ', { 'class': "actions-preview-button minetip", text: "preview (undo)", 'data-minetip-text': oldjson[k] && oldjson[k].text && oldjson[k].text.replaceAll('&amp;', '&'), 'data-minetip-title': oldjson[k] && oldjson[k].title && oldjson[k].title.replaceAll('&amp;', '&'), })							],							"class": "actions-remove"							}));						}						else if (actions[k] === "revert") {							delete actions[k];							ls[3].push($(' ', {								text: "Undo successful for item: "+k,								"class": "actions-revert",								"data-value": k							}).fadeOut(3500, function {							}));						}					}); }				$log.append(ls[0]); $log.append(ls[1]); $log.append(ls[2]); $log.append($('', {text: "Saving changes will also sort all Tooltips in alphabetical order.", "class": "actions-none"})); $("#TooltipsEditor-undoLog").append(ls[3]); //.prepend(ls[3]) $("#TooltipsEditor-totalTooltips").html($(' ', { html: [ "Tooltips Count: "+Object.keys(json).length, $(' ', (function { var diff = Object.keys(json).length - oldjsonkeys.length; if (diff < 0) { return { text: "("+diff+")", css: {color: "red"} }; }							else if (diff > 0) { return { text: "(+"+diff+")", css: {color: "lime"} }; }							else { return { text: "(0)", css: {color: "gray"} }; }						})),					],					css: {float: "right"}, }));			}			ace.define('ace/mode/minecraft-tooltips', [], function(require, exports) {				var oop = require("../lib/oop");				var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;				var colorRules = {};				function onMatch(str) {					var match = this.splitRegex.exec(str);					var values = match.slice(1);					values.push(match[0]);					var types = this.token.apply(this, values);					if (typeof types === "string")						return [{							type: types,							value: str						}];					var tokens = [];					for (var i = 0, l = types.length; i < l; i++) {						if (values[i])							tokens[tokens.length] = {								type: types[i],								value: values[i]							};					}					return tokens;				}				var conversions = {					'l': 'bold',					'm': 'strikethrough',					'n': 'underline',					'o': 'italic',				};				var escapes = {					regex: /\\(ench?a?n?t?m?e?n?t?|ra?r?i?t?y?|poti?o?n|sta?t?)\{(?: .+?)\}|\\(?:[rntvb]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{1,4}|u\{[0-9a-fA-F]{1,6}\}|[0-2][0-7]{0,2}|3[0-7][0-7]?|[4-7][0-7].)/, token: 'backescape.code', };				'0123456789abcdef'.split("").forEach(function(code) {					this['color-' + code] = {						formats: [],						rules: [{							token: function(code) {								this.nextCode = code;								return 'escape.format.code.color';							},							regex: /&([0-9a-f])/,							next: function {								return "color-" + this.nextCode;							},							onMatch: onMatch,						}, {							regex: /&([l-o])/,							token: function(code) {								this.formats.push(conversions[code]);								return 'escape.format.code.text';							},						}, {							token: "language.escape.format.code",							regex: /&r/,							next: "start",						}, escapes, {							regex: /[^\0]/,							token: function {								var ret = "format.color.format-" + code + '.code';								this.formats.forEach(function(code) { ret += '.format_' + code; });								return ret;							},						}],					};					var data = this['color-' + code];					data.rules[0].token = data.rules[0].token.bind(data);					data.rules[0].next = data.rules[0].next.bind(data);					data.rules[1].token = data.rules[1].token.bind(data);					data.rules[4].token = data.rules[4].token.bind(data);				}, colorRules); var MinecraftHighlightRules = function { var formats = []; this.$rules = { start: [{ regex: /&([0-9a-f])/, token: function(code) { this.nextCode = code; colorRules['color-' + code].formats = []; return 'escape.format.code.color'; },							next: function { return "color-" + this.nextCode; },							onMatch: onMatch, }, {							regex: "&r", token: function { formats = []; return 'escape.format.code.color'; },						}, escapes, { regex: /&([l-o])/, token: function(code) { formats.push(conversions[code]); return 'escape.format.code.color'; },						}, {							regex: /[^\0]/, token: function { var ret = "text.formatted"; formats.forEach(function(code) {									ret += '.format_' + code;								}); return ret; },						}],					};					for (var prefix in colorRules) { if (colorRules.hasOwnProperty(prefix)) { var data = colorRules[prefix]; this.$rules[prefix] = data.rules; }					}					this.normalizeRules; };				oop.inherits(MinecraftHighlightRules, TextHighlightRules); exports.MinecraftHighlightRules = MinecraftHighlightRules; });			var colorConversions = {				0: "black",				1: "dark_blue",				2: "dark_green",				3: "dark_aqua",				4: "dark_red",				5: "dark_purple",				6: "gold",				7: "gray",				8: "dark_gray",				9: "blue",				a: "green",				b: "aqua",				c: "red",				d: "light_purple",				e: "yellow",				f: "white",				l: "bold",				n: "underline",				m: "strikethrough",				o: "italic",				r: "reset",			};			var rarityConversions = {				"Common": "f",				"Uncommon": "a",				"Rare": "9",				"Epic": "5",				"Legendary": "6",				"Mythic": "d",				"Supreme": "4",				"Special": "c",				"Very Special": "c",			};			var shortForm = {				"Common": "C",				"Uncommon": "U",				"Rare": "R",				"Epic": "E",				"Legendary": "L",				"Mythic": "M",				"Supreme": "SE",				"Special": "SL",				"Very Special": "VSL",			};			var chars = ('❤ ❈ ❁ ✦ ☣ ☠ ✎ ∞ ✯ ♣ ❂ ⚔ ⫽ α ✹ ⸕ ☘ 🗲 ❣ ⚚ ⸎ ʬ')				.replaceAll(" ", "  ")				.split(" ") .map(function(v) {					if (!v.match(' ')) {						return $('', { 'class': "TooltipsEditor-insertChar", text: v,							title: 'Insert "' + v + '"', });					} else {						return v;					}				}); function generateSearch { $('#searchResultsMessage').css({ display: "" }); var $this = $("#TooltipsEditor-searchInput"); var $results = $("#TooltipsEditor-searchResults"); var val = $this.val; var abort = false; if (val.trim === "") return $results.html(' Enter a search term to start searching. '); var names = Object.keys(json).sort; var results = searchArray(names, val); if (results.length > 100) { results.length = 100; abort = true; }				$results.empty; results.forEach(function(v) {					$results[0].appendChild($('', {						html: [							$('', { href: mw.util.getUrl(v), title: v,								text: v,								target: "_blank" }),							' (',							 $('', {								'class': "TooltipsEditor-editTooltip",								text: "edit",								'data-tooltipTitle': json[v] && json[v].title && json[v].title.replaceAll('&amp;', '&'),								'data-tooltipText': json[v] && json[v].text && json[v].text.replaceAll('&amp;', '&'),								'data-tooltipLink': json[v] && json[v].name && json[v].name.replaceAll('&amp;', '&'),								'data-tooltipKey': v.replaceAll('&amp;', '&')							}), " &bull; ", $(' ', {								'class': "TooltipsEditor-previewTooltip minetip", 								text: "preview",								'data-minetip-text': json[v] && json[v].text && json[v].text.replaceAll('&amp;', '&'),								'data-minetip-title': json[v] && json[v].title && json[v].title.replaceAll('&amp;', '&'), 							}), " &bull; ", $('', {								'class': "TooltipsEditor-removeTooltip", 								text: "remove",								'data-key': v.replaceAll('&amp;', '&'), 							}), ')',						],					})[0]);				});				if (!results.length) return $results.html(' No tooltip matched your search. '); else if (abort) $results.append(' Showing the first 100 results. '); else $results.append(' Total: '+results.length+(results.length > 1 && " results" || " result" )+'. '); }			function processColors { return Object.keys(colorConversions) .map(function(v, i, a) {						return $('', { 'class': "TooltipsEditor-insertFormat" + ((i === a.length-1) && " TooltipsEditor-last" || ""), text: colorConversions[v].replaceAll('_', ' ').replaceAll(/(\w)(\w*)/g, function(_, $1, $2) { 								return $1.toUpperCase + $2;							}), 'data-insert': '&' + v,						});					}); }			function processRarityTexts { return Object.keys(rarityConversions) .map(function(v, i, a) {						return $(' ', { html: [ $('', {									'class': "TooltipsEditor-insertFormat",									text: v,									'data-insert': '&l&' + rarityConversions[v] + v.toUpperCase,									style: "font-style: italic;",								}), $('', {									'class': "TooltipsEditor-insertFormat" + ((i === a.length-1) && " TooltipsEditor-last" || ""),									text: shortForm[v],									'data-insert': '&' + rarityConversions[v],									style: "font-style: italic;",								}), ]						});					});			}			editor.append(				$(' ', { id: "TooltipsEditor-search", html: [ $(' ', { id: "TooltipsEditor-totalTooltips" }), ' Tooltips Editor Main Page ', 'Search Existing Tooltip: ', $(' ', {							id: "TooltipsEditor-searchInput",							keyup: generateSearch,						}), ' or ', $(' ', {							"class": "oo-ui-buttonElement",							html: [								$(" ", { id: "TooltipsEditor-addNew", "class": "oo-ui-buttonElement-button", text: "Add New Tooltip", click: function { openEditor; },								})							]						}),						' ',						$('<ul>', {							id: "TooltipsEditor-actionLog",							css: {								'list-style-type': 'none',								'margin-left': "10px",							},						}), $(' ', {							id: "TooltipsEditor-undoLog"						}), ' ',						$('<b>', { text: 'Search Results: ', id: "searchResultsMessage", style: "display: none;" }), $('<ul>', {							id: "TooltipsEditor-searchResults",							css: {								'list-style-type': 'square',								'margin-left': "10px",							},						}), $(" ", {							css: {"font-style": "italic", float: "right", "margin-bottom": "1em"},							html: [								"(", $('<a>', {									href: mw.util.getUrl("MediaWiki:Gadget-TooltipsEditor.js"),									text: "View JavaScript",									target: "_blank"								}), ")"								]						}),					]				}),				$(' ', {					id: "TooltipsEditor-editor", style: "display: none;", html: [ 'This editor uses minecraft formatting codes (',						$('<a>', { href: "https://minecraft.gamepedia.com/Formatting codes", text: "more info", title: "https://minecraft.gamepedia.com/Formatting codes", }),						') and the template ', $(' ', {							html: [								'', 							],						}), 'for extra formatting. See the template\'s documentation for more info.', ' ',						$(' ', {							html: [								$(' ', { text: "Toolbox (Click to Insert)", css: {"font-weight": "bold", "font-size": "16px"}}),								$(' ', { html: [ "Formatting", $(' ', { id: "TooltipsEditor-insertFormat", html: processColors, "class": "noselect" }), ' ',										"Special Character", $(' ', { id: "TooltipsEditor-insertChar", html: chars, "class": "noselect" }), ' ',										"Rarity Text/Color", $(' ', { id: "TooltipsEditor-insertFormat", html: processRarityTexts, "class": "noselect" }), ],								}),							],						}),' ',						$('<b>', { text: 'Tooltip ID: ' }), $(' ', { css: { width: "400px", position: "relative", left: "3.6em" }, id: "TooltipsEditor-key" }), ' ',						$('<b>', { text: 'Tooltip Link: ' }), $(' ', { css: { width: "400px", position: "relative", left: "2.5em" }, id: "TooltipsEditor-link" }), ' ',' ',						$('<b>', { text: 'Tooltip Title: ' }), $(' ', {							id: "TooltipsEditor-title-AceEditor",							css: {								height: "20px",								'min-width': '600px',								'max-width': '1000px',								'font-size': '14px',								'line-height': '18px',								'border': '1px solid #474747',							}						}), $('<b>', { text: 'Tooltip Text: ' }), $(' ', {							id: "TooltipsEditor-text-AceEditor",							css: {								'font-size': '14px',								'line-height': '18px',								'min-height': '200px',								'max-height': '400px',								'min-width': '600px',								'max-width': '1000px',								'border': '1px solid #474747',							}						}), ]				})			);			$(".TooltipsEditor-insertFormat:not('.TooltipsEditor-last')").after($(" ", { text: " • ", }));			editor.removeClass('mw-ajax-loader'); updateActions; var lastFocusedEditor, lastFocusedElement; function updatePreview { $('#TooltipsEditor-preview').attr({					'data-minetip-text': replaceLines(ace.tooltipsTextEditor.getValue),					'data-minetip-title': ace.tooltipsTitleEditor.getValue,				}); }			function insertText(text) { var editor = lastFocusedEditor; if (!editor && lastFocusedElement) { return lastFocusedElement.textSelection('encapsulateSelection', {						pre: text,			           peri: '',		        	}), true; }				editor.insert(text, 1); return true; }			function setupEditor(id) { var aceEditor = ace.edit(id); var mode = new (ace.require("ace/mode/javascript").Mode); mode.HighlightRules = ace.require('ace/mode/minecraft-tooltips').MinecraftHighlightRules; aceEditor.session.setMode(mode); if (id === "TooltipsEditor-text-AceEditor") { aceEditor.setOptions({						wrapBehavioursEnabled: true,						wrap: true,					}); aceEditor.session.on('change', function {						var height = aceEditor.session.getScreenLength							* aceEditor.renderer.lineHeight							+ aceEditor.renderer.scrollBar.getWidth + 'px';						$(id).css({ height: height });						aceEditor.resize;						if (aceEditor.session.getScreenWidth > 1000) {							$(id).css({ width: '1000px' });						}					}); }				aceEditor.session.on('change', updatePreview); aceEditor.on('focus', function {					lastFocusedEditor = aceEditor;				}); return aceEditor; }			$("#TooltipsEditor-key, #TooltipsEditor-link").focus(function {				lastFocusedElement = $(this);				lastFocusedEditor = null;			}); $('.TooltipsEditor-insertFormat').click(function {				var $this = $(this);				var insert = $this.attr('data-insert');				if (lastFocusedEditor) {					var editor = lastFocusedEditor;					var selection = editor.selection;					if (!selection.ranges.length) {						editor.insert(insert);					} else {						selection.ranges.forEach(function(range) { editor.session.insert({ 								row: range.start.row, 								column: range.start.column 							}, insert); });					}					lastFocusedEditor.focus;				}				else lastFocusedElement.focus;			}); window.ace.tooltipsTextEditor = setupEditor("TooltipsEditor-text-AceEditor"); window.ace.tooltipsTitleEditor = setupEditor("TooltipsEditor-title-AceEditor"); function openEditor(text, title, link, key) { // jshint ignore: line isInMain = false; var oldKey = key; $("#TooltipsEditor-search").css({ display: "none" }); $('#TooltipsEditor-editor').css({ display: "" }); ace.tooltipsTextEditor.resize; ace.tooltipsTitleEditor.resize; ace.tooltipsTextEditor.setValue(convertSlashes(text || "")); ace.tooltipsTitleEditor.setValue(title || ""); $("#TooltipsEditor-link").val(link) || ""; $("#TooltipsEditor-key").val(key || ""); $('.qdmodal-button').css({ display: "none" }); $('#TooltipsEditor-save, #TooltipsEditor-preview, #TooltipsEditor-cancel').remove; var $button1 = $(' ', {						"class": "oo-ui-buttonElement",					}).append(						$(' ', { id: "TooltipsEditor-save", text: "Save", "class": "oo-ui-buttonElement-button", click: function { var text = ace.tooltipsTextEditor.getValue, title = ace.tooltipsTitleEditor.getValue, key = $("#TooltipsEditor-key").val, link = $("#TooltipsEditor-link").val; throwOldjson(oldKey); throwOldjson(key); if (!key) return alert("You need to enter a tooltip ID!"); if (!link) return alert("You need to enter the tooltip's link!"); if (oldKey) delete json[oldKey]; editor.addClass('mw-ajax-loader'); $('.qdmodal-button').css({ display: "" }); $('#TooltipsEditor-editor, #searchResultsMessage').css({ display: "none" }); api.post({ 									action: "parse", 									contentmodel: "wikitext",									text: "",								}).then(function(data) {									json[key] = {										text: text ? $(data.parse.text["*"])											.find('p')											.html											.trim											.replace(/&amp;/g, '&') : undefined,										title: title.trim,										name: link.trim,									};									isInMain = true;									data = json;									updateActions([oldKey, key]);									reset(true);								}); },						})					);				var $button2 = $(' ', {						"class": "oo-ui-buttonElement",					}).append(						$(' ', { id: "TooltipsEditor-cancel", text: "Cancel", "class": "oo-ui-buttonElement-button", click: function { reset(confirm('Go back to main page without saving?')); },						})					);				var $button3 = $(' ', {						"class": "oo-ui-buttonElement",						css: {'float': 'right'},					}).append(						$(' ', { id: "TooltipsEditor-preview", 'class': "minetip oo-ui-buttonElement-button", text: "Preview", })					);				$('#TooltipsEditor-editor').append(					$button1,					$button2,					$button3				); updatePreview; }			$(document.body).on('click', '.TooltipsEditor-insertChar', function(e) {				e.preventDefault;				e.stopImmediatePropagation;				if (lastFocusedEditor) {					insertText($(this).attr('data-insert') || $(this).text);					lastFocusedEditor.focus;				}				else lastFocusedElement.focus;			}); $(document.body).on('click', '.TooltipsEditor-removeTooltip', function {				var $this = $(this);				var key = $this.attr('data-key');       		throwOldjson(key);				delete json[key];				updateActions(key);				$('#TooltipsEditor-searchInput').keyup;			}); $(document.body).on('click', '.TooltipsEditor-editTooltip', function {				var $this = $(this);
 * 1) minetip-tooltip {\
 * 1) TooltipsEditor {\
 * 1) TooltipsEditor .oo-ui-buttonElement-button {\
 * 1) TooltipsEditor-save {\
 * 1) TooltipsEditor-cancel {\
 * 1) TooltipsEditor-preview {\
 * 1) TooltipsEditor-actionLog li, .actions-revert {\
 * 1) TooltipsEditor-totalTooltips p {\
 * 1) TooltipsEditor-totalTooltips p span {\

openEditor(					$this.attr('data-tooltipText'), 					$this.attr('data-tooltipTitle'), 					$this.attr('data-tooltipLink'),					$this.attr('data-tooltipKey')				); });		}, function(code, e) {			return alert('Failed to parse Tooltips: ', e), console.warn('Failed to parse Tooltips: ', e);		}).catch(console.warn); }	$('.editTooltips').click(function {		api.get({ action: "query", format: "json", prop: "revisions", titles: mw.config.get('wgPageName'), formatversion: 2, rvprop: "content", rvslots: "*" }).then(function(d) { var content = d.query.pages[0].revisions[0].slots.main.content; actions = []; onClick(content); });	}); }).catch(console.warn);