User:Evad37/Module/multiButtonConfirm.js

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.
/**
 * @module multiButtonConfirm
 * @description A confirmation dialog that can have multiple customised buttons.
 * Derived from <https://en.wikipedia.org/wiki/User:Evad37/XFDcloser/v3.js>.
 * @author User:Evad37
 * @version 1.0.0
 * @requires mediawiki.util
 * @requires oojs-ui-core
 * @requires oojs-ui-widgets
 * @requires oojs-ui-windows
 * @exports {Function} multiButtonConfirm
 *   @param {Object} config  configuartion options
 *   @param {String} config.title  Title for the dialogue
 *   @param {String} config.message  Message for the dialogue. HTML tags (except
 *     for <br>, <p>, <ul>, <li>, <hr>, and <pre> --plain tags only, no
 *     attributes allowed) are escaped; wikilinks are turned into real links.
 *   @param {Object[]} config.actions  Optional. Array of configuration objects for
 *     OO.ui.ActionWidget <https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.ActionWidget>.
 *     If not specified, the default actions are 'accept' (with label 'OK') and
 *     'reject' (with label 'Cancel').
 *   @param {String} config.size  Symbolic name of the dialog size: small,
 *     medium, large, larger or full.
 *   @returns {Promise<String>} action taken by user
 */
Window.exportScriptModule('multiButtonConfirm', (function() {
	var dependenciesLoaded = $.Deferred();
	mw.loader.using(
		['mediawiki.util', 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows'],
		dependenciesLoaded.resolve,
		dependenciesLoaded.reject
	 );
	 return dependenciesLoaded.then(function() {
		/**
		 * Un-escapes some HTML tags (<br>, <p>, <ul>, <li>, <hr>, and <pre>);
		 * turns wikilinks into real links. Ignores anyting within
		 * <pre>...</pre> tags.
		 * Input will first be escaped using mw.html.escape() unless specified 
		 * otherwise.
		 * @param {String} text
		 * @param {Object} config Configuration options
		 * @param {Boolean} config.noEscape - do not escape the input first
		 * @returns {String} unescaped text
		 */
		var safeUnescape = function(text, config) {
			var path = 'https:' + mw.config.get('wgServer') + '/wiki/';
		
			return ( config && config.noEscape && text || mw.html.escape(text) )
			// Step 1: unescape <pre> tags
			.replace(  
				/&lt;(\/?pre\s?\/?)&gt;/g,
				'<$1>'
			)
			// Step 2: replace piped wikilinks with real links (unless inside <pre> tags)
			.replace( 
				/\[\[([^\|\]]*?)\|([^\|\]]*?)\]\](?![^<]*?<\/pre>)/g,
				'<a href="' + path + mw.util.wikiUrlencode('$1') + '" target="_blank">$2</a>'
			)
			// Step 3: replace other wikilinks with real links (unless inside <pre> tags)
			.replace( 
				/\[\[([^\|\]]+?)]\](?![^<]*?<\/pre>)/g,
				'<a href="' + path + mw.util.wikiUrlencode('$1') + '" target="_blank">$1</a>'
			)
			// Step 4: unescape other tags: <br>, <p>, <ul>, <li>, <hr> (unless inside <pre> tags)
			.replace(
				/&lt;(\/?(?:br|p|ul|li|hr)\s?\/?)&gt;(?![^<]*?<\/pre>)/g,
				'<$1>'
			);
		};
		
		/** @see #exports */
		var multiButtonConfirm = function(config) {
			var dialogClosed = $.Deferred();
			
			// Wrap message in a HtmlSnippet to prevent escaping
			var htmlSnippetMessage = new OO.ui.HtmlSnippet(
				safeUnescape(config.message)
			);
		
			var windowManager = new OO.ui.WindowManager();
			var messageDialog = new OO.ui.MessageDialog();
			$('body').append( windowManager.$element );
			windowManager.addWindows( [ messageDialog ] );
			windowManager.openWindow( messageDialog, {
				'title': config.title,
				'message': htmlSnippetMessage,
				'actions': config.actions,
				'size': config.size
			} );
			windowManager.on('closing', function(_win, promise) {
				promise.then(function(data) {
					dialogClosed.resolve(data && data.action);
					windowManager.destroy();
				});
			});
		
			return dialogClosed.promise();
		};
		
		return multiButtonConfirm;
	 });
})());