User:NguoiDungKhongDinhDanh/RfDHelper.js

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

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/** <nowiki>
 * RfDHelper is a script that helps nominating pages for deletion at [[WM:RfD]].
 * 
 * See also: [[User:NguoiDungKhongDinhDanh/WarningDialog.js]]
**/
/* jshint esversion: 6, maxerr: 9999 *//* globals $, mw */

$(function() {
	if (mw.config.get('wgNamespaceNumber') < 0 && mw.config.get('wgRelevantPageName') === mw.config.get('wgPageName')) return;
	mw.util.addPortletLink('p-tb', '', 'Nominate for deletion', 't-rfdhelper');
	
	var advert = ' ([[User:NguoiDungKhongDinhDanh/RfDHelper.js|RfDHelper]])';
	
	$('#t-rfdhelper').click(function(e) {
		e.preventDefault();
		if ($('#rfdhelper').length) {
			$('#rfdhelper').dialog('open');
			return;
		}
		var ns = mw.config.get('wgNamespaceNumber');
		var pn = mw.config.get('wgPageName').replace(/_/g, ' ');
		var rpn = mw.config.get('wgRelevantPageName');
		var p =  ns >= 0 ? pn : rpn;
		
		var css = `
			.rfdhelper-loader .rfdhelper-loader-items::after {
				content: ' ';
				display: block;
				position: absolute;
				top: 4px;
				left: 36px;
				width: 6px;
				height: 18px;
				border-radius: 20%;
				background: #000000;
			}
			@keyframes rfdhelper-loader {
				0% {
					opacity: 1;
				}
				100% {
					opacity: 0;
				}
			}
			#rfdhelper input, #rfdhelper textarea, #rfdhelper select {
				-webkit-transition: border-color 250ms, box-shadow 250ms;
				transition: border-color 250ms, box-shadow 250ms;
			}
			#rfdhelper input:not([disabled]):focus,
			#rfdhelper textarea:not([disabled]):focus,
			#rfdhelper select:not([disabled]):focus,
			#rfdhelper input:not([disabled]):active,
			#rfdhelper textarea:not([disabled]):active,
			#rfdhelper select:not([disabled]):active {
				outline: 0;
				border-color: #3366CC;
				box-shadow: inset 0 0 0 1px #3366CC;
			}
		`; // Copied from OO.UI core.
		try {
			mw.util.addCSS(css);
		} catch (e) {
			mw.loader.addStyleTag(css);
		}
		var loader = function() {
			var e = function() {
				var r = '';
				for (let i = 0; i < 12; i++) {
					r += '<div class="rfdhelper-loader-items" style="' +
						'animation: rfdhelper-loader 1.2s linear infinite; ' +
						'transform: rotate(' + (i * 30) + 'deg); ' +
						'transform-origin: 40px 40px; ' +
						'animation-delay: ' + Math.round((-1.1 + (i * 0.1)) * 10) / 10 + 's;">' +
						'</div>';
				}
				return r;
			};
			var l = '<div class="rfdhelper-loader-wrapper" id="rfdhelper-loader" ' +
					'style="display: block; margin: 3em 0; text-align: center;">' +
						'<div class="rfdhelper-loader" style="display: inline-block; ' +
						'position: relative; width: 80px; height: 80px;">' +
							e() +
						'</div>' +
					'</div>';
			return l;
		};
		var call = function(data, callback, onerror) {
			// For attribution: [[:en:User:Joeytje50/JWB.js]].
			$.ajax({
				url: mw.config.get('wgScriptPath') + '/api.php',
				data: data,
				dataType: 'json',
				type: 'POST',
				success: function(response) {
					if (response.error) {
						if (onerror && onerror(response, 'API') === false) return;
						alert('API error: ' + response.error.info);
					} else {
						callback(response);
					}
				},
				// onerror: if it exists and returns false, do not show error alert. Otherwise, do show alert.
				error: function(xhr, error) {
					if (onerror && onerror(error, 'AJAX') === false) return;
					alert('AJAX error: ' + error);
				}
			});
		};
		
		$('<div>').attr('id', 'rfdhelper').css('font-size', '1.2em').append(
			$('<div>').attr('id', 'rfdhelper-single')
				.append(
					$('<label>').attr('for', 'rfdhelper-single-subsectiontitle').css({
						'display': 'flex',
						'flex-direction': 'column'
					}).append(
						$('<span>')
						.attr({
							class: 'rfdhelper-single-label',
						})
						.css({
							'align-self': 'flex-start',
							'margin': '0.3em'
						})
						.text('Subsection title:')
					).append(
						$('<div>').css({
							'display': 'flex'
						}).append(
							$('<input>')
							.attr({
								type: 'text',
								id: 'rfdhelper-single-subsectiontitle'
							})
							.css({
								'flex-grow': '4',
								'margin': '0.3em',
								'padding': '0.3em'
							})
							.val('[[:' + p + ']]')
							.prop('disabled', true)
						).append(
							$('<select>').attr('id', 'rfdhelper-single-sectiontitle').css({
								'margin': '0.3em',
								'padding': '0.3em'
							})
							.append(
								$('<option>').val('pages').text('Page'),
								$('<option>').val('templates').text('Template'),
								$('<option>').val('categories').text('Category'),
								$('<option>').val('files').text('File'),
								$('<option>').val('redirects').text('Redirect')
							)
						)
					)
				).append(
					$('<label>').css({
						'display': 'flex',
						'flex-direction': 'column'
					}).append(
						$('<span>')
						.attr({
							class: 'rfdhelper-single-label',
						})
						.css({
							'align-self': 'flex-start',
							'margin': '0.3em'
						})
						.text('Page to nominate:')
					).append(
						$('<input>')
						.attr({
							type: 'text',
							id: 'rfdhelper-single-pagename'
						})
						.css({
							'align-self': 'stretch',
							'margin': '0.3em',
							'padding': '0.3em'
						})
						.val(p)
					)
				).append(
					$('<label>').css({
						'display': 'flex',
						'flex-direction': 'column'
					}).append(
						$('<span>')
						.attr({
							class: 'rfdhelper-single-label'
						})
						.css({
							'align-self': 'flex-start',
							'margin': '0.3em'
						})
						.text('Why should it be deleted?')
					).append(
						$('<textarea>')
						.attr({
							id: 'rfdhelper-single-rationale'
						})
						.css({
							'margin': '0.3em',
							'padding': '0.5em',
							'resize': 'vertical',
							'width': 'auto',
							'min-height': '7.5em'
						})
					)
				)
		).append(
			$('<div>').attr('id', 'rfdhelper-multi')
				.css('display', 'none')
				.append(
					$('<label>').css({
						'display': 'flex',
						'flex-direction': 'column'
					}).append(
						$('<span>')
						.attr({
							class: 'rfdhelper-multi-label',
						})
						.css({
							'align-self': 'flex-start',
							'margin': '0.3em'
						})
						.text('Subsection title:')
					).append(
						$('<div>').css({
							'display': 'flex'
						}).append(
							$('<input>')
							.attr({
								type: 'text',
								autocomplete: 'off',
								id: 'rfdhelper-multi-subsectiontitle'
							})
							.css({
								'flex-grow': '4',
								'margin': '0.3em',
								'padding': '0.3em'
							})
							.val('[[:' + p + ']]')
						).append(
							$('<select>').attr('id', 'rfdhelper-multi-sectiontitle').css({
								'margin': '0.3em',
								'padding': '0.3em'
							})
							.append(
								$('<option>').val('pages').text('Pages')
							).append(
								$('<option>').val('templates').text('Templates')
							).append(
								$('<option>').val('categories').text('Categories')
							).append(
								$('<option>').val('files').text('Files')
							).append(
								$('<option>').val('redirects').text('Redirects')
							)
						)
					)
				).append(
					$('<div>').css({
						'display': 'flex',
						'flex-direction': 'column'
					}).append(
						$('<label>')
						.attr({
							class: 'rfdhelper-multi-label',
						})
						.css({
							'align-self': 'flex-start',
							'margin': '0.3em 0',
							'padding': '0 0.3em'
						})
						.text('Pages to nominate:')
					).append(
						$('<div>').attr('id', 'rfdhelper-multi-pagenames')
							.css({
								'display': 'flex',
								'flex-direction': 'column',
								'padding': '0 0.3em'
							})
							.append(
								$('<div>')
								.attr('class', 'rfdhelper-multi-pagenames-line')
								.css({
									'display': 'flex',
									'align-content': 'stretch'
								})
								.append(
									$('<input>')
									.attr({
										type: 'text',
										class: 'rfdhelper-multi-pagenames'
									})
									.css({
										'align-self': 'center',
										'flex-grow': '4',
										'margin': '0.3em 0',
										'padding': '0.3em'
									})
									.val(p)
								).append(
									$('<button>')
									.attr('class', 'rfdhelper-multi-button-remove')
									.css('margin', '0.3em 0 0.3em 0.3em')
									.text('Remove')
									.button()
								)
							)
					).append(
						$('<div>')
						.css({
							'display': 'flex',
							'flex-direction': 'row-reverse',
							'padding': '0 0.3em'
						}).append(
							$('<button>')
							.attr('id', 'rfdhelper-multi-button-add')
							.text('New line')
							.button()
						).append(
							$('<button>')
							.attr('id', 'rfdhelper-multi-button-toggle')
							.text('Switch editor')
							.button()
						).append(
							$('<button>')
							.attr('id', 'rfdhelper-multi-button-autotitle')
							.text('Get me a title')
							.button()
						)
					)
				).append(
					$('<label>').css({
						'display': 'flex',
						'flex-direction': 'column'
					})
					.append(
						$('<span>')
						.attr({
							class: 'rfdhelper-multi-label'
						})
						.css({
							'align-self': 'flex-start',
							'margin': '0.3em'
						})
						.text('Why should they be deleted?')
					).append(
						$('<textarea>')
						.attr({
							id: 'rfdhelper-multi-rationale'
						})
						.css({
							'margin': '0.3em',
							'padding': '0.5em',
							'resize': 'vertical',
							'width': 'auto',
							'min-height': '7.5em'
						})
					)
				)
		).append(
			$('<label>').css({
				'display': 'flex',
				'flex-direction': 'column'
			})
			.append(
				$('<span>')
				.attr({
					class: 'rfdhelper-label'
				})
				.css({
					'align-self': 'flex-start',
					'margin': '0.3em'
				})
				.text('Users to notify:')
			).append(
				$('<div>').attr('id', 'rfdhelper-contributors').css({
					'display': 'flex',
					'flex-direction': 'column',
					'gap': '1em',
					'margin': '0.3em',
					'border': '1px solid #C8CCD1',
					'min-height': '7.5em',
					'overflow-y': 'auto',
					'padding': '1em'
				})
			)
		).appendTo('body');
		
		$('#rfdhelper').dialog({
			autoOpen: true,
			width: '80%',
			'min-width': '60%',
			height: 600,
			'min-height': 400,
			title: 'Nominating ' + p + ' for deletion',
			buttons: [
				{
					text: 'Help',
					click: function() {
						if (!$('#rfdhelper-help').length) $('#rfdhelper').append(
							$('<div>').attr('id', 'rfdhelper-help').css({
								'display': 'none',
								'padding': '0.3em'
							}).append(
								$('<p>').html('By clicking <i>Submit</i>, you will...')
							).append(
								$('<div>').css({
									'display': 'flex',
									'text-align': 'justify'
								}).append(
									$('<div>').css({
										'flex-grow': '2',
										'padding': '0 1em'
									})
									.append(
										$('<p>').text('Single mode:')
									).append(
										$('<ul>').append(
											$('<li>').html(
												'Prepend {{<a href="/wiki/Template:Rfd" target="_blank">rfd</a>}} ' +
												'(noincluded by default) to the page if it\'s valid. Else, you will be warned.'
											)
										).append(
											$('<li>').html(
												'Create a subsection at <a href="/wiki/Meta:Requests_for_deletion" target="_blank">WM:RfD</a> ' +
												'using the page\'s name as title.'
											)
										).append(
											$('<li>').html(
												'Notify all users chosen (only appear after clicking the "Get contributors" button; ' +
												'no IPs will be included). If no one are chosen, you will not notify anyone.'
											)
										)
									)
								).append(
									$('<div>').css({
										'flex-grow': '2',
										'padding': '0 1em'
									})
									.append(
										$('<p>').text('Multiple mode:')
									).append(
										$('<ul>').append(
											$('<li>').html(
												'Prepend {{<a href="/wiki/Template:Rfd" target="_blank">rfd</a>}} ' +
												'(noincluded by default) to all valid pages.'
											)
										).append(
											$('<li>').html(
												'Create a subsection at <a href="/wiki/Meta:Requests_for_deletion" target="_blank">WM:RfD</a> ' +
												'with the title you chose and the list of valid pages.'
											)
										).append(
											$('<li>').html(
												'Notify all users chosen for each page (only appear after clicking the "Get contributors" button; ' +
												'no IPs will be included). This means that you may notify an user more than once.'
											)
										)
									)
								)
							).append(
								$('<p>').css('text-align', 'justify').html(
									'<i>Get contributors</i> will create one or multiple areas of checkboxes. To avoid ' +
									'<a href="/wiki/c:File:Server-kitty.jpg" target="_blank">killing server kittens</a>, ' +
									'you can only query for no more than 50 pages, and up to 500 users (5000 with admins) each page. ' +
									'If it eventually turns out that Meta <em>do</em> have some pages with quite a history that ' +
									'needs deletion, just <a href="/wiki/User talk:NguoiDungKhongDinhDanh" target="_blank">tell me</a> ' +
									'and I\'ll tweak the code.'
								)
							)
						);
						$('#rfdhelper').animate({
							scrollTop: $('#rfdhelper-help').slideToggle().offset().top
						}, 800);
					}
				},
				{
					text: 'Get contributors',
					click: function() {
						for (let i of [0, 1]) {
							$('#rfdhelper-multi-button-toggle').click();
						}
						$('#rfdhelper').parent().find('button').not(this).each(function() {
							$(this).button('disable');
						});
						$('#rfdhelper-contributors').empty().append(loader);
						
						var p = [];
						if (!$('#rfdhelper-single').is(':visible')) {
							if (!$('#rfdhelper-multi-pagenames-textarea').length) {
								$('#rfdhelper-multi-pagenames .rfdhelper-multi-pagenames').each(function() {
									p.push($(this).val());
								});
							} else {
								p = $('#rfdhelper-multi-pagenames-textarea').val().split('\n');
							}
						} else {
							p.push($('#rfdhelper-single-pagename').val());
						}
						
						if (!p.length) {
							$('#rfdhelper-loader').remove();
							$('#rfdhelper').parent().find('button').not(this).button('enable');
							return;
						}
						
						call({
							action: 'query',
							prop: 'contributors',
							titles: p.join('|'),
							pcexcludegroup: 'bot',
							pclimit: 'max',
							format: 'json',
							formatversion: 2
						}, function(response) {
							console.log(response);
							var pages = response.query.pages;
							var htmlescape = function(str) {
								return $('<span>').attr('title', str).prop('outerHTML').match(/"(.+?)"/)[1];
							};
							for (let i of pages) {
								if (i.missing) continue;
								$('#rfdhelper-contributors').append(
									$('<div>').attr('class', 'rfdhelper-contributors-page').append(
										$('<span>').css('font-weight', 'bold').text(i.title + ':'),
										$('<ul>').attr('name', htmlescape(i.title)).css({
											'display': 'grid',
											'grid-template-columns': 'repeat(auto-fit, minmax(33%, 1fr))',
											'margin-bottom': '1px solid gray'
										})
									)
								);
								if (i.contributors instanceof Array) {
									for (let j of i.contributors) {
										$('#rfdhelper-contributors').find('ul[name="' + htmlescape(i.title) + '"]').append(
											$('<li>').append(
												$('<label>').attr('title', j.name).css({
													'display': 'inline-flex',
													'align-items': 'center'
												})
												.append(
													$('<input>').attr({
														'type': 'checkbox',
														'name': i.title,
														'data-user': j.name
													})
												).append(
													$('<span>')
													.attr({
														'class': 'rfdhelper-contributors-label'
													})
													.css({
														'margin': '0 3px'
													}).text(j.name)
												)
											)
										);
									}
								} else {
									$('#rfdhelper-contributors').find('ul[name="' + i.title + '"]').append(
										$('<span>').text('None found.')
									);
								}
							}
							
							$('#rfdhelper-loader').remove();
							$('#rfdhelper').parent().find('button').not(this).button('enable');
						}, function(error, response) {
							try {
								$('#rfdhelper-contributors').append(
									$('<p>').attr('id', 'rfdhelper-contributors-error').append(
										$('<strong>').attr('class', 'error').css({
											'font-size': 'larger',
											'color': '#DD3333'
										}).text('API error: ' + response.error.info)
									)
								);
								window.setTimeout(function() {
									$('#rfdhelper-contributors-error').fadeOut({
										complete: function() {
											$(this).remove();
										}
									});
								}, 5000);
								
								$('#rfdhelper-loader').remove();
								$('#rfdhelper').parent().find('button').not(this).each(function() {
									$(this).button('enable');
								});
							} catch (e) {
								console.warn(error, response);
							}
						});
					}
				},
				{
					text: 'Switch mode',
					click: function() {
						$('#rfdhelper-single, #rfdhelper-multi').toggle();
						$('#rfdhelper-contributors').empty();
						if (!$('#rfdhelper-single').is(':visible')) {
							$('#rfdhelper').dialog('option', 'title', 'Nominating pages for deletion');
						} else {
							$('#rfdhelper').dialog('option', 'title', 'Nominating ' + p + ' for deletion');
						}
					}
				},
				{
					text: 'Submit',
					click: function() {
						$('#rfdhelper').parent().find('button').not(this).button('disable');
						var p = [];
						var s = '';
						var ss = '';
						var r = '';
						var c = $('#rfdhelper-contributors').clone();
						
						if (!$('#rfdhelper-single').is(':visible')) {
							$('#rfdhelper-multi-button-toggle').click();
							if ($('#rfdhelper-multi-pagenames-textarea').length) $('#rfdhelper-multi-button-toggle').click();
							$('.rfdhelper-multi-pagenames').each(function() {
								p.push($(this).val());
							});
							s = $('#rfdhelper-multi-subsectiontitle').val();
							ss = $('#rfdhelper-multi-sectiontitle').val();
							r = $('#rfdhelper-multi-rationale').val().trim();
						} else {
							p.push($('#rfdhelper-single-pagename').val());
							s = $('#rfdhelper-single-subsectiontitle').val();
							ss = $('#rfdhelper-single-sectiontitle').val();
							r = $('#rfdhelper-single-rationale').val().trim();
						}
						r = r.replace(/\s*~{3,5}$/, '').trim();
						
						if (p.length === 0) {
							alert('You are nominating 0 pages for deletion. Maybe something went wrong.');
							$('#rfdhelper').parent().find('button').button('enable');
							return;
						}
						
						$.when(function() {
							return void(0);
						}).then(function() {
							$('#rfdhelper').empty().append(
								$('<div>').attr('id', 'rfdhelper-submitting').css({
									'padding': '1em',
									'font-size': 'x-large'
								})
								.append(
									$('<p>').attr('id', 'rfdhelper-submitting-pages-wrapper').html(
										'Tagging <span id="rfdhelper-submitting-pages">0</span>/' + p.length + ' pages...'
									)
								)
							);
							(new mw.Api()).get({
								action: 'parse',
								title: 'Meta:Requests for deletion',
								summary: s,
								format: 'json',
								formatversion: 2
							}).done(function(res) {
								var ps = $($('<span>').html(res.parse.parsedsummary)[0]).text();
								p.forEach(function(e) {
									(new mw.Api()).postWithToken('csrf', {
										action: 'edit',
										title: e,
										summary: 'Adding RfD template' + advert,
										minor: true,
										nocreate: true,
										prependtext: '<noinclude>{{RFD|1=' + ps + '}}</noinclude>',
										format: 'json',
										formatversion: 2
									}, {
										async: false
									}).done(function(response) {
										$('#rfdhelper-submitting-pages').text(+$('#rfdhelper-submitting-pages').text() + 1);
										if (e === p[p.length - 1]) {
											$('#rfdhelper-submitting-pages-wrapper').html(
												'Tagged ' + $('#rfdhelper-submitting-pages').text() + '/' + p.length + ' pages.'
											);
										}
									}).fail(function(error, response) {
										console.warn(error, response.error.info);
										if (e === p[p.length - 1]) {
											$('#rfdhelper-submitting-pages-wrapper').html(
												'Tagged ' + $('#rfdhelper-submitting-pages').text() + '/' + p.length + ' pages.'
											);
										}
									});
								});
							}).fail(function(error, response) {
								console.warn(error, response.error.info);
								p.forEach(function(e) {
									(new mw.Api()).postWithToken('csrf', {
										action: 'edit',
										title: e,
										summary: 'Adding RfD template' + advert,
										minor: true,
										nocreate: true,
										appendtext: '<noinclude>{{RFD|{{delink|1=' + s + '}}}}</noinclude>',
										format: 'json',
										formatversion: 2
									}, {
										async: false
									}).done(function(response) {
										$('#rfdhelper-submitting-pages').text(+$('#rfdhelper-submitting-pages').text() + 1);
										if (e === p[p.length - 1]) {
											$('#rfdhelper-submitting-pages-wrapper').html(
												'Tagged ' + $('#rfdhelper-submitting-pages').text() + '/' + p.length + ' pages.'
											);
										}
									}).fail(function(error, response) {
										console.warn(error, response.error.info);
										if (e === p[p.length - 1]) {
											$('#rfdhelper-submitting-pages-wrapper').html(
												'Tagged ' + $('#rfdhelper-submitting-pages').text() + '/' + p.length + ' pages.'
											);
										}
									});
								});
							});
						}).then(function() {
							$('#rfdhelper-submitting').append(
								$('<p>').attr('id', 'rfdhelper-submitting-addsection').html(
									'Adding subsection to <a href="/wiki/Meta:Requests_for_deletion" target="_blank">WM:RfD</a>...'
								)
							);
							(new mw.Api()).get({
								action: 'parse',
								page: 'Meta:Requests for deletion',
								prop: ['sections', 'wikitext'],
								format: 'json',
								formatversion: 2
							}).done(function(res) {
								var sect = res.parse.sections;
								var index = 0;
								for (let i = 0; i < sect.length; i++) {
									if (parseInt(sect[i].level) === 2 && sect[i].line.match(new RegExp('^' + ss + '$', 'i'))) {
										index = i + 1;
										break;
									}
								}
								console.log(sect, index, ss);
								
								var text = ['\n\n=== ' + s + ' ==='];
								if (p.length !== 1) {
									text.push('* [[:' + p.join(']]\n* [[:') + ']]');
								}
								text.push(r + ' ~~~~');
								text = text.join('\n');
								
								(new mw.Api()).postWithToken('csrf', {
									action: 'edit',
									title: 'Meta:Requests for deletion',
									section: index,
									summary: 'Nominating ' + (p.length === 1 ? '[[:' + p[0] + ']]' : p.length + ' pages') + ' for deletion' + advert,
									nocreate: true,
									appendtext: text,
									format: 'json',
									formatversion: 2
								}, {
									async: false
								}).done(function(response) {
									$('#rfdhelper-submitting-addsection').html(
										'Added subsection to <a href="/wiki/Meta:Requests_for_deletion" target="_blank">WM:RfD</a>.'
									);
								}).fail(function(error, response) {
									console.warn(error, response.error.info);
									$('#rfdhelper-submitting-addsection').html(
										'Could not add subsection to <a href="/wiki/Meta:Requests_for_deletion" target="_blank">WM:RfD</a>. API error: ' +
										response.error.info
									);
								});
							}).fail(function(error, response) {
								console.warn(error, response.error.info);
								$('#rfdhelper-submitting-addsection').html(
									'Could not add subsection to <a href="/wiki/Meta:Requests_for_deletion" target="_blank">WM:RfD</a>. API error: ' +
									response.error.info
								);
							});
						}).then(function() {
							$('#rfdhelper-submitting').append(
								$('<p>').attr('id', 'rfdhelper-submitting-notify-wrapper').html(
									'Notifying <span id="rfdhelper-submitting-notify">0</span>/' +
									$('input[type="checkbox"]:checked', c).length + ' users...'
								)
							);
							$('input[type="checkbox"]:checked', c).each(function(index) {
								var user = $(this).attr('data-user');
								var page = $(this).closest('ul').attr('name');
								(new mw.Api()).postWithToken('csrf', {
									action: 'edit',
									title: 'User talk:' + user,
									summary: 'Sending RfD notice' + advert,
									nocreate: true,
									appendtext: '\n\n{{subst:' + 'RfD notice|1=' + page + '}} ~~~~',
									format: 'json',
									formatversion: 2
								}, {
									async: false
								}).done(function(response) {
									$('#rfdhelper-submitting-notify').text(+$('#rfdhelper-submitting-notify').text() + 1);
									if (index === $('input[type="checkbox"]:checked', c).length) {
										$('#rfdhelper-submitting-notify-wrapper').html(
											'Notified ' + $('#rfdhelper-submitting-notify').text() + '/' +
											$('input[type="checkbox"]:checked', c).length + ' users.'
										);
									}
								}).fail(function(error, response) {
									console.warn(error, response.error.info);
									if (error === 'missingtitle') {
										(new mw.Api()).postWithToken('csrf', {
											action: 'edit',
											title: 'User talk:' + user,
											summary: 'Sending RfD notice' + advert,
											nocreate: true,
											appendtext: '{{subst:' + 'RfD notice|1=' + page + '}}',
											format: 'json',
											formatversion: 2
										}, {
											async: false
										}).done(function(response) {
											$('#rfdhelper-submitting-notify').text(+$('#rfdhelper-submitting-notify').text() + 1);
											if (index === $('input[type="checkbox"]:checked', c).length) {
												$('#rfdhelper-submitting-notify-wrapper').html(
													'Notified ' + $('#rfdhelper-submitting-notify').text() + '/' +
													$('input[type="checkbox"]:checked', c).length + ' users.'
												);
											}
										}).fail(function(error, response) {
											console.warn(error, response.error.info);
											if (index === $('input[type="checkbox"]:checked', c).length) {
												$('#rfdhelper-submitting-notify-wrapper').html(
													'Notified ' + $('#rfdhelper-submitting-notify').text() + '/' +
													$('input[type="checkbox"]:checked', c).length + ' users.'
												);
											}
										});
									} else if (index === $('input[type="checkbox"]:checked', c).length) {
										$('#rfdhelper-submitting-notify-wrapper').html(
											'Notified ' + $('#rfdhelper-submitting-notify').text() + '/' +
											$('input[type="checkbox"]:checked', c).length + ' users.'
										);
									}
								});
							});
						});
					}
				}
			]
		});
		
		
		$('#rfdhelper-single-pagename').each(function() {
			var ns, t;
			try {
				ns = mw.Title.newFromText($('#rfdhelper-single-pagename').val()).namespace;
			} catch (e) {
				ns = 0;
			}
			switch (ns) {
				case 6: case 7:
					t = 'files';
				break;
				case 10: case 11: case 828: case 829:
					t = 'templates';
				break;
				case 14: case 15:
					t = 'categories';
				break;
				default:
					t = 'pages';
				break;
			}
			if (mw.config.get('wgIsRedirect')) t = 'redirects';
			
			$('#rfdhelper-single-sectiontitle, #rfdhelper-multi-sectiontitle').find('option[value="' + t + '"]').prop('selected', true);
		});
		$('#rfdhelper-single-pagename').on('input keydown keyup focusout', function() {
			$('#rfdhelper-single-subsectiontitle').val('[[:' + $('#rfdhelper-single-pagename').val() + ']]');
			$('#rfdhelper').dialog('option', 'title', 'Nominating ' + $('#rfdhelper-single-pagename').val() + ' for deletion');
		});
		$('#rfdhelper-single-pagename').focusout(function() {
			var $p = $('#rfdhelper-single-pagename');
			var p;
			try {
				p = mw.Title.newFromText($p.val()).toText();
			} catch (e) {
				p = $p.val().replace(/[\t_]+/g, ' ').trim();
				$p[0].setCustomValidity('Warning: Invalid title.');
				$p[0].reportValidity();
			}
			$p.val(p);
			$p.trigger('input');
		});
		$('#rfdhelper-multi-pagenames').on('click', '.rfdhelper-multi-button-remove', function() {
			$(this).parent('.rfdhelper-multi-pagenames-line').remove();
			if (!$('#rfdhelper-multi-pagenames').children().length) $('#rfdhelper-multi-button-add').click();
		});
		$('#rfdhelper-multi-button-add').click(function() {
			$('#rfdhelper-multi-pagenames').append(
				$('<div>')
				.attr('class', 'rfdhelper-multi-pagenames-line')
				.css({
					'display': 'flex',
					'align-content': 'stretch'
				})
				.append(
					$('<input>')
					.attr({
						type: 'text',
						class: 'rfdhelper-multi-pagenames'
					})
					.css({
						'align-self': 'center',
						'flex-grow': '4',
						'margin': '0.3em 0',
						'padding': '0.3em'
					})
				).append(
					$('<button>')
					.attr('class', 'rfdhelper-multi-button-remove')
					.text('Remove')
					.button()
				)
			);
		});
		$('#rfdhelper-multi-button-toggle').click(function() {
			$('#rfdhelper-multi-button-add').toggle();
			var c = [];
			if (!$('#rfdhelper-multi-pagenames-textarea').length) {
				$('.rfdhelper-multi-pagenames').each(function() {
					try {
						c.push(mw.Title.newFromText($(this).val()).toText());
					} catch (e) {
						
					}
				});
				
				$('#rfdhelper-multi-pagenames').html(
					$('<textarea>')
					.attr({
						id: 'rfdhelper-multi-pagenames-textarea'
					})
					.css({
						'margin': '0.3em 0',
						'padding': '0.5em',
						'resize': 'vertical',
						'width': 'auto',
						'min-height': '7.5em'
					})
					.val(c.join('\n'))
				);
			} else {
				$('#rfdhelper-multi-pagenames-textarea').val($('#rfdhelper-multi-pagenames-textarea').val().replace(/\n{2,}/, '\n'));
				c = $('#rfdhelper-multi-pagenames-textarea').val().split('\n').map(function(e) {
					try {
						return mw.Title.newFromText(e).toText();
					} catch (e) {
						return '';
					}
				});
				c = c.filter(function(e) {
					return e !== '';
				});
				c.push('');
				
				$('#rfdhelper-multi-pagenames').empty();
				
				c.forEach(function(e, i) {
					if ((i < c.length - 1) || (i === c.length - 1 && $('#rfdhelper-multi-pagenames').children().length === 0)) {
						$('#rfdhelper-multi-pagenames').append(
							$('<div>')
							.attr('class', 'rfdhelper-multi-pagenames-line')
							.css({
								'display': 'flex',
								'align-content': 'stretch'
							})
							.append(
								$('<input>')
								.attr({
									type: 'text',
									class: 'rfdhelper-multi-pagenames'
								})
								.css({
									'align-self': 'center',
									'flex-grow': '4',
									'margin': '0.3em 0',
									'padding': '0.3em'
								})
								.val(e)
							).append(
								$('<button>')
								.attr('class', 'rfdhelper-multi-button-remove')
								.text('Remove')
								.button()
							)
						);
					}
				});
			}
		});
		$('#rfdhelper-multi-pagenames').on('keydown', '.rfdhelper-multi-pagenames', function(e) {
			if (e.which === 13) {
				if ($(this).is('.rfdhelper-multi-pagenames:last')) {
					$('#rfdhelper-multi-button-add').click();
					$('.rfdhelper-multi-pagenames:last').select();
				} else {
					$(this).parent().next().children('.rfdhelper-multi-pagenames').select();
				}
			}
		});
		$('#rfdhelper-multi-button-autotitle').click(function() {
			for (let i of [0, 1]) {
				$('#rfdhelper-multi-button-toggle').click();
			}
			if ($('.rfdhelper-multi-pagenames').length == 1) {
				if ($('.rfdhelper-multi-pagenames').first().val()) {
					$('#rfdhelper-multi-subsectiontitle').val(
						'[[:' + $('.rfdhelper-multi-pagenames').first().val() + ']]'
					);
				} else {
					alert('Nothing to work. Aborting.');
				}
				return;
			}
			var o = {};
			if (!$('#rfdhelper-multi-pagenames-textarea').length) {
				o.t = $('.rfdhelper-multi-pagenames').first().val();
				o.n = $('.rfdhelper-multi-pagenames').length - 1;
			} else {
				o.t = $('#rfdhelper-multi-pagenames-textarea').val().split('\n')[0];
				o.n = $('#rfdhelper-multi-pagenames-textarea').val().split('\n').length - 1;
			}
			if (!o.t) {
				alert('Nothing to work. Aborting.');
			} else {
				$('#rfdhelper-multi-subsectiontitle').val(
					'[[:' + o.t + ']]' + (o.n > 0 ? ' and ' + o.n + ' other' + (o.n === 1 ? '' : 's') : '')
				);
			}
		});
	});
});

// </nowiki>