//TODO: Image links, transclusions
moveLinks = {};
(function ($, mw){
if (mw.config.get("wgUserGroups").indexOf("autoconfirmed") === -1 && mw.config.get("wgUserGroups").indexOf("confirmed") === -1){
return;
}
var currentIntervalID, left = 0, target, active = false, origin, limit;
var templatequery, otherquery, transclusionquery;
function confirm(nonredir, redir, transclusions){
if (nonredir + redir + transclusions <= 50) {
limit = 55;
return true;
}
var groups = mw.config.get("wgUserGroups");
if (groups.indexOf("extendedconfirmed") !== -1 || groups.indexOf("sysop") !== -1) {
limit = 100000;
var total = nonredir + redir + trans;
var time = total / 12;
if (nonredir >= 500 || redir >= 500 || transclusions >= 500) {
time = Math.floor(time / 5) * 5;
total = Math.floor(total / 10) * 10;
return window.confirm("This page is linked from at least " +
total + " pages, converting all links will take at least" + time +
" minutes. Some links may not be converted. Do you wish to continue?");
}
time = Math.round(time);
return window.confirm("This page is linked from " + total + " pages, converting all links will take about " + time + " minutes. Do you wish to continue?");
}
limit = 50;
return window.confirm("This page is linked from over 50 pages. As you are not extended confirmed, some links may not be converted. Do you wish to continue?");
}
function run(o, t, templates, redirects, articles, files, other, transclusions){
if (active) {///only allow one copy per page, as we have state
console.log("Only one instance of move links can be run at once.");
return;
}
active = true;
target = t;
origin = o;
var namespaces = [];
if (other) {
for (var ns in mw.config.get("wgFormattedNamespaces")) {
if (ns <= 0 || ns === 6 || ns === 10) {
continue;
}
namespaces.push(ns);
}
}
if (articles) {
namespaces.push(0);
}
if (templates) {
namespaces.push(10);
}
if (files) {
namespaces.push(6);
}
var redir, nonredir = namespaces.length ? undefined : 0, redirquery, trans;
if (redirects) {
$.ajax({
url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=query&format=json&list=backlinks&blfilterredir=redirects&bllimit=500&bltitle=' +
encodeURIComponent(origin),
dataType: "json",
success: function(data){
redir = data.query.backlinks.length;
redirquery = data.query.backlinks;
if (nonredir !== undefined && trans !== undefined) {
if (confirm(nonredir, redir, trans)) {
doConversions(origin, templates, redirects, articles, files, other, transclusions, redirquery);
}
}
},
error: function() {
redir = 0;
console.log("Move links failed to load redirects.");
}
});
}
else {
redir = 0;
}
if (transclusions) {
$.ajax({
url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=query&format=json&prop=transcludedin&tiprop=title&tilimit=500&titles=' +
encodeURIComponent(origin),
dataType: "json",
success: function(data){
for (var p in data.query.pages) {
trans = data.query.pages[p].transcludedin.length;
transclusionquery = data.query.pages[p].transcludedin;
}
left += trans;
if (nonredir !== undefined && redir !== undefined) {
if (confirm(nonredir, redir, trans)) {
doConversions(origin, templates, redirects, articles, files, other, transclusions, redirquery);
}
}
},
error: function() {
redir = 0;
console.log("Move links failed to load transclusions.");
}
});
}
else {
trans = 0;
}
if (namespaces.length) {
$.ajax({
url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=query&format=json&list=backlinks&blfilterredir=nonredirects&bllimit=500&bltitle=' +
encodeURIComponent(origin) + "&blnamespace=" + namespaces.join("%7C"),
dataType: "json",
success: function(data){
nonredir = data.query.backlinks.length;
if (redir !== undefined && trans !== undefined) {
if (confirm(nonredir, redir, trans)) {
doConversions(origin, templates, redirects, articles, files, other, transclusions, redirquery);
}
}
},
error: function() {
nonredir = 0;
console.log("Move links failed to load non-redirects.");
}
});
}
}
//these functions are used when we finish ging through a set of pages
function templateNext(){
if (templatequery) {
left -= templatequery.length;
currentIntervalID = window.setInterval(intervalConversions, 5000, templatequery, othersNext, "link");
}
else {
othersNext();
}
}
function othersNext(){
if (otherquery) {
left -= otherquery.length;
currentIntervalID = window.setInterval(intervalConversions, 5000, otherquery, transclusionsNext, "link");
}
else {
transclusionsNext();
}
}
function transclusionsNext(){
if (transclusionquery) {
left -= transclusionquery.length;
currentIntervalID = window.setInterval(intervalConversions, 5000, transclusionquery, done, "transclusion");
}
else {
done();
}
}
function doConversions(origin, templates, redirects, articles, files, other, transclusions, redirquery){
function next(){
if (redirects) {
currentIntervalID = window.setInterval(intervalConversions, 5000, redirquery, templateNext, "redirect");
}
else {
templateNext();
}
}
$("#move-link-box").html('<span id="move-links-pages-left">Unknown</span> pages remaining (estimated time left: <span id="move-links-time-left">unknown</span>)');
var namespaces = [];
if (other) {
for (var ns in mw.config.get("wgFormattedNamespaces")) {
if (ns <= 0 || ns === 6 || ns === 10) {
continue;
}
namespaces.push(ns);
}
}
if (articles) {
namespaces.push(0);
}
if (files) {
namespaces.push(6);
}
if (articles || files || other) {
$.ajax({
url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=query&format=json&list=backlinks&blfilterredir=nonredirects&bllimit=500&bltitle=' +
encodeURIComponent(origin) + "&blnamespace=" + namespaces.join("%7C"),
dataType: "json",
success: function(data){
otherquery = data.query.backlinks;
left += otherquery.length;
if (templatequery !== undefined) {
next();
}
},
error: function() {
nonredir = 0;
console.log("Move links failed to load others, artciles and files.");
}
});
}
else{
otherquery = null;
}
if (templates) {
$.ajax({
url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=query&format=json&list=backlinks&blfilterredir=nonredirects&bllimit=500&bltitle=' +
encodeURIComponent(origin) + "&blnamespace=10",
dataType: "json",
success: function(data){
templatequery = data.query.backlinks;
left += templatequery.length;
if (otherquery !== undefined) {
next();
}
},
error: function() {
nonredir = 0;
console.log("Move links failed to load templates.");
}
});
}
else{
templatequery = null;
}
}
function intervalConversions(links, next, type) {
if (links.length === 0) {
//complete
window.clearInterval(currentIntervalID);
next();
return;
}
var pagesLeft = Math.min(links.length + left, limit);
var timeLeft = Math.floor(pagesLeft/12) + ":" + (((pagesLeft % 12) * 5).toString().padStart(2, "0"));//format time as m:ss
if (limit-- <= 0) {// we have done the maximum number of edits.
window.clearInterval(currentIntervalID);
done();
return;
}
$("#move-links-pages-left").text(pagesLeft.toString());
$("#move-links-time-left").text(timeLeft);
var link = links.pop();
var title = link.title;
$.getJSON(
mw.util.wikiScript('api'),
{
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'content',
rvlimit: 1,
titles: title
}
)
.done(function ( data ) {//FIXME
var page, wikitext;
//try {
for ( page in data.query.pages ) {
wikitext = data.query.pages[page].revisions[0]['*'];
convertWikitext(wikitext, title, type);
}
//} catch ( e ) {
// console.log("Failed to edit " + title);
//}
})
.fail( function() {
console.log("Failed to edit " + title);
});
}
function done(){
active = false;
$("#move-link-box").html('<b>Done</b><br/>Check <b><a href="/wiki/Special:WhatLinksHere/' + encodeURIComponent(origin) + '">What links here</a></b>, as some links may not have been updated.');
}
function convertWikitext(wikitext, title, type){
var head, tail;
if (mw.config.get("wgNamespaceIds")[origin.split(":")[0].toLowerCase().replace(/ /g, "_")]) {// get namespace ids, check if namespae is valid (in lowercase, spaces replaced with _)
head = origin.split(":")[0] + ":" + origin.split(":")[1].charAt();//first char and namespace is case insensitive
}
else {
head = origin.charAt();//first char is case insensitive
}
tail = origin.slice(head.length).replace(/[.*+?^${}()|[\]\\\/]/g, '\\$&').replace(/[ _]/g, "[ _]");//tail is not case insensitive, but is escaped,spaces and underscores are identical
var safeHead = "";
for (var i = 0; i < head.length; i++) {
if (head.charAt(i).toLowerCase() === head.charAt(i).toUpperCase()) {
safeHead = safeHead + head.charAt(i).replace(/[.*+?^${}()|[\]\\\/]/g, '\\$&').replace(/[ _]/g, "[ _]");//escape this, it could be bad, also do spaces
}
else {
safeHead = safeHead + "[" + head.charAt(i).toLowerCase() + head.charAt(i).toUpperCase() + "]";//add both variants
}
}
var newWikitext;
switch (type) {//
case "redirect":
var re = new RegExp("(\\[\\[\\s*:?\\s*)" + safeHead + tail + "((#[^[\\]]*)?\\s*(\\|[^[\\n]+)?\\]\\])", "g");
newWikitext = wikitext.replace(re, "$1" + target + "$2");//convert redirect
break;
case "transclusion":
if (safeHead.len <= 4) {//mainspace needs :
safeHead = ":" + safeHead;
}
else if (mw.config.get("wgNamespaceIds")[origin.split(":")[0].toLowerCase().replace(/ /g, "_")] === 10) {//templates do not need prefix
safeHead = "(?::?" + safeHead.split(":")[0] + ":)?" + safeHead.split(":")[1];//use non-capturing group to not confuse replace()
}
else {//colon is optional otherwise
safeHead = ":?" + safeHead;
}
var re = new RegExp("(\\{\\{\\s*)" + safeHead + tail + "(\\s*(\\||\\}\\}))", "g");
newWikitext = wikitext.replace(re, "$1" + target + "$2");//convert template
break;
default:
var pipeRe = new RegExp("(\\[\\[\\s*:?\\s*)" + safeHead + tail + "((#[^[\\]]*)?\\s*\\|[^[\\n]+\\]\\])", "g");
var noPipeRe = new RegExp("(\\[\\[\\s*:?\\s*)(" + safeHead + tail + "(#[^[\\]|]*)?\\s*\\]\\])", "g");
var fairUseRe = new RegExp("(\\{\\{\\s*([Nn]on-free (use rationale( 2| logo)?|(media|image) rationale)|[Ll]ogo fur)\\s*\\|([^}]}?)*?\\|\\s*[Aa]rticle\\s*=\\s*)" + safeHead + tail + "(\s*\|.*?\}\})", "gs");//match all fair-use templates with >1000 uses
newWikitext = wikitext.replace(pipeRe, "$1" + target + "$2");//convert the links
newWikitext = newWikitext.replace(noPipeRe, "$1" + target + "$3|$2");//convert the links
newWikitext = newWikitext.replace(fairUseRe, "$1" + target + "$7");//convert fair use template
}
if (newWikitext === wikitext) {
//no changes, purge the page
$.ajax({
url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=purge&format=json&forcelinkupdate=1&titles=' +
encodeURIComponent(title),
dataType: "json"
});
}
else {
//save changes
$.ajax({
url: mw.util.wikiScript( 'api' ),
type: 'POST',
dataType: 'json',
data: {
format: 'json',
action: 'edit',
title: title,
text: newWikitext,
summary: "Converted links from [[" + origin + "]] to [[" + target + "]] ([[User:Danski454/move-links|move links]])",
minor: true,
token: mw.user.tokens.get( 'editToken' )
}
})
.fail(function(){
console.log("Could not save " + title);
});
}
}
$(document).ready(function(){
if (mw.config.get("wgPageName") === "Special:MovePage" && $("h1").first().text() === "Move succeeded") {
load();
}
});
function start(){
var t, o;
o = $("#mw-content-text p").first().find("b a").first().text();
t = $($("#mw-content-text p").first().find("b a")[1]).text();
run(o, t, $('#move-link-templates').is(':checked'), $('#move-link-redir').is(':checked'),
$('#move-link-article').is(':checked'), $('#move-link-file').is(':checked'), $('#move-link-other').is(':checked'), $('#move-link-trans').is(':checked'));
}
function load(){
$("#mw-content-text").append('<div id="move-link-box"><b>Update links from</b><br/><input type="checkbox" value="redirects" id="move-link-redir" checked /> Redirects <input type="checkbox" value="templates" id="move-link-templates" checked /> Templates <input type="checkbox" value="articles" id="move-link-article" checked /> Articles <input type="checkbox" value="files" id="move-link-file" checked /> Files <input type="checkbox" value="others" id="move-link-other" /> Others <input type="checkbox" value="others" id="move-link-trans" /> Transclusions<br/><input id="move-links-go" type="button" value="Submit" onclick="moveLinks.start();" /></div>');
}
moveLinks.start = start;
moveLinks.run = run;
moveLinks.load = load;
})(jQuery, mediaWiki);