Jump to content

User:DreamRimmer/SBRequest-enwiki.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//<nowiki>
mw.loader.using(['mediawiki.api', 'mediawiki.util', 'oojs-ui'], function () {
	'use strict';
	const page = mw.config.get('wgPageName');
	const api = new mw.Api();
	let token = null;
	async function getToken() {
		try {
			const res = await api.get({
				action: 'query',
				meta: 'tokens',
				type: 'csrf'
			});
			token = res.query.tokens.csrftoken;
		} catch (e) {
			console.error('Error getting token:', e);
			throw e;
		}
	}
	function ItemInputWidget() {
		OO.ui.Widget.call(this);
		this.textInput = new OO.ui.TextInputWidget({
			placeholder: 'Enter item',
			required: true,
			rows: 1
		});
		this.dropdown = new OO.ui.DropdownInputWidget({
			options: [
				{ data: 'link', label: 'URL' },
				{ data: 'ip', label: 'IP' },
				{ data: 'user', label: 'User' }
			],
			value: 'link'
		});
		this.textInput.$element.css('width', '67%');
		this.dropdown.$element.css('width', '30%');
		this.layout = new OO.ui.HorizontalLayout({
			items: [ this.textInput, this.dropdown ]
		});
		this.$element.addClass('itemInputWidget').css('margin-bottom', '5px');
		this.$element.append(this.layout.$element);
	}
	OO.inheritClass(ItemInputWidget, OO.ui.Widget);
	function createItemField() {
		return new ItemInputWidget();
	}
	function RequestDialog(config) {
		RequestDialog.super.call(this, config);
	}
	OO.inheritClass(RequestDialog, OO.ui.ProcessDialog);
	RequestDialog.static.name = 'requestDialog';
	RequestDialog.static.title = 'SBRequest';
	RequestDialog.static.actions = [
		{ action: 'accept', label: 'Submit', flags: ['primary', 'progressive'] },
		{ action: 'cancel', label: 'Cancel', flags: 'safe' }
	];
	RequestDialog.prototype.initialize = function () {
		RequestDialog.super.prototype.initialize.apply(this, arguments);
		this.itemContainer = new OO.ui.FieldsetLayout({
			label: 'Blacklist items:'
		});
		this.itemContainer.addItems([ createItemField() ]);
		this.reasonInput = new OO.ui.MultilineTextInputWidget({
			placeholder: 'Reason for blacklist',
			multiline: true,
			required: true,
			rows: 2
		});
		const addButton = new OO.ui.ButtonWidget({
			label: '+',
			flags: ['progressive']
		});
		addButton.on('click', () => {
			this.itemContainer.addItems([ createItemField() ]);
			this.updateSize();
		});
		this.content = new OO.ui.PanelLayout({ padded: true, expanded: false });
		this.content.$element.append(
			new OO.ui.FieldsetLayout({
				items: [
					this.itemContainer,
					new OO.ui.FieldLayout(addButton),
					new OO.ui.FieldLayout(this.reasonInput, { label: 'Reason:', align: 'top' })
				]
			}).$element
		);
		this.$body.append(this.content.$element);
	};
	RequestDialog.prototype.getBodyHeight = function () {
		return this.content.$element.outerHeight(true) + 20;
	};
	RequestDialog.prototype.getActionProcess = function (action) {
		if (action === 'accept') {
			return new OO.ui.Process(async () => {
				const items = this.itemContainer.items.map(widget => {
					return {
						value: widget.textInput.getValue(),
						type: widget.dropdown.getValue()
					};
				}).filter(item => item.value);
				const reason = this.reasonInput.getValue();
				if (items.length === 0) {
					alert('Please enter at least one item to be blacklisted.');
					return;
				}
				if (!reason) {
					alert('Please enter a reason for the blacklist.');
					return;
				}
				const signature = '~~~~';
				let report;
				if (items.length === 1) {
					const item = items[0];
					report = `== ${item.value} ==\n* {{${item.type === 'link' ? 'LinkSummary' : item.type === 'ip' ? 'ipsummary' : 'usersummary'}|${item.value}}}\n${reason} ${signature}\n`;
				} else {
					report = `== Bulk spam additions (${items[0].value} and more) ==\n`;
					items.forEach(item => {
						report += `* {{${item.type === 'link' ? 'LinkSummary' : item.type === 'ip' ? 'ipsummary' : 'usersummary'}|${item.value}}}\n`;
					});
					report += `${reason} ${signature}\n`;
				}
				const success = await appendReport(report);
				if (success) {
					alert('Request submitted successfully!');
					location.reload();
					this.close({ action: 'accept' });
				}
			});
		} else if (action === 'cancel') {
			return new OO.ui.Process(() => {
				this.close({ action: 'cancel' });
			});
		}
	};
	async function appendReport(report) {
		if (!token) await getToken();
		const res = await api.get({
			action: 'query',
			prop: 'revisions',
			titles: page,
			rvprop: 'content',
			format: 'json'
		});
		const pages = res.query.pages;
		const data = pages[Object.keys(pages)[0]];
		let content = data.revisions[0]['*'];
		const headingRegex = /^=[^=]+=$/gm;
		const headings = [...content.matchAll(headingRegex)];
		const proposedAdditionsIndex = headings.findIndex(h => /^=\s*proposed additions\s*=$/i.test(h[0]));
		if (proposedAdditionsIndex === -1) {
			alert('Could not find the "Proposed additions" section.');
			return false;
		}
		const removalsHeading = headings.find(h => /^=\s*proposed removals\s*=$/i.test(h[0]));
		let insertPos;
		if (removalsHeading) {
			insertPos = removalsHeading.index;
		} else {
			insertPos = content.length;
		}
		const newContent = content.substring(0, insertPos) + report + '\n' + content.substring(insertPos);
		await api.postWithToken('csrf', {
			action: 'edit',
			title: page,
			text: newContent,
			summary: 'Requesting additions (using [[User:DreamRimmer/SBRequest-enwiki.js|SBRequest-enwiki.js]])',
			format: 'json'
		});
		return true;
	}
	async function init() {
		if (page === 'MediaWiki_talk:Spam-blacklist') {
			const button = document.createElement('button');
			button.id = 'request-addition-button';
			button.className = 'oo-ui-buttonElement oo-ui-buttonElement-progressive oo-ui-widget oo-ui-widget-enabled';
			button.style = 'margin: 10px auto;background-color: rgb(51, 102, 204);color: white;border: 1px solid rgb(51, 102, 204);text-align: center;border-radius: 3px;font-size: 18px;padding: 8px 15px;display: block;font-weight: bold;cursor: pointer;';
			button.textContent = 'Request addition';
			document.querySelector('table[role="presentation"]').insertAdjacentElement('afterend', button);
			button.addEventListener('click', function (e) {
				e.preventDefault();
				const windowManager = new OO.ui.WindowManager();
				$(document.body).append(windowManager.$element);
				const requestDialog = new RequestDialog({ size: 'medium' });
				windowManager.addWindows([requestDialog]);
				windowManager.openWindow(requestDialog);
			});
		}
	}
	init();
});
//</nowiki>