User:Mikevoir/betterCodeMirror.js

mw.loader.using('mediawiki.api').then(function {	var lib = this._LIB;	var settings = this.betterCodeMirror || {};	var $textbox = $( '#wpTextbox1' );	var betterCodeMirror = {		config: mw.config.get(['wgAction']),		row: document.querySelector('.group-insert'),		init: function {			if (this.config.wgAction && ['edit', 'submit'].includes(this.config.wgAction)) {				if (!settings.disable || !Array.isArray(settings.disable) || !settings.disable.includes('quickOL'))				{lib.waitFor('.CodeMirror', this.quickOL);}				if (!settings.disable || !Array.isArray(settings.disable) || !settings.disable.includes('templateDataShow'))				{lib.waitFor('.CodeMirror', this.templateDataShow);}			}		},		addButton: function(query, content, handler) {			var addTo = document.querySelector(query);			if (addTo) {				var container = document.createElement('span');				container.classList.add('tool', 'oo-ui-widget', 'oo-ui-widget-enabled', 'oo-ui-buttonElement', 'oo-ui-buttonElement-frameless', 'oo-ui-iconElement', 'oo-ui-buttonWidget'); var button = document.createElement('a'); button.classList.add('oo-ui-buttonElement-button'); button.innerHTML = content; button.role = 'button'; button.addEventListener('mouseup', handler); container.appendChild(button); addTo.insertBefore(container, addTo.children[0]); }		},		quickOL: function { // Add buttons betterCodeMirror.addButton('.group-insert', 'OL_tl', addOL); betterCodeMirror.addButton('.group-insert', 'OL', addOL); // Add call when clicked function addOL(event) { // OL call without TL params if (event.target.innerHTML == 'OL'){ $textbox.textSelection(						'replaceSelection',						''); // OL call with TL params }else if (event.target.innerHTML == 'OL_tl'){ $textbox.textSelection(						'replaceSelection',						''); }			}		},		templateDataShow: function { var $textbox = $textbox || $( '#wpTextbox1' ); var api = api || new mw.Api; var loadedPage; // Load VE-only styling importArticles({			   type: 'css',			    articles: ['u:community:User:Mikevoir/betterCodeMirror.css']			});

var TDSmethods = { init: function(event) { var checkTemplate = /^[\s\S]*\{\{([^\}\{\|]+)(\}\}$|$)/g; var checkParam = /^[\s\S]*\|(\s*[\w\d_\-\s]*\s*)$/g; var uptoCaret = $textbox.textSelection('getSelection'); var customSelect = true; if (uptoCaret.length==0){ uptoCaret = $textbox.textSelection('getContents').substring(0, $textbox.textSelection('getCaretPosition')); customSelect = false; }					if (customSelect || (uptoCaret && checkTemplate.test(uptoCaret))) { var template = (customSelect && uptoCaret) || uptoCaret.replace(checkTemplate, '$1'); var toCheck = $textbox.textSelection('getContents').substring(							$textbox.textSelection('getCaretPosition') -							( (customSelect && (uptoCaret.length + 2)) || (uptoCaret.replace(checkTemplate, '$1$2').length + 2) )						);						this.parseTemplate(toCheck); if (!loadedPage || loadedPage.TEMPLATE !== template){ this.getTD(template, this.renderTD); } else { this.renderTD(loadedPage); }					} else if (uptoCaret && loadedPage && checkParam.test(uptoCaret)) { var raw_str = uptoCaret.replace(checkParam, '$1'); var param = raw_str.trim; var selection; if (param.length>0) { // Sort possible fillups selection = { paramOrder: [], params: {}, format: loadedPage.format, TEMPLATE: loadedPage.TEMPLATE, description: loadedPage.description };							loadedPage.paramOrder.forEach(function(paramName){								if (paramName.toString.indexOf(param) == 0 ) {									selection.paramOrder.push(paramName);									selection.params[paramName] = loadedPage.params[paramName];								} else if (loadedPage.params[paramName].aliases && loadedPage.params[paramName].aliases.length>0) {									loadedPage.params[paramName].aliases.forEach(function(alias){ if (!selection.params[paramName] && alias.indexOf(param) == 0 ) { selection.paramOrder.push(paramName); selection.params[paramName] = loadedPage.params[paramName]; }									});								}							});						} else { selection = loadedPage; } selection.NORECORD = true; // Do not override the saved data this.proofTD(selection, this.renderTD); var paramSelect = function(event){ if (event.target.closest('code') || event.target.nodeName == 'code'){ var selectedParam = event.target.nodeValue || event.target.innerHTML; var spacing = ' = '; var formatRegex = /\{\{/; if (loadedPage.format && loadedPage.format !== 'inline') { var touse = loadedPage.format.replace(/^.*?\|(_+) =.+$/, '$1'); if (touse.length > selectedParam.length) { spacing = ' '.repeat(touse.length-selectedParam.length) + ' = '; }								}								document.removeEventListener('mouseup', paramSelect); document.querySelector('.ve-ui-overlay-global.ve-ui-overlay-global-desktop.ve-ui-overlay').remove; if (raw_str.length>0) { var use_str = raw_str.replace(/^.*\|/, ''); $textbox.textSelection('setSelection', {start:($textbox.textSelection('getCaretPosition')-raw_str.length), end:$textbox.textSelection('getCaretPosition')}); } else { } $textbox.textSelection('replaceSelection', selectedParam + spacing); }						};						document.addEventListener('mouseup', paramSelect); }				},				getTD: function(template, callBack) { var tdRegex = / ([\s\S]+)<\/templatedata>/g; api.get({						action: 'parse',						page: 'Template:'+template+'/doc',						prop: 'wikitext|categories|sections'					}).then(function(data){						if ( data && data.parse && data.parse.wikitext && data.parse.wikitext['*'] && tdRegex.test(data.parse.wikitext['*']) ){							var raw_templateData = data.parse.wikitext['*'].match(tdRegex)[0].replace(' ', ).replace(' ', );							var templateData = JSON.parse(raw_templateData);							templateData.TEMPLATE = template;							TDSmethods.proofTD(templateData, callBack);						}					}); },				proofTD: function(data, callBack) { if (!data.paramOrder && data.params) { data.paramOrder = []; Object.keys(data.params).forEach(function(key) {							data.paramOrder.push(key);						}); }					if (!data.format) {data.format='inline';} callBack(data); },				renderTD: function(data) { if (!data.NORECORD) {loadedPage = data;} var frame = TDSmethods.nestElements(document.querySelector('body'),						[							{								classNames: [ "ve-ui-overlay-global", "ve-ui-overlay-global-desktop", "ve-ui-overlay" ]							},							{								classNames: [ "oo-ui-windowManager", "oo-ui-windowManager-modal", "ve-ui-dir-block-ltr", "oo-ui-windowManager-floating" ],								attributes: {									role: 'dialog'								}							},							{								classNames: [ "oo-ui-window", "oo-ui-dialog", "oo-ui-processDialog", "ve-ui-mwTemplateDialog-ready", "ve-ui-mwTransclusionDialog-single-transclusion", "oo-ui-window-active", "oo-ui-window-setup", "oo-ui-window-ready" ],								attributes: {									role: 'dialog'								}							},							{								classNames: ['oo-ui-window-frame'],								styles: {									width: '900px',									height: '90%'								}							},						]					); //Starting trap TDSmethods.addElement({						addTo: frame,						classNames: ['oo-ui-window-focusTrap'],						attributes: {tabindex: '0'},						noreturn: true					}); var main = TDSmethods.addElement({						addTo: frame,						classNames: [ 'oo-ui-window-content', 'oo-ui-dialog-content', 'oo-ui-processDialog-content', 'oo-ui-window-content-setup', 'oo-ui-window-content-ready' ],						attributes: {tabindex: '-1'}					}); //Ending trap TDSmethods.addElement({						addTo: frame,						classNames: ['oo-ui-window-focusTrap'],						attributes: {tabindex: '0'},						noreturn: true					}); // Head container var head = TDSmethods.nestElements(main, 						[							{ classNames: [ 'oo-ui-window-head' ] },							{ classNames: [ 'oo-ui-processDialog-navigation' ] }						]					); // Head 1 TDSmethods.nestElements(head, 						[							{ 								classNames: [ 'oo-ui-processDialog-location' ],								styles: {									'padding-left': '77.7167px',									'padding-right': '77.7167px'								}							},							{								node: 'label',								classNames: [ 'oo-ui-widget', 'oo-ui-widget-enabled', 'oo-ui-labelElement-label', 'oo-ui-labelWidget', 'oo-ui-processDialog-title', 'oo-ui-labelElement' ],								content: 'Template Data: ' + data.TEMPLATE							}						]					); // Head 2 var head2 = TDSmethods.nestElements(						head,						[							{ classNames: [ 'oo-ui-processDialog-actions-safe' ] },							{								node: 'span',								classNames: [ 'oo-ui-widget', 'oo-ui-widget-enabled', 'oo-ui-buttonElement', 'oo-ui-buttonElement-framed', 'oo-ui-iconElement', 'oo-ui-flaggedElement-safe', 'oo-ui-flaggedElement-close', 'oo-ui-buttonWidget', 'oo-ui-actionWidget' ]							},							{								node: 'a',								classNames: [ 'oo-ui-buttonElement-button' ],								attributes: {									role: 'button',									tabindex: '0',									rel: 'nofollow'								}							}						]					); TDSmethods.addElement({						addTo: head2,						node: 'span',						classNames: [ 'oo-ui-iconElement-icon', 'oo-ui-icon-close' ],						noreturn: true					}); TDSmethods.addElement({						addTo: head2,						node: 'span',						classNames: [ 'oo-ui-labelElement-label', 'oo-ui-labelElement-invisible' ],						content: 'Cancel',						noreturn: true					}); TDSmethods.addElement({						addTo: head2,						node: 'span',						classNames: [ 'oo-ui-indicatorElement-indicator', 'oo-ui-indicatorElement-noIndicator' ],						noreturn: true					}); // Window body var body = TDSmethods.nestElements(						main,						[							{ classNames: [ 'oo-ui-window-body' ], styles: { bottom: '52px' } },							{ classNames: [ 'oo-ui-layout', 'oo-ui-menuLayout', 'oo-ui-menuLayout-before', 'oo-ui-menuLayout-showMenu', 've-ui-mwTwoPaneTransclusionDialogLayout' ] },							{ classNames: [ 'oo-ui-menuLayout-content' ] },							{ classNames: [ 'oo-ui-layout', 'oo-ui-panelLayout', 'oo-ui-panelLayout-scrollable', 'oo-ui-panelLayout-expanded', 've-ui-mwVerticalLayout', 've-ui-mwTwoPaneTransclusionDialogLayout-stackLayout' ] }						]					); // Body title var body_title = TDSmethods.nestElements(						body,						[							{ classNames: [ 'oo-ui-layout', 'oo-ui-panelLayout', 'oo-ui-panelLayout-expanded', 'oo-ui-pageLayout', 've-ui-mwTemplatePage' ] },							{ 								classNames: [ 'oo-ui-layout', 'oo-ui-iconElement', 'oo-ui-labelElement', 'oo-ui-fieldsetLayout' ],								node: 'fieldset',								content: TDSmethods.listElements( null, [										{ 											classNames: [ 'oo-ui-layout', 'oo-ui-iconElement', 'oo-ui-labelElement', 'oo-ui-fieldsetLayout' ], node: 'legend', content: TDSmethods.listElements(null, [												{ classNames: [ 'oo-ui-iconElement-icon', 'oo-ui-icon-puzzle' ], node: 'span' },												{ classNames: [ 'oo-ui-labelElement-label' ], node: 'span', content: data.TEMPLATE },											]) },										{ 											classNames: [ 'oo-ui-fieldsetLayout-group' ], content: data.description || 'No template description.' },										{ 											classNames: [ 've-ui-mwTemplatePage-description' ], content: 'Format: ' + (data.format.replace(/\\/, '\\') || 'inline') },									]								)							},						]					);					data.paramOrder.forEach(function(param){						TDSmethods.addElement({ addTo: body, classNames: [ 'oo-ui-layout', 'oo-ui-panelLayout', 'oo-ui-panelLayout-expanded', 'oo-ui-pageLayout', 've-ui-mwParameterPage' ], content: TDSmethods.parseParam(data.params[param], param) });					});					// Close popup var listenTo = ['mouseup', 'keyup']; var closePopup = function(event) { if (							( event.target.closest('.oo-ui-processDialog-navigation a.oo-ui-buttonElement-button') && (event.type == 'mouseup') )||							(								event.type == 'keyup' && event.key == 'Escape' )						){							// Close popup and remove listeners var el = document.querySelector('.ve-ui-overlay'); if (el){ el.remove; listenTo.forEach(function(type){document.removeEventListener(type, closePopup);}); }						}					};					listenTo.forEach(function(type){document.addEventListener(type, closePopup);}); },				addElement: function(options) { if (!options.node){options.node = 'div';} var newNode; if (options.node !== 'text') { newNode = document.createElement(options.node); if (options.classNames) { options.classNames.forEach(function(className){								if ('string' == typeof className && className.length > 0) {									newNode.classList.add(className);								}							}); }						if (options.styles) { Object.keys(options.styles).forEach(function(key) {								newNode.style[key] = options.styles[key];							}); }						if (options.attributes) { Object.keys(options.attributes).forEach(function(key) {								newNode.setAttribute(key, options.attributes[key]);							}); }						if (Array.isArray(options.content) && options.content.length>0) { options.content.forEach(function(content){								if ('string' == typeof content) {									newNode.appendChild(document.createTextNode(content));								}else if ('object' == typeof content && content.ownerDocument) {									newNode.appendChild(content);								}							}); } else if ('string' == typeof options.content) { newNode.appendChild(document.createTextNode(options.content)); }else if ('object' == typeof options.content && options.content.ownerDocument) { newNode.appendChild(options.content); }					} else { newNode = document.createTextNode(options.content); } if (options.addTo) { options.addTo.appendChild(newNode); }					if (!options.noreturn) { return newNode; }				},				nestElements: function(startNode, optionsArray) { var oldNode = startNode; optionsArray.forEach(function(options){						options.addTo = oldNode;						oldNode = TDSmethods.addElement(options);					}); return oldNode; },				listElements: function(parentNode, optionsArray) { var newNodes = []; optionsArray.forEach(function(options){						if (parentNode) {options.addTo = parentNode;}						var newNode = TDSmethods.addElement(options);						if (!parentNode && newNode) {newNodes.push(newNode);}					}); return parentNode || newNodes; },				parseParam: function(data, param) { var param_names = [{ content: param, node: 'code', classNames: ['ve-ui-mwParameterPage-param'] }]; var param_desc = []; var hr = false; if (data.aliases && data.aliases.length>0) { data.aliases.forEach(function(alias){							param_names.push({ content: alias, node: 'code', classNames: ['ve-ui-mwParameterPage-param'] });						});					}					if (data.description) { if (!hr){param_desc.push({node: 'hr'}); hr=true;} param_desc.push({							content: data.description,							node: 'p'						}); }					if (data.default) { if (!hr){param_desc.push({node: 'hr'}); hr=true;} param_desc.push({							content: 'Default: ' + data.default,							classNames: ['ve-ui-mwParameterPage-doc-default'],							node: 'p'						});} if (data.example) { if (!hr){param_desc.push({node: 'hr'}); hr=true;} param_desc.push({							content: 'Example: ' + data.example,							classNames: ['ve-ui-mwParameterPage-doc-example'],							node: 'p'						}); }					return TDSmethods.listElements(null,						[							{								classNames: [ 've-ui-mwParameterPage-info' ],								content: TDSmethods.addElement({ classNames: [ 've-ui-mwParameterPage-label', 'oo-ui-widget', 'oo-ui-widget-enabled', 'oo-ui-labelElement', 'oo-ui-labelElement-label', 'oo-ui-labelWidget' ], node: 'label', content: data.label || param })							},							{								classNames: [ 've-ui-mwParameterPage-param' ],								content: TDSmethods.listElements(null,param_names)							},							{								classNames: [ 've-ui-mwParameterPage-inlineDescription' ],								content: TDSmethods.listElements(null,param_desc)							},						]					); },				parseTemplate: function(str) { console.log('parse template from: ', str); var nest = 0; var INTEMPLATE; var INPARAM; var template = { name: null, params: [], };					var tempParam = { name: '', value: '' };					var unnamedCount = 0; for (var i = 0; i < str.length; i++) { var char = str.at(i); var Nchar = str.at(i+1); // console.log('char at i="', i, '" is: ', char); if (!INTEMPLATE) { if (char.charCodeAt(0) == 123 && Nchar.charCodeAt(0) == 123) { INTEMPLATE = true; i++; } } else { if (!template.name) { if ( ![124,125].includes(char.charCodeAt(0)) && ![124,125].includes(Nchar.charCodeAt(0))) { tempParam.name = tempParam.name + char; } else if ( ![124,125].includes(char.charCodeAt(0)) && [124,125].includes(Nchar.charCodeAt(0))) { template.name = tempParam.name.trim; tempParam.name = ''; }							} else { // Plain copy nested templates if (nest>0) { if (char.charCodeAt(0) == 123 && Nchar.charCodeAt(0) == 123) { nest++; } else if (char.charCodeAt(0) == 125 && Nchar.charCodeAt(0) == 125) { nest--; } else { tempParam.value = tempParam.value + char; }								} else { // Template end if (char.charCodeAt(0) == 125 && Nchar.charCodeAt(0) == 125) { closeParam; console.log('finished template: ', template); return template; }									// Template param start else if (char.charCodeAt(0) == 124) { closeParam; INPARAM = true; // Special boolean to allow blank unnamed params }									else if (INPARAM && char.charCodeAt(0) == 61 && tempParam.value.length>0 && tempParam.name.length==0) { tempParam.name = tempParam.value.trim; tempParam.value = ''; }									else if (INPARAM && char.charCodeAt(0) == 123 && Nchar.charCodeAt(0) == 123) { tempParam.value = tempParam.value + char + Nchar; nest++; i++; }									// Plain copy html tags else if (INPARAM && char.charCodeAt(0) == 139 && Nchar.match(/[!\w]/)) { var htmlFrom = document.createElement('div'); htmlFrom.innerHTML = str.substring(i); htmlFrom.children.forEach(function(child){											if (child.nodeType == 3) {												if (child.data.match(/^.*?[\|\}]/g)){													return;												} else {													tempParam.value = tempParam.value + child.data;													i = i + child.data.length-1;												}											} else if (child.nodeType == 8) {												tempParam.value = tempParam.value + '';												i = i + child.data.length+6;											} else {												tempParam.value = tempParam.value + child.outerHTML;												i = i + child.outerHTML.length-1;											}										}); }else { tempParam.value = tempParam.value + char; }								}							}						}					}					function closeParam{ if (tempParam.value.length > 0 || INPARAM) { if (tempParam.name.length==0) { unnamedCount++; tempParam.name = tempParam.name+unnamedCount; }							template.params.push({								name: tempParam.name,								value: tempParam.value							}); tempParam = { name: '', value: '' };						}					}				}			};			document.addEventListener('keydown', function(event){				// Run on: left click when (alt key + ctrl + shift)				if (event.ctrlKey && event.altKey){					event.preventDefault;					TDSmethods.init(event);				}			}); },	};

betterCodeMirror.init; });