MediaWiki:Gadget-WikiSign.js

From Wikiversity
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/**
 * WikiSign is a tool for easy signing and voting in Wikipedia and other wikis
 * Authors: User:Sophivorus & User:Leoncastro
 * License: https://creativecommons.org/licenses/by-sa/3.0/
 */
window.WikiSign = {

	/**
	 * Internationalized messages
	 *
	 * @type {Object} Map from message key to value
	 */
	i18n: {
		dialogTitle: 'Add your signature',
		commentLabel: 'Comment (optional)',
		commentPlaceholder: 'Your comment will be shown next to your signature',
		nameLabel: 'Real name (optional)',
		watchLabel: 'Watch this page',
		signAction: 'Sign',
		signManuallyAction: 'Sign manually',
		cancelAction: 'Cancel',
		summary: 'Add my signature',
		error: 'There was an error while signing automatically.'
	},

	/**
	 * Configuration options
	 *
	 * @type {Object} Map from option key to value
	 */
	options: {
		buttonClassName: '.sign-button',
		validNamespaces: [ 0, 2, 4, 10, 102 ],
		signaturePrefix: '#',
		signatureSuffix: ''
	},

	/**
	 * Initialization script
	 */
	init: function () {
		var namespace = mw.config.get( 'wgNamespaceNumber' );
		if ( !WikiSign.options.validNamespaces.includes( namespace ) ) {
			return;
		}
		var $buttons = $( WikiSign.options.buttonClassName );
		if ( !$buttons.length ) {
			return;
		}
		var action = mw.config.get( 'wgAction' );
		if ( action !== 'view' ) {
			return;
		}
		mw.loader.using( [
			'mediawiki.api',
			'mediawiki.user',
			'oojs-ui-core',
			'oojs-ui-widgets',
			'oojs-ui-windows'
		] ).then( function () {
			$buttons.on( 'click', WikiSign.dialog );
		} );
	},

	/**
	 * Build the dialog
	 *
	 * @param {jQuery.Event} Click event
	 * @return {bool} false
	 */
	dialog: function ( event ) {
		var $button = $( this );
		var sectionCount;
		var sectionTitle;
		var $section = WikiSign.findClosestSection( $button );
		if ( $section ) {
			var sectionID = $section.find( '.mw-headline' ).attr( 'id' );
			$( '.mw-headline' ).each( function ( index ) {
				if ( $( this ).attr( 'id' ) === sectionID ) {
					sectionCount = index + 1;
					return false;
				}
			} );
			sectionTitle = $section.children( '.mw-headline' ).text();
		}
		var signaturePrefix = $button.data( 'sign-prefix' ) ? $button.data( 'sign-prefix' ) : WikiSign.options.signaturePrefix;
		var signatureSuffix = $button.data( 'sign-suffix' ) ? $button.data( 'sign-suffix' ) : WikiSign.options.signatureSuffix;
		var signature = '\n' + signaturePrefix + signatureSuffix + '~~' + '~~';

		// If commenting is disabled, sign immediately
		if ( $button.data( 'sign-no-comment' ) ) {
			WikiSign.sign( signature, sectionCount, sectionTitle );
			event.preventDefault();
			return false;
		}

		// Build the dialog
		var windowManager = new OO.ui.WindowManager();
		var messageDialog = new OO.ui.MessageDialog();
		$( 'body' ).append( windowManager.$element );
		windowManager.addWindows( [ messageDialog ] );
		var commentInput = new OO.ui.MultilineTextInputWidget( {
			placeholder: WikiSign.i18n.commentPlaceholder,
			required: $button.data( 'sign-comment-required' ) ? true : false,
			rows: 3
		} );
		var commentLayout = new OO.ui.FieldLayout( commentInput, { label: WikiSign.i18n.commentLabel, align: 'top' } );
		var nameInput = new OO.ui.TextInputWidget();
		var nameLayout = new OO.ui.FieldLayout( nameInput, { label: WikiSign.i18n.nameLabel, align: 'top' } );
		var fieldset = new OO.ui.FieldsetLayout( { classes: [ 'container' ], items: [ commentLayout, nameLayout ] } );
		if ( !mw.user.isAnon() ) {
			var watchCheckbox = new OO.ui.CheckboxInputWidget( { name: 'watch', selected: true } );
			var watchLayout = new OO.ui.FieldLayout( watchCheckbox, { label: WikiSign.i18n.watchLabel, align: 'inline' } );
			fieldset.addItems( watchLayout );
		}
		var form = new OO.ui.FormLayout( { items: [ fieldset ] } );
		var dialog = windowManager.openWindow( messageDialog, {
			title: WikiSign.i18n.dialogTitle,
			message: form.$element,
			actions: [
				{ label: WikiSign.i18n.signAction, action: 'sign', flags: 'progressive' },
				{ label: WikiSign.i18n.cancelAction },
			],
			size: 'medium',
		} );

		// Submit the data
		dialog.closed.then( function ( data ) {
			if ( data && data.action === 'sign' ) {
				var comment = commentInput.getValue().trim();
				var name = nameInput.getValue().trim();
				var signature = [ '\n' + signaturePrefix, comment, name, signatureSuffix, '~~' + '~~' ];
				signature = signature.filter( n => n ); // Remove empty elements
				signature = signature.join( ' ' );
				var watch = mw.user.isAnon() ? null : watchCheckbox.isSelected();
				WikiSign.sign( signature, sectionCount, sectionTitle, watch );
			}
			windowManager.destroy();
		} );

		event.preventDefault();
		return false;
	},

	/**
	 * Append the signature to the section or page
	 * @todo What if the button or some text is AFTER the list of signatures
	 *
	 * @param {string} Full signature to append
	 * @param {number} Section number where to append the signature
	 * @param {string} Section title where to append the signature
	 */
	sign: function ( signature, sectionCount, sectionTitle, watch ) {
		var api = new mw.Api();
		api.get( {
			format: 'json',
			formatversion: 2,
			action: 'parse',
			prop: 'wikitext',
			page: mw.config.get( 'wgPageName' ),
			section: sectionCount

		} ).then( function ( result ) {
			var wikitext = result.parse.wikitext;
			var summary = sectionTitle ? '/' + '* ' + sectionTitle + ' *' + '/ ' + WikiSign.i18n.summary : WikiSign.i18n.summary;
			api.postWithEditToken( {
				action: 'edit',
				title: mw.config.get( 'wgPageName' ),
				text: wikitext + signature,
				summary: summary,
				watchlist: watch ? 'watch' : 'nochange',
				section: sectionCount,

			} ).then( function ( data ) {
				// If we reach this point, all went well
				// so reload the page to show the signature to the user
				window.location.reload( true );

			} ).fail( function ( errorCode ) {
				// If we reach this point, something went wrong
				// but rather than show an unhelpful error code
				// prompt the user to sign manually
				var windowManager = new OO.ui.WindowManager();
				var messageDialog = new OO.ui.MessageDialog();
				$( 'body' ).append( windowManager.$element );
				windowManager.addWindows( [ messageDialog ] );
				var errorDialog = windowManager.openWindow( messageDialog, {
					message: WikiSign.i18n.error,
					actions: [
						{ label: WikiSign.i18n.signManuallyAction, action: 'signManually', flags: 'progressive' },
						{ label: WikiSign.i18n.cancelAction }
					]
				} );
				errorDialog.closed.then( function ( data ) {
					if ( data && data.action === 'signManually' ) {
						window.location.href = mw.util.getUrl( null, {
							action: 'edit',
							section: sectionCount ? sectionCount : null
						} );
					}
					windowManager.destroy();
				} );
			} );
		} );
	},

	/**
	 * Helper function to find the closest section
	 * by traversing back and up the DOM tree
	 *
	 * @param {jQuery object} Starting element
	 * @return {jQuery object} Closest section
	 */
	findClosestSection: function ( $element ) {
		if ( $element.attr( 'id' ) === 'mw-content-text' ) {
			return;
		}
		if ( $element.is( ':header' ) ) {
			return $element;
		}
		var $previous = $element.prevAll( ':header' ).first();
		if ( $previous.length ) {
			return $previous;
		}
		var $parent = $element.parent();
		return WikiSign.findClosestSection( $parent );
	}
};

$( WikiSign.init );