Участник:Mednik/common.js — различия между версиями

Материал из Wiki - Факультет компьютерных наук
Перейти к: навигация, поиск
(эксперимент: скрипт nuke)
 
(старая версия)
Строка 1: Строка 1:
 
/*
 
/*
* Nuke
+
* Nuke
* Reverse engineered Nuke extension
+
* Reverse engineered Nuke extension
* https://www.mediawiki.org/wiki/Extension:Nuke
+
* https://www.mediawiki.org/wiki/Extension:Nuke
* @author Ozank Cx (https://dev.fandom.com/wiki/User:Ozank Cx)
+
* @author Ozank Cx
* @author Thundercraft5 (https://dev.fandom.com/wiki/User:Thundercraft5)
+
* @TODO - implement usercontribs API if Wikia update to MW 1.23+
*/
+
/* jshint
+
esversion: 6, forin: true,
+
immed: true, indent: 4,
+
latedef: true, newcap: true,
+
onevar: true, eqeqeq: true,
+
multistr: true, maxerr: 999999,
+
noarg: true, undef: true,
+
undef: true, unused: true,
+
browser: true, jquery: true,
+
-W082, -W084
+
 
*/
 
*/
/* global mw */
 
mw.loader.using(['mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then(function() {
 
var api = new mw.Api();
 
 
 
return $.when(
+
mw.loader.using(['mediawiki.util', 'mediawiki.api'], function() {
mw.user.getRights(),
+
api,
+
api.loadMessagesIfMissing([
+
'invert',
+
'nuke',
+
'nuke-linkoncontribs',
+
'nuke-linkoncontribs-text',
+
'nuke-tools',
+
'nuke-submit-delete',
+
'nuke-submit-user',
+
'nuke-list',
+
'nuke-list-multiple',
+
'nuke-deleted',
+
'nuke-not-deleted',
+
'nuke-editby',
+
'nuke-nopages',
+
'nuke-userorip',
+
'nuke-namespace',
+
'nuke-maxpages',
+
])
+
);
+
}).then(function(rights, api) {
+
if (window.Nuke && window.Nuke.loaded) return this.warn('Script was double loaded, exiting...');
+
else if (![-1, 2, 3, 1200].includes(this.wg.wgNamespaceNumber)
+
&& !(this.wg.wgNamespaceNumber === 500 && !this.wg.wgPageName.includes('/'))
+
) return this.log('Namespace is not supported, exiting...');
+
else if (!rights.includes('delete')) return this.log('User cannot delete pages, exiting...');
+
  
var Nuke = window.Nuke = Object.assign(this, {
+
var ug = mw.config.get('wgUserGroups');
loaded: true,
+
limit: Number(mw.util.getParamValue('nukelimit') || 500),
+
deleteDelay: window.nukeDelay || 1000,
+
label: mw.msg('nuke'),
+
contribsLabel: mw.msg('nuke-linkoncontribs'),
+
token: mw.user.tokens.get('csrfToken'),
+
+
init: function() {
+
$('.page-header__title').text(this.label);
+
document.title = this.label + " | " + this.wg.wgSiteName + " | Fandom";
+
mw.util.addCSS('.thumbnail-nuke {\
+
max-width: 250px;\
+
width: auto;\
+
height: 80px;\
+
}\
+
\
+
li.nuke-query-result:hover {\
+
cursor: pointer !important;\
+
background: rgba(0, 0, 0, 0.5)\
+
}\
+
\
+
li.nuke-query-result {\
+
transition: 0.3s background ease;\
+
}\
+
\
+
button {\
+
cursor: pointer !important;\
+
}');
+
  
if (mw.util.getParamValue('nukeuser')) {
+
if (ug.indexOf('content-moderator') + ug.indexOf('sysop') + ug.indexOf('vstf') + ug.indexOf('staff') + ug.indexOf('helper') == -5) return;
this.loadUserUI();
+
} else {
+
this.loadMainUI();
+
}
+
$(document.body).on('click', '.nuke-submit', this.submitHandler);
+
},
+
+
msg: function(name) {
+
return mw.message.apply(mw, [name].concat(Array.from(arguments).slice(1))).parse().replace(/'{3}(.+?)'{3}/g, '<b>$1</b>');
+
},
+
+
rcSubmit: function() {
+
if ($('#nuke-rc').attr('disabled')) return;
+
  
$('#nuke-rc').attr('disabled', true);
+
var config = mw.config.get([
$('.nuke-check-all, .nuke-invert').remove();
+
'skin',
+
'stylepath',
if ($('#nuke-username').val()) {
+
'wgArticlePath',
var locationParams = {
+
'wgFormattedNamespaces',
blankspecial: 'nuke',
+
'wgMainpage',
nukeuser: $('#nuke-username').val()
+
'wgSiteName'
};
+
]),
 +
token = mw.user.tokens.values.editToken,
 +
API = new mw.Api(),
 +
deleteDelay = window.nukeDelay || 1000;
 +
config.wgArticlePath = config.wgArticlePath.slice(0,-2);
  
if ($('#nuke-namespace').val() !== "All")
+
var self = {
locationParams.nukenamespace = $('#nuke-namespace').val();
+
init: function() {
 
+
if ($.isNumeric($('#nuke-max').val()) && $('#nuke-max').val() > 0)
+
$('.header-column.header-title h1').text('Nuke');
locationParams.nukelimit = $('#nuke-max').val();
+
document.title = "Nuke - " + config.wgSiteName;
 
+
mw.util.addCSS('.thumbnail-nuke { width: 120px; height: 77px; }');
if ($('#nuke-match').val())
+
locationParams.nukematch = $('#nuke-match').val();
+
if ($.getUrlVar('nukeuser')) {
 
+
var user = $.getUrlVar('nukeuser'),
location.replace(mw.util.getUrl('Special:Blankpage', locationParams));
+
deleteReason = window.nukeDeleteReason || "Mass removal of pages created by " + user.replace(/_/g,' ');
return;
+
}
+
$('#mw-content-text p').html('<a href="' + config.wgArticlePath + 'Special:Blankpage?blankspecial=nuke">Switch to Nuke main form</a><br/>The following pages were created by <a href="' + config.wgArticlePath + 'Special:Contributions/' + user + '">' + user.replace(/_/g,' ') + '</a>; put in a comment and hit the button to delete them.<br/>Reason for deletion: <input style="width: 400px" type="text" id="nuke-delete-reason" value="' + deleteReason + '"/><br/><a class="wikia-button nuke-submit">Delete</a><div id="nuke-status"/><ul id="nuke-query-results"></ul><a class="wikia-button nuke-submit">Delete</a>');
 
+
$('#nuke-status').html('Getting pages... please wait <img src="' + config.stylepath + '/common/progress-wheel.gif"/>');
$('#nuke-query-results').empty();
+
 
+
API.get({
if ($('.nuke-submit').length) {
+
action: 'query',
$('.nuke-submit').remove();
+
list: 'usercontribs',
$('#mw-content-text > p:nth-child(1) > br:nth-child(14)').remove();
+
ucnamespace: $.getUrlVar('nukenamespace') || '',
}
+
ucuser: user,
 
+
uclimit: 5000,
$('#nuke-status').html('Getting pages... please wait <img src="https://static.wikia.nocookie.net/dev/images/c/c5/Circle_throbber.gif/revision/latest"/>');
+
cb: new Date().getTime()  
this.queryRecentChanges();
+
})
},
+
.done(function(d) {
 
+
if (!d.error) {
submitHandler: function() {
+
var usercontribs = d.query.usercontribs,
if (!$('.nuke-query-result, .nuke-title-check:checked').length || $(this).attr('disabled')) return;
+
maxLimit = $.getUrlVar('nukelimit') || 500,
 
+
count = 0,
$('.nuke-submit, .nuke-check-all, .nuke-invert, #nuke-protect').attr('disabled', true);
+
images = [];
$('#nuke-status').html('Deleting pages... please wait <img src="https://static.wikia.nocookie.net/dev/images/c/c5/Circle_throbber.gif/revision/latest"/>');
+
$('.nuke-title-check:checked').each(function(i) {
+
for (var i in usercontribs) {
var title = $(this).parent().find('a:not(:has(> img))').first().text();
+
if (count >= maxLimit) break;
setTimeout(function() {
+
api.post({
+
action: 'delete',
+
title: title,
+
reason: $('#nuke-delete-reason').val() || '',
+
bot: true,
+
token: this.token,
+
watchlist: 'nochange',
+
}).then(function() {
+
this.notify('success', this.msg('nuke-deleted', title));
+
 
 
$('#nuke-protect').prop('checked') ? api.post({
+
if (usercontribs[i].hasOwnProperty('new')) {
action: 'protect',
+
var escapedTitle = encodeURIComponent(usercontribs[i].title);
protections: 'create=sysop',
+
if (!$.getUrlVar('nukematch') || new RegExp($.getUrlVar('nukematch')).test(usercontribs[i].title)) {
expiry: 'infinite',
+
$('#nuke-query-results').append('<li class="nuke-query-result"><input type="checkbox" class="nuke-title-check" checked="checked"/> <a href="' + config.wgArticlePath + escapedTitle + '" target="_blank">' + usercontribs[i].title + '</a></li>');
bot: true,
+
if (usercontribs[i].title.slice(0,5) == "File:")
watchlist: 'nochange',
+
images.push(usercontribs[i].title);
token: this.token,
+
count++;
title: title,
+
}
reason: $('#nuke-delete-reason').val(),
+
}
}).then(function() {
+
this.notify('success', 'Protection of ' + title + ' successful!');
+
}.bind(this), function(_, data) {
+
this.notify('warn', 'Failed to protect ' + title + ':', data.error.info);
+
}.bind(this)) : undefined;
+
}.bind(this), function(_, data) {
+
this.notify('warn', this.msg('nuke-not-deleted', title).replace(/\.$/, ': ' + data.error.info));
+
}.bind(this));
+
+
if (i === $('.nuke-title-check:checked').length - 1) {
+
setTimeout(function() {
+
this.log('Deletions All Done, redirecting...');
+
+
location.replace(
+
!mw.util.getParamValue('nukeuser')
+
+
? mw.util.getUrl(
+
'Special:BlankPage',  
+
$.extend({ blankspecial: 'nuke' }, this.parseUrlParams(location.search))
+
)
+
+
: mw.util.getUrl(
+
mw.util.getParamValue('returnto')
+
|| ("Special:Contributions/" + mw.util.getParamValue('nukeuser')),
+
mw.util.getParamValue('returntoparams') ? this.parseUrlParams(mw.util.getParamValue('returntoparams')) : ''
+
)
+
);
+
}.bind(this), 1000);
+
 
}
 
}
}.bind(Nuke), i * this.deleteDelay);
+
if (!$('.nuke-query-result').length)
 +
self.outputError("No user contributions found");
 +
else {
 +
if (images.length > 0)
 +
self.displayImages(images);
 +
}
 +
}
 +
else
 +
self.outputError("Failed to get user contributions: " + d.error.code);
 +
})
 +
.fail(function() {
 +
self.outputError("Failed to get user contributions");
 
});
 
});
},
 
 
loadUserUI: function() {
 
var user = mw.util.getParamValue('nukeuser').replace(/_/g, ' '),
 
deleteReason = mw.html.escape(
 
mw.util.getParamValue('nukereason')
 
|| window.nukeDeleteReason && window.nukeDeleteReason.replaceAll(/\$1/g, user)
 
|| "Mass removal of pages created by [[Special:Contributions/" + user + "|" + user + "]] ([[User talk:" + user + "|talk]])"
 
);
 
 
this.addCheckboxHandler();
 
 
$('#mw-content-text p').html($('<span>', { html: [
 
$('<a>', {
 
href: mw.util.getUrl('Special:Blankpage', { blankspecial: 'nuke' }),
 
html: "Switch to Nuke main form",
 
}),
 
'<br/>',
 
this.msg('nuke-list', user),
 
'<br>',
 
'Deletion reason: ',
 
$('<input>', {
 
css: {
 
width: "400px"
 
},
 
type: "text",
 
id: "nuke-delete-reason",
 
value: deleteReason,
 
}),
 
$('<div>', {
 
html: [
 
$('<input>', {
 
type: "checkbox",
 
name: "nuke-protect",
 
id: "nuke-protect",
 
title: 'Check this box to protect deleted pages from re-creation',
 
}),
 
$('<label>', {
 
html: "Protect deleted pages",
 
'for': 'nuke-protect',
 
id: "nuke-protect-label",
 
title: 'Check this box to protect deleted pages from re-creation',
 
}),
 
],
 
class: "nuke-label",
 
}),
 
$('<hr>', { css: { 'margin': '0 20px;' }}),
 
$("<button>", {
 
class: "nuke-submit",
 
html: this.msg('nuke-submit-delete') + ' (0)',
 
}),
 
$('<div>', { id: "nuke-status" }),
 
$('<ul>', { id: "nuke-query-results" }),
 
$("<button>", {
 
class: "nuke-submit",
 
html: this.msg('nuke-submit-delete') + ' (0)',
 
}),
 
]}));
 
 
$('#nuke-status')
 
.html('Getting pages... please wait <img src="https://static.wikia.nocookie.net/dev/images/c/c5/Circle_throbber.gif/revision/latest"/>');
 
this.queryUserContribs(user);
 
 
 
$('#nuke-status').empty();
 
$('#nuke-status').empty();
},
+
}
 +
else {
 +
$('#mw-content-text p').html('This tool allows for mass deletions of pages recently added by a given user or IP address.<br/>Input the username or IP address to get a list of pages to delete, or leave blank for all users.<br/>Username, IP address or blank: <input type="text" id="nuke-username"/><br/>Pattern for the page name: <input type="text" id="nuke-match"/><br/>Limit to namespace: <select id="nuke-namespace"><option value="All">All</option><option value="Main" ns="0">Main</option><option value="Project" ns="4">Project</option><option value="Project talk" ns="5">Project talk</option><option value="Talk" ns="1">Talk</option><option value="User" ns="2">User</option><option value="User talk" ns="3">User talk</option><option value="File" ns="6">File</option><option value="File talk" ns="7">File talk</option><option value="Template" ns="10">Template</option><option value="Template talk" ns="11">Template talk</option><option value="Help" ns="12">Help</option><option value="Help talk" ns="13">Help talk</option><option value="Category" ns="14">Category</option><option value="Category talk" ns="15">Category talk</option></select><br/>Maximum number of pages: <input type="text" id="nuke-max" value="500"/><br/><a class="wikia-button" id="nuke-rc">Go</a><br/><div id="nuke-status"/><div id="nuke-query-results"/>');
 
 
+
$('#nuke-rc').click(function() {
loadMainUI: function() {
+
if ($(this).attr('disabled')) return;
this.addCheckboxHandler();
+
 
 
$('#mw-content-text p').html($('<span>', { html: [
+
$(this).attr('disabled','disabled');
this.msg('nuke-tools'),
+
'<br/>',
+
this.msg('nuke-userorip'),
+
$('<input>', {
+
type: "text",
+
id: "nuke-username",
+
}),
+
'<br>',
+
'Regex pattern (e.g. <code>.*</code>) for the page name: ',
+
$('<input>', {
+
type: "text",
+
id: "nuke-match",
+
value: mw.util.getParamValue('nukepattern'),
+
}),
+
'<br>',
+
this.msg('nuke-namespace'),
+
$('<select>', {
+
id: "nuke-namespace",
+
name: "nuke-namespace",
+
html: [
+
$('<option>', {
+
value: "all",
+
selected: "",
+
html: "all",
+
}),
+
].concat(this.generateNamespaceSelect()),
+
}),
+
'<br>',  
+
this.msg('nuke-maxpages'),
+
$('<input>', {
+
type: "text",
+
id: "nuke-max",
+
value: mw.util.getParamValue('nukelimit') || 500,
+
}),
+
'<br>',
+
'Deletion Reason: ',
+
$('<input>', {
+
type: "text",
+
id: "nuke-delete-reason",
+
value: mw.util.getParamValue('nukereason'),
+
}),
+
'<br>',
+
$('<input>', {
+
type: "checkbox",
+
name: "nuke-protect",
+
id: "nuke-protect",
+
title: 'Check this box to protect deleted pages from re-creation',
+
}),
+
$('<label>', {
+
html: "Protect deleted pages",
+
'for': 'nuke-protect',
+
id: "nuke-protect-label",
+
title: 'Check this box to protect deleted pages from re-creation',
+
}),
+
$('<div>', {
+
html: $("<input>", {
+
class: "wikia-button",
+
id: "nuke-rc",
+
name: "nuke-rc",
+
value: this.msg('nuke-submit-user'),
+
type: "submit",
+
click: this.rcSubmit.bind(this),
+
}),
+
css: {
+
'margin-top': '10px',
+
'margin-bottom': "30px",
+
},
+
}),
+
$('<div>', {
+
id: "nuke-status"
+
}),
+
$('<hr>'),
+
$('<ul>', {
+
id: "nuke-query-results",
+
}),
+
]}));
+
 
 
$('#nuke-namespace').val(mw.util.getParamValue('nukenamespace'));
+
if ($('#nuke-username').val()) {
},
+
var locationStr = config.wgArticlePath + 'Special:Blankpage?blankspecial=nuke&nukeuser=' + $('#nuke-username').val();
+
queryUserContribs: function(user) {
+
if ($('#nuke-namespace').val() != "All")
api.get({
+
locationStr += '&nukenamespace=' + $('#nuke-namespace option:selected').attr('ns');
action: 'query',
+
list: 'usercontribs',
+
if ($.isNumeric($('#nuke-max').val()) && $('#nuke-max').val() > 0)
ucnamespace: mw.util.getParamValue('nukenamespace') || '',
+
locationStr += '&nukelimit=' + $('#nuke-max').val();
ucuser: user,
+
uclimit: 'max',
+
if ($('#nuke-match').val())
}).then(function(d) {
+
locationStr += '&nukematch=' + $('#nuke-match').val();
var usercontribs = d.query.usercontribs,
+
images = [],
+
location.replace(locationStr);
count = 0;
+
return;
 
+
usercontribs.forEach(function(contrib) {
+
if (count >= this.limit) return;
+
 
+
if ('new' in contrib) {
+
if (!mw.util.getParamValue('nukematch') || new RegExp(mw.util.getParamValue('nukematch')).test(contrib.title)) {
+
count++;
+
$('#nuke-query-results').append(
+
$('<li>', {
+
class: "nuke-query-result",
+
html: [
+
$('<input>', {
+
type: "checkbox",
+
class: "nuke-title-check",
+
checked: "checked",
+
}),
+
$('<a>', {
+
href: mw.util.getUrl(contrib.title),
+
target: "_blank",
+
title: contrib.title,
+
text: mw.html.escape(contrib.title),
+
}),
+
'&nbsp;(',
+
$('<a>', {
+
target: "_blank",
+
href: mw.util.getUrl(contrib.title, { action: "info" }),
+
title: contrib.title,
+
text: "info",
+
}),
+
')',
+
],
+
})
+
);
+
if (contrib.title.indexOf(this.wg.wgFormattedNamespaces[6] + ':') === 0)
+
images.push(contrib.title);
+
}
+
}
+
}, this);
+
+
if (!$('.nuke-query-result').length) {
+
this.notify('error', this.msg('nuke-nopages', user));
+
} else {
+
if (images.length > 0) this.displayImages(images);
+
this.addCheckToggleButton();
+
$('.nuke-submit').html(this.msg('nuke-submit-delete') + ' (' + $('.nuke-title-check:checked').length + ')');
+
 
}
 
}
}.bind(this).bind(this), function(_, data) {
+
this.notify('error', "Failed to get user contributions: " + data.error.info);
+
$('#nuke-query-results').empty();
}.bind(this));
+
},
+
if ($('.nuke-submit').length) {
+
$('.nuke-submit').remove();
queryRecentChanges: function() {
+
$('#mw-content-text > p:nth-child(1) > br:nth-child(14)').remove();
api.get({
+
action: 'query',
+
list: 'recentchanges',
+
rcshow: '!bot',
+
rctype: 'new|log',
+
rclimit: 'max',
+
}).then(function(d) {
+
var recentchanges = d.query.recentchanges,
+
rcTitles = [],
+
maxLimit = $('#nuke-max').val() || 5000,
+
images = [],
+
count = 0;
+
+
recentchanges.forEach(function(page) {
+
if (count >= maxLimit) return;
+
if (
+
rcTitles.indexOf(page.title, rcTitles) === -1 && (
+
$('#nuke-namespace').val() === "All" ||
+
Number($('#nuke-namespace').val()) === page.ns
+
) && (page.type === "new" || (
+
page.type === "log" &&
+
page.ns === 6
+
))
+
) {
+
if (!$('#nuke-match').val() || new RegExp($('#nuke-match').val()).test(page.title)) {
+
count++;
+
rcTitles.push(page.title);
+
$('#nuke-query-results').append($('<li>', {
+
class: "nuke-query-result",
+
html: [
+
$('<input>', {
+
type: "checkbox",
+
class: "nuke-title-check",
+
checked: "checked",
+
}),
+
$('<a>', {
+
href: mw.util.getUrl(page.title),
+
target: "_blank",
+
title: page.title,
+
text: mw.html.escape(page.title),
+
}),
+
'&nbsp;(',
+
$('<a>', {
+
target: "_blank",
+
href: mw.util.getUrl(page.title, { action: "info" }),
+
title: page.title,
+
text: "info",
+
}),
+
')',
+
],
+
}));
+
if (page.title.indexOf(this.wg.wgFormattedNamespaces[6] + ':') === 0)
+
images.push(page.title);
+
}
+
}
+
}, this);
+
+
if (!$('.nuke-query-result').length) {
+
this.notify('error', "No recent changes found");
+
} else {
+
var $button = $('<button>', {
+
class: "nuke-submit",
+
html: 'Delete selected (' + $('.nuke-title-check:checked').length + ')</a>',
+
});
+
+
$('#nuke-query-results').before($button).after($button.clone());
+
+
$('#nuke-status').empty();
+
$('.nuke-sumbit, .nuke-check-all, .nuke-invert').remove();
+
+
this.addCheckToggleButton();
+
+
if (images.length > 0) this.displayImages(images);
+
 
}
 
}
}.bind(this), function(_, data) {
+
this.notify('error', "Failed to get recent changes: " + data.error.info);
+
$('#nuke-status').html('Getting pages... please wait <img src="' + config.stylepath + '/common/progress-wheel.gif"/>');
}.bind(this));
+
+
API.get({
$('#nuke-status').empty();
+
action: 'query',
$(this).attr('disabled', false);
+
list: 'recentchanges',
},
+
rcshow: '!bot',
+
rctype: 'new|log',
generateNamespaceSelect: function() {
+
rclimit: 5000,
return Object.entries(this.wg.wgFormattedNamespaces)
+
cb: new Date().getTime()  
.map(function(v) { return [+v[0], v[1]] })
+
.sort(function(a, b) {
+
var id1 = a[0];
+
var id2 = b[0];
+
+
if (id1 < id2) return -1;
+
else if (id1 > id2) return 1;
+
else return 0;
+
 
})
 
})
.slice(2)
+
.done(function(d) {
.map(function(d) {
+
if (!d.error) {
var namespace = d[1];
+
var recentchanges = d.query.recentchanges,
var id = d[0];
+
RCTitles = [],
+
maxLimit = $('#nuke-max').val() || 5000,
return $('<option>', {
+
count = 0,
value: id,
+
images = [];
text: namespace === "" ? "(Main)" : namespace,
+
});
+
});
+
},
+
+
notify: function(level) {
+
var params = Array.from(arguments).slice(1);
+
mw.notify($('<div>', { html: params.join(' ') }), { type: level });
+
+
(this[level] || this.log).apply(null, params.map(function(val) {
+
return $($.parseHTML(val)).text();
+
}));
+
},
+
+
addCheckboxHandler: function() {
+
var selected = new Set();
+
var anchor;
+
+
$('#mw-content-text').on('click', 'li.nuke-query-result', function(e) {
+
var $input = $(this).find('input');
+
+
if (e.target.children.length === 0 && e.target !== $input[0]) return;
+
if (e.target !== $input[0]) $input.prop('checked', !$input[0].checked);
+
if (!e.shiftKey || e.shiftKey && !anchor) anchor = $input[0], selected.clear(), selected.add($input[0]);
+
+
if (anchor && e.shiftKey && !e.ctrlKey) {
+
var $coll = $(this).parent().children().map(function() { return $(this).find('input[type="checkbox"]')[0] });
+
var targetIndex = $coll.index($input[0]);
+
var anchorIndex = $coll.index(anchor);
+
+
if (targetIndex < anchorIndex) $coll = $coll.slice(targetIndex, anchorIndex + 1);
+
else $coll = $coll.slice(anchorIndex, targetIndex + 1);
+
+
$coll.each(function() { selected.add(this); });
+
}
+
+
if (e.ctrlKey && !e.shiftKey)
+
if (selected.has($input[0])) selected.delete($input[0]);
+
else selected.add($input[0]);
+
+
if (selected.size > 1) selected.forEach(function(node) {
+
$(node).prop('checked', anchor.checked);
+
});
+
});
+
},
+
+
addCheckToggleButton: function() {
+
$('.nuke-submit')
+
.after(
+
$('<button>', {
+
class: "nuke-check-all",
+
'data-checked': true,
+
text: "Uncheck All",
+
}),
+
$('<button>', {
+
text: this.msg('invert'),
+
class: "nuke-invert",
+
})
+
);
+
 
+
$('.nuke-submit').text(this.msg('nuke-submit-delete') + ' (' + $('.nuke-title-check:checked').length + ')');
+
+
// Check/Uncheck all
+
$('.nuke-check-all').click(function() {
+
var checked = $(this).attr('data-checked') === "true";
+
+
$('.nuke-title-check').prop('checked', !checked);
+
$('.nuke-check-all')
+
.attr('data-checked', !checked)
+
.text(!checked ? "Uncheck All" : 'Check All'); 
+
});
+
+
// Invert/Uninvert all
+
$('.nuke-invert').click(function() {
+
$('.nuke-title-check').each(function() {
+
$(this).prop('checked', !$(this).prop('checked'));
+
});
+
});
+
+
// Update count
+
$(document.body).on("click", '.nuke-query-result, .nuke-check-all, .nuke-invert', function() {
+
$('.nuke-submit').html(this.msg('nuke-submit-delete') + ' (' + $('.nuke-title-check:checked').length + ')');
+
}.bind(this));
+
},
+
displayImages: function(imgs) {
+
api.post({ //POST instead of GET to avoid http 416
+
action: 'query',
+
prop: 'imageinfo',
+
titles: imgs.join('|'),
+
iiprop: 'url',
+
iilimit: 'max'
+
}).then(function(d) {
+
Object.values(d.query.pages).forEach(function(page) {
+
if (page.missing !== "" && page.imageinfo) {
+
var href = mw.util.getUrl(page.title);
+
 
 
$('a[href="' + href + '"]')
+
for (var i in recentchanges) {
.parent()
+
if (count >= maxLimit) break;
.children('.nuke-title-check')
+
.after($('<a>', {
+
if ($.inArray(recentchanges[i].title,RCTitles) == -1 && (($('#nuke-namespace').val() == "Main" && recentchanges[i].title.split(':').length === 1) || $('#nuke-namespace').val() == "All" || $('#nuke-namespace').val() == "Project" && new RegExp(config.wgFormattedNamespaces[4] + ':').test(recentchanges[i].title) || $('#nuke-namespace').val() == "Project talk" && new RegExp(config.wgFormattedNamespaces[5] + ':').test(recentchanges[i].title) || new RegExp($('#nuke-namespace').val() + ':').test(recentchanges[i].title)) && (recentchanges[i].type == "new" || (recentchanges[i].type == "log" && recentchanges[i].ns == 6))) {  
href: href,
+
if (!$('#nuke-match').val() || new RegExp($('#nuke-match').val()).test(recentchanges[i].title)) {
html: $('<img>', {
+
RCTitles.push(recentchanges[i].title);
class: "thumbnail-nuke",
+
var escapedTitle = encodeURIComponent(recentchanges[i].title);
src: page.imageinfo[0].url,
+
$('#nuke-query-results').append('<li class="nuke-query-result"><input type="checkbox" class="nuke-title-check" checked="checked"/> <a href="' + config.wgArticlePath + escapedTitle + '" target="_blank"> ' + recentchanges[i].title + '</a></li>');
}),
+
if (recentchanges[i].title.slice(0,5) == "File:")
}));
+
images.push(recentchanges[i].title);
 +
count++;
 +
}
 +
}
 +
}
 +
if (!$('.nuke-query-result').length)
 +
self.outputError("No recent changes found");
 +
else {
 +
$('#nuke-query-results').before('<br/><a class="wikia-button nuke-submit">Delete</a>').after('<a class="wikia-button nuke-submit">Delete</a>');
 +
$('#nuke-status').empty();
 +
if (images.length > 0)
 +
self.displayImages(images);
 +
}
 
}
 
}
 +
else
 +
self.outputError("Failed to get recent changes: " + d.error.code);
 +
})
 +
.fail(function() {
 +
self.outputError("Failed to get recent changes");
 
});
 
});
}, function(_, data) {
+
$('#nuke-status').empty();
this.notify('error', 'Failed to display images: ' + data.error.info);
+
$(this).removeAttr('disabled');
}.bind(this));
+
},
+
parseUrlParams: function(s) {
+
var params = s.replace(/^(?:\?|%26)/, '').split(/(?:&|%26)/);
+
var o = {};
+
+
params.forEach(function(k) {
+
var tmp = k.match(/(.+?)=(.+)/i);
+
o[tmp[1]] = tmp[2];
+
 
});
 
});
 
return o;
 
 
}
 
}
});
+
 
+
$('.nuke-submit').click(function() {
var inter = setInterval(function() {
+
if (!$('.nuke-query-result').length || $(this).attr('disabled')) return;
var username = this.wg.wgRelevantUserName || this.wg.profileUserName;
+
 
 
if ($('.page-tools-module').length) {
+
$('.nuke-submit').attr('disabled','disabled');
clearInterval(inter);
+
$('#nuke-status').html('Deleting pages... please wait <img src="' + config.stylepath + '/common/progress-wheel.gif"/>');
+
$('.nuke-title-check:checked').each(function(i) {
var $el = $('<li>', {
+
var title = $(this).parent().find('a').text();
id: "t-nuke",
+
setTimeout(function() {
html: $('<a>', {
+
API.post({
text: this.label,
+
action: 'delete',
title: window.nukeTitle || this.msg('nuke-linkoncontribs-text', username),
+
title: title,
href: mw.util.getUrl('Special:BlankPage', {
+
reason: $('#nuke-delete-reason').val() || '',
blankspecial: 'nuke',
+
bot: true,
nukeuser: username,
+
token: token
}),
+
})
}),
+
.done(function(d) {  
});
+
if (!d.error) {
+
console.log('Deletion of ' + title + ' successful!');
var $list = $('.page-tools-module ul');
+
}  
+
else {
if ($list.find('li#t-reconst').length || window.Reconstitute) {
+
console.log('Failed to delete ' + title + ': '+ d.error.code);
$list.find('li#t-reconst').before($el);
+
} else {
+
$list.find('li:is(#t-userrights, :last-of-type)').first().after($el);
+
}
+
}
+
}.bind(this));
+
+
switch (this.wg.wgCanonicalSpecialPageName) {
+
case "UserProfileActivity":
+
case "DeletedContributions":
+
case "Contributions": {
+
var usr = this.wg.wgRelevantUserName || this.wg.profileUserName,
+
nukeTitle = window.nukeTitle || this.msg('nuke-linkoncontribs-text', usr),
+
url = mw.util.getUrl('Special:BlankPage', {
+
blankspecial: 'nuke',
+
nukeuser: usr,
+
});
+
 
+
if (usr) {
+
var $el = $('<span>', {
+
id: "link-nuke",
+
html: $('<a>', {
+
title: nukeTitle,
+
href: url,
+
text: this.contribsLabel,
+
}),
+
});
+
+
if (!window.QuickLogs) {
+
if (this.wg.wgCanonicalSpecialPageName === 'DeletedContributions') {
+
$('.page-header__subtitle > a:last-of-type').after(' | ', $el.find('a'));
+
} else {
+
if ($('#link-rconst').length) {
+
$('#link-rconst').before($el);
+
} else {
+
$([
+
'.mw-contributions-user-tools > .mw-changeslist-links > span:last-child',
+
'.UserProfileActivityModeration__links > span:last-child',
+
].join(', ')).after($el);
+
 
}
 
}
}
+
})
}
+
.fail(function() {
mw.hook('QuickLogs.loaded').add(function(ql) {
+
console.log('Failed to delete ' + title);
ql.addLink('nuke', {
+
href: url,
+
title: nukeTitle,
+
message: this.contribsLabel,
+
 
});
 
});
});
+
if (i === $('.nuke-title-check:checked').length - 1) {
}
+
setTimeout(function() {
 
+
location.replace(config.wgArticlePath + config.wgMainpage);
break;
+
}, 1000);
}
+
}
 
+
}, i*deleteDelay);
case "AdminDashboard":
+
case "Specialpages": {
+
var link = mw.util.getUrl('Special:Blankpage', { blankspecial: 'nuke' });
+
var canNuke = rights.includes('nuke');
+
var nukeItem = $('<li>', {
+
class: "mw-specialpagerestricted",
+
html: $('<a>', {
+
title: "Special:Nuke",
+
href: link,
+
text: this.label + (canNuke ? ' (JavaScript)' : ""),
+
}),
+
 
});
 
});
$(canNuke
+
});
? '#mw-content-text a[href*="Special:Nuke"]'
+
},
: '#mw-content-text a[title="Special:Undelete"]'
+
outputError: function(text) {
).parent().after(nukeItem);
+
switch (config.skin) {
var pageToolsTable = nukeItem.closest('.mw-specialpages-table');
+
case 'oasis':
var pageTools = $('li', pageToolsTable).toArray().sort(function (a, b) {
+
case 'wikia':
return a.textContent.localeCompare(b.textContent);
+
new BannerNotification(text,'error').show();
});
+
var uls = $('td[width="45%"] ul', pageToolsTable);
+
if (uls.length > 0) { // Avoid divide by zero error.
+
var perChunk = Math.ceil(pageTools.length / uls.length);
+
uls.each(function(i, ul) {
+
$(ul).append(pageTools.slice(i * perChunk, (i + 1) * perChunk));
+
});
+
}
+
 
break;
 
break;
}
+
case "Blankpage": {
+
default:
if (mw.util.getParamValue('blankspecial') === "nuke")
+
alert(text);
this.init();
+
 
break;
 
break;
 
}
 
}
 +
},
 +
displayImages: function(imgs) {
 +
API.post({ //POST instead of GET for longer length
 +
action: 'query',
 +
prop: 'imageinfo',
 +
titles: imgs.join('|'),
 +
iiprop: 'url',
 +
iilimit: 500
 +
})
 +
.done(function(d) {
 +
if (!d.error) {
 +
for (var i in d.query.pages) {
 +
if (d.query.pages[i].missing != "") {
 +
var href = config.wgArticlePath + encodeURIComponent(d.query.pages[i].title);
 +
$('a[href="' + href + '"]').parent().children('.nuke-title-check').after('<a href="' + href + '"><img class="thumbnail-nuke" src="' + d.query.pages[i].imageinfo[0].url + '" /></a>');
 +
}
 +
}
 +
}
 +
else
 +
self.outputError('Failed to display images: ' + d.error.code);
 +
})
 +
.fail(function() {
 +
self.outputError('Failed to display images');
 +
});
 
}
 
}
}.bind(function() {
+
};
Object.keys(this).forEach(function(key) {
+
 
this[key] = function() {
+
switch (mw.config.get('wgCanonicalSpecialPageName')) {
console[key].apply(null, [ '[Nuke v1.5] [' + key.toUpperCase() + ']' ].concat(Array.from(arguments)));
+
case "Contributions":
};
+
$('#contentSub a:last-child').after(' | <a title="Special:Nuke" href="' + mw.config.get('wgArticlePath').replace('$1','Special:Blankpage?blankspecial=nuke&nukeuser=' + mw.config.get('wgPageName').split('/')[1] ) + '">Nuke</a>');
}, this);
+
break;
 +
 +
case "Specialpages":
 +
if (!$('a[title="Special:Nuke"]').length)
 +
$('.mw-specialpagerestricted a[title="Special:Undelete"]').after('<li class="mw-specialpagerestricted"><a title="Special:Nuke" href="' + mw.config.get('wgArticlePath').replace('$1','Special:Blankpage?blankspecial=nuke') + '">Mass delete</a></li>');
 +
else
 +
$('.mw-specialpagerestricted a[title="Special:Nuke"]').after('<li class="mw-specialpagerestricted"><a title="Special:Nuke" href="' + mw.config.get('wgArticlePath').replace('$1','Special:Blankpage?blankspecial=nuke') + '">Mass delete (JavaScript)</a></li>');
 +
break;
 
 
this.wg = mw.config.get([
+
case "Blankpage":
'wgUserGroups',
+
if ($.getUrlVar('blankspecial') == "nuke")
'wgCanonicalSpecialPageName',
+
self.init();
'wgFormattedNamespaces',
+
break;
'wgMainpage',
+
'wgPageName',
+
'wgSiteName',
+
'wgNamespaceNumber',
+
'profileUserName',
+
'wgRelevantUserName',
+
]);
+
 
 
return this;
+
default:
}.call({
+
return;
error: console.error,
+
break;
warn: console.warn,
+
}
log: console.log,
+
debug: console.debug,
+
})));
+
  
window.Nuke = window.Nuke || {};
+
});

Версия 13:07, 26 августа 2022

/*
* Nuke
* Reverse engineered Nuke extension
* https://www.mediawiki.org/wiki/Extension:Nuke
* @author Ozank Cx
* @TODO - implement usercontribs API if Wikia update to MW 1.23+
*/
 
mw.loader.using(['mediawiki.util', 'mediawiki.api'], function() {
 
var ug = mw.config.get('wgUserGroups');
 
if (ug.indexOf('content-moderator') + ug.indexOf('sysop') + ug.indexOf('vstf') + ug.indexOf('staff') + ug.indexOf('helper') == -5) return;
 
var config = mw.config.get([
	'skin',
	'stylepath',
	'wgArticlePath',
	'wgFormattedNamespaces',
	'wgMainpage',
	'wgSiteName'
]),
token = mw.user.tokens.values.editToken,
API = new mw.Api(),
deleteDelay = window.nukeDelay || 1000;
config.wgArticlePath = config.wgArticlePath.slice(0,-2);
 
var self = {
	init: function() {
 
		$('.header-column.header-title h1').text('Nuke');
		document.title = "Nuke - " + config.wgSiteName;
		mw.util.addCSS('.thumbnail-nuke { width: 120px; height: 77px; }');
 
		if ($.getUrlVar('nukeuser')) {
			var user = $.getUrlVar('nukeuser'),
			deleteReason = window.nukeDeleteReason || "Mass removal of pages created by " + user.replace(/_/g,' ');
 
			$('#mw-content-text p').html('<a href="' + config.wgArticlePath + 'Special:Blankpage?blankspecial=nuke">Switch to Nuke main form</a><br/>The following pages were created by <a href="' + config.wgArticlePath + 'Special:Contributions/' + user + '">' + user.replace(/_/g,' ') + '</a>; put in a comment and hit the button to delete them.<br/>Reason for deletion: <input style="width: 400px" type="text" id="nuke-delete-reason" value="' + deleteReason + '"/><br/><a class="wikia-button nuke-submit">Delete</a><div id="nuke-status"/><ul id="nuke-query-results"></ul><a class="wikia-button nuke-submit">Delete</a>');
			$('#nuke-status').html('Getting pages... please wait <img src="' + config.stylepath + '/common/progress-wheel.gif"/>');
 
			API.get({
			action: 'query',
			list: 'usercontribs',
			ucnamespace: $.getUrlVar('nukenamespace') || '',
			ucuser: user,
			uclimit: 5000,
			cb: new Date().getTime() 
			})
			.done(function(d) {
				if (!d.error) {
					var usercontribs = d.query.usercontribs,
					maxLimit = $.getUrlVar('nukelimit') || 500,
					count = 0,
					images = [];
 
					for (var i in usercontribs) {
						if (count >= maxLimit) break;
 
						if (usercontribs[i].hasOwnProperty('new')) {
							var escapedTitle = encodeURIComponent(usercontribs[i].title);
							if (!$.getUrlVar('nukematch') || new RegExp($.getUrlVar('nukematch')).test(usercontribs[i].title)) {
								$('#nuke-query-results').append('<li class="nuke-query-result"><input type="checkbox" class="nuke-title-check" checked="checked"/> <a href="' + config.wgArticlePath + escapedTitle + '" target="_blank">' + usercontribs[i].title + '</a></li>');
								if (usercontribs[i].title.slice(0,5) == "File:")
									images.push(usercontribs[i].title);
								count++;								
							}
						}
					}
					if (!$('.nuke-query-result').length)
						self.outputError("No user contributions found");
					else {
						if (images.length > 0)
							self.displayImages(images);
					}
				}
				else
					self.outputError("Failed to get user contributions: " + d.error.code);
			})
			.fail(function() {
				self.outputError("Failed to get user contributions");
			});
			$('#nuke-status').empty();
		}
		else {
			$('#mw-content-text p').html('This tool allows for mass deletions of pages recently added by a given user or IP address.<br/>Input the username or IP address to get a list of pages to delete, or leave blank for all users.<br/>Username, IP address or blank: <input type="text" id="nuke-username"/><br/>Pattern for the page name: <input type="text" id="nuke-match"/><br/>Limit to namespace: <select id="nuke-namespace"><option value="All">All</option><option value="Main" ns="0">Main</option><option value="Project" ns="4">Project</option><option value="Project talk" ns="5">Project talk</option><option value="Talk" ns="1">Talk</option><option value="User" ns="2">User</option><option value="User talk" ns="3">User talk</option><option value="File" ns="6">File</option><option value="File talk" ns="7">File talk</option><option value="Template" ns="10">Template</option><option value="Template talk" ns="11">Template talk</option><option value="Help" ns="12">Help</option><option value="Help talk" ns="13">Help talk</option><option value="Category" ns="14">Category</option><option value="Category talk" ns="15">Category talk</option></select><br/>Maximum number of pages: <input type="text" id="nuke-max" value="500"/><br/><a class="wikia-button" id="nuke-rc">Go</a><br/><div id="nuke-status"/><div id="nuke-query-results"/>');
 
			$('#nuke-rc').click(function() {
				if ($(this).attr('disabled')) return;
 
				$(this).attr('disabled','disabled');
 
				if ($('#nuke-username').val()) {
					var locationStr = config.wgArticlePath + 'Special:Blankpage?blankspecial=nuke&nukeuser=' + $('#nuke-username').val();
 
					if ($('#nuke-namespace').val() != "All")
						locationStr += '&nukenamespace=' + $('#nuke-namespace option:selected').attr('ns');
 
					if ($.isNumeric($('#nuke-max').val()) && $('#nuke-max').val() > 0)
						locationStr += '&nukelimit=' + $('#nuke-max').val();
 
					if ($('#nuke-match').val())
						locationStr += '&nukematch=' + $('#nuke-match').val();
 
					location.replace(locationStr);
					return;
				}
 
				$('#nuke-query-results').empty();
 
				if ($('.nuke-submit').length) {
					$('.nuke-submit').remove();
					$('#mw-content-text > p:nth-child(1) > br:nth-child(14)').remove();
				}
 
				$('#nuke-status').html('Getting pages... please wait <img src="' + config.stylepath + '/common/progress-wheel.gif"/>');
 
				API.get({	
					action: 'query',
					list: 'recentchanges',
					rcshow: '!bot',
					rctype: 'new|log',
					rclimit: 5000,
					cb: new Date().getTime() 
				})
				.done(function(d) {
					if (!d.error) {
						var recentchanges = d.query.recentchanges,
						RCTitles = [],
						maxLimit = $('#nuke-max').val() || 5000,
						count = 0,
						images = [];
 
						for (var i in recentchanges) {
							if (count >= maxLimit) break;
 
							if ($.inArray(recentchanges[i].title,RCTitles) == -1 && (($('#nuke-namespace').val() == "Main" && recentchanges[i].title.split(':').length === 1) || $('#nuke-namespace').val() == "All" || $('#nuke-namespace').val() == "Project" && new RegExp(config.wgFormattedNamespaces[4] + ':').test(recentchanges[i].title) || $('#nuke-namespace').val() == "Project talk" && new RegExp(config.wgFormattedNamespaces[5] + ':').test(recentchanges[i].title) || new RegExp($('#nuke-namespace').val() + ':').test(recentchanges[i].title)) && (recentchanges[i].type == "new" || (recentchanges[i].type == "log" && recentchanges[i].ns == 6))) { 
								if (!$('#nuke-match').val() || new RegExp($('#nuke-match').val()).test(recentchanges[i].title)) {
									RCTitles.push(recentchanges[i].title);
									var escapedTitle = encodeURIComponent(recentchanges[i].title);
									$('#nuke-query-results').append('<li class="nuke-query-result"><input type="checkbox" class="nuke-title-check" checked="checked"/> <a href="' + config.wgArticlePath + escapedTitle + '" target="_blank"> ' + recentchanges[i].title + '</a></li>');
									if (recentchanges[i].title.slice(0,5) == "File:")
										images.push(recentchanges[i].title);
									count++;
								}
							}
						}
						if (!$('.nuke-query-result').length)
							self.outputError("No recent changes found");
						else {
							$('#nuke-query-results').before('<br/><a class="wikia-button nuke-submit">Delete</a>').after('<a class="wikia-button nuke-submit">Delete</a>');					 
							$('#nuke-status').empty();
							if (images.length > 0)
								self.displayImages(images);
						}
					}
					else
						self.outputError("Failed to get recent changes: " + d.error.code);
				})
				.fail(function() {
					self.outputError("Failed to get recent changes");
				});
				$('#nuke-status').empty();
				$(this).removeAttr('disabled');
			});
		}
 
		$('.nuke-submit').click(function() {
			if (!$('.nuke-query-result').length || $(this).attr('disabled')) return;
 
			$('.nuke-submit').attr('disabled','disabled');
			$('#nuke-status').html('Deleting pages... please wait <img src="' + config.stylepath + '/common/progress-wheel.gif"/>');
			$('.nuke-title-check:checked').each(function(i) {
				var title = $(this).parent().find('a').text();
				setTimeout(function() {
					API.post({
					action: 'delete',
					title: title,
					reason: $('#nuke-delete-reason').val() || '',
					bot: true,
					token: token
					})
					.done(function(d) { 
						if (!d.error) {
							console.log('Deletion of ' + title + ' successful!');
						} 
						else {
							console.log('Failed to delete ' + title + ': '+ d.error.code);
						}
					})
					.fail(function() {
						console.log('Failed to delete ' + title);
					});
					if (i === $('.nuke-title-check:checked').length - 1) {
						setTimeout(function() {
							location.replace(config.wgArticlePath + config.wgMainpage);
						}, 1000);	 
					}
				}, i*deleteDelay);		
			});
		});
	},
	outputError: function(text) {
		switch (config.skin) {
			case 'oasis': 
			case 'wikia':
				new BannerNotification(text,'error').show();				
			break;
 
			default:
				alert(text);
			break;
		}
	},
	displayImages: function(imgs) {
		API.post({ //POST instead of GET for longer length
		action: 'query',
		prop: 'imageinfo',
		titles: imgs.join('|'),
		iiprop: 'url',
		iilimit: 500
		})
		.done(function(d) {
			if (!d.error) {
				for (var i in d.query.pages) {
					if (d.query.pages[i].missing != "") {
						var href = config.wgArticlePath + encodeURIComponent(d.query.pages[i].title);
						$('a[href="' + href + '"]').parent().children('.nuke-title-check').after('<a href="' + href + '"><img class="thumbnail-nuke" src="' + d.query.pages[i].imageinfo[0].url + '" /></a>');
					}
				}
			}
			else
				self.outputError('Failed to display images: ' + d.error.code);
		})
		.fail(function() {	
			self.outputError('Failed to display images');			
		});
	}
};
 
switch (mw.config.get('wgCanonicalSpecialPageName')) {
	case "Contributions":
		$('#contentSub a:last-child').after(' | <a title="Special:Nuke" href="' + mw.config.get('wgArticlePath').replace('$1','Special:Blankpage?blankspecial=nuke&nukeuser=' + mw.config.get('wgPageName').split('/')[1] ) + '">Nuke</a>');
	break;
 
	case "Specialpages":
		if (!$('a[title="Special:Nuke"]').length)
			$('.mw-specialpagerestricted a[title="Special:Undelete"]').after('<li class="mw-specialpagerestricted"><a title="Special:Nuke" href="' + mw.config.get('wgArticlePath').replace('$1','Special:Blankpage?blankspecial=nuke') + '">Mass delete</a></li>');
		else
			$('.mw-specialpagerestricted a[title="Special:Nuke"]').after('<li class="mw-specialpagerestricted"><a title="Special:Nuke" href="' + mw.config.get('wgArticlePath').replace('$1','Special:Blankpage?blankspecial=nuke') + '">Mass delete (JavaScript)</a></li>');		
	break;
 
	case "Blankpage":
		if ($.getUrlVar('blankspecial') == "nuke")
			self.init();
	break;
 
	default:
		return;
	break;
}
 
});