User:DreamRimmer/SBRequest-enwiki.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | Documentation for this user script can be added at User:DreamRimmer/SBRequest-enwiki. |
//<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>