User:Chaotic Enby/Unblock wizard.js: Difference between revisions

From Test Wiki
Jump to navigation Jump to search
Content deleted Content added
figuring out what happened
yeah
 
(4 intermediate revisions by the same user not shown)
Line 15: Line 15:
/* globals mw, $, OO */
/* globals mw, $, OO */
/* <nowiki> */
/* <nowiki> */

console.log("a");


(async function () {
(async function () {

console.log("a");


var wizard = {}, ui = {}, block = {};
var wizard = {}, ui = {}, block = {};
Line 33: Line 29:
var demoMode = !!mw.util.getParamValue("demoMode");
var demoMode = !!mw.util.getParamValue("demoMode");
var usernameBlock = mw.util.getParamValue("usernameBlock");
var usernameBlock = mw.util.getParamValue("usernameBlock");
console.log("console.log");

console.log("b");

await new mw.Api().loadMessagesIfMissing(['wikimedia-copyrightwarning', 'copyrightwarning']);
await new mw.Api().loadMessagesIfMissing(['wikimedia-copyrightwarning', 'copyrightwarning']);
console.log("awawawait");

console.log("c");
// TODO: move to a separate JSON subpage, would be feasible once [[phab:T198758]] is resolved
// TODO: move to a separate JSON subpage, would be feasible once [[phab:T198758]] is resolved
var messages = {
var messages = {
Line 79: Line 72:
"copyright-notice": `<small>${mw.message('wikimedia-copyrightwarning').plain()}</small>`,
"copyright-notice": `<small>${mw.message('wikimedia-copyrightwarning').plain()}</small>`,
};
};
console.log("aaaaa");
var messagesCache = {};
var messagesCache = {};


Line 98: Line 92:
var emptyFieldsWarned = false;
var emptyFieldsWarned = false;
var mainPosition = -1;
var mainPosition = -1;

console.log("yeah");


async function parseAndCacheMsg(key, ...messageArgs) {
async function parseAndCacheMsg(key, ...messageArgs) {
Line 112: Line 108:


function init() {
function init() {
console.log("init");
for (var key in messages) {
for (var key in messages) {
mw.messages.set('ubw-' + key, messages[key]);
mw.messages.set('ubw-' + key, messages[key]);
Line 141: Line 138:
"uiprop": "blockinfo"
"uiprop": "blockinfo"
}).then( setBlockData ).then( async function ( block ) {
}).then( setBlockData ).then( async function ( block ) {
console.log("init?");
blockType = mw.config.get('wgPageName').split('/');
blockType = mw.config.get('wgPageName').split('/');
if (blockType.includes("Demo")) {
if (blockType.includes("Demo")) {
Line 190: Line 188:
'#catlinks { display: none } '
'#catlinks { display: none } '
);
);
console.log("???");
constructUI();
constructUI();
});
});
Line 666: Line 664:
}
}


console.log("await $$$");

await $.when(
await $.when(
$.ready,
$.ready,
Line 674: Line 672:
])
])
);
);
console.log("im rich now");


if (!(mw.config.get('wgPageName').includes('Wikipedia:Unblock_wizard/')) ||
if ((!(mw.config.get('wgPageName').includes('Wikipedia:Unblock_wizard/')) && !(mw.config.get('wgPageName').includes('Chaotic_Enby/'))) ||
mw.config.get('wgAction') !== 'view') {
mw.config.get('wgAction') !== 'view') {
return;
return;
}
}
console.log("innit");
init();
init();



Latest revision as of 17:21, 23 July 2025

/**
 * MediaWiki:Unblock-wizard.js
 *
 * JavaScript used for submitting unblock requests.
 * Used on [[Wikipedia:Unblock wizard]].
 * Loaded via [[mw:Snippets/Load JS and CSS by URL]].
 * 
 * Edits can be proposed via [[Wikipedia talk:Unblock wizard]].
 *
 * Author: [[User:Chaotic Enby]] (derived from a script by [[User:SD0001]])
 * Licence: MIT (dual-licensed with CC-BY-SA 4.0 and GFDL 1.2)
 */

/* jshint maxerr: 999 */
/* globals mw, $, OO */
/* <nowiki> */

(async function () {

var wizard = {}, ui = {}, block = {};
window.wizard = wizard;
wizard.ui = ui;

var config = {
	debounceDelay: 500,
	redirectionDelay: 1000,
};

var demoMode = !!mw.util.getParamValue("demoMode");
var usernameBlock = mw.util.getParamValue("usernameBlock");
console.log("console.log");
await new mw.Api().loadMessagesIfMissing(['wikimedia-copyrightwarning', 'copyrightwarning']);
console.log("awawawait");
// TODO: move to a separate JSON subpage, would be feasible once [[phab:T198758]] is resolved
var messages = {
	"document-title": "Wikipedia Unblock Wizard",
	"page-title": "Wikipedia Unblock Wizard",
	"explain-label": "Can you explain, in your own words, what you were blocked for?",
	"future-label": "If unblocked, what edits would you make and what (if applicable) would you do differently?",
	"other-label": "Is there anything else that may be helpful to your unblock request?",
	"accounts-label": "Please list all accounts you have used besides this one.",
	"so-label": "Have you taken the standard offer?",
	"explain-promo-label": "Can you explain, in your own words, why your edits were promotional?",
	"coi-label": "What is your relationship with the subjects you have been editing about?",
	"future-promo-label": "If you are unblocked, what topic areas will you edit in?",
	"username-label": (usernameBlock == "required" ? "What new username do you want to pick?" : "If your username was an issue, what new username do you want to pick?"),
	"standalone-username-label": "What new username do you want to pick?",
	"additional-reason-label": "Additional reason to be unblocked",
	"clarification-label": "Is there anything specific you want to ask about your block?",
	"submit-label": "Submit",
	"utrs-necessary": "It is necessary to appeal your block via UTRS. This is because your talk page access is disabled. [[Wikipedia:UTRS|Learn more about UTRS]]]",
	"utrs-necessary-confirm": "It is necessary to appeal your block via UTRS. This is because your talk page access is disabled. Select \"Confirm\" to learn more about UTRS.",
	"footer-text": "<small>If you are not sure about what to enter in a field, you can skip it. If you need help, you can ask on <b>[[Special:MyTalk|your talkpage]]</b> with <b>{{[[Template:Help me|Help me]]}}</b> or get live help via <b>[[WP:IRCHELP|IRC]]</b>.<br>Facing some issues in using this form? <b>Report it in {{irc|wikipedia-en-unblock}} on [[WP:IRC|IRC]], in <span style=\"font-family:monospace;\">#technical</span> on [[Wikipedia:Discord|Discord]], or through an issue/pull request on [https://github.com/L235/unblock-wizard GitHub]</b>.</small>",
	"submitting-as": "Submitting as User:$1",
	"validation-notitle": "User not found",
	"validation-invalidtitle": "User page does not exist.",
	"validation-missingtitle": "User page does not exist.",
	"status-processing": "Processing ...",
	"status-saving": "Saving talk page ...",
	"status-blank": "One or several required forms are missing.",
	"editsummary-main": "Submitting using [[Wikipedia:Unblock wizard]]",
	"status-redirecting": "Submission succeeded. Redirecting you to your talk page ...",
	"status-redirecting-utrs": "Redirecting you to UTRS ...",
	"status-not-blocked": "You are not currently blocked.",
	"status-not-blocked-confirm": "You are not currently blocked. Select \"OK\" to activate demo mode, which will allow you to check out the workflow without posting a block request.",
	"status-error": "Due to an error, your unblock request could not be parsed. You can try to submit an unblock request manually by {{#if:$2|[$2 clicking this link] or}} pasting the following on [[Special:MyTalk|your talk page]]:<br /><code>$1</code><br />If you are having difficulties, please [[Wikipedia:UTRS|make a request through UTRS]] and inform them of the issues you are encountering.",
	"captcha-label": "Please enter the letters appearing in the box below",
	"captcha-placeholder": "Enter the letters here",
	"captcha-helptip": "CAPTCHA security check. Click \"Submit\" again when done.",
	"error-saving-main": "An error occurred ($1). Please try again or ask for help on your talk page.",
	"error-main": "An error occurred ($1). Please try again or ask for help on your talk page.",
	"copyright-notice": `<small>${mw.message('wikimedia-copyrightwarning').plain()}</small>`,
};
console.log("aaaaa");
var messagesCache = {};

// var infoLevels = {
// 	"process": ["0/01", "OOjs_UI_icon_ellipsis-progressive.svg"],
// 	"notice": ["4/4b", "OOjs_UI_icon_information-yellow.svg"],
// 	"success": ["8/86", "OOjs_UI_icon_speechBubbleAdd-ltr-constructive.svg"],
// 	"redirect": ["2/23", "OOjs_UI_icon_articleRedirect-ltr-progressive.svg"],
// 	"warning": ["4/4b", "OOjs_UI_icon_information-yellow.svg"],
// 	"error": ["4/4e", "OOjs_UI_icon_error-destructive.svg"],
// };

var questionLabels = [];
var questionFields = {'explain': 0, 'future': 0, 'other': 0, 'accounts': 0, 'so': 2, 'explain-promo': 0, 'coi': 0, 'future-promo': 0, 'username': 1, 'clarification': 0, 'standalone-username': 1, 'additional-reason': 0};
var required = {'explain': true, 'future': true, 'other': false, 'accounts': true, 'so': true, 'explain-promo': true, 'coi': true, 'future-promo': true, 'username': (usernameBlock == "required"), 'additional-reason': false, 'clarification': false, 'standalone-username': true};

var blockType = '';
var emptyFields = false;
var emptyFieldsWarned = false;
var mainPosition = -1;

console.log("yeah");

async function parseAndCacheMsg(key, ...messageArgs) {
	if (messagesCache[key] && [...messageArgs].length == 0) {
		return messagesCache[key];
	}
	return await new mw.Api().parse("<div>" + mw.message('ubw-' + key, ...messageArgs).plain() + "</div>").then(function (parsedMsg) {
		if ([...messageArgs].length == 0) {
			messagesCache[key] = $(parsedMsg).find("div").eq(0).html();
		}
		return $(parsedMsg).find("div").eq(0).html();
	});
}

function init() {
	console.log("init");
	for (var key in messages) {
		mw.messages.set('ubw-' + key, messages[key]);
	}

	for (var key in messages) {
		parseAndCacheMsg(key);
	}
	var apiOptions = {
		parameters: {
			format: 'json',
			formatversion: '2'
		},
		ajax: {
			headers: {
				'Api-User-Agent': 'w:en:MediaWiki:Unblock-wizard.js'
			}
		}
	};

	// Two different API objects so that aborts on the lookupApi don't stop the final
	// evaluate process
	wizard.api = new mw.Api(apiOptions);
	wizard.lookupApi = new mw.Api(apiOptions);
	
	wizard.lookupApi.get({
		"action": "query",
		"meta": "userinfo",
		"uiprop": "blockinfo"
	}).then( setBlockData ).then( async function ( block ) {
		console.log("init?");
		blockType = mw.config.get('wgPageName').split('/');
		if (blockType.includes("Demo")) {
			demoMode = true;
		}
		console.log(blockType)
		blockType = blockType[blockType.length - 1];
		
		switch (blockType) {
			case "Sockpuppet":
				questionLabels = ['accounts', 'so', 'other'];
				break;
			case "Promo":
				questionLabels = ['explain-promo', 'coi', 'future-promo', 'other'];
				break;
			case "Autoblock":
				questionLabels = [];
				break;
			case "IP_hardblock":
				questionLabels = [];
				break;
			case "Other":
				questionLabels = ['explain', 'future', 'other'];
				break;
			case "Clarification":
				questionLabels = ['clarification'];
				break;
			case "Username":
				questionLabels = ['standalone-username', 'additional-reason'];
				break;
			default:
				questionLabels = [];
		}
		
		if(usernameBlock && blockType != "Username" && blockType != "Clarification" && blockType != "IP_hardblock" && blockType != "Autoblock"  && blockType != "IP") {
			questionLabels = ['username'].concat(questionLabels);
		}
	
		document.title = await msg('document-title');
		$('#firstHeading').text(await msg('page-title'));
		
		mw.util.addCSS(
			// CSS adjustments for vector-2022: hide prominent page controls which are
			// irrelevant and confusing while using the wizard
			'.vector-page-toolbar { display: none } ' +
			'.vector-page-titlebar #p-lang-btn { display: none } ' + 
			
			// Hide categories as well, prevents accidental HotCat usage
			'#catlinks { display: none } '
		);
		console.log("???");
		constructUI();
	});
}

async function setBlockData(json) {
	var userinfo = json.query.userinfo;
	var errors = errorsFromPageData(userinfo);
	block.target = userinfo.name;
	if (errors.length) {
		return block;
	}
	if("blockid" in userinfo){
		block.id = userinfo.blockid;
		block.by = userinfo.blockedby;
		block.reason = userinfo.blockreason;
		block.notalk = userinfo.blockowntalk;
	}
	return block;
}

async function constructUI() {
	ui.itemsLayout = [];
	ui.itemsInput = [];
	
	var copyrightEligible = false;
	
	for(var label of questionLabels){
		switch(questionFields[label]) {
			case 0:
				ui.itemsInput.push(new OO.ui.MultilineTextInputWidget({
						// placeholder: await msg(label + '-placeholder'),
						multiline: true,
						autosize: true,
					}));
				copyrightEligible = true;
				break;
			case 1:
				ui.itemsInput.push(new OO.ui.TextInputWidget({
						// placeholder: await msg(label + '-placeholder'),
						maxLength: 85,
					}));
				copyrightEligible = true;
				break;
			case 2:
				ui.itemsInput.push(new OO.ui.RadioSelectInputWidget({
						align: 'inline',
					}));
				ui.itemsInput[ui.itemsInput.length - 1].setOptions([{label:"Yes", data:"Yes."}, {label:"No", data:"No."}]);
				break;
			default:
				break;
		}
		ui.itemsLayout.push(new OO.ui.FieldLayout(ui.itemsInput[ui.itemsInput.length - 1], {
				label: await msg(label + '-label') + (required[label] ? " (*)" : ""),
				align: 'top',
				// help: await msg(label + '-helptip'),
				helpInline: true
			}));
	}
	
	ui.itemsLayout.push(ui.submitLayout = new OO.ui.FieldLayout(ui.submitButton = new OO.ui.ButtonWidget({
		label: await msg('submit-label'),
		flags: [ 'progressive', 'primary' ],
	})));
	
	if(copyrightEligible){
		ui.itemsLayout.push(new OO.ui.FieldLayout(new OO.ui.LabelWidget({
			label: $('<div>')
				.append(linkify(await msgParsed('copyright-notice')))
		}), {
			align: 'top'
		}));
	}

	ui.fieldset = new OO.ui.FieldsetLayout({
		classes: [ 'container' ],
		items: ui.itemsLayout
	});

	ui.footerLayout = new OO.ui.FieldLayout(new OO.ui.LabelWidget({
		label: $('<div>')
			.append(linkify(await msgParsed('footer-text')))
	}), {
		align: 'top'
	});

	var asUser = mw.util.getParamValue('username');
	if (asUser && asUser !== block.target) {
		ui.fieldset.addItems([
			new OO.ui.FieldLayout(new OO.ui.MessageWidget({
				type: 'notice',
				inline: true,
				label: await msg('submitting-as', asUser)
			}))
		], /* position */ 5); // just before submit button
	}

	// Attach
	$('#unblock-wizard-container').empty().append(ui.fieldset.$element, ui.footerLayout.$element);


	initLookup();

	if (blockType != "IP" && !("id" in block) && !demoMode) {
		setMainStatus('warning', await msgParsed('status-not-blocked'));
		demoMode = confirm(await msg('status-not-blocked-confirm'));
		console.log(demoMode)
	}

	if (block.notalk) {
		ui.submitButton.setDisabled(true);
		setMainStatus('error', await msgParsed('utrs-necessary'));
		if (confirm(await msg("utrs-necessary-confirm"))) {
			location.href = mw.config.get("wgArticlePath").replace("$1", "Wikipedia:UTRS");
		}
	} else {
		ui.submitButton.on('click', handleSubmit);
	}

	// The default font size in monobook and modern are too small at 10px
	mw.util.addCSS('.skin-modern .projectTagOverlay, .skin-monobook .projectTagOverlay { font-size: 130%; }');

	wizard.beforeUnload = function (e) {
		var changedContent = false;
		for (var [i, label] of questionLabels.entries()) {
			if (ui.itemsInput[i].getValue() != "" && questionFields[label] != 2) {
				changedContent = true;
			}
			if (ui.itemsInput[i].getValue() != "Yes." && questionFields[label] == 2) {
				changedContent = true;
			}
		}
		if(changedContent){
			e.preventDefault();
		}
		e.returnValue = '';
		return '';
	};
	$(window).on('beforeunload', wizard.beforeUnload);
}

function initLookup() {
	wizard.lookupApi.abort(); // abort older API requests

	var userTalk = "User talk:" + block.target;

	// re-initialize
	wizard.pagetext = null;

	wizard.lookupApi.get({
		"action": "query",
		"prop": "revisions|description|info",
		"titles": userTalk,
		"rvprop": "content",
		"rvslots": "main"
	}).then(setPrefillsFromPageData);
}

function setPrefillsFromPageData(json) {
	var page = json.query.pages[0];
	var preNormalizedTitle = json.query.normalized && json.query.normalized[0] &&
		json.query.normalized[0].from;
	var errors = errorsFromPageData(page);
	if (errors.length) {
		return;
	}

	wizard.pagetext = page.revisions[0].slots.main.content;
}

/**
 * @param {Object} page - from query API response
 * @returns {string[]}
 */
async function errorsFromPageData(page) {
	if (!page || page.invalid) {
		return [await msg('validation-invalidtitle')];
	}
	if (page.missing) {
		return [await msg('validation-missingtitle')];
	}
	return [];
}

/**
 * @param {string} type
 * @param {string} message
 */
function setMainStatus(type, message) {
	if (mainPosition == -1) {
		mainPosition = ui.fieldset.items.length;
		ui.fieldset.addItems([
			ui.mainLabel = new OO.ui.MessageWidget( {
				align: 'top',
				type: type,
				label: $("<span/>").append(linkify(message))
			})
		]);
	} else {
		ui.mainLabel.setType(type);
		ui.mainLabel.setLabel($('<span/>').append(linkify(message)));
	}
}

async function handleSubmit() {
	if (ui.submitButton.isDisabled()) {
		return;
	}
	setMainStatus('', await msgParsed('status-processing'));
	ui.submitButton.setDisabled(true);
	ui.mainLabel.scrollElementIntoView();
	
	var url = prepareUserTalkPageLink();
	var text = prepareUserTalkText();
	for(var [i, label] of questionLabels.entries()){
		if(required[label] && !ui.itemsInput[i].getValue()){
			emptyFields = true;
		}
	}
	if (emptyFields && !emptyFieldsWarned) {
		setMainStatus('warning', await msgParsed('status-blank'));
		emptyFieldsWarned = true;
		ui.submitButton.setDisabled(false);
	} else {
		var userTalk = "User talk:" + block.target;
		if (!block.target) { // empty
			ui.fieldset.removeItems([ui.mainLabel]);
			ui.submitButton.setDisabled(false);
			return; // really get the ip please
		}
	
		wizard.api.get({
			"action": "query",
			"prop": "revisions|description",
			"titles": userTalk,
			"rvprop": "content",
			"rvslots": "main",
		}).then(async function (json) {
			var apiPage = json.query.pages[0];
	
			var errors = errorsFromPageData(apiPage);
			if (errors.length) {
				// ui.fieldset.removeItems([ui.mainLabel]);
				ui.submitButton.setDisabled(false);
				setMainStatus('error', await msgParsed('status-error', text, url));
				return;
			}
	
			setMainStatus('', await msg('status-saving'));
			if (demoMode) {
				setMainStatus('success', 'Wikitext: <code style="display: block">' + text + '</code>\n\nPreload URL: <a href=\"' + url + '\" target=\"_blank\">' + url.replace("&", "&amp;").replace("<", "&lt;") + '</a>');
			} else {
				saveUserTalkPage(userTalk, apiPage.revisions[0].slots.main.content + text).then(async function () {
					setMainStatus('success', await msgParsed('status-redirecting'));
		
					$(window).off('beforeunload', wizard.beforeUnload);
					setTimeout(function () {
						location.href = mw.util.getUrl(userTalk);
					}, config.redirectionDelay);
				}, async function (code, err) {
					if (code === 'captcha') {
						ui.fieldset.removeItems([ui.mainLabel, ui.talkStatusLayout]);
						ui.captchaLayout.scrollElementIntoView();
					} else {
						setMainStatus('error', await msgParsed('status-error', text, url));
					}
					ui.submitButton.setDisabled(false);
				});
			}
		}).catch(async function (code, err) {
			setMainStatus('error', await msgParsed('status-error', text, url));
			ui.submitButton.setDisabled(false);
		});
	}
}

async function saveUserTalkPage(title, text) {

	// TODO: handle edit conflict
	var editParams = {
		"action": "edit",
		"title": title,
		"text": text,
		"summary": await msg('editsummary-main')
	};
	if (ui.captchaLayout && ui.captchaLayout.isElementAttached()) {
		editParams.captchaid = wizard.captchaid;
		editParams.captchaword = ui.captchaInput.getValue();
		ui.fieldset.removeItems([ui.captchaLayout]);
	}
	return wizard.api.postWithEditToken(editParams).then(async function (data) {
		if (!data.edit || data.edit.result !== 'Success') {
			if (data.edit && data.edit.captcha) {
				// Handle captcha for non-confirmed users

				var url = data.edit.captcha.url;
				wizard.captchaid = data.edit.captcha.id; // abuse of global?
				ui.fieldset.addItems([
					ui.captchaLayout = new OO.ui.FieldLayout(ui.captchaInput = new OO.ui.TextInputWidget({
						placeholder: await msg('captcha-placeholder'),
						required: true
					}), {
						warnings: [ new OO.ui.HtmlSnippet('<img src=' + url + '>') ],
						label: await msg('captcha-label'),
						align: 'top',
						help: await msg('captcha-helptip'),
						helpInline: true,
					}),
				], /* position */ 6); // just after submit button // TODO: fix number
				// TODO: submit when enter key is pressed in captcha field

				return $.Deferred().reject('captcha');

			} else {
				return $.Deferred().reject('unexpected-result');
			}
		}
	});
}

async function prepareUserTalkPageLink() {
	var url = new URL(location.origin + mw.config.get("wgArticlePath").replace("$1", "User_talk:" + mw.config.get("wgUserName")));
	url.searchParams.set("action", "edit");
	url.searchParams.set("section", "new");
	switch(blockType){
		case "Autoblock":
			if("id" in block){
				url.searchParams.set("editintro", `Template:Unblock-auto/editintro`);
				url.searchParams.set("preloadtitle", "Autoblock appeal");
				url.searchParams.set("preload", `Template:Unblock-auto/preload`);
				url.searchParams.set("preloadparams[0]", block.reason);
				url.searchParams.set("preloadparams[1]", block.by);
				url.searchParams.set("preloadparams[2]", block.id);
			}
			break;
		case "Clarification":
			url.searchParams.set("preload", `Help:Contents/helpmepreload2`);
			url.searchParams.set("preloadparams[0]", ui.itemsInput[0].getValue());
			url.searchParams.set("preloadparams[1]", "");
			break;
		case "Username":
			url.searchParams.set("editintro", `Template:Unblock-un/editintro`);
			url.searchParams.set("preloadtitle", "Unblock request for change in username");
			url.searchParams.set("preload", `Template:Unblock-un/preload`);
			url.searchParams.append("preloadparams[0]", ui.itemsInput[1] ? ui.itemsInput[1].getValue() : '');
			url.searchParams.append("preloadparams[1]", ui.itemsInput[0].getValue());
			break;
		default:
			url.searchParams.set("editintro", `Template:Unblock/editintro`);
			url.searchParams.set("preloadtitle", "Unblock request");
			url.searchParams.set("preload", `Template:Unblock/preload`);
			var reason = '';
			for(var [i, label] of questionLabels.entries()){
				if(required[label] || ui.itemsInput[i].getValue()) {
					if(label == "username") {
						url.searchParams.set("editintro", `Template:Unblock-un/editintro`);
						url.searchParams.set("preloadtitle", "Unblock request with change in username");
						url.searchParams.set("preload", `Template:Unblock-un/preload`);
						url.searchParams.append("preloadparams[1]", ui.itemsInput[i].getValue());
					} else {
						reason += "'''''" + await msg(label + '-label') + "'''''" + "{{pb}}" + ui.itemsInput[i].getValue() + "{{pb}}";
					}
				}
			}
			url.searchParams.append("preloadparams[0]", reason);
	}
	return url.toString();
}

/**
 * @param {Object} page - page information from the API
 * @returns {string} final talk page text to save
 */
async function prepareUserTalkText() {
	var unblock = '';
	
	// put unblock template
	switch(blockType){
		case "Autoblock":
			if("id" in block){
				unblock += '\n{{unblock-auto|2=\u003Cnowiki>' + block.reason + '\u003C/nowiki>|3=' + block.by + '|4=' + block.id + '}}\n';
			} else {
				unblock += '\n{{unblock-auto|2=REASON|3=THE BLOCKING ADMIN|4=BLOCK ID}}\n';
			}
			break;
		case "Clarification":
			if(ui.itemsInput[0].getValue()){
				unblock += '\n{{Help me}}\n' + ui.itemsInput[0].getValue() + '\n~~' + '~~';
			} else {
				unblock += '\n{{Help me}}\n' + 'I would like a more detailed explanation for my block.' + '\n~~' + '~~';
			}
			break;
		case "Username":
			unblock += `\n{{unblock-un|1=${ui.itemsInput[0].getValue()}|reason=${ui.itemsInput[1] ? ui.itemsInput[1].getValue() : ''}}} \n`;
			break;
		default:
			unblockStart = '\n{{unblock|reason=';
			
			for(var [i, label] of questionLabels.entries()){
				if(required[label] || ui.itemsInput[i].getValue()) {
					if(label == "username") {
						unblockStart = '\n{{unblock-un|1=' + ui.itemsInput[i].getValue() + '|reason=';
					} else {
						unblock += "'''''" + await msg(label + '-label') + "'''''" + "{{pb}}" + ui.itemsInput[i].getValue() + "{{pb}}";
					}
				}
			}
				
			unblock = unblockStart + "<small>The following request was written through the [[Wikipedia:Unblock wizard|unblock wizard]].</small>\n" + unblock + ' ~~' + '~~}}\n';
	}

	return unblock;
}

/**
 * Load a JSON page from the wiki.
 * Use API (instead of $.getJSON with action=raw) to take advantage of caching
 * @param {string} page
 * @returns {jQuery.Promise<Record<string, any>>}
 **/
function getJSONPage (page) {
	return wizard.api.get({
		action: 'query',
		titles: page,
		prop: 'revisions',
		rvprop: 'content',
		rvlimit: 1,
		rvslots: 'main',
		uselang: 'content',
		maxage: '3600', // 1 hour
		smaxage: '3600',
		formatversion: 2
	}).then(function (json) {
		var content = json.query.pages[0].revisions[0].slots.main.content;
		return JSON.parse(content);
	}).catch(function (code, err) {
		console.error(makeErrorMessage(code, err));
	});
}

/**
 * Expands wikilinks and external links into HTML.
 * Used instead of mw.await msg(...).parse() because we want links to open in a new tab,
 * and we don't want tags to be mangled.
 * @param {string} input
 * @returns {string}
 */
function linkify(input) {
	var $input = $("<span>" + input + "</span>");
	$input.find('a').attr('target', '_blank');
	return $input.html();
}

function msg(key, ...messageArgs) {
	return mw.message('ubw-' + key, ...messageArgs).plain();
}

async function msgParsed(key, ...messageArgs) {
	let parsedMsg = await parseAndCacheMsg(key, ...messageArgs);
	return parsedMsg;
}

function makeErrorMessage(code, err) {
	if (code === 'http') {
		return 'http: there is no internet connectivity';
	}
	return code + (err && err.error && err.error.info ? ': ' + err.error.info : '');
}

function debug() {
	Array.prototype.slice.call(arguments).forEach(function (arg) {
		console.log(arg);
	});
}

console.log("await $$$");
await $.when(
	$.ready,
	mw.loader.using([
		'mediawiki.util', 'mediawiki.api', 'mediawiki.Title',
		'mediawiki.widgets', 'oojs-ui-core', 'oojs-ui-widgets'
	])
);
console.log("im rich now");

if ((!(mw.config.get('wgPageName').includes('Wikipedia:Unblock_wizard/')) && !(mw.config.get('wgPageName').includes('Chaotic_Enby/'))) ||
	mw.config.get('wgAction') !== 'view') {
	return;
}
console.log("innit");
init();

})(); // File-level closure to protect functions from being exposed to the global scope or overwritten

/* </nowiki> */