پیش‌نویس:Gadget-twinkleprotect-2020.js

// <nowiki>


(function($) {


/*
 ****************************************
 *** twinkleprotect.js: Protect/RPP module
 ****************************************
 * Mode of invocation:     Tab ("PP"/"RPP")
 * Active on:              Non-special, non-MediaWiki pages
 */

// Note: a lot of code in this module is re-used/called by batchprotect.

Twinkle.protect = function twinkleprotect() {
	if (mw.config.get('wgNamespaceNumber') < 0 || mw.config.get('wgNamespaceNumber') === 8) {
		return;
	}

	Twinkle.addPortletLink(Twinkle.protect.callback, Morebits.userIsSysop ? 'حفاظت' : 'حفاظت', 'tw-rpp', // localized
		Morebits.userIsSysop ? 'حفاظت صفحه' : 'درخواست حفاظت صفحه'); // localized
};

Twinkle.protect.callback = function twinkleprotectCallback() {
	var Window = new Morebits.simpleWindow(620, 530);
	Window.setTitle(Morebits.userIsSysop ? 'اعمال، درخواست یا برچسب‌گذاری حفاظت صفحه' : 'درخواست یا برچسب‌گذاری حفاظت صفحه'); // localized
	Window.setScriptName('توینکل'); // localized
	Window.addFooterLink('الگوهای حفاظت', 'الگو:الگوهای حفاظت'); // localized
	Window.addFooterLink('سیاست حفاظت', 'وپ:حفاظت'); // localized
	Window.addFooterLink('راهنمای توینکل', 'وپ:تل/توضیحات#حفاظت'); // localized

	var form = new Morebits.quickForm(Twinkle.protect.callback.evaluate);
	var actionfield = form.append({
		type: 'field',
		label: 'نوع کنش' // localized
	});
	if (Morebits.userIsSysop) {
		actionfield.append({
			type: 'radio',
			name: 'actiontype',
			event: Twinkle.protect.callback.changeAction,
			list: [
				{
					label: 'محافظت صفحه', // localized
					value: 'protect',
					tooltip: 'اجرای حفاظت بر روی صفحه.', // localized
					checked: true
				}
			]
		});
	}
	actionfield.append({
		type: 'radio',
		name: 'actiontype',
		event: Twinkle.protect.callback.changeAction,
		list: [
			{
				label: 'درخواست حفاظت صفحه', // localized
				value: 'request',
				tooltip: 'اگر می خواهید ' + (Morebits.userIsSysop ? ' بجای اینکه خودتان شخصا محافظت را اجرا کنید،' : 'از طریق وپ:دمص درخواست دهید'), // localized
				checked: !Morebits.userIsSysop
			},
			{
				label: 'برچسب‌زدن صفحه با الگوی حفاظت', // localized
				value: 'tag',
				tooltip: 'اگر مدیر حفاظت‌کننده فراموش کرده باشد برچسب بزند یا خودتان بدون افزودن برچسب حفاظت را اجرا کرده‌اید، از اینجا می‌توانید برچسب را اعمال کنید', // localized
				disabled: mw.config.get('wgArticleId') === 0 || mw.config.get('wgPageContentModel') === 'Scribunto'
			}
		]
	});

	form.append({ type: 'field', label: 'پیش‌فرض', name: 'field_preset' });
	form.append({ type: 'field', label: '1', name: 'field1' });
	form.append({ type: 'field', label: '2', name: 'field2' });

	form.append({ type: 'submit' });

	var result = form.render();
	Window.setContent(result);
	Window.display();

	// We must init the controls
	var evt = document.createEvent('Event');
	evt.initEvent('change', true, true);
	result.actiontype[0].dispatchEvent(evt);

	// get current protection level asynchronously
	Twinkle.protect.fetchProtectionLevel();
};

// Contains the current protection level in an object
// Once filled, it will look something like:
// { edit: { level: "sysop", expiry: <some date>, cascade: true }, ... }
Twinkle.protect.currentProtectionLevels = {};

// returns a jQuery Deferred object, usage:
//   Twinkle.protect.fetchProtectingAdmin(apiObject, pageName, protect/stable).done(function(admin_username) { ...code... });
Twinkle.protect.fetchProtectingAdmin = function twinkleprotectFetchProtectingAdmin(api, pageName, protType, logIds) {
	logIds = logIds || [];

	return api.get({
		format: 'json',
		action: 'query',
		list: 'logevents',
		letitle: pageName,
		letype: protType
	}).then(function(data) {
		// don't check log entries that have already been checked (e.g. don't go into an infinite loop!)
		var event = data.query ? $.grep(data.query.logevents, function(le) {
			return $.inArray(le.logid, logIds);
		})[0] : null;
		if (!event) {
			// fail gracefully
			return null;
		} else if (event.action === 'move_prot' || event.action === 'move_stable') {
			return twinkleprotectFetchProtectingAdmin(api, protType === 'protect' ? event.params.oldtitle_title : event.params.oldtitle, protType, logIds.concat(event.logid));
		}
		return event.user;
	});
};

// mw.loader.getState('ext.flaggedRevs.review') returns null if the
// FlaggedRevs extension is not registered.  Previously, this was done with
// wgFlaggedRevsParams, but after 1.34-wmf4 it is no longer exported if empty
// (https://gerrit.wikimedia.org/r/c/mediawiki/extensions/FlaggedRevs/+/508427)
Twinkle.protect.fetchProtectionLevel = function twinkleprotectFetchProtectionLevel() {

	var api = new mw.Api();
	var protectDeferred = api.get({
		format: 'json',
		indexpageids: true,
		action: 'query',
		list: 'logevents',
		letype: 'protect',
		letitle: mw.config.get('wgPageName'),
		prop: mw.loader.getState('ext.flaggedRevs.review') ? 'info|flagged' : 'info',
		inprop: 'protection',
		titles: mw.config.get('wgPageName')
	});
	var stableDeferred = api.get({
		format: 'json',
		action: 'query',
		list: 'logevents',
		letype: 'stable',
		letitle: mw.config.get('wgPageName')
	});

	var earlyDecision = [protectDeferred];
	if (mw.loader.getState('ext.flaggedRevs.review')) {
		earlyDecision.push(stableDeferred);
	}

	$.when.apply($, earlyDecision).done(function(protectData, stableData) {
		// $.when.apply is supposed to take an unknown number of promises
		// via an array, which it does, but the type of data returned varies.
		// If there are two or more deferreds, it returns an array (of objects),
		// but if there's just one deferred, it retuns a simple object.
		// This is annoying.
		protectData = $(protectData).toArray();

		var pageid = protectData[0].query.pageids[0];
		var page = protectData[0].query.pages[pageid];
		var current = {}, adminEditDeferred;

		$.each(page.protection, function(index, protection) {
			if (protection.type !== 'aft') {
				current[protection.type] = {
					level: protection.level,
					expiry: protection.expiry,
					cascade: protection.cascade === ''
				};
				// logs report last admin who made changes to either edit/move/create protection, regardless if they only modified one of them
				if (!adminEditDeferred) {
					adminEditDeferred = Twinkle.protect.fetchProtectingAdmin(api, mw.config.get('wgPageName'), 'protect');
				}
			}
		});

		if (page.flagged) {
			current.stabilize = {
				level: page.flagged.protection_level,
				expiry: page.flagged.protection_expiry
			};
			adminEditDeferred = Twinkle.protect.fetchProtectingAdmin(api, mw.config.get('wgPageName'), 'stable');
		}

		// show the protection level and log info
		Twinkle.protect.hasProtectLog = !!protectData[0].query.logevents.length;
		Twinkle.protect.hasStableLog = mw.loader.getState('ext.flaggedRevs.review') ? !!stableData[0].query.logevents.length : false;
		Twinkle.protect.currentProtectionLevels = current;

		if (adminEditDeferred) {
			adminEditDeferred.done(function(admin) {
				if (admin) {
					$.each(['edit', 'move', 'create', 'stabilize'], function(i, type) {
						if (Twinkle.protect.currentProtectionLevels[type]) {
							Twinkle.protect.currentProtectionLevels[type].admin = admin;
						}
					});
				}
				Twinkle.protect.callback.showLogAndCurrentProtectInfo();
			});
		} else {
			Twinkle.protect.callback.showLogAndCurrentProtectInfo();
		}
	});
};

Twinkle.protect.callback.showLogAndCurrentProtectInfo = function twinkleprotectCallbackShowLogAndCurrentProtectInfo() {
	var currentlyProtected = !$.isEmptyObject(Twinkle.protect.currentProtectionLevels);

	if (Twinkle.protect.hasProtectLog || Twinkle.protect.hasStableLog) {
		var $linkMarkup = $('<span>');

		if (Twinkle.protect.hasProtectLog) {
			$linkMarkup.append(
				$('<a target="_blank" href="' + mw.util.getUrl('Special:Log', {action: 'view', page: mw.config.get('wgPageName'), type: 'protect'}) + '">protection log</a>'),
				Twinkle.protect.hasStableLog ? $('<span> &bull; </span>') : null
			);
		}

		if (Twinkle.protect.hasStableLog) {
			$linkMarkup.append($('<a target="_blank" href="' + mw.util.getUrl('Special:Log', {action: 'view', page: mw.config.get('wgPageName'), type: 'stable'}) + '">pending changes log</a>)'));
		}

		Morebits.status.init($('div[name="hasprotectlog"] span')[0]);
		Morebits.status.warn(
			currentlyProtected ? 'محافظت‌های پیشین' : 'این صفحه در گذشته مورد حفاظت قرار گرفته‌است', // localized
			$linkMarkup[0]
		);
	}

	Morebits.status.init($('div[name="currentprot"] span')[0]);
	var protectionNode = [], statusLevel = 'info';

	if (currentlyProtected) {
		$.each(Twinkle.protect.currentProtectionLevels, function(type, settings) {
			var label = type === 'stabilize' ? 'تغییرات در حال انتظار' : Morebits.string.toUpperCaseFirstChar(type); // localized
			protectionNode.push($('<b>' + label + ': ' + settings.level + '</b>')[0]);
			if (settings.expiry === 'infinity') {
				protectionNode.push(' (بی‌پایان) '); // localized
			} else {
				protectionNode.push(' (زمان سرآمدن ' + new Date(settings.expiry).toUTCString() + ') '); // localized
			}
			if (settings.cascade) {
				protectionNode.push('(آبشاری) '); // localized
			}
			if (settings.admin) {
				var adminLink = '<a target="_blank" href="' + mw.util.getUrl('User talk:' + settings.admin) + '">' + settings.admin + '</a>';
				protectionNode.push($('<span>توسط ' + adminLink + '&nbsp;</span>')[0]); // localized
			}
			protectionNode.push($('<span> \u2022 </span>')[0]);
		});
		protectionNode = protectionNode.slice(0, -1); // remove the trailing bullet
		statusLevel = 'warn';
	} else {
		protectionNode.push($('<b>محافظت نشده</b>')[0]); // localized
	}

	Morebits.status[statusLevel]('سطح محافظت فعلی', protectionNode); // localized
};

Twinkle.protect.callback.changeAction = function twinkleprotectCallbackChangeAction(e) {
	var field_preset;
	var field1;
	var field2;
	var isTemplate = mw.config.get('wgNamespaceNumber') === 10 || mw.config.get('wgNamespaceNumber') === 828;

	switch (e.target.values) {
		case 'protect':
			field_preset = new Morebits.quickForm.element({ type: 'field', label: 'Preset', name: 'field_preset' });
			field_preset.append({
				type: 'select',
				name: 'category',
				label: 'انتخاب یک پیش‌فرض:', // localized
				event: Twinkle.protect.callback.changePreset,
				list: mw.config.get('wgArticleId') ?
					Twinkle.protect.protectionTypes.filter(function(v) {
						return isTemplate || v.label !== 'Template protection';
					}) :
					Twinkle.protect.protectionTypesCreate
			});

			field2 = new Morebits.quickForm.element({ type: 'field', label: 'گزینه‌های حفاظت', name: 'field2' }); // localized
			field2.append({ type: 'div', name: 'currentprot', label: ' ' });  // holds the current protection level, as filled out by the async callback
			field2.append({ type: 'div', name: 'hasprotectlog', label: ' ' });
			// for existing pages
			if (mw.config.get('wgArticleId')) {
				field2.append({
					type: 'checkbox',
					name: 'editmodify',
					event: Twinkle.protect.formevents.editmodify,
					list: [
						{
							label: 'تغییر حفاظت در برابر ویرایش', // localized
							value: 'editmodify',
							tooltip: 'درصورت خاموش‌کردن این جعبه، سطح حفاظت از ویرایش و زمان سرآمدن به همان شکلی که هستند باقی می‌مانند', // localized
							checked: true
						}
					]
				});
				var editlevel = field2.append({
					type: 'select',
					name: 'editlevel',
					label: 'محافظت در برابر ویرایش:', // localized
					event: Twinkle.protect.formevents.editlevel
				});
				editlevel.append({
					type: 'option',
					label: 'همه', // localized
					value: 'all'
				});
				editlevel.append({
					type: 'option',
					label: 'تأییدشدهٔ خودکار', // localized
					value: 'autoconfirmed'
				});
				editlevel.append({
					type: 'option',
					label: 'تأییدشدهٔ پایدار', // localized
					value: 'extendedconfirmed'
				});
				if (isTemplate) {
					editlevel.append({
						type: 'option',
						label: 'ویرایشگر الگو', // localized
						value: 'templateeditor'
					});
				}
				editlevel.append({
					type: 'option',
					label: 'مدیر', // localized
					value: 'sysop',
					selected: true
				});
				field2.append({
					type: 'select',
					name: 'editexpiry',
					label: 'سرآمدن:', // localized
					event: function(e) {
						if (e.target.value === 'custom') {
							Twinkle.protect.doCustomExpiry(e.target);
						}
					},
					// default expiry selection is conditionally set in Twinkle.protect.callback.changePreset
					list: [
						{ label: '۱ ساعت', value: '1 hour' }, // localized
						{ label: '۲ ساعت', value: '2 hours' }, // localized
						{ label: '۳ ساعت', value: '3 hours' }, // localized
						{ label: '۶ ساعت', value: '6 hours' }, // localized
						{ label: '۱۲ ساعت', value: '12 hours' }, // localized
						{ label: '۱ روز', value: '1 day' }, // localized
						{ label: '۲ روز', value: '2 days' }, // localized
						{ label: '۳ روز', value: '3 days' }, // localized
						{ label: '۴ روز', value: '4 days' }, // localized
						{ label: '۱ هفته', value: '1 week' }, // localized
						{ label: '۲ هفته', value: '2 weeks' }, // localized
						{ label: '۱ ماه', value: '1 month' }, // localized
						{ label: '۲ ماه', value: '2 months' }, // localized
						{ label: '۳ ماه', value: '3 months' }, // localized
						{ label: '۱ سال', value: '1 year' }, // localized
						{ label: 'بی‌پایان', value: 'indefinite' }, // localized
						{ label: 'دلخواه', value: 'custom' } // localized
					]
				});
				field2.append({
					type: 'checkbox',
					name: 'movemodify',
					event: Twinkle.protect.formevents.movemodify,
					list: [
						{
							label: 'تغییر حفاظت از انتقال', // localized
							value: 'movemodify',
							tooltip: 'اگر این جعبه خاموش باشد، سطح حفاظت از انتقال و زمان سرآمدن به همان شکلی که هستند باقی‌می‌مانند', // localized
							checked: true
						}
					]
				});
				var movelevel = field2.append({
					type: 'select',
					name: 'movelevel',
					label: 'حفاظت دربرابر انتقال:', // localized
					event: Twinkle.protect.formevents.movelevel
				});
				movelevel.append({
					type: 'option',
					label: 'همه', // localized
					value: 'all'
				});
				movelevel.append({
					type: 'option',
					label: 'تأیید‌شدهٔ پایدار', // localized
					value: 'extendedconfirmed'
				});
				if (isTemplate) {
					movelevel.append({
						type: 'option',
						label: 'ویرایشگر الگو', // localized
						value: 'templateeditor'
					});
				}
				movelevel.append({
					type: 'option',
					label: 'مدیر', // localized
					value: 'sysop',
					selected: true
				});
				field2.append({
					type: 'select',
					name: 'moveexpiry',
					label: 'سرآمدن:', // localized
					event: function(e) {
						if (e.target.value === 'custom') {
							Twinkle.protect.doCustomExpiry(e.target);
						}
					},
					// default expiry selection is conditionally set in Twinkle.protect.callback.changePreset
					list: [
						{ label: '۱ ساعت', value: '1 hour' }, // localized
						{ label: '۲ ساعت', value: '2 hours' }, // localized
						{ label: '۳ ساعت', value: '3 hours' }, // localized
						{ label: '۶ ساعت', value: '6 hours' }, // localized
						{ label: '۱۲ ساعت', value: '12 hours' }, // localized
						{ label: '۱ روز', value: '1 day' }, // localized
						{ label: '۲ روز', value: '2 days' }, // localized
						{ label: '۳ روز', value: '3 days' }, // localized
						{ label: '۴ روز', value: '4 days' }, // localized
						{ label: '۱ هفته', value: '1 week' }, // localized
						{ label: '۲ هفته', value: '2 weeks' }, // localized
						{ label: '۱ ماه', value: '1 month' }, // localized
						{ label: '۲ ماه', value: '2 months' }, // localized
						{ label: '۳ ماه', value: '3 months' }, // localized
						{ label: '۱ سال', value: '1 year' }, // localized
						{ label: 'بی‌پایان', value: 'indefinite' }, // localized
						{ label: 'دلخواه', value: 'custom' } // localized
					]
				});
				// Namespaces hardcoded until [[phab:T218479]]
				if (mw.loader.getState('ext.flaggedRevs.review') && (mw.config.get('wgNamespaceNumber') === 0 || mw.config.get('wgNamespaceNumber') === 4)) {
					field2.append({
						type: 'checkbox',
						name: 'pcmodify',
						event: Twinkle.protect.formevents.pcmodify,
						list: [
							{
								label: 'تغییر حفاظت نیازمند بازبینی', // localized
								value: 'pcmodify',
								tooltip: 'اگر این جعبه خاموش باشد، سطح حفاظت نیازمند بازبینی و زمان سرآمدن به همان شکلی که هستند باقی می‌مانند', // localized
								checked: true
							}
						]
					});
					var pclevel = field2.append({
						type: 'select',
						name: 'pclevel',
						label: 'تغییرات درحال انتظار:', // localized
						event: Twinkle.protect.formevents.pclevel
					});
					pclevel.append({
						type: 'option',
						label: 'هیچ', // localized
						value: 'none'
					});
					pclevel.append({
						type: 'option',
						label: 'تغییرات در حال انتظار', // localized
						value: 'autoconfirmed',
						selected: true
					});
					field2.append({
						type: 'select',
						name: 'pcexpiry',
						label: 'سرآمدن:', // localized
						event: function(e) {
							if (e.target.value === 'custom') {
								Twinkle.protect.doCustomExpiry(e.target);
							}
						},
						list: [
							{ label: '۱ ساعت', value: '1 hour' }, // localized
							{ label: '۲ ساعت', value: '2 hours' }, // localized
							{ label: '۳ ساعت', value: '3 hours' }, // localized
							{ label: '۶ ساعت', value: '6 hours' }, // localized
							{ label: '۱۲ ساعت', value: '12 hours' }, // localized
							{ label: '۱ روز', value: '1 day' }, // localized
							{ label: '۲ روز', value: '2 days' }, // localized
							{ label: '۳ روز', value: '3 days' }, // localized
							{ label: '۴ روز', value: '4 days' }, // localized
							{ label: '۱ هفته', value: '1 week' }, // localized
							{ label: '۲ هفته', value: '2 weeks' }, // localized
							{ label: '۱ ماه', selected: true, value: '1 month' }, // localized
							{ label: '۲ ماه', value: '2 months' }, // localized
							{ label: '۳ ماه', value: '3 months' }, // localized
							{ label: '۱ سال', value: '1 year' }, // localized
							{ label: 'بی‌پایان', value: 'indefinite' }, // localized
							{ label: 'دلخواه', value: 'custom' } // localized
						]
					});
				}
			} else {  // for non-existing pages
				var createlevel = field2.append({
					type: 'select',
					name: 'createlevel',
					label: 'حفاظت در برابر ایجاد:', // localized
					event: Twinkle.protect.formevents.createlevel
				});
				createlevel.append({
					type: 'option',
					label: 'همه', // localized
					value: 'all'
				});
				if (mw.config.get('wgNamespaceNumber') !== 0) {
					createlevel.append({
						type: 'option',
						label: 'تأیید خودکار', // localized
						value: 'autoconfirmed'
					});
				}
				if (isTemplate) {
					createlevel.append({
						type: 'option',
						label: 'ویرایشگر الگو', // localized
						value: 'templateeditor'
					});
				}
				createlevel.append({
					type: 'option',
					label: 'تأییدشدهٔ پایدار', // localized
					value: 'extendedconfirmed',
					selected: true
				});
				createlevel.append({
					type: 'option',
					label: 'مدیر', // localized
					value: 'sysop'
				});
				field2.append({
					type: 'select',
					name: 'createexpiry',
					label: 'سرآمدن:', // localized
					event: function(e) {
						if (e.target.value === 'custom') {
							Twinkle.protect.doCustomExpiry(e.target);
						}
					},
					list: [
						{ label: '۱ ساعت', value: '1 hour' }, // localized
						{ label: '۲ ساعت', value: '2 hours' }, // localized
						{ label: '۳ ساعت', value: '3 hours' }, // localized
						{ label: '۶ ساعت', value: '6 hours' }, // localized
						{ label: '۱۲ ساعت', value: '12 hours' }, // localized
						{ label: '۱ روز', value: '1 day' }, // localized
						{ label: '۲ روز', value: '2 days' }, // localized
						{ label: '۳ روز', value: '3 days' }, // localized
						{ label: '۴ روز', value: '4 days' }, // localized
						{ label: '۱ هفته', value: '1 week' }, // localized
						{ label: '۲ هفته', value: '2 weeks' }, // localized
						{ label: '۱ ماه', value: '1 month' }, // localized
						{ label: '۲ ماه', value: '2 months' }, // localized
						{ label: '۳ ماه', value: '3 months' }, // localized
						{ label: '۱ سال', value: '1 year' }, // localized
						{ label: 'بی‌پایان', selected: true, value: 'indefinite' }, // localized
						{ label: 'دلخواه', value: 'custom' } // localized
					]
				});
			}
			field2.append({
				type: 'textarea',
				name: 'protectReason',
				label: 'دلیل (برای سیاههٔ محافظت):' // localized
			});
			if (!mw.config.get('wgArticleId') || mw.config.get('wgPageContentModel') === 'Scribunto') {  // tagging isn't relevant for non-existing or module pages
				break;
			}
			/* falls through */
		case 'tag':
			field1 = new Morebits.quickForm.element({ type: 'field', label: 'گزینه‌های برچسب زدن', name: 'field1' });
			field1.append({ type: 'div', name: 'currentprot', label: ' ' });  // holds the current protection level, as filled out by the async callback
			field1.append({ type: 'div', name: 'hasprotectlog', label: ' ' });
			field1.append({
				type: 'select',
				name: 'tagtype',
				label: 'انتخاب الگوی محافظت:', // localized
				list: Twinkle.protect.protectionTags,
				event: Twinkle.protect.formevents.tagtype
			});
			field1.append({
				type: 'checkbox',
				list: [
					{
						name: 'small',
						label: 'کوچک (small=yes)', // localized
						tooltip: 'استفاده از ویژگی |small=yes  الگو، به شکلی که فقط قفل نمایش داده شود', // localized
						checked: true
					},
					{
						name: 'noinclude',
						label: 'قراردادن الگوی حفاظت درون برچسب <noinclude>', // localized
						tooltip: 'الگوی حفاظت را درون &lt;noinclude&gt; قرار می‌دهد تا تراگنجانش نشود', // localized
						checked: mw.config.get('wgNamespaceNumber') === 10
					}
				]
			});
			break;

		case 'request':
			field_preset = new Morebits.quickForm.element({ type: 'field', label: 'نوع محافظت', name: 'field_preset' }); // localized
			field_preset.append({
				type: 'select',
				name: 'category',
				label: 'نوع و دلیل:', // localized
				event: Twinkle.protect.callback.changePreset,
				list: mw.config.get('wgArticleId') ? Twinkle.protect.protectionTypes : Twinkle.protect.protectionTypesCreate
			});

			field1 = new Morebits.quickForm.element({ type: 'field', label: 'گزینه‌ها', name: 'field1' }); // localized
			field1.append({ type: 'div', name: 'currentprot', label: ' ' });  // holds the current protection level, as filled out by the async callback
			field1.append({ type: 'div', name: 'hasprotectlog', label: ' ' });
			field1.append({
				type: 'select',
				name: 'expiry',
				label: 'مدت: ', // localized
				list: [
					{ label: 'موقت', value: 'temporary' }, // localized
					{ label: 'بی‌پایان', value: 'indefinite' },  // localized
					{ label: '', selected: true, value: '' }
				]
			});
			field1.append({
				type: 'textarea',
				name: 'reason',
				label: 'دلیل: '  // localized
			});
			break;
		default:
			alert("مشکلی در حین اجرای حفاظت توینکلی پیش آمد"); // localized
			break;
	}

	var oldfield;

	if (field_preset) {
		oldfield = $(e.target.form).find('fieldset[name="field_preset"]')[0];
		oldfield.parentNode.replaceChild(field_preset.render(), oldfield);
	} else {
		$(e.target.form).find('fieldset[name="field_preset"]').css('display', 'none');
	}
	if (field1) {
		oldfield = $(e.target.form).find('fieldset[name="field1"]')[0];
		oldfield.parentNode.replaceChild(field1.render(), oldfield);
	} else {
		$(e.target.form).find('fieldset[name="field1"]').css('display', 'none');
	}
	if (field2) {
		oldfield = $(e.target.form).find('fieldset[name="field2"]')[0];
		oldfield.parentNode.replaceChild(field2.render(), oldfield);
	} else {
		$(e.target.form).find('fieldset[name="field2"]').css('display', 'none');
	}

	if (e.target.values === 'protect') {
		// fake a change event on the preset dropdown
		var evt = document.createEvent('Event');
		evt.initEvent('change', true, true);
		e.target.form.category.dispatchEvent(evt);

		// reduce vertical height of dialog
		$(e.target.form).find('fieldset[name="field2"] select').parent().css({ display: 'inline-block', marginRight: '0.5em' });
	}

	// re-add protection level and log info, if it's available
	Twinkle.protect.callback.showLogAndCurrentProtectInfo();
};

Twinkle.protect.formevents = {
	editmodify: function twinkleprotectFormEditmodifyEvent(e) {
		e.target.form.editlevel.disabled = !e.target.checked;
		e.target.form.editexpiry.disabled = !e.target.checked || (e.target.form.editlevel.value === 'all');
		e.target.form.editlevel.style.color = e.target.form.editexpiry.style.color = e.target.checked ? '' : 'transparent';
	},
	editlevel: function twinkleprotectFormEditlevelEvent(e) {
		e.target.form.editexpiry.disabled = e.target.value === 'all';
	},
	movemodify: function twinkleprotectFormMovemodifyEvent(e) {
		// sync move settings with edit settings if applicable
		if (e.target.form.movelevel.disabled && !e.target.form.editlevel.disabled) {
			e.target.form.movelevel.value = e.target.form.editlevel.value;
			e.target.form.moveexpiry.value = e.target.form.editexpiry.value;
		} else if (e.target.form.editlevel.disabled) {
			e.target.form.movelevel.value = 'sysop';
			e.target.form.moveexpiry.value = 'indefinite';
		}
		e.target.form.movelevel.disabled = !e.target.checked;
		e.target.form.moveexpiry.disabled = !e.target.checked || (e.target.form.movelevel.value === 'all');
		e.target.form.movelevel.style.color = e.target.form.moveexpiry.style.color = e.target.checked ? '' : 'transparent';
	},
	movelevel: function twinkleprotectFormMovelevelEvent(e) {
		e.target.form.moveexpiry.disabled = e.target.value === 'all';
	},
	pcmodify: function twinkleprotectFormPcmodifyEvent(e) {
		e.target.form.pclevel.disabled = !e.target.checked;
		e.target.form.pcexpiry.disabled = !e.target.checked || (e.target.form.pclevel.value === 'none');
		e.target.form.pclevel.style.color = e.target.form.pcexpiry.style.color = e.target.checked ? '' : 'transparent';
	},
	pclevel: function twinkleprotectFormPclevelEvent(e) {
		e.target.form.pcexpiry.disabled = e.target.value === 'none';
	},
	createlevel: function twinkleprotectFormCreatelevelEvent(e) {
		e.target.form.createexpiry.disabled = e.target.value === 'all';
	},
	tagtype: function twinkleprotectFormTagtypeEvent(e) {
		e.target.form.small.disabled = e.target.form.noinclude.disabled = (e.target.value === 'none') || (e.target.value === 'noop');
	}
};

Twinkle.protect.doCustomExpiry = function twinkleprotectDoCustomExpiry(target) {
	var custom = prompt('یک زمان سرآمدن سفارشی وارد کنید. \n می‌توانید زمان‌های نسبی مثل «۱ دقیقه» یا «۱۹ روز» یا زمان‌مهر مطلق به شکل yyyymmddhhmm وارد کنید (به عنوان مثال "200602011405" نشان دهندهٔ اول فوریهٔ ۲۰۰۶، ساعت ۱۴:۰۵ جهانی است).', ''); // localized fixes might be necessary
	if (custom) {
		var option = document.createElement('option');
		option.setAttribute('value', custom);
		option.textContent = custom;
		target.appendChild(option);
		target.value = custom;
	} else {
		target.selectedIndex = 0;
	}
};

Twinkle.protect.protectionTypes = [
	{ label: 'خروج از حفاظت', value: 'unprotect' }, // localized
	{
		label: 'حفاظت کامل', // localized
		list: [
			{ label: 'کلی (کامل)', value: 'pp-protected' }, // localized
			{ label: 'اختلاف نظر / جنگ ویرایشی (کامل)', value: 'pp-dispute' }, // localized
			{ label: 'خرابکاری مداوم (کامل)', value: 'pp-vandalism' }, // localized
			{ label: 'بحث کاربری بسته‌شده (کامل)', value: 'pp-usertalk' } // localized
		]
	},
	{
		label: 'حفاظت الگو', // localized
		list: [
			{ label: 'الگوی پرکاربرد', value: 'pp-template' } // localized
		]
	},
	{
		label: 'Extended confirmed protection',
		list: [
			{ label: 'تصمیم هیئت داوری', selected: true, value: 'pp-30-500-arb' }, // localized
			{ label: 'خرابکاری پی‌درپی', value: 'pp-30-500-vandalism' }, // localized
			{ label: 'ویرایش فلج‌کننده', value: 'pp-30-500-disruptive' }, // localized
			{ label: 'سرپیچی از سیاست زندگی‌نامهٔ زندگان', value: 'pp-30-500-blp' }, // localized
			{ label: 'زاپاس‌بازی', value: 'pp-30-500-sock' } // localized
		]
	},
	{
		label: 'Semi-protection',
		list: [
			{ label: 'کلی (نیمه‌حفاظت)', value: 'pp-semi-protected' }, // localized
			{ label: 'خرابکاری ادامه‌دار (نیمه‌حفاظت)', selected: true, value: 'pp-semi-vandalism' }, // localized
			{ label: 'ویرایش فلج‌کننده (نیمه‌حفاظت)', value: 'pp-semi-disruptive' }, // localized
			{ label: 'افزودن مطالب بدون منبع (نیمه حفاظت)', value: 'pp-semi-unsourced' }, // localized
			{ label: 'سرپیچی از سیاست زندگی‌نامهٔ زندگان (نیمه‌حفاظت)', value: 'pp-semi-blp' }, // localized
			{ label: 'زاپاس‌بازی (نیمه‌حفاظت)', value: 'pp-semi-sock' }, // localized
			{ label: 'صفحهٔ بحث کاربر بسته‌شده (نیمه‌حفاظت)', value: 'pp-semi-usertalk' } // localized
		]
	},
	{
		label: 'تغییرات در حال انتظار', // localized
		list: [
			{ label: 'کلی', value: 'pp-pc-protected' }, // localized
			{ label: 'خرابکاری پی‌درپی', value: 'pp-pc-vandalism' }, // localized
			{ label: 'ویرایش فلج‌کننده', value: 'pp-pc-disruptive' }, // localized
			{ label: 'افزودن مطالب بی‌منبع', value: 'pp-pc-unsourced' }, // localized
			{ label: 'سرپیچی از سیاست زندگی‌نامهٔ زندگان', value: 'pp-pc-blp' } // localized
		]
	},
	{
		label: 'حفاظت از انتقال', // localized
		list: [
			{ label: 'کلی (انتقال)', value: 'pp-move' }, // localized
			{ label: 'اختلاف نظر/جنگ برسر عنوان (انتقال)', value: 'pp-move-dispute' }, // localized
			{ label: 'خرابکاری از طریق انتقال (انتقال)', value: 'pp-move-vandalism' }, // localized
			{ label: 'صفحهٔ پربازدید (انتقال)', value: 'pp-move-indef' } // localized
		]
	}
];

Twinkle.protect.protectionTypesCreate = [
	{ label: 'خروج از محافظت', value: 'unprotect' }, // localized
	{
		label: 'محافظت در برابر ایجاد', // localized
		list: [
			{ label: 'کلی ({{pp-create}})', value: 'pp-create' }, // localized
			{ label: 'نام نامناسب', value: 'pp-create-offensive' }, // localized
			{ label: 'ایجادهای مجدد', selected: true, value: 'pp-create-salt' }, // localized
			{ label: 'زندگی‌نامهٔ زندگان که یه تازگی حذف‌شده', value: 'pp-create-blp' } // localized
		]
	}
];

// A page with both regular and PC protection will be assigned its regular
// protection weight plus 2
Twinkle.protect.protectionWeight = {
	sysop: 40,
	templateeditor: 30,
	extendedconfirmed: 20,
	autoconfirmed: 10,
	flaggedrevs_autoconfirmed: 5,  // Pending Changes protection alone
	all: 0,
	flaggedrevs_none: 0  // just in case
};

// NOTICE: keep this synched with [[MediaWiki:Protect-dropdown]]
// Also note: stabilize = Pending Changes level
Twinkle.protect.protectionPresetsInfo = {
	'pp-protected': {
		edit: 'sysop',
		move: 'sysop',
		reason: null
	},
	'pp-dispute': {
		edit: 'sysop',
		move: 'sysop',
		reason: '[[وپ:مناقشه|مناقشه بر سر محتوا/جنگ ویرایشی]]' // localized
	},
	'pp-vandalism': {
		edit: 'sysop',
		move: 'sysop',
		reason: '[[وپ:خ|خرابکاری]] ادامه‌دار' // localized
	},
	'pp-usertalk': {
		edit: 'sysop',
		move: 'sysop',
		reason: '[[وپ:حبک|استفادهٔ نادرست از صفحهٔ بحث کاربر در حین بندایش]]' // localized
	},
	'pp-template': {
		edit: 'templateeditor',
		move: 'templateeditor',
		reason: '[[وپ:حساس|الگوهای بسیار پرکاربرد]]' // localized
	},
	'pp-30-500-arb': {
		edit: 'extendedconfirmed',
		move: 'extendedconfirmed',
		reason: '[[وپ:قفل آبی|درخواست هیئت نظارت]]',
		template: 'pp-30-500'
	},
	'pp-30-500-vandalism': {
		edit: 'extendedconfirmed',
		move: 'extendedconfirmed',
		reason: ' [[وپ:خ|خرابکاری]] ادامه‌دار از سوی حساب‌های تأیید‌شده(ی‌خودکار)', // localized
		template: 'pp-30-500'
	},
	'pp-30-500-disruptive': {
		edit: 'extendedconfirmed',
		move: 'extendedconfirmed',
		reason: '[[وپ:اخلال|ویرایش اخلالگرانهٔ]] ادامه‌دار توسط کاربران تأیید شده', // localized
		template: 'pp-30-500'
	},
	'pp-30-500-blp': {
		edit: 'extendedconfirmed',
		move: 'extendedconfirmed',
		reason: 'نقض ادامه‌دار [[وپ:زز|سیاست زندگی‌نامه زندگان]] توسط کاربران تأیید شده', // localized
		template: 'pp-30-500'
	},
	'pp-30-500-sock': {
		edit: 'extendedconfirmed',
		move: 'extendedconfirmed',
		reason: 'Persistent [[وپ:زاپاس|زاپاس بازی]]', // localized
		template: 'pp-30-500'
	},
	'pp-semi-vandalism': {
		edit: 'autoconfirmed',
		reason: '[[وپ:خرابکاری|خرابکاری]] ادامه‌دار', // localized
		template: 'pp-vandalism'
	},
	'pp-semi-disruptive': {
		edit: 'autoconfirmed',
		reason: '[[وپ:اخلال|ویرایش اخلالگرانهٔ]] ادامه‌دار', // localized
		template: 'pp-protected'
	},
	'pp-semi-unsourced': {
		edit: 'autoconfirmed',
		reason: 'افزودن مداوم [[WP:INTREF|مطالب بدون منبع یا با منبع نامعتبر]]', // localized
		template: 'pp-protected'
	},
	'pp-semi-blp': {
		edit: 'autoconfirmed',
		reason: 'Violations of the [[WP:BLP|biographies of living persons policy]]',
		template: 'pp-blp'
	},
	'pp-semi-usertalk': {
		edit: 'autoconfirmed',
		move: 'autoconfirmed',
		reason: '[[WP:PP#Talk-page protection|Inappropriate use of user talk page while blocked]]',
		template: 'pp-usertalk'
	},
	'pp-semi-template': {  // removed for now
		edit: 'autoconfirmed',
		move: 'autoconfirmed',
		reason: '[[WP:High-risk templates|Highly visible template]]',
		template: 'pp-template'
	},
	'pp-semi-sock': {
		edit: 'autoconfirmed',
		reason: 'Persistent [[WP:Sock puppetry|sock puppetry]]',
		template: 'pp-sock'
	},
	'pp-semi-protected': {
		edit: 'autoconfirmed',
		reason: null,
		template: 'pp-protected'
	},
	'pp-pc-vandalism': {
		stabilize: 'autoconfirmed',  // stabilize = Pending Changes
		reason: '[[وپ:خرابکاری|خرابکاری]] مداوم', // localized
		template: 'pp-pc'
	},
	'pp-pc-disruptive': {
		stabilize: 'autoconfirmed',
		reason: '[[وپ:اخلال|ویرایش‌های اخلالگرانه]] ادامه‌دار', // localized
		template: 'pp-pc'
	},
	'pp-pc-unsourced': {
		stabilize: 'autoconfirmed',
		reason: 'ادامه‌دار بودن [[WP:INTREF|افزودن مداوم مطالب بدون منبع یا منبع ضعیف]]', // localized
		template: 'pp-pc'
	},
	'pp-pc-blp': {
		stabilize: 'autoconfirmed',
		reason: 'نقض [[وپ:زنده|سیاست زندگی‌نامه زندگان]]', // localized
		template: 'pp-pc'
	},
	'pp-pc-protected': {
		stabilize: 'autoconfirmed',
		reason: null,
		template: 'pp-pc'
	},
	'pp-move': {
		move: 'sysop',
		reason: null
	},
	'pp-move-dispute': {
		move: 'sysop',
		reason: '[[وپ:قفل سبز|مناقشه بر سر نام]]' // localized
	},
	'pp-move-vandalism': {
		move: 'sysop',
		reason: '[[وپ:قفل سبز|خرابکاری از طریق انتقال]]' // localized
	},
	'pp-move-indef': {
		move: 'sysop',
		reason: '[[وپ:قفل سبز|صفحهٔ پربیننده]]' // localized
	},
	'unprotect': {
		edit: 'all',
		move: 'all',
		stabilize: 'none',
		create: 'all',
		reason: null,
		template: 'none'
	},
	'pp-create-offensive': {
		create: 'sysop',
		reason: '[[وپ:نمک|نام نامناسب]]' // localized
	},
	'pp-create-salt': {
		create: 'extendedconfirmed',
		reason: '[[وپ:نمک|ایجاد پیاپی]]' // localized
	},
	'pp-create-blp': {
		create: 'extendedconfirmed',
		reason: '[[WP:BLPDEL|Recently deleted BLP]]'
	},
	'pp-create': {
		create: 'extendedconfirmed',
		reason: '{{pp-create}}' // localized version to be decided, non-existing in source
	}
};

Twinkle.protect.protectionTags = [
	{
		label: 'هیچ (حذف الگوهای حفاظت فعلی)', // localized
		value: 'none'
	},
	{
		label: 'هیچ (بدون حذف الگوهای حفاظت فعلی)', // localized
		value: 'noop'
	},
	{
		label: 'الگوهای حفاظت دربرابر ویرایش', // localized
		list: [
			{ label: '{{pp-vandalism}}: خرابکاری', value: 'pp-vandalism' }, // localized
			{ label: '{{pp-dispute}}: مناقشه/جنگ ویرایشی', value: 'pp-dispute' }, // localized
			{ label: '{{pp-blp}}: سرپیچی از سیاست زندگی‌نامهٔ زندگان', value: 'pp-blp' }, // localized
			{ label: '{{pp-sock}}: زاپاس‌بازی', value: 'pp-sock' }, // localized
			{ label: '{{pp-template}}: الگوی حساس', value: 'pp-template' }, // localized
			{ label: '{{pp-usertalk}}: صفحهٔ بحث کاربر بسته‌شده', value: 'pp-usertalk' }, // localized
			{ label: '{{pp-protected}}: حفاظت کلی', value: 'pp-protected' }, // localized
			{ label: '{{pp-semi-indef}}: نیمه‌حفاظت کلی و طولانی‌مدت', value: 'pp-semi-indef' }, // localized
			{ label: '{{pp-30-500}}: نیمه‌حفاظت ویژه', value: 'pp-30-500' } // localized
		]
	},
	{
		label: 'الگوهای تغییرات درحال انتظار', // localized
		list: [
			{ label: '{{pp-pc}}: تغییرات در حال انتظار', value: 'pp-pc' } // localized
		]
	},
	{
		label: 'الگوهای حفاظت در برابر انتقال', // localized
		list: [
			{ label: '{{pp-move-dispute}}: مناقشه/جنگ بر سر انتقال', value: 'pp-move-dispute' }, // localized
			{ label: '{{pp-move-vandalism}}: خرابکاری از طریق انتقال', value: 'pp-move-vandalism' }, // localized
			{ label: '{{pp-move-indef}}: کلی و طولانی‌مدت', value: 'pp-move-indef' }, // localized
			{ label: '{{pp-move}}: سایر', value: 'pp-move' } // localized
		]
	}
];

Twinkle.protect.callback.changePreset = function twinkleprotectCallbackChangePreset(e) {
	var form = e.target.form;

	var actiontypes = form.actiontype;
	var actiontype;
	for (var i = 0; i < actiontypes.length; i++) {
		if (!actiontypes[i].checked) {
			continue;
		}
		actiontype = actiontypes[i].values;
		break;
	}

	if (actiontype === 'protect') {  // actually protecting the page
		var item = Twinkle.protect.protectionPresetsInfo[form.category.value];

		if (mw.config.get('wgArticleId')) {
			if (item.edit) {
				form.editmodify.checked = true;
				Twinkle.protect.formevents.editmodify({ target: form.editmodify });
				form.editlevel.value = item.edit;
				Twinkle.protect.formevents.editlevel({ target: form.editlevel });
				form.editexpiry.value = '2 days';
			} else {
				form.editmodify.checked = false;
				Twinkle.protect.formevents.editmodify({ target: form.editmodify });
			}

			if (item.move) {
				form.movemodify.checked = true;
				Twinkle.protect.formevents.movemodify({ target: form.movemodify });
				form.movelevel.value = item.move;
				Twinkle.protect.formevents.movelevel({ target: form.movelevel });
				form.moveexpiry.value = '2 days';
			} else {
				form.movemodify.checked = false;
				Twinkle.protect.formevents.movemodify({ target: form.movemodify });
			}

			if (form.pcmodify) {
				if (item.stabilize) {
					form.pcmodify.checked = true;
					Twinkle.protect.formevents.pcmodify({ target: form.pcmodify });
					form.pclevel.value = item.stabilize;
					Twinkle.protect.formevents.pclevel({ target: form.pclevel });
				} else {
					form.pcmodify.checked = false;
					Twinkle.protect.formevents.pcmodify({ target: form.pcmodify });
				}
			}
		} else {
			if (item.create) {
				form.createlevel.value = item.create;
				Twinkle.protect.formevents.createlevel({ target: form.createlevel });
			}
		}

		var reasonField = actiontype === 'protect' ? form.protectReason : form.reason;
		if (item.reason) {
			reasonField.value = item.reason;
		} else {
			reasonField.value = '';
		}

		// sort out tagging options, disabled if nonexistent or lua
		if (mw.config.get('wgArticleId') && mw.config.get('wgPageContentModel') !== 'Scribunto') {
			if (form.category.value === 'unprotect') {
				form.tagtype.value = 'none';
			} else {
				form.tagtype.value = item.template ? item.template : form.category.value;
			}
			Twinkle.protect.formevents.tagtype({ target: form.tagtype });

			if (/template/.test(form.category.value)) {
				form.noinclude.checked = true;
				form.editexpiry.value = form.moveexpiry.value = form.pcexpiry.value = 'indefinite';
			} else if (mw.config.get('wgNamespaceNumber') !== 10) {
				form.noinclude.checked = false;
			}
		}

	} else {  // RPP request
		if (form.category.value === 'unprotect') {
			form.expiry.value = '';
			form.expiry.disabled = true;
		} else {
			form.expiry.value = '';
			form.expiry.disabled = false;
		}
	}
};

Twinkle.protect.callback.evaluate = function twinkleprotectCallbackEvaluate(e) {
	var form = e.target;

	var actiontypes = form.actiontype;
	var actiontype;
	for (var i = 0; i < actiontypes.length; i++) {
		if (!actiontypes[i].checked) {
			continue;
		}
		actiontype = actiontypes[i].values;
		break;
	}

	var tagparams;
	if (actiontype === 'tag' || (actiontype === 'protect' && mw.config.get('wgArticleId') && mw.config.get('wgPageContentModel') !== 'Scribunto')) {
		tagparams = {
			tag: form.tagtype.value,
			reason: (form.tagtype.value === 'pp-protected' || form.tagtype.value === 'pp-semi-protected' || form.tagtype.value === 'pp-move') && form.protectReason ? form.protectReason.value : null,
			small: form.small.checked,
			noinclude: form.noinclude.checked
		};
	}

	switch (actiontype) {
		case 'protect':
			// protect the page
			Morebits.wiki.actionCompleted.redirect = mw.config.get('wgPageName');
			Morebits.wiki.actionCompleted.notice = 'محافظت کامل شد'; // localized

			var statusInited = false;
			var thispage;

			var allDone = function twinkleprotectCallbackAllDone() {
				if (thispage) {
					thispage.getStatusElement().info('done');
				}
				if (tagparams) {
					Twinkle.protect.callbacks.taggingPageInitial(tagparams);
				}
			};

			var stabilizeValues = {};
			if (form.pclevel) {
				stabilizeValues = {
					pclevel: form.pclevel.value,
					pcexpiry: form.pcexpiry.value,
					protectReason: form.protectReason.value
				};
			}

			var protectIt = function twinkleprotectCallbackProtectIt(next) {
				thispage = new Morebits.wiki.page(mw.config.get('wgPageName'), ' محافظت صفحه'); // localized
				if (mw.config.get('wgArticleId')) {
					if (form.editmodify.checked) {
						thispage.setEditProtection(form.editlevel.value, form.editexpiry.value);
					}
					if (form.movemodify.checked) {
						thispage.setMoveProtection(form.movelevel.value, form.moveexpiry.value);
					}
				} else {
					thispage.setCreateProtection(form.createlevel.value, form.createexpiry.value);
					thispage.setWatchlist(false);
				}

				if (form.protectReason.value) {
					thispage.setEditSummary(form.protectReason.value);
				} else {
					alert('می‌بایست دلیلی برای حفاظت جهت ذکر در سیاههٔ محافظت ارائه دهید.'); // localized
					return;
				}

				if (!statusInited) {
					Morebits.simpleWindow.setButtonsEnabled(false);
					Morebits.status.init(form);
					statusInited = true;
				}

				thispage.protect(next);
			};

			var stabilizeIt = function twinkleprotectCallbackStabilizeIt() {
				if (thispage) {
					thispage.getStatusElement().info('done');
				}

				thispage = new Morebits.wiki.page(mw.config.get('wgPageName'), 'Applying pending changes protection');
				thispage.setFlaggedRevs(stabilizeValues.pclevel, stabilizeValues.pcexpiry);

				if (stabilizeValues.protectReason) {
					thispage.setEditSummary(stabilizeValues.protectReason);
				} else {
					alert('باید دلیلی برای درخواست ذکر کنید تا در سیاهه محافظت ثبت شود.'); // localized
					return;
				}

				if (!statusInited) {
					Morebits.simpleWindow.setButtonsEnabled(false);
					Morebits.status.init(form);
					statusInited = true;
				}

				thispage.stabilize(allDone, function(error) {
					if (error.errorCode === 'stabilize_denied') { // [[phab:T234743]]
						thispage.getStatusElement().error('Failed trying to modify pending changes settings, likely due to a mediawiki bug. Other actions (tagging or regular protection) may have taken place. Please reload the page and try again.');
					}
				});
			};

			if ((form.editmodify && form.editmodify.checked) || (form.movemodify && form.movemodify.checked) ||
				!mw.config.get('wgArticleId')) {
				if (form.pcmodify && form.pcmodify.checked) {
					protectIt(stabilizeIt);
				} else {
					protectIt(allDone);
				}
			} else if (form.pcmodify && form.pcmodify.checked) {
				stabilizeIt();
			} else {
				alert("لطفا دستوری به توینکل دهید.\nاگر صرفا قصد برچسب‌زدن دارید، گزینهٔ 'برچسب زدن صفحه' را از بالاانتخاب کنید."); // localized
			}

			break;

		case 'tag':
			// apply a protection template

			Morebits.simpleWindow.setButtonsEnabled(false);
			Morebits.status.init(form);

			Morebits.wiki.actionCompleted.redirect = mw.config.get('wgPageName');
			Morebits.wiki.actionCompleted.followRedirect = false;
			Morebits.wiki.actionCompleted.notice = 'برچسب زدن کامل شد'; // localized

			Twinkle.protect.callbacks.taggingPageInitial(tagparams);
			break;

		case 'request':
			// file request at RFPP
			var typename, typereason;
			switch (form.category.value) {
				case 'pp-dispute':
				case 'pp-vandalism':
				case 'pp-usertalk':
				case 'pp-protected':
					typename = 'full protection';
					break;
				case 'pp-template':
					typename = 'template protection';
					break;
				case 'pp-30-500-arb':
				case 'pp-30-500-vandalism':
				case 'pp-30-500-disruptive':
				case 'pp-30-500-blp':
				case 'pp-30-500-sock':
					typename = 'extended confirmed protection';
					break;
				case 'pp-semi-vandalism':
				case 'pp-semi-disruptive':
				case 'pp-semi-unsourced':
				case 'pp-semi-usertalk':
				case 'pp-semi-sock':
				case 'pp-semi-blp':
				case 'pp-semi-protected':
					typename = 'semi-protection';
					break;
				case 'pp-pc-vandalism':
				case 'pp-pc-blp':
				case 'pp-pc-protected':
				case 'pp-pc-unsourced':
				case 'pp-pc-disruptive':
					typename = 'pending changes';
					break;
				case 'pp-move':
				case 'pp-move-dispute':
				case 'pp-move-indef':
				case 'pp-move-vandalism':
					typename = 'move protection';
					break;
				case 'pp-create':
				case 'pp-create-offensive':
				case 'pp-create-blp':
				case 'pp-create-salt':
					typename = 'create protection';
					break;
				case 'unprotect':
					var admins = $.map(Twinkle.protect.currentProtectionLevels, function(pl) {
						return pl.admin ? 'User:' + pl.admin : null;
					});
					if (admins.length && !confirm('آیا قبلا با مدیران حفاظت کننده (' + $.unique(admins).join(', ') + ') تماس گرفته‌اید؟')) { // localized
						return false;
					}
					// otherwise falls through
				default:
					typename = 'unprotection';
					break;
			}
			switch (form.category.value) {
				case 'pp-dispute':
					typereason = 'مناقشه بر سر محتوا/جنگ ویرایشی'; // localized
					break;
				case 'pp-vandalism':
				case 'pp-semi-vandalism':
				case 'pp-pc-vandalism':
				case 'pp-30-500-vandalism':
					typereason = ' [[وپ:خ|خرابکاری]] ادامه‌دار'; // localized
					break;
				case 'pp-semi-disruptive':
				case 'pp-pc-disruptive':
				case 'pp-30-500-disruptive':
					typereason = ' [[Wikipedia:Disruptive editing|ویرایش فلج‌کنندهٔ ]] ادامه‌دار'; // localized
					break;
				case 'pp-semi-unsourced':
				case 'pp-pc-unsourced':
					typereason = '[[WP:INTREF|مطالب بدون منبع]] افزودن ادامه‌دار'; // localized
					break;
				case 'pp-template':
					typereason = '[[WP:HIGHRISK|الگوی حساس]]'; // localized
					break;
				case 'pp-30-500-arb':
					typereason = '[[WP:30/500|تصمیم هیئت داوری]]'; // localized
					break;
				case 'pp-usertalk':
				case 'pp-semi-usertalk':
					typereason = 'استفادهٔ نادرست از صفحهٔ بحث کاربر در حین بندایش'; // localized
					break;
				case 'pp-semi-sock':
				case 'pp-30-500-sock':
					typereason = '[[وپ:ز|زاپاس‌بازی]] ادامه‌دار'; // localized
					break;
				case 'pp-semi-blp':
				case 'pp-pc-blp':
				case 'pp-30-500-blp':
					typereason = 'سرپیچی از سیاست زندگی‌نامهٔ زندگان'; // localized
					break;
				case 'pp-move-dispute':
					typereason = 'مناقشه/جنگ بر سر عنوان/انتقال'; // localized
					break;
				case 'pp-move-vandalism':
					typereason = 'خرابکاری از طریق اناقال صفحات'; // localized
					break;
				case 'pp-move-indef':
					typereason = 'صفحهٔ پربازدید'; // localized
					break;
				case 'pp-create-offensive':
					typereason = 'نام نامناسب'; // localized
					break;
				case 'pp-create-blp':
					typereason = 'زندگی‌نامهٔ زندگان که به تازگی حذف شده'; // localized
					break;
				case 'pp-create-salt':
					typereason = 'ایجادهای پی‌درپی'; // localized
					break;
				default:
					typereason = '';
					break;
			}

			var reason = typereason;
			if (form.reason.value !== '') {
				if (typereason !== '') {
					reason += '\u00A0\u2013 ';  // U+00A0 NO-BREAK SPACE; U+2013 EN RULE
				}
				reason += form.reason.value;
			}
			if (reason !== '' && reason.charAt(reason.length - 1) !== '.') {
				reason += '.';
			}

			var rppparams = {
				reason: reason,
				typename: typename,
				category: form.category.value,
				expiry: form.expiry.value
			};

			Morebits.simpleWindow.setButtonsEnabled(false);
			Morebits.status.init(form);

			var rppName = 'ویکی‌پدیا:درخواست محافظت از صفحه'; // localized

			// Updating data for the action completed event
			Morebits.wiki.actionCompleted.redirect = rppName;
			Morebits.wiki.actionCompleted.notice = 'درخواست کامل شد، درحال بازگشت به صفحه بحث'; // localized

			var rppPage = new Morebits.wiki.page(rppName, 'درحال درخواست برای محافظت از صفحه'); // localized
			rppPage.setFollowRedirect(true);
			rppPage.setCallbackParameters(rppparams);
			rppPage.load(Twinkle.protect.callbacks.fileRequest);
			break;
		default:
			alert('twinkleprotect: unknown kind of action');
			break;
	}
};

Twinkle.protect.callbacks = {
	taggingPageInitial: function(tagparams) {
		if (tagparams.tag === 'noop') {
			Morebits.status.info(' اعمال الگوی حفاظت', 'کاری برای انجام نیست'); // localized
			return;
		}

		var protectedPage = new Morebits.wiki.page(mw.config.get('wgPageName'), 'برچسب زدن صفحه'); // localized
		protectedPage.setCallbackParameters(tagparams);
		protectedPage.load(Twinkle.protect.callbacks.taggingPage);
	},
	taggingPage: function(protectedPage) {
		var params = protectedPage.getCallbackParameters();
		var text = protectedPage.getPageText();
		var tag, summary;

		var oldtag_re = /\s*(?:<noinclude>)?\s*\{\{\s*(pp-[^{}]*?|protected|(?:t|v|s|p-|usertalk-v|usertalk-s|sb|move)protected(?:2)?|protected template|privacy protection)\s*?\}\}\s*(?:<\/noinclude>)?\s*/gi;
		var re_result = oldtag_re.exec(text);
		if (re_result) {
			if (params.tag === 'none' || confirm('{{' + re_result[1] + '}} در صفحه یافت نشد. \nبرای حذف آن تأیید و برای نگه‌داشتن آن لغو را کلیک کنید.')) { // localized
				text = text.replace(oldtag_re, '');
			}
		}

		if (params.tag === 'none') {
			summary = 'حذف الگوی حفاظت' + Twinkle.getPref('summaryAd'); // localized
		} else {
			tag = params.tag;
			if (params.reason) {
				tag += '|reason=' + params.reason;
			}
			if (params.small) {
				tag += '|small=yes';
			}

			if (/^\s*#redirect/i.test(text)) { // redirect page
				// Only tag if no {{rcat shell}} is found
				if (!text.match(/{{(?:redr|this is a redirect|r(?:edirect)?(?:.?cat.*)?[ _]?sh)/i)) {
					text = text.replace(/#REDIRECT ?(\[\[.*?\]\])(.*)/i, '#REDIRECT $1$2\n\n{{' + tag + '}}');
				} else {
					Morebits.status.info('پوستهٔ ردهٔ تغییر مسیر موجود است', 'کاری برای انجام وجود ندارد'); // localized
					return;
				}
			} else if (params.noinclude) {
				text = '<noinclude>{{' + tag + '}}</noinclude>' + text;
			} else {
				text = '{{' + tag + '}}\n' + text;
			}
			summary = 'افزودن {{' + params.tag + '}}' + Twinkle.getPref('summaryAd'); // localized
		}

		protectedPage.setEditSummary(summary);
		protectedPage.setPageText(text);
		protectedPage.setCreateOption('nocreate');
		protectedPage.suppressProtectWarning(); // no need to let admins know they are editing through protection
		protectedPage.save();
	},

	fileRequest: function(rppPage) {

		var params = rppPage.getCallbackParameters();
		var text = rppPage.getPageText();
		var statusElement = rppPage.getStatusElement();

		var rppRe = new RegExp('===\\s*(\\[\\[)?\\s*:?\\s*' + RegExp.escape(Morebits.pageNameNorm, true) + '\\s*(\\]\\])?\\s*===', 'm');
		var tag = rppRe.exec(text);

		var rppLink = document.createElement('a');
		rppLink.setAttribute('href', mw.util.getUrl(rppPage.getPageName()));
		rppLink.appendChild(document.createTextNode(rppPage.getPageName()));

		if (tag) {
			statusElement.error([ 'در حال حاضر درخواست حفاظتی برای این صفحه در ', rppLink, ' موجود است، ادامه نمی‌دهیم' ]); // localized
			return;
		}

		var newtag = '=== [[:' + Morebits.pageNameNorm + ']] ===\n';
		if (new RegExp('^' + RegExp.escape(newtag).replace(/\s+/g, '\\s*'), 'm').test(text)) {
			statusElement.error([ 'در حال حاضر درخواست حفاظتی برای این صفحه در ', rppLink, ' موجود است، ادامه نمی‌دهیم' ]); // localized
			return;
		}
		newtag += '* {{pagelinks|1=' + Morebits.pageNameNorm + '}}\n\n';

		var words;
		switch (params.expiry) {
			case 'temporary':
				words = 'موقت '; // localized
				break;
			case 'indefinite':
				words = 'بی‌پایان '; // localized
				break;
			default:
				words = '';
				break;
		}

		words += params.typename;

		newtag += "'''" + Morebits.string.toUpperCaseFirstChar(words) + (params.reason !== '' ? ":''' " +
			Morebits.string.formatReasonText(params.reason) : ".'''") + ' ~~~~';

		// If either protection type results in a increased status, then post it under increase
		// else we post it under decrease
		var increase = false;
		var protInfo = Twinkle.protect.protectionPresetsInfo[params.category];

		// function to compute protection weights (see comment at Twinkle.protect.protectionWeight)
		var computeWeight = function(mainLevel, stabilizeLevel) {
			var result = Twinkle.protect.protectionWeight[mainLevel || 'all'];
			if (stabilizeLevel) {
				if (result) {
					if (stabilizeLevel.level === 'autoconfirmed') {
						result += 2;
					}
				} else {
					result = Twinkle.protect.protectionWeight['flaggedrevs_' + stabilizeLevel];
				}
			}
			return result;
		};

		// compare the page's current protection weights with the protection we are requesting
		var editWeight = computeWeight(Twinkle.protect.currentProtectionLevels.edit &&
			Twinkle.protect.currentProtectionLevels.edit.level,
		Twinkle.protect.currentProtectionLevels.stabilize &&
			Twinkle.protect.currentProtectionLevels.stabilize.level);
		if (computeWeight(protInfo.edit, protInfo.stabilize) > editWeight ||
			computeWeight(protInfo.move) > computeWeight(Twinkle.protect.currentProtectionLevels.move &&
			Twinkle.protect.currentProtectionLevels.move.level) ||
			computeWeight(protInfo.create) > computeWeight(Twinkle.protect.currentProtectionLevels.create &&
			Twinkle.protect.currentProtectionLevels.create.level)) {
			increase = true;
		}

		var reg;
		if (increase) {
			reg = /(\n==\s*Current requests for reduction in protection level\s*==)/;
		} else {
			reg = /(\n==\s*Current requests for edits to a protected page\s*==)/;
		}

		var originalTextLength = text.length;
		text = text.replace(reg, '\n' + newtag + '\n$1');
		if (text.length === originalTextLength) {
			var linknode = document.createElement('a');
			linknode.setAttribute('href', mw.util.getUrl('Wikipedia:Twinkle/Fixing RPP'));
			linknode.appendChild(document.createTextNode('How to fix RPP'));
			statusElement.error([ 'عنوانی مناسب در وپ:دمص یافت نشد. برای حل این مشکل ', linknode, ' را ببینید' ]); // localized
			return;
		}
		statusElement.status('افزودن درخواست جدید...'); // localized
		rppPage.setEditSummary('/* ' + Morebits.pageNameNorm + ' */ Requesting ' + params.typename + (params.typename === 'pending changes' ? ' on [[:' : ' of [[:') +
			Morebits.pageNameNorm + ']].' + Twinkle.getPref('summaryAd'));
		rppPage.setPageText(text);
		rppPage.setCreateOption('recreate');
		rppPage.save();
	}
};
})(jQuery);


// </nowiki>