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.

// From [[WP:Kill-It-With-Fire]]







/*

* Kill-It-With-Fire

* Forked from Restore-a-lot which was in turn forked from Cat-a-lot

* Undo multiple edits from Special:Contributions

* See ? for documentation (that inspires confidence)

*

* @rev 00:13, 10 February 2018 (UTC)

* @author Originally by Magnus Manske (2007)

* @author RegExes by Ilmari Karonen (2010)

* @author Completely rewritten by DieBuche (2010-2012)

* @author Rillke (2012-2014)

* @author Perhelion (2017)

* @author Alexis Jazz is a forking idiot (Restore-a-lot, 2020)

* @author Various fixes by Zhuyifei1999 (Restore-a-lot, 2020)

* @author Alexis Jazz is screwing around again (Kill-It-With-Fire, 2022)

* <nowiki>

*/



/* global jQuery, mediaWiki */

/* eslint one-var:0, vars-on-top:0, no-underscore-dangle:0, valid-jsdoc:0,

curly:0, camelcase:0, no-useless-escape:0, no-alert:0 */ // extends: wikimedia

/* jshint unused:true, forin:false, smarttabs:true, loopfunc:true, browser:true */



( function ( $, mw ) {

'use strict';



var ns = mw.config.get( 'wgNamespaceNumber' );



var msgs = {

// Preferences

// new: added 2012-09-19. Please translate.

// Use user language for i18n

	'restore-a-lot-comment-label': 'Custom undo reason',

	'restore-a-lot-edit-question': 'Why is this undo necessary?',



	// Progress

	// 'restore-a-lot-loading': 'Loading …',

	'restore-a-lot-editing': 'Undoing edit',

	'restore-a-lot-of': 'of ',

	'restore-a-lot-skipped-server': 'The following {{PLURAL:$1|1=page|$1 pages}} couldn’t be changed, since there were problems connecting to the server:',

	'restore-a-lot-all-done': 'Selected revisions have been undone.',

	'restore-a-lot-done': 'Done!', // mw.msg("Feedback-close")

	'restore-a-lot-undelete': 'Revision undone',



	// as in 17 files selected

	'restore-a-lot-files-selected': '{{PLURAL:$1|1=One revision|$1 revisions}} selected.',



	// Actions

	'restore-a-lot-undeletelink': 'Undo',

	'restore-a-lot-instructions': 'Select revisions, hit undo.',

	'restore-a-lot-select': 'Select',

	'restore-a-lot-all': 'all',

	'restore-a-lot-none': 'none',

	// 'restore-a-lot-none-selected': 'No files selected!', 'Ooui-selectfile-placeholder'



	// Summaries (project language):

	'restore-a-lot-summary': 'Undo revision [[Special:Diff/REVID|REVID]] by [[User:USER|USER]] [Undone using [[w:en:WP:Kill-It-With-Fire|Kill-It-With-Fire]]]',

};

mw.messages.set( msgs );



function msg( /* params */ ) {

	var args = Array.prototype.slice.call( arguments, 0 );

	args 0  = 'restore-a-lot-' + args 0 ];

	return ( args.length === 1 ) ?

		mw.message( args 0  ).plain() :

		mw.message.apply( mw.message, args ).parse();

}



mw.util.addCSS(

'#killitwithfire {bottom: 0;display: block;position: fixed;left: 0;z-index: 100;padding: 5px;box-shadow: 0 2px 4px rgba(0,0,0,0.5); background-color: #FEF6E7;}'+

'#killitwithfire.ui-resizable {min-width:15em;}'+

'#killitwithfire_data, #killitwithfire_mark_counter {display: none;}'+

'#killitwithfire_data ul {list-style-image: none;list-style-type: none;margin: 0 0 0 5px;}'+

//'#killitwithfire_selections, #killitwithfire_mark_counter, #killitwithfire_settings {background: url(/w/skins/Vector/images/portal-break.png) no-repeat;padding: 5px;}'+

'#killitwithfire_remove {font-weight: bold;display: block;}'+

'a {cursor:pointer;}'+

'.killitwithfire_move, .killitwithfire_action {font-weight: bold;}'+

'.killitwithfire_feedback {border: 1px #A9DE16 solid !important;background: #EAF2CB /*url(//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif)*/ no-repeat 8px 14px !important;padding-left: 2.85em !important;padding-top: 10px !important;font-size: 1.1em !important;}'+

'.killitwithfire_done {background-image: url(//upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Dialog-apply.svg/50px-Dialog-apply.svg.png) !important;background-position: 8px 50% !important;padding-top: 0 !important;}'+

'#killitwithfire_searchcatname,#killitwithfire_comment {font-size: 112%;margin: -5px 0 5px -5px;width: 100%;}'+

'.skin-vector #killitwithfire {font-size: .75em;}'+

'.killitwithfire_markAsDone {background-color: #BBB !important;}'+

'.killitwithfire_selected {background-color: #DF6 !important;}'+

'#killitwithfire_no_found, #killitwithfire_last_selected, #killitwithfire_settings {font-weight:bold;}'+

'#killitwithfire_last_selected {outline:1px dotted #999;}'+

'#killitwithfire_category_list table {border-collapse: collapse;}'+

'#killitwithfire_category_list tr:hover {background-color: #fc3;}'+

'#killitwithfire_category_list {overflow: auto;}');



// There is only one Restore-a-lot on one page

var $body, $container, $dataContainer, $markCounter, $instructions, $selections,

	$selectFiles, $selectPages, $selectNone, $selectInvert, $head, $link;



var KIWF = mw.libs.restoreALot = {

	apiUrl: mw.util.wikiScript( 'api' ),

	origin: '',

	searchmode: false,

	version: '4.77',

	setHeight: 450,

	settings: '',



	init: function () {



		$body = $( document.body );

		$container = $( '<div>' )

			.attr( 'id', 'killitwithfire' )

			.appendTo( $body );

		$dataContainer = $( '<div>' )

			.attr( 'id', 'killitwithfire_data' )

			.appendTo( $container );

		$markCounter = $( '<div>' )

			.attr( 'id', 'killitwithfire_mark_counter' )

			.appendTo( $dataContainer );

		$instructions = $( '<div>' )

			.attr( 'id', 'killitwithfire_selections' )

			.text( msg( 'instructions' ) )

			.appendTo( $dataContainer );

		$selections = $( '<div>' )

			.attr( 'id', 'killitwithfire_selections' )

			.text( msg( 'select' ) + ':' )

			.appendTo( $dataContainer );

		$head = $( '<div>' )

			.attr( 'id', 'killitwithfire_head' )

			.appendTo( $container );

		$link = $( '<a>' )

			.attr( 'id', 'killitwithfire_toggle' )

			.text( 'Kill-It-With-Fire' )

			.appendTo( $head );

		$container.one( 'mouseover', function () { // Try load on demand earliest as possible

			mw.loader.load(  'jquery.ui' );

		} );



		$( '<a>' )

		// .attr( 'id', 'killitwithfire_select_all' )

			.text( msg( 'all' ) )

			.on( 'click', function () {

				KIWF.toggleAll( true );

			} )

			.appendTo( $selections.append( ' ' ) );

		if ( this.settings.editpages ) {

			$selectFiles = $( '<a>' )

				.on( 'click', function () {

					KIWF.toggleAll( 'files' );

				} );

			$selectPages = $( '<a>' )

				.on( 'click', function () {

					KIWF.toggleAll( 'pages' );

				} );

			$selections.append( $( '<span>' ).hide().append(  ' / ', $selectFiles, ' / ', $selectPages  ) );

		}

		$selectNone = $( '<a>' )

		// .attr( 'id', 'killitwithfire_select_none' )

			.text( msg( 'none' ) )

			.on( 'click', function () {

				KIWF.toggleAll( false );

			} );

		$selectInvert = $( '<a>' )

			.on( 'click', function () {

				KIWF.toggleAll( null );

			} );

		$selections.append(  ' • ', $selectNone, ' • ', $selectInvert );



		$('#killitwithfire_data').append(

			$( '<div>' ).append( 

				$( '<input>' )

					.attr( {

						id: 'killitwithfire_comment',

						tabindex: -1,

						type: 'text',

						placeholder: msg( 'comment-label' )

					} )

			 )

		);

		

		$selections.append( $( '<a>' )

			.text( msg( 'undeletelink' ) )

			.on( 'click', function () {

				KIWF.doSomething();

			} )

			.addClass( 'killitwithfire_action ui-button' )

			.css( { margin: '5px', padding: '2px' } )

		);



		$link

			.on( 'click', function () {

				$( this ).toggleClass( 'killitwithfire_enabled' );

				// Load autocomplete on demand

				mw.loader.using( 'jquery.ui' );



				if ( !KIWF.executed ) {

					$.when( mw.loader.using( 

						'jquery.ui',

						'jquery.ui',

						'jquery.ui',

						'mediawiki.api',

						'mediawiki.jqueryMsg'

					 ), $.ready )

						.then( function () {

							return new mw.Api().loadMessagesIfMissing( 

								'Cancel',

								'Mobile-frontend-return-to-page',

								'Ooui-selectfile-placeholder',

								// 'Visualeditor-clipboard-copy',

								'Prefs-files',

								'Categories',

								'Checkbox-invert',

								//'Apifeatureusage-warnings'

							 );

						} ).then( function () {

							KIWF.run();

						} );

				} else { KIWF.run(); }

			} );

		mw.loader.using( 'mediawiki.cookie', function () { // Let catAlot stay open

			var val = mw.cookie.get( 'catAlotO' );

			if ( val && Number( val ) === ns ) { $link.click(); }

		}

		);

	},



	findAllLabels: function ( searchmode ) {

	// It's possible to allow any kind of pages as well but what happens if you click on "select all" and don't expect it

		switch ( searchmode ) {

			case 'contribs':

				this.labels = this.labels.add( $( 'div.mw-body-content li' ) );

				break;

		}

	},



	/**

*  @brief Get rev from selected pages

*  @return [array] touple of page rev and $object

*/

	getMarkedLabels: function () {

		this.selectedLabels = this.labels.filter( '.killitwithfire_selected:visible' );

		return this.selectedLabels.map( function () {

			// this might select too much in cases currently unknown, does it even matter?

			// it was 'a.new[class$="title"]' previously but this doesn't work on DRs

			var label = $( this ), revHref = label0].querySelectorAll('.mw-changeslist-diff')[0].attributes.href;

			return   revHref, label  ];

		} );

	},



	updateSelectionCounter: function () {

		this.selectedLabels = this.labels.filter( '.killitwithfire_selected:visible' );

		var first = $markCounter.is( ':hidden' );

		$markCounter

			.html( msg( 'files-selected', this.selectedLabels.length ) )

			.show();

		if ( first && !$dataContainer.is( ':hidden' ) ) { // Workaround to fix position glitch

			first = $markCounter.innerHeight();

			$container

				.offset( { top: $container.offset().top - first } )

				.height( $container.height() + first );

			$( window ).on( 'beforeunload', function () {

				if ( KIWF.labels.filter( '.killitwithfire_selected:visible' )[ 0  ) { return 'You have pages selected!'; } // There is a default message in the browser

			} );

		}

	},



	makeClickable: function () {

		this.labels = $();

		this.pageLabels = $(); // only for distinct all selections

		this.findAllLabels( this.searchmode );

		this.labels.KIWFShiftClick( function () {

			KIWF.updateSelectionCounter();

		} )

			.addClass( 'killitwithfire_label' );

	},



	toggleAll: function ( select ) {

		if ( typeof select === 'string' && this.pageLabels 0  ) {

			this.pageLabels.toggleClass( 'killitwithfire_selected', true );

			if ( select === 'files' ) // pages get deselected

			{ this.labels.toggleClass( 'killitwithfire_selected' ); }

		} else {

		// invert / none / all

			this.labels.toggleClass( 'killitwithfire_selected', select );

		}

		this.updateSelectionCounter();

	},

	undeleteFile: function ( rev ) {

		var revIDToUndo;

		revIDToUndo = new mw.Uri(window.location.protocol+'//'+window.location.host+rev0].nodeValue).query.oldid;

		var sumCmt; // summary comment

		sumCmt = msg( 'summary' ).replace(/USER/g,mw.config.get('wgRelevantUserName')).replace(/REVID/g,revIDToUndo);

		sumCmt += this.summary ? ' ' + this.summary : '';

		var data = {

			action: 'edit',

			summary: sumCmt,

			title: new mw.Uri(window.location.protocol+'//'+window.location.host+rev0].nodeValue).query.title.replace(/_/g,' '),

			undo: revIDToUndo,

			token: this.edittoken

		};

		

		this.doAPICall( data, function ( r ) {

			delete KIWF.XHR rev 0  ];

			return KIWF.updateCounter( r );

		} );

		this.markAsDone( rev 1  );

	},



	markAsDone: function ( label ) {

		label.addClass( 'killitwithfire_markAsDone' ).append( '<br>' + msg( 'undelete' ) );

	},



	updateCounter: function () {

		this.counterCurrent++;

		if ( this.counterCurrent > this.counterNeeded ) { this.displayResult(); } else { this.domCounter.text( this.counterCurrent ); }

	},



	displayResult: function () {

		document.body.style.cursor = 'auto';

		this.progressDialog.parent()

			.addClass( 'killitwithfire_done' )

			.find( '.ui-dialog-buttonpane button span' ).eq( 0 )

			.text( mw.msg( 'Mobile-frontend-return-to-page' ) );

		var rep = this.domCounter.parent()

			.height( 'auto' )

			.html( '<h3>' + msg( 'done' ) + '</h3>' )

			.append( msg( 'all-done' ) + '<br>' );



		if ( this.connectionError.length ) {

			rep.append( '<h5>' + msg( 'skipped-server', this.connectionError.length ) + '</h5>' )

				.append( this.connectionError.join( '<br>' ) );

		}



	},



	doSomething: function () {

		var pages = this.getMarkedLabels();

		if ( !pages.length ) { return alert( mw.msg( 'Ooui-selectfile-placeholder' ) ); }



		this.connectionError = [];

		this.counterCurrent = 1;

		this.counterNeeded = pages.length;

		this.XHR = {};

		this.cancelled = 0;

		this.summary = '';



		if ( $( '#killitwithfire_comment' )[0].value != '' ) { this.summary = $( '#killitwithfire_comment' )[0].value; } // TODO custom pre-value



		if ( this.summary !== null ) {

			mw.loader.using(  'jquery.ui', 'mediawiki.util' ], function () {

				KIWF.showProgress();

				if ( !KIWF.cancelled ) {

					KIWF.doAPICall( {

						meta: 'tokens',

					}, function ( result ) {

						if ( !result || !result.query ) { return; }

						KIWF.edittoken = result.query.tokens.csrftoken;

						pages = Array.from( pages ).map( function ( page ) {

							return function () {

								var defer = $.Deferred();

								setTimeout( function timer() {

									KIWF.undeleteFile( page );

									defer.resolve();

								}, 0 );

								return defer;

							};

						} );



						var defer = pages.shift()();

						pages.map( function ( pagefunc ) {

							defer = defer.then( pagefunc );

						} );

					} );

				}

			} );

		}



	},



	doAPICall: function ( params, callback ) {

		params = $.extend( {

			action: 'query',

			format: 'json'

		}, params );



		var i = 0,

			apiUrl = this.apiUrl,

			doCall,

			handleError = function ( jqXHR, textStatus, errorThrown ) {

				mw.log( 'Error: ', jqXHR, textStatus, errorThrown );

				if ( i < 4 ) {

					window.setTimeout( doCall, 300 );

					i++;

				} else if ( params.undo ) {

					this.connectionError.push( params.undo );

					this.updateCounter();

					return;

				}

			};

		doCall = function () {

			var xhr = $.ajax( {

				url: apiUrl,

				cache: false,

				dataType: 'json',

				data: params,

				type: 'POST',

				success: callback,

				error: handleError

			} );



			if ( params.action === 'undelete' && !KIWF.cancelled ) { KIWF.XHR params.undo  = xhr; }

		};

		doCall();

	},



	doAbort: function () {

		for ( var t in this.XHR ) { this.XHR t ].abort(); }



		if ( this.cancelled ) { // still not for undo

			this.progressDialog.remove();

			this.toggleAll( false );

			$head.last().show();

		}

		this.cancelled = 1;

	},



	showProgress: function () {

		document.body.style.cursor = 'wait';

		this.progressDialog = $( '<div>' )

			.html( ' ' + msg( 'editing' ) + ' <span id="killitwithfire_current">' + KIWF.counterCurrent + '</span> ' + msg( 'of' ) + KIWF.counterNeeded )

			.dialog( {

				width: 450,

				height: 180,

				minHeight: 90,

				modal: true,

				resizable: false,

				draggable: false,

				// closeOnEscape: true,

				dialogClass: 'killitwithfire_feedback',

				buttons:  {

					text: mw.msg( 'Cancel' ), // Stops all actions

					click: function () {

						$( this ).dialog( 'close' );

					}

				} ],

				close: function () {

					KIWF.cancelled = 1;

					KIWF.doAbort();

					$( this ).remove();

				},

				open: function ( event, ui ) { // Workaround modify

					ui = $( this ).parent();

					ui.find( '.ui-dialog-titlebar' ).hide();

					ui.find( '.ui-dialog-buttonpane.ui-widget-content' )

						.removeClass( 'ui-widget-content' );

				/* .find( 'span' ).css( { fontSize: '90%' } )*/

				}

			} );

		if ( $head.children().length < 3 ) {

			$( '<span>' )

				.css( {

					'float': 'right',

					fontSize: '75%'

				} );

		}



		this.domCounter = $( '#killitwithfire_current' );

	},



	minimize: function ( e ) {

		KIWF.top = Math.max( 0, $container.position().top );

		KIWF.height = $container.height();

		$dataContainer.hide();

		$container.animate( {

			height: $head.height(),

			top: $( window ).height() - $head.height() * 1.4

		}, function () {

			$( e.target ).one( 'click', KIWF.maximize );

		} );

	},



	maximize: function ( e ) {

		$dataContainer.show();

		$container.animate( {

			top: KIWF.top,

			height: KIWF.height

		}, function () {

			$( e.target ).one( 'click', KIWF.minimize );

		} );

	},



	run: function () {

		if ( $( '.killitwithfire_enabled' )[ 0  ) {

			this.makeClickable();

			if ( !this.executed ) { // only once

				$selectInvert.text( mw.msg( 'Checkbox-invert' ) );

				if ( this.settings.editpages && this.pageLabels 0  ) {

					$selectFiles.text( mw.msg( 'Prefs-files' ) );

					$selectPages.text( mw.msg( 'Categories' ) ).parent().show();

				}

				//$link.after( $( '<a>' )

				//	.text( '–' )

				//	.css( { fontWeight: 'bold', marginLeft: '.7em' } )

				//	.one( 'click', this.minimize ),

				$link.after( $( '<a href="https://commons.wikimedia.org/wiki/Special:MyLanguage/Help:Gadget-Restore-a-lot">' )

					.text( 'Kill-It-With-Fire 0.1' )

					.css( { float: 'right' } )

				);

			}

			$dataContainer.show();

			$container.one( 'mouseover', function () {

				$( this )

					.resizable( {

						handles: 'n',

						alsoResize: '#killitwithfire_category_list',

						start: function ( e, ui ) { // Otherwise box get static if sametime resize with draggable

							ui.helper.css( {

								top: ui.helper.offset().top - $( window ).scrollTop(),

								position: 'fixed'

							} );

						},

					} )

					.draggable( {

						cursor: 'move',

						start: function ( e, ui ) {

							ui.helper.on( 'click.prevent',

								function ( e ) { e.preventDefault(); }

							);

							ui.helper.css( 'height', ui.helper.height() );

						},

						stop: function ( e, ui ) {

							setTimeout(

								function () {

									ui.helper.off( 'click.prevent' );

								}, 300

							);

						}

					} )

					.one( 'mousedown', function () {

						$container.height( $container.height() ); // Workaround to calculate

					} );

			} );



			$link.html( $( '<span>' )

				.text( '×' )

				.css( { font: 'bold 2em monospace', lineHeight: '.75em' } )

			);

			$link.next().show();

			if ( this.cancelled ) { $head.last().show(); }

			mw.cookie.set( 'catAlotO', ns ); // Let stay open on new window

		} else { // Reset

			$dataContainer.hide();

			$container

				.draggable( 'destroy' )

				.resizable( 'destroy' )

				.removeAttr( 'style' );

			// Unbind click handlers

			this.labels.off( 'click.KIWF' );

			this.setHeight = 450;

			$link.text( 'Kill-It-With-Fire' )

				.nextAll().hide();

			this.executed = 1;

			mw.cookie.set( 'catAlotO', null );

		}

	},

};



// The gadget is not immediately needed, so let the page load normally

window.setTimeout( function () {



	switch ( ns ) {

		case -1:

			KIWF.searchmode = {

				'Contributions': 'contribs',

			}[ mw.config.get( 'wgCanonicalSpecialPageName' ) ];

			break;

	}		



	if ( KIWF.searchmode ) {

		var maybeLaunch = function () {

			function init() {

				$( function () {

					KIWF.init();

				} );

			}

			mw.loader.using(  'user' ], init, init );

		};

		maybeLaunch();

	}

}, 400 );



/**

 * When clicking a restore-a-lot label with Shift pressed, select all labels between the current and last-clicked one.

 */

$.fn.KIWFShiftClick = function ( cb ) {

	var prevCheckbox = null,

		$box = this;

	// When our boxes are clicked..

	$box.on( 'click.KIWF', function ( e ) {

	// Prevent following the link and text selection

		if ( !e.ctrlKey ) { e.preventDefault(); }

		// Highlight last selected

		$( '#killitwithfire_last_selected' )

			.removeAttr( 'id' );

		var $thisControl = $( e.target ),

			method;

		if ( !$thisControl.hasClass( 'killitwithfire_label' ) ) { $thisControl = $thisControl.parents( '.killitwithfire_label' ); }



		$thisControl.attr( 'id', 'killitwithfire_last_selected' )

			.toggleClass( 'killitwithfire_selected' );

		// And one has been clicked before…

		if ( prevCheckbox !== null && e.shiftKey ) {

			method = $thisControl.hasClass( 'killitwithfire_selected' ) ? 'addClass' : 'removeClass';

			// Check or uncheck this one and all in-between checkboxes

			$box.slice(

				Math.min( $box.index( prevCheckbox ), $box.index( $thisControl ) ),

				Math.max( $box.index( prevCheckbox ), $box.index( $thisControl ) ) + 1

			)[ method ]( 'killitwithfire_selected' );

		}

		// Either way, update the prevCheckbox variable to the one clicked now

		prevCheckbox = $thisControl;

		if ( $.isFunction( cb ) ) { cb(); }

	} );

	return $box;

};



}( jQuery, mediaWiki ) );

// </nowiki>
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.

// From [[WP:Kill-It-With-Fire]]







/*

* Kill-It-With-Fire

* Forked from Restore-a-lot which was in turn forked from Cat-a-lot

* Undo multiple edits from Special:Contributions

* See ? for documentation (that inspires confidence)

*

* @rev 00:13, 10 February 2018 (UTC)

* @author Originally by Magnus Manske (2007)

* @author RegExes by Ilmari Karonen (2010)

* @author Completely rewritten by DieBuche (2010-2012)

* @author Rillke (2012-2014)

* @author Perhelion (2017)

* @author Alexis Jazz is a forking idiot (Restore-a-lot, 2020)

* @author Various fixes by Zhuyifei1999 (Restore-a-lot, 2020)

* @author Alexis Jazz is screwing around again (Kill-It-With-Fire, 2022)

* <nowiki>

*/



/* global jQuery, mediaWiki */

/* eslint one-var:0, vars-on-top:0, no-underscore-dangle:0, valid-jsdoc:0,

curly:0, camelcase:0, no-useless-escape:0, no-alert:0 */ // extends: wikimedia

/* jshint unused:true, forin:false, smarttabs:true, loopfunc:true, browser:true */



( function ( $, mw ) {

'use strict';



var ns = mw.config.get( 'wgNamespaceNumber' );



var msgs = {

// Preferences

// new: added 2012-09-19. Please translate.

// Use user language for i18n

	'restore-a-lot-comment-label': 'Custom undo reason',

	'restore-a-lot-edit-question': 'Why is this undo necessary?',



	// Progress

	// 'restore-a-lot-loading': 'Loading …',

	'restore-a-lot-editing': 'Undoing edit',

	'restore-a-lot-of': 'of ',

	'restore-a-lot-skipped-server': 'The following {{PLURAL:$1|1=page|$1 pages}} couldn’t be changed, since there were problems connecting to the server:',

	'restore-a-lot-all-done': 'Selected revisions have been undone.',

	'restore-a-lot-done': 'Done!', // mw.msg("Feedback-close")

	'restore-a-lot-undelete': 'Revision undone',



	// as in 17 files selected

	'restore-a-lot-files-selected': '{{PLURAL:$1|1=One revision|$1 revisions}} selected.',



	// Actions

	'restore-a-lot-undeletelink': 'Undo',

	'restore-a-lot-instructions': 'Select revisions, hit undo.',

	'restore-a-lot-select': 'Select',

	'restore-a-lot-all': 'all',

	'restore-a-lot-none': 'none',

	// 'restore-a-lot-none-selected': 'No files selected!', 'Ooui-selectfile-placeholder'



	// Summaries (project language):

	'restore-a-lot-summary': 'Undo revision [[Special:Diff/REVID|REVID]] by [[User:USER|USER]] [Undone using [[w:en:WP:Kill-It-With-Fire|Kill-It-With-Fire]]]',

};

mw.messages.set( msgs );



function msg( /* params */ ) {

	var args = Array.prototype.slice.call( arguments, 0 );

	args 0  = 'restore-a-lot-' + args 0 ];

	return ( args.length === 1 ) ?

		mw.message( args 0  ).plain() :

		mw.message.apply( mw.message, args ).parse();

}



mw.util.addCSS(

'#killitwithfire {bottom: 0;display: block;position: fixed;left: 0;z-index: 100;padding: 5px;box-shadow: 0 2px 4px rgba(0,0,0,0.5); background-color: #FEF6E7;}'+

'#killitwithfire.ui-resizable {min-width:15em;}'+

'#killitwithfire_data, #killitwithfire_mark_counter {display: none;}'+

'#killitwithfire_data ul {list-style-image: none;list-style-type: none;margin: 0 0 0 5px;}'+

//'#killitwithfire_selections, #killitwithfire_mark_counter, #killitwithfire_settings {background: url(/w/skins/Vector/images/portal-break.png) no-repeat;padding: 5px;}'+

'#killitwithfire_remove {font-weight: bold;display: block;}'+

'a {cursor:pointer;}'+

'.killitwithfire_move, .killitwithfire_action {font-weight: bold;}'+

'.killitwithfire_feedback {border: 1px #A9DE16 solid !important;background: #EAF2CB /*url(//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif)*/ no-repeat 8px 14px !important;padding-left: 2.85em !important;padding-top: 10px !important;font-size: 1.1em !important;}'+

'.killitwithfire_done {background-image: url(//upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Dialog-apply.svg/50px-Dialog-apply.svg.png) !important;background-position: 8px 50% !important;padding-top: 0 !important;}'+

'#killitwithfire_searchcatname,#killitwithfire_comment {font-size: 112%;margin: -5px 0 5px -5px;width: 100%;}'+

'.skin-vector #killitwithfire {font-size: .75em;}'+

'.killitwithfire_markAsDone {background-color: #BBB !important;}'+

'.killitwithfire_selected {background-color: #DF6 !important;}'+

'#killitwithfire_no_found, #killitwithfire_last_selected, #killitwithfire_settings {font-weight:bold;}'+

'#killitwithfire_last_selected {outline:1px dotted #999;}'+

'#killitwithfire_category_list table {border-collapse: collapse;}'+

'#killitwithfire_category_list tr:hover {background-color: #fc3;}'+

'#killitwithfire_category_list {overflow: auto;}');



// There is only one Restore-a-lot on one page

var $body, $container, $dataContainer, $markCounter, $instructions, $selections,

	$selectFiles, $selectPages, $selectNone, $selectInvert, $head, $link;



var KIWF = mw.libs.restoreALot = {

	apiUrl: mw.util.wikiScript( 'api' ),

	origin: '',

	searchmode: false,

	version: '4.77',

	setHeight: 450,

	settings: '',



	init: function () {



		$body = $( document.body );

		$container = $( '<div>' )

			.attr( 'id', 'killitwithfire' )

			.appendTo( $body );

		$dataContainer = $( '<div>' )

			.attr( 'id', 'killitwithfire_data' )

			.appendTo( $container );

		$markCounter = $( '<div>' )

			.attr( 'id', 'killitwithfire_mark_counter' )

			.appendTo( $dataContainer );

		$instructions = $( '<div>' )

			.attr( 'id', 'killitwithfire_selections' )

			.text( msg( 'instructions' ) )

			.appendTo( $dataContainer );

		$selections = $( '<div>' )

			.attr( 'id', 'killitwithfire_selections' )

			.text( msg( 'select' ) + ':' )

			.appendTo( $dataContainer );

		$head = $( '<div>' )

			.attr( 'id', 'killitwithfire_head' )

			.appendTo( $container );

		$link = $( '<a>' )

			.attr( 'id', 'killitwithfire_toggle' )

			.text( 'Kill-It-With-Fire' )

			.appendTo( $head );

		$container.one( 'mouseover', function () { // Try load on demand earliest as possible

			mw.loader.load(  'jquery.ui' );

		} );



		$( '<a>' )

		// .attr( 'id', 'killitwithfire_select_all' )

			.text( msg( 'all' ) )

			.on( 'click', function () {

				KIWF.toggleAll( true );

			} )

			.appendTo( $selections.append( ' ' ) );

		if ( this.settings.editpages ) {

			$selectFiles = $( '<a>' )

				.on( 'click', function () {

					KIWF.toggleAll( 'files' );

				} );

			$selectPages = $( '<a>' )

				.on( 'click', function () {

					KIWF.toggleAll( 'pages' );

				} );

			$selections.append( $( '<span>' ).hide().append(  ' / ', $selectFiles, ' / ', $selectPages  ) );

		}

		$selectNone = $( '<a>' )

		// .attr( 'id', 'killitwithfire_select_none' )

			.text( msg( 'none' ) )

			.on( 'click', function () {

				KIWF.toggleAll( false );

			} );

		$selectInvert = $( '<a>' )

			.on( 'click', function () {

				KIWF.toggleAll( null );

			} );

		$selections.append(  ' • ', $selectNone, ' • ', $selectInvert );



		$('#killitwithfire_data').append(

			$( '<div>' ).append( 

				$( '<input>' )

					.attr( {

						id: 'killitwithfire_comment',

						tabindex: -1,

						type: 'text',

						placeholder: msg( 'comment-label' )

					} )

			 )

		);

		

		$selections.append( $( '<a>' )

			.text( msg( 'undeletelink' ) )

			.on( 'click', function () {

				KIWF.doSomething();

			} )

			.addClass( 'killitwithfire_action ui-button' )

			.css( { margin: '5px', padding: '2px' } )

		);



		$link

			.on( 'click', function () {

				$( this ).toggleClass( 'killitwithfire_enabled' );

				// Load autocomplete on demand

				mw.loader.using( 'jquery.ui' );



				if ( !KIWF.executed ) {

					$.when( mw.loader.using( 

						'jquery.ui',

						'jquery.ui',

						'jquery.ui',

						'mediawiki.api',

						'mediawiki.jqueryMsg'

					 ), $.ready )

						.then( function () {

							return new mw.Api().loadMessagesIfMissing( 

								'Cancel',

								'Mobile-frontend-return-to-page',

								'Ooui-selectfile-placeholder',

								// 'Visualeditor-clipboard-copy',

								'Prefs-files',

								'Categories',

								'Checkbox-invert',

								//'Apifeatureusage-warnings'

							 );

						} ).then( function () {

							KIWF.run();

						} );

				} else { KIWF.run(); }

			} );

		mw.loader.using( 'mediawiki.cookie', function () { // Let catAlot stay open

			var val = mw.cookie.get( 'catAlotO' );

			if ( val && Number( val ) === ns ) { $link.click(); }

		}

		);

	},



	findAllLabels: function ( searchmode ) {

	// It's possible to allow any kind of pages as well but what happens if you click on "select all" and don't expect it

		switch ( searchmode ) {

			case 'contribs':

				this.labels = this.labels.add( $( 'div.mw-body-content li' ) );

				break;

		}

	},



	/**

*  @brief Get rev from selected pages

*  @return [array] touple of page rev and $object

*/

	getMarkedLabels: function () {

		this.selectedLabels = this.labels.filter( '.killitwithfire_selected:visible' );

		return this.selectedLabels.map( function () {

			// this might select too much in cases currently unknown, does it even matter?

			// it was 'a.new[class$="title"]' previously but this doesn't work on DRs

			var label = $( this ), revHref = label0].querySelectorAll('.mw-changeslist-diff')[0].attributes.href;

			return   revHref, label  ];

		} );

	},



	updateSelectionCounter: function () {

		this.selectedLabels = this.labels.filter( '.killitwithfire_selected:visible' );

		var first = $markCounter.is( ':hidden' );

		$markCounter

			.html( msg( 'files-selected', this.selectedLabels.length ) )

			.show();

		if ( first && !$dataContainer.is( ':hidden' ) ) { // Workaround to fix position glitch

			first = $markCounter.innerHeight();

			$container

				.offset( { top: $container.offset().top - first } )

				.height( $container.height() + first );

			$( window ).on( 'beforeunload', function () {

				if ( KIWF.labels.filter( '.killitwithfire_selected:visible' )[ 0  ) { return 'You have pages selected!'; } // There is a default message in the browser

			} );

		}

	},



	makeClickable: function () {

		this.labels = $();

		this.pageLabels = $(); // only for distinct all selections

		this.findAllLabels( this.searchmode );

		this.labels.KIWFShiftClick( function () {

			KIWF.updateSelectionCounter();

		} )

			.addClass( 'killitwithfire_label' );

	},



	toggleAll: function ( select ) {

		if ( typeof select === 'string' && this.pageLabels 0  ) {

			this.pageLabels.toggleClass( 'killitwithfire_selected', true );

			if ( select === 'files' ) // pages get deselected

			{ this.labels.toggleClass( 'killitwithfire_selected' ); }

		} else {

		// invert / none / all

			this.labels.toggleClass( 'killitwithfire_selected', select );

		}

		this.updateSelectionCounter();

	},

	undeleteFile: function ( rev ) {

		var revIDToUndo;

		revIDToUndo = new mw.Uri(window.location.protocol+'//'+window.location.host+rev0].nodeValue).query.oldid;

		var sumCmt; // summary comment

		sumCmt = msg( 'summary' ).replace(/USER/g,mw.config.get('wgRelevantUserName')).replace(/REVID/g,revIDToUndo);

		sumCmt += this.summary ? ' ' + this.summary : '';

		var data = {

			action: 'edit',

			summary: sumCmt,

			title: new mw.Uri(window.location.protocol+'//'+window.location.host+rev0].nodeValue).query.title.replace(/_/g,' '),

			undo: revIDToUndo,

			token: this.edittoken

		};

		

		this.doAPICall( data, function ( r ) {

			delete KIWF.XHR rev 0  ];

			return KIWF.updateCounter( r );

		} );

		this.markAsDone( rev 1  );

	},



	markAsDone: function ( label ) {

		label.addClass( 'killitwithfire_markAsDone' ).append( '<br>' + msg( 'undelete' ) );

	},



	updateCounter: function () {

		this.counterCurrent++;

		if ( this.counterCurrent > this.counterNeeded ) { this.displayResult(); } else { this.domCounter.text( this.counterCurrent ); }

	},



	displayResult: function () {

		document.body.style.cursor = 'auto';

		this.progressDialog.parent()

			.addClass( 'killitwithfire_done' )

			.find( '.ui-dialog-buttonpane button span' ).eq( 0 )

			.text( mw.msg( 'Mobile-frontend-return-to-page' ) );

		var rep = this.domCounter.parent()

			.height( 'auto' )

			.html( '<h3>' + msg( 'done' ) + '</h3>' )

			.append( msg( 'all-done' ) + '<br>' );



		if ( this.connectionError.length ) {

			rep.append( '<h5>' + msg( 'skipped-server', this.connectionError.length ) + '</h5>' )

				.append( this.connectionError.join( '<br>' ) );

		}



	},



	doSomething: function () {

		var pages = this.getMarkedLabels();

		if ( !pages.length ) { return alert( mw.msg( 'Ooui-selectfile-placeholder' ) ); }



		this.connectionError = [];

		this.counterCurrent = 1;

		this.counterNeeded = pages.length;

		this.XHR = {};

		this.cancelled = 0;

		this.summary = '';



		if ( $( '#killitwithfire_comment' )[0].value != '' ) { this.summary = $( '#killitwithfire_comment' )[0].value; } // TODO custom pre-value



		if ( this.summary !== null ) {

			mw.loader.using(  'jquery.ui', 'mediawiki.util' ], function () {

				KIWF.showProgress();

				if ( !KIWF.cancelled ) {

					KIWF.doAPICall( {

						meta: 'tokens',

					}, function ( result ) {

						if ( !result || !result.query ) { return; }

						KIWF.edittoken = result.query.tokens.csrftoken;

						pages = Array.from( pages ).map( function ( page ) {

							return function () {

								var defer = $.Deferred();

								setTimeout( function timer() {

									KIWF.undeleteFile( page );

									defer.resolve();

								}, 0 );

								return defer;

							};

						} );



						var defer = pages.shift()();

						pages.map( function ( pagefunc ) {

							defer = defer.then( pagefunc );

						} );

					} );

				}

			} );

		}



	},



	doAPICall: function ( params, callback ) {

		params = $.extend( {

			action: 'query',

			format: 'json'

		}, params );



		var i = 0,

			apiUrl = this.apiUrl,

			doCall,

			handleError = function ( jqXHR, textStatus, errorThrown ) {

				mw.log( 'Error: ', jqXHR, textStatus, errorThrown );

				if ( i < 4 ) {

					window.setTimeout( doCall, 300 );

					i++;

				} else if ( params.undo ) {

					this.connectionError.push( params.undo );

					this.updateCounter();

					return;

				}

			};

		doCall = function () {

			var xhr = $.ajax( {

				url: apiUrl,

				cache: false,

				dataType: 'json',

				data: params,

				type: 'POST',

				success: callback,

				error: handleError

			} );



			if ( params.action === 'undelete' && !KIWF.cancelled ) { KIWF.XHR params.undo  = xhr; }

		};

		doCall();

	},



	doAbort: function () {

		for ( var t in this.XHR ) { this.XHR t ].abort(); }



		if ( this.cancelled ) { // still not for undo

			this.progressDialog.remove();

			this.toggleAll( false );

			$head.last().show();

		}

		this.cancelled = 1;

	},



	showProgress: function () {

		document.body.style.cursor = 'wait';

		this.progressDialog = $( '<div>' )

			.html( ' ' + msg( 'editing' ) + ' <span id="killitwithfire_current">' + KIWF.counterCurrent + '</span> ' + msg( 'of' ) + KIWF.counterNeeded )

			.dialog( {

				width: 450,

				height: 180,

				minHeight: 90,

				modal: true,

				resizable: false,

				draggable: false,

				// closeOnEscape: true,

				dialogClass: 'killitwithfire_feedback',

				buttons:  {

					text: mw.msg( 'Cancel' ), // Stops all actions

					click: function () {

						$( this ).dialog( 'close' );

					}

				} ],

				close: function () {

					KIWF.cancelled = 1;

					KIWF.doAbort();

					$( this ).remove();

				},

				open: function ( event, ui ) { // Workaround modify

					ui = $( this ).parent();

					ui.find( '.ui-dialog-titlebar' ).hide();

					ui.find( '.ui-dialog-buttonpane.ui-widget-content' )

						.removeClass( 'ui-widget-content' );

				/* .find( 'span' ).css( { fontSize: '90%' } )*/

				}

			} );

		if ( $head.children().length < 3 ) {

			$( '<span>' )

				.css( {

					'float': 'right',

					fontSize: '75%'

				} );

		}



		this.domCounter = $( '#killitwithfire_current' );

	},



	minimize: function ( e ) {

		KIWF.top = Math.max( 0, $container.position().top );

		KIWF.height = $container.height();

		$dataContainer.hide();

		$container.animate( {

			height: $head.height(),

			top: $( window ).height() - $head.height() * 1.4

		}, function () {

			$( e.target ).one( 'click', KIWF.maximize );

		} );

	},



	maximize: function ( e ) {

		$dataContainer.show();

		$container.animate( {

			top: KIWF.top,

			height: KIWF.height

		}, function () {

			$( e.target ).one( 'click', KIWF.minimize );

		} );

	},



	run: function () {

		if ( $( '.killitwithfire_enabled' )[ 0  ) {

			this.makeClickable();

			if ( !this.executed ) { // only once

				$selectInvert.text( mw.msg( 'Checkbox-invert' ) );

				if ( this.settings.editpages && this.pageLabels 0  ) {

					$selectFiles.text( mw.msg( 'Prefs-files' ) );

					$selectPages.text( mw.msg( 'Categories' ) ).parent().show();

				}

				//$link.after( $( '<a>' )

				//	.text( '–' )

				//	.css( { fontWeight: 'bold', marginLeft: '.7em' } )

				//	.one( 'click', this.minimize ),

				$link.after( $( '<a href="https://commons.wikimedia.org/wiki/Special:MyLanguage/Help:Gadget-Restore-a-lot">' )

					.text( 'Kill-It-With-Fire 0.1' )

					.css( { float: 'right' } )

				);

			}

			$dataContainer.show();

			$container.one( 'mouseover', function () {

				$( this )

					.resizable( {

						handles: 'n',

						alsoResize: '#killitwithfire_category_list',

						start: function ( e, ui ) { // Otherwise box get static if sametime resize with draggable

							ui.helper.css( {

								top: ui.helper.offset().top - $( window ).scrollTop(),

								position: 'fixed'

							} );

						},

					} )

					.draggable( {

						cursor: 'move',

						start: function ( e, ui ) {

							ui.helper.on( 'click.prevent',

								function ( e ) { e.preventDefault(); }

							);

							ui.helper.css( 'height', ui.helper.height() );

						},

						stop: function ( e, ui ) {

							setTimeout(

								function () {

									ui.helper.off( 'click.prevent' );

								}, 300

							);

						}

					} )

					.one( 'mousedown', function () {

						$container.height( $container.height() ); // Workaround to calculate

					} );

			} );



			$link.html( $( '<span>' )

				.text( '×' )

				.css( { font: 'bold 2em monospace', lineHeight: '.75em' } )

			);

			$link.next().show();

			if ( this.cancelled ) { $head.last().show(); }

			mw.cookie.set( 'catAlotO', ns ); // Let stay open on new window

		} else { // Reset

			$dataContainer.hide();

			$container

				.draggable( 'destroy' )

				.resizable( 'destroy' )

				.removeAttr( 'style' );

			// Unbind click handlers

			this.labels.off( 'click.KIWF' );

			this.setHeight = 450;

			$link.text( 'Kill-It-With-Fire' )

				.nextAll().hide();

			this.executed = 1;

			mw.cookie.set( 'catAlotO', null );

		}

	},

};



// The gadget is not immediately needed, so let the page load normally

window.setTimeout( function () {



	switch ( ns ) {

		case -1:

			KIWF.searchmode = {

				'Contributions': 'contribs',

			}[ mw.config.get( 'wgCanonicalSpecialPageName' ) ];

			break;

	}		



	if ( KIWF.searchmode ) {

		var maybeLaunch = function () {

			function init() {

				$( function () {

					KIWF.init();

				} );

			}

			mw.loader.using(  'user' ], init, init );

		};

		maybeLaunch();

	}

}, 400 );



/**

 * When clicking a restore-a-lot label with Shift pressed, select all labels between the current and last-clicked one.

 */

$.fn.KIWFShiftClick = function ( cb ) {

	var prevCheckbox = null,

		$box = this;

	// When our boxes are clicked..

	$box.on( 'click.KIWF', function ( e ) {

	// Prevent following the link and text selection

		if ( !e.ctrlKey ) { e.preventDefault(); }

		// Highlight last selected

		$( '#killitwithfire_last_selected' )

			.removeAttr( 'id' );

		var $thisControl = $( e.target ),

			method;

		if ( !$thisControl.hasClass( 'killitwithfire_label' ) ) { $thisControl = $thisControl.parents( '.killitwithfire_label' ); }



		$thisControl.attr( 'id', 'killitwithfire_last_selected' )

			.toggleClass( 'killitwithfire_selected' );

		// And one has been clicked before…

		if ( prevCheckbox !== null && e.shiftKey ) {

			method = $thisControl.hasClass( 'killitwithfire_selected' ) ? 'addClass' : 'removeClass';

			// Check or uncheck this one and all in-between checkboxes

			$box.slice(

				Math.min( $box.index( prevCheckbox ), $box.index( $thisControl ) ),

				Math.max( $box.index( prevCheckbox ), $box.index( $thisControl ) ) + 1

			)[ method ]( 'killitwithfire_selected' );

		}

		// Either way, update the prevCheckbox variable to the one clicked now

		prevCheckbox = $thisControl;

		if ( $.isFunction( cb ) ) { cb(); }

	} );

	return $box;

};



}( jQuery, mediaWiki ) );

// </nowiki>

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook