مدیاویکی:Gadget-twinkleconfig-2020.js

از ویکی‌واژه

نکته: پس از انتشار ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.

  • فایرفاکس / سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload کلیک کنید، یا کلید‌های Ctrl-F5 یا Ctrl-R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-R)
  • گوگل کروم: کلیدهای Ctrl+Shift+R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-Shift-R)
  • اینترنت اکسپلورر/ Edge: کلید Ctrl را نگه‌دارید و روی دکمهٔ Refresh کلیک کنید، یا کلید‌های Ctrl-F5 را با هم فشار دهید
  • اپرا: Ctrl-F5 را بفشارید.
// <nowiki>


(function($) {


/*
 ****************************************
 *** twinkleconfig.js: Preferences module
 ****************************************
 * Mode of invocation:     Adds configuration form to Wikipedia:Twinkle/Preferences,
                           and adds an ad box to the top of user subpages belonging to the
                           currently logged-in user which end in '.js'
 * Active on:              What I just said.  Yeah.

 I, [[User:This, that and the other]], originally wrote this.  If the code is misbehaving, or you have any
 questions, don't hesitate to ask me.  (This doesn't at all imply [[WP:OWN]]ership - it's just meant to
 point you in the right direction.)  -- TTO
 */


Twinkle.config = {};

Twinkle.config.watchlistEnums = { yes: 'به فهرست پی‌گیری اضافه کن', no: "به فهرست پی‌گیری اضافه نکن", 'default': 'از تنظیمات وبگاه تبعیت کن' }; // localized

Twinkle.config.commonSets = {
	csdCriteria: { // localized
		"حذف سریع": "دلیل دلخواه ({{حذف سریع}})",
		"ع۱": "ع۱", "ع۲": "ع۲", "ع۳": "ع۳", "ع۴": "ع۴", "ع۵": "ع۵", "ع۶": "ع۶", "ع۷": "ع۷", "ع۸": "ع۸", "ع۱۰": "ع۱۰", "ع۱۱": "ع۱۱", "ع۱۲": "ع۱۲", "ع۱۳": "ع۱۳", "ع۱۴": "ع۱۴",
		"م۱": "م۱", "م۲": "م۲", "م۳": "م۳", "م۵": "م۵", "م۷": "م۷", "م۹": "م۹", "م۱۰": "م۱۰", "م۱۱": "م۱۱",
		"ک۱": "ک۱", "ک۲": "ک۲", "ک۳": "ک۳", "ک۵": "ک۵",
		"پ۱": "پ۱", "پ۲": "پ۲", "پ۳": "پ۳", "پ۷": "پ۷", "پ۸": "پ۸", "پ۹": "پ۹", "پ۱۰": "پ۱۰",
		"ر۱": "ر۱",
		"ا۲": "ا۲", "ا۳": "ا۳",
		"ت۲": "ت۲", "ت۳": "ت۳", "ت۴": "ت۴",
		"د۱": "د۱", "د۲": "د۲"
	},
	csdCriteriaDisplayOrder: [
		'حذف سریع',
		"ع۱", "ع۲", "ع۳", "ع۴", "ع۵", "ع۶", "ع۷", "ع۸", "ع۱۰", "ع۱۱", "ع۱۲", "ع۱۳", "ع۱۴",
		"م۱", "م۲", "م۳", "م۵", "م۷", "م۹", "م۱۰", "م۱۱",
		"ک۱", "ک۲", "ک۳", "ک۵",
		"پ۱", "پ۲", "پ۳", "پ۷", "پ۸", "پ۹", "پ۱۰",
		"ر۱",
		"ا۲", "ا۳",
		"ت۲", "ت۳", "ت۴",
		"د۱", "د۲"
	],
	csdCriteriaNotification: {
		"حذف سریع": "دلیل دلخواه ({{حذف سریع}})",
		"ع۱": "ع۱", "ع۲": "ع۲", "ع۳": "ع۳", "ع۴": "ع۴", "ع۵": "ع۵", "ع۶": "ع۶", "ع۷": "ع۷", "ع۸": "ع۸", "ع۱۰": "ع۱۰", "ع۱۱": "ع۱۱", "ع۱۲": "ع۱۲", "ع۱۳": "ع۱۳", "ع۱۴": "ع۱۴",
		"م۱": "م۱", "م۲": "م۲", "م۳": "م۳", "م۵": "م۵", "م۷": "م۷", "م۹": "م۹", "م۱۰": "م۱۰", "م۱۱": "م۱۱",
		"ک۱": "ک۱", "ک۲": "ک۲", "ک۳": "ک۳", "ک۵": "ک۵",
		"پ۱": "پ۱", "پ۲": "پ۲", "پ۳": "پ۳", "پ۷": "پ۷", "پ۸": "پ۸", "پ۹": "پ۹", "پ۱۰": "پ۱۰",
		"ر۱": "ر۱",
		"ا۲": "ا۲", "ا۳": "ا۳",
		"ت۲": "ت۲", "ت۳": "ت۳", "ت۴": "ت۴",
		"د۱": "د۱", "د۲": "د۲"
	},
	csdCriteriaNotificationDisplayOrder: [
		'حذف سریع',
		"ع۱", "ع۲", "ع۳", "ع۴", "ع۵", "ع۶", "ع۷", "ع۸", "ع۱۰", "ع۱۱", "ع۱۲", "ع۱۳", "ع۱۴",
		"م۱", "م۲", "م۳", "م۵", "م۷", "م۹", "م۱۰", "م۱۱",
		"ک۱", "ک۲", "ک۳", "ک۵",
		"پ۱", "پ۲", "پ۳", "پ۷", "پ۸", "پ۹", "پ۱۰",
		"ر۱",
		"ا۲", "ا۳",
		"ت۲", "ت۳", "ت۴",
		"د۱", "د۲"
	],
	csdAndDICriteria: {
		"حذف سریع": "دلیل دلخواه ({{حذف سریع}})",
		"ع۱": "ع۱", "ع۲": "ع۲", "ع۳": "ع۳", "ع۴": "ع۴", "ع۵": "ع۵", "ع۶": "ع۶", "ع۷": "ع۷", "ع۸": "ع۸", "ع۱۰": "ع۱۰", "ع۱۱": "ع۱۱", "ع۱۲": "ع۱۲", "ع۱۳": "ع۱۳", "ع۱۴": "ع۱۴",
		"م۱": "م۱", "م۲": "م۲", "م۳": "م۳", "م۵": "م۵", "م۷": "م۷", "م۹": "م۹", "م۱۰": "م۱۰", "م۱۱": "م۱۱",
		"ک۱": "ک۱", "ک۲": "ک۲", "ک۳": "ک۳", "ک۵": "ک۵",
		"پ۱": "پ۱", "پ۲": "پ۲", "پ۳": "پ۳", "پ۷": "پ۷", "پ۸": "پ۸", "پ۹": "پ۹", "پ۱۰": "پ۱۰",
		"ر۱": "ر۱",
		"ا۲": "ا۲", "ا۳": "ا۳",
		"ت۲": "ت۲", "ت۳": "ت۳", "ت۴": "ت۴",
		"د۱": "د۱", "د۲": "د۲"
	},
	csdAndDICriteriaDisplayOrder: [
		'حذف سریع',
		"ع۱", "ع۲", "ع۳", "ع۴", "ع۵", "ع۶", "ع۷", "ع۸", "ع۱۰", "ع۱۱", "ع۱۲", "ع۱۳", "ع۱۴",
		"م۱", "م۲", "م۳", "م۵", "م۷", "م۹", "م۱۰", "م۱۱",
		"ک۱", "ک۲", "ک۳", "ک۵",
		"پ۱", "پ۲", "پ۳", "پ۷", "پ۸", "پ۹", "پ۱۰",
		"ر۱",
		"ا۲", "ا۳",
		"ت۲", "ت۳", "ت۴",
		"د۱", "د۲"
	],
	namespacesNoSpecial: {
		'0': 'مقاله', // localized
		'1': 'بحث (مقاله)', // localized
		'2': 'کاربر', // localized
		'3': 'بحث کاربر', // localized
		'4': 'ویکی‌واژه', // localized
		'5': 'بحث ویکی‌واژه', // localized
		'6': 'پرونده', // localized
		'7': 'بحث پرونده', // localized
		'8': 'مدیاویکی', // localized
		'9': 'بحث مدیاویکی', // localized
		'10': 'الگو', // localized
		'11': 'بحث الگو', // localized
		'12': 'راهنما', // localized
		'13': 'بحث راهنما', // localized
		'14': 'رده', // localized
		'15': 'بحث رده', // localized
		'100': 'درگاه', // localized
		'101': 'بحث درگاه', // localized
		'108': 'کتاب', // localized
		'109': 'بحث کتاب', // localized
		'118': 'پیش‌نویس', // localized
		'119': 'بحث پیش‌نویس', // localized
		// '710': 'TimedText', // localized
		// '711': 'TimedText talk', // localized
		'828': 'پودمان', // localized
		'829': 'بحث پودمان' // localized
	}
};

/**
 * Section entry format:
 *
 * {
 *   title: <human-readable section title>,
 *   adminOnly: <true for admin-only sections>,
 *   hidden: <true for advanced preferences that rarely need to be changed - they can still be modified by manually editing twinkleoptions.js>,
 *   preferences: [
 *     {
 *       name: <TwinkleConfig property name>,
 *       label: <human-readable short description - used as a form label>,
 *       helptip: <(optional) human-readable text (using valid HTML) that complements the description, like limits, warnings, etc.>
 *       adminOnly: <true for admin-only preferences>,
 *       type: <string|boolean|integer|enum|set|customList> (customList stores an array of JSON objects { value, label }),
 *       enumValues: <for type = "enum": a JSON object where the keys are the internal names and the values are human-readable strings>,
 *       setValues: <for type = "set": a JSON object where the keys are the internal names and the values are human-readable strings>,
 *       setDisplayOrder: <(optional) for type = "set": an array containing the keys of setValues (as strings) in the order that they are displayed>,
 *       customListValueTitle: <for type = "customList": the heading for the left "value" column in the custom list editor>,
 *       customListLabelTitle: <for type = "customList": the heading for the right "label" column in the custom list editor>
 *     },
 *     . . .
 *   ]
 * },
 * . . .
 *
 */

Twinkle.config.sections = [
	{
		title: 'عمومی', // localized
		preferences: [
			// TwinkleConfig.summaryAd (string)
			// Text to be appended to the edit summary of edits made using Twinkle
			{
				name: 'summaryAd',
				label: "پسوند تبلیغی جهت ضمیمه‌شدن به خلاصه ویرایش‌های توینکل", // localized
				helptip: 'خلاصهٔ پیشرفته باید با یک فاصله آغاز شده و تا حد امکان کوتاه نوشته‌شود.', // localized (to Huji: Summary Ad را به خلاصهٔ پیشرفته ترجمه کردم، چون «تبلیغ در خلاصه ویرایش منطقی نبود؛ آیا خلاصهٔ پیشرفته ترجمهٔ دقیقی است؟)
				type: 'string'
			},

			// TwinkleConfig.deletionSummaryAd (string)
			// Text to be appended to the edit summary of deletions made using Twinkle
			{
				name: 'deletionSummaryAd',
				label: 'خلاصهٔ مورد استفاده در خلاصه ویرایش حذف', // localized
				helptip: 'معمولاً برابر با همان خلاصه ویرایش پیشرفته در بالا.', // localized
				adminOnly: true,
				type: 'string'
			},

			// TwinkleConfig.protectionSummaryAd (string)
			// Text to be appended to the edit summary of page protections made using Twinkle
			{
				name: 'protectionSummaryAd',
				label: 'خلاصهٔ پیشرفته برای استفاده در خلاصه ویرایش محافظت صفحه', // localized
				helptip: 'معمولاً برابر با همان خلاصه ویرایش پیشرفته در بالا.', // localized
				adminOnly: true,
				type: 'string'
			},

			// TwinkleConfig.userTalkPageMode may take arguments:
			// 'window': open a new window, remember the opened window
			// 'tab': opens in a new tab, if possible.
			// 'blank': force open in a new window, even if such a window exists
			{
				name: 'userTalkPageMode',
				label: 'باز کردن بحث کاربر در ...', // localized
				type: 'enum',
				enumValues: { window: 'یک پنجره، به‌جای بحث کاربران', tab: 'یک زبانهٔ جدید', blank: 'یک پنجرهٔ کاملاً جدید' } // localized
			},

			// TwinkleConfig.dialogLargeFont (boolean)
			{
				name: 'dialogLargeFont',
				label: 'استفاده از متن بزرگتر در پیام‌های توینکل', // localized
				type: 'boolean'
			},

			// Twinkle.config.disabledModules (array)
			{
				name: 'disabledModules',
				label: 'خاموش‌کردن پودمان‌های انتخاب‌شدهٔ توینکل', // localized
				helptip: 'هر آنچه در اینجا انتخاب کنید، برای استفاده در دسترس نخواهد بود، پس با دقت عمل کنید. برای فعال‌کردن دوباره، گزینه‌ها را غیرفعال کنید.', // localized
				type: 'set',
				setValues: { /*arv: 'ARV',*/ warn: 'هشدار', welcome: 'خوش آمدید', shared: 'نشانی آی‌پی مشترک', talkback: 'بازبحث', speedy: 'حذف سریع', prod: 'حذف زمان‌دار', xfd: 'نظرخواهی حذف', image: 'تصویر', protect: 'محافظت (دمص)', tag: 'برچسب', diff: 'تفاوت', unlink: 'حذف پیوند', 'fluff': 'بازگردانی و واگردانی' } // localized
			},

			// Twinkle.config.disabledSysopModules (array)
			{
				name: 'disabledSysopModules',
				label: 'خاموش کردن پودمان‌های ویژهٔ مدیران', // localized
				helptip: 'هر آنچه در اینجا انتخاب کنید، برای استفاده در دسترس نخواهد بود، پس با دقت عمل کنید. برای فعال‌کردن دوباره، گزینه‌ها را غیرفعال کنید.', // localized
				adminOnly: true,
				type: 'set',
				setValues: { block: 'بستن', deprod: 'مخالفت با حذف زمان‌دار (مخزمان)', batchdelete: 'حذف دسته‌جمعی', batchprotect: 'محافظت دسته‌جمعی', batchundelete: 'احیای دسته‌جمعی' } // localized
			}
		]
	},
	/*
	{
		title: 'ARV',
		preferences: [
			{
				name: 'spiWatchReport',
				label: 'افزودن صفحه‌های گزارش زاپاس‌بازی به فهرست پیگیری', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			}
		]
	},
	*/ // localized [removed]

	{
		title: 'بستن کاربر', // localized
		adminOnly: true,
		preferences: [
			// TwinkleConfig.defaultToPartialBlocks (boolean)
			// Whether to default partial blocks on or off
			{
				name: 'defaultToPartialBlocks',
				label: 'به صورت پیش‌فرض در زمان بازکردن منوی بستن، قطع دسترسی موردی انتخاب شود', // localized
				type: 'boolean'
			},

			// TwinkleConfig.blankTalkpageOnIndefBlock (boolean)
			// if true, blank the talk page when issuing an indef block notice (per [[WP:UWUL#Indefinitely blocked users]])
			{
				name: 'blankTalkpageOnIndefBlock',
				label: 'صفحه بحث را در زمان قطع دسترسی بی‌پایان پاک شود', // localized
				helptip: 'برای اطلاعات بیشتر، <a href="' + mw.util.getUrl('en:Wikipedia:WikiProject_User_warnings/Usage_and_layout#Indefinitely_blocked_users') + '">WP:UWUL</a> را ببینید.', // localized
				type: 'boolean'
			}
		]
	},

	{
		title: 'حذف تصویر', // localized
		preferences: [
			// TwinkleConfig.notifyUserOnDeli (boolean)
			// If the user should be notified after placing a file deletion tag
			{
				name: 'notifyUserOnDeli',
				label: '"اطلاع‌رسانی به بارگذار پرونده" به صورت پیش‌فرض فعال باشد', // localized
				type: 'boolean'
			},

			// TwinkleConfig.deliWatchPage (string)
			// The watchlist setting of the page tagged for deletion. Either "yes", "no", or "default". Default is "default" (Duh).
			{
				name: 'deliWatchPage',
				label: 'تصویر در زمان برچسب‌زدن به فهرست پیگیری اضافه شود', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			},

			// TwinkleConfig.deliWatchUser (string)
			// The watchlist setting of the user talk page if a notification is placed. Either "yes", "no", or "default". Default is "default" (Duh).
			{
				name: 'deliWatchUser',
				label: 'صفحه بحث بارگذار پرونده در زمان اطلاع‌رسانی، به فهرست پیگیری اضافه شود', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			}
		]
	},

	{
		title: 'حذف زمان‌دار', // localized
		preferences: [
			// TwinkleConfig.watchProdPages (boolean)
			// If, when applying prod template to page, to watch the page
			{
				name: 'watchProdPages',
				label: 'مقاله در زمان برچسب‌زدن به فهرست پیگیری اضافه شود', // localized
				type: 'boolean'
			},

			// TwinkleConfig.markProdPagesAsPatrolled (boolean)
			// If, when applying prod template to page, to mark the page as curated/patrolled (if the page was reached from NewPages)
			{
				name: 'markProdPagesAsPatrolled',
				label: 'علامت زدن صفحه به‌عنوان گشت‌خورده/بازبینی‌شده در زمان برچسب زدن (در صورت امکان)', // localized
				helptip: 'از آنجا که این عمل بر خلاف اجماع برای بهترین راهکار است، در بیشتر موارد نباید این گزینه را انتخاب کرد', // localized
				type: 'boolean'
			},

			// TwinkleConfig.prodReasonDefault (string)
			// The prefilled PROD reason.
			{
				name: 'prodReasonDefault',
				label: 'دلیل پیش‌فرض حذف زمان‌دار', // localized
				type: 'string'
			},

			{
				name: 'logProdPages',
				label: 'نگهداری سیاهه‌ای از همهٔ صفحه‌هایی که نامزد حذف زمان‌دار کرده‌اید در زیرصفحه کاربری', // localized
				helptip: 'از آنجا که کاربران غیرمدیر به مشارکت‌های حذف‌شدهٔ خود دسترسی ندارند، سیاههٔ نگهداری‌شده در زیرصفحهٔ کاربری می‌تواند برای پیگیری تمام صفحه‌هایی که با استفاده از توینکل نامزد حذف زمان‌دار کرده‌اید، مفید باشد.', // localized
				type: 'boolean'
			},
			{
				name: 'prodLogPageName',
				label: 'نگهداری سیاههٔ حذف زمان‌دار در این زیرصفحهٔ کاربری', // localized
				helptip: 'نام یک زیرصفحه را در این جعبه وارد کنید. می‌توانید در صفحهٔ کاربر:<i>نام کاربری</i>/<i>نام زیرصفحه</i> به سیاههٔ حذف زمان‌دار خود دسترسی داشته باشید. این قابلیت تنها در صورتی کار می‌کند که گزینهٔ سیاههٔ حذف زمان‌دار در زیرصفحه کاربری را فعال کرده باشید.', // localized
				type: 'string'
			}
		]
	},

	{
		title: 'برگرداندن و واگردانی',  // twinklefluff module  // localized
		preferences: [
			// TwinkleConfig.autoMenuAfterRollback (bool)
			// Option to automatically open the warning menu if the user talk page is opened post-reversion
			{
				name: 'autoMenuAfterRollback',
				label: 'باز کردن خودکار منوی هشدار توینکل در صفحهٔ بحث کاربر پس از بازگردانی با توینکل', // localized
				helptip: 'تنها در صورتی کار می‌کند که گزینهٔ مرتبط در پایین را فعال کرده باشید.', // localized
				type: 'boolean'
			},

			// TwinkleConfig.openTalkPage (array)
			// What types of actions that should result in opening of talk page
			{
				name: 'openTalkPage',
				label: 'باز کردن بحث کاربر پس از انجام این گونه‌های بازبینی', // localized
				type: 'set',
				setValues: { agf: 'برگردانی با فرض حسن نیت', norm: 'برگردانی عادی', vand: 'برگردانی خرابکاری', torev: '«برگرداندن این نسخه»' } // localized
			},

			// TwinkleConfig.openTalkPageOnAutoRevert (bool)
			// Defines if talk page should be opened when calling revert from contribs or recent changes pages. If set to true, openTalkPage defines then if talk page will be opened.
			{
				name: 'openTalkPageOnAutoRevert',
				label: 'باز کردن بحث کاربر به‌هنگام فراخواندن برگردانی از طریق مشارکت‌های کاربر یا تغییرات اخیر', // localized
				helptip: 'برای اینکه این قابلیت کار کند، در صورت فعال بودن این گزینه باید گزینه‌های مورد نظر در تنظیمات قبلی نیز فعال شده باشند.', // localized
				type: 'boolean'
			},

			// TwinkleConfig.rollbackInPlace (bool)
			//
			{
				name: 'rollbackInPlace',
				label: "جلوگیری از بارگیری مجدد صفحه در زمان برگردانی از طریق مشارکت‌های کاربر یا تغییرات اخیر", // localized
				helptip: "در صورت فعال بودن این گزینه، توینکل صفحهٔ مشارکت‌های کاربر یا تغییرات اخیر را پس از برگردانی مجدداً بارگیری نخواهد کرد. این به شما این امکان را می‌دهد که همزمان بیش از یک ویرایش را برگردانی کنید.", // localized
				type: 'boolean'
			},

			// TwinkleConfig.markRevertedPagesAsMinor (array)
			// What types of actions that should result in marking edit as minor
			{
				name: 'markRevertedPagesAsMinor',
				label: 'علامت‌زدن این گونه‌های بازبینی به‌عنوان ویرایش جزئی',
				type: 'set',
				setValues: { agf: 'برگردانی با فرض حسن نیت', norm: 'برگردانی عادی', vand: 'برگردانی خرابکاری', torev: '«برگرداندن این نسخه»' }
			},

			// TwinkleConfig.watchRevertedPages (array)
			// What types of actions that should result in forced addition to watchlist
			{
				name: 'watchRevertedPages',
				label: 'برای این انواع واگردانی، صفحه را به فهرست پی‌گیری بیفزا', // localized
				type: 'set',
				setValues: { agf: 'برگردانی با فرض حسن نیت', norm: 'برگردانی عادی', vand: 'برگردانی خرابکاری', torev: '«برگرداندن این نسخه»' } // localized
			},

			// TwinkleConfig.offerReasonOnNormalRevert (boolean)
			// If to offer a prompt for extra summary reason for normal reverts, default to true
			{
				name: 'offerReasonOnNormalRevert',
				label: 'درخواست دلیل برای برگردانی‌های عادی', // localized
				helptip: 'برگردانی‌های «عادی» آن‌هایی هستند که از طریق پیوند [برگردانی] میانی فراخوانده شده‌اند.', // localized
				type: 'boolean'
			},

			{
				name: 'confirmOnFluff',
				label: 'قبل از بازگرداندن پیغام تایید نمایش داده شود', // localized
				helptip: 'برای کاربرانی که از دستگاه‌های لمسی یا قلمی استفاده می‌کنند، و افرادی که به‌طور مزمن، مردد هستند.', // localized
				type: 'boolean'
			},

			// TwinkleConfig.showRollbackLinks (array)
			// Where Twinkle should show rollback links:
			// diff, others, mine, contribs, history, recent
			// Note from TTO: |contribs| seems to be equal to |others| + |mine|, i.e. redundant, so I left it out heres
			{
				name: 'showRollbackLinks',
				label: 'نمایش پیوندهای برگردانی در این صفحه‌ها', // localized
				type: 'set',
				setValues: { diff: 'صفحه‌های تفاوت', others: 'صفحه‌های مشارکت‌های کاربران دیگر', mine: 'صفحهٔ مشارکت‌های من', recent: 'تغییرات اخیر و صفحه‌های ویژهٔ تغییرات مرتبط', history: 'صفحه‌های تاریخچه' } // localized
			}
		]
	},

	{
		title: 'برچسب آی‌پی مشترک', // localized
		preferences: [
			{
				name: 'markSharedIPAsMinor',
				label: 'علامت‌گذاری برچسب‌زدن آی‌پی مشترک به‌عنوان ویرایش جزئی', // localized
				type: 'boolean'
			}
		]
	},

	{
		title: 'حذف سریع', // localized
		preferences: [
			{
				name: 'speedySelectionStyle',
				label: 'چه زمانی صفحه حذف شود یا برچسب زده شود؟', // localized
				type: 'enum',
				enumValues: { 'buttonClick': 'وقتی روی دکمهٔ «ثبت» کلیک کردم', 'radioClick': 'به محض کلیک کردن روی گزینه' } // localized
			},

			// TwinkleConfig.watchSpeedyPages (array)
			// Whether to add speedy tagged or deleted pages to watchlist
			{
				name: 'watchSpeedyPages',
				label: 'برای این معیارها، صفحه را به فهرست پی‌گیری بیفزا', // localized
				type: 'set',
				setValues: Twinkle.config.commonSets.csdCriteria,
				setDisplayOrder: Twinkle.config.commonSets.csdCriteriaDisplayOrder
			},

			// TwinkleConfig.markSpeedyPagesAsPatrolled (boolean)
			// If, when applying speedy template to page, to mark the page as triaged/patrolled (if the page was reached from NewPages)
			{
				name: 'markSpeedyPagesAsPatrolled',
				label: 'در زمان نصب برچسب، صفحه را در صورت امکان گشت بزن یا بازبینی کن', // localized
				helptip: 'این گزینه احتمالاً نباید استفاده شود چون برای آن اجماع وجود ندارد', // localized
				type: 'boolean'
			},

			// TwinkleConfig.welcomeUserOnSpeedyDeletionNotification (array of strings)
			// On what types of speedy deletion notifications shall the user be welcomed
			// with a "firstarticle" notice if their talk page has not yet been created.
			{
				name: 'welcomeUserOnSpeedyDeletionNotification',
				label: 'وقتی کاربر را از برچسب‌های مربوط به این معیارها آگاه می‌کنی به او خوشامد هم بگو', // localized
				helptip: 'پیام خوشامد فقط وقتی افزوده می‌شود که صفحهٔ بحث کاربر وجود نداشته باشد. الگوی {{نخستین نوشتار}} برای این منظور به کار خواهد رفت.', // localized
				type: 'set',
				setValues: Twinkle.config.commonSets.csdCriteriaNotification,
				setDisplayOrder: Twinkle.config.commonSets.csdCriteriaNotificationDisplayOrder
			},

			// TwinkleConfig.notifyUserOnSpeedyDeletionNomination (array)
			// What types of actions should result in the author of the page being notified of nomination
			{
				name: 'notifyUserOnSpeedyDeletionNomination',
				label: 'برای این معیارها، سازندهٔ صفحه را آگاه کن', // localized
				helptip: 'وقتی گزینهٔ آگاه کردن سازندهٔ صفحه را انتخاب می‌کند، این آگاه‌سازی فقط برای معیارهای زیر رخ خواهد داد.', // localized
				type: 'set',
				setValues: Twinkle.config.commonSets.csdCriteriaNotification,
				setDisplayOrder: Twinkle.config.commonSets.csdCriteriaNotificationDisplayOrder
			},

			// TwinkleConfig.warnUserOnSpeedyDelete (array)
			// What types of actions should result in the author of the page being notified of speedy deletion (admin only)
			{
				name: 'warnUserOnSpeedyDelete',
				label: 'آگاه‌سازی سازندهٔ صفحه در زمان حذف با این معیارها', // localized
				helptip: 'حتی در صورتی که در صفحهٔ معیارهای حذف سریع آگاه‌سازی را فعال کنید، این آگاه‌سازی تنها برای معیارهایی که در اینجا انتخاب شده‌اند انجام خواهد شد.', // localized
				adminOnly: true,
				type: 'set',
				setValues: Twinkle.config.commonSets.csdCriteriaNotification,
				setDisplayOrder: Twinkle.config.commonSets.csdCriteriaNotificationDisplayOrder
			},

			// TwinkleConfig.promptForSpeedyDeletionSummary (array of strings)
			{
				name: 'promptForSpeedyDeletionSummary',
				label: 'فراهم کردن امکان ویرایش خلاصهٔ حذف در صورت حذف با این معیارها', // localized
				adminOnly: true,
				type: 'set',
				setValues: Twinkle.config.commonSets.csdAndDICriteria,
				setDisplayOrder: Twinkle.config.commonSets.csdAndDICriteriaDisplayOrder
			},

			// TwinkleConfig.deleteTalkPageOnDelete (boolean)
			// If talk page if exists should also be deleted (CSD G8) when spedying a page (admin only)
			{
				name: 'deleteTalkPageOnDelete',
				label: 'انتخاب گزینهٔ «صفحهٔ بحث نیز حذف شود» به‌طور پیش‌فرض', // localized
				adminOnly: true,
				type: 'boolean'
			},

			{
				name: 'deleteRedirectsOnDelete',
				label: 'انتخاب گزینهٔ «تغییرمسیرها نیز حذف شوند» به‌طور پیش‌فرض', // localized
				adminOnly: true,
				type: 'boolean'
			},

			// TwinkleConfig.deleteSysopDefaultToDelete (boolean)
			// Make the CSD screen default to "delete" instead of "tag" (admin only)
			{
				name: 'deleteSysopDefaultToDelete',
				label: 'فعال‌سازی پیش‌فرض حذف بی‌درنگ به‌جای قرار دادن برچسب حذف سریع', // localized
				helptip: 'در صورت از پیش موجود بودن برچسب حذف سریع، جالت پیش‌فرض توینکل همیشه حالت «حذف» خواهد بود', // localized
				adminOnly: true,
				type: 'boolean'
			},

			// TwinkleConfig.speedyWindowWidth (integer)
			// Defines the width of the Twinkle SD window in pixels
			{
				name: 'speedyWindowWidth',
				label: 'عرض پنجرهٔ حذف سریع (به پیکسل)', // localized
				type: 'integer'
			},

			// TwinkleConfig.speedyWindowWidth (integer)
			// Defines the width of the Twinkle SD window in pixels
			{
				name: 'speedyWindowHeight',
				label: 'ارتفاع پنجرهٔ حذف سریع (به پیکسل)', // localized
				helptip: 'اگر یک نمایشگر بزرگ دارید، ممکن است بخواهید این اندازه را افزایش دهید.', // localized
				type: 'integer'
			},

			{
				name: 'logSpeedyNominations',
				label: 'نگهداری یک سیاهه از نامزدی‌ها برای حذف سریع در زیرصفحهٔ کاربری', // localized
				helptip: 'از آنجا که کاربران غیرمدیر به مشارکت‌های حذف‌شدهٔ خود دسترسی ندارند، سیاههٔ نگهداری‌شده در زیرصفحهٔ کاربری می‌تواند برای پیگیری تمام صفحه‌هایی که با استفاده از توینکل نامزد حذف سریع کرده‌اید، مفید باشد. پرونده‌هایی که با معیارهای حذف پرونده برچسب خورده‌اند نیز به این سیاهه افزوده می‌شوند.', // localized
				type: 'boolean'
			},
			{
				name: 'speedyLogPageName',
				label: 'نگهداری سیاههٔ حذف سریع در این زیرصفحهٔ کاربری', // localized
				helptip: 'نام یک زیرصفحه را در این جعبه وارد کنید. می‌توانید در صفحهٔ کاربر:<i>نام کربری</i>/<i>نام زیرصفحه</i> به سیاههٔ حذف سریع خود دسترسی داشته باشید. این قابلیت تنها در صورتی کار می‌کند که گزینهٔ سیاههٔ حذف سریع در زیرصفحه کاربری را فعال کرده باشید.', // localized
				type: 'string'
			},
			{
				name: 'noLogOnSpeedyNomination',
				label: 'عدم افزودن صفحه به سیاههٔ حذف در فضای کاربری در زمان استفاده از این معیارها',
				type: 'set',
				setValues: Twinkle.config.commonSets.csdAndDICriteria,
				setDisplayOrder: Twinkle.config.commonSets.csdAndDICriteriaDisplayOrder
			}
		]
	},

	{
		title: 'برچسب', // localized
		preferences: [
			{
				name: 'watchTaggedPages',
				label: 'در زمان افزودن برچسب، صفحه را به فهرست پی‌گیری بیفزا', // localized
				type: 'boolean'
			},
			{
				name: 'watchMergeDiscussions',
				label: 'افزودن صفحه‌های بحث به فهرست پیگیری در زمان آغاز نظرخواهی برای ادغام', // localized
				type: 'boolean'
			},
			{
				name: 'markTaggedPagesAsMinor',
				label: 'علامت‌زدن ویرایش‌ها برای افزودن برچسب به‌عنوان ویرایش جزئی', // localized
				type: 'boolean'
			},
			{
				name: 'markTaggedPagesAsPatrolled',
				label: 'انتخاب گزینهٔ «علامت‌گذاری صفحه به‌عنوان گشت‌خورده/بازبینی‌شده» به‌صورت پیش‌فرض', // localized
				type: 'boolean'
			},
			{
				name: 'groupByDefault',
				label: 'انتخاب گزینهٔ «گروه‌بندی در {{مشکلات متعدد}}» به‌صورت پیش‌فرض', // localized
				type: 'boolean'
			},
			{
				name: 'tagArticleSortOrder',
				label: 'حالت پیش‌فرض برای مرتب‌سازی برچسب‌های مقاله‌ها', // localized
				type: 'enum',
				enumValues: { 'cat': 'بر پایه رده', 'alpha': 'به ترتیب الفبا' } // localized
			},
			{
				name: 'customTagList',
				label: 'برچسب‌های نگهداری سفارشی مقاله/پیش‌نویس جهت نمایش', // localized
				helptip: "این برچسب‌ها به‌عنوان گزینه‌های بیشتر در پایین فهرست برچسب‌ها نمایش می‌یابند. به‌عنوان مثال، می‌توانید برچسب‌های نگهداری اضافه‌ای که هنوز به برچسب‌های پیش‌فرض توینکل اضافه نشده‌اند را بیافزایید.", // localized
				type: 'customList',
				customListValueTitle: 'نام الگو (بدون آکولاد)', // localized
				customListLabelTitle: 'متنی برای نمایش در کادر برچسب' // localized
			},
			{
				name: 'customFileTagList',
				label: 'برچسب‌های سفارشی نگهداری پرونده جهت نمایش', // localized
				helptip: 'برچسب‌های بیشتری که می‌خواهید برای پرونده‌ها بیافزایید.', // localized
				type: 'customList',
				customListValueTitle: 'نام الگو (بدون آکولاد)', // localized
				customListLabelTitle: 'متنی برای نمایش در کادر برچسب' // localized
			},
			{
				name: 'customRedirectTagList',
				label: 'برچسب‌های سفارشی ردهٔ تغییرمسیر جهت نمایش', // localized
				helptip: 'برچسب‌های بیشتری که می‌خواهید برای تغییرمسیرها بیافزایید.', // localized
				type: 'customList',
				customListValueTitle: 'نام الگو (بدون آکولاد)', // localized
				customListLabelTitle: 'متنی برای نمایش در کادر برچسب' // localized
			}
		]
	},

	{
		title: 'گفتگو', // localized
		preferences: [
			{
				name: 'markTalkbackAsMinor',
				label: 'علامت‌گذاری بازبحث‌ها به‌عنوان ویرایش جزئی', // localized
				type: 'boolean'
			},
			{
				name: 'insertTalkbackSignature',
				label: 'قرار دادن امضا در درون بازبحث‌ها', // localized
				type: 'boolean'
			},
			{
				name: 'talkbackHeading',
				label: 'عنوان بخش برای استفاده در بازبحث‌ها', // localized
				type: 'string'
			},
			{
				name: 'adminNoticeHeading',
				label: "عنوان بخش برای استفاده در گزارش‌های ارسال‌شده در تابلوی اعلانات مدیران", // localized
				helptip: 'تنها مرتبط با وو:تام.', // localized
				type: 'string'
			},
			{
				name: 'mailHeading',
				label: "عنوان بخش برای استفاده در پیام‌های \«ایمیل دارید\»", // localized
				type: 'string'
			}
		]
	},

	{
		title: 'زدودن پیوند', // localized
		preferences: [
			// TwinkleConfig.unlinkNamespaces (array)
			// In what namespaces unlink should happen, default in 0 (article), 10 (template), 100 (portal), and 118 (draft)
			{
				name: 'unlinkNamespaces',
				label: 'پیوندها را از صفحه‌هایی که در این فضاهای نام هستند بزدا', // localized
				helptip: 'از انتخاب فضاهای بحث پرهیز کنید، چون توینکل ممکن است پیوند به بایگانی‌های بحث را حذف کند که کاری است به شدت نکوهش شده.', // localized
				type: 'set',
				setValues: Twinkle.config.commonSets.namespacesNoSpecial
			}
		]
	},

	{
		title: 'هشدار به کاربر', // localized
		preferences: [
			// TwinkleConfig.defaultWarningGroup (int)
			// Which level warning should be the default selected group, default is 1
			{
				name: 'defaultWarningGroup',
				label: 'سطح پیش‌فرض هشدارها', // localized
				type: 'enum',
				enumValues: {
					'1': 'سطح ۱', // localized
					'2': 'سطح ۲', // localized
					'3': 'سطح ۳', // localized
					'4': 'سطح ۴', // localized
					'5': 'سطح ۵ (فوری)', // localized
					'6': 'اعلان راجع به یک مشکل واحد', // localized
					'7': 'هشدار راجع به یک مشکل واحد', // localized
					// 8 was used for block templates before #260
					'9': 'هشدار سفارشی', // localized
					'10': 'تمام الگوهای هشدار', // localized
					'11': 'انتخاب خودکار (سطح ۱-۴)' // localized
				}
			},

			// TwinkleConfig.combinedSingletMenus (boolean)
			// if true, show one menu with both single-issue notices and warnings instead of two separately
			{
				name: 'combinedSingletMenus',
				label: 'جایگزینی دو منوی جداگانه برای تک‌اشکال در یک منوی ترکیب‌شده', // localized
				helptip: 'انتخاب اعلان‌های تک‌اشکال یا هشدارهای تک‌اشکال به‌عنوان گزینهٔ پیش‌فرض شما، در صورت فعال بودن، این را به انتخاب پیش‌فرض شما تبدیل خواهد کرد.', // localized
				type: 'boolean'
			},

			// TwinkleConfig.showSharedIPNotice may take arguments:
			// true: to show shared ip notice if an IP address
			// false: to not print the notice
			{
				name: 'showSharedIPNotice',
				label: 'افزودن اعلان اضافی در صفحه‌های بحث آی‌پی مشترک', // localized
				helptip: 'اعلان مورد استفاده، {{آگاهی آی‌پی مشترک}} است', // localized
				type: 'boolean'
			},

			// TwinkleConfig.watchWarnings (boolean)
			// if true, watch the page which has been dispatched an warning or notice, if false, default applies
			{
				name: 'watchWarnings',
				label: 'افزودن بحث کاربری به فهرست پیگیری در زمان ارسال اعلان', // localized
				type: 'boolean'
			},

			// TwinkleConfig.oldSelect (boolean)
			// if true, use the native select menu rather the select2-based one
			{
				name: 'oldSelect',
				label: 'استفاده از منوی انتخاب کلاسیک غیر قابل جستجو', // localized
				type: 'boolean'
			},

			{
				name: 'customWarningList',
				label: 'الگوهای هشدار سفارشی برای نمایش', // localized
				helptip: 'می‌توانید الگوهای شخصی یا زیرصفحه‌های کاربری را بیافزایید. هشدارهای سفارشی در ردهٔ «هشدارهای سفارشی» در داخل کادر جعبهٔ هشدار نمایش می‌یابند.', // localized
				type: 'customList',
				customListValueTitle: 'نام الگو (بدون آکولاد)', // localized
				customListLabelTitle: 'متنی برای نمایش در فهرست هشدار (برای خلاصه ویرایش نیز استفاده می‌شود)' // localized
			}
		]
	},

	{
		title: 'خوشامدگویی', // localized
		preferences: [
			{
				name: 'topWelcomes',
				label: 'قرار دادن خوشامدهای در بالای محتوای موجود در صفحه‌های بحث کاربران', // localized
				type: 'boolean'
			},
			{
				name: 'watchWelcomes',
				label: 'افزودن صفحه‌های بحث کاربران به فهرست پیگیری در زمان خوشامدگویی', // localized
				helptip: 'انجام این کار، تجربهٔ شخصی شما از خوشامدگویی به یک کاربر را بهبود می‌بخشد - شما قادر خواهید بود تا واکنش کاربر به‌عنوان یک تازه‌کار را ببینید و احتمالاً به او کمک کنید.', // localized
				type: 'boolean'
			},
			{
				name: 'insertUsername',
				label: 'افزودن نام کربری شما به الگو (در صورت امکان)', // localized
				helptip: "برخی الگوهای خوشامد دارای جملهٔ اولیه‌ای مانند \«سلام، من &lt;username&gt; هستم. خوش آمدید\" یا مشابه آن هستند. اگر این گزینه را غیرفعال کنید، این الگوها نام کاربری شما را به‌این نحو نمایش نخواهند داد.", // localized
				type: 'boolean'
			},
			{
				name: 'quickWelcomeMode',
				label: 'عملکرد پیوند «خوشامد» در صفحهٔ تفاوت', // localized
				helptip: 'اگر حالت خوشامدگویی خودکار را انتخاب کنید، الگویی که در زیر مشخص کرده‌اید مورد استفاده قرار خواهد گرفت.', // localized
				type: 'enum',
				enumValues: { auto: 'خوشامدگویی خودکار', norm: 'الزام برای انتخاب یک الگو' } // localized
			},
			{
				name: 'quickWelcomeTemplate',
				label: 'الگوی مورد استفاده در زمان خوشامدگویی خودکار', // localized
				helptip: 'نام یک الگوی خواشمد را بدون استفاده از آکولاد وارد کنید. پیوندی به مقالهٔ مورد نظر اضافه خواهد شد.', // localized
				type: 'string'
			},
			{
				name: 'customWelcomeList',
				label: 'الگوهای خوشامد سفارشی برای نمایش', // localized
				helptip: "می‌توانید الگوهای خوشامد یا زیرصفحه‌های کاربری که الگوی خوشامدگویی هستند را اضافه کنید (همراه با پیشوند \"کاربر:\"). فراموش نکنید که این الگوها در صفحه‌های بحث کاربران جانشانی خواهند شد.", // localized
				type: 'customList',
				customListValueTitle: 'نام الگو (بدون آکولاد)', // localized
				customListLabelTitle: 'متنی برای نمایش در کادر خوشامد' // localized
			},
			{
				name: 'customWelcomeSignature',
				label: 'امضای خودکار الگوهای خوشامد سفارشی', // localized
				helptip: 'در صورتی که الگوهای خوشامد سفارشی شما شامل امضای یکپارچه در داخل الگو هستند، این گزینه را غیرفعال کنید.', // localized
				type: 'boolean'
			}
		]
	},

	{
		title: 'نظرخواهی برای حذف', // localized
		preferences: [
			{
				name: 'logXfdNominations',
				label: 'نگهداری یک سیاهه از نامزدی‌ها در نظرخواهی برای حذف (نبح) توسط شما در زیرصفحهٔ کاربری', // localized
				helptip: 'سیاههٔ نگهداری‌شده در زیرصفحهٔ کاربری می‌تواند برای پیگیری تمام صفحه‌هایی که با استفاده از توینکل نامزد نظرخواهی برای حذف کرده‌اید، مفید باشد.', // localized
				type: 'boolean'
			},
			{
				name: 'xfdLogPageName',
				label: 'نگهداری سیاههٔ نظرخواهی برای حذف در این زیرصفحهٔ کاربری', // localized
				helptip: 'نام یک زیرصفحه را در این جعبه وارد کنید. می‌توانید در صفحهٔ کاربر:<i>نام کربری</i>/<i>نام زیرصفحه</i> به سیاههٔ نظرخواهی برای حذف خود دسترسی داشته باشید. این قابلیت تنها در صورتی کار می‌کند که گزینهٔ سیاههٔ نظرخواهی برای حذف در زیرصفحه کاربری را فعال کرده باشید.', // localized
				type: 'string'
			},
			{
				name: 'noLogOnXfdNomination',
				label: 'برای نامزدی‌های حذف در این دسته، سیاهه‌ای در زیرصفحهٔ کاربری‌ام ایجاد نکن', // localized
				type: 'set',
				setValues: { afd: 'نبح'/*, tfd: 'TfD', ffd: 'FfD', cfd: 'CfD', cfds: 'CfD/S', mfd: 'MfD', rfd: 'RfD', rm: 'RM'*/ } // localized
			},

			// TwinkleConfig.xfdWatchPage (string)
			// The watchlist setting of the page being nominated for XfD. Either "yes" (add to watchlist), "no" (don't
			// add to watchlist), or "default" (use setting from preferences). Default is "default" (duh).
			{
				name: 'xfdWatchPage',
				label: 'صفحهٔ نامزد حذف را به فهرست پی‌گیری اضافه کن', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			},

			// TwinkleConfig.xfdWatchDiscussion (string)
			// The watchlist setting of the newly created XfD page (for those processes that create discussion pages for each nomination),
			// or the list page for the other processes.
			// Either "yes" (add to watchlist), "no" (don't add to watchlist), or "default" (use setting from preferences). Default is "default" (duh).
			{
				name: 'xfdWatchDiscussion',
				label: 'صفحهٔ نظرخواهی را به فهرست پی‌گیری اضافه کن', // localized
				helptip: 'این گزینه مربوط به صفحه‌ای است که در آن بحث راجع به حذف صورت می‌گیرد، یعنی صفحهٔ نظرخواهی', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			},

			// TwinkleConfig.xfdWatchList (string)
			// The watchlist setting of the XfD list page, *if* the discussion is on a separate page. Either "yes" (add to watchlist), "no" (don't
			// add to watchlist), or "default" (use setting from preferences). Default is "no" (Hehe. Seriously though, who wants to watch it?
			// Sorry in advance for any false positives.).
			/*
			{
				name: 'xfdWatchList',
				label: 'افزودن صفحهٔ سیاهه/فهرست روزانه به فهرست پیگیری (در صورت امکان)', // localized
				helptip: 'این گزینه تنها در مورد وو:نبح اعمال خواهد شد که بحث‌های آن در یک سیاههٔ روزانه یا صفحهٔ اصلی نبح تراگنجایش می‌شوند.', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			},
			*/ // localized [removed]

			// TwinkleConfig.xfdWatchUser (string)
			// The watchlist setting of the user talk page if they receive a notification. Either "yes" (add to watchlist), "no" (don't
			// add to watchlist), or "default" (use setting from preferences). Default is "default" (duh).
			{
				name: 'xfdWatchUser',
				label: 'صفحه بحث کاربر یا سازندهٔ اولیهٔ صفحه را در هنگام اطلاع‌رسانی به فهرست پیگیری اضافه کن', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			},

			// TwinkleConfig.xfdWatchRelated (string)
			// The watchlist setting of the target of a redirect being nominated for RfD. Either "yes" (add to watchlist), "no" (don't
			// add to watchlist), or "default" (use setting from preferences). Default is "default" (duh).
			{
				name: 'xfdWatchRelated',
				label: "در زمان اطلاع‌رسانی، صفحه هدف تغییرمسیر را به فهرست پیگیری اضافه کن", // localized
				helptip: 'این فقط برای زمانی کاربرد دارد که شما در صفحه بحث هدف تغییرمسیر اطلاع‌رسانی کرده‌اید.', // localized
				type: 'enum',
				enumValues: Twinkle.config.watchlistEnums
			},

			{
				name: 'markXfdPagesAsPatrolled',
				label: 'در صورت امکان صفحه را در زمان ایجاد نظرخواهی برای حذف گشت بزن', // localized
				type: 'boolean'
			}
		]
	},

	{
		title: 'پنهان', // localized
		hidden: true,
		preferences: [
			// twinkle.js: portlet setup
			{
				name: 'portletArea',
				type: 'string'
			},
			{
				name: 'portletId',
				type: 'string'
			},
			{
				name: 'portletName',
				type: 'string'
			},
			{
				name: 'portletType',
				type: 'string'
			},
			{
				name: 'portletNext',
				type: 'string'
			},
			// twinklefluff.js: defines how many revision to query maximum, maximum possible is 50, default is 50
			{
				name: 'revertMaxRevisions',
				type: 'integer'
			},
			// twinklewarn.js: When using the autolevel select option, how many days makes a prior warning stale
			// Huggle is three days ([[Special:Diff/918980316]] and [[Special:Diff/919417999]]) while ClueBotNG is two:
			// https://github.com/DamianZaremba/cluebotng/blob/4958e25d6874cba01c75f11debd2e511fd5a2ce5/bot/action_functions.php#L62
			{
				name: 'autolevelStaleDays',
				type: 'integer'
			},
			// twinklebatchdelete.js: How many pages should be processed maximum
			{
				name: 'batchMax',
				type: 'integer',
				adminOnly: true
			},
			// twinklebatchdelete.js: How many pages should be processed at a time
			{
				name: 'batchdeleteChunks',
				type: 'integer',
				adminOnly: true
			},
			// twinklebatchprotect.js: How many pages should be processed at a time
			{
				name: 'batchProtectChunks',
				type: 'integer',
				adminOnly: true
			},
			// twinklebatchundelete.js: How many pages should be processed at a time
			{
				name: 'batchundeleteChunks',
				type: 'integer',
				adminOnly: true
			},
			// twinkledeprod.js: How many pages should be processed at a time
			{
				name: 'proddeleteChunks',
				type: 'integer',
				adminOnly: true
			}
		]
	}

]; // end of Twinkle.config.sections


Twinkle.config.init = function twinkleconfigInit() {

	// create the config page at Wikipedia:Twinkle/Preferences
	if ((mw.config.get('wgNamespaceNumber') === mw.config.get('wgNamespaceIds').project && mw.config.get('wgTitle') === 'توینکل/ترجیحات') &&
			mw.config.get('wgAction') === 'view') {

		if (!document.getElementById('twinkle-config')) {
			return;  // maybe the page is misconfigured, or something - but any attempt to modify it will be pointless
		}

		// set style (the url() CSS function doesn't seem to work from wikicode - ?!)
		document.getElementById('twinkle-config-titlebar').style.backgroundImage = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB%2FqqA%2BAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAEhQTFRFr73ZobTPusjdsMHZp7nVwtDhzNbnwM3fu8jdq7vUt8nbxtDkw9DhpbfSvMrfssPZqLvVztbno7bRrr7W1d%2Fs1N7qydXk0NjpkW7Q%2BgAAADVJREFUeNoMwgESQCAAAMGLkEIi%2FP%2BnbnbpdB59app5Vdg0sXAoMZCpGoFbK6ciuy6FX4ABAEyoAef0BXOXAAAAAElFTkSuQmCC)';

		var contentdiv = document.getElementById('twinkle-config-content');
		contentdiv.textContent = '';  // clear children

		// let user know about possible conflict with skin js/common.js file
		// (settings in that file will still work, but they will be overwritten by twinkleoptions.js settings)
		if (window.TwinkleConfig || window.FriendlyConfig) {
			var contentnotice = document.createElement('p');
			contentnotice.innerHTML = '<table class="plainlinks ombox ombox-content"><tr><td class="mbox-image">' +
				'<img alt="" src="https://upload.wikimedia.org/wikipedia/commons/3/38/Imbox_content.png" /></td>' +
				'<td class="mbox-text"><p><big><b>قبل از ویرایش تنظیمات در اینجا،</b> شما باید تنظیمات قبلی توینکل یا تنظیمات سفارشی تم خود را حذف کنید.</big></p>' + // localized
				'<p>برای انجام آن شما می‌توانید <a href="' + mw.util.getUrl('User:' + mw.config.get('wgUserName') + '/' + mw.config.get('skin') + // localized
				'.js', { action: 'edit' }) + '" target="_blank"><b>فایل جاوااسکریپت شخصی خود</b></a> یا <a href="' + // localized
				mw.util.getUrl('User:' + mw.config.get('wgUserName') + '/common.js', { action: 'edit'}) + '" target="_blank"><b>فایل common.js خود را ویرایش کرده و</b></a> همه خط‌های کد که به <code>TwinkleConfig</code> و <code>FriendlyConfig</code> مرتبط است را حذف کنید.</p>' +  // localized
				'</td></tr></table>';
			contentdiv.appendChild(contentnotice);
		}

		// start a table of contents
		var toctable = document.createElement('div');
		toctable.className = 'toc';
		toctable.style.marginLeft = '0.4em';
		// create TOC title
		var toctitle = document.createElement('div');
		toctitle.id = 'toctitle';
		var toch2 = document.createElement('h2');
		toch2.textContent = 'Contents ';
		toctitle.appendChild(toch2);
		// add TOC show/hide link
		var toctoggle = document.createElement('span');
		toctoggle.className = 'toctoggle';
		toctoggle.appendChild(document.createTextNode('['));
		var toctogglelink = document.createElement('a');
		toctogglelink.className = 'internal';
		toctogglelink.setAttribute('href', '#tw-tocshowhide');
		toctogglelink.textContent = 'hide';
		toctoggle.appendChild(toctogglelink);
		toctoggle.appendChild(document.createTextNode(']'));
		toctitle.appendChild(toctoggle);
		toctable.appendChild(toctitle);
		// create item container: this is what we add stuff to
		var tocul = document.createElement('ul');
		toctogglelink.addEventListener('click', function twinkleconfigTocToggle() {
			var $tocul = $(tocul);
			$tocul.toggle();
			if ($tocul.find(':visible').length) {
				toctogglelink.textContent = 'hide';
			} else {
				toctogglelink.textContent = 'show';
			}
		}, false);
		toctable.appendChild(tocul);
		contentdiv.appendChild(toctable);

		var tocnumber = 1;

		var contentform = document.createElement('form');
		contentform.setAttribute('action', 'javascript:void(0)');  // was #tw-save - changed to void(0) to work around Chrome issue
		contentform.addEventListener('submit', Twinkle.config.save, true);
		contentdiv.appendChild(contentform);

		var container = document.createElement('table');
		container.style.width = '100%';
		contentform.appendChild(container);

		$(Twinkle.config.sections).each(function(sectionkey, section) {
			if (section.hidden || (section.adminOnly && !Morebits.userIsSysop)) {
				return true;  // i.e. "continue" in this context
			}

			// add to TOC
			var tocli = document.createElement('li');
			tocli.className = 'toclevel-1';
			var toca = document.createElement('a');
			toca.setAttribute('href', '#twinkle-config-section-' + tocnumber.toString());
			toca.appendChild(document.createTextNode(section.title));
			tocli.appendChild(toca);
			tocul.appendChild(tocli);

			var row = document.createElement('tr');
			var cell = document.createElement('td');
			cell.setAttribute('colspan', '3');
			var heading = document.createElement('h4');
			heading.style.borderBottom = '1px solid gray';
			heading.style.marginTop = '0.2em';
			heading.id = 'twinkle-config-section-' + (tocnumber++).toString();
			heading.appendChild(document.createTextNode(section.title));
			cell.appendChild(heading);
			row.appendChild(cell);
			container.appendChild(row);

			var rowcount = 1;  // for row banding

			// add each of the preferences to the form
			$(section.preferences).each(function(prefkey, pref) {
				if (pref.adminOnly && !Morebits.userIsSysop) {
					return true;  // i.e. "continue" in this context
				}

				row = document.createElement('tr');
				row.style.marginBottom = '0.2em';
				// create odd row banding
				if (rowcount++ % 2 === 0) {
					row.style.backgroundColor = 'rgba(128, 128, 128, 0.1)';
				}
				cell = document.createElement('td');

				var label, input;
				switch (pref.type) {

					case 'boolean':  // create a checkbox
						cell.setAttribute('colspan', '2');

						label = document.createElement('label');
						input = document.createElement('input');
						input.setAttribute('type', 'checkbox');
						input.setAttribute('id', pref.name);
						input.setAttribute('name', pref.name);
						if (Twinkle.getPref(pref.name) === true) {
							input.setAttribute('checked', 'checked');
						}
						label.appendChild(input);
						label.appendChild(document.createTextNode(' ' + pref.label));
						cell.appendChild(label);
						break;

					case 'string':  // create an input box
					case 'integer':
						// add label to first column
						cell.style.textAlign = 'right';
						cell.style.paddingRight = '0.5em';
						label = document.createElement('label');
						label.setAttribute('for', pref.name);
						label.appendChild(document.createTextNode(pref.label + ':'));
						cell.appendChild(label);
						row.appendChild(cell);

						// add input box to second column
						cell = document.createElement('td');
						cell.style.paddingRight = '1em';
						input = document.createElement('input');
						input.setAttribute('type', 'text');
						input.setAttribute('id', pref.name);
						input.setAttribute('name', pref.name);
						if (pref.type === 'integer') {
							input.setAttribute('size', 6);
							input.setAttribute('type', 'number');
							input.setAttribute('step', '1');  // integers only
						}
						if (Twinkle.getPref(pref.name)) {
							input.setAttribute('value', Twinkle.getPref(pref.name));
						}
						cell.appendChild(input);
						break;

					case 'enum':  // create a combo box
						// add label to first column
						// note: duplicates the code above, under string/integer
						cell.style.textAlign = 'right';
						cell.style.paddingRight = '0.5em';
						label = document.createElement('label');
						label.setAttribute('for', pref.name);
						label.appendChild(document.createTextNode(pref.label + ':'));
						cell.appendChild(label);
						row.appendChild(cell);

						// add input box to second column
						cell = document.createElement('td');
						cell.style.paddingRight = '1em';
						input = document.createElement('select');
						input.setAttribute('id', pref.name);
						input.setAttribute('name', pref.name);
						$.each(pref.enumValues, function(enumvalue, enumdisplay) {
							var option = document.createElement('option');
							option.setAttribute('value', enumvalue);
							if (Twinkle.getPref(pref.name) === enumvalue) {
								option.setAttribute('selected', 'selected');
							}
							option.appendChild(document.createTextNode(enumdisplay));
							input.appendChild(option);
						});
						cell.appendChild(input);
						break;

					case 'set':  // create a set of check boxes
						// add label first of all
						cell.setAttribute('colspan', '2');
						label = document.createElement('label');  // not really necessary to use a label element here, but we do it for consistency of styling
						label.appendChild(document.createTextNode(pref.label + ':'));
						cell.appendChild(label);

						var checkdiv = document.createElement('div');
						checkdiv.style.paddingLeft = '1em';
						var worker = function(itemkey, itemvalue) {
							var checklabel = document.createElement('label');
							checklabel.style.marginRight = '0.7em';
							checklabel.style.display = 'inline-block';
							var check = document.createElement('input');
							check.setAttribute('type', 'checkbox');
							check.setAttribute('id', pref.name + '_' + itemkey);
							check.setAttribute('name', pref.name + '_' + itemkey);
							if (Twinkle.getPref(pref.name) && Twinkle.getPref(pref.name).indexOf(itemkey) !== -1) {
								check.setAttribute('checked', 'checked');
							}
							// cater for legacy integer array values for unlinkNamespaces (this can be removed a few years down the track...)
							if (pref.name === 'unlinkNamespaces') {
								if (Twinkle.getPref(pref.name) && Twinkle.getPref(pref.name).indexOf(parseInt(itemkey, 10)) !== -1) {
									check.setAttribute('checked', 'checked');
								}
							}
							checklabel.appendChild(check);
							checklabel.appendChild(document.createTextNode(itemvalue));
							checkdiv.appendChild(checklabel);
						};
						if (pref.setDisplayOrder) {
							// add check boxes according to the given display order
							$.each(pref.setDisplayOrder, function(itemkey, item) {
								worker(item, pref.setValues[item]);
							});
						} else {
							// add check boxes according to the order it gets fed to us (probably strict alphabetical)
							$.each(pref.setValues, worker);
						}
						cell.appendChild(checkdiv);
						break;

					case 'customList':
						// add label to first column
						cell.style.textAlign = 'right';
						cell.style.paddingRight = '0.5em';
						label = document.createElement('label');
						label.setAttribute('for', pref.name);
						label.appendChild(document.createTextNode(pref.label + ':'));
						cell.appendChild(label);
						row.appendChild(cell);

						// add button to second column
						cell = document.createElement('td');
						cell.style.paddingRight = '1em';
						var button = document.createElement('button');
						button.setAttribute('id', pref.name);
						button.setAttribute('name', pref.name);
						button.setAttribute('type', 'button');
						button.addEventListener('click', Twinkle.config.listDialog.display, false);
						// use jQuery data on the button to store the current config value
						$(button).data({
							value: Twinkle.getPref(pref.name),
							pref: pref
						});
						button.appendChild(document.createTextNode('ویرایش آیتم‌ها')); // localized
						cell.appendChild(button);
						break;

					default:
						alert('twinkleconfig: unknown data type for preference ' + pref.name);
						break;
				}
				row.appendChild(cell);

				// add help tip
				cell = document.createElement('td');
				cell.style.fontSize = '90%';

				cell.style.color = 'gray';
				if (pref.helptip) {
					// convert mentions of templates in the helptip to clickable links
					cell.innerHTML = pref.helptip.replace(/{{(.+?)}}/g,
						'{{<a href="' + mw.util.getUrl('Template:') + '$1" target="_blank">$1</a>}}');
				}
				// add reset link (custom lists don't need this, as their config value isn't displayed on the form)
				if (pref.type !== 'customList') {
					var resetlink = document.createElement('a');
					resetlink.setAttribute('href', '#tw-reset');
					resetlink.setAttribute('id', 'twinkle-config-reset-' + pref.name);
					resetlink.addEventListener('click', Twinkle.config.resetPrefLink, false);
					resetlink.style.cssFloat = 'right';
					resetlink.style.margin = '0 0.6em';
					resetlink.appendChild(document.createTextNode('بازگشت به مقدار پیش‌فرض')); // localized
					cell.appendChild(resetlink);
				}
				row.appendChild(cell);

				container.appendChild(row);
				return true;
			});
			return true;
		});

		var footerbox = document.createElement('div');
		footerbox.setAttribute('id', 'twinkle-config-buttonpane');
		footerbox.style.backgroundColor = '#BCCADF';
		footerbox.style.padding = '0.5em';
		var button = document.createElement('button');
		button.setAttribute('id', 'twinkle-config-submit');
		button.setAttribute('type', 'submit');
		button.appendChild(document.createTextNode('ذخیره کردن تغییرات')); // localized
		footerbox.appendChild(button);
		var footerspan = document.createElement('span');
		footerspan.className = 'plainlinks';
		footerspan.style.marginLeft = '2.4em';
		footerspan.style.fontSize = '90%';
		var footera = document.createElement('a');
		footera.setAttribute('href', '#tw-reset-all');
		footera.setAttribute('id', 'twinkle-config-resetall');
		footera.addEventListener('click', Twinkle.config.resetAllPrefs, false);
		footera.appendChild(document.createTextNode('بازگرداندن مقادیر پیش‌فرض')); // localized
		footerspan.appendChild(footera);
		footerbox.appendChild(footerspan);
		contentform.appendChild(footerbox);

		// since all the section headers exist now, we can try going to the requested anchor
		if (location.hash) {
			window.location.hash = location.hash;
		}

	} else if (mw.config.get('wgNamespaceNumber') === mw.config.get('wgNamespaceIds').user &&
			mw.config.get('wgTitle').indexOf(mw.config.get('wgUserName')) === 0 &&
			mw.config.get('wgPageName').slice(-3) === '.js') {

		var box = document.createElement('div');
		// Styled in twinkle.css
		box.setAttribute('id', 'twinkle-config-headerbox');

		var link,
			scriptPageName = mw.config.get('wgPageName').slice(mw.config.get('wgPageName').lastIndexOf('/') + 1,
				mw.config.get('wgPageName').lastIndexOf('.js'));

		if (scriptPageName === 'twinkleoptions') {
			// place "why not try the preference panel" notice
			box.setAttribute('class', 'config-twopt-box');

			if (mw.config.get('wgArticleId') > 0) {  // page exists
				box.appendChild(document.createTextNode('این صفحه شامل تنظیمات توینکل است. شما می‌توانید آن را در ')); // localized
			} else {  // page does not exist
				box.appendChild(document.createTextNode('شما می‌توانید تنظیمات سفارشی خود برای توینکل را در ')); // localized
			}
			link = document.createElement('a');
			link.setAttribute('href', mw.util.getUrl(mw.config.get('wgFormattedNamespaces')[mw.config.get('wgNamespaceIds').project] + ':توینکل/ترجیحات'));
			link.appendChild(document.createTextNode('پنل تنظیمات توینکل')); // localized
			box.appendChild(link);
			box.appendChild(document.createTextNode('تغییر دهید یا این صفحه را ویرایش کنید.')); // localized
			$(box).insertAfter($('#contentSub'));

		} else if (['monobook', 'vector', 'cologneblue', 'modern', 'timeless', 'minerva', 'common'].indexOf(scriptPageName) !== -1) {
			// place "Looking for Twinkle options?" notice
			box.setAttribute('class', 'config-userskin-box');

			box.appendChild(document.createTextNode('اگر می‌خواهید تنظیمات توینکل را تغییر دهید می‌توانید از ')); // localized
			link = document.createElement('a');
			link.setAttribute('href', mw.util.getUrl(mw.config.get('wgFormattedNamespaces')[mw.config.get('wgNamespaceIds').project] + ':توینکل/ترجیحات'));
			link.appendChild(document.createTextNode('پنل تنظیمات توینکل')); // localized
			box.appendChild(link);
			box.appendChild(document.createTextNode('استفاده کنید.')); // localized
			$(box).insertAfter($('#contentSub'));
		}
	}
};

// custom list-related stuff

Twinkle.config.listDialog = {};

Twinkle.config.listDialog.addRow = function twinkleconfigListDialogAddRow(dlgtable, value, label) {
	var contenttr = document.createElement('tr');
	// "remove" button
	var contenttd = document.createElement('td');
	var removeButton = document.createElement('button');
	removeButton.setAttribute('type', 'button');
	removeButton.addEventListener('click', function() {
		$(contenttr).remove();
	}, false);
	removeButton.textContent = 'حذف'; // localized
	contenttd.appendChild(removeButton);
	contenttr.appendChild(contenttd);

	// value input box
	contenttd = document.createElement('td');
	var input = document.createElement('input');
	input.setAttribute('type', 'text');
	input.className = 'twinkle-config-customlist-value';
	input.style.width = '97%';
	if (value) {
		input.setAttribute('value', value);
	}
	contenttd.appendChild(input);
	contenttr.appendChild(contenttd);

	// label input box
	contenttd = document.createElement('td');
	input = document.createElement('input');
	input.setAttribute('type', 'text');
	input.className = 'twinkle-config-customlist-label';
	input.style.width = '98%';
	if (label) {
		input.setAttribute('value', label);
	}
	contenttd.appendChild(input);
	contenttr.appendChild(contenttd);

	dlgtable.appendChild(contenttr);
};

Twinkle.config.listDialog.display = function twinkleconfigListDialogDisplay(e) {
	var $prefbutton = $(e.target);
	var curvalue = $prefbutton.data('value');
	var curpref = $prefbutton.data('pref');

	var dialog = new Morebits.simpleWindow(720, 400);
	dialog.setTitle(curpref.label);
	dialog.setScriptName('تنظیمات توینکل'); // localized

	var dialogcontent = document.createElement('div');
	var dlgtable = document.createElement('table');
	dlgtable.className = 'wikitable';
	dlgtable.style.margin = '1.4em 1em';
	dlgtable.style.width = 'auto';

	var dlgtbody = document.createElement('tbody');

	// header row
	var dlgtr = document.createElement('tr');
	// top-left cell
	var dlgth = document.createElement('th');
	dlgth.style.width = '5%';
	dlgtr.appendChild(dlgth);
	// value column header
	dlgth = document.createElement('th');
	dlgth.style.width = '35%';
	dlgth.textContent = curpref.customListValueTitle ? curpref.customListValueTitle : 'Value';
	dlgtr.appendChild(dlgth);
	// label column header
	dlgth = document.createElement('th');
	dlgth.style.width = '60%';
	dlgth.textContent = curpref.customListLabelTitle ? curpref.customListLabelTitle : 'Label';
	dlgtr.appendChild(dlgth);
	dlgtbody.appendChild(dlgtr);

	// content rows
	var gotRow = false;
	$.each(curvalue, function(k, v) {
		gotRow = true;
		Twinkle.config.listDialog.addRow(dlgtbody, v.value, v.label);
	});
	// if there are no values present, add a blank row to start the user off
	if (!gotRow) {
		Twinkle.config.listDialog.addRow(dlgtbody);
	}

	// final "add" button
	var dlgtfoot = document.createElement('tfoot');
	dlgtr = document.createElement('tr');
	var dlgtd = document.createElement('td');
	dlgtd.setAttribute('colspan', '3');
	var addButton = document.createElement('button');
	addButton.style.minWidth = '8em';
	addButton.setAttribute('type', 'button');
	addButton.addEventListener('click', function() {
		Twinkle.config.listDialog.addRow(dlgtbody);
	}, false);
	addButton.textContent = 'اضافه‌کردن'; // localized
	dlgtd.appendChild(addButton);
	dlgtr.appendChild(dlgtd);
	dlgtfoot.appendChild(dlgtr);

	dlgtable.appendChild(dlgtbody);
	dlgtable.appendChild(dlgtfoot);
	dialogcontent.appendChild(dlgtable);

	// buttonpane buttons: [Save changes] [Reset] [Cancel]
	var button = document.createElement('button');
	button.setAttribute('type', 'submit');  // so Morebits.simpleWindow puts the button in the button pane
	button.addEventListener('click', function() {
		Twinkle.config.listDialog.save($prefbutton, dlgtbody);
		dialog.close();
	}, false);
	button.textContent = 'ذخیره تغییرات'; // localized
	dialogcontent.appendChild(button);
	button = document.createElement('button');
	button.setAttribute('type', 'submit');  // so Morebits.simpleWindow puts the button in the button pane
	button.addEventListener('click', function() {
		Twinkle.config.listDialog.reset($prefbutton, dlgtbody);
	}, false);
	button.textContent = 'بازنشانی'; // localized
	dialogcontent.appendChild(button);
	button = document.createElement('button');
	button.setAttribute('type', 'submit');  // so Morebits.simpleWindow puts the button in the button pane
	button.addEventListener('click', function() {
		dialog.close();  // the event parameter on this function seems to be broken
	}, false);
	button.textContent = 'لغو'; // localized
	dialogcontent.appendChild(button);

	dialog.setContent(dialogcontent);
	dialog.display();
};

// Resets the data value, re-populates based on the new (default) value, then saves the
// old data value again (less surprising behaviour)
Twinkle.config.listDialog.reset = function twinkleconfigListDialogReset(button, tbody) {
	// reset value on button
	var $button = $(button);
	var curpref = $button.data('pref');
	var oldvalue = $button.data('value');
	Twinkle.config.resetPref(curpref);

	// reset form
	var $tbody = $(tbody);
	$tbody.find('tr').slice(1).remove();  // all rows except the first (header) row
	// add the new values
	var curvalue = $button.data('value');
	$.each(curvalue, function(k, v) {
		Twinkle.config.listDialog.addRow(tbody, v.value, v.label);
	});

	// save the old value
	$button.data('value', oldvalue);
};

Twinkle.config.listDialog.save = function twinkleconfigListDialogSave(button, tbody) {
	var result = [];
	var current = {};
	$(tbody).find('input[type="text"]').each(function(inputkey, input) {
		if ($(input).hasClass('twinkle-config-customlist-value')) {
			current = { value: input.value };
		} else {
			current.label = input.value;
			// exclude totally empty rows
			if (current.value || current.label) {
				result.push(current);
			}
		}
	});
	$(button).data('value', result);
};

// reset/restore defaults

Twinkle.config.resetPrefLink = function twinkleconfigResetPrefLink(e) {
	var wantedpref = e.target.id.substring(21); // "twinkle-config-reset-" prefix is stripped

	// search tactics
	$(Twinkle.config.sections).each(function(sectionkey, section) {
		if (section.hidden || (section.adminOnly && !Morebits.userIsSysop)) {
			return true;  // continue: skip impossibilities
		}

		var foundit = false;

		$(section.preferences).each(function(prefkey, pref) {
			if (pref.name !== wantedpref) {
				return true;  // continue
			}
			Twinkle.config.resetPref(pref);
			foundit = true;
			return false;  // break
		});

		if (foundit) {
			return false;  // break
		}
	});
	return false;  // stop link from scrolling page
};

Twinkle.config.resetPref = function twinkleconfigResetPref(pref) {
	switch (pref.type) {

		case 'boolean':
			document.getElementById(pref.name).checked = Twinkle.defaultConfig[pref.name];
			break;

		case 'string':
		case 'integer':
		case 'enum':
			document.getElementById(pref.name).value = Twinkle.defaultConfig[pref.name];
			break;

		case 'set':
			$.each(pref.setValues, function(itemkey) {
				if (document.getElementById(pref.name + '_' + itemkey)) {
					document.getElementById(pref.name + '_' + itemkey).checked = Twinkle.defaultConfig[pref.name].indexOf(itemkey) !== -1;
				}
			});
			break;

		case 'customList':
			$(document.getElementById(pref.name)).data('value', Twinkle.defaultConfig[pref.name]);
			break;

		default:
			alert('تنظیمات توینکل: نوع داده برای ' + pref.name + ' اشتباه است'); // localized
			break;
	}
};

Twinkle.config.resetAllPrefs = function twinkleconfigResetAllPrefs() {
	// no confirmation message - the user can just refresh/close the page to abort
	$(Twinkle.config.sections).each(function(sectionkey, section) {
		if (section.hidden || (section.adminOnly && !Morebits.userIsSysop)) {
			return true;  // continue: skip impossibilities
		}
		$(section.preferences).each(function(prefkey, pref) {
			if (!pref.adminOnly || Morebits.userIsSysop) {
				Twinkle.config.resetPref(pref);
			}
		});
		return true;
	});
	return false;  // stop link from scrolling page
};

Twinkle.config.save = function twinkleconfigSave(e) {
	Morebits.status.init(document.getElementById('twinkle-config-content'));

	var userjs = mw.config.get('wgFormattedNamespaces')[mw.config.get('wgNamespaceIds').user] + ':' + mw.config.get('wgUserName') + '/twinkleoptions.js';
	var wikipedia_page = new Morebits.wiki.page(userjs, 'ذخیره تنظیمات در ' + userjs); // localized
	wikipedia_page.setCallbackParameters(e.target);
	wikipedia_page.load(Twinkle.config.writePrefs);

	return false;
};

Twinkle.config.writePrefs = function twinkleconfigWritePrefs(pageobj) {
	var form = pageobj.getCallbackParameters();

	// this is the object which gets serialized into JSON; only
	// preferences that this script knows about are kept
	var newConfig = {optionsVersion: 2};

	// a comparison function is needed later on
	// it is just enough for our purposes (i.e. comparing strings, numbers, booleans,
	// arrays of strings, and arrays of { value, label })
	// and it is not very robust: e.g. compare([2], ["2"]) === true, and
	// compare({}, {}) === false, but it's good enough for our purposes here
	var compare = function(a, b) {
		if (Array.isArray(a)) {
			if (a.length !== b.length) {
				return false;
			}
			var asort = a.sort(), bsort = b.sort();
			for (var i = 0; asort[i]; ++i) {
				// comparison of the two properties of custom lists
				if ((typeof asort[i] === 'object') && (asort[i].label !== bsort[i].label ||
					asort[i].value !== bsort[i].value)) {
					return false;
				} else if (asort[i].toString() !== bsort[i].toString()) {
					return false;
				}
			}
			return true;
		}
		return a === b;

	};

	$(Twinkle.config.sections).each(function(sectionkey, section) {
		if (section.adminOnly && !Morebits.userIsSysop) {
			return;  // i.e. "continue" in this context
		}

		// reach each of the preferences from the form
		$(section.preferences).each(function(prefkey, pref) {
			var userValue;  // = undefined

			// only read form values for those prefs that have them
			if (!pref.adminOnly || Morebits.userIsSysop) {
				if (!section.hidden) {
					switch (pref.type) {
						case 'boolean':  // read from the checkbox
							userValue = form[pref.name].checked;
							break;

						case 'string':  // read from the input box or combo box
						case 'enum':
							userValue = form[pref.name].value;
							break;

						case 'integer':  // read from the input box
							userValue = parseInt(form[pref.name].value, 10);
							if (isNaN(userValue)) {
								Morebits.status.warn('در حال ذخیره', 'مقداری که برای ' + pref.name + ' (' + pref.value + ') انتخاب کرده‌اید اشتباه است.  ذخیره کردن ادامه می‌یابد اما مقدار مشکل‌دار ثبت نمی‌شود.'); // localized
								userValue = null;
							}
							break;

						case 'set':  // read from the set of check boxes
							userValue = [];
							if (pref.setDisplayOrder) {
							// read only those keys specified in the display order
								$.each(pref.setDisplayOrder, function(itemkey, item) {
									if (form[pref.name + '_' + item].checked) {
										userValue.push(item);
									}
								});
							} else {
							// read all the keys in the list of values
								$.each(pref.setValues, function(itemkey) {
									if (form[pref.name + '_' + itemkey].checked) {
										userValue.push(itemkey);
									}
								});
							}
							break;

						case 'customList':  // read from the jQuery data stored on the button object
							userValue = $(form[pref.name]).data('value');
							break;

						default:
							alert('twinkleconfig: unknown data type for preference ' + pref.name);
							break;
					}
				} else if (Twinkle.prefs) {
					// Retain the hidden preferences that may have customised by the user from twinkleoptions.js
					// undefined if not set
					userValue = Twinkle.prefs[pref.name];
				}
			}

			// only save those preferences that are *different* from the default
			if (userValue !== undefined && !compare(userValue, Twinkle.defaultConfig[pref.name])) {
				newConfig[pref.name] = userValue;
			}
		});
	});

	var text =
		'// twinkleoptions.js: personal Twinkle preferences file\n' +
		'//\n' +
		'// NOTE: The easiest way to change your Twinkle preferences is by using the\n' +
		'// Twinkle preferences panel, at [[' + Morebits.pageNameNorm + ']].\n' +
		'//\n' +
		'// This file is AUTOMATICALLY GENERATED.  Any changes you make (aside from\n' +
		'// changing the configuration parameters in a valid-JavaScript way) will be\n' +
		'// overwritten the next time you click "save" in the Twinkle preferences\n' +
		'// panel.  If modifying this file, make sure to use correct JavaScript.\n' +
		'// <no' + 'wiki>\n' +
		'\n' +
		'window.Twinkle.prefs = ';
	text += JSON.stringify(newConfig, null, 2);
	text +=
		';\n' +
		'\n' +
		'// </no' + 'wiki>\n' +
		'// End of twinkleoptions.js\n';

	pageobj.setPageText(text);
	pageobj.setEditSummary('ذخیره تنظیمات توینکل: ویرایش خودکار از [[:' + Morebits.pageNameNorm + ']] ([[وو:تل]])'); // localized
	pageobj.setCreateOption('recreate');
	pageobj.save(Twinkle.config.saveSuccess);
};

Twinkle.config.saveSuccess = function twinkleconfigSaveSuccess(pageobj) {
	pageobj.getStatusElement().info('successful');

	var noticebox = document.createElement('div');
	noticebox.className = 'successbox';
	noticebox.style.fontSize = '100%';
	noticebox.style.marginTop = '2em';
	noticebox.innerHTML = '<p><b>تنظیمات توینکل شما ذخیره شد.</b></p><p>برای دیدن تغییرات باید <b>کاشه مرورگر را خالی کنید</b> (توضیح بیشتر در<a href="' + mw.util.getUrl('WP:BYPASS') + '" title="وو:کاشه">وو:کاشه</a>).</p>'; // localized
	Morebits.status.root.appendChild(noticebox);
	var noticeclear = document.createElement('br');
	noticeclear.style.clear = 'both';
	Morebits.status.root.appendChild(noticeclear);
};
})(jQuery);


// </nowiki>