/* Ajax batch move module, version [0.0.3c]
Originally from: http://en.wikipedia.org/wiki/User:Splarka/ajaxbatchmove.js
Notes:
* It is a bit verbose, after debugging perhaps some output should be removed.
* It waits 1 second after every move before starting the next.
* Can be aborted by simply deleting the contents of the textarea, or leaving the page.
* Stops when it hits a blank line, or line with no pipe.
* Nonfatal errors (skip to next line):
** Bad character or malformed line
** Bad token
** Unexpected response
* Pauses in execution can be added with a blank line.
* Not been postively tested! As of this writing API moves are broken on test.wikipedia [5:23 PM 3/13/09]
* Suppressing redirects should work, maybe. I didn't bother with move subpage/talkpage switches, too scary!
To do:
* Cache the token if two the same?
** Please note the move token is not guaranteed to be static, but currently it always is.
*/
$(function() {
mw.util.addPortletLink('p-tb','/wiki/Special:BlankPage?blankspecial=ajaxbm','Batch Move');
});
if(wgCanonicalSpecialPageName && wgCanonicalSpecialPageName.toLowerCase() == 'blankpage' && queryString('blankspecial') == 'ajaxbm') {
document.title = 'Ajax Batch Move';
addOnloadHook(abmForm);
}
function abmForm() {
mw.util.addPortletLink('p-tb','/wiki/Special:Log/move?user=' + encodeURIComponent(wgUserName),'My move log');
//subvert this Special: page to our own needs.
var con = document.getElementById('content') || document.getElementById('mw_content');
var bcon = document.getElementById('bodyContent') || document.getElementById('mw_contentholder');
var fh = getElementsByClassName(con,'h1','firstHeading')[0];
while(fh.firstChild) fh.removeChild(fh.firstChild)
fh.appendChild(document.createTextNode('Ajax Batch Move'));
for(var i=0;i<bcon.childNodes.length;i++) {
bcur = bcon.childNodes[i];
if(bcur.id != 'siteSub' && bcur.id != 'contentSub' && bcur.className != 'visualClear') {
while(bcur.firstChild) bcur.removeChild(bcur.firstChild)
if(bcur.nodeType == 3) bcur.nodeValue = '';
}
}
//generate content (this is ugly yes, but better than innerHTML and very portable; only needs wikibits.js)
var form = document.createElement('form');
form.appendChild(document.createTextNode('Enter the pages to be moved here, one per line, with the format: Old title|New title'));
form.setAttribute('action','javascript:void(0)');
form.appendChild(document.createElement('p'));
form.setAttribute('action','javascript:void(0);');
var txt = document.createElement('textarea');
txt.style.height = '20em';
txt.style.width = '50%';
txt.setAttribute('id','abm-textarea');
form.appendChild(txt);
form.appendChild(document.createElement('p'));
var lab1 = document.createElement('label');
lab1.setAttribute('for','abm-reason')
lab1.appendChild(document.createTextNode('Move reason: '));
form.appendChild(lab1);
var inp1 = document.createElement('input');
inp1.style.width = '20em';
inp1.setAttribute('type','text');
inp1.setAttribute('id','abm-reason');
form.appendChild(inp1);
var inp2 = document.createElement('input');
inp2.setAttribute('type','checkbox');
inp2.setAttribute('id','abm-redirect');
form.appendChild(inp2);
var lab2 = document.createElement('label');
lab2.setAttribute('for','abm-redirect')
lab2.appendChild(document.createTextNode('Suppress redirects'));
form.appendChild(lab2);
form.appendChild(document.createElement('p'));
var sub1 = document.createElement('input');
sub1.setAttribute('type','button');
sub1.setAttribute('id','abm-startbutton');
sub1.setAttribute('value','start');
addHandler(sub1,'click',abmStart);
form.appendChild(sub1);
bcon.appendChild(form);
var pre = document.createElement('pre');
pre.setAttribute('id','abm-output');
bcon.appendChild(pre);
}
function abmStart() {
document.getElementById('abm-startbutton').setAttribute('disabled','disabled');
var out = document.getElementById('abm-output');
var txt = document.getElementById('abm-textarea');
var moves = txt.value.split('\n');
var move = moves[0];
if(move.indexOf('|') == -1 || move == '') {
out.appendChild(document.createTextNode('* Done! Nothing left to do, or next line is blank.\n'));
document.getElementById('abm-startbutton').removeAttribute('disabled');
} else {
var badchars = /(\#|\<|\>|\[|\]|\{|\}|\|.*\|)/;
if(badchars.test(move)) {
out.appendChild(document.createTextNode('! Illegal characters detected, skipping:' + move + '\n'));
setTimeout('abmStart()',1000);
} else {
var oldtitle = move.substr(0,move.indexOf('|'));
var newtitle = move.substr(move.indexOf('|')+1);
out.appendChild(document.createTextNode('> Attempting to move [[' + oldtitle + ']] to [[' + newtitle + ']]\n'));
abdGetToken(oldtitle,newtitle);
}
}
moves = moves.slice(1,moves.length);
txt.value = moves.join('\n');
}
function abdGetToken(oldtitle,newtitle) {
var out = document.getElementById('abm-output');
out.appendChild(document.createTextNode(' > Fetching move token for [[' + oldtitle + ']]\n'));
var url = wgScriptPath + '/api.php?action=query&prop=info&indexpageids=1&intoken=move&format=json&titles=' + encodeURIComponent(oldtitle);
var req = sajax_init_object();
req.open('GET', url, true);
req.onreadystatechange = function() {
if(req.readyState == 4 && req.status == 200) {
eval("abmMove(" + req.responseText + ",'" + req.responseText.replace(/\'/g,"`") + "','" + oldtitle + "','" + newtitle + "')");
}
}
req.send(null);
}
function abmMove(obj,txt,oldtitle,newtitle) {
var out = document.getElementById('abm-output');
if(obj['error']) {
out.appendChild(document.createTextNode(' ! Api error: ' + obj['error']['code'] + ' - ' + obj['error']['info'] + '\n'));
return;
}
if(!obj['query'] || !obj['query']['pageids'] || !obj['query']['pages'][obj['query']['pageids'][0]] || !obj['query']['pages'][obj['query']['pageids'][0]]['movetoken']) {
out.appendChild(document.createTextNode(' ? Unexpected response: ' + txt + '\n'));
return;
}
var token = obj['query']['pages'][obj['query']['pageids'][0]]['movetoken'];
out.appendChild(document.createTextNode(' > Token found, attempting move\n'));
var reason = document.getElementById('abm-reason').value;
var params = 'action=move&format=json&token=' + encodeURIComponent(token) + '&from=' + encodeURIComponent(oldtitle) + '&to=' + encodeURIComponent(newtitle) + '&reason=' + encodeURIComponent(reason);
if(document.getElementById('abm-redirect').checked) params += '&noredirect=1'
var url = wgScriptPath + '/api.php';
var req = sajax_init_object();
req.open('POST', url, true);
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
req.setRequestHeader('Content-length', params.length);
req.setRequestHeader('Connection', 'close');
req.onreadystatechange = function() {
if(req.readyState == 4 && req.status == 200) {
eval("abmMoveAftermath(" + req.responseText + ",'" + req.responseText.replace(/\'/g,"`") + "')");
}
}
req.send(params);
}
function abmMoveAftermath(obj,txt) {
var out = document.getElementById('abm-output');
//{"error":{"code":"Invalid token","info":"badtoken"}}
//{"move": {"from": "User:Splarka\/cat","to": "User:Splarka\/cattest","reason": "better name","redirectcreated": ""}}
if(obj['error']) {
out.appendChild(document.createTextNode(' ! Api error: ' + obj['error']['code'] + ' - ' + obj['error']['info'] + '\n'));
} else if(obj['move'] && obj['move']['from'] && obj['move']['to']) {
out.appendChild(document.createTextNode(' > Page [[' + obj['move']['from'] + ']] moved to [[' + obj['move']['to'] + ']]\n'));
} else {
out.appendChild(document.createTextNode(' ? Unexpected response: ' + txt + '\n'));
}
setTimeout('abmStart()',1000);
}
function queryString(p) {
var re = RegExp('[&?]' + p + '=([^&]*)');
var matches;
if (matches = re.exec(document.location)) {
try {
return decodeURI(matches[1]);
} catch (e) {
}
}
return null;
}