MediaWiki:Gadget-MarkupFormatting.js

From Yugipedia
Jump to: navigation, search

Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: hold down Ctrl and click the Refresh or Reload button. Firefox: hold down ⇧ Shift while clicking Reload (or press Ctrl+⇧ Shift+R). Google Chrome and Safari users can just click the Reload button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

/**
 * Prettifies template transclusions and gallery tags.
 * Original author is Deltaneos.
 * Adapted to gadget by Becasita.
 * Further improvements by Dinoguy1000.
 * @author Deltaneos, Becasita, Dinoguy1000
 * @contact [[User:Becasita]] <https://yugipedia.com/wiki/User:Becasita>
 * @contact [[User:Dinoguy1000]] <https://yugipedia.com/wiki/User:Dinoguy1000>
 */
( function _gadgetMarkupFormatting( window, $, mw, console ) {
	"use strict";

	var LAST_LOG = '13:11, 17 February 2024 (UTC)';

	/**
	 * By Deltaneos
	 */
	function align( text ) {
		// Get the selected text or all text
		var selected_text = (window.getSelection().toString()) ? window.getSelection().toString() : text;
		var cleaned_text, pos, max_pos = -1, j;

		// Normalize whitespace and put each line in an array
		var lines = selected_text
						// paranoia
						.replace(/\r\n/g, '\n')
						// collapse multiple newlines
						// "[^\S\n]" selects all whitespace but newlines <https://stackoverflow.com/a/3469155>
						.replace(/(?:\n[^\S\n]*){3,}/g, '\n\n')
						// replace all non-newline whitespace characters (except the ideographic space) with U+0020 spaces
						.replace(/[^\S\n \u3000]/g, ' ')
						// collapse multiple spaces
						.replace(/  +/g, ' ')
						// remove spaces from the ends of lines
						.replace(/ +$/gm, '')
						// normalize whitespace within template parameter lines
						.replace(/^ ?\| ?([^=\n]+?) ?= ?([^\}])/gm, '| $1 = $2')
						// split by line
						.split('\n');

		// Loop through each line to find the furthest out "=".
		for (var i = 0; i < lines.length; i++)
		{
			pos = lines[i].startsWith('|') ? lines[i].indexOf(' = ') : -1;
			if (pos > max_pos) { max_pos = pos; }
		}

		// Loop through each line again
		for (i = 0; i < lines.length; i++)
		{
			// Only touch lines that start with a pipe and have an equals sign (but not {{=}})
			if (lines[i].startsWith('|') && lines[i].indexOf(' = ') > 0)
			{
				// Get the number of spaces to add
				pos  = lines[i].indexOf(' = ');
				lines[i] = lines[i].substring(0, pos) + ' '.repeat(max_pos - pos) + lines[i].substring(pos);
			}
		}

		cleaned_text = lines.join('\n');

		// Check for gallery tags
		if (cleaned_text.indexOf('<gallery') > -1)
		{
			// Get the text inside each set of gallery tags
			var galleries = cleaned_text.match(/<gallery[^>]*>(\n[^<][^\n]*)+\n<\/gallery>/g);
			var gallery_lines;

			for (i = 0; i < galleries.length; i++)
			{
				// Reset max_pos from previous iterations
				max_pos = -1;

				// Reduce the spacing around the "|" in each line to a single space.
				// Put each line in an array.
				gallery_lines = galleries[i].replace(/^([^\|]+?) ?\| ?/gm, '$1 \| ').split('\n');

				// Loop through each line to find the furthest out "|"
				for (j = 0; j < gallery_lines.length; j++)
				{
					pos = gallery_lines[j].indexOf('|');
					if (pos > max_pos) { max_pos = pos; }
				}

				// Check if this gallery needs aligned (some galleries may not have anything but filenames)
				if (max_pos > -1)
				{
					// Loop through each line again
					for (j = 0; j < gallery_lines.length; j++)
					{
						if (gallery_lines[j].indexOf('|') > 0) {
							// Get the amount of space to add
							pos  = gallery_lines[j].indexOf('|');
							gallery_lines[j] = gallery_lines[j].substring(0, pos) + ' '.repeat(max_pos - pos) + gallery_lines[j].substring(pos);
						}
					}
				}

				cleaned_text = cleaned_text.replace(galleries[i], gallery_lines.join('\n'));
			}
		}

		// Final changes
		cleaned_text = cleaned_text
								// add space between list markup and list item content
								.replace(/^ ?([*#:;]+) ?/gm, '$1 ')
								// fix [[wikipedia:MOS:LISTGAP]] issues
								.replace(/^([*#:;][^\n]+)\n+(?=[*#:;])/gm, '$1\n')
								// add space around header content
								.replace(/^(=+) ?(.+?) ?\1$/gm, '$1 $2 $1')
								// ensure each header is preceded by an empty line
								.replace(/\n+((=+) .* \2)/gm, '\n\n$1')
								// ensure each header is followed by content on the next line
								.replace(/^((=+) .* \2)\n+/gm, '$1\n');

		// Replace the old text with the new text
		return text.replace(selected_text, cleaned_text);
	}

	function doAlign( $textBox ) {
		$textBox.val( function( index, text ) {
			return align( text );
		} );
	}

	function init() {
		var $editBox = $( '#wpTextbox1' );

		if ( !$editBox.length ) {
			window.MARKUP_FORMATTING_ONKEYDOWN_SET = function() {
				// Nothing, just to prevent errors.
			};

			return;
		}

		var $button = $( '<span>', {
			id: 'ca-alignText',
			'class': 'tab',
			html: $( '<a>', {
				href: '#',
				title: 'Align text.',
				text: 'Align text',
			} ),
			click: function( e ) {
				e.preventDefault();

				doAlign( $editBox );
			},
		} );

		if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) {
			// Enhanced edit toolbar:
			$( '#wikiEditor-ui-toolbar' )
				.find( '.tabs' )
					.append( $button )
			;
		} else {
			// Classic toolbar:
			$( '#toolbar' ).append(
				$( '<div>' )
					.addClass( 'mw-toolbar-editbutton' )
					.addClass( 'mw-toolbar-editbutton--custom' )
					.append( $button )
			);
		}

		/**
		 * To add a keyboard shortcut, add the following to Special:MyPage/common.js
		 * ```
		 *	mw.loader.using( 'ext.gadget.MarkupFormatting' ).then( function() {
		 *		window.MARKUP_FORMATTING_ONKEYDOWN_SET( function( e ) {
		 *			return // predicate.
		 *		} );
		 *	} );
		 * ```
		 * @param {function} keysPredicate Callback that receives
		 * an onKeydown event and returns a boolean indicating
		 * when the keydown listeners should be triggered.
		 */
		window.MARKUP_FORMATTING_ONKEYDOWN_SET = function( keysPredicate ) {
			$editBox.keydown( function( e ) {
				if ( keysPredicate( e ) ) {
					doAlign( $editBox );
				}
			} );
		};
	}

	mw.hook( 'wikipage.editform' ).add( function() {
		if( mw.config.get('wgNamespaceNumber') !== 10) {
			mw.loader.using( 'mediawiki.toolbar' ).then( init );
		}
	} );

	console.log( '[Gadget] MarkupFormatting last updated at', LAST_LOG );

} )( window, window.jQuery, window.mediaWiki, window.console );