MediaWiki:Gadget-toolbar.js: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
importo da it.Wikipedia
(Nessuna differenza)

Versione delle 18:05, 9 set 2015

/**
 * Gadget-toolbar.js
 * Permette di aggiungere ulteriori pulsanti alla toolbar di modifica
 * e di selezionarli tramite una finestra di opzioni.
 *
 * @author [[it:User:Rotpunkt]]
 */
/*jshint unused: false, evil: true */
/*global mediaWiki, jQuery, gadgetToolbarButtons  */
/* <nowiki> */

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

	var sign = ' --~~~~',
		configVersion = 1,
		optionname = 'userjs-gadget-toolbar',
		iconOptions = '//upload.wikimedia.org/wikipedia/commons/1/1e/Button_ns-basics.png',
		hotkeys,
		userConfig,
		groups = {
			formattazione: { label: 'Formattazione' },
			avvisivoci: { label: 'Avvisi voci' },
			messaggiutente: { label: 'Messaggi utente'  },
			altro: { label: 'Altro' }
		};

	// ===========================
	//     Funzioni di utilità
	// ===========================

	function padleft0( num ) {
		return ( num < 10 ? '0' : '' ) + num;
	}

	function makeTimestamp( date ) {
		return date.getUTCFullYear() + '-' + padleft0( date.getUTCMonth() + 1 ) + '-' + padleft0( date.getUTCDate() ) +
			   'T' + padleft0( date.getUTCHours() ) + ':' + padleft0( date.getUTCMinutes() ) + ':00Z';
	}

	function endsWith( str, suffix ) {
		return str.length >= suffix.length && str.indexOf( suffix, str.length - suffix.length ) !== -1;
	}

	function readUserConfig() {
		var config, ret = { buttons: [], version: configVersion };
		if ( mw.user.options.exists( optionname ) ) {
			config = JSON.parse( mw.user.options.get( optionname ) );
			if ( config.version === configVersion ) {
				ret = config;
			}
		}
		return ret;
	}

	function writeUserConfig( config ) {
		$.ajax( {
			url: mw.util.wikiScript( 'api' ),
			data: {
				action: 'options',
				optionname: optionname,
				optionvalue: config,
				token: mw.user.tokens.get( 'editToken' ),
				format: 'json'
			},
			dataType: 'json',
			type: 'POST'
		} )
			.done( function ( data ) {
				var msg;
				if ( data && data.options === 'success' ) {
					mw.notify( 'La configurazione dei pulsanti è stata aggiornata.' );
				} else {
					msg = data && data.error ? ': ' + data.error.code + ' ' + data.error.info : '';
					mw.notify( 'Errore nell\'aggiornare la configurazione dei pulsanti ' + msg );
				}
			} );
	}

	function readUserButtons( readHandler ) {
		var title = 'User:' + mw.config.get( 'wgUserName' ) + '/toolbarbuttons.js';
		$.ajax( {
			url: mw.config.get( 'wgScript' ),
			data: {
				title: title,
				action: 'raw'
			},
			dataType: 'text'
		} )
			.done( function ( data ) {
				var buttons = [];
				try {
					// non si può usare JSON perché i pulsanti contengono anche funzioni
					eval( data );
					if ( window.gadgetToolbarUserButtons !== undefined &&
						 $.isPlainObject( window.gadgetToolbarUserButtons ) ) {
						buttons = window.gadgetToolbarUserButtons;
					}
				} catch ( e ) {
					mw.notify( 'La pagina di configurazione ' + title + ' contiene errori.' );
				} finally {
					readHandler( buttons );
				}
			} )
			.fail( function ( jqXHR, textStatus, errorThrown ) {
				readHandler( [] );
			} );
	}

	function buildDescr( button ) {
		var ret = '';
		if ( button.text ) {
			ret = $( '<div>' ).text( 'Inserisce il testo ' +
				  ( button.text.pre || '' ) + ' ' +
				  ( button.text.post || '' ) + ' nella pagina.' ).html();
		} else if ( button.template ) {
			var $a = $( '<a>' )
				.attr( 'href', '/wiki/Template:' + button.template.name )
				.attr( 'target', '_blank' )
				.attr( 'tabindex', '-1' )
				.css( 'color', '#2e45ad' )
				.text( button.template.name );
			ret = [ 'Inserisce il template {{', $a, '}} nella pagina.'];
		}
		return ret;
	}

	/**
	 * Aggiunge l'autocompletamento con gli ultimi contributi, non più vecchi di un'ora.
	 */
	function addAutocompleteContribs( inputEl ) {
		var dateEnd = new Date();
		dateEnd.setHours( dateEnd.getHours() - 1 );
		$.ajax( {
			url: mw.util.wikiScript( 'api' ),
			data: {
				action: 'query',
				list: 'usercontribs',
				ucuser: mw.config.get( 'wgUserName' ),
				uclimit: '10',
				ucend: makeTimestamp( dateEnd ),
				ucdir: 'older',
				ucprop: 'title',
				format: 'json'
			},
			dataType: 'json'
		} )
			.done( function ( data ) {
				var contribs = [];
				$.each( data.query.usercontribs, function( i, usercontrib ) {
					if ( $.inArray( usercontrib.title, contribs ) === -1 ) {
						contribs.push( usercontrib.title );
					}
				});
				inputEl.autocomplete( { source: contribs } );
			} );
	}

	/**
	 * Aggiunge l'autocompletamento per i nomi utente.
	 */
	function addAutocompleteUsers( inputEl ) {
		inputEl.autocomplete( {
			source: function( request, response ) {
				$.ajax( {
					url: mw.util.wikiScript( 'api' ),
					data: {
						action: 'query',
						list: 'allusers',
						aulimit: '10',
						auprefix: request.term,
						format: 'json'
					},
					dataType: 'json'
				} )
					.done( function ( data ) {
						var users = [];
						$.each( data.query.allusers, function( i, user ) {
							users.push( user.name );
						});
						response( users );
					} );
			}
		} );
	}

	// =======================
	//    Finestra opzioni
	// =======================

	function buildRow( id, button ) {
		var $tr = $( '<tr>' );
		$( '<td>' ).html( '<img src="' + button.icon + '"/>&nbsp;' + id ).appendTo( $tr );
		$( '<td>' ).append( button.descr || buildDescr( button ) ).appendTo( $tr );
		$( '<td>' ).append( $( '<input>' ).data( 'id', id )
			.attr( 'type', 'checkbox' ).attr( 'checked', $.inArray( id, userConfig.buttons ) > -1 ) ).appendTo( $tr );
		return $tr;
	}

	function buildTable() {
		var $table, $thead, $tr;
		$table = $( '<table>' )
			.attr( 'border', '0' )
			.attr( 'cellpadding', '0' )
			.attr( 'cellspacing', '0' )
			.attr( 'width', '100%' );
		$thead = $( '<thead>' ).appendTo( $table );
		$tr = $( '<tr>' ).appendTo( $thead );
		$( '<th>' ).text( 'Pulsante' ).appendTo( $tr );
		$( '<th>' ).text( 'Descrizione' ).appendTo( $tr );
		$( '<th>' ).text( '' ).appendTo( $tr );
		$( '<tbody>' ).appendTo( $table );
		return $table;
	}

	/**
	 * Visualizza la finestra delle opzioni per selezionare i pulsanti.
	 */
	function showConfigDialog() {
		var $div, $ul;
		if ( $( '#gtb-dialog-options' ).hasClass( 'ui-dialog-content' ) ) {
			$( '#gtb-dialog-options' ).dialog( 'open' );
			return;
		}

		$div = $( '<div>' ).attr( 'id', 'tabs' );
		$ul = $( '<ul>' ).appendTo( $div );
		$.each( groups, function ( key, group ) {
			var $a = $( '<a>' ).attr( 'href', '#tabs-' + key ).text( group.label );
			$( '<li/>' ).append( $a ).appendTo( $ul );
			group.table = buildTable();
		} );
		$.each( gadgetToolbarButtons, function ( id, button ) {
			groups[button.group].table.find( 'tbody' ).append( buildRow( id, button ) );
		} );
		$.each( groups, function ( key, group ) {
			$( '<div>' ).addClass( 'gtb-tablecontainer' ).attr( 'id', 'tabs-' +  key )
			.append( group.table )
			.appendTo( $ul );
		} );
		$( '#gtb-dialog-options' ).html( $div ).tabs();

		// visualizza il dialog
		$( '#gtb-dialog-options' ).dialog( {
			title: '<img src="' + iconOptions + '"/>&nbsp;Configurazione pulsanti toolbar',
			width: 700,
			resizable: false,
			modal: true,
			open: function( event, ui ) {
				$( '#gtb-dialog-options' ).tabs( 'option', 'active', 0 );
			},
			buttons: {
				'Salva': function () {
					var newConfig, newConfigJSON;
					// genera la nuova configurazione
					newConfig = $( '#gtb-dialog-options' ).find( 'tr:has( td )' ).map( function () {
						var $input = $( this ).find( 'input' ).eq( 0 );
						return $input.prop( 'checked' ) ? [ $input.data( 'id' ) ] : null;
					} ).get();
					newConfig = { buttons: newConfig, version: configVersion };
					newConfigJSON = JSON.stringify( newConfig );
					// se necessario scrive la configurazione
					if ( newConfigJSON === JSON.stringify( userConfig ) ) {
						mw.notify( 'I pulsanti non sono stati modificati.' );
					} else {
						writeUserConfig( newConfigJSON );
						userConfig = newConfig;
						addButtons();
					}
					$( this ).dialog( 'close' );
				},
				'Annulla': function () {
					$( this ).dialog( 'close' );
				}
			}
		} );
	}

	// =====================================
	//    Finestra parametri per template
	// =====================================

	function buildInputEl( id, val ) {
		var inputEl;

		switch ( val.type ) {
			case 'textbox':
				inputEl = $( '<input/>' ).attr( 'id', id ).attr( 'type', 'text' ).attr( 'size', 50 );
				if ( val.autocomplete ) {
					mw.loader.using( 'jquery.ui.autocomplete', function () {
						switch ( val.autocomplete ) {
							case 'contribs':
								addAutocompleteContribs( inputEl );
								break;
							case 'users':
								addAutocompleteUsers( inputEl );
								break;
							// supporto per eventuali altri tipi di autocompletamento
							default:
								break;
						}
					});
				}
				break;
			case 'combobox':
				inputEl = $( '<select>' ).attr( 'id', id ).css( 'width', '200px' );
				$.each( val.value, function ( i, option ) {
					$( '<option>' ).html( option ).appendTo( inputEl );
				} );
				break;
			case 'checkbox':
				inputEl = $( '<input/>' ).attr( 'id', id ).attr( 'type', 'checkbox' ).attr( 'checked', val.value );
				break;
			default:
				break;
		}

		return inputEl;
	}

	/**
	 * Visualizza la finestra di dialogo per richiedere i parametri dei template.
	 */
	function showTemplateDialog( button ) {
		var $dialog, $fieldset, template = button.template;

		// crea l'html del dialog
		$dialog = $( '#gtb-dialog-template' ).html( buildDescr( button ) );
		$fieldset = $( '<fieldset>' ).css( 'border-color', 'gray' ).appendTo( $dialog );
		$( '<legend>' ).text( 'Parametri' ).appendTo( $fieldset );
		$.each( template.params, function ( id, val ) {
			var inputEl = buildInputEl( id, val );
			$( '<label>' ).attr( 'for', id ).text( val.label + ':' ).appendTo( $fieldset );
			$fieldset.append( '<br/>', inputEl, '<br/>' );
		} );

		// visualizza il dialog
		$dialog.dialog( {
			title: '<img src="' + button.icon + '"/>&nbsp;' + button.label,
			width: 500,
			resizable: false,
			modal: false,
			buttons: {
				'Inserisci': function () {
					var params = {};
					$dialog.find( 'input:text,select' ).each( function () {
						params[$( this ).attr( 'id' )] = $.trim( $( this ).val() );
					} );
					$dialog.find( 'input:checkbox' ).each( function () {
						params[$( this ).attr( 'id' )] = $( this ).prop( 'checked' );
					} );
					dumpTemplate( template, params );
					setSummary( button );
					$( this ).dialog( 'close' );
				},
				'Annulla': function () {
					$( this ).dialog( 'close' );
				}
			}
		} );
	}

	// =====================================
	//    Inserimento e gestione pulsanti
	// =====================================

	/**
	 * Inserisce il template nell'area di testo.
	 */
	function dumpTemplate( template, params ) {
		var text, templateParams;

		if ( template.format ) {
			templateParams = template.format( params || {} );
		}
		text = ( template.noinclude ? '<noinclude>' : '' ) +
			   '{{' + ( template.subst ? 'subst:' : '' ) +
			   template.name + ( templateParams || '' ) + '}}' +
			   ( template.sign ? sign : '' ) +
			   ( template.noinclude ? '</noinclude>' : '' ) +
			   ( template.extratext ? template.extratext : '' );
		if ( template.position === 'top' ) {
			$( '#wpTextbox1' ).textSelection( 'setSelection', { start: 0, end: 0 } );
			$( '#wpTextbox1' ).textSelection( 'encapsulateSelection', { post: text + '\n' } );
		} else if ( template.position === 'bottom' ) {
			$( '#wpTextbox1' ).select().val( $( '#wpTextbox1' ).val() + '\n' + text );
		} else {
			$( '#wpTextbox1' ).textSelection( 'encapsulateSelection', { pre: text } );
		}
	}

	/**
	 * Valorizza il campo oggetto della modifica.
	 */
	function setSummary( button ) {
		var text, replace = false;

		if ( button.summary !== undefined ) {
			text = button.summary;
		} else if ( button.template ) {
			if ( $( '#wpMinoredit' ).length ) {
				text = '+' + button.template.name;
			} else if ( button.group === 'messaggiutente' ) {
				text = 'Avviso';
				replace = true;
			}
		}
		if ( text ) {
			$( '#wpSummary' ).val( function ( i, prevText ) {
				return replace ? text : prevText + ( prevText.length > 0 ? ' ' : '' ) + text;
			} );
		}
	}

	/**
	 * Gestore del click sui pulsanti della toolbar (avanzata e classica).
	 */
	function clickHandler( button ) {
		var dialog = false;
		if ( button.text ) {
			$( '#wpTextbox1' ).textSelection( 'encapsulateSelection', button.text );
		} else if ( button.execute ) {
			button.execute();
		} else if ( button.template ) {
			if ( button.template.params ) {
				dialog = true;
				showTemplateDialog( button );
				// setSummary avviene alla conferma del dialog
			} else {
				dumpTemplate( button.template );
			}
		}
		if ( !dialog ) {
			setSummary( button );
		}
	}

	/**
	 * Ritorna true se il namespace è corretto per il pulsante.
	 */
	function rightNs( button ) {
		var ret = true;
		if ( button.ns !== undefined ) {
			if ( typeof button.ns === 'function' ) {
				ret = button.ns();
			} else {
				ret = mw.config.get( 'wgNamespaceNumber' ) === button.ns;
			}
		}
		return ret;
	}

	/**
	 * Inizializza il pulsante per l'utilizzo nella toolbar.
	 */
	function initButton( id, button ) {
		button.label = button.tooltip = id;
		if ( button.hotkey ) {
			button.hotkey = button.hotkey.toUpperCase();
			button.tooltip += ' [Alt+' + button.hotkey + ']';
			hotkeys[button.hotkey] = button;
		}
	}

	/**
	 * Aggiunge i pulsanti alla toolbar avanzata (wikiEditor).
	 */
	function addButtonsAdvancedToolbar() {
		$.each( groups, function ( key, buttons ) {
			groups[key].tools = {};
		} );
		$.each( userConfig.buttons, function( i, id ) {
			var button = gadgetToolbarButtons[id];
			if ( button && rightNs( button ) ) {
				initButton( id, button );
				groups[button.group].tools[id] = {
					label: button.tooltip,
					type: 'button',
					icon: button.icon,
					action: {
						type: 'callback',
						execute: function ( context ) {
							clickHandler( button );
						}
					}
				};
			}
		} );
		var tb = {
			sections: {
				altro: {
					type: 'toolbar',
					label: 'Altri pulsanti',
					groups: {
						opzioni: {
							label: 'Opzioni',
							tools: {
								opzioni: {
									type: 'button',
									label: 'Opzioni',
									icon: iconOptions,
									action: {
										type: 'callback',
										execute: function ( context ) {
											showConfigDialog();
										}
									}
								}
							}
						}
					}
				}
			}
		};
		$.each( groups, function ( key, group ) {
			tb.sections.altro.groups[key] = { label: group.label, tools: group.tools }; 
		} );
		$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', tb );
	}

	/**
	 * Aggiunge i pulsanti alla toolbar "classica".
	 */
	function addButtonsClassicToolbar() {
		$.each( userConfig.buttons, function( i, id ) {
			var button = gadgetToolbarButtons[id];
			if ( button && rightNs( button ) ) {
				initButton( id, button );
				$( '<img/>' )
					.attr( 'src', button.icon )
					.attr( 'title', button.tooltip )
					.css( 'cursor', 'pointer' )
					.addClass( 'gtb-button' )
					.click( function () {
						clickHandler( button );
					} )
					.appendTo( '#toolbar' );
			}
		} );
	}

	function addButtons( userButtons ) {
		hotkeys = {};
		// unisce userButtons a gadgetToolbarButtons
		if ( userButtons ) {
			$.extend( gadgetToolbarButtons, userButtons );
		}
		// aggiunge i pulsanti alla toolbar
		if ( mw.user.options.get( 'usebetatoolbar' ) ) {
			mw.loader.using( [ 'ext.wikiEditor.toolbar' ], function () {
				// rimozione pulsanti precedenti
				if ( !userButtons ) {
					$( '#wpTextbox1' ).wikiEditor( 'removeFromToolbar', { 'section': 'altro' } );
				}
				addButtonsAdvancedToolbar();
			} );
		} else {
			if ( userButtons ) {
				mw.toolbar.addButton( {
					imageFile: iconOptions,
					speedTip: 'Opzioni',
					onClick: showConfigDialog
				} );
			} else {
				// rimozione pulsanti precedenti
				$( '.gtb-button' ).remove();
			}
			addButtonsClassicToolbar();
		}
	}

	/**
	 * Installa il gestore per gli hotkeys
	 */
	function installHotkeyHandler() {
		$( '#wpTextbox1' ).keypress( function ( event ) {
			var button, help = '';
			if ( event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ) {
				if ( event.which === 72 || event.which === 104 ) {
					event.preventDefault();
					$.each( hotkeys, function ( hotkey, button ) {
						help += button.label + ' = Alt+' + hotkey + '\n';
					} );
					alert( 'Hotkey attivi:\n' + help );
				} else {
					button = hotkeys[String.fromCharCode( event.which ).toUpperCase()];
					if ( button ) {
						event.preventDefault();
						clickHandler( button );
					}
				}
			}
		} );
	}

	/**
	 * Verifica se la pagina userà codeEditor
	 */
	function needCodeEditor() {
		var title =  mw.config.get( 'wgTitle' ), ns = mw.config.get( 'wgNamespaceNumber' );
		return endsWith( title, '.js' ) || ( ns == 828 && !endsWith( title, '/man' ) );
	}

	$( function () {
		if ( $.inArray( mw.config.get( 'wgAction' ), ['edit', 'submit'] ) !== -1 && !needCodeEditor() ) {
			mw.loader.using( [ 'jquery.ui.dialog', 'jquery.ui.tabs'], function () {
				// lettura configurazione
				userConfig = readUserConfig();
				// setup dialog
				$( '<div>' ).attr( 'id', 'gtb-dialog-options' ).appendTo( 'body' );
				$( '<div>' ).attr( 'id', 'gtb-dialog-template' ).appendTo( 'body' );
				// installa handler hotkeys
				installHotkeyHandler();
				// aggiunge i pulsanti
				readUserButtons( function( userButtons ) {
					addButtons( userButtons );
				} );
			} );
		}
	} );
}( mediaWiki, jQuery ) );

/* </nowiki> */