משתמש:מגזין יהלום/VandalCleaner.js

מתוך אקו-ויקי, מקום מפגש בנושאי אקולוגיה, חברה וכלכלה.
קפיצה לניווט קפיצה לחיפוש

הערה: לאחר השמירה, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.

  • פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload), או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
  • גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
  • אינטרנט אקספלורר: להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh), או ללחוץ על צירוף המקשים Ctrl-F5.
  • אופרה: לפתוח תפריט ← הגדרות (במחשב מק: Opera ← העדפות) ואז ללחוץ על פרטיות ואבטחה ← מחק היסטוריית גלישה ← Cached images and files.
/* עדכנתי ב-26/10/2019 */
/* הסקריפט המקורי עבר לסקריפט 107 */
/* [[מדיה ויקי:סקריפטים/107.js]]

/* שחזור אוטומטי לעריכות טרולים */
/* סקריפט שגיא בנה, הוא מיועד למחזיקים בהרשאות שחזור מהיר */
/* [[משתמש:Guycn2]]  */
/* לאחר הוספתו נוסף לדף התרומות של משתמשים שאינם בדוקי עריכות כפתור בשם "טיפול מהיר בהשחתות" וזה במכה משחזר את כל העריכות של המשתמש  */
/* (בהנחה והן הגרסאות האחרונות) */
/* המילים "שחזור אוטומטי עצבני לעריכות טרולים" הן אופציונליות, ומהוות את תקציר העריכה לשחזורים */
/* הכפתור הזה משחזר את כל הערכים שנערכו על ידי המשחית + מוחק את כל הדפים שלו + חוסם אותו */
/* שתי האופציות האחרונות הן רק למפעילים) */
/* 24/06/2018 [[שיחת משתמש:דגש חזק#שחזור אוטומטי לעריכות טרולים]] */
/* 24/06/2018 [[שיחת משתמש:Guycn2#הגדרת התקציר בכלי הטרולים]] */
/* 20-24/06/2018 [[ויקיפדיה:פיתוח התשתית#כלי לטיפול מהיר בטרולים ובהשחתות]]
/* כל הסקריפט נמצא בקישור */
/* Https://he.wikibooks.org/w/index.php?title=משתמש:Guycn2/VandalCleaner.js&action=raw&ctype=text/javascript */
/* :והמקור שלו */
/* !!! בויקיספר */
/* [[B:משתמש:Guycn2/VandalCleaner.js]] */
/* קישור ישיר */
/* Https://he.wikibooks.org/wiki/משתמש:Guycn2/VandalCleaner.js */

/*

This tool allows you to handle vandalism more easily.

It adds a link on "Contribution" pages, that let you rollback all edits made by the user/IP address, delete all pages created by them, and block them – all in one operation.

Written by: [[User:Guycn2]] (from he.wikipedia.org)


Dependencies: mediawiki.util, mediawiki.api, jquery.ui

If you export this script to your wiki, please include the above lines.

*/

$.when(mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.ui']), $.ready).then(function () {
	
	'use strict';
	
	var relevantUser = mw.config.get('wgRelevantUserName'),
	    currentUserRights,
	    relevantUserGender,
	    isRelevantUserAnon = mw.util.isIPAddress(relevantUser),
	    queryLimit = 70,
	    latestEdits,
	    totalEdits,
	    createdPages,
	    totalPages,
	    isRollbackChecked = false,
	    isDeleteChecked = false,
	    isBlockChecked = false,
	    cleanerSummary,
	    blockDuration = isRelevantUserAnon ? '3days' : 'infinite',
	    editNumber = 0,
	    rollbackPercent = 0,
	    failedRollbacks = false,
	    pageNumber = 0,
	    deletePercent = 0,
	    failedDeletions = false;
	
	if (mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') {
		
		new mw.Api().get({
			action: 'query',
			list: 'users',
			usprop: 'rights|gender',
			ususers: relevantUser + '|' + mw.config.get('wgUserName')
		}).then(function (data) {
			
			var relevantUserRights = data.query.users[0].rights;
			
			currentUserRights = data.query.users[1].rights, relevantUserGender = data.query.users[0].gender;
			
			if (isRelevantUserAnon || (typeof relevantUserRights !== 'undefined' && relevantUserRights.indexOf('editautopatrolprotected') < 0)) {
				
				$('div#contentSub a:last').after(
					$('<a>')
						.text(i18n('contribsLinkText'))
						.attr({'id': 'vandal-cleaner-link', 'title': i18n('contribsLinkTooltip')})
						.on('click', initializeTool)
				).after(' | ');
				
			}
			
		});
		
	}
	
	function i18n(key) {
		
		switch (mw.config.get('wgUserLanguage')) {
			default:
				switch (key) {
					case 'contribsLinkText': return 'Vandal Cleaner';
					case 'contribsLinkTooltip': return 'Quickly undo all actions made by this ' + (isRelevantUserAnon ? 'IP address' : 'user');
					case 'para1': return 'Welcome to Vandal Cleaner!';
					case 'para2': return 'You can use this tool to quickly revert all actions made by this ' + (isRelevantUserAnon ? 'IP address' : 'user') + ' (' + relevantUser + ').';
					case 'para3': return 'Please select the actions you want to do below.';
					case 'rollbackLabel': return 'Rollback all edits';
					case 'rollbackDesc': return 'Revert all edits made by this ' + (isRelevantUserAnon ? 'IP address' : 'user') + '.';
					case 'cannotRollback': return 'Rollback right is required to perform this operation.';
					case 'tooManyEdits': return 'Warning: This ' + (isRelevantUserAnon ? 'IP address' : 'user') + ' appears to have made more than ' + queryLimit.toString() + ' edits that haven\'t yet been reverted. For performance reasons and to avoid unconstructive usage, this tool will only rollback the latest ' + queryLimit.toString() + ' edits. If appropriate, you will be able to run Vandal Cleaner again after it has been finished running.';
					case 'deleteLabel': return 'Delete all pages';
					case 'deleteDesc': return 'Delete all pages created by this ' + (isRelevantUserAnon ? 'IP address' : 'user') + '.';
					case 'cannotDelete': return 'Delete right is required to perform this operation.';
					case 'tooManyPages': return 'Warning: This ' + (isRelevantUserAnon ? 'IP address' : 'user') + ' appears to have created more than ' + queryLimit.toString() + ' pages that haven\'t yet been deleted. For performance reasons and to avoid unconstructive usage, this tool will only delete the latest ' + queryLimit.toString() + ' pages. If appropriate, you will be able to run Vandal Cleaner again after it has been finished running.';
					case 'blockLabel': return 'Block this ' + (isRelevantUserAnon ? 'IP address' : 'user');
					case 'blockDesc': return 'Block ' + relevantUser + ' from editing. Account creation, sending email and editing own talk page will be blocked as well. Both registered and unregistered users using this IP address will be blocked.';
					case 'blockDuration': return 'Block duration';
					case 'changeBlockDuration': return 'change';
					case 'cannotBlock': return 'Block right is required to perform this operation.';
					case 'blockTwoHours': return '2 hours';
					case 'blockOneDay': return '1 day';
					case 'blockThreeDays': return '3 days';
					case 'blockOneWeek': return '1 week';
					case 'blockTwoWeeks': return '2 weeks';
					case 'blockOneMonth': return '1 month';
					case 'blockThreeMonths': return '3 months';
					case 'blockSixMonths': return '6 months';
					case 'blockOneYear': return '1 year';
					case 'blockIndefinite': return 'indefinite';
					case 'summaryInfo': return 'You may set an edit summary for all actions checked above. The default summary is "' + i18n('summaryValue') + '".';
					case 'summaryPlaceholder': return 'Enter summary here';
					case 'summaryValue': return window.vandalCleanerSummary || 'Vandalism';
					case 'dialogTitle': return 'Vandal Cleaner';
					case 'runCleaner': return 'Run cleaner';
					case 'cancel': return 'Cancel';
					case 'noActionSelected': return 'No action selected!';
					case 'pleaseWait': return 'Please wait...';
					case 'blocking': return 'Blocking ' + relevantUser;
					case 'blockFailed': return 'Could not block ' + relevantUser + '. ' + (relevantUserGender === 'female' ? 'She' : (relevantUserGender === 'male' ? 'He' : 'They')) + ' may have already been blocked by someone else.';
					case 'rollbacking': return 'Reverting edits made by ' + relevantUser;
					case 'rollbackNoEdits': return 'Either ' + relevantUser + ' has not made any edit, or all edits have already been undone.';
					case 'rollbackFailed': return 'Some edits could not be reverted. They may have already been undone or changed by someone else.';
					case 'deleting': return 'Deleting pages created by ' + relevantUser;
					case 'deleteNoPages': return 'Either ' + relevantUser + ' has not created any pages, or all pages have already been deleted.';
					case 'deleteFailed': return 'Some pages could not be deleted. They may have already been deleted by someone else.';
					case 'finishedRunning': return 'Vandal Cleaner has finished running.';
					case 'para4': return 'Thank you for using this tool. Please make sure all actions were performed intentionally and correctly.';
					case 'para5': return 'If you found any errors or malfunctions in this tool, please report them in the appropriate talk page.';
					case 'para6': return 'Keep up your good job of protecting ' + mw.config.get('wgSiteName') + ' from vandalism!';
					case 'para7': return 'To close this dialog, click the button below.';
					case 'closeAndReload': return 'Close & reload';
				}
				break;
			case 'he':
				switch (key) {
					case 'contribsLinkText': return 'טיפול מהיר בהשחתות';
					case 'contribsLinkTooltip': return 'ביטול מיידי של כל הפעולות שנעשו על־ידי ' + (isRelevantUserAnon ? 'כתובת IP זו' : (relevantUserGender === 'female' ? 'משתמשת זו' : 'משתמש זה'));
					case 'para1': return 'ברוך בואך לכלי הטיפול המהיר בהשחתות!';
					case 'para2': return 'ניתן להשתמש בכלי זה כדי לבטל את כל הפעולות שנעשו על־ידי ' + (isRelevantUserAnon ? 'כתובת IP זו' : (relevantUserGender === 'female' ? 'משתמשת זו' : 'משתמש זה')) + ' (' + relevantUser + ') באופן מיידי.';
					case 'para3': return 'נא לבחור את הפעולות שברצונך לעשות להלן.';
					case 'rollbackLabel': return 'שחזור כל העריכות';
					case 'rollbackDesc': return 'שחזור כל העריכות שנעשו על־ידי ' + (isRelevantUserAnon ? 'כתובת IP זו' : (relevantUserGender === 'female' ? 'משתמשת זו' : 'משתמש זה')) + '.';
					case 'cannotRollback': return 'נדרשת הרשאת שחזור מהיר כדי לבצע פעולה זו.';
					case 'tooManyEdits': return 'אזהרה: נראה ' + (isRelevantUserAnon ? 'שנעשו מכתובת IP זו' : (relevantUserGender === 'female' ? 'שמשתמשת זו ביצעה' : 'שמשתמש זה ביצע')) + ' יותר מ־' + queryLimit.toString() + ' עריכות שעדיין לא שוחזרו. מסיבות של ביצועים וכדי למנוע שימוש בלתי־יעיל, הכלי הזה ישחזר רק את ' + queryLimit.toString() + ' העריכות האחרונות. במידת הצורך, ניתן יהיה להפעיל את הכלי מחדש לאחר סיום פעולתו.';
					case 'deleteLabel': return 'מחיקת כל הדפים';
					case 'deleteDesc': return 'מחיקת כל הדפים שנוצרו על־ידי ' + (isRelevantUserAnon ? 'כתובת IP זו' : (relevantUserGender === 'female' ? 'משתמשת זו' : 'משתמש זה')) + '.';
					case 'cannotDelete': return 'נדרשת הרשאת מחיקה כדי לבצע פעולה זו.';
					case 'tooManyPages': return 'אזהרה: נראה ' + (isRelevantUserAnon ? 'שנוצרו מכתובת IP זו' : (relevantUserGender === 'female' ? 'שמשתמשת זו יצרה' : 'שמשתמש זה יצר')) + ' יותר מ־' + queryLimit.toString() + ' דפים שעדיין לא נמחקו. מסיבות של ביצועים וכדי למנוע שימוש בלתי־יעיל, הכלי הזה ימחק רק את ' + queryLimit.toString() + ' הדפים האחרונים. במידת הצורך, ניתן יהיה להפעיל את הכלי מחדש לאחר סיום פעולתו.';
					case 'blockLabel': return 'חסימת ' + (isRelevantUserAnon ? 'כתובת IP זו' : (relevantUserGender === 'female' ? 'משתמשת זו' : 'משתמש זה'));
					case 'blockDesc': return 'חסימת ' + relevantUser + ' מעריכה. יצירת חשבונות, שליחת דוא"ל ועריכת דף השיחה האישי תיחסמנה גם הן. גם משתמשים רשומים וגם משתמשים אנונימיים המשתמשים בכתובת IP זו ייחסמו.';
					case 'blockDuration': return 'משך החסימה';
					case 'changeBlockDuration': return 'שינוי';
					case 'cannotBlock': return 'נדרשת הרשאת חסימה כדי לבצע פעולה זו.';
					case 'blockTwoHours': return 'שעתיים';
					case 'blockOneDay': return 'יום';
					case 'blockThreeDays': return 'שלושה ימים';
					case 'blockOneWeek': return 'שבוע';
					case 'blockTwoWeeks': return 'שבועיים';
					case 'blockOneMonth': return 'חודש';
					case 'blockThreeMonths': return 'שלושה חודשים';
					case 'blockSixMonths': return 'שישה חודשים';
					case 'blockOneYear': return 'שנה';
					case 'blockIndefinite': return 'זמן בלתי מוגבל';
					case 'summaryInfo': return 'באפשרותך להזין תקציר עריכה עבור כל הפעולות המסומנות למעלה. תקציר ברירת המחדל הוא "' + i18n('summaryValue') + '".';
					case 'summaryPlaceholder': return 'יש להזין את התקציר כאן';
					case 'summaryValue': return window.vandalCleanerSummary || 'שחזור אוטומטי עצבני לעריכות טרולים';
					case 'dialogTitle': return 'טיפול מהיר בהשחתות';
					case 'runCleaner': return 'הפעלת הכלי';
					case 'cancel': return 'ביטול';
					case 'noActionSelected': return 'לא נבחרו פעולות!';
					case 'pleaseWait': return 'נא להמתין...';
					case 'blocking': return 'חסימת ' + relevantUser;
					case 'blockFailed': return 'לא ניתן היה לחסום את ' + relevantUser + '. ייתכן ' + (relevantUserGender === 'female' ? 'שהיא כבר נחסמה' : 'שהוא כבר נחסם') + ' על־ידי מישהו אחר.';
					case 'rollbacking': return 'שחזור העריכות שנעשו על־ידי ' + relevantUser;
					case 'rollbackNoEdits': return 'נראה ש־' + relevantUser + ' לא ' + (relevantUserGender === 'female' ? 'ביצעה' : 'ביצע') + ' שום עריכה, או שכל העריכות כבר שוחזרו.';
					case 'rollbackFailed': return 'לא ניתן היה לשחזר עריכות מסוימות. ייתכן שהן כבר שוחזרו או שונו על־ידי מישהו אחר.';
					case 'deleting': return 'מחיקת דפים שנוצרו על־ידי ' + relevantUser;
					case 'deleteNoPages': return 'נראה ש־' + relevantUser + ' לא ' + (relevantUserGender === 'female' ? 'יצרה' : 'יצר') + ' שום דף, או שכל הדפים כבר נמחקו.';
					case 'deleteFailed': return 'לא ניתן היה למחוק דפים מסוימים. ייתכן שהם כבר נמחקו על־ידי מישהו אחר.';
					case 'finishedRunning': return 'כלי הטיפול המהיר בהשחתות סיים לבצע את הפעולות.';
					case 'para4': return 'תודה שהשתמשת בכלי זה. נא לוודא שכל הפעולות בוצעו במכוון ובאופן תקין.';
					case 'para5': return 'אם מצאת שגיאות או תקלות כלשהן בכלי זה, נא לדווח עליהן בדף השיחה של הסקריפט.';
					case 'para6': return 'ישר כוח על עבודתך בהגנה על ' + mw.config.get('wgSiteName') + ' מפני השחתות!';
					case 'para7': return 'כדי לסגור את תיבת הדו־שיח הזו, יש ללחוץ על הכפתור "סגירה ורענון".';
					case 'closeAndReload': return 'סגירה ורענון';
				}
		}
		
		return key;
		
	}
	
	function initializeTool() {
		
		if (!$('#vandal-cleaner-dialog1').length) {
			
			new mw.Api().get({
				action: 'query',
				list: 'usercontribs',
				ucuser: relevantUser,
				ucprop: 'title',
				ucshow: 'top|!new',
				uclimit: queryLimit
			}).then(function (firstQuery) {
				
				latestEdits = firstQuery.query.usercontribs,
				totalEdits = latestEdits.length;
				
				new mw.Api().get({
					action: 'query',
					list: 'usercontribs',
					ucuser: relevantUser,
					ucprop: 'title',
					ucshow: 'new',
					uclimit: queryLimit
				}).then(function (secondQuery) {
					
					createdPages = secondQuery.query.usercontribs,
					totalPages = createdPages.length;
					
					createDialog();
					
				});
				
			});
			
		}
		else {
			console.log('Vandal Cleaner dialog is already open.');
		}
		
	}
	
	function createDialog() {
		
		var solidSeparator = '<div style="border: .3px solid lightgray; width: 100%; margin-bottom: 5px; margin-top: 4px;"></div>',
		    dashedSeparator = '<div style="border: .4px dashed lightgray; width: 100%; margin-bottom: 5px; margin-top: 4px;"></div>',
		    para1 = '<p>' + i18n('para1') + '</p>',
		    para2 = '<p>' + i18n('para2') + '</p>',
		    para3 = '<p>' + i18n('para3') + '</p>',
		    rollback = createCheckbox(
		               'rollback',
		               i18n('rollbackLabel'),
		               i18n('rollbackDesc') + '<br>' +
		               '<strong style="color: darkred;">' + (currentUserRights.indexOf('rollback') < 0 ? i18n('cannotRollback') : (totalEdits >= queryLimit ? i18n('tooManyEdits') : '')) + '</strong>'
		               ),
		    massDelete = createCheckbox(
		                 'delete',
		                 i18n('deleteLabel'),
		                 i18n('deleteDesc') + '<br>' +
		                 '<strong style="color: darkred;">' + (currentUserRights.indexOf('delete') < 0 ? i18n('cannotDelete') : (totalPages >= queryLimit ? i18n('tooManyPages') : '')) + '</strong>'
		                 ),
		    block = createCheckbox(
		            'block',
		            i18n('blockLabel'),
		            i18n('blockDesc') + '<br>' +
		            (currentUserRights.indexOf('block') < 0
			            ? '<strong style="color: darkred;">' + i18n('cannotBlock') + '</strong>'
			            : '<span id="block-duration-container" style="color: #4d4d4d;"><strong>' + i18n('blockDuration') + '</strong>: <span id="block-duration">' + (isRelevantUserAnon ? i18n('blockThreeDays') : i18n('blockIndefinite')) + ' (<a>' + i18n('changeBlockDuration') + '</a>)' + '</span></span>'
		            )
		            ),
		    summary = '<p>' + i18n('summaryInfo') + '</p>' +
		              '<input type="text" id="vandal-cleaner-summary" style="width: 70%;" placeholder="' + i18n('summaryPlaceholder') + '" value="' + i18n('summaryValue') + '" maxlength="500">',
		    htmlForm = para1 + para2 + para3 + solidSeparator + rollback + dashedSeparator + massDelete + dashedSeparator + block + solidSeparator + summary;
		
		$('<div>', {id: 'vandal-cleaner-dialog1'}).html(htmlForm).dialog({
			
			title: i18n('dialogTitle'),
			resizable: false,
			width: (window.orientation === 90 || window.orientation === -90) ? '640px' : '480px',
			open: function () {
				mw.util.addCSS('#block-duration-container { display: none; }');
				
				if (currentUserRights.indexOf('rollback') < 0) {
					$(this).find('#rollback-cbx').attr('disabled', true);
					$(this).find('label[for="rollback-cbx"]').css('color', 'grey');
				}
				else {
					$(this).find('#rollback-cbx').attr('checked', true);
				}
				
				if (currentUserRights.indexOf('delete') < 0) {
					$(this).find('#delete-cbx').attr('disabled', true);
					$(this).find('label[for="delete-cbx"]').css('color', 'grey');
				}
				else {
					$(this).find('#delete-cbx').attr('checked', true);
				}
				
				if (currentUserRights.indexOf('block') < 0) {
					$(this).find('#block-cbx').attr('disabled', true);
					$(this).find('label[for="block-cbx"]').css('color', 'grey');
				}
				else {
					$(this).find('#block-cbx').attr('checked', true);
					$(this).find('#block-duration a').on('click', function () {
						$('#block-duration').html($('<select>', {id: 'block-duration-dropdown'}).html(
							'<option value="2hours">' + i18n('blockTwoHours') + '</option>' +
							'<option value="1day">' + i18n('blockOneDay') + '</option>' +
							'<option value="3days"' + (isRelevantUserAnon ? ' selected' : '') + '>' + i18n('blockThreeDays') + '</option>' +
							'<option value="1week">' + i18n('blockOneWeek') + '</option>' +
							'<option value="2weeks">' + i18n('blockTwoWeeks') + '</option>' +
							'<option value="1month">' + i18n('blockOneMonth') + '</option>' +
							'<option value="3months">' + i18n('blockThreeMonths') + '</option>' +
							'<option value="6months">' + i18n('blockSixMonths') + '</option>' +
							'<option value="1year">' + i18n('blockOneYear') + '</option>' +
							'<option value="infinite"' + (isRelevantUserAnon ? '' : ' selected') + '>' + i18n('blockIndefinite') + '</option>'
						));
					});
					var blockOptionsToggle = mw.util.addCSS('#block-duration-container { display: inline; }');
					$(this).find('#block-cbx').on('change', function () {
						blockOptionsToggle.disabled = !blockOptionsToggle.disabled;
					});
				}
				
				if (typeof window.orientation === 'undefined') {
					$(this).find('#vandal-cleaner-summary').focus();
				}
			},
			close: function () {
				$(this).remove();
			},
			buttons: [
				{
					text: i18n('runCleaner'),
					style: 'font-weight: bold;',
					click: runCleaner
				},
				{
					text: i18n('cancel'),
					click: function () {
						$(this).dialog('close');
					}
				}
			]
			
		}).keypress(function (event) {
			if (event.which === 13) {
				runCleaner();
			}
		});
		
	}
	
	function createCheckbox(action, title, description) {
		
		return '<table><tr><td rowspan="2" style="vertical-align: top;">' +
		       '<input type="checkbox" id="' + action + '-cbx">' +
		       '</td><td>' +
		       '<label for="' + action + '-cbx" style="font-weight: bold;">' + title + '</label>' +
		       '</td></tr><tr><td style="font-size: 85%; color: grey;">' +
		       description +
		       '</td></tr></table>';
		
	}
	
	function runCleaner() {
		
		isRollbackChecked = document.getElementById('rollback-cbx').checked,
		isDeleteChecked = document.getElementById('delete-cbx').checked,
		isBlockChecked = document.getElementById('block-cbx').checked,
		cleanerSummary = $('#vandal-cleaner-summary').val();
		
		if ($('#vandal-cleaner-dialog1').find('#block-duration-dropdown').val()) {
			blockDuration = $('#block-duration-dropdown').val();
		}
		
		if (isBlockChecked || isRollbackChecked || isDeleteChecked) {
			
			if (isBlockChecked) {
				hermeticBlock();
			}
			else if (isRollbackChecked) {
				massRollback();
			}
			else if (isDeleteChecked) {
				massDelete();
			}
			
			var pleaseWait = '<h5>' + i18n('pleaseWait') + '</h5>',
			    statusImg = '<img src="//upload.wikimedia.org/wikipedia/commons/7/7a/Ajax_loader_metal_512.gif" style="width: 17px; margin: 6px;">',
			    infoImg = '<img src="//upload.wikimedia.org/wikipedia/commons/e/e1/Info.svg" style="width: 14px; margin: 6px;">',
			    warningImg = '<img src="//upload.wikimedia.org/wikipedia/commons/3/3b/OOjs_UI_icon_alert-warning.svg" style="width: 14px; margin: 6px;">',
			    blocking = '<p id="block-status">' + statusImg + i18n('blocking') + ' <span style="font-weight: normal;">... (<span id="block-percent" style="unicode-bidi: isolate;">0%</span>)' + '</span></p>',
			    blockFail = '<p id="block-fail" style="font-weight: normal;">' + warningImg + i18n('blockFailed') + '</p>',
			    rollbacking = '<p id="rollback-status">' + statusImg + i18n('rollbacking') + ' <span style="font-weight: normal;">... (<span id="rollback-percent" style="unicode-bidi: isolate;">0%</span>)' + '</span></p>',
			    rollbackNoEdits = '<p id="rollback-no-edits" style="font-weight: normal;">' + infoImg + i18n('rollbackNoEdits') + '</p>',
			    rollbackFail = '<p id="rollback-fail" style="font-weight: normal;">' + warningImg + i18n('rollbackFailed') + '</p>',
			    deleting = '<p id="delete-status">' + statusImg + i18n('deleting') + ' <span style="font-weight: normal;">... (<span id="delete-percent" style="unicode-bidi: isolate;">0%</span>)' + '</span></p>',
			    deleteNoPages = '<p id="delete-no-pages" style="font-weight: normal;">' + infoImg + i18n('deleteNoPages') + '</p>',
			    deleteFail = '<p id="delete-fail" style="font-weight: normal;">' + warningImg + i18n('deleteFailed') + '</p>';
			
			$('#vandal-cleaner-dialog1').html(pleaseWait + blocking + blockFail + rollbacking + rollbackNoEdits + rollbackFail + deleting + deleteNoPages + deleteFail).dialog({
				buttons: [],
				close: function () {
					window.location.reload();
				}
			});
			
			mw.util.addCSS('#vandal-cleaner-dialog1 p { display: none; font-weight: bold; }');
			
		}
		else {
			alert(i18n('noActionSelected'));
		}
		
	}
	
	function hermeticBlock() {
		
		mw.util.addCSS('#block-status { display: block !important; }');
		
		new mw.Api().postWithToken('csrf', {
			action: 'block',
			user: relevantUser,
			expiry: blockDuration,
			nocreate: 1,
			autoblock: 1,
			noemail: 1,
			reblock: 1,
			reason: cleanerSummary
			//tags: 'VandalCleaner'
		}).then(function () {
			
			$('#block-status img').attr('src', '//upload.wikimedia.org/wikipedia/commons/8/8f/Checkmark.svg');
			$('#block-percent').text('100%');
			mw.util.addCSS('#block-status { font-weight: normal !important; }');
			
			setTimeout(function () {
				moveOn('block');
			}, 800);
			
		}).fail(function () {
			
			mw.util.addCSS('#block-status { display: none !important; } #block-fail { display: block !important; }');
			
			setTimeout(function () {
				moveOn('block');
			}, 800);
			
		});
		
	}
	
	function massRollback() {
		
		if (totalEdits === 0) {
			mw.util.addCSS('#rollback-no-edits { display: block !important; }');
		}
		
		if (editNumber < totalEdits) {
			
			mw.util.addCSS('#rollback-status { display: block !important; }');
			
			new mw.Api().postWithToken('rollback', {
				action: 'rollback',
				title: latestEdits[editNumber].title,
				user: relevantUser,
				summary: cleanerSummary
				//tags: 'VandalCleaner'
			}).then(function () {
				moveOn('rollback');
			}).fail(function () {
				failedRollbacks = true;
				moveOn('rollback');
			});
			
		}
		else {
			
			$('#rollback-status img').attr('src', '//upload.wikimedia.org/wikipedia/commons/8/8f/Checkmark.svg');
			mw.util.addCSS('#rollback-status { font-weight: normal !important; }');
			
			if (failedRollbacks) {
				mw.util.addCSS('#rollback-fail { display: block !important; }');
			}
			
			setTimeout(function () {
				if (isDeleteChecked) {
					massDelete();
				}
				else {
					setTimeout(allDone, 1500);
				}
			}, 800);
			
		}
		
	}
	
	function massDelete() {
		
		if (totalPages === 0) {
			mw.util.addCSS('#delete-no-pages { display: block !important; }');
		}
		
		if (pageNumber < totalPages) {
			
			mw.util.addCSS('#delete-status { display: block !important; }');
			
			new mw.Api().postWithToken('csrf', {
				action: 'delete',
				title: createdPages[pageNumber].title,
				reason: cleanerSummary
				//tags: 'VandalCleaner'
			}).then(function () {
				moveOn('delete');
			}).fail(function () {
				failedDeletions = true;
				moveOn('delete');
			});
			
		}
		else {
			
			$('#delete-status img').attr('src', '//upload.wikimedia.org/wikipedia/commons/8/8f/Checkmark.svg');
			mw.util.addCSS('#delete-status { font-weight: normal !important; }');
			
			if (failedDeletions) {
				mw.util.addCSS('#delete-fail { display: block !important; }');
			}
			
			setTimeout(allDone, 2000);
			
		}
		
	}
	
	function moveOn(currentAction) {
		
		switch (currentAction) {
			case 'block':
				if (isRollbackChecked) {
					massRollback();
				}
				else if (isDeleteChecked) {
					massDelete();
				}
				else {
					setTimeout(allDone, 1500);
				}
				break;
			case 'rollback':
				editNumber++;
				rollbackPercent = editNumber / totalEdits * 100;
				$('#rollback-percent').text(rollbackPercent.toFixed(0) + '%');
				setTimeout(massRollback, 800);
				break;
			case 'delete':
				pageNumber++;
				deletePercent = pageNumber / totalPages * 100;
				$('#delete-percent').text(deletePercent.toFixed(0) + '%');
				setTimeout(massDelete, 800);
		}
		
	}
	
	function allDone() {
		
		$('#vandal-cleaner-dialog1').remove();
		
		setTimeout(function () {
			
			$('<div>', {id: 'vandal-cleaner-dialog2'})
				.html(
					
					'<img src="//upload.wikimedia.org/wikipedia/commons/c/ce/Emoji_u1f44d.svg" style="opacity: 0.8;">' +
					'<h6 style="color: green;">' + i18n('finishedRunning') + '</h6>' +
					'<p>' + i18n('para4') + '</p>' +
					'<p>' + i18n('para5') + '</p>' +
					'<p>' + i18n('para6') + '</p>' +
					'<p>' + i18n('para7') + '</p>'
					
				).dialog({
					
					title: i18n('dialogTitle'),
					resizable: false,
					width: '520px',
					modal: true,
					show: {
						effect: 'fade',
						duration: 300
					},
					open: function () {
						$(this).addClass('modal-opened');
						mw.util.addCSS('.rtl #vandal-cleaner-dialog2 img { float: left; } .ltr #vandal-cleaner-dialog2 img { float: right; }');
					},
					close: function () {
						$(this).removeClass('modal-opened');
						window.location.reload();
					},
					buttons: [
						{
							text: i18n('closeAndReload'),
							click: function () {
								$(this).dialog('close');
							}
						}
					]
					
				});
			
		}, 500);
		
	}
	
});