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

از ویکی‌واژه

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

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

(function($) {


/*
 ****************************************
 *** friendlytag.js: Tag module
 ****************************************
 * Mode of invocation:     Tab ("Tag")
 * Active on:              Existing articles and drafts; file pages with a corresponding file
 *                         which is local (not on Commons); all redirects
 */

Twinkle.tag = function friendlytag() {
	// redirect tagging
	if (Morebits.wiki.isPageRedirect()) {
		Twinkle.tag.mode = 'redirect';
		Twinkle.addPortletLink(Twinkle.tag.callback, 'برچسب', 'friendly-tag', 'تغییرمسیر برچسب'); // localized
	// file tagging
	} else if (mw.config.get('wgNamespaceNumber') === 6 && !document.getElementById('mw-sharedupload') && document.getElementById('mw-imagepage-section-filehistory')) {
		Twinkle.tag.mode = 'file';
		Twinkle.addPortletLink(Twinkle.tag.callback, 'برچسب', 'friendly-tag', 'زدن برچسب‌های نگهداری به پرونده'); // localized
	// article/draft article tagging
	} else if ([0, 118].indexOf(mw.config.get('wgNamespaceNumber')) !== -1 && mw.config.get('wgCurRevisionId')) {
		Twinkle.tag.mode = 'article';
		// Can't remove tags when not viewing current version
		Twinkle.tag.canRemove = (mw.config.get('wgCurRevisionId') === mw.config.get('wgRevisionId')) &&
			// Disabled on latest diff because the diff slider could be used to slide
			// away from the latest diff without causing the script to reload
			!mw.config.get('wgDiffNewId');
		Twinkle.addPortletLink(Twinkle.tag.callback, 'برچسب', 'friendly-tag', 'افزودن یا حذف برچسب‌های نگهداری مقاله'); // localized
	}
};

Twinkle.tag.checkedTags = [];

Twinkle.tag.callback = function friendlytagCallback() {
	var Window = new Morebits.simpleWindow(630, Twinkle.tag.mode === 'article' ? 500 : 400);
	Window.setScriptName('Twinkle');
	// anyone got a good policy/guideline/info page/instructional page link??
	Window.addFooterLink('Twinkle help', 'WP:TW/DOC#tag');

	var form = new Morebits.quickForm(Twinkle.tag.callback.evaluate);

	form.append({
		type: 'input',
		label: 'پالایش سریع: ', // localized
		name: 'quickfilter',
		size: '30px',
		event: function twinkletagquickfilter() {
			// flush the DOM of all existing underline spans
			$allCheckboxDivs.find('.search-hit').each(function(i, e) {
				var label_element = e.parentElement;
				// This would convert <label>Hello <span class=search-hit>wo</span>rld</label>
				// to <label>Hello world</label>
				label_element.innerHTML = label_element.textContent;
			});

			if (this.value) {
				$allCheckboxDivs.hide();
				$allHeaders.hide();
				var searchString = this.value;
				var searchRegex = new RegExp(mw.util.escapeRegExp(searchString), 'i');

				$allCheckboxDivs.find('label').each(function () {
					var label_text = this.textContent;
					var searchHit = searchRegex.exec(label_text);
					if (searchHit) {
						var range = document.createRange();
						var textnode = this.childNodes[0];
						range.selectNodeContents(textnode);
						range.setStart(textnode, searchHit.index);
						range.setEnd(textnode, searchHit.index + searchString.length);
						var underline_span = $('<span>').addClass('search-hit').css('text-decoration', 'underline')[0];
						range.surroundContents(underline_span);
						this.parentElement.style.display = 'block'; // show
					}
				});
			} else {
				$allCheckboxDivs.show();
				$allHeaders.show();
			}
		}
	});

	switch (Twinkle.tag.mode) {
		case 'article':
			Window.setTitle('Article maintenance tagging');

			form.append({
				type: 'select',
				name: 'sortorder',
				label: 'مشاهده این فهرست:', // localized
				tooltip: 'می‌توانید ترتیب پیش‌فرض نمایش را در ترجیحات توینکل خود تغییر دهید (وپ:توینکل تر).', // localized
				event: Twinkle.tag.updateSortOrder,
				list: [
					{ type: 'option', value: 'cat', label: 'بر پایه رده', selected: Twinkle.getPref('tagArticleSortOrder') === 'cat' }, // localized
					{ type: 'option', value: 'alpha', label: 'به‌ترتیب الفبا', selected: Twinkle.getPref('tagArticleSortOrder') === 'alpha' } // localized
				]
			});


			if (!Twinkle.tag.canRemove) {
				var divElement = document.createElement('div');
				divElement.innerHTML = 'برای حذف برچسب‌های موجود، لطفاً منوی برچسب را از نسخهٔ کنونی مقاله باز کنید'; // localized
				form.append({
					type: 'div',
					name: 'untagnotice',
					label: divElement
				});
			}

			form.append({
				type: 'div',
				id: 'tagWorkArea',
				className: 'morebits-scrollbox',
				style: 'max-height: 28em'
			});

			form.append({
				type: 'checkbox',
				list: [
					{
						label: 'گروه‌بندی برچسب‌ها در {{مشکلات متعدد}}، در صورت امکان', // localized
						value: 'group',
						name: 'group',
						tooltip: 'در صورتی که در حال افزودن دو یا چند الگویی که توسط {{مشکلات متعدد}} پشتیبانی می‌شوند هستید و این گزینه نیز انتخاب شده‌است، تمامی الگوهای پشتیبانی‌شده در درون الگوی {{مشکلات متعدد}} گروه‌بندی خواهند شد.', // localized
						checked: Twinkle.getPref('groupByDefault')
					}
				]
			});

			form.append({
				type: 'input',
				label: 'دلیل',
				name: 'reason',
				tooltip: 'دلیل اختیاری برای پیوست‌شدن به خلاصه ویرایش. ذکر دلیل به‌هنگام حذف برچسب‌ها توصیه می‌شود.', // localized
				size: '60px'
			});

			break;

		case 'file':
			Window.setTitle('File maintenance tagging');

			form.append({ type: 'header', label: 'برچسب‌های مشکلات مجوز و منبع‌دهی' }); // localized
			form.append({ type: 'checkbox', name: 'fileTags', list: Twinkle.tag.file.licenseList });

			form.append({ type: 'header', label: 'برچسب‌های مرتبط با ویکی‌انبار' }); // localized
			form.append({ type: 'checkbox', name: 'fileTags', list: Twinkle.tag.file.commonsList });

			form.append({ type: 'header', label: 'برچسب‌های تمیزکاری' }); // localized
			form.append({ type: 'checkbox', name: 'fileTags', list: Twinkle.tag.file.cleanupList });

			form.append({ type: 'header', label: 'برچسب‌های کیفیت تصویر' }); // localized
			form.append({ type: 'checkbox', name: 'fileTags', list: Twinkle.tag.file.qualityList });

			form.append({ type: 'header', label: 'برچسب‌های جایگزینی' }); // localized
			form.append({ type: 'checkbox', name: 'fileTags', list: Twinkle.tag.file.replacementList });

			if (Twinkle.getPref('customFileTagList').length) {
				form.append({ type: 'header', label: 'برچسب‌های سفارشی' }); // localized
				form.append({ type: 'checkbox', name: 'fileTags', list: Twinkle.getPref('customFileTagList') });
			}
			break;

		case 'redirect':
			Window.setTitle('Redirect tagging');

			form.append({ type: 'header', label: 'Spelling, misspelling, tense and capitalization templates' });
			form.append({ type: 'checkbox', name: 'redirectTags', list: Twinkle.tag.spellingList });

			form.append({ type: 'header', label: 'الگوهای نام جایگزین' }); // localized
			form.append({ type: 'checkbox', name: 'redirectTags', list: Twinkle.tag.alternativeList });

			form.append({ type: 'header', label: 'الگوهای تغییرمسیر گوناگون و مدیریتی' }); // localized
			form.append({ type: 'checkbox', name: 'redirectTags', list: Twinkle.tag.administrativeList });

			if (Twinkle.getPref('customRedirectTagList').length) {
				form.append({ type: 'header', label: 'برچسب‌های سفارشی' }); // localized
				form.append({ type: 'checkbox', name: 'redirectTags', list: Twinkle.getPref('customRedirectTagList') });
			}
			break;

		default:
			alert('Twinkle.tag: unknown mode ' + Twinkle.tag.mode);
			break;
	}

	if (document.getElementsByClassName('patrollink').length) {
		form.append({
			type: 'checkbox',
			list: [
				{
					label: 'علامت زدن صفحه به‌عنوان گشت‌خورده/بازبینی‌شده', // localized
					value: 'patrolPage',
					name: 'patrolPage',
					checked: Twinkle.getPref('markTaggedPagesAsPatrolled')
				}
			]
		});
	}
	form.append({ type: 'submit', className: 'tw-tag-submit' });

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

	// for quick filter:
	$allCheckboxDivs = $(result).find('[name$=Tags]').parent();
	$allHeaders = $(result).find('h5');
	result.quickfilter.focus();  // place cursor in the quick filter field as soon as window is opened
	result.quickfilter.autocomplete = 'off'; // disable browser suggestions
	result.quickfilter.addEventListener('keypress', function(e) {
		if (e.keyCode === 13) { // prevent enter key from accidentally submitting the form
			e.preventDefault();
			return false;
		}
	});

	if (Twinkle.tag.mode === 'article') {

		Twinkle.tag.alreadyPresentTags = [];

		if (Twinkle.tag.canRemove) {
			// Look for existing maintenance tags in the lead section and put them in array

			// All tags are HTML table elements that are direct children of .mw-parser-output,
			// except when they are within {{multiple issues}}
			$('.mw-parser-output').children().each(function parsehtml(i, e) {

				// break out on encountering the first heading, which means we are no
				// longer in the lead section
				if (e.tagName === 'H2') {
					return false;
				}

				// The ability to remove tags depends on the template's {{ambox}} |name=
				// parameter bearing the template's correct name (preferably) or a name that at
				// least redirects to the actual name

				// All tags have their first class name as "box-" + template name
				if (e.className.indexOf('box-') === 0) {
					if (e.classList[0] === 'box-Multiple_issues') {
						$(e).find('.ambox').each(function(idx, e) {
							var tag = e.classList[0].slice(4).replace(/_/g, ' ');
							Twinkle.tag.alreadyPresentTags.push(tag);
						});
						return true; // continue
					}

					var tag = e.classList[0].slice(4).replace(/_/g, ' ');
					Twinkle.tag.alreadyPresentTags.push(tag);
				}
			});

			// {{Uncategorized}} and {{Improve categories}} are usually placed at the end
			if ($('.box-Uncategorized').length) {
				Twinkle.tag.alreadyPresentTags.push('Uncategorized');
			}
			if ($('.box-Improve_categories').length) {
				Twinkle.tag.alreadyPresentTags.push('Improve categories');
			}

		}

		// Add status text node after Submit button
		var statusNode = document.createElement('small');
		statusNode.id = 'tw-tag-status';
		Twinkle.tag.status = {
			// initial state; defined like this because these need to be available for reference
			// in the click event handler
			numAdded: 0,
			numRemoved: 0
		};
		$('button.tw-tag-submit').after(statusNode);

		// fake a change event on the sort dropdown, to initialize the tag list
		var evt = document.createEvent('Event');
		evt.initEvent('change', true, true);
		result.sortorder.dispatchEvent(evt);

	} else {
		// Redirects and files: Add a link to each template's description page
		Morebits.quickForm.getElements(result, Twinkle.tag.mode + 'Tags').forEach(generateLinks);
	}
};


// $allCheckboxDivs and $allHeaders are defined globally, rather than in the
// quickfilter event function, to avoid having to recompute them on every keydown
var $allCheckboxDivs, $allHeaders;

Twinkle.tag.updateSortOrder = function(e) {
	var form = e.target.form;
	var sortorder = e.target.value;
	Twinkle.tag.checkedTags = form.getChecked('articleTags') || [];

	var container = new Morebits.quickForm.element({ type: 'fragment' });

	// function to generate a checkbox, with appropriate subgroup if needed
	var makeCheckbox = function(tag, description) {
		var checkbox = { value: tag, label: '{{' + tag + '}}: ' + description };
		if (Twinkle.tag.checkedTags.indexOf(tag) !== -1) {
			checkbox.checked = true;
		}
		switch (tag) {
			case 'Cleanup':
				checkbox.subgroup = {
					name: 'cleanup',
					type: 'input',
					label: 'دلیل مشخص برای اینکه چرا به تمیزکاری نیاز است: ', // localized
					tooltip: 'الزامی.', // localized
					size: 35
				};
				break;
			case 'Close paraphrasing':
				checkbox.subgroup = {
					name: 'closeParaphrasing',
					type: 'input',
					label: 'منبع: ', // localized
					tooltip: 'منبعی که به‌طور نزدیک بازنویسی شده‌است' // localized
				};
				break;
			case 'Copy edit':
				checkbox.subgroup = {
					name: 'copyEdit',
					type: 'input',
					label: '"این مقاله ممکن است نیازمند ویرایستاری باشد..." ', // localized
					tooltip: 'به‌عنوان مثال، "املای یکپارچه". انتخابی.', // localized
					size: 35
				};
				break;
			case 'Copypaste':
				checkbox.subgroup = {
					name: 'copypaste',
					type: 'input',
					label: 'نشانی منبع: ', // localized
					tooltip: 'اگر مشخص است.', // localized
					size: 50
				};
				break;
			case 'Expand language':
				checkbox.subgroup = [ {
					name: 'expandLanguageLangCode',
					type: 'input',
					label: 'شناسه زبان: ', // localized
					tooltip: 'شناسهٔ زبانی که مقاله باید از روی آن گسترش داده‌شود' // localized
				}, {
					name: 'expandLanguageArticle',
					type: 'input',
					label: 'عنوان مقاله: ', // localized
					tooltip: 'عنوان مقاله‌ای که گسترش از روی آن انجام می‌شود، بدون پیشوند میان‌ویکی' // localized
				}
				];
				break;
			case 'Expert needed':
				checkbox.subgroup = [
					{
						name: 'expertNeeded',
						type: 'input',
						label: 'عنوان ویکی‌پروژهٔ مرتبط: ', // localized
						tooltip: 'به‌طور انتخابی، نام ویکی‌پروژه‌ای که می‌تواند به جذب یک کاربر باتجربه کمک کند را وارد کنید. بدون پیشوند «ویکی‌پروژه».' // localized
					},
					{
						name: 'expertNeededReason',
						type: 'input',
						label: 'دلیل: ', // localized
						tooltip: 'توضیح کوتاه برای توصیف مشکل. پیوند به دلیل یا بحث الزامی است.' // localized
					},
					{
						name: 'expertNeededTalk',
						type: 'input',
						label: 'ریسهٔ بحث: ', // localized
						tooltip: 'عنوان بخشی از صفحهٔ بحث این مقاله که بحث دربارهٔ مشکل در آن جریان دارد. نیاز به درج پیوند نیست، تنها عنوان بخش را وارد کنید. پیوند به دلیل یا بحث الزامی است.' // localized
					}
				];
				break;
			case 'Globalize':
				checkbox.subgroup = {
					name: 'globalizeRegion',
					type: 'input',
					label: 'منطقه یا کشورِ بیش از اندازه معرفی‌شده' // localized
				};
				break;
			case 'History merge':
				checkbox.subgroup = [
					{
						name: 'histmergeOriginalPage',
						type: 'input',
						label: 'مقالهٔ دیگر: ', // localized
						tooltip: 'عنوان صفحه‌ای که می‌تواند در این مقاله ادغام شود (الزامی).' // localized
					},
					{
						name: 'histmergeReason',
						type: 'input',
						label: 'دلیل: ', // localized
						tooltip: 'توضیح کوتاه که دلیل نیاز به ادغام تاریخچه را بیان کند. بهتر است با عبارت «زیرا» آغاز شده و با یک نقطه پایان یابد.' // localized
					},
					{
						name: 'histmergeSysopDetails',
						type: 'input',
						label: 'جزئیات بیشتر: ', // localized
						tooltip: 'برای موارد پیچیده، راهنمایی‌های بیشتری را در اختیار مدیر بررسی‌کننده قرار دهید.' // localized
					}
				];
				break;
			case 'Merge':
			case 'Merge from':
			case 'Merge to':
				var otherTagName = 'Merge';
				switch (tag) {
					case 'Merge from':
						otherTagName = 'Merge to';
						break;
					case 'Merge to':
						otherTagName = 'Merge from';
						break;
					// no default
				}
				checkbox.subgroup = [
					{
						name: 'mergeTarget',
						type: 'input',
						label: 'مقاله(های) دیگر: ', // localized
						tooltip: 'اگر قصد دارید مقاله‌های متعدد را مشخص کنید، آن‌ها را با نویسهٔ لوله از هم جدا کنید: مقالهٔ اول|مقالهٔ دوم' // localized
					},
					{
						name: 'mergeTagOther',
						type: 'checkbox',
						list: [
							{
								label: 'مقالهٔ دیگر را با یک برچسب {{' + otherTagName + '}} مشخص کنید', // localized
								checked: true,
								tooltip: 'فقط در صورتی که تنها عنوان یک مقاله وارد شده‌باشد، در دسترس است.' // localized
							}
						]
					}
				];
				if (mw.config.get('wgNamespaceNumber') === 0) {
					checkbox.subgroup.push({
						name: 'mergeReason',
						type: 'textarea',
						label: 'دلیل اصلی برای ادغام (بر روی صفحهٔ بحث' +
							(tag === 'Merge to' ? 'the other article\'s' : 'this article\'s') + ' قرار خواهد گرفت):', // localized
						tooltip: 'انتخابی، اما به‌شدت توصیه‌شده. در صورت عدم تمایل، خالی بگذارید. فقط در صورتی که تنها عنوان یک مقاله وارد شده‌باشد، در دسترس است.' // localized
					});
				}
				break;
			case 'Not English':
			case 'Rough translation':
				checkbox.subgroup = [
					{
						name: 'translationLanguage',
						type: 'input',
						label: 'زبان مقاله (اگر مشخص است): ', // localized
						tooltip: 'برای راهنمایی، مرور [[en:WP:LRC]] را در نظر داشته‌باشید. اگر مقاله را در صفحهٔ مقاله‌های نیازمند ترجمه فهرست می‌کنید، لطفاً از خالی‌گذاشتن این جعبه خودداری کنید؛ مگر آنکه کاملاً نامطمؤن باشید.' // localized
					}
				];
				if (tag === 'Not English') {
					checkbox.subgroup.push({
						name: 'translationNotify',
						type: 'checkbox',
						list: [
							{
								label: 'اطلاع‌رسانی به سازندهٔ مقاله', // localized
								checked: true,
								tooltip: "الگوی {{uw-notenglish}} را در صفحهٔ بحث سازندهٔ مقاله قرار می‌دهد." // localized
							}
						]
					});
				}
				if (mw.config.get('wgNamespaceNumber') === 0) {
					checkbox.subgroup.push({
						name: 'translationPostAtPNT',
						type: 'checkbox',
						list: [
							{
								label: 'فهرست‌کردن این مقاله در ویکی‌پدیا:صفحه‌های نیازمند ترجمه به فارسی (PNT)', // localized
								checked: true
							}
						]
					});
					checkbox.subgroup.push({
						name: 'translationComments',
						type: 'textarea',
						label: 'توضیح بیشتر برای ارسال به ویکی‌پدیا:صفحه‌های نیازمند ترجمه به فارسی', // localized
						tooltip: 'انتخابی، و متناسب تنها در صورتی که "فهرست‌کردن این مقاله..." در بالا انتخاب شده‌باشد.' // localized
					});
				}
				break;
			case 'Notability':
				checkbox.subgroup = {
					name: 'notability',
					type: 'select',
					list: [
						{ label: "{{سرشناسی}}: موضوع مقاله ممکن است رهنمود اصلی سرشناسی را احراز نکند", value: 'none' }, // localized
						{ label: '{{سرشناسی|دانشگاهیان}}: رهنمود سرشناسی دانشگاهیان', value: 'Academics' }, // localized
						{ label: '{{سرشناسی|اجرام آسمانی}}: رهنمود سرشناسی اجرام آسمانی', value: 'Astro' }, // localized
						{ label: '{{سرشناسی|افراد}}: رهنمود سرشناسی زندگی‌نامه افراد', value: 'Biographies' }, // localized
						{ label: '{{سرشناسی|کتاب‌ها}}: رهنمود سرشناسی کتاب', value: 'Books' }, // localized
						{ label: '{{سرشناسی|سازمان‌ها}}: رهنمودهای سرشناسی شرکت‌ها و سازمان‌ها', value: 'Companies' }, // localized
						{ label: '{{سرشناسی|رویدادها}}: رهنمود سرشناسی برای رویدادها', value: 'Events' }, // localized
						{ label: '{{سرشناسی|فیلم‌ها}}: رهنمود سرشناسی فیلم‌ها', value: 'Films' }, // localized
						{ label: '{{سرشناسی|مکان}}: رهنمود سرشناسی ویژگی‌های جغرافیایی', value: 'Geographic' }, // localized
						{ label: '{{سرشناسی|فهرست‌ها}}: رهنمود سرشناسی فهرست‌های مسقل', value: 'Lists' }, // localized
						{ label: '{{سرشناسی|موسیقی}}: رهنمود سرشناسی موسیقی', value: 'Music' }, // localized
						{ label: '{{سرشناسی|نوواژه‌ها}}: رهنمود سرشناسی نوواژه‌ها', value: 'Neologisms' }, // localized
						{ label: '{{سرشناسی|عددها}}: رهنمود سرشناسی عددها', value: 'Numbers' }, // localized
						{ label: '{{سرشناسی|محصولات}}: رهنمود سرشناسی محصولات و خدمات', value: 'Products' }, // localized
						{ label: '{{سرشناسی|ورزش‌ها}}: رهنمود سرشناسی ورزش‌ها', value: 'Sports' }, // localized
						{ label: '{{سرشناسی|تلویزیون}}: رهنمود سرشناسی برنامه‌های تلویزیونی', value: 'Television' }, // localized
						{ label: '{{سرشناسی|وب}}: رهنمود سرشناسی مجتوای وب', value: 'Web' } // localized
					]
				};
				break;
			default:
				break;
		}
		return checkbox;
	};

	var makeCheckboxesForAlreadyPresentTags = function() {
		container.append({ type: 'header', id: 'tagHeader0', label: 'Tags already present' });
		var subdiv = container.append({ type: 'div', id: 'tagSubdiv0' });
		var checkboxes = [];
		var unCheckedTags = e.target.form.getUnchecked('alreadyPresentArticleTags') || [];
		Twinkle.tag.alreadyPresentTags.forEach(function(tag) {
			var description = Twinkle.tag.article.tags[tag];
			var checkbox =
				{
					value: tag,
					label: '{{' + tag + '}}' + (description ? ': ' + description : ''),
					checked: unCheckedTags.indexOf(tag) === -1,
					style: 'font-style: italic'
				};

			checkboxes.push(checkbox);
		});
		subdiv.append({
			type: 'checkbox',
			name: 'alreadyPresentArticleTags',
			list: checkboxes
		});
	};

	if (sortorder === 'cat') { // categorical sort order
		// function to iterate through the tags and create a checkbox for each one
		var doCategoryCheckboxes = function(subdiv, array) {
			var checkboxes = [];
			$.each(array, function(k, tag) {
				var description = Twinkle.tag.article.tags[tag];
				if (Twinkle.tag.alreadyPresentTags.indexOf(tag) === -1) {
					checkboxes.push(makeCheckbox(tag, description));
				}
			});
			subdiv.append({
				type: 'checkbox',
				name: 'articleTags',
				list: checkboxes
			});
		};

		if (Twinkle.tag.alreadyPresentTags.length > 0) {
			makeCheckboxesForAlreadyPresentTags();
		}
		var i = 1;
		// go through each category and sub-category and append lists of checkboxes
		$.each(Twinkle.tag.article.tagCategories, function(title, content) {
			container.append({ type: 'header', id: 'tagHeader' + i, label: عنوان }); // localized
			var subdiv = container.append({ type: 'div', id: 'tagSubdiv' + i++ });
			if (Array.isArray(content)) {
				doCategoryCheckboxes(subdiv, content);
			} else {
				$.each(content, function(subtitle, subcontent) {
					subdiv.append({ type: 'div', label: [ Morebits.htmlNode('b', subtitle) ] });
					doCategoryCheckboxes(subdiv, subcontent);
				});
			}
		});
	} else { // alphabetical sort order
		if (Twinkle.tag.alreadyPresentTags.length > 0) {
			makeCheckboxesForAlreadyPresentTags();
			container.append({ type: 'header', id: 'tagHeader1', label: 'برچسب‌های قابل استفاده' }); // localized
		}
		var checkboxes = [];
		$.each(Twinkle.tag.article.tags, function(tag, description) {
			if (Twinkle.tag.alreadyPresentTags.indexOf(tag) === -1) {
				checkboxes.push(makeCheckbox(tag, description));
			}
		});
		container.append({
			type: 'checkbox',
			name: 'articleTags',
			list: checkboxes
		});
	}

	// append any custom tags
	if (Twinkle.getPref('customTagList').length) {
		container.append({ type: 'header', label: 'برچسب‌های سفارشی' }); // localized
		container.append({ type: 'checkbox', name: 'articleTags',
			list: Twinkle.getPref('customTagList').map(function(el) {
				el.checked = Twinkle.tag.checkedTags.indexOf(el.value) !== -1;
				return el;
			})
		});
	}

	var $workarea = $(form).find('#tagWorkArea');
	var rendered = container.render();
	$workarea.empty().append(rendered);

	// for quick filter:
	$allCheckboxDivs = $workarea.find('[name$=Tags]').parent();
	$allHeaders = $workarea.find('h5, .quickformDescription');
	form.quickfilter.value = ''; // clear search, because the search results are not preserved over mode change
	form.quickfilter.focus();

	// style adjustments
	$workarea.find('h5').css({ 'font-size': '110%' });
	$workarea.find('h5:not(:first-child)').css({ 'margin-top': '1em' });
	$workarea.find('div').filter(':has(span.quickformDescription)').css({ 'margin-top': '0.4em' });

	var alreadyPresentTags = Morebits.quickForm.getElements(form, 'alreadyPresentArticleTags');
	if (alreadyPresentTags) {
		alreadyPresentTags.forEach(generateLinks);
	}
	// in the unlikely case that *every* tag is already on the page
	var notPresentTags = Morebits.quickForm.getElements(form, 'articleTags');
	if (notPresentTags) {
		notPresentTags.forEach(generateLinks);
	}

	// tally tags added/removed, update statusNode text
	var statusNode = document.getElementById('tw-tag-status');
	$('[name=articleTags], [name=alreadyPresentArticleTags]').click(function() {
		if (this.name === 'articleTags') {
			Twinkle.tag.status.numAdded += this.checked ? 1 : -1;
		} else if (this.name === 'alreadyPresentArticleTags') {
			Twinkle.tag.status.numRemoved += this.checked ? -1 : 1;
		}

		var firstPart = 'Adding ' + Twinkle.tag.status.numAdded + ' tag' + (Twinkle.tag.status.numAdded > 1 ? 's' : '');
		var secondPart = 'Removing ' + Twinkle.tag.status.numRemoved + ' tag' + (Twinkle.tag.status.numRemoved > 1 ? 's' : '');
		statusNode.textContent =
			(Twinkle.tag.status.numAdded ? '  ' + firstPart : '') +
			(Twinkle.tag.status.numRemoved ? (Twinkle.tag.status.numAdded ? '; ' : '  ') + secondPart : '');
	});
};

/**
 * Adds a link to each template's description page
 * @param {Morebits.quickForm.element} checkbox  associated with the template
 */
var generateLinks = function(checkbox) {
	var link = Morebits.htmlNode('a', '>');
	link.setAttribute('class', 'tag-template-link');
	var tagname = checkbox.values;
	link.setAttribute('href', mw.util.getUrl(
		(tagname.indexOf(':') === -1 ? 'Template:' : '') +
		(tagname.indexOf('|') === -1 ? tagname : tagname.slice(0, tagname.indexOf('|')))
	));
	link.setAttribute('target', '_blank');
	$(checkbox).parent().append(['\u00A0', link]);
};


// Tags for ARTICLES start here

Twinkle.tag.article = {};

// A list of all article tags, in alphabetical order
// To ensure tags appear in the default "categorized" view, add them to the tagCategories hash below.

Twinkle.tag.article.tags = {
	'Advert': 'مشابه یک متن تبلیغاتی نوشته شده‌است', // localized
	'All plot': 'تقریباً به‌طور کامل یک خلاصهٔ طرح است', // localized
	'Autobiography': 'خودزندگی‌نامه است و احتمالاً بی‌طرفانه نوشته نشده‌است', // localized
	'BLP sources': 'زندگی‌نامه زندگان که برای تأییدپذیری نیامند منابع بیشتر است', // localized
	'BLP unsourced': 'زندگی‌نامهٔ زندگان که هیچ منبعی ندارد (برای مقاله‌های جدید، از حذف زماندار زندگی‌نامه زندگان اسفاده کنید)', // localized
	'Citation style': 'از سبک یادکرد مبهم یا متناقض برخوردار است', // localized
	'Cleanup': 'نیازمند تمیزکاری است', // localized
	'Cleanup bare URLs': 'از پیوندهای عریان برای ارجاع استفاده می‌کند، که مستعد خراب‌شدن پیوند است', // localized
	'Cleanup-PR': 'مشابه یک انتشار مطبوعاتی یا مقالهٔ خبری نوشته شده‌است', // localized
	'Cleanup reorganize': "برای سازگار شدن با رهنمودهای قالب‌بندی ویکی‌پدیا، نیازمند سازماندهی مجدد است", // localized
	'Cleanup rewrite': "برای سازگار شدن با استانداردهای کیفی ویکی‌پدیا× نیازمند بازنویسی عمده است", // localized
	'Cleanup tense': 'از رهنمودهای استفاده از زمان‌های مختلف افعال پیروی نمی‌کند.', // localized
	'Close paraphrasing': 'دربردارندهٔ بازنویسی نزدیگ از یک منبع غرآزاد دارای حق تکثیر است', // localized
	'COI': 'سازنده یا مشارکت‌کنندهٔ عمده ممکن است دارای تعارض منافع باشد', // localized
	'Condense': 'تعداد زیاد عنوان‌های بخش که محتوا را پراکنده کرده‌اند', // localized
	'Confusing': 'گیج‌کننده و مبهم', // localized
	'Context': 'زمینهٔ ناکافی برای کسانی که با موضوع آشنا نیستند', // localized
	'Copy edit': 'نیازمند ویراستاری دستور زبان، سبک، انسجام، لحن، یا آوانگاری', // localized
	'Copypaste': 'به‌نظر می‌رسد از جای دیگری کپی‌کاری شده‌است', // localized
	'Current': 'دربردارندهٔ یک رویداد روز است', // localized
	'Dead end': 'مقاله به هیچ مقالهٔ دیگری پیوند ندارد', // localized
	'Disputed': 'دقت در بیان حقایق مورد سؤال است', // localized
	'Essay-like': 'همانند یک تفکر شخصی، انشای شخصی یا مقالهٔ استدلالی نوشته شده‌است', // localized
	'Expand language': 'لازم است که با ترجمهٔ متن از یک مقاله به زبان دیگر، گسترش یابد', // localized
	'Expert needed': 'نیازمند توجه از سوی یک فرد آشنا با موضوع است', // localized
	'External links': 'پیوندهای به بیرون ممکن است از سیاست‌ها یا رهنمودهای محتوایی پیروی نکنند', // localized
	'Fanpov': "از دیدگاه یک طرفدار نوشته شده‌است", // localized
	'Fiction': 'وجه تمایز میان حقایق و حکایت‌ها مشخص نیست', // localized
	'Globalize': 'نمایانگر وجههٔ جهانی موضوع نیست', // localized
	'GOCEinuse': 'currently undergoing a major copy edit by the Guild of Copy Editors',
	'History merge': 'تاریخچهٔ یک صفحهٔ دیگر می‌تواند در تاریخچهٔ این صفحه ادغام شود', // localized
	'Hoax': 'کل یا بخشی از آن ممکن است شامل کلک‌زنی باشد', // localized
	'Improve categories': 'نیازمند رده‌های تخصصی بیشتر است', // localized
	'Incomprehensible': 'فهمیدن آن بسیار سخت یا غیرقابل درک است', // localized
	'In-universe': 'موضوع، تخیلی است و برای ارائهٔ یک دیدگاه غیرخیالی، نیازمند بازنویسی است', // localized
	'In use': 'برای مدتی کوتاه تحت ویرایش عمده است', // localized
	'Lead missing': 'فاقد بخش آغازین است', // localized
	'Lead rewrite': 'بخش آغازین برای سازگار شدن با رهنمودها، نیازمند بازنویسی است', // localized
	'Lead too long': 'بخش آغازین نسبت به طول کلی مقاله بسیار بلند است', // localized
	'Lead too short': 'بخش آغازین بسیار کوتاه است و برای بیان خلاصه‌ای از نکته‌های کلیدی، نیازمند گسترش است', // localized
	'Like resume': 'همانند یک رزومه نوشته شده‌است', // localized
	'Long plot': 'خلاصهٔ طرح بسیار بلند است یا دارای جزئیات بیش از اندازه است', // localized
	'Manual': 'همانند یک دفترچهٔ راهنما نوشته شده‌است', // localized
	'Merge': 'لازم است با یک مقالهٔ مشخص دیگر ادغام شود', // localized
	'Merge from': 'یک مقالهٔ مشخص دیگر باید در این مقاله ادغام شود', // localized
	'Merge to': 'لازم است که در یک مقالهٔ مشخص دیگر ادغام شود', // localized
	'More citations needed': 'برای تأییدپذیری، نیازمند منابع و ارجاع‌های بیشتر است', // localized
	'More footnotes': 'چند ارجاع دارد، اما یادکردهای درون‌خطی آن کافی نیستند', // localized
	'No footnotes': 'دارای ارجاع است، اما فاقد یادکرد درون‌خطی است', // localized
	'No plot': 'نیازمند خلاصهٔ طرح است', // localized
	'Non-free': 'ممکن است بیش از اندازه یا به‌طور نادرست از محتوای دارای حق تکثیر استفاده کرده‌باشد', // localized
	'Notability': 'موضوع ممکن است رهنمود اصلی سرشناسی را احراز نکند', // localized
	'Not English': 'written in a language other than English and needs translation',
	'One source': 'به‌طور گسترده یا تنها به یک منبع متکی است', // localized
	'Original research': 'شامل تحقیق دست اول است', // localized
	'Orphan': 'از هیچ مقالهٔ دیگری به آن پیوند داده نشده‌است', // localized
	'Over-coverage': 'جانبداری گسترده یا پوشش نامتناسب به‌سمت یک یا چند منطقهٔ مشخص', // localized
	'Overlinked': 'پیوندهای تکراری و/یا نامرتبط زیاد به مقاله‌های دیگر', // localized
	'Overly detailed': 'مقدار بیش از اندازه از جزئیات پیچیده', // localized
	'Over-quotation': 'گفتاوردهای خیلی زیاد یا خیلی طولانی برای یک مدخل دانشنامه‌ای', // localized
	'Peacock': 'شامل جمله‌بندی‌ است که بدون افزودن اطلاعات، موضوع را به شیوه‌ای انتزاعی تبلیغ می‌کند', // localized
	'POV': 'به دیدگاه بی‌طرف پایبند نیست', // localized
	'Primary sources': 'بیش از اندازه بر ارجاع به منابع اولیه متکی است و نیازمند ارجاع به منابع ثانویه است', // localized
	'Prose': 'در قالب یک فهرست نوشته شده‌است، اما در صورتی که به نثر درآید، بهتر خوانده می‌شود', // localized
	'Recentism': 'دارای دید یک‌طرفه به رویدادهای اخیر است', // localized
	'Rough translation': 'ترجمهٔ ضعیف از یک زبان دیگر', // localized
	'Sections': 'نیازمند تقسیم به چند بخش بر پایه موضوع است', // localized
	'Self-published': 'دارای ارجاع‌های بیش از اندازه و نامناسب به منابع خود چاپ‌کرده است', // localized
	'Sources exist': 'موضوع سرشناس، منابعی موجود هستند که می‌توانند به مقاله افزوده شوند', // localized
	'Technical': 'به‌اندازه‌ای فنی است که درک آن برای بیشتر مخاطبان سخت است', // localized
	'Third-party': 'به‌شدت به منابعی اتکا دارد که به‌طور نزدیکی با موضوع مرتبط هستند', // localized
	'Tone': 'لحن یا سبک نوشتار بازتاب‌دهندهٔ لحن دانشنامه‌ای به‌کار رفته در ویکی‌پدیا نیست', // localized
	'Too few opinions': 'ممکن است دربردارندهٔ تمامی دیدگاه‌های قابل توجه نباشد', // localized
	'Uncategorized': 'در هیچ رده‌ای قرار نگرفته‌است', // localized
	'Under construction': 'در فرایند گسترش یا بازسازی عمده است', // localized
	'Underlinked': 'نیازمند ویکی‌پیوندهای بیشتر به مقاله‌های دیگر است', // localized
	'Undue weight': 'به بعضی ایده‌ها، وقایع یا حواشی، وزن بی‌مورد داده‌است', // localized
	'Unfocused': 'فاقد تمرکز است، یا در مورد بیش از یک موضوع است', // localized
	'Unreferenced': 'به هیچ منبعی استناد نمی‌کند', // localized
	'Unreliable sources': 'بعضی منابع ممکن است قابل اعتماد نباشند', // localized
	'Undisclosed paid': 'ممکن است در برابر دستمزد فاش‌نشده ایجاد یا ویرایش شده‌باشد', // localized
	'Update': 'نیازمند افزودن اطلاعات به‌روز بیشتر است', // localized
	'Very long': 'به اندازه‌ای طولانی است که خواندن و گشتن در آن سخت است', // localized
	'Weasel': 'به‌دلیل استفاده از الفاظ طفره‌آمیز، بی‌طرفی و اثبات‌پذیری آن به‌خطر افتاده‌است' // localized
};

// A list of tags in order of category
// Tags should be in alphabetical order within the categories
// Add new categories with discretion - the list is long enough as is!

Twinkle.tag.article.tagCategories = {
	'Cleanup and maintenance tags': {
		'General cleanup': [
			'Cleanup',  // has a subgroup with text input
			'Cleanup rewrite',
			'Copy edit'  // has a subgroup with text input
		],
		'Potentially unwanted content': [
			'Close paraphrasing',
			'Copypaste',  // has a subgroup with text input
			'External links',
			'Non-free'
		],
		'Structure, formatting, and lead section': [
			'Cleanup reorganize',
			'Condense',
			'Lead missing',
			'Lead rewrite',
			'Lead too long',
			'Lead too short',
			'Sections',
			'Very long'
		],
		'Fiction-related cleanup': [
			'All plot',
			'Fiction',
			'In-universe',
			'Long plot',
			'No plot'
		]
	},
	'General content issues': {
		'Importance and notability': [
			'Notability'  // has a subgroup with subcategories
		],
		'Style of writing': [
			'Advert',
			'Cleanup tense',
			'Essay-like',
			'Fanpov',
			'Like resume',
			'Manual',
			'Cleanup-PR',
			'Over-quotation',
			'Prose',
			'Technical',
			'Tone'
		],
		'Sense (or lack thereof)': [
			'Confusing',
			'Incomprehensible',
			'Unfocused'
		],
		'Information and detail': [
			'Context',
			'Expert needed',
			'Overly detailed',
			'Undue weight'
		],
		'Timeliness': [
			'Current',
			'Update'
		],
		'Neutrality, bias, and factual accuracy': [
			'Autobiography',
			'COI',
			'Disputed',
			'Hoax',
			'Globalize',
			'Over-coverage',
			'Peacock',
			'POV',
			'Recentism',
			'Too few opinions',
			'Undisclosed paid',
			'Weasel'
		],
		'Verifiability and sources': [
			'BLP sources',
			'BLP unsourced',
			'More citations needed',
			'One source',
			'Original research',
			'Primary sources',
			'Self-published',
			'Sources exist',
			'Third-party',
			'Unreferenced',
			'Unreliable sources'
		]
	},
	'Specific content issues': {
		'Language': [
			'Not English',  // has a subgroup with several options
			'Rough translation',  // has a subgroup with several options
			'Expand language'
		],
		'Links': [
			'Dead end',
			'Orphan',
			'Overlinked',
			'Underlinked'
		],
		'Referencing technique': [
			'Citation style',
			'Cleanup bare URLs',
			'More footnotes',
			'No footnotes'
		],
		'Categories': [
			'Improve categories',
			'Uncategorized'
		]
	},
	'Merging': [
		'History merge',
		'Merge',   // these three have a subgroup with several options
		'Merge from',
		'Merge to'
	],
	'Informational': [
		'GOCEinuse',
		'In use',
		'Under construction'
	]
};

// Contains those article tags that *do not* work inside {{multiple issues}}.
Twinkle.tag.multipleIssuesExceptions = [
	'Copypaste',
	'Current', // Works but not intended for use in MI
	'Expand language',
	'GOCEinuse',
	'History merge',
	'Improve categories',
	'In use',
	'Merge',
	'Merge from',
	'Merge to',
	'Not English',
	'Rough translation',
	'Uncategorized',
	'Under construction'
];

// Tags for REDIRECTS start here

Twinkle.tag.spellingList = [
	{
		label: '{{R from acronym}}: تغییرمسیر از یک سرنام (مانند فحن) به قالب گسترش‌یافتهٔ آن', // localized
		value: 'R from acronym'
	},
	{
		label: '{{R from alternative spelling}}: تغییرمسیر از یک عنوان با تلفظ متفاوت', // localized
		value: 'R from alternative spelling'
	},
	{
		label: '{{R from initialism}}: تغییرمسیر از یک سرواژه (مانند BBC) به قالب گسترش‌یافتهٔ آن', // localized
		value: 'R from initialism'
	},
	{
		label: '{{R from ASCII-only}}: redirect from a title in only basic ASCII to the formal article title, with differences that are not diacritical marks (accents, umlauts, etc.) or ligatures', // localized
		value: 'R from ASCII-only'
	},
	{
		label: '{{R from member}}: تغییرمسیر از عضو یک گروه به عنوان مرتبط مانند خود گروه، سازمان یا تیمی که در آن عضویت دارد', // localized
		value: 'R from member'
	},
	{
		label: '{{R from misspelling}}: تغییرمسیر از یک آوانگاری اشتباه یا خطای نشانه‌گذاری', // localized
		value: 'R from misspelling'
	},
	{
		label: '{{R from modification}}: تغییرمسیر از اعمال تغییر بر عنوان هدف، مثلاً مرتب‌سازی مجدد واژگان', // localized
		value: 'R from modification'
	},
	{
		label: '{{R from other capitalisation}}: redirect from a title with another method of capitalisation',
		value: 'R from other capitalisation'
	},
	{
		label: '{{R from plural}}: تغییرمسیر از یک واژهٔ جمع بسته‌شده به معادل مفرد', // localized
		value: 'R from plural'
	},
	{
		label: '{{R from related word}}: تغییرمسیر از یک واژهٔ مرتبط', // Localized
		value: 'R from related word'
	},
	{
		label: '{{R to list entry}}: تغییرمسیر به یک مقاله از نوع «فهرستی از موجودیت‌های جزئی» که شامل توضیحات مختصری در مورد موضوعاتی است که سرشناسی کافی برای داشتن مقالهٔ مستقل را ندارند', // localized
		value: 'R to list entry'
	},
	{
		label: '{{تغییرمسیر به بخش}}: مشابه {{R to list entry}}، اما برای زمانی که فهرست بخش‌بندی شده‌است، مانند فهرستی از شخصیت‌ها در یک دنیای خیالی.', // localized
		value: 'R to section'
	},
	{
		label: '{{R with possibilities}}: تغییرمسیر از یک عنوان اختصاصی‌تر به یک مقالهٔ عمومی‌تر و با جزئیات کمتر، که می‌تواند و بایست که گسترش پیدا کند', // Localized
		value: 'R with possibilities'
	}
];

Twinkle.tag.alternativeList = [
	{
		label: '{{تغییرمسیر از زبانی دیگر}}: تغییرمسیر از یک نام فارسی به نامی به زبان دیگر، یا برعکس', // localized
		value: 'R from alternative language',
		subgroup: [
			{
				name: 'altLangFrom',
				type: 'input',
				label: 'از زبان (شناسه دوحرفی): ', // localized
				tooltip: 'شناسهٔ دوحرفی زبانی که عنوان تغییرمسیر به آن زبان نوشته شده‌است را وارد کنید؛ مانند fa برای فارسی و en برای انگلیسی' // localized
			},
			{
				name: 'altLangTo',
				type: 'input',
				label: 'به زبان (شناسه دوحرفی): ', // localized
				tooltip: 'شناسهٔ دوحرفی زبانی که عنوان هدف به آن زبان نوشته شده‌است را وارد کنید؛ مانند fa برای فارسی و en برای انگلیسی' // localized
			},
			{
				name: 'altLangInfo',
				type: 'div',
				label: $.parseHTML('<p>برای فهرستی از شناسه‌های زبان‌ها، <a href="/wiki/Wp:Template_messages/Redirect_language_codes">en:Wikipedia:Template messages/Redirect language codes</a></p> را ببینید') // localized
			}
		]
	},
	{
		label: '{{R from alternative name}}: تغییرمسیر از عنوانی که نام دیگر، نام مستعار، نام خودمانی یا نام مترادف است', // localized
		value: 'R from alternative name'
	},
	{
		label: '{{R from former name}}: تغییرمسیر از نام یا عنوان کاری سابق', // localized
		value: 'R from former name'
	},
	{
		label: '{{R from historic name}}: تغییرمسیر از نامی دیگر با پیشینهٔ تاریخی قابل توجه مانند یک منطقه، ایالت، شهر یا نظایر آن، که دیگر با آن نام یا عنوان شناخته نمی‌شود', // localized
		value: 'R from historic name'
	},
	{
		label: '{{R from incorrect name}}: تغییرمسیر از یک نام اشتباه که برای استفاده در عنوان، مناسب نیست', // localized
		value: 'R from incorrect name'
	},
	{
		label: '{{R from long name}}: تغییرمسیر از عنوانی که شامل نام کامل یا کامل‌تر است', // localized
		value: 'R from long name'
	},
	{
		label: '{{R from molecular formula}}: تغییرمسیر از یک فرمول مولکولی/شیمیایی به نام فنی یا بدیهی آن', // localized
		value: 'R from molecular formula'
	},
	{
		label: '{{R from name and country}}: تغییرمسیر از نام اختصاصی به نام مختصرتر', // localized
		value: 'R from name and country'
	},
	{
		label: '{{R from phrase}}: تغییرمسیر از یک اصطلاح به یک مقالهٔ مرتبط عمومی‌تر که موضوع را پوشش می‌دهد', // localized
		value: 'R from phrase'
	},
	{
		label: '{{R from scientific name}}: تغییرمسیر از نام علمی به نام رایج', // localized
		value: 'R from scientific name'
	},
	{
		label: '{{R from short name}}: تغییرمسیر از عنوانی که صورت کوتاه‌شدهٔ نام کامل یک شخص، یک عنوان کتاب، یا عنوان کامل‌تر دیگری است', // localized
		value: 'R from short name'
	},
	{
		label: '{{R from subtopic}}: تغییرمسیر از عنوانی که موضوعی فرعی از مقالهٔ مقصد است', // localized
		value: 'R from subtopic'
	},
	{
		label: '{{R from surname}}: تغییرمسیر از عنوانی که لقب است', // localized
		value: 'R from surname'
	},
	{
		label: '{{R to diacritic}}: تغییرمسیر به عنوان مقاله با حرکت‌گذاری (تلفظ، دونقطه، و غیره)', // localized
		value: 'R to diacritic'
	},
	{
		label: '{{R to related topic}}: تغییرمسیر به یک مقاله دربارهٔ یک موضوع مشابه', // localized
		value: 'R to related topic'
	},
	{
		label: '{{R to scientific name}}: تغییرمسیر از یک نام رایج به نام علمی', // localized
		value: 'R to scientific name'
	}
];

Twinkle.tag.administrativeList = [
	{
		label: '{{R from ambiguous term}}: تغییرمسیر از یک نام صفحهٔ مبهم به صفحه‌ای که آن را ابهام‌زدایی می‌کند. این الگو هرگز نباید در صفحه‌ای که «(ابهام‌زدایی)» را در عنوانش دارد، نمایش یابد، به‌جای آن از تغییرمسیر به صفحه ابهام‌زدایی استفاده کنید', // localized
		value: 'R from ambiguous term'
	},
	{
		label: '{{R from CamelCase}}: تغییرمسیر از یک عنوان با نگارش شتری', // localized
		value: 'R from CamelCase'
	},
	{
		label: '{{R to decade}}: تغییرمسیر از یک سال به مقالهٔ دهه', // localized
		value: 'R to decade'
	},
	{
		label: '{{R to disambiguation page}}: تغییرمسیر به یک صفحه ابهام‌زدایی', // localized
		value: 'R to disambiguation page'
	},
	{
		label: '{{R from duplicated article}}: تغییرمسیر به یک مقالهٔ مشابه جهت حفظ تاریخچهٔ ویرایش آن', // localized
		value: 'R from duplicated article'
	},
	{
		label: '{{R from file metadata link}}: تغییرمسیر یک ویکی‌پیوند ایجادشده از EXIF، XMP، یا اطلاعات دیگر (مثلاً بخش «فراداده» در بعضی از صفحه‌های توضیحات تصویر)', // localized
		value: 'R from file metadata link'
	},
	{
		label: '{{R with history}}: تغییرمسیر از یک صفحه با تاریخچهٔ قابل توجه، که جهت حفظ محتوا و انتساب‌ها نگهداری شده‌است', // localized
		value: 'R with history'
	},
	{
		label: '{{R from incomplete disambiguation}}: تغییرمسیر از نام یک صفحه که بیش از آن دارای ابهام است که بتواند عنوان یک نوشتار قرار گیرد و باید به یک صفحهٔ ابهام‌زدایی مناسب تغییرمسیر یابد.', // localized
		value: 'R from incomplete disambiguation'
	},
	{
		label: '{{تغییرمسیر حاصل از ادغام}}: تغییرمسیر از یک صفحهٔ ادغام‌شده جهت حفظ تاریخچهٔ ویرایشی آن', // localized
		value: 'R from merge'
	},
	{
		label: '{{R from other disambiguation}}: تغییرمسیر از نام یک صفحه با یک واژه ابهام‌زدایی جایگزین', // localized
		value: 'R from other disambiguation'
	},
	{
		label: '{{R printworthy}}: تغییرمسیر از عنوانی که می‌تواند در یک نسخهٔ چاپ‌شده یا نسخهٔ سی‌دی/دی‌وی‌دی ویکی‌پدیا کمک‌کننده باشد', // localized
		value: 'R printworthy'
	},
	{
		label: '{{R from school}}: تغییرمسیر از مقالهٔ یک مدرسه دارای اطلاعات کمی بوده‌است', // localized
		value: 'R from school'
	},
	{
		label: '{{R from shortcut}}: تغییرمسیر از یک میانبر ویکی‌پدیا', // localized
		value: 'R from shortcut'
	},
	{
		label: '{{R from sort name}}: تغییرمسیر از نام مرتب‌سازی هدف، مثلاً عنوانی که به‌جای نام کوچک، با نام خانوادگی شروع می‌شود', // localized
		value: 'R from sort name'
	},
	{
		label: '{{R unprintworthy}}: تغییرمسیر از عنوانی که «نمی‌تواند» در یک نسخهٔ چاپ‌شده یا نسخهٔ سی‌دی/دی‌وی‌دی ویکی‌پدیا کمک‌کننده باشد', // localized
		value: 'R unprintworthy'
	}
];

// maintenance tags for FILES start here

Twinkle.tag.file = {};

Twinkle.tag.file.licenseList = [
	{ label: '{{Bsr}}: source info consists of bare image URL/generic base URL only', value: 'Bsr' },
	{ label: '{{نیازمند نسخه کوچکتر}}: تصویر مورد استفادهٔ منصفانه با وضوح بالا (یا کلیپ صوتی بسیار بلند و غیره)', value: 'Non-free reduce' }, // localized
	{ label: '{{نسخه‌های غیر آزاد یتیم}}: رسانه‌های استفادهٔ منصفانه با اصلاحات قدیمی که نیازمند حذف هستند', value: 'subst:orfurrev' } // localized
];

Twinkle.tag.file.commonsList = [
	{ label: '{{انتقال به ویکی‌انبار}}: رسانه‌های آزاد که باید به ویکی‌انبار منتقل شوند', value: 'Copy to Commons' }, // localized
	{ label: '{{به ویکی‌انبار انتقال ندهید}} (مشکل مالکیت عمومی): پرونده در ایالات متحده در مالکیت عمومی قرار دارد، اما در کشور مبدأ خود، خیر.', value: 'Do not move to Commons' }, // localized
	{
		label: '{{به ویکی‌انبار انتقال ندهید}} (دلیل دیگر)', // localized
		value: 'Do not move to Commons_reason',
		subgroup: {
			type: 'input',
			name: 'DoNotMoveToCommons',
			label: 'دلیل: ', // localized
			tooltip: 'دلیلی ارائه دهید که چرا نباید این تصویر را به ویکی‌انبار انتقال داد (الزامی)' // localized
		}
	},
	{
		label: '{{نسخه محلی حفظ شود}}: درخواست برای نگه‌داشتن نسخهٔ محلی از یک پروندهٔ انبار', // localized
		value: 'Keep local',
		subgroup: {
			type: 'input',
			name: 'keeplocalName',
			label: 'نام تصویر در انبار در صورت تفاوت داشتن: ', // localized
			tooltip: 'نام تصویر در ویکی‌انبار (اگر با نام محلی متفاوت است)، بدون پیشوند «پرونده:»:' // localized
		}
	},
	{
		label: '{{موجود در انبار}}: پرونده به انبار کپی شده‌است', // localized
		value: 'subst:ncd',
		subgroup: {
			type: 'input',
			name: 'ncdName',
			label: 'نام تصویر در انبار در صورت تفاوت داشتن: ', // localized
			tooltip: 'نام تصویر در ویکی‌انبار (اگر با نام محلی متفاوت است), ، بدون پیشوند «پرونده:»:' // localized
		}
	}
];

Twinkle.tag.file.cleanupList = [
	{ label: '{{Artifacts}}: پروندهٔ PNG شامل مصنوعات فشرده‌سازی باقی‌مانده', value: 'Artifacts' }, // localized
	{ label: '{{Bad font}}: پروندهٔ SVG استفاده‌کننده از فونت‌هایی که در سرور بندانگشتی موجود نیستند', value: 'Bad font' }, // localized
	{ label: '{{Bad format}}: پروندهٔ PDF/DOC/... باید به یک فرمت کاربردی‌تر تبدیل شود', value: 'Bad format' }, // localized
	{ label: '{{Bad GIF}}: پروندهٔ GIF که باید در فرمت PNG، JPEG، یا SVG باشد', value: 'Bad GIF' }, // localized
	{ label: '{{Bad JPEG}}: پروندهٔ JPEG که باید در فرمت PNG یا SVG باشد', value: 'Bad JPEG' }, // localized
	{ label: '{{Bad SVG}}: پروندهٔ SVG شامل جلوه‌های شطرنجی', value: 'Bad SVG' }, // localized
	{ label: '{{Bad trace}}: پروندهٔ SVG ترسیم‌شده به‌صورت خودکار که نیازمند تمیزکاری است', value: 'Bad trace' }, // localized
	{
		label: '{{تمیزکاری تصویر}}: تمیزکاری عمومی', value: 'Cleanup image', // localized
		subgroup: {
			type: 'input',
			name: 'cleanupimageReason',
			label: 'دلیل: ', // localized
			tooltip: 'دلیل نیاز به تمیزکاری را وارد کنید (الزامی)' // localized
		}
	},
	{ label: '{{ClearType}}: تصویر (نه نماگرفت) با تصحیح فرکانس ClearType', value: 'ClearType' }, // localized
	{ label: '{{واترمارک تصویر}}: تصویر شامل واترمارک نمایان یا پنهان است', value: 'Imagewatermark' }, // localized
	{ label: '{{NoCoins}}: تصویر استفاده‌کننده از سکه برای نشان‌دادن مقیاس', value: 'NoCoins' }, // localized
	{ label: '{{Overcompressed JPEG}}: پروندهٔ JPEG با سطح بالایی از مصنوعات', value: 'Overcompressed JPEG' }, // localized
	{ label: '{{Opaque}}: پس‌زمینهٔ مات که باید شفاف باشد', value: 'Opaque' }, // localized
	{ label: '{{نیازمند حذف کادر}}: کادر نالازم، فضای سفید و غیره.', value: 'Remove border' }, // localized
	{
		label: '{{تغییرنام پرونده}}: نام پرونده با توجه به معیار درج‌شده در [[وپ:بت]] باید تغییر یابد', // localized
		value: 'Rename media',
		subgroup: [
			{
				type: 'input',
				name: 'renamemediaNewname',
				label: 'نام جدید: ', // localized
				tooltip: 'نام جدید برای تصویر را وارد کنید (اختیاری)' // localized
			},
			{
				type: 'input',
				name: 'renamemediaReason',
				label: 'دلیل: ', // localized
				tooltip: 'دلیل تغییر نام را وارد کنید (اختیاری)' // localized
			}
		]
	},
	{ label: '{{Should be PNG}}: پروندهٔ GIF یا JPEG که باید lossless باشد', value: 'Should be PNG' }, // localized
	{
		label: '{{باید اس‌وی‌جی باشد}}: پروندهٔ PNG، GIF یا JPEG که باید گرافیکی بُرداری باشد', value: 'Should be SVG', // localized
		subgroup: {
			name: 'svgCategory',
			type: 'select',
			list: [
				{ label: '{{باید اس‌وی‌جی باشد|other}}', value: 'other' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|alphabet}}: character images, font examples, etc.', value: 'alphabet' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|chemical}}: chemical diagrams, etc.', value: 'chemical' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|circuit}}: electronic circuit diagrams, etc.', value: 'circuit' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|coat of arms}}: coats of arms', value: 'coat of arms' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|diagram}}: diagrams that do not fit any other subcategory', value: 'diagram' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|emblem}}: emblems, free/libre logos, insignias, etc.', value: 'emblem' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|fair use}}: fair-use images, fair-use logos', value: 'fair use' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|flag}}: flags', value: 'flag' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|graph}}: visual plots of data', value: 'graph' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|logo}}: logos', value: 'logo' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|map}}: maps', value: 'map' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|music}}: musical scales, notes, etc.', value: 'music' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|physical}}: "realistic" images of physical objects, people, etc.', value: 'physical' }, // localized
				{ label: '{{باید اس‌وی‌جی باشد|symbol}}: miscellaneous symbols, icons, etc.', value: 'symbol' } // localized
			]
		}
	},
	{ label: '{{Should be text}}: image should be represented as text, tables, or math markup', value: 'Should be text' } // localized
];

Twinkle.tag.file.qualityList = [
	{ label: '{{Image-blownout}}', value: 'Image-blownout' },
	{ label: '{{Image-out-of-focus}}', value: 'Image-out-of-focus' },
	{
		label: '{{Image-Poor-Quality}}', value: 'Image-Poor-Quality',
		subgroup: {
			type: 'input',
			name: 'ImagePoorQualityReason',
			label: 'دلیل: ', // localized
			tooltip: 'دلیل اینکه چرا این تصویر خوب نیست (الزامی)' // localized
		}
	},
	{ label: '{{Image-underexposure}}', value: 'Image-underexposure' },
	{
		label: '{{Low quality chem}}: ساختارهای شیمیایی مورد اختلاف', value: 'Low quality chem', // localized
		subgroup: {
			type: 'input',
			name: 'lowQualityChemReason',
			label: 'دلیل: ', // localized
			tooltip: 'دلیل اینکه چرا نمودار مورد اختلاف است (الزامی)' // localized
		}
	}
];

Twinkle.tag.file.replacementList = [
	{ label: '{{Obsolete}}: نسخهٔ بهبودیافته موجود است', value: 'Obsolete' }, // localized
	{ label: '{{PNG version available}}', value: 'نسخهٔ پی‌ان‌جی موجود است' }, // localized
	{ label: '{{Vector version available}}', value: 'نسخهٔ وکتور موجود است' } // localized
];
Twinkle.tag.file.replacementList.forEach(function(el) {
	el.subgroup = {
		type: 'input',
		label: 'پروندهٔ جایگزین: ', // localized
		tooltip: 'نام پرونده‌ای که جایگزین این پرونده می‌شود را وارد کنید (الزامی)', // localized
		name: el.value.replace(/ /g, '_') + 'File'
	};
});


Twinkle.tag.callbacks = {
	article: function articleCallback(pageobj) {

		// Remove tags that become superfluous with this action
		var pageText = pageobj.getPageText().replace(/\{\{\s*([Uu]serspace draft)\s*(\|(?:\{\{[^{}]*\}\}|[^{}])*)?\}\}\s*/g, '');
		var params = pageobj.getCallbackParameters();

		/**
		 * Saves the page following the removal of tags if any. The last step.
		 * Called from removeTags()
		 */
		var postRemoval = function() {
			if (params.tagsToRemove.length) {
				// Remove empty {{multiple issues}} if found
				pageText = pageText.replace(/\{\{(multiple ?issues|article ?issues|mi)\s*\|\s*\}\}\n?/im, '');
				// Remove single-element {{multiple issues}} if found
				pageText = pageText.replace(/\{\{(?:multiple ?issues|article ?issues|mi)\s*\|\s*(\{\{[^}]+\}\})\s*\}\}/im, '$1');
			}

			// Build edit summary
			var makeSentence = function(array) {
				if (array.length < 3) {
					return array.join(' and ');
				}
				var last = array.pop();
				return array.join(', ') + ', and ' + last;
			};
			var makeTemplateLink = function(tag) {
				var text = '{{[[';
				// if it is a custom tag with a parameter
				if (tag.indexOf('|') !== -1) {
					tag = tag.slice(0, tag.indexOf('|'));
				}
				text += tag.indexOf(':') !== -1 ? tag : 'Template:' + tag + '|' + tag;
				return text + ']]}}';
			};

			var summaryText;
			var addedTags = params.tags.map(makeTemplateLink);
			var removedTags = params.tagsToRemove.map(makeTemplateLink);
			if (addedTags.length) {
				summaryText = 'Added ' + makeSentence(addedTags);
				summaryText += removedTags.length ? '; and removed ' + makeSentence(removedTags) : '';
			} else {
				summaryText = 'Removed ' + makeSentence(removedTags);
			}
			summaryText += ' tag' + (addedTags.length + removedTags.length > 1 ? 's' : '');
			if (params.reason) {
				summaryText += ': ' + params.reason;
			}

			// avoid truncated summaries
			if (summaryText.length > (499 - Twinkle.getPref('summaryAd').length)) {
				summaryText = summaryText.replace(/\[\[[^|]+\|([^\]]+)\]\]/g, '$1');
			}

			pageobj.setPageText(pageText);
			pageobj.setEditSummary(summaryText + Twinkle.getPref('summaryAd'));
			pageobj.setWatchlist(Twinkle.getPref('watchTaggedPages'));
			pageobj.setMinorEdit(Twinkle.getPref('markTaggedPagesAsMinor'));
			pageobj.setCreateOption('nocreate');
			pageobj.save(function() {
				// special functions for merge tags
				if (params.mergeReason) {
					// post the rationale on the talk page (only operates in main namespace)
					var talkpageText = '\n\n== ' + params.talkDiscussionTitleLinked + ' ==\n\n';
					talkpageText += params.mergeReason.trim() + ' ~~~~';
					var talkpage = new Morebits.wiki.page('Talk:' + params.discussArticle, 'Posting rationale on talk page');
					talkpage.setAppendText(talkpageText);
					talkpage.setEditSummary('/* ' + params.talkDiscussionTitle + ' */ new section' + Twinkle.getPref('summaryAd'));
					talkpage.setWatchlist(Twinkle.getPref('watchMergeDiscussions'));
					talkpage.setCreateOption('recreate');
					talkpage.append();
				}
				if (params.mergeTagOther) {
					// tag the target page if requested
					var otherTagName = 'Merge';
					if (params.mergeTag === 'Merge from') {
						otherTagName = 'Merge to';
					} else if (params.mergeTag === 'Merge to') {
						otherTagName = 'Merge from';
					}
					var newParams = {
						tags: [otherTagName],
						tagsToRemove: [],
						tagsToRemain: [],
						mergeTarget: Morebits.pageNameNorm,
						discussArticle: params.discussArticle,
						talkDiscussionTitle: params.talkDiscussionTitle,
						talkDiscussionTitleLinked: params.talkDiscussionTitleLinked
					};
					var otherpage = new Morebits.wiki.page(params.mergeTarget, 'Tagging other page (' +
						params.mergeTarget + ')');
					otherpage.setCallbackParameters(newParams);
					otherpage.load(Twinkle.tag.callbacks.article);
				}

				// post at WP:PNT for {{not English}} and {{rough translation}} tag
				if (params.translationPostAtPNT) {
					var pntPage = new Morebits.wiki.page('Wikipedia:Pages needing translation into English',
						'Listing article at Wikipedia:Pages needing translation into English');
					pntPage.setFollowRedirect(true);
					pntPage.load(function friendlytagCallbacksTranslationListPage(pageobj) {
						var old_text = pageobj.getPageText();

						var template = params.tags.indexOf('Rough translation') !== -1 ? 'duflu' : 'needtrans';
						var lang = params.translationLanguage;
						var reason = params.translationComments;

						var templateText = '{{subst:' + template + '|pg=' + Morebits.pageNameNorm + '|Language=' +
							(lang || 'uncertain') + '|Comments=' + reason.trim() + '}} ~~~~';

						var text, summary;
						if (template === 'duflu') {
							text = old_text + '\n\n' + templateText;
							summary = 'Translation cleanup requested on ';
						} else {
							text = old_text.replace(/\n+(==\s?Translated pages that could still use some cleanup\s?==)/,
								'\n\n' + templateText + '\n\n$1');
							summary = 'Translation' + (lang ? ' from ' + lang : '') + ' requested on ';
						}

						if (text === old_text) {
							pageobj.getStatusElement().error('failed to find target spot for the discussion');
							return;
						}
						pageobj.setPageText(text);
						pageobj.setEditSummary(summary + ' [[:' + Morebits.pageNameNorm + ']]' + Twinkle.getPref('summaryAd'));
						pageobj.setCreateOption('recreate');
						pageobj.save();
					});
				}
				if (params.translationNotify) {
					pageobj.lookupCreation(function(innerPageobj) {
						var initialContrib = innerPageobj.getCreator();

						// Disallow warning yourself
						if (initialContrib === mw.config.get('wgUserName')) {
							innerPageobj.getStatusElement().warn('You (' + initialContrib + ') created this page; skipping user notification');
							return;
						}

						var userTalkPage = new Morebits.wiki.page('User talk:' + initialContrib,
							'Notifying initial contributor (' + initialContrib + ')');
						var notifytext = '\n\n== Your article [[' + Morebits.pageNameNorm + ']]==\n' +
							'{{subst:uw-notenglish|1=' + Morebits.pageNameNorm +
							(params.translationPostAtPNT ? '' : '|nopnt=yes') + '}} ~~~~';
						userTalkPage.setAppendText(notifytext);
						userTalkPage.setEditSummary('Notice: Please use English when contributing to the English Wikipedia.' +
							Twinkle.getPref('summaryAd'));
						userTalkPage.setCreateOption('recreate');
						userTalkPage.setFollowRedirect(true);
						userTalkPage.append();
					});
				}
			});

			if (params.patrol) {
				pageobj.triage();
			}
		};

		/**
		 * Removes the existing tags that were deselected (if any)
		 * Calls postRemoval() when done
		 */
		var removeTags = function removeTags() {

			if (params.tagsToRemove.length === 0) {
				postRemoval();
				return;
			}

			Morebits.status.info('Info', 'Removing deselected tags that were already present');

			var getRedirectsFor = [];

			// Remove the tags from the page text, if found in its proper name,
			// otherwise moves it to `getRedirectsFor` array earmarking it for
			// later removal
			params.tagsToRemove.forEach(function removeTag(tag) {
				var tag_re = new RegExp('\\{\\{' + Morebits.pageNameRegex(tag) + '\\s*(\\|[^}]+)?\\}\\}\\n?');

				if (tag_re.test(pageText)) {
					pageText = pageText.replace(tag_re, '');
				} else {
					getRedirectsFor.push('Template:' + tag);
				}
			});

			if (!getRedirectsFor.length) {
				postRemoval();
				return;
			}

			// Remove tags which appear in page text as redirects
			var api = new Morebits.wiki.api('Getting template redirects', {
				'action': 'query',
				'prop': 'linkshere',
				'titles': getRedirectsFor.join('|'),
				'redirects': 1,  // follow redirect if the class name turns out to be a redirect page
				'lhnamespace': '10',  // template namespace only
				'lhshow': 'redirect',
				'lhlimit': 'max' // 500 is max for normal users, 5000 for bots and sysops
			}, function removeRedirectTag(apiobj) {

				$(apiobj.responseXML).find('page').each(function(idx, page) {
					var removed = false;
					$(page).find('lh').each(function(idx, el) {
						var tag = $(el).attr('title').slice(9);
						var tag_re = new RegExp('\\{\\{' + Morebits.pageNameRegex(tag) + '\\s*(\\|[^}]*)?\\}\\}\\n?');
						if (tag_re.test(pageText)) {
							pageText = pageText.replace(tag_re, '');
							removed = true;
							return false;   // break out of $.each
						}
					});
					if (!removed) {
						Morebits.status.warn('Info', 'Failed to find {{' +
						$(page).attr('title').slice(9) + '}} on the page... excluding');
					}

				});

				postRemoval();

			});
			api.post();

		};

		if (!params.tags.length) {
			removeTags();
			return;
		}

		var tagRe, tagText = '', tags = [], groupableTags = [], groupableExistingTags = [];
		// Executes first: addition of selected tags

		/**
		 * Updates `tagText` with the syntax of `tagName` template with its parameters
		 * @param {number} tagIndex
		 * @param {string} tagName
		 */
		var addTag = function articleAddTag(tagIndex, tagName) {
			var currentTag = '';
			if (tagName === 'Uncategorized' || tagName === 'Improve categories') {
				pageText += '\n\n{{' + tagName + '|date={{subst:CURRENTMONTHNAME}} {{subst:CURRENTYEAR}}}}';
			} else {
				currentTag += '{{' + tagName;
				// fill in other parameters, based on the tag
				switch (tagName) {
					case 'Cleanup':
						currentTag += '|reason=' + params.cleanup;
						break;
					case 'Close paraphrasing':
						currentTag += '|source=' + params.closeParaphrasing;
						break;
					case 'Copy edit':
						if (params.copyEdit) {
							currentTag += '|for=' + params.copyEdit;
						}
						break;
					case 'Copypaste':
						if (params.copypaste) {
							currentTag += '|url=' + params.copypaste;
						}
						break;
					case 'Expand language':
						currentTag += '|topic=';
						currentTag += '|langcode=' + params.expandLanguageLangCode;
						if (params.expandLanguageArticle !== null) {
							currentTag += '|otherarticle=' + params.expandLanguageArticle;
						}
						break;
					case 'Expert needed':
						if (params.expertNeeded) {
							currentTag += '|1=' + params.expertNeeded;
						}
						if (params.expertNeededTalk) {
							currentTag += '|talk=' + params.expertNeededTalk;
						}
						if (params.expertNeededReason) {
							currentTag += '|reason=' + params.expertNeededReason;
						}
						break;
					case 'Globalize':
						currentTag += '|1=article';
						if (params.globalizeRegion) {
							currentTag += '|2=' + params.globalizeRegion;
						}
						break;
					case 'News release':
						currentTag += '|1=article';
						break;
					case 'Notability':
						if (params.notability !== 'none') {
							currentTag += '|' + params.notability;
						}
						break;
					case 'Not English':
					case 'Rough translation':
						if (params.translationLanguage) {
							currentTag += '|1=' + params.translationLanguage;
						}
						if (params.translationPostAtPNT) {
							currentTag += '|listed=yes';
						}
						break;
					case 'History merge':
						currentTag += '|originalpage=' + params.histmergeOriginalPage;
						if (params.histmergeReason) {
							currentTag += '|reason=' + params.histmergeReason;
						}
						if (params.histmergeSysopDetails) {
							currentTag += '|details=' + params.histmergeSysopDetails;
						}
						break;
					case 'Merge':
					case 'Merge to':
					case 'Merge from':
						params.mergeTag = tagName;
						// normalize the merge target for now and later
						params.mergeTarget = Morebits.string.toUpperCaseFirstChar(params.mergeTarget.replace(/_/g, ' '));

						currentTag += '|' + params.mergeTarget;

						// link to the correct section on the talk page, for article space only
						if (mw.config.get('wgNamespaceNumber') === 0 && (params.mergeReason || params.discussArticle)) {
							if (!params.discussArticle) {
								// discussArticle is the article whose talk page will contain the discussion
								params.discussArticle = tagName === 'Merge to' ? params.mergeTarget : mw.config.get('wgTitle');
								// nonDiscussArticle is the article which won't have the discussion
								params.nonDiscussArticle = tagName === 'Merge to' ? mw.config.get('wgTitle') : params.mergeTarget;
								var direction = '[[' + params.nonDiscussArticle + ']]' + (params.mergeTag === 'Merge' ? ' with ' : ' into ') + '[[' + params.discussArticle + ']]';
								params.talkDiscussionTitleLinked = 'Proposed merge of ' + direction;
								params.talkDiscussionTitle = params.talkDiscussionTitleLinked.replace(/\[\[(.*?)\]\]/g, '$1');
							}
							currentTag += '|discuss=Talk:' + params.discussArticle + '#' + params.talkDiscussionTitle;
						}
						break;
					default:
						break;
				}

				currentTag += '|date={{subst:CURRENTMONTHNAME}} {{subst:CURRENTYEAR}}}}\n';
				tagText += currentTag;
			}
		};

		/**
		 * Adds the tags which go outside {{multiple issues}}, either because
		 * these tags aren't supported in {{multiple issues}} or because
		 * {{multiple issues}} is not being added to the page at all
		 */
		var addUngroupedTags = function() {
			$.each(tags, addTag);

			// Smartly insert the new tags after any hatnotes or
			// afd, csd, or prod templates or hatnotes. Regex is
			// extra complicated to allow for templates with
			// parameters and to handle whitespace properly.
			pageText = pageText.replace(
				new RegExp(
					// leading whitespace
					'^\\s*' +
					// capture template(s)
					'(?:((?:\\s*' +
					// AfD is special, as the tag includes html comments before and after the actual template
					'(?:<!--.*AfD.*\\n\\{\\{(?:Article for deletion\\/dated|AfDM).*\\}\\}\\n<!--.*(?:\\n<!--.*)?AfD.*(?:\\s*\\n))?|' + // trailing whitespace/newline needed since this subst's a newline
					// begin template format
					'\\{\\{\\s*(?:' +
					// CSD
					'db|delete|db-.*?|speedy deletion-.*?|' +
					// PROD
					'(?:proposed deletion|prod blp)\\/dated(?:\\s*\\|(?:concern|user|timestamp|help).*)+|' +
					// various hatnote templates
					'about|correct title|dablink|distinguish|for|other\\s?(?:hurricaneuses|people|persons|places|uses(?:of)?)|redirect(?:-acronym)?|see\\s?(?:also|wiktionary)|selfref|short description|the' +
					// not a hatnote, but sometimes under a CSD or AfD
					'|salt|proposed deletion endorsed' +
					// end main template name, optionally with a number (such as redirect2)
					')\\d*\\s*' +
					// template parameters
					'(\\|(?:\\{\\{[^{}]*\\}\\}|[^{}])*)?' +
					// end template format
					'\\}\\})+' +
					// end capture
					'(?:\\s*\\n)?)' +
					// trailing whitespace
					'\\s*)?',
					'i'), '$1' + tagText
			);

			removeTags();
		};

		// Separate tags into groupable ones (`groupableTags`) and non-groupable ones (`tags`)
		params.tags.forEach(function(tag) {
			tagRe = new RegExp('\\{\\{' + tag + '(\\||\\}\\})', 'im');
			// regex check for preexistence of tag can be skipped if in canRemove mode
			if (Twinkle.tag.canRemove || !tagRe.exec(pageText)) {
				// condition Twinkle.tag.article.tags[tag] to ensure that its not a custom tag
				// Custom tags are assumed non-groupable, since we don't know whether MI template supports them
				if (Twinkle.tag.article.tags[tag] && Twinkle.tag.multipleIssuesExceptions.indexOf(tag) === -1) {
					groupableTags.push(tag);
				} else {
					tags.push(tag);
				}
			} else {
				if (tag === 'Merge from' || tag === 'History merge') {
					tags.push(tag);
				} else {
					Morebits.status.warn('Info', 'Found {{' + tag +
						'}} on the article already...excluding');
					// don't do anything else with merge tags
					if (['Merge', 'Merge to'].indexOf(tag) !== -1) {
						params.mergeTarget = params.mergeReason = params.mergeTagOther = null;
					}
				}
			}
		});

		// To-be-retained existing tags that are groupable
		params.tagsToRemain.forEach(function(tag) {
			if (Twinkle.tag.multipleIssuesExceptions.indexOf(tag) === -1) {
				groupableExistingTags.push(tag);
			}
		});

		var miTest = /\{\{(multiple ?issues|article ?issues|mi)(?!\s*\|\s*section\s*=)[^}]+\{/im.exec(pageText);

		if (miTest && groupableTags.length > 0) {
			Morebits.status.info('Info', 'Adding supported tags inside existing {{multiple issues}} tag');

			tagText = '';
			$.each(groupableTags, addTag);

			var miRegex = new RegExp('(\\{\\{\\s*' + miTest[1] + '\\s*(?:\\|(?:\\{\\{[^{}]*\\}\\}|[^{}])*)?)\\}\\}\\s*', 'im');
			pageText = pageText.replace(miRegex, '$1' + tagText + '}}\n');
			tagText = '';

			addUngroupedTags();

		} else if (params.group && !miTest && (groupableExistingTags.length + groupableTags.length) >= 2) {
			Morebits.status.info('Info', 'Grouping supported tags inside {{multiple issues}}');

			tagText += '{{Multiple issues|\n';

			/**
			 * Adds newly added tags to MI
			 */
			var addNewTagsToMI = function() {
				$.each(groupableTags, addTag);
				tagText += '}}\n';

				addUngroupedTags();
			};


			var getRedirectsFor = [];

			// Reposition the tags on the page into {{multiple issues}}, if found with its
			// proper name, else moves it to `getRedirectsFor` array to be handled later
			groupableExistingTags.forEach(function repositionTagIntoMI(tag) {
				var tag_re = new RegExp('(\\{\\{' + Morebits.pageNameRegex(tag) + '\\s*(\\|[^}]+)?\\}\\}\\n?)');
				if (tag_re.test(pageText)) {
					tagText += tag_re.exec(pageText)[1];
					pageText = pageText.replace(tag_re, '');
				} else {
					getRedirectsFor.push('Template:' + tag);
				}
			});

			if (!getRedirectsFor.length) {
				addNewTagsToMI();
				return;
			}

			var api = new Morebits.wiki.api('Getting template redirects', {
				'action': 'query',
				'prop': 'linkshere',
				'titles': getRedirectsFor.join('|'),
				'redirects': 1,
				'lhnamespace': '10', // template namespace only
				'lhshow': 'redirect',
				'lhlimit': 'max' // 500 is max for normal users, 5000 for bots and sysops
			}, function replaceRedirectTag(apiobj) {
				$(apiobj.responseXML).find('page').each(function(idx, page) {
					var found = false;
					$(page).find('lh').each(function(idx, el) {
						var tag = $(el).attr('title').slice(9);
						var tag_re = new RegExp('(\\{\\{' + Morebits.pageNameRegex(tag) + '\\s*(\\|[^}]*)?\\}\\}\\n?)');
						if (tag_re.test(pageText)) {
							tagText += tag_re.exec(pageText)[1];
							pageText = pageText.replace(tag_re, '');
							found = true;
							return false;   // break out of $.each
						}
					});
					if (!found) {
						Morebits.status.warn('Info', 'Failed to find the existing {{' +
						$(page).attr('title').slice(9) + '}} on the page... skip repositioning');
					}
				});
				addNewTagsToMI();
			});
			api.post();

		} else {
			tags = tags.concat(groupableTags);
			addUngroupedTags();
		}
	},

	redirect: function redirect(pageobj) {
		var params = pageobj.getCallbackParameters(),
			pageText = pageobj.getPageText(),
			tagRe, tagText = '', summaryText = 'Added',
			tags = [], i;

		for (i = 0; i < params.tags.length; i++) {
			tagRe = new RegExp('(\\{\\{' + params.tags[i] + '(\\||\\}\\}))', 'im');
			if (!tagRe.exec(pageText)) {
				tags.push(params.tags[i]);
			} else {
				Morebits.status.warn('Info', 'Found {{' + params.tags[i] +
					'}} on the redirect already...excluding');
			}
		}

		var addTag = function redirectAddTag(tagIndex, tagName) {
			tagText += '\n{{' + tagName;
			if (tagName === 'R from alternative language') {
				if (params.altLangFrom) {
					tagText += '|from=' + params.altLangFrom;
				}
				if (params.altLangTo) {
					tagText += '|to=' + params.altLangTo;
				}
			}
			tagText += '}}';

			if (tagIndex > 0) {
				if (tagIndex === (tags.length - 1)) {
					summaryText += ' and';
				} else if (tagIndex < (tags.length - 1)) {
					summaryText += ',';
				}
			}

			summaryText += ' {{[[:' + (tagName.indexOf(':') !== -1 ? tagName : 'Template:' + tagName + '|' + tagName) + ']]}}';
		};

		tags.sort();
		$.each(tags, addTag);

		// Check for all Rcat shell redirects (from #433)
		if (pageText.match(/{{(?:redr|this is a redirect|r(?:edirect)?(?:.?cat.*)?[ _]?sh)/i)) {
			// Regex inspired by [[User:Kephir/gadgets/sagittarius.js]] ([[Special:PermaLink/831402893]])
			var oldTags = pageText.match(/(\s*{{[A-Za-z ]+\|)((?:[^|{}]*|{{[^}]*}})+)(}})\s*/i);
			pageText = pageText.replace(oldTags[0], oldTags[1] + tagText + oldTags[2] + oldTags[3]);
		} else {
			// Fold any pre-existing Rcats into taglist and under Rcatshell
			var pageTags = pageText.match(/\n{{R(?:edirect)? .*?}}/img);
			var oldPageTags = '';
			if (pageTags) {
				pageTags.forEach(function(pageTag) {
					var pageRe = new RegExp(pageTag, 'img');
					pageText = pageText.replace(pageRe, '');
					oldPageTags += pageTag;
				});
			}
			pageText += '\n{{Redirect category shell|' + tagText + oldPageTags + '\n}}';
		}

		summaryText += (tags.length > 0 ? ' tag' + (tags.length > 1 ? 's' : '') : '') + ' to redirect';

		// avoid truncated summaries
		if (summaryText.length > (499 - Twinkle.getPref('summaryAd').length)) {
			summaryText = summaryText.replace(/\[\[[^|]+\|([^\]]+)\]\]/g, '$1');
		}

		pageobj.setPageText(pageText);
		pageobj.setEditSummary(summaryText + Twinkle.getPref('summaryAd'));
		pageobj.setWatchlist(Twinkle.getPref('watchTaggedPages'));
		pageobj.setMinorEdit(Twinkle.getPref('markTaggedPagesAsMinor'));
		pageobj.setCreateOption('nocreate');
		pageobj.save();

		if (params.patrol) {
			pageobj.triage();
		}

	},

	file: function friendlytagCallbacksFile(pageobj) {
		var text = pageobj.getPageText();
		var params = pageobj.getCallbackParameters();
		var summary = 'Adding ';

		// Add maintenance tags
		if (params.tags.length) {

			var tagtext = '', currentTag;
			$.each(params.tags, function(k, tag) {
				// when other commons-related tags are placed, remove "move to Commons" tag
				if (['Keep local', 'subst:ncd', 'Do not move to Commons_reason', 'Do not move to Commons',
					'Now Commons'].indexOf(tag) !== -1) {
					text = text.replace(/\{\{(mtc|(copy |move )?to ?commons|move to wikimedia commons|copy to wikimedia commons)[^}]*\}\}/gi, '');
				}

				currentTag = '{{' + (tag === 'Do not move to Commons_reason' ? 'Do not move to Commons' : tag);

				switch (tag) {
					case 'subst:ncd':
						if (params.ncdName !== '') {
							currentTag += '|1=' + params.ncdName;
						}
						break;
					case 'Keep local':
						if (params.keeplocalName !== '') {
							currentTag += '|1=' + params.keeplocalName;
						}
						break;
					case 'Rename media':
						if (params.renamemediaNewname !== '') {
							currentTag += '|1=' + params.renamemediaNewname;
						}
						if (params.renamemediaReason !== '') {
							currentTag += '|2=' + params.renamemediaReason;
						}
						break;
					case 'Cleanup image':
						currentTag += '|1=' + params.cleanupimageReason;
						break;
					case 'Image-Poor-Quality':
						currentTag += '|1=' + params.ImagePoorQualityReason;
						break;
					case 'Low quality chem':
						currentTag += '|1=' + params.lowQualityChemReason;
						break;
					case 'Vector version available':
						text = text.replace(/\{\{((convert to |convertto|should be |shouldbe|to)?svg|badpng|vectorize)[^}]*\}\}/gi, '');
						/* falls through */
					case 'PNG version available':
						/* falls through */
					case 'Obsolete':
						currentTag += '|1=' + params[tag.replace(/ /g, '_') + 'File'];
						break;
					case 'Do not move to Commons_reason':
						currentTag += '|reason=' + params.DoNotMoveToCommons;
						break;
					case 'subst:orfurrev':
						// remove {{non-free reduce}} and redirects
						text = text.replace(/\{\{\s*(Template\s*:\s*)?(Non-free reduce|FairUseReduce|Fairusereduce|Fair Use Reduce|Fair use reduce|Reduce size|Reduce|Fair-use reduce|Image-toobig|Comic-ovrsize-img|Non-free-reduce|Nfr|Smaller image|Nonfree reduce)\s*(\|(?:\{\{[^{}]*\}\}|[^{}])*)?\}\}\s*/ig, '');
						currentTag += '|date={{subst:date}}';
						break;
					case 'Copy to Commons':
						currentTag += '|human=' + mw.config.get('wgUserName');
						break;
					case 'Should be SVG':
						currentTag += '|' + params.svgCategory;
						break;
					default:
						break;  // don't care
				}

				currentTag += '}}\n';

				tagtext += currentTag;
				summary += '{{' + tag + '}}, ';
			});

			if (!tagtext) {
				pageobj.getStatusElement().warn('User canceled operation; nothing to do');
				return;
			}

			text = tagtext + text;
		}

		pageobj.setPageText(text);
		pageobj.setEditSummary(summary.substring(0, summary.length - 2) + Twinkle.getPref('summaryAd'));
		pageobj.setWatchlist(Twinkle.getPref('watchTaggedPages'));
		pageobj.setMinorEdit(Twinkle.getPref('markTaggedPagesAsMinor'));
		pageobj.setCreateOption('nocreate');
		pageobj.save();

		if (params.patrol) {
			pageobj.triage();
		}
	}
};

Twinkle.tag.callback.evaluate = function friendlytagCallbackEvaluate(e) {
	var form = e.target;
	var params = {};
	if (form.patrolPage) {
		params.patrol = form.patrolPage.checked;
	}

	// Don't return null if there aren't any available tags
	params.tags = form.getChecked(Twinkle.tag.mode + 'Tags') || [];

	// Save values of input fields into params object. This works as quickform input
	// fields within subgroups of elements with name 'articleTags' (say) have their
	// name attribute as 'articleTags.' + name of the subgroup element

	var name_prefix = Twinkle.tag.mode + 'Tags.';
	$(form).find("[name^='" + name_prefix + "']:not(div)").each(function(idx, el) {
		// el are the HTMLInputElements, el.name gives the name attribute
		params[el.name.slice(name_prefix.length)] =
			el.type === 'checkbox' ? form[el.name].checked : form[el.name].value;
	});

	switch (Twinkle.tag.mode) {
		case 'article':
			params.tagsToRemove = form.getUnchecked('alreadyPresentArticleTags') || [];
			params.tagsToRemain = form.getChecked('alreadyPresentArticleTags') || [];
			params.reason = form.reason.value.trim();

			params.group = form.group.checked;

			// Validation
			if ((params.tags.indexOf('Merge') !== -1) || (params.tags.indexOf('Merge from') !== -1) ||
				(params.tags.indexOf('Merge to') !== -1)) {
				if (((params.tags.indexOf('Merge') !== -1) + (params.tags.indexOf('Merge from') !== -1) +
					(params.tags.indexOf('Merge to') !== -1)) > 1) {
					alert('Please select only one of {{merge}}, {{merge from}}, and {{merge to}}. If several merges are required, use {{merge}} and separate the article names with pipes (although in this case Twinkle cannot tag the other articles automatically).');
					return;
				}
				if (!params.mergeTarget) {
					alert('Please specify the title of the other article for use in the merge template.');
					return;
				}
				if ((params.mergeTagOther || params.mergeReason) && params.mergeTarget.indexOf('|') !== -1) {
					alert('Tagging multiple articles in a merge, and starting a discussion for multiple articles, is not supported at the moment. Please turn off "tag other article", and/or clear out the "reason" box, and try again.');
					return;
				}
			}
			if ((params.tags.indexOf('Not English') !== -1) && (params.tags.indexOf('Rough translation') !== -1)) {
				alert('Please select only one of {{not English}} and {{rough translation}}.');
				return;
			}
			if (params.tags.indexOf('History merge') !== -1 && params.histmergeOriginalPage.trim() === '') {
				alert('You must specify a page to be merged for the {{history merge}} tag.');
				return;
			}
			if (params.tags.indexOf('Cleanup') !== -1 && params.cleanup.trim() === '') {
				alert('You must specify a reason for the {{cleanup}} tag.');
				return;
			}
			if (params.tags.indexOf('Expand language') !== -1 && params.expandLanguageLangCode.trim() === '') {
				alert('You must specify language code for the {{expand language}} tag.');
				return;
			}
			break;

		case 'file':

			if (params.tags.indexOf('Cleanup image') !== -1 && params.cleanupimageReason === '') {
				alert('You must specify a reason for the cleanup tag.');
				return;
			}
			if (params.tags.indexOf('Image-Poor-Quality') !== -1 && params.ImagePoorQualityReason === '') {
				alert('You must specify a reason for the {{Image-Poor-Quality}} tag');
				return;
			}
			if (params.tags.indexOf('Low Quality Chem') !== -1 && params.lowQualityChemReason === '') {
				alert('You must specify a reason for the {{Low Quality Chem}} tag');
				return;
			}
			if ((params.tags.indexOf('Obsolete') !== -1 && params.ObsoleteFile === '') ||
				(params.tags.indexOf('PNG version available') !== -1 && params.PNG_version_availableFile === '') ||
				(params.tags.indexOf('Vector version available') !== -1 && params.Vector_version_availableFile === '')
			) {
				alert('You must specify the replacement file name for a tag in the Replacement tags list');
				return;
			}
			if (params.tags.indexOf('Do not move to Commons_reason') !== -1 && params.DoNotMoveToCommons === '') {
				alert('You must specify a reason for the {{Do not move to Commons}} tag');
				return;
			}
			break;

		case 'redirect':
			break;

		default:
			alert('Twinkle.tag: unknown mode ' + Twinkle.tag.mode);
			break;
	}

	// File/redirect: return if no tags selected
	// Article: return if no tag is selected and no already present tag is deselected
	if (params.tags.length === 0 && (Twinkle.tag.mode !== 'article' || params.tagsToRemove.length === 0)) {
		alert('You must select at least one tag!');
		return;
	}

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

	Morebits.wiki.actionCompleted.redirect = Morebits.pageNameNorm;
	Morebits.wiki.actionCompleted.notice = 'Tagging complete, reloading article in a few seconds';
	if (Twinkle.tag.mode === 'redirect') {
		Morebits.wiki.actionCompleted.followRedirect = false;
	}

	var wikipedia_page = new Morebits.wiki.page(Morebits.pageNameNorm, 'Tagging ' + Twinkle.tag.mode);
	wikipedia_page.setCallbackParameters(params);
	wikipedia_page.load(Twinkle.tag.callbacks[Twinkle.tag.mode]);

};

})(jQuery);
// </nowiki>