User:GroovySandwich/monobook.js

var popupVersion="Fri Jul 28 11:40:49 EDT 2006 bugfix(2)";

// STARTFILE: main.js

// **********************************************************************

// ** **

// ** changes to this file affect many users. **

// ** please discuss on the talk page before editing **

// ** **

// **********************************************************************

// ** **

// ** if you do edit this file, be sure that your editor recognizes it **

// ** as utf8, or the weird and wonderful characters in the namespaces **

// ** below will be completely broken. You can check with the show **

// ** changes button before submitting the edit. **

// ** test: مدیا מיוחד Мэдыя **

// ** **

// **********************************************************************

////////////////////////////////////////////////////////////////////

// Import stylesheet(s)

//

if ( window.localCSS ) {

document.write('');

} else {

document.write('');

}

//////////////////////////////////////////////////

// Globals

//

// Trying to shove as many of these as possible into the pg (popup globals) object

function pg(){}; // dummy to stop errors

window.pg = {

re: {}, // regexps

ns: {}, // namespaces

string: {}, // translatable strings

wiki: {}, // local site info

misc: {}, // YUCK PHOOEY

option: {}, // options, see newOption etc

optionDefault: {}, // default option values

flag: {}, // misc flags

cache: {}, // page and image cache

structures: {}, // navlink structures

timer: {}, // all sorts of timers (too damn many)

counter: {}, // .. and all sorts of counters

current: {}, // state info

endoflist: null

};

window.pop = { // wrap various functions in here

init: {},

util: {},

endoflist: null

};

function popupsReady() {

if (!window.pg) { return false; }

if (!pg.flag) { return false; }

if (!pg.flag.finishedLoading) { return false; }

return true;

}

////////////////////////////////////////////////////////////////////

// Run things

////////////////////////////////////////////////////////////////////

addOnloadHook(setupPopups);

/// Local Variables: ///

/// mode:c ///

/// End: ///

// ENDFILE: main.js

// STARTFILE: actions.js

function setupTooltips(container, remove) {

log('setupTooltips, container='+container+', remove='+remove);

if (!container) {

//

// the main initial call

if (getValueOf('popupOnEditSelection') && window.doSelectionPopup ) {

try {

document.editform.wpTextbox1.onmouseup=function() { doSelectionPopup(); };

} catch (neverMind) {}

}

//

// article/content is a structure-dependent thing

container = defaultPopupsContainer();

}

if (!remove && container.ranSetupTooltipsAlready) { return; }

container.ranSetupTooltipsAlready = !remove;

var anchors;

anchors=container.getElementsByTagName('A');

setupTooltipsLoop(anchors, 0, 250, 100, remove);

}

function defaultPopupsContainer() {

if (getValueOf('popupOnlyArticleLinks')) {

return document.getElementById('article') ||

document.getElementById('content') || document;

}

return document;

}

function setupTooltipsLoop(anchors,begin,howmany,sleep, remove) {

log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments));

var finish=begin+howmany;

var loopend = min(finish, anchors.length);

var j=loopend - begin;

log ('setupTooltips: anchors.length=' + anchors.length + ', begin=' + begin +

', howmany=' + howmany + ', loopend=' + loopend + ', remove=' + remove);

var doTooltip= remove ? removeTooltip : addTooltip;

// try a faster (?) loop construct

if (j > 0) {

do {

var a=anchors[loopend - j];

if (!a || !a.href) {

log('got null anchor at index ' + loopend - j);

continue;

}

doTooltip(a);

} while (--j);

}

if (finish < anchors.length) {

setTimeout(function() {setupTooltipsLoop(anchors,finish,howmany,sleep,remove);}, sleep);

} else {

if ( !remove && ! getValueOf('popupTocLinks')) { rmTocTooltips(); }

pg.flag.finishedLoading=true;

}

}

// eliminate popups from the TOC

// This also kills any onclick stuff that used to be going on in the toc

function rmTocTooltips() {

//console.log('rmTocTooltips');

var toc=document.getElementById('toc');

if (toc) {

var tocLinks=toc.getElementsByTagName('A');

var tocLen = tocLinks.length;

for (j=0; j

//console.log ('killing popup for toclinks[' + j + ']');

removeTooltip(tocLinks[j], true);

}

}

}

function addTooltip(a) {

if ( !isPopupLink(a) ) { return; }

a.onmouseover=mouseOverWikiLink;

a.onmouseout= mouseOutWikiLink;

a.onclick= killPopup;

a.hasPopup = true;

if (getValueOf('removeTitles') && typeof a.originalTitle=='undefined') {

a.originalTitle=a.title;

a.title='';

}

}

function removeTooltip(a) {

if ( !a.hasPopup ) { return; }

a.onmouseover = null;

a.onmouseout = null;

if (a.originalTitle) { a.title = a.originalTitle; }

a.hasPopup=false;

}

function registerHooks(np) {

var popupMaxWidth=getValueOf('popupMaxWidth');

if (typeof popupMaxWidth == 'number') {

var setMaxWidth = function () {

np.mainDiv.style.maxWidth = popupMaxWidth + 'px';

np.maxWidth = popupMaxWidth;

// hack for IE

// see http://www.svendtofte.com/code/max_width_in_ie/

// use setExpression as documented here on msdn: http://tinyurl dot com/dqljn

if (np.mainDiv.style.setExpression) {

np.mainDiv.style.setExpression(

'width', 'document.body.clientWidth > ' +

popupMaxWidth + ' ? "' +popupMaxWidth + 'px": "auto"');

}

};

np.addHook(setMaxWidth, 'unhide', 'before');

}

//

if (window.addPopupShortcuts && window.rmPopupShortcuts) {

np.addHook(addPopupShortcuts, 'unhide', 'after');

np.addHook(rmPopupShortcuts, 'hide', 'before');

}

//

}

function mouseOverWikiLink() {

if (!window.popupsReady || !window.popupsReady()) { return; }

return mouseOverWikiLink2(this);

}

function footnoteTarget(a) {

var aTitle=Title.fromAnchor(a);

// We want ".3A" rather than "%3A" or "?" here, so use the anchor property directly

var anch = aTitle.anchor;

if ( ! /^(_note-|endnote)/.test(anch) ) { return false; }

var lTitle=Title.fromURL(location.href);

if ( lTitle.toString(true) != aTitle.toString(true) ) { return false; }

var el=document.getElementById(anch);

while ( el && typeof el.nodeName == 'string') {

var nt = el.nodeName.toLowerCase();

if ( nt == 'li' ) { return el; }

else if ( nt == 'body' ) { return false; }

else if ( el.parentNode ) { el=el.parentNode; }

else { return false; }

}

return false;

}

function footnotePreview(x, navpop) {

setPopupHTML('


' + x.innerHTML, 'popupPreview', navpop.idNumber,

getValueOf('popupSubpopups') ? function() {

setupTooltips(document.getElementById('popupPreview' + navpop.idNumber));

} : null);

}

function mouseOverWikiLink2(a) {

// try not to duplicate effort

if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; }

pg.current.link=a;

if (getValueOf('simplePopups') && pg.option.popupStructure===null) {

// reset *default value* of popupStructure

setDefault('popupStructure', 'original');

}

var article=(new Title()).fromAnchor(a);

// set global variable (ugh) to hold article (wikipage)

pg.current.article = article;

if (pg.timer.image !== null) {

clearInterval(pg.timer.image);

pg.timer.image=null;

pg.counter.checkImages=0;

}

if (!a.navpopup) {

// FIXME: this doesn't behave well if you mouse out of a popup

// directly into a link with the same href

if (pg.current.linksHash[a.href] && false) {

a.navpopup = pg.current.linksHash[a.href];

}

else {

a.navpopup=newNavpopup(a, article);

pg.current.linksHash[a.href] = a.navpopup;

pg.current.links.push(a);

}

}

if (a.navpopup.pending===null || a.navpopup.pending!==0) {

// either fresh popups or those with unfinshed business are redone from scratch

simplePopupContent(a, article);

}

a.navpopup.showSoonIfStable(a.navpopup.delay);

getValueOf('popupInitialWidth');

clearInterval(pg.timer.checkPopupPosition);

pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600);

if(getValueOf('simplePopups')) { return; }

if (a.navpopup.pending!==0 ) {

//console.log('a.navpopup.pending='+a.navpopup.pending);

nonsimplePopupContent(a, article);

}

}

// simplePopupContent: the content that is shown even when simplePopups is true

function simplePopupContent(a, article) {

a.navpopup.setInnerHTML(popupHTML(a));

fillEmptySpans({navpopup:a.navpopup});

var dragHandle = getValueOf('popupDragHandle') || null;

if (dragHandle && dragHandle != 'all') {

dragHandle += a.navpopup.idNumber;

}

setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150);

//

/* FIXME hack */ a.navpopup.hasPopupMenu=false;

if (getValueOf('popupRedlinkRemoval') && a.className=='new') {

setPopupHTML('
'+popupRedlinkHTML(article), 'popupRedlink', a.navpopup.idNumber);

}

//

}

function debugData(navpopup) {

if(getValueOf('popupDebugging') && navpopup.idNumber) {

setPopupHTML('idNumber='+navpopup.idNumber + ', pending=' + navpopup.pending,

'popupError', navpopup.idNumber);

}

}

function newNavpopup(a, article) {

var navpopup = new Navpopup();

navpopup.fuzz=5;

navpopup.delay=getValueOf('popupDelay')*1000;

// increment global counter now

navpopup.idNumber = ++pg.idNumber;

navpopup.parentAnchor = a;

navpopup.article = article;

registerHooks(navpopup);

return navpopup;

}

function nonsimplePopupContent(a, article) {

//console.log('nonsimplePopupContent');

var diff=null, history=null;

var params=parseParams(a.href);

var oldid=(typeof params.oldid=='undefined' ? null : params.oldid);

//

if(getValueOf('popupPreviewDiffs') && window.loadDiff) {

diff=params.diff;

}

if(getValueOf('popupPreviewHistory') && getValueOf('popupUseQueryInterface')) {

history=(params.action=='history');

}

//

a.navpopup.pending=0;

var previewImage=true;

var x;

pg.misc.gImage=null;

if (x=footnoteTarget(a)) {

footnotePreview(x, a.navpopup);

//

} else if ( diff || diff === 0 ) {

//alert([article,oldid,diff]);

loadDiff(article, oldid, diff, a.navpopup);

} else if ( history && getValueOf('popupUseQueryInterface') ) {

loadQueryPreview('history', article, a.navpopup);

} else if ( pg.re.contribs.test(a.href) && getValueOf('popupUseQueryInterface')) {

loadQueryPreview('contribs', article, a.navpopup);

} else if ( // FIXME should be able to get all preview combinations with options

article.namespace()==pg.ns.image &&

( getValueOf('imagePopupsForImages') || ! anchorContainsImage(a) )

) {

if (getValueOf('popupUseQueryInterface')) {

loadQueryPreview('imagepagepreview', article, a.navpopup);

} else { startArticlePreview(article, oldid, a.navpopup); }

loadImages(article);

//

} else if (article.namespace() == pg.ns.category &&

getValueOf('popupCategoryMembers')) {

getValueOf('popupUseQueryInterface') &&

loadQueryPreview('category', article, a.navpopup);

startArticlePreview(article, oldid, a.navpopup);

}

else if (!article.namespace()!=pg.ns.image && previewImage ) {

startArticlePreview(article, oldid, a.navpopup);

}

}

function pendingNavpopTask(navpop) {

if (navpop && navpop.pending===null) { navpop.pending=0; }

++navpop.pending;

debugData(navpop);

}

function completedNavpopTask(navpop) {

//console.log('completedNavpopTask...');

//console.log('...navpop='+navpop+', navpop.pending='+navpop.pending);

if (navpop && navpop.pending) { --navpop.pending; }

debugData(navpop);

}

function startArticlePreview(article, oldid, navpop) {

//console.log('startArticlePreview');

navpop.redir=0;

loadPreview(article, oldid, navpop);

}

function loadPreview(article, oldid, navpop) {

//console.log('loadPreview(' + article + ', ' + oldid + ', ' + navpop + ')');

pendingNavpopTask(navpop);

if (!navpop.redir) { navpop.originalArticle=article; }

if (!navpop.visible && getValueOf('popupLazyDownloads')) {

var id=(navpop.redir) ? 'DOWNLOAD_PREVIEW_REDIR_HOOK' : 'DOWNLOAD_PREVIEW_HOOK';

//console.log(id);

//console.log(navpop);

navpop.addHook(function() {

//console.log('hook from loadPreview called');

getWiki(article, insertPreview, oldid, navpop);

return true; }, 'unhide', 'before', id);

} else {

//console.log('calling getWiki directly from loadPreview');

getWiki(article, insertPreview, oldid, navpop);

}

}

function loadPreviewFromRedir(redirMatch, navpop) {

// redirMatch is a regex match

//console.log('loadPreviewFromRedir');

var target = new Title().fromWikiText(redirMatch[2]);

var trailingRubbish=redirMatch[4];

navpop.redir++;

navpop.redirTarget=target;

//

if (window.redirLink) {

var warnRedir = redirLink(target, navpop.article);

setPopupHTML(warnRedir, 'popupWarnRedir', navpop.idNumber);

}

//

navpop.article=target;

fillEmptySpans({redir: true, redirTarget: target, navpopup:navpop});

return loadPreview(target, null, navpop);

}

function insertPreview(download) {

//console.log('insertPreview');

if (!download.owner) { return; }

var redirMatch = pg.re.redirect.exec(download.data);

if (download.owner.redir===0 && redirMatch) {

completedNavpopTask(download.owner);

loadPreviewFromRedir(redirMatch, download.owner);

return;

}

if (download.owner.visible || !getValueOf('popupLazyPreviews')) {

insertPreviewNow(download);

} else {

var id=(download.owner.redir) ? 'PREVIEW_REDIR_HOOK' : 'PREVIEW_HOOK';

//console.log(id);

download.owner.addHook( function(){insertPreviewNow(download); return true;},

'unhide', 'after', id );

}

}

function insertPreviewNow(download) {

//console.log('insertPreviewNow');

if (!download.owner) { return; }

var wikiText=download.data;

var navpop=download.owner;

completedNavpopTask(navpop);

var art=navpop.redirTarget || navpop.originalArticle;

//

//console.log('running makeFixDabs');

makeFixDabs(wikiText, navpop);

//console.log('done makeFixDabs');

if (getValueOf('popupSummaryData') && window.getPageInfo) {

var info=getPageInfo(wikiText, download);

setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber);

}

//console.log('done page info');

var imagePage='';

if (art.namespace()==pg.ns.image) { imagePage=art.toString(); }

else { imagePage=getValidImageFromWikiText(wikiText); }

if(imagePage) { loadImages(Title.fromWikiText(imagePage)); }

//

if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); }

}

function insertArticlePreview(download, art, navpop) {

//console.log('insertArticlePreview');

if (download && typeof download.data == typeof ''){

if (art.namespace()==pg.ns.template && getValueOf('popupPreviewRawTemplates')) {

// FIXME compare/consolidate with diff escaping code for wikitext

var h='


' + download.data.entify().split('\\n').join('
\\n') + '
';

setPopupHTML(h, 'popupPreview', navpop.idNumber);

}

else {

var p=prepPreviewmaker(download.data, art, navpop);

p.showPreview();

}

}

}

function prepPreviewmaker(data, article, navpop) {

//console.log('prepPreviewmaker, article='+article);

// deal with tricksy anchors

var d=anchorize(data, article.anchorString());

var urlBase=joinPath([pg.wiki.articlebase, article.urlString()]);

var p=new Previewmaker(d.substring(0,10000), urlBase, navpop);

return p;

}

// Try to imitate the way mediawiki generates HTML anchors from section titles

function anchorize(d, anch) {

if (!anch) { return d; }

var anchRe=RegExp('=+\\s*' + literalizeRegex(anch).replace(/[_ ]/g, '[_ ]') + '\\s*=+');

var match=d.match(anchRe);

if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); }

// now try to deal with == foo baz boom == -> #foo_baz_boom

var lines=d.split('\n');

for (var i=0; i

lines[i]=lines[i].replace(RegExp('\\*?[|])?(.*?)[\\]]{2}', 'g'), '$2')

.replace(/'([^'])/g, '$1').replace(RegExp("([^'])", 'g'), '$1');

if (lines[i].match(anchRe)) {

return d.split('\n').slice(i).join('\n').replace(RegExp('^[^=]*'), '');

}

}

return d;

}

function killPopup() {

if (getValueOf('popupShortcutKeys') && window.rmPopupShortcuts) { rmPopupShortcuts(); }

if (!pg) { return; }

pg.current.link && pg.current.link.navpopup && pg.current.link.navpopup.banish();

pg.current.link=null;

abortAllDownloads();

window.stopImagesDownloading && stopImagesDownloading();

if (pg.timer.checkPopupPosition !== null) {

clearInterval(pg.timer.checkPopupPosition);

pg.timer.checkPopupPosition=null;

}

if (pg.timer.checkImages !== null) { clearInterval(pg.timer.checkImages); pg.timer.checkImages=null; }

if (pg.timer.image !== null) { clearInterval(pg.timer.image); pg.timer.image=null; }

return true; // preserve default action

}

// ENDFILE: actions.js

// STARTFILE: domdrag.js

/**

@fileoverview

The {@link Drag} object, which enables objects to be dragged around.

*************************************************

dom-drag.js

09.25.2001

www.youngpup.net

**************************************************

10.28.2001 - fixed minor bug where events

sometimes fired off the handle, not the root.

*************************************************

Pared down, some hooks added by User:Lupin

Copyright Aaron Boodman.

Saying stupid things daily since March 2001.

  • /

/**

Creates a new Drag object. This is used to make various DOM elements draggable.

@constructor

  • /

function Drag () {

/**

Condition to determine whether or not to drag. This function should take one parameter, an Event.

To disable this, set it to null.

@type Function

*/

this.startCondition = null;

/**

Hook to be run when the drag finishes. This is passed the final coordinates of

the dragged object (two integers, x and y). To disables this, set it to null.

@type Function

*/

this.endHook = null;

}

/**

Gets an event in a cross-browser manner.

@param {Event} e

@private

  • /

Drag.prototype.fixE = function(e) {

if (typeof e == 'undefined') { e = window.event; }

if (typeof e.layerX == 'undefined') { e.layerX = e.offsetX; }

if (typeof e.layerY == 'undefined') { e.layerY = e.offsetY; }

return e;

};

/**

Initialises the Drag instance by telling it which object you want to be draggable, and what you want to drag it by.

@param {DOMElement} o The "handle" by which oRoot is dragged.

@param {DOMElement} oRoot The object which moves when o is dragged, or o if omitted.

  • /

Drag.prototype.init = function(o, oRoot) {

var dragObj = this;

this.obj = o;

o.onmousedown = function(e) { dragObj.start.apply( dragObj, [e]); };

o.dragging = false;

o.draggable = true;

o.hmode = true;

o.vmode = true;

o.root = oRoot && oRoot !== null ? oRoot : o ;

if (isNaN(parseInt(o.root.style.left, 10))) { o.root.style.left = "0px"; }

if (isNaN(parseInt(o.root.style.top, 10))) { o.root.style.top = "0px"; }

o.root.onthisStart = function(){};

o.root.onthisEnd = function(){};

o.root.onthis = function(){};

};

/**

Starts the drag.

@private

@param {Event} e

  • /

Drag.prototype.start = function(e) {

var o = this.obj; // = this;

e = this.fixE(e);

if (this.startCondition && !this.startCondition(e)) { return; }

var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10);

var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10);

o.root.onthisStart(x, y);

o.lastMouseX = e.clientX;

o.lastMouseY = e.clientY;

var dragObj = this;

o.onmousemoveDefault = document.onmousemove;

o.dragging = true;

document.onmousemove = function(e) { dragObj.drag.apply( dragObj, [e] ); };

document.onmouseup = function(e) { dragObj.end.apply( dragObj, [e] ); };

return false;

};

/**

Does the drag.

@param {Event} e

@private

  • /

Drag.prototype.drag = function(e) {

e = this.fixE(e);

var o = this.obj;

var ey = e.clientY;

var ex = e.clientX;

var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10);

var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10 );

var nx, ny;

nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));

ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

this.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";

this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";

this.obj.lastMouseX = ex;

this.obj.lastMouseY = ey;

this.obj.root.onthis(nx, ny);

return false;

};

/**

Ends the drag.

@private

  • /

Drag.prototype.end = function() {

document.onmousemove=this.obj.onmousemoveDefault;

document.onmouseup = null;

this.obj.dragging = false;

if (this.endHook) {

this.endHook( parseInt(this.obj.root.style[this.obj.hmode ? "left" : "right"], 10),

parseInt(this.obj.root.style[this.obj.vmode ? "top" : "bottom"], 10));

}

};

// ENDFILE: domdrag.js

// STARTFILE: structures.js

//

pg.structures.original={};

pg.structures.original.popupLayout=function () {

return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle',

'popupData', 'popupOtherLinks',

'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks',

'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],

'popupMiscTools', ['popupRedlink'],

'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPostPreview', 'popupFixDab'];

};

pg.structures.original.popupRedirSpans=function () {

return ['popupRedir', 'popupWarnRedir', 'popupRedirTopLinks',

'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'];

};

pg.structures.original.popupTitle=function (x) {

log ('defaultstructure.popupTitle');

if (!getValueOf('popupNavLinks')) {

return navlinkStringToHTML('<>',x.article,x.oldid);

}

return '';

};

pg.structures.original.popupTopLinks=function (x) {

log ('defaultstructure.popupTopLinks');

if (getValueOf('popupNavLinks')) { return navLinksHTML(x.article, x.hint, x.oldid); }

return '';

};

pg.structures.original.popupImage=function(x) {

log ('original.popupImage, x.article='+x.article+', x.navpop.idNumber='+x.navpop.idNumber);

return imageHTML(x.article, x.navpop.idNumber);

};

pg.structures.original.popupRedirTitle=pg.structures.original.popupTitle;

pg.structures.original.popupRedirTopLinks=pg.structures.original.popupTopLinks;

function copyStructure(oldStructure, newStructure) {

pg.structures[newStructure]={};

for (var prop in pg.structures[oldStructure]) {

pg.structures[newStructure][prop]=pg.structures[oldStructure][prop];

}

}

copyStructure('original', 'nostalgia');

pg.structures.nostalgia.popupTopLinks=function(x) {

var str='';

str += '<>';

// user links

// contribs - log - count - email - block

// count only if applicable; block only if popupAdminLinks

str += 'if(user){
<>';

str+='if(wikimedia){*<>}';

str+='if(ipuser){}else{*<>}if(admin){*<>}}';

// editing links

// talkpage -> edit|new - history - un|watch - article|edit

// other page -> edit - history - un|watch - talk|edit|new

var editstr='<>';

var editOldidStr='if(oldid){<>|<>|<>}else{'

+ editstr + '}'

var historystr='<>';

var watchstr='<>|<>';

str+='
if(talk){' +

editOldidStr+'|<>' + '*' + historystr+'*'+watchstr + '*' +

'<>|<>' +

'}else{' + // not a talk page

editOldidStr + '*' + historystr + '*' + watchstr + '*' +

'<>|<>|<>'

+ '}';

// misc links

str += '
<>*<>';

str += 'if(admin){
}else{*}<>';

// admin links

str += 'if(admin){*<>|<>*' +

'<>|<>}';

return navlinkStringToHTML(str, x.article, x.oldid);

};

pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks;

/** -- fancy -- **/

copyStructure('original', 'fancy');

pg.structures.fancy.popupTitle=function (x) {

return navlinkStringToHTML('<>',x.article,x.oldid);

};

pg.structures.fancy.popupTopLinks=function(x) {

var hist='<>|<>if(mainspace_en){|<>}';

var watch='<>|<>';

var move='<>';

return navlinkStringToHTML('if(talk){' +

'<>|<>*' + hist + '*' +

'<>|<>' + '*' + watch + '*' + move +

'}else{<>*' + hist +

'*<>|<>|<>' +

'*' + watch + '*' + move+'}
', x.article, x.oldid);

};

pg.structures.fancy.popupOtherLinks=function(x) {

var admin='<>|<>*<>|<>';

var user='<>if(wikimedia){|<>}';

user+='if(ipuser){|<>}else{*<

popupString('email')+'>>}if(admin){*<>}';

var normal='<>*<>';

return navlinkStringToHTML('
if(user){' + user + '*}if(admin){'+admin+'if(user){
}else{*}}' + normal,

x.article, x.oldid);

};

pg.structures.fancy.popupRedirTitle=pg.structures.fancy.popupTitle;

pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks;

pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks;

/** -- fancy2 -- **/

// hack for User:MacGyverMagic

copyStructure('fancy', 'fancy2');

pg.structures.fancy2.popupTopLinks=function(x) { // hack out the
at the end and put one at the beginning

return '
'+pg.structures.fancy.popupTopLinks(x).replace(RegExp('
$','i'),'');

};

pg.structures.fancy2.popupLayout=function () { // move toplinks to after the title

return ['popupError', 'popupImage', 'popupTitle', 'popupData', 'popupTopLinks', 'popupOtherLinks',

'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],

'popupMiscTools', ['popupRedlink'],

'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPostPreview', 'popupFixDab'];

};

/** -- menus -- **/

copyStructure('original', 'menus');

pg.structures.menus.popupLayout=function () {

return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks',

'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],

'popupData', 'popupMiscTools', ['popupRedlink'],

'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPostPreview', 'popupFixDab'];

};

function toggleSticky(uid) {

var popDiv=document.getElementById('navpopup_maindiv'+uid);

if (!popDiv) { return; }

if (!popDiv.navpopup.sticky) { popDiv.navpopup.stick(); }

else {

popDiv.navpopup.unstick();

popDiv.navpopup.hide();

}

}

pg.structures.menus.popupTopLinks = function (x, shorter) {

// FIXME this stuff should be cached

var s=[];

var dropdiv='

';

var endspan='';

var hist='<>';

if (!shorter) { hist = '' + hist +

'|<>if(mainspace_en){|<>}'; }

var lastedit='<>';

var jsHistory='<><>';

var linkshere='<>';

var related='<>';

var search='<>if(wikimedia){|<>}' +

'|<>';

var watch='<>|<>';

var protect='<>|<>|<>';

var del='<>|<>|<>';

var move='<>';

var nullPurge='<>|<>';

var viewOptions='<>|<>|<>';

var editRow='if(oldid){<>|<>' +

'<>' + '}else{<>}';

var newTopic='if(talk){<>}';

var protectDelete='if(admin){' + protect + '' + del + '}';

if (getValueOf('popupActionsMenu')) {

s.push( '<>*' + dropdiv + ''+popupString('actions') + '');

} else {

s.push( dropdiv + '<>');

}

s.push( '

')

s.push( editRow + newTopic + hist + lastedit )

if (!shorter) { s.push(jsHistory); }

s.push( move + linkshere + related)

if (!shorter) { s.push(nullPurge + search); }

if (!shorter) { s.push(viewOptions); }

s.push('


' + watch + protectDelete);

s.push('


' +

'if(talk){<><>}' +

'else{<><>' +

'<>}

' + enddiv);

// user menu starts here

var email='<>';

var contribs= 'if(wikimedia){}<>' +

'if(wikimedia){|<>}';

s.push('if(user){*' + dropdiv + ''+popupString('user')+'');

s.push('

'); +

s.push('<>|<>');

s.push('<><>' +

'<>');

if(!shorter) { s.push( 'if(ipuser){<>}else{' + email + '}') }

else { s.push( 'if(ipuser){}else{' + email + '}') }

s.push('


' + contribs + '<>');

s.push('if(wikimedia){<>}');

s.push('if(admin){<>|<>}');

s.push('<>' + getValueOf('popupExtraUserMenu'));

s.push('

' + enddiv + '}');

// popups menu starts here

if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) {

x.navpop.hasPopupMenu=true;

s.push('*' + dropdiv + '' + popupString('popupsMenu') + '

');

s.push('<>');

s.push('<>');

s.push('<>');

s.push('

'+enddiv);

}

return navlinkStringToHTML(s.join(''), x.article, x.oldid);

};

pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle;

pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks;

copyStructure('menus', 'shortmenus');

pg.structures.shortmenus.popupTopLinks=function(x) {

return pg.structures.menus.popupTopLinks(x,true);

};

pg.structures.shortmenus.popupRedirTopLinks=pg.structures.shortmenus.popupTopLinks;

//

pg.structures.lite={};

pg.structures.lite.popupLayout=function () {

return ['popupTitle', 'popupPreview' ];

};

pg.structures.lite.popupTitle=function (x) {

log (x.article + ': structures.lite.popupTitle');

//return navlinkStringToHTML('<>',x.article,x.oldid);

return '

' + x.article.toString() + '
';

};

// ENDFILE: structures.js

// STARTFILE: autoedit.js

//

function getParamValue(paramName, h) {

if (typeof h == 'undefined' ) { h = document.location.href; }

var cmdRe=RegExp('[&?]'+paramName+'=([^&]*)');

var m=cmdRe.exec(h);

if (m) {

try {

return decodeURI(m[1]);

} catch (someError) {}

}

return null;

}

function substitute(data,cmdBody) {

// alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags);

var fromRe=RegExp(cmdBody.from, cmdBody.flags);

//console.log(fromRe);

return data.replace(fromRe, cmdBody.to);

}

function execCmds(data, cmdList) {

for (var i=0; i

data=cmdList[i].action(data, cmdList[i]);

}

return data;

}

function parseCmd(str) {

// returns a list of commands

if (!str.length) { return []; }

var p=false;

switch (str.charAt(0)) {

case 's':

p=parseSubstitute(str);

break;

default:

return false;

}

if (p) { return [p].concat(parseCmd(p.remainder)); }

return false;

}

function unEscape(str, sep) {

return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n');

}

function parseSubstitute(str) {

// takes a string like s/a/b/flags;othercmds and parses it

var from,to,flags,tmp;

if (str.length<4) { return false; }

var sep=str.charAt(1);

str=str.substring(2);

tmp=skipOver(str,sep);

if (tmp) { from=tmp.segment; str=tmp.remainder; }

else { return false; }

tmp=skipOver(str,sep);

if (tmp) { to=tmp.segment; str=tmp.remainder; }

else { return false; }

flags='';

if (str.length) {

tmp=skipOver(str,';') || skipToEnd(str, ';');

if (tmp) {flags=tmp.segment; str=tmp.remainder; }

}

return {action: substitute, from: from, to: to, flags: flags, remainder: str};

}

function skipOver(str,sep) {

var endSegment=findNext(str,sep);

if (endSegment<0) { return false; }

var segment=unEscape(str.substring(0,endSegment), sep);

return {segment: segment, remainder: str.substring(endSegment+1)};

}

function skipToEnd(str,sep) {

return {segment: str, remainder: ''};

}

function findNext(str, ch) {

for (var i=0; i

if (str.charAt(i)=='\\') { i+=2; }

if (str.charAt(i)==ch) { return i; }

}

return -1;

}

function setCheckbox(param, box) {

var val=getParamValue(param);

if (val!==null) {

switch (val) {

case '1': case 'yes': case 'true':

box.checked=true;

break;

case '0': case 'no': case 'false':

box.checked=false;

}

}

}

function autoEdit() {

if (!document.editform) { return false; }

if (window.autoEdit.alreadyRan) { return false; }

window.autoEdit.alreadyRan=true;

var cmdString=getParamValue('autoedit');

if (cmdString) {

try {

var editbox=document.editform.wpTextbox1;

} catch (dang) { return; }

var cmdList=parseCmd(cmdString);

var input=editbox.value;

var output=execCmds(input, cmdList);

editbox.value=output;

}

setCheckbox('autominor', document.editform.wpMinoredit);

setCheckbox('autowatch', document.editform.wpWatchthis);

var rvid = getParamValue('autorv');

if (getValueOf('popupUseQueryInterface') && getParamValue('autorv')) {

var url=pg.wiki.wikibase + '/query.php?format=json&what=revisions&revids='+rvid;

startDownload(url, null, autoEdit2);

} else { autoEdit2(); }

}

function autoEdit2(d) {

var summary=getParamValue('autosummary');

var summaryprompt=getParamValue('autosummaryprompt');

var summarynotice='';

if (d && d.data && getParamValue('autorv')) {

var s = getRvSummary(summary, d.data);

if (s===false) {

summaryprompt=true;

summarynotice=popupString('Failed to get revision information, please edit manually.\n\n');

summary = simplePrintf(summary, [getParamValue('autorv'), '(unknown)', '(unknown)']);

} else { summary = s; }

}

if (summaryprompt) {

var txt= summarynotice +

popupString('Enter a non-empty edit summary or press cancel to abort');

var response=prompt(txt, summary);

if (response) { summary=response; }

else { return; }

}

if (summary) { document.editform.wpSummary.value=summary; }

// Attempt to avoid possible premature clicking of the save button

// (maybe delays in updates to the DOM are to blame?? or a red herring)

setTimeout(autoEdit3, 100);

}

function autoEdit3() {

var btn=getParamValue('autoclick');

if (btn) {

if (document.editform && document.editform[btn]) {

var button=document.editform[btn];

var msg=tprintf('The %s button has been automatically clicked. Please wait for the next page to load.',

[ button.value ]);

bannerMessage(msg);

document.title='('+document.title+')';

button.click();

} else {

alert(tprintf('Could not find button %s. Please check the settings in your javascript file.',

[ btn ]));

}

}

}

function bannerMessage(s) {

var headings=document.getElementsByTagName('h1');

if (headings) {

var div=document.createElement('div');

div.innerHTML='' + s + '';

headings[0].parentNode.insertBefore(div, headings[0]);

}

}

function getRvSummary(template, json) {

var o=getJsObj(json);

try {

var edit = anyChild(o.pages).revisions[0];

} catch (badness) {return false;}

var timestamp = edit.timestamp.split(/[A-Z]/g).join(' ').replace(/^ *| *$/g, '');

return simplePrintf(template, [edit.revid, timestamp, edit.user]);

}

addOnloadHook(autoEdit);

//

// ENDFILE: autoedit.js

// STARTFILE: downloader.js

/**

@fileoverview

{@link Downloader}, a xmlhttprequest wrapper, and helper functions.

  • /

/**

Creates a new Downloader

@constructor

@class The Downloader class. Create a new instance of this class to download stuff.

@param {String} url The url to download. This can be omitted and supplied later.

  • /

function Downloader(url) {

// Source: http://jibbering.com/2002/4/httprequest.html

/** xmlhttprequest object which we're wrapping */

this.http = false;

/*@cc_on @*/

/*@if (@_jscript_version >= 5)

// JScript gives us Conditional compilation,

// we can cope with old IE versions.

// and security blocked creation of the objects.

try {

this.http = new ActiveXObject("Msxml2.XMLHTTP");

} catch (e) {

try {

this.http = new ActiveXObject("Microsoft.XMLHTTP");

} catch (E) {

// this.http = false;

}

}

@end @*/

if (! this.http && typeof XMLHttpRequest!='undefined') { this.http = new XMLHttpRequest(); }

/**

The url to download

@type String

*/

this.url = url;

/**

A universally unique ID number

@type integer

*/

this.id=null;

/**

Modification date, to be culled from the incoming headers

@type Date

@private

*/

this.lastModified = null;

/**

What to do when the download completes successfully

@type Function

@private

*/

this.callbackFunction = null;

/**

What to do on failure

@type Function

@private

*/

this.onFailure = null;

/**

Flag set on abort

@type boolean

*/

this.aborted = false;

/**

HTTP method. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html for possibilities.

@type String

*/

this.method='GET';

/**

Async flag.

@type boolean

*/

this.async=true;

}

new Downloader();

/** Submits the http request. */

Downloader.prototype.send = function (x) {

if (!this.http) { return null; }

return this.http.send(x);

};

/** Aborts the download, setting the aborted field to true. */

Downloader.prototype.abort = function () {

if (!this.http) { return null; }

this.aborted=true;

return this.http.abort();

};

/** Returns the downloaded data. */

Downloader.prototype.getData = function () {if (!this.http) { return null; } return this.http.responseText;};

/** Prepares the download. */

Downloader.prototype.setTarget = function () {

if (!this.http) { return null; }

this.http.open(this.method, this.url, this.async);

};

/** Gets the state of the download. */

Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;};

pg.misc.downloadsInProgress = { };

/** Starts the download.

Note that setTarget {@link Downloader#setTarget} must be run first

  • /

Downloader.prototype.start=function () {

if (!this.http) { return; }

pg.misc.downloadsInProgress[this.id] = this;

this.http.send(null);

};

/** Gets the 'Last-Modified' date from the download headers.

Should be run after the download completes.

Returns null on failure.

@return {Date}

  • /

Downloader.prototype.getLastModifiedDate=function () {

if(!this.http) { return null; }

var lastmod=null;

try {

lastmod=this.http.getResponseHeader('Last-Modified');

} catch (err) {}

if (lastmod) { return new Date(lastmod); }

return null;

};

/** Sets the callback function.

@param {Function} f callback function, called as f(this) on success

  • /

Downloader.prototype.setCallback = function (f) {

if(!this.http) { return; }

this.http.onreadystatechange = f;

};

Downloader.prototype.getStatus = function() { if (!this.http) { return null; } return this.http.status; };

//////////////////////////////////////////////////

// helper functions

/** Creates a new {@link Downloader} and prepares it for action.

@param {String} url The url to download

@param {integer} id The ID of the {@link Downloader} object

@param {Function} callback The callback function invoked on success

@return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser

  • /

function newDownload(url, id, callback, onfailure) {

var d=new Downloader(url);

if (!d.http) { return 'ohdear'; }

d.id=id;

d.setTarget();

if (!onfailure) {

onfailure=2;

}

var f = function () {

if (d.getReadyState() == 4) {

delete pg.misc.downloadsInProgress[this.id];

try {

if ( d.getStatus() == 200 ) {

d.data=d.getData();

d.lastModified=d.getLastModifiedDate();

callback(d);

} else if (typeof onfailure == typeof 1) {

if (onfailure > 0) {

// retry

newDownload(url, id, callback, onfailure - 1);

}

} else if (typeof onfailure == 'function') {

onfailure(d,url,id,callback);

}

} catch (somerr) { /* ignore it */ }

}

};

d.setCallback(f);

return d;

}

/** Simulates a download from cached data.

The supplied data is put into a {@link Downloader} as if it had downloaded it.

@param {String} url The url.

@param {integer} id The ID.

@param {Function} callback The callback, which is invoked immediately as callback(d),

where d is the new {@link Downloader}.

@param {String} data The (cached) data.

@param {Date} lastModified The (cached) last modified date.

  • /

function fakeDownload(url, id, callback, data, lastModified, owner) {

var d=newDownload(url,callback);

d.owner=owner;

d.id=id; d.data=data;

d.lastModified=lastModified;

return callback(d);

}

/**

Starts a download.

@param {String} url The url to download

@param {integer} id The ID of the {@link Downloader} object

@param {Function} callback The callback function invoked on success

@return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser

  • /

function startDownload(url, id, callback) {

var d=newDownload(url, id, callback);

if (typeof d == typeof '' ) { return d; }

d.start();

return d;

}

/**

Aborts all downloads which have been started.

  • /

function abortAllDownloads() {

for ( var x in pg.misc.downloadsInProgress ) {

try {

pg.misc.downloadsInProgress[x].aborted=true;

pg.misc.downloadsInProgress[x].abort();

delete pg.misc.downloadsInProgress[x];

} catch (e) { }

}

}

// ENDFILE: downloader.js

// STARTFILE: livepreview.js

// TODO: location is often not correct (eg relative links in previews)

/**

* InstaView - a Mediawiki to HTML converter in JavaScript

* Version 0.6.1

* Copyright (C) Pedro Fayolle 2005-2006

* http://en.wikipedia.org/wiki/User:Pilaf

* Distributed under the BSD license

*

* Changelog:

*

* 0.6.1

* - Fixed problem caused by \r characters

* - Improved inline formatting parser

*

* 0.6

* - Changed name to InstaView

* - Some major code reorganizations and factored out some common functions

* - Handled conversion of relative links (i.e. /foo)

* - Fixed misrendering of adjacent definition list items

* - Fixed bug in table headings handling

* - Changed date format in signatures to reflect Mediawiki's

* - Fixed handling of :Image:...

* - Updated MD5 function (hopefully it will work with UTF-8)

* - Fixed bug in handling of links inside images

*

* To do:

* - Better support for

* - Full support for

* - Parser-based (as opposed to RegExp-based) inline wikicode handling (make it one-pass and bullet-proof)

* - Support for templates (through AJAX)

* - Support for coloured links (AJAX)

*/

var Insta = {}

function setupLivePreview() {

// options

Insta.conf =

{

baseUrl: '',

user: {},

wiki: {

lang: pg.wiki.lang,

interwiki: pg.wiki.interwiki,

default_thumb_width: 180

},

paths: {

articles: '/' + joinPath([pg.wiki.prePath, pg.wiki.articlePath]) + '/',

math: '/math/', // FIXME

images: ( window.getImageUrlStart ? getImageUrlStart(pg.wiki.hostname) : ''),

images_fallback: 'http://upload.wikimedia.org/wikipedia/commons/',

magnify_icon: 'skins/common/images/magnify-clip.png'

},

locale: {

user: pg.ns.user,

image: pg.ns.image,

category: pg.ns.category,

// shouldn't be used in popup previews, i think

months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

}

}

// options with default values or backreferences

with (Insta.conf) {

user.name = user.name || 'Wikipedian'

user.signature = ''+user.name+''

//paths.images = 'http://upload.wikimedia.org/wikipedia/' + wiki.lang + '/'

}

// define constants

Insta.BLOCK_IMAGE = new RegExp('^\\[\\['+Insta.conf.locale.image+

':.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i');

}

Insta.dump = function(from, to)

{

if (typeof from == 'string') from = document.getElementById(from)

if (typeof to == 'string') to = document.getElementById(to)

to.innerHTML = this.convert(from.value)

}

Insta.convert = function(wiki)

{

var ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode

o='', // output

p=0, // para flag

$r // result of passing a regexp to $()

// some shorthands

function remain() { return ll.length }

function sh() { return ll.shift() } // shift

function ps(s) { o+=s } // push

function f() // similar to C's printf, uses ? as placeholders, ?? to escape question marks

{

var i=1,a=arguments,f=a[0],o='',c,p

for (;i

// allow character escaping

i -= c=f.charAt(p+1)=='?'?1:0

o += f.substring(0,p)+(c?'?':a[i])

f=f.substr(p+1+c)

} else break;

return o+f

}

function html_entities(s) { return s.replace(/&/g,"&").replace(//g,">") }

function max(a,b) { return (a>b)?a:b }

function min(a,b) { return (a

// return the first non matching character position between two strings

function str_imatch(a, b)

{

for (var i=0, l=min(a.length, b.length); i

return i

}

// compare current line against a string or regexp

// if passed a string it will compare only the first string.length characters

// if passed a regexp the result is stored in $r

function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)) }

function $$(c) { return ll[0]==c } // compare current line against a string

function _(p) { return ll[0].charAt(p) } // return char at pos p

function endl(s) { ps(s); sh() }

function parse_list()

{

var prev='';

while (remain() && $(/^([*#:;]+)(.*)$/)) {

var l_match = $r

sh()

var ipos = str_imatch(prev, l_match[1])

// close uncontinued lists

for (var i=prev.length-1; i >= ipos; i--) {

var pi = prev.charAt(i)

if (pi=='*') ps('')

else if (pi=='#') ps('')

// close a dl only if the new item is not a dl item (:, ; or empty)

else switch (l_match[1].charAt(i)) { case'':case'*':case'#': ps('') }

}

// open new lists

for (var i=ipos; i

var li = l_match[1].charAt(i)

if (li=='*') ps('

');

}

function navlinkDepth(magic,s) {

return s.split('<' + magic + '>').length - s.split('').length;

}

// navlinkString: * becomes the separator

// <> becomes a foo-link with attribute bar='baz'

// and visible text 'fubar'

// if(test){...} and if(test){...}else{...} work too (nested ok)

function navlinkStringToHTML(s,article,oldid) {

//limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article));

var p=navlinkStringToArray(s,article,oldid);

var html='';

var menudepth = 0; // nested menus not currently allowed, but doesn't do any harm to code for it

var menurowdepth = 0;

var wrapping = null;

for (var i=0; i

if (typeof p[i] == typeof '') {

html+=navlinkSubstituteHTML(p[i]);

menudepth += navlinkDepth('menu', p[i]);

menurowdepth += navlinkDepth('menurow', p[i]);

// if (menudepth === 0) {

// tagType='span';

// } else if (menurowdepth === 0) {

// tagType='li';

// } else {

// tagType = null;

// }

} else if (typeof p[i].type != 'undefined' && p[i].type=='navlinkTag') {

if (menudepth > 0 && menurowdepth === 0) {

html += '

';

} else {

html+=p[i].html();

}

}

}

return html;

}

function navlinkTag() {

this.type='navlinkTag';

}

navlinkTag.prototype.html=function () {

this.getNewWin();

this.getPrintFunction();

var html='';

var opening, closing;

var tagType='span';

if (!tagType) {

opening = ; closing = ;

} else {

opening = '<' + tagType + ' class="popup_' + this.id + '">';

closing = '';

}

if (typeof this.print!='function') {

errlog ('Oh dear - invalid print function for a navlinkTag, id='+this.id);

} else {

html=this.print(this);

if (typeof html != typeof ) {html=;}

else if (typeof this.shortcut!='undefined') html=addPopupShortcut(html, this.shortcut);

}

return opening + html + closing;

};

navlinkTag.prototype.getNewWin=function() {

getValueOf('popupLinksNewWindow');

if (typeof pg.option.popupLinksNewWindow[this.id] === 'undefined') { this.newWin=null; }

this.newWin=pg.option.popupLinksNewWindow[this.id];

}

navlinkTag.prototype.getPrintFunction=function() { //think about this some more

// this.id and this.article should already be defined

if (typeof this.id!=typeof '' || typeof this.article!=typeof {} ) { return; }

var html='';

var a,t;

switch (this.id) {

case 'email': case 'contribs': case 'block': case 'unblock':

case 'userlog': case 'userSpace':

this.article=this.article.userName();

}

switch (this.id) {

case 'userTalk': case 'newUserTalk': case 'editUserTalk':

case 'userPage': case 'monobook': case 'editMonobook': case 'blocklog':

this.article=this.article.userName(true);

// fall through; no break

case 'pagelog': case 'deletelog': case 'protectlog':

delete this.oldid;

}

if (this.id=='editMonobook' || this.id=='monobook') { this.article.append('/monobook.js'); }

if (this.id != 'mainlink') {

// FIXME anchor handling should be done differently with Title object

this.article=this.article.removeAnchor();

// if (typeof this.text=='undefined') this.text=popupString(this.id);

}

switch (this.id) {

case 'undelete': this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break;

case 'whatLinksHere': this.print=specialLink; this.specialpage='Whatlinkshere'; break;

case 'relatedChanges': this.print=specialLink; this.specialpage='Recentchangeslinked'; break;

case 'move': this.print=specialLink; this.specialpage='Movepage'; break;

case 'contribs': this.print=specialLink; this.specialpage='Contributions'; break;

case 'email': this.print=specialLink; this.specialpage='Emailuser'; break;

case 'block': this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break;

case 'unblock': this.print=specialLink; this.specialpage='Ipblocklist'; this.sep='&action=unblock&ip='; break;

case 'userlog': this.print=specialLink; this.specialpage='Log'; this.sep='&user='; break;

case 'blocklog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=block&page='; break;

case 'pagelog': this.print=specialLink; this.specialpage='Log'; this.sep='&page='; break;

case 'protectlog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=protect&page='; break;

case 'deletelog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=delete&page='; break;

case 'userSpace': this.print=specialLink; this.specialpage='Prefixindex'; this.sep='&namespace=2&from='; break;

case 'search': this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break;

case 'history': case 'historyfeed': case 'unwatch': case 'watch':

case 'unprotect': case 'protect':

this.print=wikiLink; this.action=this.id; break;

case 'delete':

this.print=wikiLink; this.action='delete';

if (this.article.namespace()==pg.ns.image) {

var img=this.article.stripNamespace();

this.action+='&image='+img;

}

break;

case 'edit': // editOld should keep the oldid, but edit should not.

delete this.oldid; // fall through

case 'view': case 'purge': case 'render':

this.print=wikiLink;

this.action=this.id; break;

case 'raw':

this.print=wikiLink; this.action='raw&ctype=text/css'; break;

case 'new':

this.print=wikiLink; this.action='edit§ion=new'; break;

case 'mainlink':

if (typeof this.text=='undefined') { this.text=this.article.toString().entify(); }

if (getValueOf('popupSimplifyMainLink') && isInStrippableNamespace(this.article)) {

var s=this.text.split('/'); this.text=s[s.length-1];

if (this.text=='' && s.length > 1) { this.text=s[s.length-2]; }

}

this.print=titledWikiLink;

if (typeof this.title=='undefined' && pg.current.link && typeof pg.current.link.href != 'undefined') {

this.title=safeDecodeURI((pg.current.link.originalTitle)?pg.current.link.originalTitle:this.article);

if (typeof this.oldid != 'undefined' && this.oldid) {

this.title=tprintf('Revision %s of %s', [this.oldid, this.title]);

}

}

this.action='view'; break;

case 'userPage':

case 'article':

case 'monobook':

case 'editMonobook':

case 'editArticle':

delete this.oldid;

//alert(this.id+'\n'+this.article + '\n'+ typeof this.article);

this.article=this.article.articleFromTalkOrArticle();

//alert(this.id+'\n'+this.article + '\n'+ typeof this.article);

this.print=wikiLink;

if (this.id.indexOf('edit')==0) {

this.action='edit';

} else { this.action='view';}

break;

case 'userTalk':

case 'talk':

this.article=this.article.talkPage();

delete this.oldid;

this.print=wikiLink;

this.action='view'; break;

case 'arin':

this.print=arinLink; break;

case 'count':

this.print=kateLink; break;

case 'google':

this.print=googleLink; break;

case 'contribsTree':

this.print=contribsTreeLink; break;

case 'editors':

this.print=editorListLink; break;

case 'globalsearch':

this.print=globalSearchLink; break;

case 'lastEdit':

this.print=titledDiffLink;

this.title=popupString('Show the last edit');

this.from='prev'; this.to='cur'; break;

case 'oldEdit':

this.print=titledDiffLink;

this.title=popupString('Show the edit made to get revision') + ' ' + this.oldid;

this.from='prev'; this.to=this.oldid; break;

case 'editOld':

this.print=wikiLink; this.action='edit'; break;

case 'revert':

this.print=wikiLink; this.action='revert'; break;

case 'nullEdit':

this.print=wikiLink; this.action='nullEdit'; break;

case 'diffCur':

this.print=titledDiffLink;

this.title=tprintf('Show changes since revision %s', [this.oldid]);

this.from=this.oldid; this.to='cur'; break;

case 'editUserTalk':

case 'editTalk':

delete this.oldid;

this.article=this.article.talkPage();

this.action='edit'; this.print=wikiLink; break;

case 'newUserTalk':

case 'newTalk':

this.article=this.article.talkPage();

this.action='edit§ion=new'; this.print=wikiLink; break;

case 'lastContrib':

case 'sinceMe':

this.print=magicHistoryLink;

break;

case 'togglePreviews':

this.text=popupString(pg.option.simplePopups ? 'enable previews' : 'disable previews');

case 'disablePopups': case 'purgePopups':

this.print=popupMenuLink;

break;

default:

this.print=function () {return 'Unknown navlink type: '+this.id+''};

}

};

//

// end navlinks

//////////////////////////////////////////////////

//

// ENDFILE: navlinks.js

// STARTFILE: shortcutkeys.js

//

function popupHandleKeypress(evt) {

var keyCode = window.event ? window.event.keyCode : ( evt.keyCode ? evt.keyCode : evt.which);

if (!keyCode || !pg.current.link || !pg.current.link.navpopup) { return; }

if (keyCode==27) { // escape

killPopup();

return false; // swallow keypress

}

var letter=String.fromCharCode(keyCode);

var links=pg.current.link.navpopup.mainDiv.getElementsByTagName('A');

var startLink=0;

var i,j;

if (popupHandleKeypress.lastPopupLinkSelected) {

for (i=0; i

if (links[i]==popupHandleKeypress.lastPopupLinkSelected) { startLink=i; }

}

}

for (j=0; j

i=(startLink + j + 1) % links.length;

if (links[i].getAttribute('popupkey')==letter) {

if (evt && evt.preventDefault) evt.preventDefault();

links[i].focus();

popupHandleKeypress.lastPopupLinkSelected=links[i];

return false; // swallow keypress

}

}

// pass keypress on

if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); }

return true;

}

function addPopupShortcuts() {

if (document.onkeypress && document.onkeypress.toString()==popupHandleKeypress.toString()) return;

document.oldPopupOnkeypress=document.onkeypress;

document.onkeypress=popupHandleKeypress;

}

function rmPopupShortcuts() {

popupHandleKeypress.lastPopupLinkSelected=null;

try {

if (document.oldPopupOnkeypress && document.oldPopupOnkeypress.toString()==popupHandleKeypress.toString()) {

// panic

document.onkeypress=null; //function () {};

return;

}

document.onkeypress=document.oldPopupOnkeypress;

} catch (nasties) { /* IE goes here */ }

}

function addLinkProperty(html, property) {

// take "... and add a property

// not sophisticated at all, easily broken

var i=html.indexOf('>');

if (i<0) { return html; }

return html.substring(0,i) + ' ' + property + html.substring(i);

}

function addPopupShortcut(html, key) {

if (!getValueOf('popupShortcutKeys')) { return html; }

var ret= addLinkProperty(html, 'popupkey="'+key+'"');

if (key==' ') { key=popupString('spacebar'); }

return ret.replace(RegExp('^(.*?)(title=")(.*?)(".*)$', 'i'),'$1$2$3 ['+key+']$4');

}

//

// ENDFILE: shortcutkeys.js

// STARTFILE: diffpreview.js

//

function loadDiff(article, oldid, diff, navpop) {

//console.log('loadDiff');

navpop.diffData={};

var oldRev, newRev;

switch (diff) {

case 'cur':

switch ( oldid ) {

case null:

case '':

case 'prev':

// eg newmessages diff link

oldRev='0&direction=prev';

newRev=0;

break;

default:

oldRev = oldid;

newRev = 0;

}

break;

case 'prev':

oldRev = ( oldid || 0 ) + '&direction=prev'; newRev = oldid; break;

case 'next':

oldRev = oldid; newRev = oldid + '&direction=next';

break;

default:

oldRev = oldid || 0; newRev = diff || 0; break;

}

oldRev = oldRev || 0;

newRev = newRev || 0;

var go = function() {

//console.log('go');

pendingNavpopTask(navpop);

getWiki(article, doneDiffNew, newRev, navpop);

pendingNavpopTask(navpop);

getWiki(article, doneDiffOld, oldRev, navpop);

var tz = Cookie.read('popTz');

if (getValueOf('popupUseQueryInterface') && getValueOf('popupAdjustDiffDates') && tz===null) {

pendingNavpopTask(navpop);

getPageWithCaching(pg.wiki.wikibase + '/query.php?format=json&what=userinfo&uioptions=timecorrection',

function(d) {

completedNavpopTask(navpop);

setTimecorrectionCookie(d);

if (diffDownloadsComplete(navpop)) { insertDiff(navpop); }

}, navpop);

}

return true; // remove hook once run

}

if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); }

else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); }

}

function setTimecorrectionCookie(d) {

Cookie.create('popTz', getTimeOffset(getJsObj(d.data).meta.user.timecorrection), 1);

}

function doneDiff(download, isOld) {

//console.log('doneDiff');

if (!download.owner || !download.owner.diffData) { return; }

var navpop=download.owner;

var label= (isOld) ? 'Old' : 'New';

var otherLabel=(isOld) ? 'New' : 'Old';

navpop.diffData[label]=download;

completedNavpopTask(download.owner);

if (diffDownloadsComplete(navpop)) { insertDiff(navpop); }

}

function diffDownloadsComplete(navpop) {

if (getValueOf('popupUseQueryInterface') && Cookie.read('popTz')===null) { return false; }

return navpop.diffData.Old && navpop.diffData.New;

}

function doneDiffNew(download) { doneDiff(download, false); }

function doneDiffOld(download) { doneDiff(download, true); }

function rmBoringLines(a,b,context) {

if (typeof context == 'undefined') { context=2; }

// this is fairly slow... i think it's quicker than doing a word-based diff from the off, though

var aa=[], aaa=[];

var bb=[], bbb=[];

var i, j;

// first, gather all disconnected nodes in a and all crossing nodes in a and b

for (i=0; i

if(!a[i].paired) { aa[i]=1; }

else if (countCrossings(b,a,i, true)) {

aa[i]=1;

bb[ a[i].row ] = 1;

}

}

// pick up remaining disconnected nodes in b

for (i=0; i

if (bb[i]==1) { continue; }

if(!b[i].paired) { bb[i]=1; }

}

// another pass to gather context: we want the neighbours of included nodes which are not yet included

// we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass

for (i=0; i

if ( bb[i] == 1 ) {

for (j=max(0,i-context); j < min(b.length, i+context); ++j) {

if ( !bb[j] ) { bb[j] = 1; aa[ b[j].row ] = 0.5; }

}

}

}

for (i=0; i

if ( aa[i] == 1 ) {

for (j=max(0,i-context); j < min(a.length, i+context); ++j) {

if ( !aa[j] ) { aa[j] = 1; bb[ a[j].row ] = 0.5; }

}

}

}

for (i=0; i

if (bb[i] > 0) { // it's a row we need

if (b[i].paired) { bbb.push(b[i].text); } // joined; partner should be in aa

else {

bbb.push(b[i]);

}

}

}

for (i=0; i

if (aa[i] > 0) { // it's a row we need

if (a[i].paired) { aaa.push(a[i].text); } // joined; partner should be in aa

else {

aaa.push(a[i]);

}

}

}

return { a: aaa, b: bbb};

}

function stripOuterCommonLines(a,b,context) {

var i=0;

while (i

var j=a.length-1; var k=b.length-1;

while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; }

return { a: a.slice(max(0,i - 1 - context), min(a.length+1, j + context+1)),

b: b.slice(max(0,i - 1 - context), min(b.length+1, k + context+1)) };

}

function insertDiff(navpop) {

//console.log('insertDiff');

// for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff

// FIXME: sometimes this gives misleading diffs as distant chunks are squashed together

var oldlines=navpop.diffData.Old.data.split('\n');

var newlines=navpop.diffData.New.data.split('\n');

var inner=stripOuterCommonLines(oldlines,newlines,getValueOf('popupDiffContextLines'));

oldlines=inner.a; newlines=inner.b;

var truncated=false;

getValueOf('popupDiffMaxLines');

if (oldlines.length > pg.option.popupDiffMaxLines || newlines.length > pg.option.popupDiffMaxLines) {

// truncate

truncated=true;

inner=stripOuterCommonLines(oldlines.slice(0,pg.option.popupDiffMaxLines),

newlines.slice(0,pg.option.popupDiffMaxLines),

pg.option.popupDiffContextLines);

oldlines=inner.a; newlines=inner.b;

}

var lineDiff=diff(oldlines, newlines);

var lines2=rmBoringLines(lineDiff.o, lineDiff.n);

var oldlines2=lines2.a; var newlines2=lines2.b;

var simpleSplit = !String.prototype.parenSplit.isNative;

var html='


';

if (getValueOf('popupDiffDates')) {

html += diffDatesTable(navpop.diffData.Old, navpop.diffData.New);

html += '


';

}

html += shortenDiffString(

diffString(oldlines2.join('\n'), newlines2.join('\n'), simpleSplit),

getValueOf('popupDiffContextCharacters') ).join('


');

setPopupTipsAndHTML(html.split('\n').join('
') +

(truncated ? '


'+popupString('Diff truncated for performance reasons')+'' : '') ,

'popupPreview', navpop.idNumber);

}

function diffDatesTable( oldDl, newDl ) {

var html='

';

html += diffDatesTableRow( newDl, tprintf('New revision'));

html += diffDatesTableRow( oldDl, tprintf('Old revision'));

html += '

';

return html;

}

function diffDatesTableRow( dl, label ) {

var txt='';

if (!dl) {

txt=popupString('Something went wrong :-(');

} else if (!dl.lastModified) {

txt= (/^\s*$/.test(dl.data)) ?

popupString('Empty revision, maybe non-existent') : popupString('Unknown date');

} else {

var datePrint=getValueOf('popupDiffDatePrinter');

if (typeof dl.lastModified[datePrint] == 'function') {

if (getValueOf('popupAdjustDiffDates')) {

var off;

if (off=Cookie.read('popTz')) {

var d2=adjustDate(dl.lastModified, off);

txt = dayFormat(d2, true) + ' ' + timeFormat(d2, true);

}

} else {

txt = dl.lastModified[datePrint]();

}

} else {

txt = tprintf('Invalid %s %s', ['popupDiffDatePrinter', datePrint]);

}

}

var revlink = generalLink({url: dl.url.replace(/&.*?(oldid=[0-9]+(?:&direction=[^&]*)?).*/, '&$1'),

text: label, title: label});

return simplePrintf('%s%s', [ revlink, txt ]);

}

//

// ENDFILE: diffpreview.js

// STARTFILE: links.js

//

/////////////////////

// LINK GENERATION //

/////////////////////

// titledDiffLink --> titledWikiLink --> generalLink

// wikiLink --> titledWikiLink --> generalLink

// kateLink --> generalLink

function titledDiffLink(l) { // article, text, title, from, to) {

return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from,

newWin: l.newWin,

text: l.text, title: l.title,

/* hack: no oldid here */

actionName: 'diff'});

}

function wikiLink(l) {

//{article:article, action:action, text:text, oldid}) {

if (! (typeof l.article == typeof {}

&& typeof l.action == typeof && typeof l.text==typeof )) return null;

if (typeof l.oldid == 'undefined') l.oldid=null;

if (!/^((edit|view|revert|render)$|(raw))/.test(l.action)) { l.oldid=null; }

var hint=popupString(l.action + 'Hint'); // revertHint etc etc etc

var oldidData=[l.oldid, safeDecodeURI(l.article)];

var revisionString = tprintf('revision %s of %s', oldidData);

log('revisionString='+revisionString);

switch (l.action) {

case 'edit§ion=new': hint = popupString('newSectionHint'); break;

case 'raw&ctype=text/css': hint=popupString('rawHint'); break;

case 'revert':

var p=parseParams(pg.current.link.href);

l.action='edit&autoclick=wpSave&autosummary=' + revertSummary(l.oldid, p.diff);

if (p.diff=='prev') {

l.action += '&direction=prev';

revisionString = tprintf('the revision prior to revision %s of %s', oldidData);

}

if (getValueOf('popupRevertSummaryPrompt')) { l.action += '&autosummaryprompt=true'; }

log('revisionString is now '+revisionString);

break;

case 'nullEdit':

l.action='edit&autoclick=wpSave&autosummary=null';

break;

case 'historyfeed':

l.action='history&feed=rss';

break;

}

if (hint) {

if (l.oldid) {

hint = simplePrintf(hint, [revisionString]);

}

else {

hint = simplePrintf(hint, [safeDecodeURI(l.article)]);

}

}

else {

hint = safeDecodeURI(l.article + '&action=' + l.action) + (l.oldid) ? '&oldid='+l.oldid : '';

}

return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin,

title: hint, oldid: l.oldid});

}

function revertSummary(oldid, diff) {

if (getValueOf('popupUseQueryInterface')) { return revertSummaryQueried(oldid, diff); }

if (typeof getValueOf('popupTimeOffset') == 'number' && /[?&]action=history/.test(document.location.href)) {

var links=document.links;

var numlinks=links.length;

var date=null, editor=null;

var dateRe = RegExp('^([0-9]{2}:[0-9]{2}),\s*(.*[1-3][0-9]{3})$');

for (var i=0; i

if (RegExp('oldid='+oldid).test(links[i].href) && dateRe.test(links[i].innerHTML)) {

// help konqueror out by putting the time at the end

var ds = links[i].innerHTML.replace(dateRe, '$2 $1');

// d is parsed according to current locale, in FF at least

// this is only OK if the user has set the time offset in prefs!

var d=new Date(+(new Date(ds)) - 1000*3600*getValueOf('popupTimeOffset'));

// strip out zero seconds and timezone in date, since they're prolly bogus

date=d.toString().replace(/([0-9]{2}:[0-9]{2}):00.*/, '$1');

editor=Title.fromURL(links[i+1].href).userName();

break;

}

}

if (date && editor && diff != 'prev') {

return simplePrintf(getValueOf('popupExtendedRevertSummary'), [date, editor, oldid]);

}

}

if (diff != 'prev') {

return simplePrintf(getValueOf('popupRevertSummary'), [ oldid ]);

}

return simplePrintf(getValueOf('popupRevertToPreviousSummary'), [ oldid ]);

}

function revertSummaryQueried(oldid, diff) {

var ret='';

if (diff == 'prev') {

ret=getValueOf('popupQueriedRevertToPreviousSummary');

} else { ret = getValueOf('popupQueriedRevertSummary'); }

return ret + '&autorv=' + oldid;

}

function titledWikiLink(l) {

// possible properties of argument:

// article, action, text, title, oldid, actionName, className

// oldid = null is fine here

// article and action are mandatory args

if (typeof l.article == 'undefined' || typeof l.action=='undefined') {

errlog('got undefined article or actino in titledWikiLink');

return null;

}

var base = pg.wiki.titlebase + l.article.urlString();

var url=base;

if (typeof l.actionName=='undefined' || !l.actionName) { l.actionName='action'; }

// no need to add &action=view, and this confuses anchors

if (l.action != 'view') { url = base + '&' + l.actionName + '=' + l.action; }

if (typeof l.oldid!='undefined' && l.oldid) { url+='&oldid='+l.oldid; }

var cssClass=pg.misc.defaultNavlinkClassname;

if (typeof l.className!='undefined' && l.className) { cssClass=l.className; }

return generalNavLink({url: url, newWin: l.newWin,

title: (typeof l.title != 'undefined') ? l.title : null,

text: (typeof l.text!='undefined')?l.text:null,

className: cssClass});

}

function getLastContrib(wikipage, newWin) {

getHistoryInfo(wikipage, function(x){processLastContribInfo(x,{page: wikipage, newWin: newWin})});

}

function processLastContribInfo(info, stuff) {

if(!info.edits || !info.edits.length) { alert('Popups: an odd thing happened. Please retry.'); return; }

if(!info.firstNewEditor) {

alert(tprintf('Only found one editor: %s made %s edits', [info.edits[0].editor,info.edits.length]));

return;

}

var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+info.firstNewEditor.oldid;

displayUrl(newUrl, stuff.newWin);

}

function getDiffSinceMyEdit(wikipage, newWin) {

getHistoryInfo(wikipage, function(x){processDiffSinceMyEdit(x,{page: wikipage, newWin: newWin})});

}

function processDiffSinceMyEdit(info, stuff) {

if(!info.edits || !info.edits.length) { alert('Popups: something fishy happened. Please try again.'); return; }

var friendlyName=stuff.page.split('_').join(' ');

if(!info.myLastEdit) {

alert(tprintf('Couldn\'t find an edit by %s\nin the last %s edits to\n%s',

[info.userName, getValueOf('popupHistoryLimit'), friendlyName]));

return;

}

if(info.myLastEdit.index==0) {

alert(tprintf("%s seems to be the last editor to the page %s", [info.userName, friendlyName]));

return;

}

var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+ info.myLastEdit.oldid;

displayUrl(newUrl, stuff.newWin);

}

function displayUrl(url, newWin){

if(newWin) { window.open(url); }

else { document.location=url; }

}

function purgePopups() {

processAllPopups(true);

setupCache(); // deletes all cached items (not browser cached, though...)

pg.option={};

abortAllDownloads();

}

function processAllPopups(nullify, banish) {

for (var i=0; i

if (!pg.current.links[i].navpopup) { continue; }

(nullify || banish) && pg.current.links[i].navpopup.banish();

nullify && (pg.current.links[i].navpopup=null);

}

}

function disablePopups(){

processAllPopups(false, true);

setupTooltips(null, true);

}

function togglePreviews() {

processAllPopups(true, true);

pg.option.simplePopups=!pg.option.simplePopups;

abortAllDownloads();

}

function magicHistoryLink(l) {

// FIXME use onclick change href trick to sort this out instead of window.open

var jsUrl=, title=;

switch(l.id) {

case 'lastContrib':

jsUrl=simplePrintf('javascript:getLastContrib(\'%s\',%s)',

[l.article.toString(true).split("'").join("\\'"), l.newWin]);

title=popupString('lastContribHint');

break;

case 'sinceMe':

jsUrl=simplePrintf('javascript:getDiffSinceMyEdit(\'%s\',%s)',

[l.article.toString(true).split("'").join("\\'"), l.newWin]);

title=popupString('sinceMeHint');

break;

}

return generalNavLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think

title: title, text: l.text});

}

function popupMenuLink(l) {

var jsUrl=simplePrintf('javascript:%s()', [l.id]);

var title=popupString(simplePrintf('%sHint', [l.id]));

return generalNavLink({url: jsUrl, newWin:false, title:title, text:l.text});

}

function specialLink(l) {

// properties: article, specialpage, text, sep

if (typeof l.specialpage=='undefined'||!l.specialpage) return null;

var base = pg.wiki.titlebase + pg.ns.special+':'+l.specialpage;

if (typeof l.sep == 'undefined' || l.sep===null) l.sep='&target=';

var article=l.article.urlString({keepSpaces: l.specialpage=='Search'});

var hint=popupString(l.specialpage+'Hint');

switch (l.specialpage) {

case 'Log':

switch (l.sep) {

case '&user=': hint=popupString('userLogHint'); break;

case '&type=block&page=': hint=popupString('blockLogHint'); break;

case '&page=': hint=popupString('pageLogHint'); break;

case '&type=protect&page=': hint=popupString('protectLogHint'); break;

case '&type=delete&page=': hint=popupString('deleteLogHint'); break;

default: log('Unknown log type, sep=' + l.sep); hint='Missing hint (FIXME)';

}

break;

case 'Prefixindex': article += '/'; break;

}

if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]);

else hint = safeDecodeURI(l.specialpage+':'+l.article) ;

var url = base + l.sep + article;

return generalNavLink({url: url, title: hint, text: l.text, newWin:l.newWin});

}

function generalLink(l) {

// l.url, l.text, l.title, l.newWin, l.className

if (typeof l.url=='undefined') return null;

// only quotation marks in the url can screw us up now... I think

var url=l.url.split('"').join('%22');

var ret='

if (typeof l.title!='undefined' && l.title) ret += ' title="' + l.title + '"';

var newWin;

if (typeof l.newWin=='undefined' || l.newWin===null) newWin=getValueOf('popupNewWindows');

else newWin=l.newWin;

if (newWin) ret += ' target="_blank"';

if (typeof l.className!='undefined'&&l.className) ret+=' class="'+l.className+'"';

ret += '>';

if (typeof l.text==typeof '') ret+= l.text;

ret +='';

return ret;

}

function appendParamsToLink(linkstr, params) {

var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i'));

if (sp.length<2) return null;

var ret=sp.shift() + sp.shift();

ret += '&' + params + '"';

ret += sp.join('');

return ret;

}

function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor) {

if (x.newTarget) {

log ('changeLinkTargetLink: newTarget=' + x.newTarget);

}

// optional: oldTarget (in wikitext)

// if x.newTarget omitted or null, remove the link

//x.text=encodeURI(x.text); // this buggers things up on zh.wikipedia.org and doesn't seem necessary

x.clickButton=encodeURI(x.clickButton);

// FIXME: first character of page title as well as namespace should be case insensitive

// eg category:foo and Category:Foo are equivalent

// this'll break if charAt(0) is nasty

var cA=literalizeRegex(x.oldTarget);

var chs=cA.charAt(0).toUpperCase();

chs='['+chs + chs.toLowerCase()+']';

var currentArticleRegexBit=chs+cA.substring(1);

currentArticleRegexBit=currentArticleRegexBit

.split(RegExp('[_ ]+', 'g')).join('[_ ]+')

.split('\\(').join('(?:%2528|\\()')

.split('\\)').join('(?:%2529|\\))');

currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + ')\\s*';

// e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s*

// autoedit=s~\[\[([Cc]ad)\]\]~$1~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g

// get the page to edit from the title

try {

//var title=document.getElementsByTagName('h1')[0].innerHTML.replace(RegExp(' ', 'g'), '_');

var title=document.title.split(' - ');

title[title.length-1]='';

title=title.join(' - ').replace(/ - $/, '');

} catch (err) { return; }

var lk=titledWikiLink({article: new Title(title), newWin:x.newWin,

action: 'edit',

text: x.text,

title: x.hint,

className: 'popup_change_title_link'

});

var cmd='';

if (x.newTarget) {

// escape '&' and other nasties

var t=encodeURI(x.newTarget);

var s=encodeURI(literalizeRegex(x.newTarget));

cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~$1~g;';

cmd += 's~\\[\\['+currentArticleRegexBit+'[|]~[['+t+'|~g;';

cmd += 's~\\[\\['+s + '\\|' + s + '\\]\\]~' + t + '~g';

} else {

cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~$1~g;';

cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g';

}

cmd += '&autoclick='+x.clickButton;

cmd += ( x.minor == null ) ? '' : '&autominor='+x.minor;

cmd += ( x.watch == null ) ? '' : '&autowatch='+x.watch;

cmd += '&autosummary='+x.summary;

return appendParamsToLink(lk, 'autoedit='+cmd);

}

function redirLink(redirMatch, article) {

// NB redirMatch is in wikiText

var ret='';

if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) {

ret += '


';

if (getValueOf('popupFixRedirs') && typeof autoEdit != 'undefined' && autoEdit) {

log('redirLink: newTarget=' + redirMatch);

ret += addPopupShortcut(

changeLinkTargetLink(

{newTarget: redirMatch, text: popupString('Redirects'),

hint: popupString('Fix this redirect'),

summary: simplePrintf(getValueOf('popupFixRedirsSummary'),

[article.toString(), redirMatch ]),

oldTarget: article.toString(),

clickButton: getValueOf('popupRedirAutoClick'), minor: true,

watch: getValueOf('popupWatchRedirredPages')})

, 'R');

ret += popupString(' to ');

}

else ret += popupString('Redirects') + popupString(' to ');

return ret;

}

else return '
' + popupString('Redirects') + popupString(' to ') +

titledWikiLink({article: new Title().fromWikiText(redirMatch), action: 'view', /* FIXME: newWin */

text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')});

}

function arinLink(l) {

if (!saneLinkCheck(l)) { return null; }

if ( ! l.article.isIpUser() || ! pg.wiki.wikimedia) return null;

var uN=safeDecodeURI(l.article.userName());

return generalNavLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + uN, newWin:l.newWin,

title: tprintf('Look up %s in ARIN whois database', [uN]),

text: l.text});

}

function toolDbName(cookieStyle) {

var ret=null;

var theWiki=pg.wiki.hostname.split('.')[1];

if (pg.wiki.hostname==pg.wiki.commons) {

ret = 'commonswiki';

} else {

switch(theWiki) {

case 'wikipedia':

ret = pg.wiki.lang + 'wiki';

break;

default:

ret = pg.wiki.lang + theWiki;

break;

}

}

if (!cookieStyle) { ret+= '_p'; }

return ret;

}

function saneLinkCheck(l) {

if (typeof l.article != typeof {} || typeof l.text != typeof '') { return false; }

return true;

}

function kateLink(l) {

if(!saneLinkCheck(l)) return null;

if (! pg.wiki.wikimedia) return null;

var uN=safeDecodeURI(l.article.userName());

var tool=getValueOf('popupEditCounterTool');

var url;

var defaultToolUrl='http://tools.wikimedia.de/~$3/cgi-bin/count_edits?dbname=$2&user=$1';

switch(tool) {

case 'custom':

url=simplePrintf(getValueOf('popupEditCounterUrl'), [ uN, toolDbName() ]);

break;

default:

url=simplePrintf(defaultToolUrl, [ uN, toolDbName(), tool ]);

}

return generalNavLink({url:url, title: tprintf('katelinkHint', [uN]), newWin:l.newWin, text: l.text});

}

function contribsTreeLink(l) {

if(!saneLinkCheck(l)) return null;

if (! pg.wiki.wikimedia) return null;

var uN=safeDecodeURI(l.article.userName());

var url='http://tools.wikimedia.de/~interiot/cgi-bin/contribution_tree?dbname=';

url += toolDbName() + '&user='+ uN;

return generalNavLink({url:url, title: tprintf('contribsTreeHint', [uN]), newWin:l.newWin, text: l.text});

}

function globalSearchLink(l) {

if(!saneLinkCheck(l)) return null;

var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search=';

var article=l.article.urlString({keepSpaces:true});

return generalNavLink({url:base + article, newWin:l.newWin,

title: tprintf('globalSearchHint', [article]),

text: l.text});

}

function googleLink(l) {

if(!saneLinkCheck(l)) return null;

var base='http://www.google.com/search?q=';

var article=l.article.urlString({keepSpaces:true});

return generalNavLink({url:base + '%22' + article + '%22', newWin:l.newWin,

title: tprintf('googleSearchHint', [article]),

text: l.text});

}

function editorListLink(l) {

if(!saneLinkCheck(l)) return null;

var article= l.article.articleFromTalkPage() || l.article;

var base='http://tools.wikimedia.de/~tim/counter/?page=';

return generalNavLink({url:base+article.urlString(),

title: tprintf('editorListHint', [article]), newWin:l.newWin, text: l.text});

}

function generalNavLink(l) {

l.className = (l.className==null) ? 'popupNavLink' : l.className;

return generalLink(l);

}

//////////////////////////////////////////////////

// magic history links

//

function getHistoryInfo(wikipage, whatNext) {

log('getHistoryInfo');

getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory);

}

// FIXME eliminate pg.idNumber ... how? :-(

function getHistory(wikipage, onComplete) {

log('getHistory');

var url;

if (getValueOf('popupUseQueryInterface')) {

url = pg.wiki.wikibase + '/query.php?format=json&what=revisions&titles=' +

new Title(wikipage).urlString() + '&rvlimit=' + getValueOf('popupHistoryLimit');

} else {

url = pg.wiki.titlebase + new Title(wikipage).urlString() +

'&action=history' + '&limit=' + getValueOf('popupHistoryLimit');

}

log('getHistory: url='+url);

return startDownload(url, pg.idNumber+'history', onComplete);

}

function processHistory(download) {

if (getValueOf('popupUseQueryInterface')) {

return processHistoryQuery(download);

}

return processHistoryScreenScrape(download);

}

function processHistoryScreenScrape(download) {

// screen scrape alert

var d=download.data;

// pg.misc.data=d; // for debugging

var edits=[];

var split=d.split('

  • ');

    for (var i=0; i

    var histRe=RegExp(

    '^[(].*?type="radio" value="([0-9]*)".*?class=\'history-user\'>' +

    '

    var match=histRe.exec(split[i]);

    if (match) {

    edits.push({ oldid: match[1], editor: match[4] });

    }

    }

    var userName=getValueOf('popupUserName') ||

    Cookie.read(pg.wiki.userNameCookie).split('+').join('_');

    return finishProcessHistory(edits, userName);

    }

    function processHistoryQuery(download) {

    log ('processHistoryQuery');

    var d=download.data;

    log('d='+d);

    var jsobj;

    try {

    log('trying to parse JSON');

    log('jsobj=' + d);

    eval('jsobj=' + d);

    log('done eval; jsobj='+jsobj);

    window.x=jsobj;

    var p=jsobj['pages'];

    log('got p');

    for (var pageid in p) {

    var revisions=p[pageid]['revisions'];

    // we only get the first one

    break;

    }

    log('got revisions');

    log(revisions.length +' of them');

    } catch (someError) {

    log('Something went wrong with JSON business');

    return finishProcessHistory([]);

    }

    var edits=[];

    for (var i=0; i

    edits.push({ oldid: revisions[i]['revid'], editor: revisions[i]['user'] });

    }

    log('processed ' + edits.length + ' edits');

    var userName=getValueOf('popupUserName') ||

    unescape(Cookie.read(pg.wiki.userNameCookie).split('+').join(' '));

    return finishProcessHistory(edits, userName);

    }

    function finishProcessHistory(edits, userName) {

    var histInfo={};

    histInfo.edits=edits;

    histInfo.userName=userName;

    for (var i=0; i

    if (typeof histInfo.myLastEdit == 'undefined' && userName && edits[i].editor==userName) {

    histInfo.myLastEdit={index: i, oldid: edits[i].oldid, previd: (i==0 ? null : edits[i-1].oldid)};

    }

    if (typeof histInfo.firstNewEditor == 'undefined' && edits[i].editor != edits[0].editor) {

    histInfo.firstNewEditor={index:i, oldid:edits[i].oldid, previd: (i==0 ? null : edits[i-1].oldid)};

    }

    }

    //pg.misc.historyInfo=histInfo;

    return histInfo;

    }

    //

    // ENDFILE: links.js

    // STARTFILE: options.js

    //////////////////////////////////////////////////

    // options

    // check for cookies and existing value, else use default

    function defaultize(x) {

    var val=null;

    if (x!='popupCookies') {

    defaultize('popupCookies');

    if (pg.option.popupCookies && (val=Cookie.read(x))) {

    pg.option[x]=val;

    return;

    }

    }

    if (pg.option[x]===null || typeof pg.option[x]=='undefined') {

    if (typeof window[x] != 'undefined' ) pg.option[x]=window[x];

    else pg.option[x]=pg.optionDefault[x];

    }

    }

    function newOption(x, def) {

    pg.optionDefault[x]=def;

    }

    function setDefault(x, def) {

    return newOption(x, def);

    }

    function getValueOf(varName) {

    defaultize(varName);

    return pg.option[varName];

    }

    function useDefaultOptions() { // for testing

    for (var p in pg.optionDefault) {

    pg.option[p]=pg.optionDefault[p];

    if (typeof window[p]!='undefined') { delete window[p]; }

    }

    }

    function setOptions() {

    // user-settable parameters and defaults

    // Basic options

    newOption('popupDelay', 0.5);

    newOption('popupHideDelay', 0.5);

    newOption('simplePopups', false);

    newOption('popupStructure', 'shortmenus'); // see later - default for popupStructure is 'original' if simplePopups is true

    newOption('popupActionsMenu', true);

    newOption('popupSetupMenu', true);

    newOption('popupAdminLinks', false);

    newOption('popupShortcutKeys', false);

    newOption('popupHistoricalLinks', true);

    newOption('popupOnlyArticleLinks', true);

    newOption('removeTitles', true);

    newOption('popupMaxWidth', 350);

    newOption('popupInitialWidth', false); // integer or false

    newOption('popupSimplifyMainLink', true);

    newOption('popupAppendRedirNavLinks', true);

    newOption('popupTocLinks', false);

    newOption('popupSubpopups', true);

    newOption('popupUserName', ''); // should be magically detected with cookies if this isn't set

    newOption('popupDragHandle', false /* 'popupTopLinks' */);

    newOption('popupLazyPreviews', true);

    newOption('popupLazyDownloads', true);

    newOption('popupAllDabsStubs', false);

    newOption('popupDebugging', false);

    newOption('popupAdjustDiffDates', true),

    //

    // images

    newOption('popupImages', true);

    newOption('imagePopupsForImages', true);

    newOption('popupNeverGetThumbs', false);

    newOption('popupImagesFromThisWikiOnly', false);

    newOption('popupMinImageWidth', 50);

    newOption('popupLoadImagesSequentially', false);

    //newOption('popupImagesToggleSize', true);

    newOption('popupThumbAction', 'imagepage'); //'sizetoggle');

    newOption('popupImageSize', 60);

    newOption('popupShowNonCommonsImages', false);

    // redirs, dabs, reversion

    newOption('popupFixRedirs', false);

    newOption('popupRedirAutoClick', 'wpDiff');

    newOption('popupFixDabs', false);

    newOption('popupRevertSummaryPrompt', false);

    newOption('popupRedlinkRemoval', false);

    newOption('popupWatchDisambiggedPages', null);

    newOption('popupWatchRedirredPages', null);

    // navlinks

    newOption('popupNavLinks', true);

    newOption('popupNavLinkSeparator', ' ⋅ ');

    newOption('popupLastEditLink', true);

    newOption('popupEditCounterTool', 'interiot');

    newOption('popupEditCounterUrl', '');

    newOption('popupExtraUserMenu', '');

    //

    // previews etc

    newOption('popupPreviews', true);

    newOption('popupSummaryData', true);

    newOption('popupMaxPreviewSentences', 4);

    newOption('popupMaxPreviewCharacters', 600);

    newOption('popupLastModified', true);

    newOption('popupPreviewKillTemplates', true);

    newOption('popupPreviewRawTemplates', false);

    newOption('popupPreviewFirstParOnly', true);

    newOption('popupPreviewCutHeadings', true);

    //

    // diffs

    newOption('popupPreviewDiffs', true);

    newOption('popupDiffMaxLines', 100);

    newOption('popupDiffContextLines', 2);

    newOption('popupDiffContextCharacters', 40);

    newOption('popupDiffDates', true);

    newOption('popupDiffDatePrinter', 'toLocaleString');

    // edit summaries. God, these are ugly.

    newOption('popupFixDabsSummary', popupString('defaultpopupFixDabsSummary') );

    newOption('popupExtendedRevertSummary', popupString('defaultpopupExtendedRevertSummary') );

    newOption('popupTimeOffset', null);

    newOption('popupRevertSummary', popupString('defaultpopupRevertSummary') );

    newOption('popupRevertToPreviousSummary', popupString('defaultpopupRevertToPreviousSummary') );

    newOption('popupQueriedRevertSummary', popupString('defaultpopupQueriedRevertSummary') );

    newOption('popupQueriedRevertToPreviousSummary', popupString('defaultpopupQueriedRevertToPreviousSummary') );

    newOption('popupFixRedirsSummary', popupString('defaultpopupFixRedirsSummary') );

    newOption('popupRedlinkSummary', popupString('defaultpopupRedlinkSummary') );

    newOption('popupRmDabLinkSummary', popupString('defaultpopupRmDabLinkSummary') );

    //

    // misc

    newOption('popupCookies', false);

    newOption('popupHistoryLimit', 50);

    //

    newOption('popupFilters', [popupFilterStubDetect, popupFilterDisambigDetect,

    popupFilterPageSize, popupFilterCountLinks,

    popupFilterCountImages, popupFilterCountCategories,

    popupFilterLastModified]);

    newOption('extraPopupFilters', []);

    newOption('popupOnEditSelection', true);

    newOption('popupUseQueryInterface', true);

    newOption('popupPreviewHistory', true);

    newOption('popupImageLinks', true);

    newOption('popupCategoryMembers', true);

    newOption('popupHistoryPreviewLimit', 25);

    newOption('popupContribsPreviewLimit',25);

    //

    // new windows

    newOption('popupNewWindows', false);

    newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true});

    }

    // ENDFILE: options.js

    // STARTFILE: strings.js

    //

    //////////////////////////////////////////////////

    // Translatable strings

    //////////////////////////////////////////////////

    //

    // See instructions at

    // http://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation

    pg.string = {

    /////////////////////////////////////

    // summary data, searching etc.

    /////////////////////////////////////

    'article': 'article',

    'category': 'category',

    'categories': 'categories',

    'image': 'image',

    'images': 'images',

    'stub': 'stub',

    'section stub': 'section stub',

    'Empty page': 'Empty page',

    'kB': 'kB',

    'bytes': 'bytes',

    'day': 'day',

    'days': 'days',

    'hour': 'hour',

    'hours': 'hours',

    'minute': 'minute',

    'minutes': 'minutes',

    'second': 'second',

    'seconds': 'seconds',

    'week': 'week',

    'weeks': 'weeks',

    'search': 'search',

    'SearchHint': 'Find English Wikipedia articles containing %s',

    'web': 'web',

    'global': 'global',

    'globalSearchHint': 'Search across Wikipedias in different languages for %s',

    'googleSearchHint': 'Google for %s',

    /////////////////////////////////////

    // article-related actions and info

    // (some actions also apply to user pages)

    /////////////////////////////////////

    'actions': 'actions', ///// view articles and view talk

    'popupsMenu': 'popups',

    'togglePreviewsHint': 'Toggle preview generation in popups on this page',

    'toggle previews': 'toggle previews',

    'reset': 'reset',

    'disable': 'disable popups',

    'disablePopupsHint': 'Disable popups on this page. Reload page to re-enable.',

    'purgePopupsHint': 'Reset popups, clearing all cached popup data.',

    'PopupsHint': 'Reset popups, clearing all cached popup data.',

    'spacebar': 'space',

    'view': 'view',

    'view article': 'view article',

    'viewHint': 'Go to %s',

    'talk': 'talk',

    'talk page': 'talk page',

    'this revision': 'this revision',

    'revision %s of %s': 'revision %s of %s',

    'Revision %s of %s': 'Revision %s of %s',

    'the revision prior to revision %s of %s': 'the revision prior to revision %s of %s',

    'Toggle image size': 'Click to toggle image size',

    'del': 'del', ///// delete, protect, move

    'delete': 'delete',

    'deleteHint': 'Delete %s',

    'undeleteShort': 'un',

    'UndeleteHint': 'Show the deletion history for %s',

    'protect': 'protect',

    'protectHint': 'Restrict editing rights to %s',

    'unprotectShort': 'un',

    'unprotectHint': 'Allow %s to be edited by anyone again',

    'move': 'move',

    'move page': 'move page',

    'MovepageHint': 'Change the title of %s',

    'edit': 'edit', ///// edit articles and talk

    'edit article': 'edit article',

    'editHint': 'Change the content of %s',

    'edit talk': 'edit talk',

    'new': 'new',

    'new topic': 'new topic',

    'newSectionHint': 'Start a new section on %s',

    'null edit': 'null edit',

    'nullEditHint': 'Submit an edit to %s, making no changes ',

    'hist': 'hist', ///// history, diffs, editors, related

    'history': 'history',

    'historyHint': 'List the changes made to %s',

    'last': 'last',

    'lastEdit': 'lastEdit',

    'show last edit': 'most recent edit',

    'Show the last edit': 'Show the effects of the most recent change',

    'lastContrib': 'lastContrib',

    'last set of edits': 'latest edits',

    'lastContribHint': 'Show the net effect of changes made by the last editor',

    'cur': 'cur',

    'diffCur': 'diffCur',

    'Show changes since revision %s': 'Show changes since revision %s',

    '%s old': '%s old', // as in 4 weeks old

    'oldEdit': 'oldEdit',

    'purge': 'purge',

    'purgeHint': 'Demand a fresh copy of %s',

    'raw': 'source',

    'rawHint': 'Download the source of %s',

    'render': 'simple',

    'renderHint': 'Show a plain HTML version of %s',

    'Show the edit made to get revision': 'Show the edit made to get revision',

    'sinceMe': 'sinceMe',

    'changes since mine': 'diff my edit',

    'sinceMeHint': 'Show changes since my last edit',

    'Couldn\'t find an edit by %s\nin the last %s edits to\n%s': 'Couldn\'t find an edit by %s\nin the last %s edits to\n%s',

    'eds': 'eds',

    'editors': 'editors',

    'editorListHint': 'List the users who have edited %s',

    'related': 'related',

    'relatedChanges': 'relatedChanges',

    'related changes': 'related changes',

    'RecentchangeslinkedHint': 'Show changes in articles related to %s',

    'editOld': 'editOld', ///// edit old version, or revert

    'rv': 'rv',

    'revert': 'revert',

    'revertHint': 'Revert to %s',

    'defaultpopupRedlinkSummary': 'Removing link to empty page %s using popups',

    'defaultpopupFixDabsSummary': 'Disambiguate %s to %s using popups',

    'defaultpopupFixRedirsSummary': 'Redirect bypass from %s to %s using popups',

    'defaultpopupExtendedRevertSummary': 'Revert to revision dated %s by %s, oldid %s using popups',

    'defaultpopupRevertToPreviousSummary': 'Revert to the revision prior to revision %s using popups',

    'defaultpopupRevertSummary': 'Revert to revision %s using popups',

    'defaultpopupQueriedRevertToPreviousSummary': 'Revert to the revision prior to revision $1 dated $2 by $3 using popups',

    'defaultpopupQueriedRevertSummary': 'Revert to revision $1 dated $2 by $3 using popups',

    'defaultpopupRmDabLinkSummary': 'Remove link to dab page %s using popups',

    'Redirects': 'Redirects', // as in Redirects to ...

    ' to ': ' to ', // as in Redirects to ...

    'Bypass redirect': 'Bypass redirect',

    'Fix this redirect': 'Fix this redirect',

    'disambig': 'disambig', ///// add or remove dab etc.

    'disambigHint': 'Disambiguate this link to %s',

    'Click to disambiguate this link to:': 'Click to disambiguate this link to:',

    'remove this link': 'remove this link',

    'remove all links to this page from this article': 'remove all links to this page from this article',

    'remove all links to this disambig page from this article': 'remove all links to this disambig page from this article',

    'mainlink': 'mainlink', ///// links, watch, unwatch

    'wikiLink': 'wikiLink',

    'wikiLinks': 'wikiLinks',

    'links here': 'links here',

    'whatLinksHere': 'whatLinksHere',

    'what links here': 'what links here',

    'WhatlinkshereHint': 'List the pages that are hyperlinked to %s',

    'unwatchShort': 'un',

    'watchThingy': 'watch', // called watchThingy because {}.watch is a function

    'watchHint': 'Add %s to my watchlist',

    'unwatchHint': 'Remove %s from my watchlist',

    'Only found one editor: %s made %s edits': 'Only found one editor: %s made %s edits',

    '%s seems to be the last editor to the page %s': '%s seems to be the last editor to the page %s',

    'rss': 'rss',

    /////////////////////////////////////

    // diff previews

    /////////////////////////////////////

    'Diff truncated for performance reasons': 'Diff truncated for performance reasons',

    'Old revision': 'Old revision',

    'New revision': 'New revision',

    'Something went wrong :-(': 'Something went wrong :-(',

    'Empty revision, maybe non-existent': 'Empty revision, maybe non-existent',

    'Unknown date': 'Unknown date',

    /////////////////////////////////////

    // other special previews

    /////////////////////////////////////

    'Empty category': 'Empty category',

    'Category members (%s shown)': 'Category members (%s shown)',

    'No image links found': 'No image links found',

    'File links': 'File links',

    'not commons': 'There is no file with this name on the Wikimedia Commons.',

    'commons only': 'This file is from the Wikimedia Commons.',

    'No image found': 'No image found',

    'commons dupe': 'The same file appears to be available on the Wikimedia Commons.',

    'commons conflict': 'A different file with the same name is available on the Wikimedia Commons.',

    /////////////////////////////////////

    // user-related actions and info

    /////////////////////////////////////

    'user': 'user', ///// user page, talk, email, space

    'user page': 'user page',

    'user talk': 'user talk',

    'edit user talk': 'edit user talk',

    'leave comment': 'leave comment',

    'email': 'email',

    'email user': 'email user',

    'EmailuserHint': 'Send an email to %s',

    'space': 'space', // short form for userSpace link

    'PrefixindexHint': 'Show pages in the userspace of %s',

    'count': 'count', ///// contributions, tree, log

    'edit counter': 'edit counter',

    'katelinkHint': 'Count the countributions made by %s',

    'contribs': 'contribs',

    'contributions': 'contributions',

    'ContributionsHint': 'List the contributions made by %s',

    'tree': 'tree',

    'contribsTreeHint': 'Explore %s\'s contributions by namespace and by article',

    'log': 'log',

    'user log': 'user log',

    'userLogHint': 'Show %s\'s user log',

    'arin': 'ARIN lookup', ///// ARIN lookup, block user or IP

    'Look up %s in ARIN whois database': 'Look up %s in the ARIN whois database',

    'unblockShort': 'un',

    'block': 'block',

    'block user': 'block user',

    'IpblocklistHint': 'Unblock %s',

    'BlockipHint': 'Prevent %s from editing',

    'block log': 'block log',

    'blockLogHint': 'Show the block log for %s',

    'protectLogHint': 'Show the protection log for %s',

    'pageLogHint': 'Show the page log for %s',

    'deleteLogHint': 'Show the deletion log for %s',

    'Invalid %s %s': 'The option %s is invalid: %s',

    /////////////////////////////////////

    // Autoediting

    /////////////////////////////////////

    'Enter a non-empty edit summary or press cancel to abort': 'Enter a non-empty edit summary or press cancel to abort',

    'Failed to get revision information, please edit manually.\n\n': 'Failed to get revision information, please edit manually.\n\n',

    'The %s button has been automatically clicked. Please wait for the next page to load.': 'The %s button has been automatically clicked. Please wait for the next page to load.',

    'Could not find button %s. Please check the settings in your javascript file.': 'Could not find button %s. Please check the settings in your javascript file.',

    /////////////////////////////////////

    // Popups setup

    /////////////////////////////////////

    'Open full-size image': 'Open full-size image',

    'zxy': 'zxy'

    };

    function popupString(str) {

    if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { return popupStrings[str]; }

    if (pg.string[str]) { return pg.string[str]; }

    return str;

    }

    function tprintf(str,subs) {

    if (typeof subs != typeof []) { subs = [subs]; }

    return simplePrintf(popupString(str), subs);

    }

    //

    // ENDFILE: strings.js