# MediaWiki:Gadget-twinkleconfig-2020.js

From faraghaib
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press 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('الگو:') + '$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('وپ:کاشه') + '" 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>

Retrieved from "https://en.faraghaib.ir/w/index.php?title=MediaWiki:Gadget-twinkleconfig-2020.js&oldid=448"