User:Nardog/CodeEditorAssist.js

mw.loader.using([	'user.options', 'ext.visualEditor.desktopArticleTarget.init' ], function codeEditorAssist {	let isEdit = mw.config.exists('wgCodeEditorCurrentLanguage') &&		['edit', 'submit'].includes(mw.config.get('wgAction'));	let veAvailable = mw.libs.ve.isVisualAvailable;	let isAf = mw.config.exists('aceConfig');	if (!isEdit && !veAvailable && !isAf) return;	let context, curEditor, defSettingsMap = new WeakMap;	let getSettings = (editor, isDef) => {		let settings = {};		let defSettings = !isDef && defSettingsMap.get(editor);		Object.entries(editor.getOptions).forEach(([k, v]) => { if (v === undefined) { v = null; }			if (isDef || v !== defSettings[k] ||				k === 'showInvisibles' || k === 'wrap'			) { settings[k] = v;			} });		delete settings.mode;		delete settings.readOnly;		delete settings.maxLines;		delete settings.minLines;		delete settings.firstLineNumber;		if (isDef) {			settings.showInvisibles = false;			settings.wrap = 'off';		}		return settings;	};	let updateToolbar = => {		if (!context) return;		let names = [];		if (curEditor.getShowInvisibles !== context.showInvisibleChars) {			names.push('invisibleChars');		}		if (curEditor.session.getUseWrapMode !== context.lineWrappingActive) {			names.push('lineWrapping');		}		names.forEach(name => { context.modules.toolbar.$toolbar.find(`.tool[rel="${name}"]`) .data('action').execute(context); });	};	let saveRemoveHandler = function (e) {		this.disabled = true;		let change = 'userjs-codeeditorassist-settings';		let value;		if (!e.data) {			value = JSON.stringify(getSettings(curEditor));			change += '=' + value;		}		mw.loader.using('mediawiki.api').then( => (			new mw.Api.postWithEditToken({ action: 'globalpreferences', change: change })		)).always(response => { this.disabled = false; if (!response || response.globalpreferences !== 'success') { mw.notify(					e.data						? `Couldn't remove settings from your global preferences`						: `Couldn't save settings to your global preferences`,					{ type: 'error' }				); return; }			if (e.data) { delete mw.user.options.values['userjs-codeeditorassist-settings']; mw.notify('Removed settings from your global preferences'); } else { mw.user.options.set('userjs-codeeditorassist-settings', value); mw.notify('Saved settings to your global preferences'); }		});	};	let observing;	let addButtons = => {		if (observing) return;		observing = true;		let $buttons = $(' ').addClass('floatright').append( $(' ').text('Save').on('click', saveRemoveHandler), ' ',			$(' ').text('Remove').on('click', true, saveRemoveHandler), ' ',			$(' ').text('Reset').on('click', => {				curEditor.setOptions(defSettingsMap.get(curEditor));				$('#ace_settingsmenu').parent[0].click;				curEditor.execCommand('showSettingsMenu');			}) );		new MutationObserver( => { $buttons.appendTo('#ace_settingsmenu > table > tr:last-child > td'); updateToolbar; }).observe(document.body, { childList: true });	};	let onFocus = (e, editor) => {		curEditor = editor;	};	let initialize = editor => {		if (!window.ace) return;		if (!(editor instanceof ace.Editor)) {			if (context) {				editor = context.codeEditor;			} else {				let el = document.querySelector('.ace_editor');				if (!el) return;				editor = ace.edit(el);			}		}		if (defSettingsMap.has(editor)) return;		curEditor = editor;		defSettingsMap.set(editor, getSettings(editor, true));		let savedSettings = mw.user.options.get('userjs-codeeditorassist-settings');		if (savedSettings) {			savedSettings = JSON.parse(savedSettings);			editor.setOptions(savedSettings);			updateToolbar;		}		editor.on('focus', onFocus);		addButtons;	};	if (isAf) {		$.when($.ready, mw.loader.using('ext.abuseFilter.ace')).then(initialize);		return;	}	if (veAvailable) {		mw.hook('ve.loadModules').add(addPlugin => { addPlugin( => {				let setupEditor = ve.ui.MWAceEditorWidget.prototype.setupEditor;				ve.ui.MWAceEditorWidget.prototype.setupEditor = function {					setupEditor.apply(this, arguments);					initialize(this.editor);				};			}); });	}	if (!isEdit) return;	mw.loader.load('oojs-ui.styles.icons-interactions');	mw.hook('codeEditor.configure').add(initialize);	let promise = new Promise(resolve => { mw.hook('codeEditor.configure').add(resolve); });	mw.hook('wikiEditor.toolbarReady').add($textarea => { context = $textarea.data('wikiEditorContext'); promise.then( => {			$textarea.wikiEditor('addToToolbar', { section: 'main', group: 'codeeditor-style', tools: { settings: { label: 'Open code editor settings', type: 'button', oouiIcon: 'settings', action: { type: 'callback', execute: => { curEditor.execCommand('showSettingsMenu'); }						}					}				}			});		});	}); });