Jump to content

User:Mr. Stradivarius/gadgets/ConfirmRollback.js

From Wikipedia, the free encyclopedia
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.
// <nowiki>
/*                            ConfirmRollback
 * 
 * This script allows you to customise your rollback links. You can either
 * allow them, hide them, or ask for confirmation when you click them.
 * Furthermore, you can have different rollback settings for different pages,
 * and different settings for mobile and desktop devices.
 * 
 * To install, add the following to your [[Special:MyPage/skin.js]]:

importScript('User:Mr. Stradivarius/gadgets/ConfirmRollback.js') // Linkback: [[User:Mr. Stradivarius/gadgets/ConfirmRollback.js]]

 * See  [[User:Mr. Stradivarius/gadgets/ConfirmRollback]] for documentation.
 */

mw.loader.using( [ 'oojs-ui' ], function () {
	"use strict";

	// Get a rollback status of either "hide", "confirm" or "allow" for a given
	// page type and device type.
	function getRollbackStatus ( pageType, deviceType ) {
		var defaultConfig = {
			desktop: {
				watchlist: 'confirm',
				contributions: 'allow',
				recentchanges: 'allow',
				relatedchanges: 'allow',
				history: 'allow',
				diff: 'allow'
			},
			mobile: {
				watchlist: 'confirm',
				contributions: 'confirm',
				recentchanges: 'confirm',
				relatedchanges: 'confirm',
				history: 'confirm',
				diff: 'confirm'
			}
		};
		var scriptConfig = window.ConfirmRollback || {};
		var deviceDefaults = defaultConfig[ deviceType ];

		function resolveRollbackStatus ( cfg ) {
			// resolve the config object recursively. We need to be recursive
			// because the config syntax is very flexible.
			var ret;
			if ( typeof( cfg ) === 'object' ) {
				if ( cfg.mobile || cfg.desktop ) {
					return resolveRollbackStatus( cfg[ deviceType ] );
				} else {
					ret = cfg[ pageType ];
				}
			} else if ( cfg === 'hide' || cfg === 'allow' || cfg === 'confirm' ) {
				ret = cfg;
			}
			return ret || deviceDefaults[ pageType ] || 'confirm';
		}

		return resolveRollbackStatus( scriptConfig );
	}

	// Makes the message that says something like
	// "Revert 5 edits by Mr. Stradivarius?"
	function makeRollbackMessage( event ) {
		var targetText = $( event.target ).text();
		var count = targetText.match(/\d/) ? targetText.match(/\d+/)[0] : null;
		var edits = count ? count + ' edits' : 'edit';
		var user = mw.util.getParamValue( 'from', event.target.href );
		return 'Roll back ' + edits + ' by ' + user + '?';
	}

	// Handles rollback clicks on mobile devices. This uses the default browser
	// window.confirm dialog, as OO-js UI windows on mobile are tiny and
	// unreadable.
	function handleMobileClicks( $rollbackLinks ) {
		$rollbackLinks.click( function ( event ) {
			var message = makeRollbackMessage( event );
			if ( !confirm( message ) ) {
				return event.preventDefault();
			}
		} );
	}

	// Handle rollback clicks on desktop. This uses OO-js UI, which looks
	// pretty on desktops.
	function handleDesktopClicks( $rollbackLinks ) {
		// Initialize the dialog object.
		var confirmationDialog = new OO.ui.MessageDialog();
		var windowManager = new OO.ui.WindowManager();
		$( 'body' ).append( windowManager.$element );
		windowManager.addWindows( [ confirmationDialog ] );

		$rollbackLinks.click( function ( event ) {
			event.preventDefault();
			var message = makeRollbackMessage( event );
			windowManager.openWindow( confirmationDialog, {
				title: 'Confirm rollback',
				message: message,
				actions: [
					{ action: 'rollback', label: 'OK', flags: [ 'primary', 'destructive' ] },
					{ label: 'Cancel' }
				]
			} ).then( function ( opening ) {
				opening.then( function ( opened ) {
					opening.then( function ( closing, data ) {
						// The dialog is open. Check for the rollback action
						// and if detected, follow the original rollback link
						// URL.
						if ( data && data.action === 'rollback' ) {
							window.open( $( event.target ).attr( 'href' ), '_top' );
						}
					} );
				} );
			} );
		} );
	}

	var pageType, deviceType, rollbackStatus, $rollbackLinks;
	var mwConfig = mw.config.get( ['wgCanonicalSpecialPageName', 'wgAction'] );

	// Find the page type, and exit if we are not viewing a page on which
	// rollback links can appear.
	if ( mwConfig.wgCanonicalSpecialPageName === 'Watchlist' ) {
		pageType = 'watchlist';
	} else if ( mwConfig.wgCanonicalSpecialPageName === 'Contributions' ) {
		pageType = 'contributions';
	} else if ( mwConfig.wgCanonicalSpecialPageName === 'Recentchanges' ) {
		pageType = 'recentchanges';
	} else if ( mwConfig.wgCanonicalSpecialPageName === 'Recentchangeslinked' ) {
		pageType = 'relatedchanges';
	} else if ( mwConfig.wgAction === 'history' ) {
		pageType = 'history';
	} else if ( $( location ).attr( 'href' ).indexOf( '&diff' ) !== -1 ) {
		pageType = 'diff';
	} else {
		return;
	}

	deviceType = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent ) ? 'mobile' : 'desktop';
	rollbackStatus = getRollbackStatus( pageType, deviceType );
	$rollbackLinks = $( '.mw-rollback-link' );

	if ( rollbackStatus === 'hide' ) {
		$rollbackLinks.css( 'display', 'none' );
	} else if ( rollbackStatus === 'allow' ) {
		$rollbackLinks.css( 'display', 'inline' );
	} else if ( rollbackStatus === 'confirm' ) {
		// Display rollback links if they are hidden.
		$rollbackLinks.css( 'display', 'inline' );
		// Handle rollback clicks.
		if ( deviceType === 'mobile' ) {
			handleMobileClicks( $rollbackLinks );
		} else {
			handleDesktopClicks( $rollbackLinks );
		}
	}
} );

// </nowiki>