Benutzer:ICON/TemplateWizard.js

Aus WiiDatabase Wiki
Zur Navigation springenZur Suche springen

Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Strg+F5
( function ( mw, $ ) {
// <nowiki>

function defineClasses() {
	/*
	 * Messages will be moved to JSON files later on.
	 */
	mw.messages.set( 'templatewizard', 'TemplateWizard (beta)' );
	mw.messages.set( 'templatewizard-dialog-title', 'Vorlage einfügen (beta)' );
	mw.messages.set( 'templatewizard-opens-in-new-tab', 'Öffnet in einem neuen Tab' );
	mw.messages.set( 'templatewizard-help-page', 'Hilfeseite' );
	mw.messages.set( 'templatewizard-invalid-title', 'Ungültiger Titel' );
	mw.messages.set( 'templatewizard-template-not-found',
		'$1 kann nicht im TemplateWizard genutzt werden.' +
		' Dies liegt eventuell daran, dass die Vorlage nicht existiert oder keine $2-Tags besitzt.' +
		' Bitte behebe dies und versuche es erneut.'
	);
	mw.messages.set( 'templatewizard-default', 'Standard: $1' );
	mw.messages.set( 'templatewizard-example', 'Beispiel: $1' );
	mw.messages.set( 'templatewizard-parameters-required', 'Erforderliche Parameter' );
	mw.messages.set( 'templatewizard-parameters-suggested', 'Vorgeschlagene Parameter' );
	mw.messages.set( 'templatewizard-parameters-optional', 'Optionale Parameter' );
	mw.messages.set( 'templatewizard-insert', 'Einfügen' );
	mw.messages.set( 'templatewizard-cancel', 'Abbrechen' );
	mw.messages.set( 'templatewizard-use', 'Benutzen' );
	mw.messages.set( 'templatewizard-select-template', 'Wähle eine Vorlage:' );

	/* Extension namespace. */
	mediaWiki.TemplateWizard = {};

	/**
	 * @class
	 * @constructor
	 * @param {Object} [config] Configuration options
	 */
	mediaWiki.TemplateWizard.TemplateForm = function mediaWikiTemplateWizardTemplateForm( config ) {
		// Parent constructor
		OO.ui.Widget.parent.call( this, config );
		this.$element = $( '<div>' ).addClass( 'ext-templatewizard-templateform' );
	};
	OO.inheritClass( mediaWiki.TemplateWizard.TemplateForm, OO.ui.Widget );

	/**
	 * Set the template title.
	 * @param {string} newTitle No leading 'Template:' required.
	 */
	mediaWiki.TemplateWizard.TemplateForm.prototype.setTitle = function ( newTitle ) {
		this.title = mw.Title.newFromText( newTitle, mw.config.get( 'wgNamespaceIds' ).template );
		if ( !this.title ) {
			throw new Error( mw.message( 'templatewizard-invalid-title' ) );
		}
		this.$element.append( this.getHeader() );
		this.loadTemplateData();
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.setDialog = function ( dialog ) {
		this.dialog = dialog;
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.getTitle = function () {
		return this.title;
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.getFormat = function () {
		return this.format;
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.getHeader = function () {
		var link;
		link = $( '<a>' )
			.attr( 'target', '_blank' )
			.attr( 'title', mw.message( 'templatewizard-opens-in-new-tab' ) )
			.attr( 'href', this.title.getUrl() )
			.text( this.title.getMainText() );
		return $( '<h2>' ).html( link );
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.getInputWidgetForParam = function ( param, paramDefinition ) {
		var widget, config = { name: param };
		if ( paramDefinition.autovalue ) {
			config.value = paramDefinition.autovalue;
		}
		if ( paramDefinition.required ) {
			config.required = true;
		}
		if ( paramDefinition.type === 'number' ) {
			widget = new OO.ui.NumberInputWidget( config );
		} else if ( paramDefinition.type === 'date' ) {
			widget = new mw.widgets.DateInputWidget( config );
		} else if ( paramDefinition.type === 'wiki-user-name' ) {
			widget = new mw.widgets.UserInputWidget( config );
		} else if ( paramDefinition.type === 'wiki-page-name' ) {
			widget = new mw.widgets.TitleInputWidget( config );
		} else if ( paramDefinition.type === 'wiki-file-name' ) {
			config.showImages = true;
			config.namespace = mw.config.get( 'wgNamespaceIds' ).file;
			widget = new mw.widgets.TitleInputWidget( config );
		} else if ( paramDefinition.type === 'wiki-template-name' ) {
			config.namespace = mw.config.get( 'wgNamespaceIds' ).template;
			widget = new mw.widgets.TitleInputWidget( config );
		} else {
			widget = new OO.ui.TextInputWidget( config );
		}
		return widget;
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.getParameterFieldsets = function ( groupedParams ) {
		var $fieldsets = $( '<div>' ),
			self = this;
		$.each( groupedParams, function ( groupName, group ) {
			var fieldsetLabel = mw.message( 'templatewizard-parameters-' + groupName ).text(),
				fieldset = new OO.ui.FieldsetLayout( { label: fieldsetLabel } );
			if ( groupName === 'required' ) {
				fieldset.$label.css( 'color', '#e04006' );
			}
			if ( groupName === 'suggested' ) {
				fieldset.$label.css( 'color', '#f99d31' );
			}
			if ( groupName === 'optional' ) {
				fieldset.$label.css( 'color', '#78ab46' );
			}
			$.each( group, function ( param, details ) {
				var widget, field, label, description;
				widget = self.getInputWidgetForParam( param, details );
				description = '';
				if ( details.description ) {
					description = details.description;
				}
				if ( details.default ) {
					description += '<br>' + mw.message( 'templatewizard-default', details.default );
				}
				if ( details.example ) {
					description += '<br>' + mw.message( 'templatewizard-example', details.example );
				}
				label = param;
				if ( details.label ) {
					label = details.label;
				}
				field = new OO.ui.FieldLayout( widget, {
					label: label,
					help: new OO.ui.HtmlSnippet( description )
				} );
				fieldset.addItems( [ field ] );
			} );
			if ( !fieldset.isEmpty() ) {
				$fieldsets.append( fieldset.$element );
			}
		} );
		return $fieldsets;
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.processTemplateData = function ( apiResponse ) {
		var id, templateData, description, templateLink, templateDataLink, helpLink, groupedParams;
		// Get the first page's template data.
		id = $.map( apiResponse.pages, function ( _value, key ) {
			return key;
		} );
		templateData = apiResponse.pages[ id ];

		// 1. Description.
		description = '';
		if ( templateData.description ) {
			description = templateData.description;
		} else if ( templateData.missing !== undefined || templateData.params === undefined ) {
			// Treat non-existant and non-TemplateData templates the same.
			templateLink = $( '<a>' )
				.attr( 'target', '_blank' )
				.attr( 'title', mw.message( 'templatewizard-opens-in-new-tab' ) )
				.attr( 'href', this.title.getUrl() )
				.text( '{{' + this.title.getMainText() + '}}' );
			templateDataLink = $( '<a>' )
				.attr( 'target', '_blank' )
				.attr( 'title', mw.message( 'templatewizard-opens-in-new-tab' ) )
				.attr( 'href', 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:TemplateData#Structure_of_TemplateData' )
				.text( 'TemplateData' );
			helpLink = $( '<a>' )
				.attr( 'target', '_blank' )
				.attr( 'title', 'Opens in new tab' )
				.attr( 'href', 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Extension:TemplateWizard' )
				.text( mw.message( 'templatewizard-help-page' ) );
			description = mw.message(
				'templatewizard-template-not-found',
				templateLink[ 0 ].outerHTML,
				templateDataLink[ 0 ].outerHTML,
				helpLink[ 0 ].outerHTML
			).plain();
		}
		if ( description ) {
			this.$element.append( $( '<p>' ).addClass( 'description' ).append( description ) );
		}

		// 2. Parameters.
		if ( templateData.params ) {
			groupedParams = this.processParameters( templateData.params );
			this.$element.append( this.getParameterFieldsets( groupedParams ) );
		}

		// 3. Format.
		if ( templateData.format ) {
			this.format = templateData.format;
		} else {
			this.format = 'inline';
		}
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.getParameters = function () {
		var params = {};
		this.$element.find( ':input' ).each( function () {
			var name = $( this ).attr( 'name' ),
				value = $( this ).val();
			if ( value ) {
				params[ name ] = value;
			}
		} );
		return params;
	};

	mediaWiki.TemplateWizard.TemplateForm.prototype.processParameters = function ( params ) {
		var groupedParams = {
			required: {},
			suggested: {},
			optional: {}
		};
		$.each( params, function ( param, details ) {
			if ( details.deprecated ) {
				// Don't include even a mention of a deprecated parameter.
				return;
			}
			if ( details.required ) {
				groupedParams.required[ param ] = details;
			} else if ( details.suggested ) {
				groupedParams.suggested[ param ] = details;
			} else {
				groupedParams.optional[ param ] = details;
			}
		} );
		return groupedParams;
	};

	/**
	 *
	 */
	mediaWiki.TemplateWizard.TemplateForm.prototype.loadTemplateData = function () {
		var templateForm = this;
		templateForm.dialog.pushPending();
		new mw.Api().get( {
			action: 'templatedata',
			titles: this.title.getPrefixedDb(),
			redirects: true,
			doNotIgnoreMissingTitles: true,
			lang: mw.config.get( 'wgUserLanguage' )
		} )
			.done( function ( apiResponse ) {
				var fieldsets = templateForm.processTemplateData( apiResponse );
				templateForm.$element.append( fieldsets );
			} )
			.always( function () {
				templateForm.dialog.popPending();
			} );
	};

	/**
	 * @class
	 * @constructor
	 * @param {Object} [config] Configuration options.
	 * @param {OO.ui.ProcessDialog} [dialog] The dialog to attach the form to.
	 */
	mediaWiki.TemplateWizard.SearchForm = function mediaWikiTemplateWizardSearchForm( config, dialog ) {
		config.padded = true;
		config.expanded = true;
		mediaWiki.TemplateWizard.SearchForm.super.call( this, config );
		this.dialog = dialog;

		this.titleSearchWidget = new mw.widgets.TitleInputWidget( {
			validate: true,
			namespace: mw.config.get( 'wgNamespaceIds' ).template
		} );
		this.titleSearchWidget.connect( this, { change: 'onSearchWidgetChange', enter: 'onSearchWidgetEnter' } );
		this.searchButton = new OO.ui.ButtonWidget( { label: OO.ui.deferMsg( 'templatewizard-use' ), flags: [ 'progressive' ] } );
		this.searchButton.connect( this, { click: 'onSearchButtonClick' } );
		this.searchField = new OO.ui.ActionFieldLayout(
			this.titleSearchWidget,
			this.searchButton,
			{ label: OO.ui.deferMsg( 'templatewizard-select-template' ) }
		);
		this.titleSearchWidget.emit( 'change' );
		this.$element.append( this.searchField.$element );
	};
	OO.inheritClass( mediaWiki.TemplateWizard.SearchForm, OO.ui.PanelLayout );

	mediaWiki.TemplateWizard.SearchForm.prototype.getTemplateForm = function () {
		return this.templateForm;
	};

	mediaWiki.TemplateWizard.SearchForm.prototype.onSearchButtonClick = function () {
		this.searchField.setErrors( [] );
		this.templateForm = new mw.TemplateWizard.TemplateForm();
		try {
			this.templateForm.setDialog( this.dialog );
			this.templateForm.setTitle( this.titleSearchWidget.value );
			this.dialog.setResultsPanel( this.templateForm.$element );
			this.dialog.actions.setMode( 'insert' );
		} catch ( e ) {
			this.titleSearchWidget.$input.focus();
			this.titleSearchWidget.$element.addClass( 'oo-ui-flaggedElement-invalid' );
			this.dialog.actions.setMode( 'choose' );
			this.searchField.setErrors( [ e.message ] );
		}
	};

	mediaWiki.TemplateWizard.SearchForm.prototype.onSearchWidgetChange = function () {
		this.titleSearchWidget.$element.removeClass( 'oo-ui-flaggedElement-invalid' );
		this.searchButton.setDisabled( !this.titleSearchWidget.value );
	};

	mediaWiki.TemplateWizard.SearchForm.prototype.onSearchWidgetEnter = function () {
		this.searchButton.$button.focus();
		this.searchButton.emit( 'click' );
	};

	/**
	 * @class
	 * @constructor
	 */
	mediaWiki.TemplateWizard.TemplateFormatter = function mwTemplateWizardTemplateFormatter() {
		this.name = '';
		this.format = '';
		this.params = {};
	};
	OO.initClass( mediaWiki.TemplateWizard.TemplateFormatter );
	mediaWiki.TemplateWizard.TemplateFormatter.static.FORMATSTRING_REGEXP =
		/^(\n)?(\{\{ *_+)(\n? *\|\n? *_+ *= *)(_+)(\n? *\}\})(\n)?$/;
	mediaWiki.TemplateWizard.TemplateFormatter.prototype.setTemplateName = function ( newName ) {
		this.name = newName;
	};
	mediaWiki.TemplateWizard.TemplateFormatter.prototype.setParameters = function ( params ) {
		this.params = params;
	};
	mediaWiki.TemplateWizard.TemplateFormatter.prototype.setFormat = function ( format ) {
		var parsedFormat,
			inlineFormat = '{{_|_=_}}';
		if ( format === 'inline' ) {
			format = inlineFormat;
		}
		if ( format === 'block' ) {
			format = '{{_\n| _ = _\n}}';
		}
		// Check format string for validity, and fall back to 'inline' if it's not.
		parsedFormat = format.match( this.constructor.static.FORMATSTRING_REGEXP );
		if ( !parsedFormat ) {
			parsedFormat = inlineFormat.match( this.constructor.static.FORMATSTRING_REGEXP );
		}
		this.format = {
			startOfLine: parsedFormat[ 1 ],
			start: parsedFormat[ 2 ],
			paramName: parsedFormat[ 3 ],
			paramValue: parsedFormat[ 4 ],
			end: parsedFormat[ 5 ],
			endOfLine: parsedFormat[ 6 ]
		};
	};
	mediaWiki.TemplateWizard.TemplateFormatter.prototype.getFormat = function () {
		if ( !this.format ) {
			this.setFormat( 'inline' );
		}
		return this.format;
	};
	mediaWiki.TemplateWizard.TemplateFormatter.prototype.getTemplate = function () {
		var template,
			formatter = this,
			format = this.getFormat();

		// Start building the template.
		template = '';
		if ( format.startOfLine ) {
			template += '\n';
		}
		template += this.constructor.static.formatStringSubst( format.start, this.name );

		// Process the parameters.
		$.each( formatter.params, function ( key, val ) {
			template += formatter.constructor.static.formatStringSubst( format.paramName, key ) +
				formatter.constructor.static.formatStringSubst( format.paramValue, val );
		} );

		// End and return the template.
		template += format.end;
		if ( format.endOfLine && !template.match( /\n$/ ) ) {
			template += '\n';
		}
		return template;
	};

	/**
	 * Format a part of the template, based on the TemplateData format string.
	 * This method is based on that of the same name in Parsoid:
	 * https://github.com/wikimedia/parsoid/blob/9c80dd597a8c057d43598303fd53e90cbed4ffdb/lib/html2wt/WikitextSerializer.js#L405
	 * @param {String} format
	 * @param {String} value
	 * @return {String}
	 */
	mediaWiki.TemplateWizard.TemplateFormatter.static.formatStringSubst = function ( format, value ) {
		value = value.trim();
		return format.replace( /_+/, function ( hole ) {
			if ( value === '' || hole.length <= value.length ) {
				return value;
			}
			// Right-pad with spaces.
			while ( value.length < hole.length ) {
				value += ' ';
			}
			return value; // + ( ' '.repeat( hole.length - value.length ) );
		} );
	};

	/**
	 * The main dialog box for the TemplateWizard.
	 * @class
	 * @constructor
	 * @extends OO.ui.ProcessDialog
	 * @param {object} config
	 */
	mediaWiki.TemplateWizard.Dialog = function mediaWikiTemplateWizardDialog( config ) {
		mediaWiki.TemplateWizard.Dialog.super.call( this, config );
	};
	OO.inheritClass( mediaWiki.TemplateWizard.Dialog, OO.ui.ProcessDialog );
	mediaWiki.TemplateWizard.Dialog.static.name = 'templateWizard';
	mediaWiki.TemplateWizard.Dialog.static.title = OO.ui.deferMsg( 'templatewizard-dialog-title' );
	mediaWiki.TemplateWizard.Dialog.static.actions = [
		{ label: OO.ui.deferMsg( 'templatewizard-insert' ), flags: [ 'primary', 'progressive' ], action: 'insert', modes: 'insert' },
		{ label: OO.ui.deferMsg( 'templatewizard-cancel' ), flags: 'safe', modes: [ 'choose', 'insert' ] }
	];
	mediaWiki.TemplateWizard.Dialog.prototype.getBodyHeight = function () {
		return 400;
	};
	mediaWiki.TemplateWizard.Dialog.prototype.initialize = function () {
		mediaWiki.TemplateWizard.Dialog.super.prototype.initialize.apply( this, arguments );

		// Set up the search form and results panel.
		this.searchForm = new mw.TemplateWizard.SearchForm( {}, this );
		this.resultsPanel = new OO.ui.PanelLayout( { padded: true, expanded: true } );

		// Put the panels together and add to the dialog body.
		this.stack = new OO.ui.StackLayout( { items: [ this.searchForm, this.resultsPanel ], continuous: true } );
		this.$body.append( this.stack.$element );
	};
	mediaWiki.TemplateWizard.Dialog.prototype.setResultsPanel = function ( panelContents ) {
		this.resultsPanel.$element.html( panelContents );
	};
	mediaWiki.TemplateWizard.Dialog.prototype.getSetupProcess = function ( data ) {
		return mediaWiki.TemplateWizard.Dialog.super.prototype.getSetupProcess.call( this, data )
			.next( function () {
				this.actions.setMode( 'choose' );
			}, this );
	};
	mediaWiki.TemplateWizard.Dialog.prototype.getActionProcess = function ( action ) {
		var dialog = this, templateFormatter;
		if ( action === 'insert' ) {
			templateFormatter = new mw.TemplateWizard.TemplateFormatter();
			templateFormatter.setTemplateName( this.searchForm.getTemplateForm().getTitle().getMainText() );
			templateFormatter.setFormat( this.searchForm.getTemplateForm().getFormat() );
			templateFormatter.setParameters( this.searchForm.getTemplateForm().getParameters() );
			$( '#wpTextbox1' ).textSelection( 'encapsulateSelection', { post: templateFormatter.getTemplate() } );
			return new OO.ui.Process( function () {
				dialog.close( { action: action } );
			} );
		}
		// Fallback to parent handler.
		return mediaWiki.TemplateWizard.Dialog.super.prototype.getActionProcess.call( this, action );
	};
	
	addButton();
}

	function addButton() {
		$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
			section: 'main',
			group: 'insert',
			tools: {
				'template-wizard': {
					labelMsg: 'templatewizard-dialog-title',
					type: 'button',
					icon: 'https://wiki.wiidatabase.de/images/e/ef/Puzzle.png',
					action: {
						type: 'callback',
						execute: function () {
							var templateWizard = new mw.TemplateWizard.Dialog(),
								windowManager = new OO.ui.WindowManager();
							$( 'body' ).append( windowManager.$element );
							windowManager.addWindows( [ templateWizard ] );
							windowManager.openWindow( templateWizard );
						}
					}
				}
			}
		} );
	}

	function main() {

		// @TODO $( '#wpTextbox1' ).on( 'wikiEditor-toolbar-doneInitialSections', addButton );

		var isEditing = $.inArray( mw.config.get( 'wgAction' ), [ 'edit', 'submit' ] ) !== -1;
		if ( !isEditing ) {
			return;
		}
		// Otherwise, add the toolbar button.
		mw.loader.using( 'user.options', function () {
			var dependencies;
			// This can be the string "0" if the user disabled the preference.
			if ( mw.user.options.get( 'usebetatoolbar' ) ) {
				dependencies = [
					'ext.wikiEditor',
					'jquery.textSelection',
					'oojs-ui-core',
					'oojs-ui-windows',
					'oojs-ui-widgets',
					'mediawiki.widgets',
					'mediawiki.widgets.UserInputWidget',
					'mediawiki.widgets.DateInputWidget'
				];
				mw.loader.using( dependencies, $.ready ).then( defineClasses );
			}
		} );
	}

	main();
// </nowiki>
}( mediaWiki, jQuery ) );