MediaWiki:Gadget-pulsantipersonali.js

Nel mondo di oggi, MediaWiki:Gadget-pulsantipersonali.js è diventato un argomento di grande rilevanza e interesse per un vasto pubblico. Nel tempo, MediaWiki:Gadget-pulsantipersonali.js ha acquisito maggiore importanza in diversi ambiti, dalla scienza, alla tecnologia, alla politica, alla cultura e all'intrattenimento. Questo articolo si propone di esplorare in dettaglio e in modo critico vari aspetti legati a MediaWiki:Gadget-pulsantipersonali.js, al fine di fornire al lettore una visione ampia e arricchente di questo argomento. Attraverso un'analisi profonda e rigorosa, cerchiamo di far luce su diversi aspetti di MediaWiki:Gadget-pulsantipersonali.js, affrontandone le implicazioni, l'evoluzione e le ripercussioni sulla società attuale.
/**
 * Gadget-pulsantipersonali.js
 * Aggiunge alla toolbar di modifica normale e avanzata dek testo predefinito dall'utente
 * inseribile nell'area di modifica tramite una casella combinata.
 * Il testo è configurabile con una finestra di dialogo che si attiva dal menu strumenti.
 * Riscritto da zero a partire da:
 * https://it.wikipedia.org/w/index.php?title=Wikipedia:Monobook.js/Pulsanti_personali.js&oldid=10941967
 * http://it.wikipedia.org/w/index.php?title=MediaWiki:Gadget-pulsantipersonali.js&oldid=38709932
 * 
 * Formato di una entry, ereditato dal vecchio gadget (sarebbe da semplificare con un bot):
 * 0 (int):    tipo di inserimento: 1 per inizio e fine, 2 al cursore
 * 1 (string): testo prima del cursore
 * 2 (string): se il campo 0 vale 2 => testo dopo il cursore
 *             se il campo 0 vale 1 => '0' inserimento inizio, '1' inserimento fine
 * 3 (string): titolo
 * 4 (int):    offset
 * 5 (string): oggetto modifica
 *
 * @author https://it.wikipedia.orghttps://wikifreehand.com/it/Utente:Rotpunkt
 */
/* global mediaWiki, jQuery */

( function ( mw, $ ) {
	'use strict';

	// Configurazione utente
	var userConfig = 'User:' + mw.config.get( 'wgUserName' ) + '/' + mw.config.get( 'skin' ) + '.js';
	// Testo definito dell'utente (chiamato myButtons nel vector/monobook.js dell'utente)
	var userStrings;

	/**
	 * Aggiorna o aggiunge la variabile myButtons nel vector.js/monobook.js dell'utente.
	 * 
	 * @param {string} myButtonsValue - La stringa contenente il valore di myButtons da aggiornare
	 * @param {function} successHandler - La funzione da richiamare in caso di successo
	 */
	function updateUserConfig( myButtonsValue, successHandler ) {
		new mw.Api().edit( userConfig, function ( revision ) {
			var expr = /var\s+myButtons\s*=*?;\n/;
			myButtonsValue = 'var myButtons = ' + myButtonsValue + ';\n';
			var content = revision.content.match( expr ) ?
						  revision.content.replace( expr, myButtonsValue ) :
						  revision.content + '\n' + myButtonsValue;
			// eventuali tag pre
			content = content.indexOf( '//<pre>' ) === -1 ?
					  '//<pre>\n' + content : content;
			content = content.indexOf( '//</pre>' ) === -1 ?
					  content + '\n//</pre>' : content;
			return {
				text: content,
				summary: 'testo personale'
			};
		} ).done( function () {
			var url = mw.config.get( 'wgArticlePath' ).replace( '$1', userConfig );
			var msg = 'La configurazione del testo personale è stata aggiornata in <a href="' +
					  url + '" title="' + userConfig + '">' + userConfig + '</a>';
			mw.notify( $.parseHTML( msg ) );
			successHandler();
		} ).fail( function ( code, data ) {
			if ( code === 'nocreate-missing' ) {
				mw.notify(
					'Per poter inserire il testo personale è necessario prima creare la pagina ' +
					userConfig + ', senza scriverci nulla. Prova di nuovo dopo averlo fatto.'
				);
			} else {
				mw.notify( 'Errore nell\'aggiornare ' + userConfig + ': '  + code );
			}
		} );
	}

	/**
	 * Gestore del click del combobox per entrambe le toolbar.
	 * 
	 * @param {array} userString - L'elemento dell'array userStrings selezionato
	 */
	function clickHandler( userString ) {
		var text, post;
		text = userString.replace( /\\n/g, '\n' );
		post = userString.replace( /\\n/g, '\n' );
		if ( userString === 2 ) {
			$( '#wpTextbox1' ).textSelection( 'encapsulateSelection', { pre: text, post: post } );
		} else if ( userString === 1 && userString === '0' ) {
			$( '#wpTextbox1' ).textSelection( 'setSelection', { start: 0, end: 0 } );
			$( '#wpTextbox1' ).textSelection( 'encapsulateSelection', { post: text + '\n' } );
		} else if ( userString === 1 && userString === '1' ) {
			$( '#wpTextbox1' ).select().val( $( '#wpTextbox1' ).val() + '\n' + text );
		}
		if ( userStrings !== '' ) {
			$( '#wpSummary' ).val( function ( i, val ) {
				var sep = val.endsWith( ' ' ) ? '' : ' ';
				return ( val.trim() ? val + sep : '' ) + userString;
			} );
		}
	}

	/**
	 * Aggiunge la casella combinata alla toolbar di modifica avanzata.
	 */
	function addComboboxAdvancedToolbar() {
		var wb, tool;
		wb = { section: 'main', group: 'insert', tools: {} };
		tool = { label: 'Personale', type: 'select', list: {} };
		$.each( userStrings, function ( i, userString ) {
			tool.list = {
				label: userString,
				action: {
					type: 'callback',
					execute: function ( context ) {
						clickHandler( userString );
					}
				}
			};
		} );
		wb.tools.gpp = tool;
		$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', wb );
		// secondo tentativo per ]
		$( '#wpTextbox1' ).on( 'wikiEditor-toolbar-doneInitialSections', function () {
			var target = '#wikiEditor-ui-toolbar div.section ' +
						 'div.group div.tool';
			if ( !$( target ).length ) {
				$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', wb );
			}
		} );
	}

	/**
	 * Aggiunge la casella combinata alla toolbar di modifica classica.
	 */
	function addComboboxClassicToolbar() {
		var $div, $select;
		$div = $( '<div>' ).attr( 'id', 'gpp-toolbar' )
			   .css( 'margin-bottom', '5px' ).insertBefore( '#toolbar' );
		$( '<span>' )
			.text( 'Testo personale:' )
			.appendTo( $div ).after( '&nbsp;' );
		$select = $( '<select>' ).appendTo( $div );
		$.each( userStrings, function ( i, userString ) {
			$( '<option>' )
				.html( userString )
				.data( 'userString', userString )
				.appendTo( $select );
		} );
		$( '<input>' )
			.attr( 'type', 'button' )
			.attr( 'value', 'Ok' )
			.click( function () {
				clickHandler( $( 'option:selected' ).data( 'userString' ) );
			} )
			.appendTo( $div );
	}

	/**
	 * Rimuove la casella combinata dalla toolbar di modifica.
	 */
	function toolbarRemoveCombobox() {
		var target = mw.user.options.get( 'usebetatoolbar' ) ?
					'#wikiEditor-ui-toolbar div.section ' +
					'div.group div.tool' :
					'#gpp-toolbar';
		$( target ).remove();
	}

	/**
	 * Funzione di utilità di buildRow per ottenere tipo di inserimento ('Cursore', 'Inizio', 'Fine').
	 * 
	 * @param {array} userString - Un elemento dell'array userStrings
	 * @return {string} la stringa '0', '1' o '2'
	 */
	function getPos( userString ) {
		return userString === 1 && userString === '0' ? '1' :
				userString === 1 && userString === '1' ? '2' :
						userString === 2 ? '0' : '';
	}

	/**
	 * Funzione di utilità di showConfigDialog per creare una riga della tabella.
	 * 
	 * @param {array} userString - Un elemento dell'array userStrings
	 * @return {jQuery} la riga per la table
	 */
	function buildRow( userString ) {
		var $span, $input, $select, $tr = $( '<tr>' ),
			properties = {
				'width': '100%',
				'box-sizing': 'border-box',
				'-moz-box-sizing': 'border-box',
				'-webkit-box-sizing': 'border-box'
			};
		// icona spostamento
		$span = $( '<span>' ).addClass( 'ui-icon ui-icon-arrowthick-2-n-s' );
		$( '<td>' ).append( $span ).appendTo( $tr );
		// vecchi campi che contenevano il tipo di funzione da usare e l'offset
		$( '<input>' ).attr( 'type', 'hidden' ).val( userString ).appendTo( $tr );
		$( '<input>' ).attr( 'type', 'hidden' ).val( userString ).appendTo( $tr );
		// input text
		$input = $( '<input>' ).attr( 'type', 'text' ).val( userString ).css( properties );
		$( '<td>' ).css( 'width', '16%' ).append( $input ).appendTo( $tr );
		$input = $( '<input>' ).attr( 'type', 'text' ).val( userString ).css( properties );
		$( '<td>' ).css( 'width', '40%' ).append( $input ).appendTo( $tr );
		$input = $( '<input>' ).attr( 'type', 'text' ).val( userString ).css( properties )
				 .toggle( userString !== 1 );
		$( '<td>' ).css( 'width', '20%' ).append( $input ).appendTo( $tr );
		$input = $( '<input>' ).attr( 'type', 'text' ).val( userString ).css( properties );
		$( '<td>' ).css( 'width', '20%' ).append( $input ).appendTo( $tr );
		// select
		$select = $( '<select>' ).change( function () {
			$input = $tr.find( 'input' );
			$input.eq( 0 ).val( $select.val() === '0' ? '2' : '1' );
			$input.eq( 4 ).val( $select.val() === '0' ? '' :
								$select.val() === '1' ? '0' : '1' )
							.toggle( $select.val() === '0' );
		} );
		$.each( , function ( i, option ) {
			$( '<option>' ).val( i ).html( option ).appendTo( $select );
		} );
		$select.val( getPos( userString ) );
		$( '<td>' ).append( $select ).appendTo( $tr );
		// checkbox
		$( '<td>' ).append( $( '<input>' ).attr( 'type', 'checkbox' ) ).appendTo( $tr );
		return $tr;
	}

	/**
	 * Visualizza la finestra di dialogo per modificare il "testo personale".
	 */
	function showConfigDialog() {
		var $table, $thead, $tbody, $tr, $checkbox;

		// crea l'html del dialog, una singola table
		$table = $( '<table>' );
		$thead = $( '<thead>' ).appendTo( $table );
		$tr = $( '<tr>' ).attr( 'bgcolor', 'lightgrey' ).appendTo( $thead );
		$( '<th>' ).css( 'width', '2%' ).text( '' ).appendTo( $tr );
		$checkbox = $( '<input>' )
			.attr( 'id', 'gpp-selectall' )
			.attr( 'type', 'checkbox' )
			.attr( 'tabindex', '-1' )
			.click( function () {
				$( '#gpp-dialog :checkbox' ).prop( 'checked', this.checked );
			} );
		$( '<th>' ).css( 'width', '16%' ).text( 'Nome' ).appendTo( $tr );
		$( '<th>' ).css( 'width', '40%' ).text( 'Testo' ).appendTo( $tr );
		$( '<th>' ).css( 'width', '20%' ).text( 'Dopo cursore' ).appendTo( $tr );
		$( '<th>' ).css( 'width', '20%' ).text( 'Oggetto' ).appendTo( $tr );
		$( '<th>' ).text( 'Pos.' ).appendTo( $tr );
		$( '<th>' ).append( $checkbox ).appendTo( $tr );
		$tbody = $( '<tbody>' ).appendTo( $table );
		$.each( userStrings, function ( i, userString ) {
			$tbody.append( buildRow( userString ) );
		} );
		$tbody.sortable( { handle: 'span' } );
		$( '#gpp-dialog' ).html( $table );

		// visualizza il dialog
		$( '#gpp-dialog' ).dialog( {
			title: 'Configurazione testo personale',
			width: 800,
			height: 300,
			modal: true,
			buttons: {
				'Aggiungi riga': function () {
					$tbody.append( buildRow(  ) );
				},
				'Cancella riga': function () {
					$( '#gpp-dialog :checkbox:checked:not( #gpp-selectall )' ).parents( 'tr' ).remove();
					$( '#gpp-selectall' ).attr( 'checked', false );
				},
				'Salva': function () {
					var confStrings, confStringsJSON, userStringsJSON;
					// genera la nuova configurazione
					confStrings = $table.find( 'tr:has( td )' ).map( function () {
						var $input = $( this ).find( 'input' );
						return $.trim( $input.eq( 2 ).val() ) !== '' &&
							   $.trim( $input.eq( 3 ).val() ) !== '' ?
									[[ parseInt( $input.eq( 0 ).val(), 10 ), $input.eq( 3 ).val(),
										$input.eq( 4 ).val(), $input.eq( 2 ).val(),
										parseInt( $input.eq( 1 ).val(), 10 ), $input.eq( 5 ).val() ]] : null;
					} ).get();
					confStringsJSON = JSON.stringify( confStrings );
					userStringsJSON = JSON.stringify( userStrings );
					// se necessario scrive la configurazione nella pagina dell'utente
					if ( confStringsJSON === userStringsJSON ) {
						mw.notify( 'Il testo personale non è stato modificato.' );
					} else {
						updateUserConfig( confStringsJSON, function () {
							userStrings = confStrings;
							// aggiorna la toolbar
							if ( $.inArray( mw.config.get( 'wgAction' ),  ) !== -1 ) {
								toolbarRemoveCombobox();
								if ( userStrings.length > 0 ) {
									if ( mw.user.options.get( 'usebetatoolbar' ) ) {
										addComboboxAdvancedToolbar();
									} else {
										addComboboxClassicToolbar();
									}
								}
							}
						} );
					}
					$( this ).dialog( 'close' );
				},
				'Annulla': function () {
					$( this ).dialog( 'close' );
				}
			}
		} );
	}

	$( function () {
		userStrings = window.myButtons === undefined ?  : window.myButtons;
		$( '<div>' ).attr( 'id', 'gpp-dialog' ).appendTo( 'body' );
		var portletLink = mw.util.addPortletLink( 'p-tb', '#', 'Testo personale' );
		$( portletLink ).click( function ( event ) {
			event.preventDefault();
			mw.loader.using( , function () {
				showConfigDialog();
			} );
		} );
		if ( $.inArray( mw.config.get( 'wgAction' ),  ) !== -1 && userStrings.length > 0 ) {
			if ( mw.user.options.get( 'usebetatoolbar' ) ) {
				mw.loader.using(  )
					.done( addComboboxAdvancedToolbar )
					.fail( function () {
						console.error( 'Impossibile avviare l\'accessorio pulsanti personali.' );
					} );
			} else {
				addComboboxClassicToolbar();
			}
		}
	} );
}( mediaWiki, jQuery ) );