Jump to content

User:SD0001/text-reactions.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by SD0001 (talk | contribs) at 14:04, 1 December 2021. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
(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)
	 * - 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.
	 *
	 * TODO:
	 * - a way to "listen" to new refs added.
	 *
	 */
	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"');
			}
		},
		{
			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);
						}
					});
				}
			},
		},
		{
			name: 'unreliableSourceWarning',
			trigger: 'interval',
			interval: 5000,
			react: function (wikitext) {

			}
		}
	];


	$.when(
		$.ready,
		mw.loader.using([ 'mediawiki.util', 'mediawiki.api', 'mediawiki.user', 'jquery.textSelection', 'es6-polyfills' ])
	).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 wordReactionsMap = {};
		var keyReactionsMap = {};

		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);
			}
		});

		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);
					});
				}
			}
		};

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

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

	});

})();