User:SD0001/text-reactions.js

//

(function {	console.log('Running text-reactions.');

var $textarea, api;

/**	 * List of reactions. Each reaction object contains: * - name * - trigger * 		'keypress' (triggered by keyup in the textarea) * 		'word' 	(triggered by entry of a word) * 		'interval' (triggered at regular interval) * 		'paste' (triggered by text insertion via copy-paste or drag-drop) * 		'ref' (triggered when reference is inserted via RefToolbar	 * - key: (for keypress trigger) key that was pressed	 * - word: (for word trigger) word that was written	 * - interval: (for interval trigger) in milliseconds	 * - react: function that shows the notice/warning if needed.	 *	 */	var textReactions = [		{			name: 'keypress-test',			trigger: 'keypress',			key: 'e',			react: function (text, caretPosition) {				console.log('Hit key "e"');			}		},

{			name: 'word-test', trigger: 'word', word: 'test', react: function (text, caretPosition) { console.log('Hit word "test"'); }		},		{			name: 'paste-test', trigger: 'paste', react: function (pasteContent, wikitext) { console.log('You pasted: ' + pasteContent); }		},		{			name: 'ref-test', trigger: 'ref', react: function (citeTemplate) { var url = citeTemplate.getParam('url'); // check if url is blacklisted/deprecated/predatory journal, etc console.log('You inserted ref: ' + citeTemplate.wikitext); }		},		{			name: 'interval-test', trigger: 'interval', interval: 5000, react: function (wikitext) { console.log('This is triggered every 5 secs'); }		},		{			test: 'dabNotification', trigger: 'keypress', key: ']', react: function (wikitext, cursorPosition) { // Adapted from https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Disambiguator/+/716439 var matches = /.*(\[\[([^[\]|]+)(?:\|.*]]|]]))$/.exec(wikitext.slice(0, cursorPosition)); if (matches) { var pageTitle = matches[matches.length - 1].trim; var linkWikitext = matches[matches.length - 2]; return api.get({						action: 'query',						titles: pageTitle,						prop: 'pageprops',						ppprop: 'disambiguation',					}).then(function (json) {						if (json.query.pages && json.query.pages[0].pageprops && Object.prototype.hasOwnProperty.call(json.query.pages[0].pageprops, 'disambiguation') ) {							console.log('You linked the disambiguation page ' + pageTitle);						}					}); }			},		}	];

$.when(		$.ready,		mw.loader.using([ 'mediawiki.util', 'mediawiki.api', 'mediawiki.user', 'jquery.textSelection', 'ext.gadget.libExtraUtil' ])	).then(function {		if (!['edit', 'submit'].includes(mw.util.getParamValue('action'))) return;

$textarea = $('#wpTextbox1'); if (!$textarea.length) return; // probably VE

api = new mw.Api({			parameters: {				formatversion: 2			}		});

var keyReactionsMap = {}; var wordReactionsMap = {}; var pasteReactions = [];

textReactions.forEach(function (tr) {			if (tr.trigger === 'keypress') {				keyReactionsMap[tr.key] = (keyReactionsMap[tr.key] || []).concat(tr);			} else if (tr.trigger === 'word') {				wordReactionsMap[tr.word] = (wordReactionsMap[tr.word] || []).concat(tr);			} else if (tr.trigger === 'paste') {				pasteReactions.push(tr);			}		});

var WORD_DELIMITERS = [' ', '.', ',', ';']; var WORD_MATCH_REGEX = /\s(\S+)[ .,;]$/;

var keyupHandler = function (e) { (keyReactionsMap[e.key] || []).forEach(function (tr) {				tr.react($textarea.textSelection('getContents'), $textarea.textSelection('getCaretPosition'));			});

if (WORD_DELIMITERS.includes(e.key)) { var content = $textarea.textSelection('getContents'); var caretPosition = $textarea.textSelection('getCaretPosition'); var word = WORD_MATCH_REGEX.exec(content.slice(0, caretPosition))[1]; if (word) { (wordReactionsMap[word] || []).forEach(function (tr) {						tr.react(content, caretPosition);					}); }			}		};

var pasteHandler = function (e) { var wikitext = $textarea.textSelection('getContents'); var pasteData = e.originalEvent.clipboardData || // for paste e.originalEvent.dataTransfer; // for drag-drop var pasteContent = pasteData.getData('text'); pasteReactions.forEach(function (tr) {				tr.react(pasteContent, wikitext);			}); };

// HACK: Hijack WikiEditor method used by RefToolbar to insert ref into the textbox var origFunc = $.wikiEditor.modules.toolbar.fn.doAction; $.wikiEditor.modules.toolbar.fn.doAction = function { // Call the original function var args = Array.prototype.slice.call(arguments); origFunc.apply($.wikiEditor.modules.toolbar.fn, args);

// Now do our thing var ref = args[1] && args[1].options && args[1].options.post; var refContent; try { refContent = $($.parseXML(ref)).find('ref').text; } catch (e) {} if (refContent) { var citeTemplate = extraJs.parseTemplates(refContent)[0]; textReactions.filter(function (tr) {					return tr.trigger === 'ref';				}).forEach(function (tr) {					tr.react(citeTemplate);				}); }		};

// Bind textarea event handlers, with CodeMirror integration $textarea.on('keyup', keyupHandler).on('paste drop', pasteHandler); mw.hook('ext.CodeMirror.switch').add(function (_enabled, $editor) {			$textarea = $editor;			$textarea.off('keyup', keyupHandler).on('keyup', keyupHandler)				.off('paste drop', pasteHandler).on('paste drop', pasteHandler);		});

var intervalReactions = textReactions.filter(function (tr) {			return tr.trigger === 'interval';		}); intervalReactions.forEach(function (tr) {			setInterval(function { tr.react($textarea.textSelection('getContents')); }, tr.interval);		});

});

});

//