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.
//Tks4Fish's mass blocking tool
//Adapted from [[:w:en:User:Timotheus_Canens/massblock.js]], who adapted it from [[User:Animum/massdelete.js]]

/* jshint esversion: 8, esnext:false */

async function doMassBlock() {
	document.getElementById("wpMassBlockSubmit").disabled = true;
	var users = document.getElementById("wpMassBlockUsers").value.split("\n");
	if(users.length == 0) return;
	
	var wpMassBlockSummaryTalk = document.getElementById("wpMassBlockSummaryTalk").value;
	var wpMassBlockSummaryUser = document.getElementById("wpMassBlockSummaryUser").value;
	var wpMassBlockReasons = document.getElementById("wpMassBlockReasons").value;
	var wpMassBlockMessage = document.getElementById("wpMassBlockMessage").value;
	var wpMassBlockReason = document.getElementById("wpMassBlockReason").value;
	var wpMassBlockExpiry = document.getElementById("wpMassBlockExpiry").value;
	var wpMassBlockTag = document.getElementById("wpMassBlockTag").value;
	
	var wpMassBlockAutoblock = document.getElementById("wpMassBlockAutoblock").checked;
	var wpMassBlockTalkpage = document.getElementById("wpMassBlockTalkpage").checked;
	var wpMassBlockAnononly = document.getElementById("wpMassBlockAnononly").checked;
	var wpMassBlockNocreate = document.getElementById("wpMassBlockNocreate").checked;
	var wpMassBlockReblock = document.getElementById("wpMassBlockReblock").checked;
	var wpMassBlockEmail = document.getElementById("wpMassBlockEmail").checked;
	
	var blocked = 0;
	var talkpageedited = 0;
	var userpageedited = 0;
	var failed = [];
	var error = [];
	
	for(i = 0; i < users.length; i++) {
		var user = users[i];
		if(user.length > 0) {
			let data = await new mw.Api().postWithToken("csrf", {
				"action": "block",
				"format": "json",
				"user": user,
				"reason": (wpMassBlockReasons == "other" ? wpMassBlockReason : wpMassBlockReasons + (wpMassBlockReason ? ": " + wpMassBlockReason : "")),
				"expiry": (wpMassBlockExpiry == "" ? "indefinite" : wpMassBlockExpiry),
				"anononly": (wpMassBlockAnononly ? true : false),
				"nocreate": (wpMassBlockNocreate ? true : false),
				"autoblock": (wpMassBlockAutoblock ? true : false),
				"noemail": (wpMassBlockEmail ? true : false),
				"allowusertalk": (wpMassBlockTalkpage ? false : true),
				"reblock": (wpMassBlockReblock ? true : false),
				"formatversion": "2"
			});
			if(data.block) { //If blocked, update the blocked count and the button.
				blocked++;
				// now edit user and user talk.
				if(wpMassBlockMessage != "") {
					let data = await new mw.Api().postWithToken("csrf", {
						"action": "edit",
						"format": "json",
						"watchlist": "nochange",
						"title": "User talk:" + user,
						"summary": wpMassBlockSummaryTalk,
						"appendtext": wpMassBlockMessage
					});
					if(data.edit) {
						talkpageedited++;
					}
					else { //If not edited, add the title to the "failed" array and a description of the error to the "error" array.
						failed.push("User talk:" + user);
						error.push(data.error.info);
					}
				}
				if(wpMassBlockTag != "") {
					let data = await new mw.Api().postWithToken("csrf", {
						"action": "edit",
						"format": "json",
						"watchlist": "nochange",
						"title": "User:" + user,
						"summary": wpMassBlockSummaryUser,
						"text": wpMassBlockTag
					});
					if(data.edit) {
						userpageedited ++;
					}
					else { //If not edited, add the title to the "failed" array and a description of the error to the "error" array.
						failed.push("User talk:" + user);
						error.push(data.error.info);
					}
				}
				document.getElementById("wpMassBlockSubmit").value = "(" + blocked + "/" + talkpageedited + "/" + userpageedited + ")";
			}
			else { //If not blocked, add the title to the "failed" array and a description of the error to the "error" array.
				failed.push("Special:Block/" + user);
				error.push(data.error.info);
			}
		}
		if(!users[i+1]) {
			document.getElementById("wpMassBlockSubmit").value = "(" + blocked + "/" + talkpageedited + "/" + userpageedited + ")";
			if(failed.length > 0) {
				var linkedList = "";
				
				for(x = 0; x < failed.length; x++) {
					linkedList += "<li><a href=\"" + wgScript + "?title=" + encodeURIComponent(failed[x]) + "\">" + failed[x] + "</a>: " + error[x] + "</li>"; //Links the titles in the "failed" array
				}
				document.getElementById("wpMassBlockFailedContainer").innerHTML += '<br /><b>Failed actions:</b><ul>' + linkedList + '</ul>';
			}
		}
	}
}

function massblockform() {
	var bodyContent = (mw.config.get("skin") == "cologneblue" ? "article" : "bodyContent");
	document.getElementsByTagName("h1")[0].textContent = "Tks4Fish's mass-blocking tool";
	document.title = "Tks4Fish's mass-blocking tool - Wikipedia, the free encyclopedia";
	document.getElementById(bodyContent).innerHTML = '<h3 id="siteSub">From Wikipedia, the free encyclopedia</h3><br /><br />'
		+ '<form id="wpMassBlock" name="wpMassBlock">'
		+ '<b>If you abuse this tool, it\'s <i>your</i> fault, not mine.</b>'
		+ '<div id="wpMassBlockFailedContainer"></div>'
		+ '<br /><br />'
			+ 'Users to block (one on each line, please):<br />'
				+ '<textarea tabindex="1" accesskey="," name="wpMassBlockUsers" id="wpMassBlockUsers" rows="10" cols="80"></textarea>'
			+ 'Talk page message, if any (leave blank to leave no message):<br />'
				+ '<textarea tabindex="2" accesskey="," name="wpMassBlockMessage" id="wpMassBlockMessage" rows="10" cols="80"></textarea>'
			+ 'Replace user page text with (leave blank for no change):<br />'
				+ '<textarea tabindex="3" accesskey="," name="wpMassBlockTag" id="wpMassBlockTag" rows="10" cols="80"></textarea>'
			+ '<br /><br /><table style="background-color:transparent">'
				+ '<tr><td>Common reasons:</td>'
					+ '<td><select id="wpMassBlockReasons">'
						+ '<optgroup label="Other reason">'
							+ '<option value="other">Other reason</option>'
						+ '</optgroup>'
						+ '<optgroup label="Common reasons">'
							+ '<option value="Vandalism">Vandalism</option>'
							+ '<option value="Vandalism-only account">Vandalism-only account</option>'
							+ '<option value="Violations of the Biographies of living persons policy">Violations of the Biographies of living persons policy</option>'
							+ '<option value="Using Wikipedia for spam or advertising purposes">Using Wikipedia for spam or advertising purposes</option>'
							+ '<option value="Spam / advertising-only account">Spam / advertising-only account</option>'
							+ '<option value="Creating attack, nonsense or other inappropriate pages">Creating attack, nonsense or other inappropriate pages</option>'
							+ '<option value="Creating copyright violations">Creating copyright violations</option>'
							+ '<option value="Abusing multiple accounts">Abusing multiple accounts</option>'
							+ '<option value="Block evasion">Block evasion</option>'
							+ '<option value="Personal attacks or harassment">Personal attacks or harassment</option>'
							+ '<option value="Edit warring">Edit warring</option>'
							+ '<option value="Violation of the three-revert rule">Violation of the three-revert rule</option>'
							+ '<option value="Disruptive editing">Disruptive editing</option>'
							+ '<option value="Long-term abuse">Long-term abuse</option>'
							+ '<option value="Making legal threats">Making legal threats</option>'
							+ '<option value="Arbitration enforcement">Arbitration enforcement</option>'
							+ '<option value="Deliberately triggering the Edit filter">Deliberately triggering the Edit filter</option>'
							+ '<option value="Revoking talk page access: inappropriate use of user talk page while blocked">Revoking talk page access: inappropriate use of user talk page while blocked</option>'
							+ '<option value="\{\{anonblock}}">\{\{anonblock}}</option>'
							+ '<option value="\{\{schoolblock}}">\{\{schoolblock}}</option>'
							+ '<option value="\{\{blocked proxy}}">\{\{blocked proxy}}</option>'
							+ '<option value="\{\{usernameblock}}">\{\{usernameblock}}</option>'
							+ '<option value="\{\{UsernameHardBlocked}}">\{\{UsernameHardBlocked}}</option>'
							+ '<option value="\{\{spamusernameblock}}">\{\{spamusernameblock}}</option>'
							+ '<option value="\{\{softerblock}}">\{\{softerblock}}</option>'
							+ '<option value="\{\{checkuserblock}}">\{\{checkuserblock}}</option>'
							+ '<option value="\{\{checkuserblock-account}}">\{\{checkuserblock-account}}</option>'
							+ '<option value="\{\{Tor}}">\{\{Tor}}</option>'
							+ '<option value="\{\{Vaublock}}">\{\{Vaublock}}</option>'
						+ '</optgroup>'
					+ '</select></td></tr>'
			+ '<tr><td>Other/additional reason:</td>'
				+ '<td><input type="text" id="wpMassBlockReason" name="wpMassBlockReason" maxlength="255" /></td></tr>'
			+ '<tr><td>Expiration time (blank for indefinite):</td>'
				+ '<td><input type="text" id="wpMassBlockExpiry" name="wpMassBlockExpiry" maxlength="255" /></td></tr>'
			+ '<tr><td>Edit summary for talk page edit:</td>'
				+ '<td><input type="text" id="wpMassBlockSummaryTalk" name="wpMassBlockSummaryTalk" maxlength="255" /></td></tr>'
			+ '<tr><td>Edit summary for user page edit:</td>'
				+ '<td><input type="text" id="wpMassBlockSummaryUser" name="wpMassBlockSummaryUser" maxlength="255" /></td></tr>'
				+ '<tr><td>Block anonymous users only (IPs only):</td><td><input type="checkbox" id="wpMassBlockAnononly" name="wpMassBlockAnononly" /></td></tr>'
				+ '<tr><td>Enable autoblock (accounts only):</td><td><input type="checkbox" id="wpMassBlockAutoblock" name="wpMassBlockAutoblock" checked="checked" /></td></tr>'
				+ '<tr><td>Block account creation:</td><td><input type="checkbox" id="wpMassBlockNocreate" name="wpMassBlockNocreate" checked="checked" /></td></tr>'
				+ '<tr><td>Block email:</td><td><input type="checkbox" id="wpMassBlockEmail" name="wpMassBlockEmail" /></td></tr>'
				+ '<tr><td>Remove talk page access:</td><td><input type="checkbox" id="wpMassBlockTalkpage" name="wpMassBlockTalkpage" /></td></tr>'
				+ '<tr><td>Override existing blocks:</td><td><input type="checkbox" id="wpMassBlockReblock" name="wpMassBlockReblock" checked="checked" /></td></tr>'
				+ '<tr><td><input type="button" id="wpMassBlockSubmit" name="wpMassBlockSubmit" value="Block" onclick="doMassBlock()" /></td></tr>'
		+ '</form>';
	document.getElementById("wpMassBlockReasons").onchange = function() {
		var maxlength = (document.getElementById("wpMassBlockReasons").value == "other" ? 255 : 253-document.getElementById("wpMassBlockReasons").value.length); //It's 253 because of the two characters (": ") in addition to the selected summary.
		document.getElementById("wpMassBlockReason").setAttribute("maxlength", maxlength);
	};
}

if( mw.config.get("wgNamespaceNumber") == -1 && (mw.config.get("wgTitle") == "Massblock" || mw.config.get("wgTitle") == "MassBlock") )
{
	mw.loader.getScript("//meta.wikimedia.org/w/index.php?title=User:Tks4Fish/gsCheck.js&action=raw&ctype=text/javascript").then(function(){
		verifyWiki(mw.config.get("wgDBname")).then(function(data) {
			if (data === true) {
				verifyUser(mw.config.get("wgUserName")).then(function(data) {
					if (data === true) {
						$(massblockform);
					}
				});
			}
			else if (/sysop/.test(mw.config.get("wgUserGroups"))) {
				$(massblockform);
			}
		});
	});
}