User:XXN/QuickVoteDR.js
< User:XXN
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
Documentation for this user script can be added at User:XXN/QuickVoteDR. |
/**
Quick voting on deletion requests.
IE not supported, probably
* required modules: user.options, mediawiki.util, jquery.blockUI
**/
//<nowiki>
/*global mediaWiki:false, jQuery:false, prompt:false, alert:false*/
/*jshint bitwise:true, curly:false, eqeqeq:true, forin:false, laxbreak:true,
trailing:true, undef:true, unused:true, white:false, smarttabs:true */
(function($, mw) {
'use strict';
// Guard against double inclusions
if ('object' === typeof DelReqHandler) return;
var DelReqHandler = window.DelReqHandler = {
/*------------------------------------------------------------------------------------------
Deletion request: add "[del]" links to the left of the section edit
links of a deletion request. [del] prompt for an (optional) reason, then
add the reason and signature (four tildes).
------------------------------------------------------------------------------------------*/
running: [],
parse: function () {
var $content = $('#bodyContent, #mw_contentholder');
if (!$content.length) return;
//mw.util.addCSS('.reqHandlerLinks {font-size: 85%;}'); replaced by class navbar
var linkRegex = /Commons:Deletion_requests\/.*?§ion=(T-)?[1-4]$/;
$content.find('h3').each(function () {
var $t = $(this);
var headLine = $t.find('span.mw-headline').eq(0);
var requestHref = $t.find('span.mw-editsection a').not('.mw-editsection-visualeditor').eq(0).attr('href');
// It's really an edit lk to a deletion request subpage, and not a section
// edit for a daily subpage or something else
if (!linkRegex.test(requestHref)) return true;
var headLink = headLine.find('a').not('.new').eq(0);
var title = (headLink.length) ? DelReqHandler.titleFromHref(headLink.attr('href')) : "";
var requestPage = DelReqHandler.titleFromHref(requestHref);
var discussion = $t.nextUntil('h3, .printfooter, .delh');
var wholeDiscussion = discussion.add($t);
if (!$t.parents('.delh').length)
DelReqHandler.addLinks(requestPage, headLine, title, true, wholeDiscussion);
discussion.find('a').not('.new').add(headLink).each(function () {
var title = DelReqHandler.titleFromHref(this.href);
if ((title.indexOf('File:') === 0 || title.indexOf('Files uploaded') === 0) && title.indexOf('/') < 0)
//We have an image link or group of files in DR
DelReqHandler.addLinks(requestPage, $(this), title, false, wholeDiscussion);
});
});
},
titleFromHref: function (href) {
if (href) {
var title = mw.util.getParamValue('title', href);
if (title) return title.replace(/_/g, ' ');
var prefix = mw.config.get('wgArticlePath').replace('$1', "");
// Fully expanded URL?
if (href.indexOf(prefix) !== 0) prefix = mw.config.get('wgServer') + prefix;
if (href.indexOf(prefix) !== 0 && prefix.indexOf('//') === 0) prefix = document.location.protocol + prefix; // protocol-relative wgServer?
if (href.indexOf(prefix) === 0) return decodeURIComponent(href.substring(prefix.length)).replace(/_/g, ' ');
}
return "";
},
addLinks: function (requestPage, location, closeRequest, voteD, discussion) {
var span = $('<span/>', { 'class': 'navbar' });
function _click (e) {
// Use link.name for keep boolean
e.preventDefault();
e = new DelReqHandler.process(e.target.name, closeRequest, voteD, requestPage, [location, span, discussion]);
DelReqHandler.running.push(e);
}
var linkK = $('<a/>', { href: '#', 'name': 1, 'click': _click }),
linkD = $('<a/>', { href: '#', 'click': _click });
linkK.text('Del');
linkD.text('Close: Deleted');
span.append(' [').append(linkK).append('] [').append(linkD).append(']');
location.after(span);
},
setup: function () {
if (mw.config.get('wgPageName').indexOf('Commons:Deletion_requests/') !== -1 && mw.config.get('wgAction') === 'view' && document.URL.search(/[?&]oldid=/) === -1) {
// We're on COM:DEL or one of its daily subpages
// Don't do anything if we're not viewing the current version of the page
this.parse();
}
},
process: function (keep, del, closeRequestBool, voteDBool, requestPage) {
//Merge the page processing functions into our new process
$.extend(this, DelReqHandler.processHelpers);
var delReqReason = window.delReqReason || "per nomination.";
// var keepReqReason = window.keepReqReason || "no valid reason for deletion";
this.tasks = [];
this.requestPage = requestPage.replace(/_/g, ' ');
this.keep = keep;
this.del = del;
this.closeRequestBool = closeRequestBool;
this.voteDBool = voteDBool;
this.summary = 'Per [[' + requestPage + ']]';
//getToken
this.addTask('getPages');
if (closeRequestBool) {
if (keep) {
this.reason = prompt('Why do you want to delete this file?', delReqReason);
//User canceled
if (!this.reason) return;
this.pagesToGet = [requestPage];
}
this.addTask('closeRequest');
} else if (voteDBool) {
if (del) {
this.reason = prompt('Result?', delReqReason);
if (!this.reason) return;
this.pagesToGet = [requestPage];
}
this.addTask('voteD');
} else {
this.pagesToGet = [requestPage];
this.summary = prompt("Summary:", this.summary);
//User canceled
if (!this.summary) return;
}
this.nextTask();
}
};
DelReqHandler.processHelpers = {
getPages: function () {
var query = {
action: 'query',
prop: 'revisions|info',
rvprop: 'content|timestamp',
intoken: 'edit',
titles: this.pagesToGet.join('|')
};
this.doAPICall(query, 'getPagesCallback');
},
getPagesCallback: function (result) {
var pages = result.query.pages;
for (var id in pages) { // there should be only one, but we don't know it's ID
if (pages.hasOwnProperty(id)) {
// The edittoken only changes between logins
this.edittoken = pages[id].edittoken;
var type;
switch (pages[id].title) {
case this.requestPage:
type = 'requestPage';
break;
default:
type = 'unknown';
break;
}
this[type + 'Result'] = {
pageContent: pages[id].revisions[0]['*']
};
}
}
this.nextTask();
},
closeRequest: function () {
var text = this.requestPageResult.pageContent,
watchFor = '<noinclude>[[Category:MobileUpload-related deletion requests', replace = ']]</noinclude>';
this.decision = (this.del) ? 'Deleted' : 'Kept';
text = text.replace(watchFor + replace, watchFor + '/' + this.decision.toLowerCase() + replace);
// Check for second nomination (we always load the full page)
var sec = text.lastIndexOf('{{delf}}\n') + 9; // Additional more accurately: text.substr(sec).search(/^==+/m) but not really needed
text = (sec > 51) ? // minimum text-size
text.slice(0, sec) + '{{delh}}\n' + $.trim(text.slice(sec)) : '{{delh}}\n' + $.trim(text);
text += '\n----\n';
// Add dashes on 'lesser' individual signatures
var uSig = (mw.user.options.get('fancysig') && mw.user.options.get('nickname').search(/^[ ']*\[\[/) !== 0)?
'' : '--';
if (this.reason) {
this.decision += ':';
this.reason = this.reason.replace(/[.\s-]*$/, '. ');
}
else this.decision += '.';
text += "'''" + this.decision + "''' " + this.reason + uSig + '<nowiki>~~~~</nowiki>\n{{delf}}';
var page = {
title: this.requestPage,
text: text,
summary: this.decision + ' ' + this.reason,
editType: 'text'
};
this.savePage(page, 'nextTask');
},
voteD: function () {
var textvoted = this.requestPageResult.pageContent;
this.decision = (this.keep) ? 'Delete' : 'Keep';
// Add dashes on 'lesser' individual signatures
var uSig2 = (mw.user.options.get('fancysig') && mw.user.options.get('nickname').search(/^[ ']*\[\[/) !== 0)?
'' : '--';
if (this.reason) {
this.reason = this.reason.replace(/[.\s-]*$/, '. ');
textvoted += "\n*{{vd}}: " + this.reason + uSig2 + '<nowiki>~~~~</nowiki>';
}
else textvoted += "\n*{{vd}}. " + uSig2 + '<nowiki>~~~~</nowiki>';
var page1 = {
title: this.requestPage,
text: textvoted,
summary: this.decision + ' (using [[User:XXN/QuickVoteDR.js|script]])',
editType: 'text'
};
this.savePage(page1, 'nextTask');
},
apiURL: mw.util.wikiScript('api'),
currentTask: '',
addTask: function (task) {
this.tasks.push(task);
},
nextTask: function () {
var task = this.currentTask = this.tasks.shift();
try {
this[task]();
} catch (e) {
this.fail(e);
}
},
savePage: function (page, callback) {
var edit = {
action: 'edit',
summary: page.summary,
title: page.title,
token: this.edittoken
};
edit[page.editType] = page.text;
this.doAPICall(edit, callback);
},
fail: function (e) {
alert(e);
},
doAPICall: function (params, callback, ignoreErrors) {
var k = this;
params.format = 'json';
$.ajax({
url: this.apiURL,
cache: false,
dataType: 'json',
data: params,
type: 'POST',
success: function (result, status, x) {
if (ignoreErrors) {
k[callback](result);
return;
}
if (!result) return k.fail("Receive empty API response:\n" + x.responseText);
// In case we get the mysterious 231 unknown error, just try again
if (result.error && result.error.info.indexOf('231') !== -1) return setTimeout(function () {
k.doAPICall(params, callback);
}, 500);
if (result.error) return k.fail("API request failed (" + result.error.code + "): " + result.error.info);
k[callback](result);
},
error: function (x, status, error) {
return k.fail("API request returned code " + x.status + " " + status + "Error code is " + error);
}
});
},
nothing: function () {
//nothing
}
};
mw.loader.using('user.options', function () { $(DelReqHandler.setup()); });
})(jQuery, mediaWiki);
//</nowiki>