MediaWiki:Gadget-mediawiki.toolbar.js

Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;

Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.
/**
 * Interface for the classic edit toolbar.
 *
 * Adapted from MediaWiki Core, before it was removed from it on 2018-10-17
 *
 * Dependencies:
 * - jquery.textSelection, used when calling insertTags() (when clicking on a button, or manually called)
 */
( function () {
	'use strict';

	var toolbar, deferred, currentFocused;

	/**
	 * Internal helper that does the actual insertion of the button into the toolbar.
	 *
	 * For backwards-compatibility, passing `imageFile`, `speedTip`, `tagOpen`, `tagClose`,
	 * `sampleText` and `imageId` as separate arguments (in this order) is also supported.
	 *
	 * @private
	 *
	 * @param {Object} button Object with the following properties.
	 *  You are required to provide *either* the `callback` parameter, or the three parameters
	 *  `tagOpen`, `tagClose` and `sampleText`, but not both (they're mutually exclusive).
	 * @param {string} [button.imageFile] Image to use for the button.
	 * @param {string} button.speedTip Tooltip displayed when user mouses over the button.
	 * @param {Function} [button.callback] Function to be executed when the button is clicked.
	 * @param {string} [button.tagOpen]
	 * @param {string} [button.tagClose]
	 * @param {string} [button.sampleText] Alternative to `callback`. `tagOpen`, `tagClose` and
	 *  `sampleText` together provide the markup that should be inserted into page text at
	 *  current cursor position.
	 * @param {string} [button.imageId] `id` attribute of the button HTML element. Can be
	 *  used to define the image with CSS if it's not provided as `imageFile`.
	 * @param {string} [speedTip]
	 * @param {string} [tagOpen]
	 * @param {string} [tagClose]
	 * @param {string} [sampleText]
	 * @param {string} [imageId]
	 */
	function insertButton( button, speedTip, tagOpen, tagClose, sampleText, imageId ) {
		var oldButton, $button;

		// Backwards compatibility
		if ( typeof button !== 'object' ) {
			button = {
				imageFile: button,
				speedTip: speedTip,
				tagOpen: tagOpen,
				tagClose: tagClose,
				sampleText: sampleText,
				imageId: imageId
			};
		}

		if ( button.imageId ) {
			var oldButton = document.getElementById( button.imageId );
			if ( oldButton ) {
				oldButton.parentNode.removeChild( oldButton );
			}
		}

		if ( button.imageFile ) {
			$button = $( '<img>' ).attr( {
				src: button.imageFile,
				alt: button.speedTip,
				title: button.speedTip,
				id: button.imageId || undefined,
				'class': 'mw-toolbar-editbutton'
			} );
		} else {
			$button = $( '<div>' ).attr( {
				title: button.speedTip,
				id: button.imageId || undefined,
				'class': 'mw-toolbar-editbutton'
			} );
		}

		$button.click( function ( e ) {
			e.preventDefault();

			if ( button.callback ) {
				button.callback();
			} else {
				toolbar.insertTags( button.tagOpen, button.tagClose, button.sampleText );
			}
		} );

		getToolbar().append( $button );
	}

	/**
	 * Get the toolbar, lazy-creating it the first time this function is called.
	 *
	 * The result is a jQuery object, that may be empty if toolbar creation failed.
	 *
	 * @private
	 * @return {jQuery}
	 */
	function getToolbar() {
		var $toolbar, textbox;

		if ( !getToolbar.$cache ) {
			$toolbar = $( '#toolbar' );

			if ( !$toolbar.length ) {
				textbox = getTextbox();
				if ( textbox ) {
					$toolbar = $( '<div>' ).attr( 'id', 'toolbar' );

					// Undo #toolbar {height:22px} added by MediaWiki,
					// which causes troubles if the toolbar takes several lines
					$toolbar.css( 'height', 'auto' );

					$toolbar.insertBefore( textbox );
				}
			}

			getToolbar.$cache = $toolbar;
		}

		return getToolbar.$cache;
	}

	/**
	 * Get the wpTextbox1 element, using a cache for performance.
	 *
	 * @private
	 * @return {HTMLTextAreaElement|null}
	 */
	function getTextbox() {
		if ( !getTextbox.cache ) {
			getTextbox.cache = document.getElementById( 'wpTextbox1' );
		}

		return getTextbox.cache;
	}

	/**
	 * @private
	 * @property {jQuery.Deferred}
	 * Deferred object that will be resolved when the toolbar is ready to be populated.
	 */
	deferred = $.Deferred();

	/**
	 * @class mw.toolbar
	 * @singleton
	 */
	toolbar = {

		/**
		 * Add buttons to the toolbar.
		 *
		 * Takes care of race conditions and time-based dependencies by placing buttons in a queue if
		 * this method is called before the toolbar is created.
		 *
		 * For backwards-compatibility, passing `imageFile`, `speedTip`, `tagOpen`, `tagClose`,
		 * `sampleText` and `imageId` as separate arguments (in this order) is also supported.
		 *
		 * @inheritdoc #insertButton
		 */
		addButton: function () {
			var buttonArguments = [].slice.call( arguments );

			deferred.done( function () {
				insertButton.apply( toolbar, buttonArguments );
			} );
		},

		/**
		 * Apply tagOpen/tagClose to selection in currently focused textarea.
		 *
		 * Uses `sampleText` if selection is empty.
		 *
		 * @param {string} tagOpen
		 * @param {string} tagClose
		 * @param {string} sampleText
		 */
		insertTags: function ( tagOpen, tagClose, sampleText ) {
			var target = this.getCurrentFocused();
			if ( !target ) {
				return;
			}
			$( target ).textSelection(
				'encapsulateSelection', {
					pre: tagOpen || '',
					peri: sampleText || '',
					post: tagClose || ''
				}
			);
		},

		/**
		 * Get the element whose selection is to be manipulated.
		 *
		 * @return {HTMLTextAreaElement|HTMLInputElement|null}
		 */
		getCurrentFocused: function () {
			if ( !currentFocused ) {
				currentFocused = getTextbox();
			}

			return currentFocused;
		}
	};

	// Expose API publicly
	mw.toolbar = toolbar;

	$( function ( $ ) {
		deferred.resolve();

		// Apply to dynamically created textboxes as well as normal ones
		$( document ).on( 'focus', 'textarea, input:text, .CodeMirror', function () {
			if ( this.classList.contains( 'CodeMirror' ) ) {
				// CodeMirror hooks into #wpTextbox1 for textSelection changes
				currentFocused = getTextbox();
			} else {
				currentFocused = this;
			}
		} );
	} );

}() );