MediaWiki:Gadget-twinklespeedy.js

Văn thư lưu trữ mở Wikisource

Cache: Sau khi lưu biểu mẫu này, phải xóa bộ nhớ đệm (cache) của trình duyệt để những thay đổi hiện ra:

Firefox, Chrome, Safari, Opera — Shift­Reload / Tải lại       Internet Explorer — Ctrl­Refresh / Làm tươi       Konqueror — Reload / Tải lại

Nếu bạn viết mã JavaScript, chú ý đọc hướng dẫn để tránh mâu thuẫn với mã mặc định của mạng.

//<nowiki>


(function($){


/*
 ****************************************
 *** twinklespeedy.js: CSD module
 ****************************************
 * Mode of invocation:     Tab ("Xóa nhanh")
 * Active on:              Non-special, existing pages
 * Config directives in:   TwinkleConfig
 *
 * NOTE FOR DEVELOPERS:
 *   If adding a new criterion, add it to the appropriate places at the top of
 *   twinkleconfig.js.  Also check out the default values of the CSD preferences
 *   in twinkle.js, and add your new criterion to those if you think it would be
 *   good.
 */

Twinkle.speedy = function twinklespeedy() {
	// Disable on:
	// * special pages
	// * non-existent pages
	if (mw.config.get('wgNamespaceNumber') < 0 || !mw.config.get('wgArticleId')) {
		return;
	}

	Twinkle.addPortletLink( Twinkle.speedy.callback, "Xóa nhanh", "tw-csd", Morebits.userIsInGroup('sysop') ? "Xóa trang theo WS:XN" : "Đề nghị xóa nhanh theo WS:XN" );
};

// This function is run when the CSD tab/header link is clicked
Twinkle.speedy.callback = function twinklespeedyCallback() {
	Twinkle.speedy.initDialog(Morebits.userIsInGroup( 'sysop' ) ? Twinkle.speedy.callback.evaluateSysop : Twinkle.speedy.callback.evaluateUser, true);
};

// Used by unlink feature
Twinkle.speedy.dialog = null;

// The speedy criteria list can be in one of several modes
Twinkle.speedy.mode = {
	sysopSingleSubmit: 1,  // radio buttons, no subgroups, submit when "Submit" button is clicked
	sysopRadioClick: 2,  // radio buttons, no subgroups, submit when a radio button is clicked
	sysopMultipleSubmit: 3, // check boxes, subgroups, "Submit" button already present
	sysopMultipleRadioClick: 4, // check boxes, subgroups, need to add a "Submit" button
	userMultipleSubmit: 5,  // check boxes, subgroups, "Submit" button already pressent
	userMultipleRadioClick: 6,  // check boxes, subgroups, need to add a "Submit" button
	userSingleSubmit: 7,  // radio buttons, subgroups, submit when "Submit" button is clicked
	userSingleRadioClick: 8,  // radio buttons, subgroups, submit when a radio button is clicked

	// are we in "delete page" mode?
	// (sysops can access both "delete page" [sysop] and "tag page only" [user] modes)
	isSysop: function twinklespeedyModeIsSysop(mode) {
		return mode === Twinkle.speedy.mode.sysopSingleSubmit ||
			mode === Twinkle.speedy.mode.sysopMultipleSubmit ||
			mode === Twinkle.speedy.mode.sysopRadioClick ||
			mode === Twinkle.speedy.mode.sysopMultipleRadioClick;
	},
	// do we have a "Submit" button once the form is created?
	hasSubmitButton: function twinklespeedyModeHasSubmitButton(mode) {
		return mode === Twinkle.speedy.mode.sysopSingleSubmit ||
			mode === Twinkle.speedy.mode.sysopMultipleSubmit ||
			mode === Twinkle.speedy.mode.sysopMultipleRadioClick ||
			mode === Twinkle.speedy.mode.userMultipleSubmit ||
			mode === Twinkle.speedy.mode.userMultipleRadioClick ||
			mode === Twinkle.speedy.mode.userSingleSubmit;
	},
	// is db-multiple the outcome here?
	isMultiple: function twinklespeedyModeIsMultiple(mode) {
		return mode === Twinkle.speedy.mode.userMultipleSubmit ||
			mode === Twinkle.speedy.mode.sysopMultipleSubmit ||
			mode === Twinkle.speedy.mode.userMultipleRadioClick ||
			mode === Twinkle.speedy.mode.sysopMultipleRadioClick;
	},
};

// Prepares the speedy deletion dialog and displays it
Twinkle.speedy.initDialog = function twinklespeedyInitDialog(callbackfunc) {
	var dialog;
	Twinkle.speedy.dialog = new Morebits.simpleWindow( Twinkle.getPref('speedyWindowWidth'), Twinkle.getPref('speedyWindowHeight') );
	dialog = Twinkle.speedy.dialog;
	dialog.setTitle( "Chọn tiêu chí xóa nhanh" );
	dialog.setScriptName( "Twinkle" );
	dialog.addFooterLink( "Quy định xóa nhanh", "WS:XN" );
	dialog.addFooterLink( "Trợ giúp Twinkle", "w:en:WP:TW/DOC#speedy" );

	var form = new Morebits.quickForm( callbackfunc, (Twinkle.getPref('speedySelectionStyle') === 'radioClick' ? 'change' : null) );
	if( Morebits.userIsInGroup( 'sysop' ) ) {
		form.append( {
				type: 'checkbox',
				list: [
					{
						label: 'Chỉ đặt bản mẫu, không xóa bài',
						value: 'tag_only',
						name: 'tag_only',
						tooltip: 'Nếu bạn chỉ muốn đặt bản mẫu xóa vào bài thay vì xóa nó ngay lập tức',
						checked : Twinkle.getPref('deleteSysopDefaultToTag'),
						event: function( event ) {
							var cForm = event.target.form;
							var cChecked = event.target.checked;
							// enable/disable talk page checkbox
							if (cForm.talkpage) {
								cForm.talkpage.disabled = cChecked;
								cForm.talkpage.checked = !cChecked && Twinkle.getPref('deleteTalkPageOnDelete');
							}
							// enable/disable redirects checkbox
							cForm.redirects.disabled = cChecked;
							cForm.redirects.checked = !cChecked;
							// enable/disable delete multiple
							cForm.delmultiple.disabled = cChecked;
							cForm.delmultiple.checked = false;
							// enable/disable open talk page checkbox
							cForm.openusertalk.disabled = cChecked;
							cForm.openusertalk.checked = false;

							// enable/disable notify checkbox
							cForm.notify.disabled = !cChecked;
							cForm.notify.checked = cChecked;
							// enable/disable multiple
							cForm.multiple.disabled = !cChecked;
							cForm.multiple.checked = false;

							Twinkle.speedy.callback.modeChanged(cForm);

							event.stopPropagation();
						}
					}
				]
			} );

		var deleteOptions = form.append( {
				type: 'div',
				name: 'delete_options'
			} );
		deleteOptions.append( {
				type: 'header',
				label: 'Các lựa chọn xóa'
			} );
		if (mw.config.get('wgNamespaceNumber') % 2 === 0 && (mw.config.get('wgNamespaceNumber') !== 2 || (/\//).test(mw.config.get('wgTitle')))) {  // hide option for user pages, to avoid accidentally deleting user talk page
			deleteOptions.append( {
				type: 'checkbox',
				list: [
					{
						label: 'Xóa trang thảo luận',
						value: 'talkpage',
						name: 'talkpage',
						tooltip: "Tùy chọn này cho phép xóa cả trang thảo luận.",
						checked: Twinkle.getPref('deleteTalkPageOnDelete'),
						disabled: Twinkle.getPref('deleteSysopDefaultToTag'),
						event: function( event ) {
							event.stopPropagation();
						}
					}
				]
			} );
		}
		deleteOptions.append( {
				type: 'checkbox',
				list: [
					{
						label: 'Xóa tất cả trang đổi hướng',
						value: 'redirects',
						name: 'redirects',
						tooltip: "Tùy chọn này cho phép xóa tất cả trang đổi hướng đến đây. Tránh lựa chọn này khi thực hiện các tác vụ xóa để di chuyển/trộn trang.",
						checked: Twinkle.getPref('deleteRedirectsOnDelete'),
						disabled: Twinkle.getPref('deleteSysopDefaultToTag'),
						event: function( event ) {
							event.stopPropagation();
						}
					}
				]
			} );
		deleteOptions.append( {
			type: 'checkbox',
			list: [
				{
					label: 'Xóa vì nhiều tiêu chí',
					value: 'delmultiple',
					name: 'delmultiple',
					tooltip: "Khi được chọn, bạn có thể chọn nhiều tiêu chí để áp dụng vào trang.",
					event: function( event ) {
						Twinkle.speedy.callback.modeChanged( event.target.form );
						event.stopPropagation();
					}
				}
			]
		} );
		deleteOptions.append( {
				type: 'checkbox',
				list: [
					{
						label: 'Mở trang thảo luận thành viên khi lưu trang',
						value: 'openusertalk',
						name: 'openusertalk',
						tooltip: 'Giá trị mặc định tuân theo tùy chọn mở-trang-thảo-luận của bạn khi xóa các trang vì lý do được chọn. Nó được giữ nguyên nếu bạn xóa vì nhiều lý do.',
						checked : false
					}
				]
			} );
	}

	var tagOptions = form.append( {
			type: 'div',
			name: 'tag_options'
		} );

	if( Morebits.userIsInGroup( 'sysop' ) ) {
		tagOptions.append( {
				type: 'header',
				label: 'Tùy chọn thẻ'
			} );
	}

	tagOptions.append( {
			type: 'checkbox',
			list: [
				{
					label: 'Nhắn tin cho người tạo trang',
					value: 'notify',
					name: 'notify',
					tooltip: "Một tin nhắn sẽ được gửi đến người tạo trang, NẾU bạn có sử dụng hệ thống tin nhắn trong tùy chọn Twinkle " +
						"ứng với tiêu chí bạn chọn VÀ ô này được chọn. Người tạo trang có thể được hoan nghênh.",
					checked: !Morebits.userIsInGroup( 'sysop' ) || Twinkle.getPref('deleteSysopDefaultToTag'),
					disabled: Morebits.userIsInGroup( 'sysop' ) && !Twinkle.getPref('deleteSysopDefaultToTag'),
					event: function( event ) {
						event.stopPropagation();
					}
				}
			]
		} );
	tagOptions.append( {
			type: 'checkbox',
			list: [
				{
					label: 'Sử dụng nhiều tiêu chí',
					value: 'multiple',
					name: 'multiple',
					tooltip: "Khi được chọn, bạn có thể chọn nhiều tiêu chí để áp dụng vào trang.",
					disabled: Morebits.userIsInGroup( 'sysop' ) && !Twinkle.getPref('deleteSysopDefaultToTag'),
					event: function( event ) {
						Twinkle.speedy.callback.modeChanged( event.target.form );
						event.stopPropagation();
					}
				}
			]
		} );

	form.append( {
			type: 'div',
			name: 'work_area',
			label: 'Không khởi tạo được mô đun Xóa nhanh. Xin thử lại, hoặc báo cho lập trình viên Twinkle biết về vấn đề này.'
		} );

	if( Twinkle.getPref( 'speedySelectionStyle' ) !== 'radioClick' ) {
		form.append( { type: 'submit' } );
	}

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

	Twinkle.speedy.callback.modeChanged( result );

	// if sysop, check if CSD is already on the page and fill in custom rationale
	if (Morebits.userIsInGroup('sysop') && $("#delete-reason").length) {
		var customOption = $("input[name=csd][value=reason]")[0];

		if (Twinkle.getPref('speedySelectionStyle') !== 'radioClick') {
			// force listeners to re-init
			customOption.click();
			customOption.parentNode.appendChild(customOption.subgroup);
		}

		customOption.subgroup.querySelector('input').value = decodeURIComponent($("#delete-reason").text()).replace(/\+/g, ' ');
	}
};

Twinkle.speedy.callback.getMode = function twinklespeedyCallbackGetMode(form) {
	var mode = Twinkle.speedy.mode.userSingleSubmit;
	if (form.tag_only && !form.tag_only.checked) {
		if (form.delmultiple.checked) {
			mode = Twinkle.speedy.mode.sysopMultipleSubmit;
		} else {
			mode = Twinkle.speedy.mode.sysopSingleSubmit;
		}
	} else {
		if (form.multiple.checked) {
			mode = Twinkle.speedy.mode.userMultipleSubmit;
		} else {
			mode = Twinkle.speedy.mode.userSingleSubmit;
		}
	}
	if (Twinkle.getPref('speedySelectionStyle') === 'radioClick') {
		mode++;
	}

	return mode;
};

Twinkle.speedy.callback.modeChanged = function twinklespeedyCallbackModeChanged(form) {
	var namespace = mw.config.get('wgNamespaceNumber');

	// first figure out what mode we're in
	var mode = Twinkle.speedy.callback.getMode(form);

	if (Twinkle.speedy.mode.isSysop(mode)) {
		$("[name=delete_options]").show();
		$("[name=tag_options]").hide();
	} else {
		$("[name=delete_options]").hide();
		$("[name=tag_options]").show();
	}

	var work_area = new Morebits.quickForm.element( {
			type: 'div',
			name: 'work_area'
		} );

	if (mode === Twinkle.speedy.mode.userMultipleRadioClick || mode === Twinkle.speedy.mode.sysopMultipleRadioClick) {
		var evaluateType = Twinkle.speedy.mode.isSysop(mode) ? 'evaluateSysop' : 'evaluateUser';

		work_area.append( {
				type: 'div',
				label: 'Khi đã chọn xong tiêu chí, nhấn:'
			} );
		work_area.append( {
				type: 'button',
				name: 'submit-multiple',
				label: 'Gửi yêu cầu',
				event: function( event ) {
					Twinkle.speedy.callback[evaluateType]( event );
					event.stopPropagation();
				}
			} );
	}

	var radioOrCheckbox = (Twinkle.speedy.mode.isMultiple(mode) ? 'checkbox' : 'radio');

	if (Twinkle.speedy.mode.isSysop(mode) && !Twinkle.speedy.mode.isMultiple(mode)) {
		work_area.append( { type: 'header', label: 'Lý do khác' } );
		work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.customRationale, mode) } );
	}

	if (namespace % 2 === 1 && namespace !== 3) {
		// show db-talk on talk pages, but not user talk pages
		work_area.append( { type: 'header', label: 'Trang thảo luận' } );
		work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.talkList, mode) } );
	}

	if (!mw.config.get('wgIsRedirect')) {
		switch (namespace) {
			case 0:  // article
			case 1:  // talk
				work_area.append( { type: 'header', label: 'Bài viết' } );
				work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.articleList, mode) } );
				break;

			// case 2:  // user
			// case 3:  // user talk
				// work_area.append( { type: 'header', label: 'Trang cá nhân' } );
				// work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.userAllList.concat(Twinkle.speedy.userNonRedirectList), mode) } );
				// break;

			case 6:  // file
			case 7:  // file talk
				work_area.append( { type: 'header', label: 'Tập tin' } );
				work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.fileList, mode) } );
				if (!Twinkle.speedy.mode.isSysop(mode)) {
					work_area.append( { type: 'div', label: 'Các trường hợp XN TT4 (thiếu thông tin bản quyền), TT5 (không tự do không được sử dụng), và TT6 (thiếu sửa dụng hợp lý) nằm ở thẻ “DI” của Twinkle.' } );
				}
				break;

			// case 10:  // template
			// case 11:  // template talk
				// work_area.append( { type: 'header', label: 'Bản mẫu' } );
				// work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.templateList, mode) } );
				// break;

			case 14:  // category
			case 15:  // category talk
				work_area.append( { type: 'header', label: 'Thể loại' } );
				work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.categoryList, mode) } );
				break;

			// case 100:  // portal
			// case 101:  // portal talk
				// work_area.append( { type: 'header', label: 'Chủ đề' } );
				// work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.portalList, mode) } );
				// break;

			default:
				break;
		}
	} else if (namespace == 2 || namespace == 3) {
		work_area.append( { type: 'header', label: 'Trang thành viên' } );
		work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.userAllList, mode) } );
	}

	// custom rationale lives under general criteria when tagging
	var generalCriteria = Twinkle.speedy.generalList;
	if(!Twinkle.speedy.mode.isSysop(mode)) {
		generalCriteria = Twinkle.speedy.customRationale.concat(generalCriteria);
	}
	work_area.append( { type: 'header', label: 'Tiêu chí chung' } );
	work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(generalCriteria, mode) });

	if(mw.config.get('wgIsRedirect')) {
		work_area.append( { type: 'header', label: 'Trang đổi hướng' } );
		work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.redirectList, mode) } );
	}

	var old_area = Morebits.quickForm.getElements(form, "work_area")[0];
	form.replaceChild(work_area.render(), old_area);
};

Twinkle.speedy.generateCsdList = function twinklespeedyGenerateCsdList(list, mode) {
	// mode switches
	var isSysop = Twinkle.speedy.mode.isSysop(mode);
	var multiple = Twinkle.speedy.mode.isMultiple(mode);
	var hasSubmitButton = Twinkle.speedy.mode.hasSubmitButton(mode);

	var openSubgroupHandler = function(e) {
		$(e.target.form).find('input').prop('disabled', true);
		$(e.target.form).children().css('color', 'gray');
		$(e.target).parent().css('color', 'black').find('input').prop('disabled', false);
		$(e.target).parent().find('input:text')[0].focus();
		e.stopPropagation();
	};
	var submitSubgroupHandler = function(e) {
		var evaluateType = Twinkle.speedy.mode.isSysop(mode) ? 'evaluateSysop' : 'evaluateUser';
		Twinkle.speedy.callback[evaluateType](e);
		e.stopPropagation();
	};

	return $.map(list, function(critElement) {
		var criterion = $.extend({}, critElement);

		if (multiple) {
			if (criterion.hideWhenMultiple) {
				return null;
			}
			if (criterion.hideSubgroupWhenMultiple) {
				criterion.subgroup = null;
			}
		} else {
			if (criterion.hideWhenSingle) {
				return null;
			}
			if (criterion.hideSubgroupWhenSingle) {
				criterion.subgroup = null;
			}
		}

		if (isSysop) {
			if (criterion.hideWhenSysop) {
				return null;
			}
			if (criterion.hideSubgroupWhenSysop) {
				criterion.subgroup = null;
			}
		} else {
			if (criterion.hideWhenUser) {
				return null;
			}
			if (criterion.hideSubgroupWhenUser) {
				criterion.subgroup = null;
			}
		}

		if (mw.config.get('wgIsRedirect') && criterion.hideWhenRedirect) {
			return null;
		}

		if (criterion.subgroup && !hasSubmitButton) {
			if ($.isArray(criterion.subgroup)) {
				criterion.subgroup.push({
					type: 'button',
					name: 'submit',
					label: 'Gửi yêu cầu',
					event: submitSubgroupHandler
				});
			} else {
				criterion.subgroup = [
					criterion.subgroup,
					{
						type: 'button',
						name: 'submit',  // ends up being called "csd.submit" so this is OK
						label: 'Gửi yêu cầu',
						event: submitSubgroupHandler
					}
				];
			}
			// FIXME: does this do anything?
			criterion.event = openSubgroupHandler;
		}

		if ( isSysop ) {
			var originalEvent = criterion.event;
			criterion.event = function(e) {
				if (multiple) return originalEvent(e);

				var normalizedCriterion = Twinkle.speedy.normalizeHash[e.target.value];
				$('[name=openusertalk]').prop('checked',
						Twinkle.getPref('openUserTalkPageOnSpeedyDelete').indexOf(normalizedCriterion) !== -1
					);
				if ( originalEvent ) {
					return originalEvent(e);
				}
			};
		}

		return criterion;
	});
};

Twinkle.speedy.customRationale = [
	{
		label: 'Lý do tùy chỉnh' + (Morebits.userIsInGroup('sysop') ? ' (lý do xóa tùy chỉnh)' : ' dùng bản mẫu {{cx}}'),
		value: 'lydo',
		tooltip: '{{cx}} là viết tắt của "chờ xóa". Ít nhất phải có một tiêu chí xóa nhanh phù hợp với trang, và bạn phải nhắc tới nó trong lý do của mình. Đây không phải là một dạng "phủ đầu" khi bạn không tìm được lý do thích hợp.',
		subgroup: {
			name: 'reason_1',
			type: 'input',
			label: 'Lý do: ',
			size: 60
		},
		hideWhenMultiple: true
	}
];

Twinkle.speedy.talkList = [
	{
		label: 'K4: Trang mồ côi',
		value: 'thaoluan',
		tooltip: 'Một trang thảo luận của nội dung đã bị xóa hoặc không tồn tại, trừ khi nó hữu ích cho Wikisource.'
	}
];

Twinkle.speedy.fileList = [
	// {
		// label: 'F1: Redundant file',
		// value: 'redundantimage',
		// tooltip: 'Any file that is a redundant copy, in the same file format and same or lower resolution, of something else on Wikipedia. Likewise, other media that is a redundant copy, in the same format and of the same or lower quality. This does not apply to files duplicated on Wikimedia Commons, because of licence issues; these should be tagged with {{subst:ncd|Image:newname.ext}} or {{subst:ncd}} instead',
		// subgroup: {
			// name: 'redundantimage_filename',
			// type: 'input',
			// label: 'File this is redundant to: ',
			// tooltip: 'The "File:" prefix can be left off.'
		// }
	// },
	// {
		// label: 'F2: Corrupt or blank file',
		// value: 'noimage',
		// tooltip: 'Before deleting this type of file, verify that the MediaWiki engine cannot read it by previewing a resized thumbnail of it. This also includes empty (i.e., no content) file description pages for Commons files'
	// },
	// {
		// label: 'F2: Unneeded file description page for a file on Commons',
		// value: 'fpcfail',
		// tooltip: 'An image, hosted on Commons, but with tags or information on its English Wikipedia description page that are no longer needed. (For example, a failed featured picture candidate.)',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'F3: Improper license',
		// value: 'noncom',
		// tooltip: 'Files licensed as "for non-commercial use only", "non-derivative use" or "used with permission" that were uploaded on or after 2005-05-19, except where they have been shown to comply with the limited standards for the use of non-free content. This includes files licensed under a "Non-commercial Creative Commons License". Such files uploaded before 2005-05-19 may also be speedily deleted if they are not used in any articles'
	// },
	// {
		// label: 'F4: Lack of licensing information',
		// value: 'unksource',
		// tooltip: 'Files in category "Files with unknown source", "Files with unknown copyright status", or "Files with no copyright tag" that have been tagged with a template that places them in the category for more than seven days, regardless of when uploaded. Note, users sometimes specify their source in the upload summary, so be sure to check the circumstances of the file.',
		// hideWhenUser: true
	// },
	// {
		// label: 'F5: Unused unfree copyrighted file',
		// value: 'unfree',
		// tooltip: 'Files that are not under a free license or in the public domain that are not used in any article and that have been tagged with a template that places them in a dated subcategory of Category:Orphaned fairuse files for more than seven days. Reasonable exceptions may be made for file uploaded for an upcoming article. Use the "Orphaned fair use" option in Twinkle\'s DI module to tag files for forthcoming deletion.',
		// hideWhenUser: true
	// },
	// {
		// label: 'F6: Missing fair-use rationale',
		// value: 'norat',
		// tooltip: 'Any file without a fair use rationale may be deleted seven days after it is uploaded.  Boilerplate fair use templates do not constitute a fair use rationale.  Files uploaded before 2006-05-04 should not be deleted immediately; instead, the uploader should be notified that a fair-use rationale is needed.  Files uploaded after 2006-05-04 can be tagged using the "No fair use rationale" option in Twinkle\'s DI module. Such files can be found in the dated subcategories of Category:Files with no fair use rationale.',
		// hideWhenUser: true
	// },
	// {
		// label: 'F7: Clearly invalid fair-use tag',
		// value: 'badfairuse',  // same as below
		// tooltip: 'This is only for files with a clearly invalid fair-use tag, such as a {{Non-free logo}} tag on a photograph of a mascot. For cases that require a waiting period (replaceable images or otherwise disputed rationales), use the options on Twinkle\'s DI tab.',
		// subgroup: {
			// name: 'badfairuse_reason',
			// type: 'input',
			// label: 'Optional explanation: ',
			// size: 60
		// }
	// },
	// {
		// label: 'F7: Fair-use media from a commercial image agency which is not the subject of sourced commentary',
		// value: 'badfairuse',  // same as above
		// tooltip: 'Non-free images or media from a commercial source (e.g., Associated Press, Getty), where the file itself is not the subject of sourced commentary, are considered an invalid claim of fair use and fail the strict requirements of WP:NFCC.',
		// subgroup: {
			// name: 'badfairuse_reason',
			// type: 'input',
			// label: 'Optional explanation: ',
			// size: 60
		// },
		// hideWhenMultiple: true
	// },
	// {
		// label: 'F8: File available as an identical or higher-resolution copy on Wikimedia Commons',
		// value: 'nowcommons',
		// tooltip: 'Provided the following conditions are met: 1: The file format of both images is the same. 2: The file\'s license and source status is beyond reasonable doubt, and the license is undoubtedly accepted at Commons. 3: All information on the file description page is present on the Commons file description page. That includes the complete upload history with links to the uploader\'s local user pages. 4: The file is not protected, and the file description page does not contain a request not to move it to Commons. 5: If the file is available on Commons under a different name than locally, all local references to the file must be updated to point to the title used at Commons. 6: For {{c-uploaded}} files: They may be speedily deleted as soon as they are off the Main Page',
		// subgroup: {
			// name: 'nowcommons_filename',
			// type: 'input',
			// label: 'Filename on Commons: ',
			// value: Morebits.pageNameNorm,
			// tooltip: 'This can be left blank if the file has the same name on Commons as here. The "File:" prefix is optional.'
		// },
		// hideWhenMultiple: true
	// },
	// {
		// label: 'F9: Unambiguous copyright infringement',
		// value: 'imgcopyvio',
		// tooltip: 'The file was copied from a website or other source that does not have a license compatible with Wikipedia, and the uploader neither claims fair use nor makes a credible assertion of permission of free use. Sources that do not have a license compatible with Wikipedia include stock photo libraries such as Getty Images or Corbis. Non-blatant copyright infringements should be discussed at Wikipedia:Files for deletion',
		// subgroup: {
			// name: 'imgcopyvio_url',
			// type: 'input',
			// label: 'URL of the copyvio, including the "http://".  If you cannot provide a URL, please do not use CSD F9.  (Exception: for copyvios of non-Internet sources, leave the box blank.) ',
			// size: 60
		// }
	// },
	// {
		// label: 'TT10: Tập tin vô ích không phải phương tiện',
		// value: 'badfiletype',
		// tooltip: 'Các tập tin gồm hoặc là hình ảnh, âm thanh hoặc các tạp tin không phải video (như .doc, .pdf, hay .xls) không được sử dụng trong bất kỳ bài viết nào và được cho là không thể sử dụng mang tính bách khoa'
	// },
	// {
		// label: 'TT11: Không có bằng chứng về sự cấp phép',
		// value: 'nopermission',
		// tooltip: 'Nếu người tải lên đưa ra giấy phép và có tên bên thứ 3 như người giữa bản quyền/nguồn mà không đưa ra được bằng chứng về sự đồng ý cấp phép của bên thứ 3 thì tập tin đó sẽ bị xóa sau 7 ngày kể từ ngày thông báo cho người tải lên',
		// hideWhenUser: true
	// },
	{
		label: 'K4: Trang mô tả tập tin không có tập tin',
		value: 'tranghinh',
		tooltip: 'Trang tập tin không chứa tập tin.'
	}
];

Twinkle.speedy.articleList = [
	{
		label: 'B1: Bài viết đã được chuyển sang dự án wiki khác',
		value: 'chuyenwiki',
		tooltip: 'Những bài không phù hợp với Wikisource và nội dung của nó đã được chuyển sang đó rồi',
		subgroup: {
			name: 'foreign_source',
			type: 'input',
			label: 'Liên kết liên wiki đến bài viết đã được chuyển tại ngôn ngữ hoặc dự án: ',
			tooltip: 'Ví dụ, w:Phạm Công Cúc Hoa'
		}
	},
       // {
		// label: 'BV1: Không ngữ cảnh hoặc thiếu ngữ cảnh cần thiết để người khác xác định đúng chủ thể được nói đến.',
		// value: 'nocontext',
		// tooltip: 'Ví dụ: "Ông ấy là một người vui tính, có một chiếc xe hơi màu xanh lá cây. Ông chuyên gia làm người khác cười." This applies only to very short articles. Context is different from content, treated in A3, below.'
	// },
	
	// {
		// label: 'BV3: Không có nội dung thực',
		// value: 'nocontent',
		// tooltip: 'Ví dụ, bài viết chỉ gồm các liên kết, thể loại, phần "Xem thêm" và một câu lặp lại tiêu đề. Không áp dụng cho các trang định hướng'
	// },
	//{
	//	label: 'A5: Transwikied articles',
	//	value: 'transwiki',
	//	tooltip: 'Any article that has been discussed at Articles for Deletion (et al), where the outcome was to transwiki, and where the transwikification has been properly performed and the author information recorded. Alternately, any article that consists of only a dictionary definition, where the transwikification has been properly performed and the author information recorded'
	//},
	{
		label: 'B2: Nội dung không nổi bật',
		value: 'khongnoibat',
		tooltip: 'Văn kiện không được thẩm định chéo kỹ hoặc chưa từng đăng dưới một ấn bản hoặc diễn đàn nổi tiếng nào',
		hideWhenSingle: true
	},
	// {
		// label: 'BV4: Cá nhân không nổi bật',
		// value: 'person',
		// tooltip: 'Bài viết về người thật mà rõ ràng chưa đáp ứng tiêu chí độ nổi bật. Nếu có tranh cãi, hoặc trước đó đã có biểu quyết xóa và bài được giữ lại, hãy đưa ra Biểu quyết xóa bài',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'BV4: Nhóm nhạc không nổi bật',
		// value: 'band',
		// tooltip: 'Bài viết về nhóm nhạc, ca sĩ, nhạc sĩ hoặc nhạc công mà rõ ràng chưa đáp ứng tiêu chí độ nổi bật',
		// hideWhenMultiple: true
	// },
	//{
	//	label: 'A7: Unremarkable club',
	//	value: 'club',
	//	tooltip: 'Article about a club that does not assert the importance or significance of the subject',
	//	hideWhenMultiple: true
	//},
	// {
		// label: 'BV4: Tổ chức không nổi bật',
		// value: 'inc',
		// tooltip: 'Bài viết về công ty hay tổ chức mà rõ ràng chưa đáp ứng tiêu chí độ nổi bật',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'BV4: Trang mạng hoặc nội dung mạng không nổi bật',
		// value: 'web',
		// tooltip: 'Bài viết về trang mạng, blog cá nhân, diễn đàn hoặc nội dung mạng tương tự mà rõ ràng chưa đáp ứng tiêu chí độ nổi bật',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'BV4: Vật nuôi cá nhân không nổi bật',
		// value: 'animal',
		// tooltip: 'Bài viết về vật nuôi cá nhân mà rõ ràng chưa đáp ứng tiêu chí độ nổi bật',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'A7: Unremarkable organized event',
		// value: 'event',
		// tooltip: 'Article about an organized event (tour, function, meeting, party, etc.) that does not assert the importance or significance of its subject',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'A9: Unremarkable musical recording where artist\'s article doesn\'t exist',
		// value: 'a9',
		// tooltip: 'An article about a musical recording which does not indicate why its subject is important or significant, and where the artist\'s article has never existed or has been deleted'
	// },
	// {
		// label: 'A10: Recently created article that duplicates an existing topic',
		// value: 'a10',
		// tooltip: 'A recently created article with no relevant page history that does not aim to expand upon, detail or improve information within any existing article(s) on the subject, and where the title is not a plausible redirect. This does not include content forks, split pages or any article that aims at expanding or detailing an existing one.',
		// subgroup: {
			// name: 'a10_article',
			// type: 'input',
			// label: 'Article that is duplicated: '
		// }
	// },
	{
		label: 'B3: Tác phẩm không có thông tin tác giả',
		value: 'khongtacgia',
		tooltip: 'Tuy đã có nhiều cố gắng để tìm thông tin này và liên hệ với người đưa văn kiện vào. Chú ý là nó không áp dụng cho văn kiện mà tác giả là vô danh'
	}
];

Twinkle.speedy.categoryList = [
	// {
		// label: 'C1: Empty categories',
		// value: 'catempty',
		// tooltip: 'Categories that have been unpopulated for at least seven days. This does not apply to categories being discussed at WP:CFD, disambiguation categories, and certain other exceptions. If the category isn\'t relatively new, it possibly contained articles earlier, and deeper investigation is needed'
	// },
	{
		label: 'K4: Thể loại chỉ bao gồm bản mẫu bị xóa hoặc đổi hướng',
		value: 'theloaibanmau',
		tooltip: 'Đây là tình huống một thể loại coi như là trống, vì các bản mẫu từng nằm trong thể loại giờ đã bị xóa. Không tính các thể loại vẫn còn giá trị sử dụng'
	}
];

Twinkle.speedy.userAllList = [
	{
		label: 'C7: Thành viên yêu cầu xóa',
		value: 'tvyeucau',
		tooltip: 'Yêu cầu xóa các trang trong không gian tên thành viên. Trong một số ít trường hợp, BQV cần cân nhắc giữ lại trang cho mục đích tham khảo.',
		subgroup: ((mw.config.get('wgNamespaceNumber') === 3 && mw.config.get('wgTitle').indexOf('/') === -1) ? {
			name: 'userreq_rationale',
			type: 'input',
			label: 'Lời giải thích bắt buộc để giải thích tại sao trang thảo luận thành viên này cần bị xóa: ',
			tooltip: 'Trang thảo luận thành viên chỉ bị xóa trong các trường hợp cực kỳ đặc biệt',
			size: 60
		} : null),
		hideSubgroupWhenMultiple: true
	}
];

Twinkle.speedy.userNonRedirectList = [
	{
		label: 'TV2: Tên thành viên không tồn tại',
		value: 'nouser',
		tooltip: 'Trang thành viên của người dùng không có thực (kiểm tra Đặc biệt:Danh sách thành viên)'
	},
	{
		label: 'TV3: Trang hình không tự do',
		value: 'gallery',
		tooltip: 'Trang chứa hình trong không gian tên mà chỉ chứa chủ yếu các hình "sử dụng hợp lý" hoặc hình không tự do. Cho dù thành viên là người tải hình lên, việc chứa các hình như vậy trong không gian nào khác, ngoài không gian bài viết liên quan, là không được phép'
	},
	{
		label: 'U5: Blatant WP:NOTWEBHOST violations',
		value: 'notwebhost',
		tooltip: 'Pages in userspace consisting of writings, information, discussions, and/or activities not closely related to Wikipedia\'s goals, where the owner has made few or no edits outside of userspace, with the exception of plausible drafts, pages adhering to WP:UPYES, and résumé-style pages.'
	},
	{
		label: 'G6: Bản nháp trống',
		value: 'blankdraft',
		tooltip: 'Userspace drafts containing only the default Article Wizard text, where the author of the page has been inactive for at least one year.',
		hideWhenMultiple: true
	},
	{
		label: 'G11: Promotional user page under a promotional user name',
		value: 'spamuser',
		tooltip: 'A promotional user page, with a username that promotes or implies affiliation with the thing being promoted. Note that simply having a page on a company or product in one\'s userspace does not qualify it for deletion. If a user page is spammy but the username is not, then consider tagging with regular G11 instead.',
		hideWhenMultiple: true
	}
];

Twinkle.speedy.templateList = [
	{
		label: 'T2: Templates that are blatant misrepresentations of established policy',
		value: 'policy',
		tooltip: 'This includes "speedy deletion" templates for issues that are not speedy deletion criteria and disclaimer templates intended to be used in articles'
	},
	{
		label: 'T3: Duplicate templates or hardcoded instances',
		value: 'duplicatetemplate',
		tooltip: 'Templates that are either substantial duplications of another template or hardcoded instances of another template where the same functionality could be provided by that other template',
		subgroup: {
			name: 'duplicatetemplate_2',
			type: 'input',
			label: 'Template this is redundant to: ',
			tooltip: 'The "Template:" prefix is not needed.'
		},
		hideWhenMultiple: true
	}
];

Twinkle.speedy.portalList = [
	{
		label: 'P1: Portal that would be subject to speedy deletion if it were an article',
		value: 'p1',
		tooltip: 'You must specify the article criterion that applies in this case (A1, A3, A7, or A10).',
		subgroup: {
			name: 'p1_1',
			type: 'input',
			label: 'Article criterion that would apply: '
		},
		hideWhenMultiple: true
	},
	{
		label: 'P2: Underpopulated portal',
		value: 'emptyportal',
		tooltip: 'Any Portal based on a topic for which there is not a non-stub header article, and at least three non-stub articles detailing subject matter that would be appropriate to discuss under the title of that Portal'
	}
];

Twinkle.speedy.generalList = [
	{
		label: 'C1: Nội dung hoặc lịch sử vô nghĩa.',
		value: 'vonghia',
		tooltip: 'Bao gồm các sửa đổi thử nghiệm (như, "asdf" hoặc "Tôi có thể tạo trang ở đây thiệt hả?"), rõ ràng là vớ vẩn, hoặc phá hoại đơn thuần.'
	},
       {
		label: 'C2: Đăng lại nội dung',
		value: 'danglai',
		tooltip: 'Nội dung đã từng bị xóa trước đây theo quy định xóa, trừ khi nó được viết lại đáng kể đến mức lý do xóa trước đây không còn phù hợp',
		subgroup: {
			name: 'repost_1',
			type: 'input',
			label: 'Trang nơi có thảo luận xóa: ',
			tooltip: 'Phải bắt đầu bằng "Wikisource:"',
			size: 60
		},
		hideSubgroupWhenMultiple: true
	},
       {
		label: 'C3: Thành viên bị cấm',
		value: 'cam',
		tooltip: 'Nội dung do một thành viên bị cấm tạo ra hoặc sửa đổi sau khi họ bị cấm, rất có thể với ý đồ xấu. Những đóng góp của thành viên bị cấm nên được chấp thuận, nhưng nếu cảm thấy có vấn đề, cứ cho đó là ý đồ xấu',
		subgroup: {
			name: 'banned_1',
			type: 'input',
			label: 'ên thành viên bị cấm (nếu có): ',
			tooltip: 'Không cần ghi "Thành viên:"'
		},
		hideSubgroupWhenMultiple: true
	},
       {
		label: 'C4: Trùng lắp',
		value: 'trunglap',
		tooltip: 'Hai phiên bản văn kiện y hệt tại các trang khác nhau, không có khác biệt đáng kể',
		subgroup: {
			name: 'copypaste_1',
			type: 'input',
			label: 'Trang trùng lắp với trang sắp xóa: '
		},
		hideWhenMultiple: true
	},
       {
		label: 'C5: Rõ ràng không thuộc Wikisource hoặc các dự án khác',
		value: 'khongws',
		tooltip: 'Nội dung rõ ràng không nằm trong phạm vi bao phủ của Wikisource (như quảng cáo hoặc miêu tả sách mà không có nội dung). Nó không áp dụng cho các tác phẩm thuộc về các dự án Wikimedia khác (xem C1)'
	},
       {
		label: 'C6: Rõ ràng vi phạm bản quyền',
		value: 'vpbq',
		tooltip: 'Nội dung rõ ràng và được chứng minh là vi phạm bản quyền, hoặc nội dung đã từng bị xóa trước đây vì vi phạm bản quyền, hoặc trang tác giả có các tác phẩm đều có bản quyền',
		subgroup: [
			{
				name: 'copyvio_url',
				type: 'input',
				label: 'URL (nếu có): ',
				tooltip: 'Nếu văn kiện được chép từ nguồn trực tuyến, ghi URL ở đây, gồm cả giao thức "http://" hoặc "https://". Nếu URL nằm trong danh sách spam, bạn có thể bỏ qua phần giao thức.',
				size: 60
			},
			{
				name: 'copyvio_url2',
				type: 'input',
				label: 'URL khác: ',
				tooltip: 'Tùy chọn.',
				size: 60
			},
			{
				name: 'copyvio_url3',
				type: 'input',
				label: 'URL khác: ',
				tooltip: 'Tùy chọn.',
				size: 60
			}
		]
	},
       {
		label: 'C7: Tác giả yêu cầu xóa hoặc tẩy trắng',
		value: 'tacgiayeucau',
		tooltip: 'Xóa theo yêu cầu của người tạo trang, nếu người đó là đóng góp đáng kể duy nhất, yêu cầu không có ý đồ xấu, và nội dung không có lợi cho Wikisource. Nếu người tạo trang tẩy trống trang, đó có thể xem là yêu cầu',
		subgroup: {
			name: 'author_rationale',
			type: 'input',
			label: 'Giải thích tùy chọn: ',
			tooltip: 'Có thể liên kết đến nơi yêu cầu xóa.',
			size: 60
		},
		hideSubgroupWhenSysop: true
	},
       {
		label: 'K1: Trộn lịch sử',
		value: 'tronlichsu',
		tooltip: 'Tạm thời xóa trang để tiến hành trộn lịch sử',
		subgroup: {
			name: 'histmerge_1',
			type: 'input',
			label: 'Trang sắp được trộn vào trang này: '
		},
		hideWhenMultiple: true,
		hideWhenSysop: true
	},
       {
		label: 'K1: Di chuyển',
		value: 'dichuyen',
		tooltip: 'Tạm thời xóa trang để có chỗ di chuyển trang',
		subgroup: [
			{
				name: 'move_1',
				type: 'input',
				label: 'Trang sắp được di chuyển sang đây: '
			},
			{
				name: 'move_2',
				type: 'input',
				label: 'Lý do: ',
				size: 60
			}
		],
		hideWhenMultiple: true
	},
       {
		label: 'K1: Xóa theo biểu quyết',
		value: 'bqxoa',
		tooltip: 'Xóa theo biểu quyết xóa bài khi có kết luận "xóa".',
		subgroup: {
			name: 'xfd_fullvotepage',
			type: 'input',
			label: 'Trang nơi diễn ra thảo luận xóa bài: ',
			size: 40
		},
		hideWhenMultiple: true
	},
       {
		label: 'K4: Trang mồ côi',
		value: 'mocoi',
		tooltip: 'một trang thảo luận của nội dung đã bị xóa hoặc không tồn tại, trang con không kèm theo trang mẹ, trang tập tin không chứa tập tin, đổi hướng đến trang không tồn tại, lặp đổi hướng, và tên tồi; hoặc thể loại chỉ bao gồm các bản mẫu đã bị xóa hoặc đổi hướng. Các ngoại lệ là những trang hữu ích cho dự án: trang biểu quyết xóa, trang thành viên và thảo luận thành viên, trang lưu thảo luận, trang tập tin hoặc thảo luận tập tin của tập tin được lưu giữ tại Wikimedia Commons',
		subgroup: {
			name: 'g8_rationale',
			type: 'input',
			label: 'Giải thích tùy chọn: ',
			size: 60
		}
	}       
	// {
		// label: 'C2: Thử nghiệm',
		// value: 'test',
		// tooltip: 'Một trang được tạo ra nhằm thử nghiệm việc sửa đổi hoặc tính năng khác của Wikipedia. Không bao gồm các trang nằm trong không gian tên Thành viên.'
	// },
	// {
		// label: 'C3: Phá hoại',
		// value: 'vandalism',
		// tooltip: 'Bao gồm việc trang mang nội dung lừa bịp và được tạo ra do phá hoại di chuyển trang.'
	// },
	// {
		// label: 'C3: Nội dung lừa bịp',
		// value: 'hoax',
		// tooltip: 'Trang mang nội dung lừa bịp rõ ràng',
		// hideWhenMultiple: true
	// },	
	// //{
	// //	label: 'C6: Trang định hướng không cần thiết',
	// //	value: 'disambig',
	// //	tooltip: 'This only applies for orphaned disambiguation pages which either: (1) disambiguate two or fewer existing Wikipedia pages and whose title ends in "(disambiguation)" (i.e., there is a primary topic); or (2) disambiguates no (zero) existing Wikipedia pages, regardless of its title.',
	// //	hideWhenMultiple: true,
	// //	hideWhenRedirect: true
	// //},	
	// {
		// label: 'C6: Dọn dẹp',
		// value: 'g6',
		// tooltip: 'Các tác vụ dọn dẹp',
		// subgroup: {
			// name: 'g6_rationale',
			// type: 'input',
			// label: 'Rationale: ',
			// size: 60
		// }
	// },	
	// {
		// label: 'G8: Subpages with no parent page',
		// value: 'subpage',
		// tooltip: 'This excludes any page that is useful to the project, and in particular: deletion discussions that are not logged elsewhere, user and user talk pages, talk page archives, plausible redirects that can be changed to valid targets, and file pages or talk pages for files that exist on Wikimedia Commons.',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'G10: Attack page (không hoạt động)',
		// value: 'attack',
		// tooltip: 'Pages that serve no purpose but to disparage their subject or some other entity (e.g., "John Q. Doe is an imbecile"). This includes a biography of a living person that is negative in tone and unsourced, where there is no NPOV version in the history to revert to. Administrators deleting such pages should not quote the content of the page in the deletion summary!'
	// },
	// {
		// label: 'G10: Wholly negative, unsourced BLP',
		// value: 'negublp',
		// tooltip: 'A biography of a living person that is entirely negative in tone and unsourced, where there is no neutral version in the history to revert to.',
		// hideWhenMultiple: true
	// },
	// {
		// label: 'G13: Old, abandoned Articles for Creation submissions',
		// value: 'afc',
		// tooltip: 'Any rejected or unsubmitted AfC submission that has not been edited for more than 6 months.',
		// hideWhenRedirect: true
	// }
];

Twinkle.speedy.redirectList = [
       {
		label: 'K2: Đổi hướng không cần thiết',
		value: 'doihuong',
		tooltip: 'từ những tựa trang vừa tạo ra tuần trước, hoặc các đổi hướng đổi hướng cũ được đánh dấu {{subst:chuyển hướng mềm lạc hậu|"[[tựa mới]]"}} trong vòng tối thiểu hai tháng. Các đổi hướng đến trang không tồn tại có thể bị xóa bất cứ lúc nào. Các đổi hướng không cần thiết gồm cả dạng viết hoa ngẫu nhiên trong từng từ (một đổi hướng cho tên trang viết hoa chữ đầu cho tất cả các chữ vẫn được chấp nhận), và các đổi hướng khi di chuyển trang, trong đó tựa gốc bị sai.',
		hideWhenMultiple: true
	},
       {
		label: 'K3: Đổi hướng qua không gian tên',
		value: 'doihuongkgten',
		tooltip: 'từ không gian bài viết sang không gian khác.'
	}
	// {
		// label: 'R3: Redirects as a result of an implausible typo or misnomers that were recently created',
		// value: 'redirtypo',
		// tooltip: 'However, redirects from common misspellings or misnomers are generally useful, as are redirects in other languages'
	// },
	// {
		// label: 'G6: Redirect to malplaced disambiguation page',
		// value: 'movedab',
		// tooltip: 'This only applies for redirects to disambiguation pages ending in (disambiguation) where a primary topic does not exist.',
		// hideWhenMultiple: true
	// },
	
];

Twinkle.speedy.normalizeHash = {
	'lydo': 'cx',
	'vonghia': 'c1',
	'test': 'c2',
	'vandalism': 'c3',
	'hoax': 'c3',
	'danglai': 'c2',
	'cam': 'c3',
	'tronlichsu': 'k1',
	'dichuyen': 'k1',
	'bqxoa': 'k1',
	'disambig': 'c4',
	'movedab': 'c4',
	'trunglap': 'c4',
	'blankdraft': 'c4',
	'g6': 'c4',
	'tacgiayeucau': 'c7',
	'mocoi': 'k4',
	'thaoluan': 'k4',
	'subpage': 'k4',
	'doihuong': 'k2',
	'theloaibanmau': 'k4',
	'tranghinh': 'k4',
	'attack': 'c10',
	'negublp': 'c10',
	'khongws': 'c5',
	'spamuser': 'g11',
	'vpbq': 'c6',
	'afc': 'g13',
	'nocontext': 'a1',
	'chuyenwiki': 'b1',
	'nocontent': 'a3',
	'transwiki': 'a5',
	'khongnoibat': 'b2',
	'person': 'b2',
	'corp': 'b2',
	'web': 'b2',
	'band': 'b2',
	'club': 'b2',
	'animal': 'b2',
	'event': 'b2',
	'a9': 'a9',
	'a10': 'a10',
	'khongtacgia': 'b3',
	'doihuongkgten': 'k3',
	'redirtypo': 'r3',
	'redundantimage': 'f1',
	'noimage': 'f2',
	'fpcfail': 'f2',
	'noncom': 'f3',
	'unksource': 'f4',
	'unfree': 'f5',
	'norat': 'f6',
	'badfairuse': 'f7',
	'nowcommons': 'f8',
	'imgcopyvio': 'f9',
	'badfiletype': 'f10',
	'nopermission': 'f11',
	'catempty': 'c1',
	'tvyeucau': 'c7',
	'nouser': 'u2',
	'gallery': 'u3',
	'notwebhost': 'u5',
	'policy': 't2',
	'duplicatetemplate': 't3',
	'p1': 'p1',
	'emptyportal': 'p2'
};

Twinkle.speedy.callbacks = {
	getTemplateCodeAndParams: function(params) {
		var code, parameters, i;
		if (params.normalizeds.length > 1) {
			code = "{{cx-nhiều";
			params.utparams = {};
			$.each(params.normalizeds, function(index, norm) {
				code += "|" + norm.toUpperCase();
				parameters = params.templateParams[index] || [];
				for (var i in parameters) {
					if (typeof parameters[i] === 'string' && !parseInt(i, 10)) {  // skip numeric parameters - {{db-multiple}} doesn't understand them
						code += "|" + i + "=" + parameters[i];
					}
				}
				$.extend(params.utparams, Twinkle.speedy.getUserTalkParameters(norm, parameters));
			});
			code += "}}";
		} else {
			parameters = params.templateParams[0] || [];
			code = "{{cx-" + params.values[0];
			for (i in parameters) {
				if (typeof parameters[i] === 'string') {
					code += "|" + i + "=" + parameters[i];
				}
			}
			if (params.usertalk) {
				code += "|giúp=tắt";
			}
			code += "}}";
			params.utparams = Twinkle.speedy.getUserTalkParameters(params.normalizeds[0], parameters);
		}

		return [code, params.utparams];
	},

	parseWikitext: function(wikitext, callback) {
		var query = {
			action: "parse",
			prop: "text",
			pst: "true",
			text: wikitext,
			contentmodel: "wikitext",
			title: mw.config.get("wgPageName")
		};

		var statusIndicator = new Morebits.status( 'Đang soạn tóm lược xóa' );
		var api = new Morebits.wiki.api( 'Đang phân tích bản mẫu xóa', query, function(apiObj) {
				var reason = decodeURIComponent($(apiObj.getXML().querySelector('text').childNodes[0].nodeValue).find('#delete-reason').text()).replace(/\+/g, ' ');
				if (!reason) {
					statusIndicator.warn( 'Không thể tạo tóm lược từ bản mẫu xóa' );
				} else {
					statusIndicator.info( 'hoàn tất' );
				}
				callback(reason);
			}, statusIndicator);
		api.post();
	},

	sysop: {
		main: function( params ) {
			var reason;

			if (!params.normalizeds.length && params.normalizeds[0] === 'cx') {
				reason = prompt("Nhập lý do xóa, sẽ được lưu vào nhật trình xóa:", "");
				Twinkle.speedy.callbacks.sysop.deletePage( reason, params );
			} else {
				var code = Twinkle.speedy.callbacks.getTemplateCodeAndParams(params)[0];
				Twinkle.speedy.callbacks.parseWikitext(code, function(reason) {
					if (params.promptForSummary) {
						reason = prompt("Nhập lý do xóa, hoặc nhấn OK để chấp nhận lý do mặc định.", reason);
					}
					Twinkle.speedy.callbacks.sysop.deletePage( reason, params );
				});
			}
		},
		deletePage: function( reason, params ) {
			var thispage = new Morebits.wiki.page( mw.config.get('wgPageName'), "Đang xóa trang" );

			if (reason === null) {
				return Morebits.status.error("Yêu cầu lý do", "Thành viên tự hủy");
			} else if (!reason || !reason.replace(/^\s*/, "").replace(/\s*$/, "")) {
				return Morebits.status.error("Yêu cầu lý do", "bạn không ghi lý do. Tôi không biết nhưng...không hiểu sao bạn có thể làm bảo quản viên được...lý trí của bạn đâu rồi?");
			}
			thispage.setEditSummary( reason + Twinkle.getPref('deletionSummaryAd') );
			thispage.deletePage(function() {
				thispage.getStatusElement().info("done");
				Twinkle.speedy.callbacks.sysop.deleteTalk( params );
			});

			// look up initial contributor. If prompting user for deletion reason, just display a link.
			// Otherwise open the talk page directly
			if( params.openUserTalk ) {
				thispage.setCallbackParameters( params );
				thispage.lookupCreator( Twinkle.speedy.callbacks.sysop.openUserTalkPage );
			}
		},
		deleteTalk: function( params ) {
			// delete talk page
			if (params.deleteTalkPage &&
					params.normalized !== 'f8' &&
					document.getElementById( 'ca-talk' ).className !== 'new') {
				var talkpage = new Morebits.wiki.page( Morebits.wikipedia.namespaces[ mw.config.get('wgNamespaceNumber') + 1 ] + ':' + mw.config.get('wgTitle'), "Đang xóa trang thảo luận" );
				talkpage.setEditSummary('[[WS:XN#K4|K4]]: Trang thảo luận của trang đã bị xóa "' + Morebits.pageNameNorm + '"' + Twinkle.getPref('deletionSummaryAd'));
				talkpage.deletePage();
				// this is ugly, but because of the architecture of wiki.api, it is needed
				// (otherwise success/failure messages for the previous action would be suppressed)
				window.setTimeout(function() { Twinkle.speedy.callbacks.sysop.deleteRedirects( params ); }, 1800);
			} else {
				Twinkle.speedy.callbacks.sysop.deleteRedirects( params );
			}
		},
		deleteRedirects: function( params ) {
			// delete redirects
			if (params.deleteRedirects) {
				var query = {
					'action': 'query',
					'titles': mw.config.get('wgPageName'),
					'prop': 'redirects',
					'rdlimit': 5000  // 500 is max for normal users, 5000 for bots and sysops
				};
				var wikipedia_api = new Morebits.wiki.api( 'đang lấy danh sách trang đổi hướng...', query, Twinkle.speedy.callbacks.sysop.deleteRedirectsMain,
					new Morebits.status( 'Đang xóa trang đổi hướng' ) );
				wikipedia_api.params = params;
				wikipedia_api.post();
			}

			// promote Unlink tool
			var $link, $bigtext;
			if( mw.config.get('wgNamespaceNumber') === 6 && params.normalized !== 'f8' ) {
				$link = $('<a/>', {
					'href': '#',
					'text': 'nhấn vào đây để đi đến công cụ Gỡ liên kết',
					'css': { 'fontSize': '130%', 'fontWeight': 'bold' },
					'click': function(){
						Morebits.wiki.actionCompleted.redirect = null;
						Twinkle.speedy.dialog.close();
						Twinkle.unlink.callback("Đang gỡ sử dụng hoặc liên kết đến tập tin đã xóa " + Morebits.pageNameNorm);
					}
				});
				$bigtext = $('<span/>', {
					'text': 'Khỏi liên kết mồ côi và gỡ sử dụng tập tin',
					'css': { 'fontSize': '130%', 'fontWeight': 'bold' }
				});
				Morebits.status.info($bigtext[0], $link[0]);
			} else if (params.normalized !== 'f8') {
				$link = $('<a/>', {
					'href': '#',
					'text': 'nhấn vào đây để đi đến công cụ Gỡ liên kết',
					'css': { 'fontSize': '130%', 'fontWeight': 'bold' },
					'click': function(){
						Morebits.wiki.actionCompleted.redirect = null;
						Twinkle.speedy.dialog.close();
						Twinkle.unlink.callback("Đang gỡ liên kết đến trang đã xóa " + Morebits.pageNameNorm);
					}
				});
				$bigtext = $('<span/>', {
					'text': 'Khỏi liên kết mồ côi',
					'css': { 'fontSize': '130%', 'fontWeight': 'bold' }
				});
				Morebits.status.info($bigtext[0], $link[0]);
			}
		},
		openUserTalkPage: function( pageobj ) {
			pageobj.getStatusElement().unlink();  // don't need it anymore
			var user = pageobj.getCreator();
			var params = pageobj.getCallbackParameters();

			var query = {
				'title': 'Thảo luận Thành viên:' + user,
				'action': 'edit',
				'preview': 'yes',
				'vanarticle': Morebits.pageNameNorm
			};

			if (params.normalized === 'cx' || Twinkle.getPref("promptForSpeedyDeletionSummary").indexOf(params.normalized) !== -1) {
				// provide a link to the user talk page
				var $link, $bigtext;
				$link = $('<a/>', {
					'href': mw.util.wikiScript('index') + '?' + Morebits.queryString.create( query ),
					'text': 'nhấn vào đây để mở trang Thảo luận Thành viên:' + user,
					'target': '_blank',
					'css': { 'fontSize': '130%', 'fontWeight': 'bold' }
				});
				$bigtext = $('<span/>', {
					'text': 'Để thông báo cho người tạo trang',
					'css': { 'fontSize': '130%', 'fontWeight': 'bold' }
				});
				Morebits.status.info($bigtext[0], $link[0]);
			} else {
				// open the initial contributor's talk page
				var statusIndicator = new Morebits.status('Đang mở mẫu sửa đổi trang thảo luận thành viên của ' + user, 'đang mở...');

				switch( Twinkle.getPref('userTalkPageMode') ) {
				case 'tab':
					window.open( mw.util.wikiScript('index') + '?' + Morebits.queryString.create( query ), '_blank' );
					break;
				case 'blank':
					window.open( mw.util.wikiScript('index') + '?' + Morebits.queryString.create( query ), '_blank', 'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800' );
					break;
				case 'window':
					/* falls through */
				default:
					window.open( mw.util.wikiScript('index') + '?' + Morebits.queryString.create( query ),
						( window.name === 'twinklewarnwindow' ? '_blank' : 'twinklewarnwindow' ),
						'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800' );
					break;
				}

				statusIndicator.info( 'xong' );
			}
		},
		deleteRedirectsMain: function( apiobj ) {
			var xmlDoc = apiobj.getXML();
			var $snapshot = $(xmlDoc).find('redirects rd');
			var total = $snapshot.length;
			var statusIndicator = apiobj.statelem;

			if( !total ) {
				statusIndicator.status("no redirects found");
				return;
			}

			statusIndicator.status("0%");

			var current = 0;
			var onsuccess = function( apiobjInner ) {
				var now = parseInt( 100 * (++current)/total, 10 ) + '%';
				statusIndicator.update( now );
				apiobjInner.statelem.unlink();
				if( current >= total ) {
					statusIndicator.info( now + ' (completed)' );
					Morebits.wiki.removeCheckpoint();
				}
			};

			Morebits.wiki.addCheckpoint();

			$snapshot.each(function(key, value) {
				var title = $(value).attr('title');
				var page = new Morebits.wiki.page(title, 'Deleting redirect "' + title + '"');
				page.setEditSummary('[[WS:XN#X8|X8]]: Đổi hướng đến trang bị xóa "' + Morebits.pageNameNorm + '"' + Twinkle.getPref('deletionSummaryAd'));
				page.deletePage(onsuccess);
			});
		}
	},

	user: {
		main: function(pageobj) {
			var statelem = pageobj.getStatusElement();

			if (!pageobj.exists()) {
				statelem.error( "It seems that the page doesn't exist; perhaps it has already been deleted" );
				return;
			}

			var text = pageobj.getPageText();
			var params = pageobj.getCallbackParameters();

			statelem.status( 'Checking for tags on the page...' );

			// check for existing deletion tags
			var tag = /(?:\{\{\s*(cx|chờ xóa|cx-.*?|xóa nhanh-.*?)(?:\s*\||\s*\}\}))/.exec( text );
			if( tag ) {
				statelem.error( [ Morebits.htmlNode( 'strong', tag[1] ) , " is already placed on the page." ] );
				return;
			}

			var xfd = /(?:\{\{([rsaiftcm]fd|md1|proposed deletion|biểu quyết xóa)[^{}]*?\}\})/i.exec( text );
			if( xfd && !confirm( "Bản mẫu liên quan đến việc xóa {{" + xfd[1] + "}} được tìm thấy tại trang. Bạn vẫn muốn thêm bản mẫu chờ xóa?" ) ) {
				return;
			}

			// given the params, builds the template and also adds the user talk page parameters to the params that were passed in
			// returns => [<string> wikitext, <object> utparams]
			var buildData = Twinkle.speedy.callbacks.getTemplateCodeAndParams(params),
				code = buildData[0];
			params.utparams = buildData[1];

			var thispage = new Morebits.wiki.page(mw.config.get('wgPageName'));
			// patrol the page, if reached from Special:NewPages
			if( Twinkle.getPref('markSpeedyPagesAsPatrolled') ) {
				thispage.patrol();
			}

			// Wrap SD template in noinclude tags if we are in template space.
			// Won't work with userboxes in userspace, or any other transcluded page outside template space
			if (mw.config.get('wgNamespaceNumber') === 10) {  // Template:
				code = "<noinclude>" + code + "</noinclude>";
			}

			// Remove tags that become superfluous with this action
			text = text.replace(/\{\{\s*([Nn]ew unreviewed article|[Uu]nreviewed|[Uu]serspace draft)\s*(\|(?:\{\{[^{}]*\}\}|[^{}])*)?\}\}\s*/g, "");
			if (mw.config.get('wgNamespaceNumber') === 6) {
				// remove "move to Commons" tag - deletion-tagged files cannot be moved to Commons
				text = text.replace(/\{\{(mtc|(copy |move )?to ?commons|move to wikimedia commons|copy to wikimedia commons)[^}]*\}\}/gi, "");
			}

			// Generate edit summary for edit
			var editsummary;
			if (params.normalizeds.length > 1) {
				editsummary = 'Requesting speedy deletion (';
				$.each(params.normalizeds, function(index, norm) {
					editsummary += '[[WP:CSD#' + norm.toUpperCase() + '|CSD ' + norm.toUpperCase() + ']], ';
				});
				editsummary = editsummary.substr(0, editsummary.length - 2); // remove trailing comma
				editsummary += ').';
			} else if (params.normalizeds[0] === "cx") {
				editsummary = 'Đề nghị [[WS:XN|Xóa nhanh]] với lý do “' + params.templateParams[0]["1"] + '”.';
			} else if (params.values[0] === "histmerge") {
				editsummary = "Đề nghị trộn lịch sử trang với [[:" + params.templateParams[0]["1"] + "]] ([[WS:XN#K1|XN K1]]).";
			} else {
				editsummary = "Đề nghị xóa nhanh ([[WS:XN#" + params.normalizeds[0].toUpperCase() + "|XN " + params.normalizeds[0].toUpperCase() + "]]).";
			}

			pageobj.setPageText(code + ((params.normalizeds.indexOf('g10') !== -1) ? '' : ("\n" + text) )); // cause attack pages to be blanked
			pageobj.setEditSummary(editsummary + Twinkle.getPref('summaryAd'));
			pageobj.setWatchlist(params.watch);
			pageobj.setCreateOption('nocreate');
			pageobj.save(Twinkle.speedy.callbacks.user.tagComplete);
		},

		tagComplete: function(pageobj) {
			var params = pageobj.getCallbackParameters();

			// Notification to first contributor
			if (params.usertalk) {
				var callback = function(pageobj) {
					var initialContrib = pageobj.getCreator();

					// disallow warning yourself
					if (initialContrib === mw.config.get('wgUserName')) {
						Morebits.status.warn("You (" + initialContrib + ") created this page; skipping user notification");

					// don't notify users when their user talk page is nominated
					} else if (initialContrib === mw.config.get('wgTitle') && mw.config.get('wgNamespaceNumber') === 3) {
						Morebits.status.warn("Notifying initial contributor: this user created their own user talk page; skipping notification");

					// quick hack to prevent excessive unwanted notifications, per request. Should actually be configurable on recipient page...
					} else if ((initialContrib === "Cyberbot I" || initialContrib === "SoxBot") && params.normalizeds[0] === "f2") {
						Morebits.status.warn("Notifying initial contributor: page created procedurally by bot; skipping notification");

					} else {
						var usertalkpage = new Morebits.wiki.page('Thảo luận Thành viên:' + initialContrib, "Notifying initial contributor (" + initialContrib + ")"),
							notifytext, i;

						// specialcase "cx" and "cx-nhiều"
						if (params.normalizeds.length > 1) {
							notifytext = "\n{{subst:cx-tb-nhiều|1=" + Morebits.pageNameNorm;
							var count = 2;
							$.each(params.normalizeds, function(index, norm) {
								notifytext += "|" + (count++) + "=" + norm.toUpperCase();
							});
						} else if (params.normalizeds[0] === "cx") {
							notifytext = "\n{{subst:cx-ld-tb|1=" + Morebits.pageNameNorm;
						} else {
							notifytext = "\n{{subst:cx-ycx-tb-tc|1=" + Morebits.pageNameNorm + "|2=" + params.values[0];
						}

						for (i in params.utparams) {
							if (typeof params.utparams[i] === 'string') {
								notifytext += "|" + i + "=" + params.utparams[i];
							}
						}
						notifytext += (params.welcomeuser ? "" : "|nowelcome=yes") + "}} ~~~~";

						var editsummary = "Notification: speedy deletion nomination";
						if (params.normalizeds.indexOf("g10") === -1) {  // no article name in summary for G10 deletions
							editsummary += " of [[:" + Morebits.pageNameNorm + "]].";
						} else {
							editsummary += " of an attack page.";
						}

						usertalkpage.setAppendText(notifytext);
						usertalkpage.setEditSummary(editsummary + Twinkle.getPref('summaryAd'));
						usertalkpage.setCreateOption('recreate');
						usertalkpage.setFollowRedirect(true);
						usertalkpage.append();
					}

					// thêm đề nghị này vào nhật trình không gian thành viên, nếu thành viên có kích hoạt chức năng này
					if (params.lognomination) {
						Twinkle.speedy.callbacks.user.addToLog(params, initialContrib);
					}
				};
				var thispage = new Morebits.wiki.page(Morebits.pageNameNorm);
				thispage.lookupCreator(callback);
			}
			// or, if not notifying, add this nomination to the user's userspace log without the initial contributor's name
			else if (params.lognomination) {
				Twinkle.speedy.callbacks.user.addToLog(params, null);
			}
		},

		// note: this code is also invoked from twinkleimage
		// the params used are:
		//   for CSD: params.values, params.normalizeds  (note: normalizeds is an array)
		//   for DI: params.fromDI = true, params.templatename, params.normalized  (note: normalized is a string)
		addToLog: function(params, initialContrib) {
			var wikipedia_page = new Morebits.wiki.page("User:" + mw.config.get('wgUserName') + "/" + Twinkle.getPref('speedyLogPageName'), "Adding entry to userspace log");
			params.logInitialContrib = initialContrib;
			wikipedia_page.setCallbackParameters(params);
			wikipedia_page.load(Twinkle.speedy.callbacks.user.saveLog);
		},

		saveLog: function(pageobj) {
			var text = pageobj.getPageText();
			var params = pageobj.getCallbackParameters();

			var appendText = "";

			// add blurb if log page doesn't exist
			if (!pageobj.exists()) {
				appendText +=
					"Đây là nhật trình liệt kê tất các các đề nghị [[WS:XN|xóa nhanh]] sử dụng công cụ [[WP:TW|Twinkle]] XN của thành viên này.\n\n" +
					"Nếu bạn không muốn giữ nhật trình này bạn có thể tắt nó [[Wikisource:Twinkle/Preferences|tại trang này]], và " +
					"đề nghị xóa nhanh trang này theo tiêu chí [[WS:XN#TV1|XN TV1]].";
				if (Morebits.userIsInGroup("sysop")) {
					appendText += "\n\nThis log does not track outright speedy deletions made using Twinkle.";
				}
			}

			// create monthly header
			var date = new Date();
			var headerRe = new RegExp("^==+\\s*" + date.getUTCMonthName() + "\\s+" + date.getUTCFullYear() + "\\s*==+", "m");
			if (!headerRe.exec(text)) {
				appendText += "\n\n=== " + date.getUTCMonthName() + " " + date.getUTCFullYear() + " ===";
			}

			appendText += "\n# [[:" + Morebits.pageNameNorm + "]]: ";
			if (params.fromDI) {
				appendText += "XH [[WS:XN#" + params.normalized.toUpperCase() + "|XN " + params.normalized.toUpperCase() + "]] ({{tl|xh-" + params.templatename + "}})";
			} else {
				if (params.normalizeds.length > 1) {
					appendText += "multiple criteria (";
					$.each(params.normalizeds, function(index, norm) {
						appendText += "[[WS:XN#" + norm.toUpperCase() + "|" + norm.toUpperCase() + ']], ';
					});
					appendText = appendText.substr(0, appendText.length - 2);  // remove trailing comma
					appendText += ')';
				} else if (params.normalizeds[0] === "cx") {
					appendText += "{{tl|cx-ld}}";
				} else {
					appendText += "[[WS:XN#" + params.normalizeds[0].toUpperCase() + "|XN " + params.normalizeds[0].toUpperCase() + "]] ({{tl|cx-" + params.values[0] + "}})";
				}
			}

			if (params.logInitialContrib) {
				appendText += "; notified {{user|1=" + params.logInitialContrib + "}}";
			}
			appendText += " ~~~~~\n";

			pageobj.setAppendText(appendText);
			pageobj.setEditSummary("Logging speedy deletion nomination of [[:" + Morebits.pageNameNorm + "]]." + Twinkle.getPref('summaryAd'));
			pageobj.setCreateOption("recreate");
			pageobj.append();
		}
	}
};

// validate subgroups in the form passed into the speedy deletion tag
Twinkle.speedy.getParameters = function twinklespeedyGetParameters(form, values) {
	var parameters = [];

	$.each(values, function(index, value) {
		var currentParams = [];
		switch (value) {
			case 'lydo':
				if (form["csd.reason_1"]) {
					var dbrationale = form["csd.reason_1"].value;
					if (!dbrationale || !dbrationale.trim()) {
						alert( 'Lý do tùy chỉnh: Vui lòng ghi lý do.' );
						parameters = null;
						return false;
					}
					currentParams["1"] = dbrationale;
				}
				break;

			case 'tvyeucau':  // C7
				if (form["csd.userreq_rationale"]) {
					var u1rationale = form["csd.userreq_rationale"].value;
					if (mw.config.get('wgNamespaceNumber') === 3 && !((/\//).test(mw.config.get('wgTitle'))) &&
							(!u1rationale || !u1rationale.trim())) {
						alert( 'XN C7:  Vui lòng ghi lý do khi yêu cầu xóa trang thảo luận thành viên.' );
						parameters = null;
						return false;
					}
					currentParams.rationale = u1rationale;
				}
				break;

			case 'danglai':  // C2
				if (form["csd.repost_1"]) {
					var deldisc = form["csd.repost_1"].value;
					if (deldisc) {
						if (deldisc.substring(0, 10) !== "Wikisource" && deldisc.substring(0, 3) !== "WP:") {
							alert( 'XN C2:  Tên trang có thảo luận xóa, nếu có, phải bắt đầu bằng "Wikisource:".' );
							parameters = null;
							return false;
						}
						currentParams["1"] = deldisc;
					}
				}
				break;

			case 'cam':  // C3
				if (form["csd.banned_1"] && form["csd.banned_1"].value) {
					currentParams["1"] = form["csd.banned_1"].value.replace(/^\s*(Thành viên|User):/i, "");
				}
				break;

			case 'tronlichsu':  // K1
				if (form["csd.histmerge_1"]) {
					var merger = form["csd.histmerge_1"].value;
					if (!merger || !merger.trim()) {
						alert( 'XN K1 (trộn sử):  Vui lòng ghi tên trang chuẩn bị được trộn vào.' );
						parameters = null;
						return false;
					}
					currentParams["1"] = merger;
				}
				break;

			case 'dichuyen':  // K1
				if (form["csd.move_1"] && form["csd.move_2"]) {
					var movepage = form["csd.move_1"].value,
						movereason = form["csd.move_2"].value;
					if (!movepage || !movepage.trim()) {
						alert( 'XN K1 (di chuyển):  Vui lòng ghi tên trang sắp được chuyển vào đây.' );
						parameters = null;
						return false;
					}
					if (!movereason || !movereason.trim()) {
						alert( 'XN K1 (di chuyển):  Vui lòng ghi lý do di chuyển.' );
						parameters = null;
						return false;
					}
					currentParams["1"] = movepage;
					currentParams["2"] = movereason;
				}
				break;

			case 'bqxoa':  // K1
				if (form["csd.xfd_fullvotepage"]) {
					var xfd = form["csd.xfd_fullvotepage"].value;
					if (xfd) {
						if (xfd.substring(0, 10) !== "Wikisource" && xfd.substring(0, 3) !== "WS:") {
							alert( 'XN K1 (bqx):  Tên trang thảo luận việc xóa, nếu có, phải bắt đầu bằng "Wikisource:".' );
							parameters = null;
							return false;
						}
						currentParams.fullvotepage = xfd;
					}
				}
				break;

			case 'trunglap':  // C4
				if (form["csd.copypaste_1"]) {
					var copypaste = form["csd.copypaste_1"].value;
					if (!copypaste || !copypaste.trim()) {
						alert( 'XN C4 (trùng lắp):  Vui lòng ghi tên trang nguồn.' );
						parameters = null;
						return false;
					}
					currentParams["1"] = copypaste;
				}
				break;

			case 'g6':  // G6
				if (form["csd.g6_rationale"] && form["csd.g6_rationale"].value) {
					currentParams.rationale = form["csd.g6_rationale"].value;
				}
				break;

			case 'tacgiayeucau':  // C7
				if (form["csd.author_rationale"] && form["csd.author_rationale"].value) {
					currentParams.rationale = form["csd.author_rationale"].value;
				}
				break;

			case 'mocoi':  // K4
				if (form["csd.g8_rationale"] && form["csd.g8_rationale"].value) {
					currentParams.rationale = form["csd.g8_rationale"].value;
				}
				break;

			case 'attack':  // G10
				currentParams.blanked = 'yes';
				// it is actually blanked elsewhere in code, but setting the flag here
				break;

			case 'vpbq':  // C6
				if (form["csd.copyvio_url"] && form["csd.copyvio_url"].value) {
					currentParams.url = form["csd.copyvio_url"].value;
				}
				if (form["csd.copyvio_url2"] && form["csd.copyvio_url2"].value) {
					currentParams.url2 = form["csd.copyvio_url2"].value;
				}
				if (form["csd.copyvio_url3"] && form["csd.copyvio_url3"].value) {
					currentParams.url3 = form["csd.copyvio_url3"].value;
				}
				break;

			case 'afc':  // G13
				var query = {
							action: "query",
							titles: mw.config.get("wgPageName"),
							prop: "revisions",
							rvprop: "timestamp"
						},
						api = new Morebits.wiki.api( 'Grabbing the last revision timestamp', query, function( apiobj ) {
							var xmlDoc = apiobj.getXML(),
									isoDateString = $(xmlDoc).find("rev").attr("timestamp");

							currentParams.ts = isoDateString;
						});

				// Wait for API call to finish
				api.post({
					async: false
				});

				break;

			case 'redundantimage':  // F1
				if (form["csd.redundantimage_filename"]) {
					var redimage = form["csd.redundantimage_filename"].value;
					if (!redimage || !redimage.trim()) {
						alert( 'CSD F1:  Please specify the filename of the other file.' );
						parameters = null;
						return false;
					}
					currentParams.filename = redimage.replace(/^\s*(Image|File|Tập tin|Hình):/i, "");
				}
				break;

			case 'badfairuse':  // F7
				if (form["csd.badfairuse_reason"] && form["csd.badfairuse_reason"].value) {
					currentParams.reason = form["csd.badfairuse_reason"].value;
				}
				break;

			case 'nowcommons':  // F8
				if (form["csd.nowcommons_filename"]) {
					var filename = form["csd.nowcommons_filename"].value;
					if (filename && filename !== Morebits.pageNameNorm) {
						if (filename.indexOf("Image:") === 0 || filename.indexOf("File:") === 0) {
							currentParams["1"] = filename;
						} else {
							currentParams["1"] = "File:" + filename;
						}
					}
				}
				currentParams.date = "~~~~~";
				break;

			case 'imgcopyvio':  // F9
				if (form["csd.imgcopyvio_url"] && form["csd.imgcopyvio_url"].value) {
					currentParams.url = form["csd.imgcopyvio_url"].value;
				}
				break;

			case 'chuyenwiki':  // B1
				if (form["csd.foreign_source"]) {
					var foreignlink = form["csd.foreign_source"].value;
					if (!foreignlink || !foreignlink.trim()) {
						alert( 'XN B1:  Vui lòng ghi liên kết liên wiki đến trang đã chuyển nội dung tới.' );
						parameters = null;
						return false;
					}
					currentParams.source = foreignlink;
				}
				break;

			case 'a10':  // A10
				if (form["csd.a10_article"]) {
					var duptitle = form["csd.a10_article"].value;
					if (!duptitle || !duptitle.trim()) {
						alert( 'CSD A10:  Please specify the name of the article which is duplicated.' );
						parameters = null;
						return false;
					}
					currentParams.article = duptitle;
				}
				break;

			case 'duplicatetemplate':  // T3
				if (form["csd.duplicatetemplate_2"]) {
					var t3template = form["csd.duplicatetemplate_2"].value;
					if (!t3template || !t3template.trim()) {
						alert( 'CSD T3:  Please specify the name of a template duplicated by this one.' );
						parameters = null;
						return false;
					}
					currentParams["1"] = "~~~~~";
					currentParams["2"] = t3template.replace(/^\s*(Template|Bản mẫu|Tiêu bản):/i, "");
				}
				break;

			case 'p1':  // P1
				if (form["csd.p1_criterion"]) {
					var criterion = form["csd.p1_criterion"].value;
					if (!criterion || !criterion.trim()) {
						alert( 'CSD P1:  Please specify a criterion and/or associated rationale.' );
						parameters = null;
						return false;
					}
					currentParams["1"] = criterion;
				}
				break;

			default:
				break;
		}
		parameters.push(currentParams);
	});
	return parameters;
};

// function for processing talk page notification template parameters
Twinkle.speedy.getUserTalkParameters = function twinklespeedyGetUserTalkParameters(normalized, parameters) {
	var utparams = [];
	switch (normalized) {
		case 'cx':
			utparams["2"] = parameters["1"];
			break;
		case 'g12':
			utparams.key1 = "url";
			utparams.value1 = utparams.url = parameters.url;
			break;
		case 'a10':
			utparams.key1 = "article";
			utparams.value1 = utparams.article = parameters.article;
			break;
		default:
			break;
	}
	return utparams;
};


Twinkle.speedy.resolveCsdValues = function twinklespeedyResolveCsdValues(e) {
	var values = (e.target.form ? e.target.form : e.target).getChecked('csd');
	if (values.length === 0) {
		alert( "Please select a criterion!" );
		return null;
	}
	return values;
};

Twinkle.speedy.callback.evaluateSysop = function twinklespeedyCallbackEvaluateSysop(e) {
	var form = (e.target.form ? e.target.form : e.target);

	if (e.target.type === "checkbox" || e.target.type === "text" ||
			e.target.type === "select") {
		return;
	}

	var tag_only = form.tag_only;
	if( tag_only && tag_only.checked ) {
		Twinkle.speedy.callback.evaluateUser(e);
		return;
	}

	var values = Twinkle.speedy.resolveCsdValues(e);
	if (!values) {
		return;
	}

	var normalizeds = values.map(function(value) {
		return Twinkle.speedy.normalizeHash[ value ];
	});

	// analyse each criterion to determine whether to watch the page, prompt for summary, or open user talk page
	var watchPage, promptForSummary;
	normalizeds.forEach(function(norm) {
		if (Twinkle.getPref("watchSpeedyPages").indexOf(norm) !== -1) {
			watchPage = true;
		}
		if (Twinkle.getPref("promptForSpeedyDeletionSummary").indexOf(norm) !== -1) {
			promptForSummary = true;
		}
	});

	var params = {
		values: values,
		normalizeds: normalizeds,
		watch: watchPage,
		deleteTalkPage: form.talkpage && form.talkpage.checked,
		deleteRedirects: form.redirects.checked,
		openUserTalk: form.openusertalk.checked,
		promptForSummary: promptForSummary,
		templateParams: Twinkle.speedy.getParameters( form, values )
	};
	if(!params.templateParams) {
		return;
	}

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

	Twinkle.speedy.callbacks.sysop.main( params );
};

Twinkle.speedy.callback.evaluateUser = function twinklespeedyCallbackEvaluateUser(e) {
	var form = (e.target.form ? e.target.form : e.target);

	if (e.target.type === "checkbox" || e.target.type === "text" ||
			e.target.type === "select") {
		return;
	}

	var values = Twinkle.speedy.resolveCsdValues(e);
	if (!values) {
		return;
	}
	//var multiple = form.multiple.checked;
	var normalizeds = [];
	$.each(values, function(index, value) {
		var norm = Twinkle.speedy.normalizeHash[ value ];

		normalizeds.push(norm);
	});

	// analyse each criterion to determine whether to watch the page/notify the creator
	var watchPage = false;
	$.each(normalizeds, function(index, norm) {
		if (Twinkle.getPref('watchSpeedyPages').indexOf(norm) !== -1) {
			watchPage = true;
			return false;  // break
		}
	});

	var notifyuser = false;
	if (form.notify.checked) {
		$.each(normalizeds, function(index, norm) {
			if (Twinkle.getPref('notifyUserOnSpeedyDeletionNomination').indexOf(norm) !== -1) {
				if (norm === 'c4' && ['disambig', 'trunglap'].indexOf(values[index]) === -1) {
					return true;
				}
				notifyuser = true;
				return false;  // break
			}
		});
	}

	var welcomeuser = false;
	if (notifyuser) {
		$.each(normalizeds, function(index, norm) {
			if (Twinkle.getPref('welcomeUserOnSpeedyDeletionNotification').indexOf(norm) !== -1) {
				welcomeuser = true;
				return false;  // break
			}
		});
	}

	var csdlog = false;
	if (Twinkle.getPref('logSpeedyNominations')) {
		$.each(normalizeds, function(index, norm) {
			if (Twinkle.getPref('noLogOnSpeedyNomination').indexOf(norm) === -1) {
				csdlog = true;
				return false;  // break
			}
		});
	}

	var params = {
		values: values,
		normalizeds: normalizeds,
		watch: watchPage,
		usertalk: notifyuser,
		welcomeuser: welcomeuser,
		lognomination: csdlog,
		templateParams: Twinkle.speedy.getParameters( form, values )
	};
	if (!params.templateParams) {
		return;
	}

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

	Morebits.wiki.actionCompleted.redirect = mw.config.get('wgPageName');
	Morebits.wiki.actionCompleted.notice = "Thêm thông báo hoàn tất";

	var wikipedia_page = new Morebits.wiki.page(mw.config.get('wgPageName'), "Thêm thông báo");
	wikipedia_page.setCallbackParameters(params);
	wikipedia_page.load(Twinkle.speedy.callbacks.user.main);
};
})(jQuery);


//</nowiki>