User:AxelBoldt/Gadget-popups.js
var popupVersion="en:MediaWiki:Gadget-popups.js " + /*/{{subst:Selfsubst/now string|js|/*/ "2015-06-26 14:13:40 (UTC)" /*/}}/*/;
// 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: مدیا מיוחד Мэдыя **
// ** **
// **********************************************************************
//////////////////////////////////////////////////
// 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;
}
/// Local Variables: ///
/// mode:c ///
/// End: ///
// ENDFILE: main.js
// STARTFILE: actions.js
function setupTooltips(container, remove, force, popData) {
log('setupTooltips, container='+container+', remove='+remove);
if (!container) {
//
// the main initial call
if (getValueOf('popupOnEditSelection') && window.doSelectionPopup && document && document.editform && document.editform.wpTextbox1) {
document.editform.wpTextbox1.onmouseup=doSelectionPopup;
}
//
// article/content is a structure-dependent thing
container = defaultPopupsContainer();
}
if (!remove && !force && container.ranSetupTooltipsAlready) { return; }
container.ranSetupTooltipsAlready = !remove;
var anchors;
anchors=container.getElementsByTagName('A');
setupTooltipsLoop(anchors, 0, 250, 100, remove, popData);
}
function defaultPopupsContainer() {
if (getValueOf('popupOnlyArticleLinks')) {
return document.getElementById('mw_content') ||
document.getElementById('content') ||
document.getElementById('article') || document;
}
return document;
}
function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) {
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, popData);
} while (--j);
}
if (finish < anchors.length) {
setTimeout(function() {
setupTooltipsLoop(anchors,finish,howmany,sleep,remove,popData);},
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() {
var toc=document.getElementById('toc');
if (toc) {
var tocLinks=toc.getElementsByTagName('A');
var tocLen = tocLinks.length;
for (j=0; j removeTooltip(tocLinks[j], true); } } } function addTooltip(a, popData) { if ( !isPopupLink(a) ) { return; } a.onmouseover=mouseOverWikiLink; a.onmouseout= mouseOutWikiLink; a.onmousedown = killPopup; a.hasPopup = true; a.popData = popData; } function removeTooltip(a) { if ( !a.hasPopup ) { return; } a.onmouseover = null; a.onmouseout = null; if (a.originalTitle) { a.title = a.originalTitle; } a.hasPopup=false; } function removeTitle(a) { a.title=''; if (a.originalTitle) { return; } a.originalTitle=a.title; } function restoreTitle(a) { if ( a.title || !a.originalTitle ) { return; } a.title = a.originalTitle; } function registerHooks(np) { var popupMaxWidth=getValueOf('popupMaxWidth'); if (typeof popupMaxWidth == 'number') { var setMaxWidth = function () { np.mainDiv.style.maxWidth = popupMaxWidth + 'px'; np.maxWidth = popupMaxWidth; try { // 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"'); } } catch (errors) { errlog( "Running on IE8 are we not?: " + errors ); } }; np.addHook(setMaxWidth, 'unhide', 'before'); } // if (window.addPopupShortcuts && window.rmPopupShortcuts) { np.addHook(addPopupShortcuts, 'unhide', 'after'); np.addHook(rmPopupShortcuts, 'hide', 'before'); } // } function mouseOverWikiLink(evt) { if (!window.popupsReady || !window.popupsReady()) { return; } if (!evt && window.event) {evt=window.event}; return mouseOverWikiLink2(this, evt); } 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 ( ! /^(cite_note-|_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);
}
// var modid=0;
// if(!window.opera) { window.opera={postError: console.log}; }
function modifierKeyHandler(a) {
return function(evt) {
// opera.postError('modifierKeyHandler called' + (++modid));
// opera.postError(''+evt + modid);
// for (var i in evt) {
// opera.postError('' + modid + ' ' + i + ' ' + evt[i]);
// }
// opera.postError(''+evt.ctrlKey + modid);
var mod=getValueOf('popupModifier');
if (!mod) { return true; }
if (!evt && window.event) {evt=window.event};
// opera.postError('And now....'+modid);
// opera.postError(''+evt+modid);
// opera.postError(''+evt.ctrlKey+modid);
var modPressed = modifierPressed(evt);
var action = getValueOf('popupModifierAction');
// FIXME: probable bug - modifierPressed should be modPressed below?
if ( action == 'disable' && modifierPressed ) { return true; }
if ( action == 'enable' && !modifierPressed ) { return true; }
mouseOverWikiLink2(a, evt);
};
}
function modifierPressed(evt) {
var mod=getValueOf('popupModifier');
if (!mod) { return false; }
if (!evt && window.event) {evt=window.event};
// opera.postError('And now....'+modid);
// opera.postError(''+evt+modid);
// opera.postError(''+evt.ctrlKey+modid);
return ( evt && mod && evt[mod.toLowerCase() + 'Key'] );
}
function dealWithModifier(a,evt) {
if (!getValueOf('popupModifier')) { return false; }
var action = getValueOf('popupModifierAction');
if ( action == 'enable' && !modifierPressed(evt) ||
action == 'disable' && modifierPressed(evt) ) {
// if the modifier is needed and not pressed, listen for it until
// we mouseout of this link.
restoreTitle(a);
var addHandler='addEventListener';
var rmHandler='removeEventListener';
var on='';
if (!document.addEventListener) {
addHandler='attachEvent';
rmHandler='detachEvent';
on='on';
}
if (!document[addHandler]) { // forget it
return;
}
a.modifierKeyHandler=modifierKeyHandler(a);
switch (action) {
case 'enable':
document[addHandler](on+'keydown', a.modifierKeyHandler, false);
a[addHandler](on+'mouseout', function() {
document[rmHandler](on+'keydown',
a.modifierKeyHandler, false);
}, true);
break;
case 'disable':
document[addHandler](on+'keyup', a.modifierKeyHandler, false);
}
return true;
}
return false;
}
function mouseOverWikiLink2(a, evt) {
if (dealWithModifier(a,evt)) { return; }
if ( getValueOf('removeTitles') ) { removeTitle(a); }
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 (!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')) {
if (getValueOf('popupPreviewButton') && !a.simpleNoMore) {
var d=document.createElement('div');
d.className='popupPreviewButtonDiv';
var s=document.createElement('span');
d.appendChild(s);
s.className='popupPreviewButton';
s['on' + getValueOf('popupPreviewButtonEvent')] = function() {
a.simpleNoMore=true;
nonsimplePopupContent(a,article);
}
s.innerHTML=popupString('show preview');
setPopupHTML(d, 'popupPreview', a.navpopup.idNumber);
}
return;
}
if (a.navpopup.pending!==0 ) {
nonsimplePopupContent(a, article);
}
}
// simplePopupContent: the content that is shown even when simplePopups is true
function simplePopupContent(a, article) {
/* FIXME hack */ a.navpopup.hasPopupMenu=false;
a.navpopup.setInnerHTML(popupHTML(a));
fillEmptySpans({navpopup:a.navpopup});
if (getValueOf('popupDraggable'))
{
var dragHandle = getValueOf('popupDragHandle') || null;
if (dragHandle && dragHandle != 'all') {
dragHandle += a.navpopup.idNumber;
}
setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150);
}
//
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.parentPopup = (a.popData && a.popData.owner);
navpopup.article = article;
registerHooks(navpopup);
return navpopup;
}
function nonsimplePopupContent(a, article) {
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')) {
history=(params.action=='history');
}
//
a.navpopup.pending=0;
var x;
if (x=footnoteTarget(a)) {
footnotePreview(x, a.navpopup);
//
} else if ( diff || diff === 0 ) {
loadDiff(article, oldid, diff, a.navpopup);
} else if ( history ) {
loadAPIPreview('history', article, a.navpopup);
} else if ( pg.re.contribs.test(a.href) ) {
loadAPIPreview('contribs', article, a.navpopup);
} else if ( pg.re.backlinks.test(a.href) ) {
loadAPIPreview('backlinks', 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) )
) {
loadAPIPreview('imagepagepreview', article, a.navpopup);
loadImage(article, a.navpopup);
//
} else {
if (article.namespace() == pg.ns.category &&
getValueOf('popupCategoryMembers')) {
loadAPIPreview('category', article, a.navpopup);
} else if ((article.namespace() == pg.ns.user || article.namespace() == pg.ns.usertalk) &&
getValueOf('popupUserInfo')) {
loadAPIPreview('userinfo', article, a.navpopup);
}
startArticlePreview(article, oldid, a.navpopup);
}
}
function pendingNavpopTask(navpop) {
if (navpop && navpop.pending===null) { navpop.pending=0; }
++navpop.pending;
debugData(navpop);
}
function completedNavpopTask(navpop) {
if (navpop && navpop.pending) { --navpop.pending; }
debugData(navpop);
}
function startArticlePreview(article, oldid, navpop) {
navpop.redir=0;
loadPreview(article, oldid, navpop);
}
function 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';
navpop.addHook(function() {
getWiki(article, insertPreview, oldid, navpop);
return true; }, 'unhide', 'before', id);
} else {
getWiki(article, insertPreview, oldid, navpop);
}
}
function loadPreviewFromRedir(redirMatch, navpop) {
// redirMatch is a regex match
var target = new Title().fromWikiText(redirMatch[2]);
// overwrite (or add) anchor from original target
// mediawiki does overwrite; eg User:Lupin/foo3#Done
if ( navpop.article.anchor ) { target.anchor = navpop.article.anchor; }
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) {
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';
download.owner.addHook( function(){insertPreviewNow(download); return true;},
'unhide', 'after', id );
}
}
function insertPreviewNow(download) {
if (!download.owner) { return; }
var wikiText=download.data;
var navpop=download.owner;
completedNavpopTask(navpop);
var art=navpop.redirTarget || navpop.originalArticle;
//
makeFixDabs(wikiText, navpop);
if (getValueOf('popupSummaryData') && window.getPageInfo) {
var info=getPageInfo(wikiText, download);
setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber);
}
var imagePage='';
if (art.namespace()==pg.ns.image) { imagePage=art.toString(); }
else { imagePage=getValidImageFromWikiText(wikiText); }
if(imagePage) { loadImage(Title.fromWikiText(imagePage), navpop); }
//
if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); }
}
function insertArticlePreview(download, art, navpop) {
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) {
// deal with tricksy anchors
var d=anchorize(data, article.anchorString());
var urlBase=joinPath([pg.wiki.articlebase, article.urlString()]);
var p=new Previewmaker(d, 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*=+|\\{\\{\\s*'+getValueOf('popupAnchorRegexp')+'\\s*(?:\\|[^|}]*)*?\\s*'+literalizeRegex(anch)+'\\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(); if (pg.timer.checkPopupPosition !== null) { clearInterval(pg.timer.checkPopupPosition); pg.timer.checkPopupPosition=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.popups_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', 'popupPreviewMore', '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('<
}
return '';
};
pg.structures.original.popupTopLinks=function (x) {
log ('defaultstructure.popupTopLinks');
if (getValueOf('popupNavLinks')) { return navLinksHTML(x.article, x.hint, x.params); }
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{*<
// 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){<
+ editstr + '}'
var historystr='<
var watchstr='<
str+='
if(talk){' +
editOldidStr+'|<
'<
'}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.params);
};
pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks;
/** -- fancy -- **/
copyStructure('original', 'fancy');
pg.structures.fancy.popupTitle=function (x) {
return navlinkStringToHTML('<
};
pg.structures.fancy.popupTopLinks=function(x) {
var hist='<
var watch='<
var move='<
return navlinkStringToHTML('if(talk){' +
'<
'<
'}else{<
'*<
'*' + watch + '*' + move+'}
', x.article, x.params);
};
pg.structures.fancy.popupOtherLinks=function(x) {
var admin='<
var user='<
user+='if(ipuser){|< popupString('email')+'>>}if(admin){*< var normal='< return navlinkStringToHTML(' x.article, x.params); }; 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 return ' }; 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', 'popupPreviewMore', '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', 'popupPreviewMore', '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 maybe this stuff should be cached var s=[]; var dropdiv=' var enddiv='
if(user){' + user + '*}if(admin){'+admin+'if(user){
}else{*}}' + normal,
at the end and put one at the beginning
'+pg.structures.fancy.popupTopLinks(x).replace(RegExp('
$','i'),'');
var endspan='';
var hist='<
if (!shorter) { hist = '
'|<
var lastedit='<
var jsHistory='<
var linkshere='<
var related='<
var search='
'|<
var watch='
var protect='
'<
var del='
'<
var move='<
var nullPurge='
var viewOptions='
var editRow='if(oldid){' +
'
'
var markPatrolled='if(rcid){<
var newTopic='if(talk){<
var protectDelete='if(admin){' + protect + del + '}';
if (getValueOf('popupActionsMenu')) {
s.push( '<
} else {
s.push( dropdiv + '<
}
s.push( '
' + enddiv);// user menu starts here
var email='<
var contribs= 'if(wikimedia){
'if(admin){
s.push('if(user){*' + dropdiv + menuTitle('user'));
s.push('
' + enddiv + '}');// popups menu starts here
if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) {
x.navpop.hasPopupMenu=true;
s.push('*' + dropdiv + menuTitle('popupsMenu') + '
'+enddiv);}
return navlinkStringToHTML(s.join(''), x.article, x.params);
};
function menuTitle(s) {
return '' + popupString(s) + '';
}
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;
copyStructure('shortmenus', 'dabshortmenus');
pg.structures.dabshortmenus.popupLayout=function () {
return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks',
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
'popupData', 'popupMiscTools', ['popupRedlink'], 'popupFixDab',
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview'];
};
copyStructure('menus', 'dabmenus');
pg.structures.dabmenus.popupLayout=pg.structures.dabshortmenus.popupLayout;
//
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('<
return '
};
// 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 decodeURIComponent(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);
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 (!setupPopups.completed) { setupPopups(); } if (!document.editform || false || false ) { 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; // wikEd user script compatibility if (typeof(wikEdUseWikEd) != 'undefined') { if (wikEdUseWikEd == true) { WikEdUpdateFrame(); } } } setCheckbox('autominor', document.editform.wpMinoredit); setCheckbox('autowatch', document.editform.wpWatchthis); var rvid = getParamValue('autorv'); if (rvid) { var url=pg.wiki.apiwikibase + '?action=query&format=json&prop=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 autoClickToken() { return document.cookie.substr(document.cookie.indexOf("session=")+8,4); } function autoEdit3() { if( getParamValue('actoken') != autoClickToken()) return; 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) { try { var o=getJsObj(json); var edit = anyChild(o.query.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]); } // // 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 @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 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 @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 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 where @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: pg.wiki.articlePath + '/', // Only used for Insta previews with images. (not in popups) math: '/math/', images: 'http://upload.wikimedia.org/wikipedia/en/', // FIXME ( 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('^\\[\\[(?:File|Image|'+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(' else if (li=='#') ps(' // open a new dl only if the prev item is not a dl item (:, ; or empty) else switch(prev.charAt(i)) { case'':case'*':case'#': ps(' } switch (l_match[1].charAt(l_match[1].length-1)) { case '*': case '#': ps(' case ';': ps('
abort
aborted
field to true. */
null
on failure.
f(this)
on success
callback(d)
,d
is the new {@link Downloader}.
')
')
') }
var dt_match
// handle ;dt :dd format
if (dt_match = l_match[2].match(/(.*?)(:.*?)$/)) {
ps(parse_inline_nowiki(dt_match[1]))
ll.unshift(dt_match[2])
} else ps(parse_inline_nowiki(l_match[2]))
break
case ':':
ps('
}
prev=l_match[1]
}
// close remaining lists
for (var i=prev.length-1; i>=0; i--)
ps(f('?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl')))
}
function parse_table()
{
endl(f('
case '-': endl(f('
default: parse_table_data()
}
else if ($('!')) parse_table_data()
else sh()
}
function parse_table_data()
{
var td_line, match_i
// 1: "|+", '|' or '+'
// 2: ??
// 3: attributes ??
// TODO: finish commenting this regexp
var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/)
if (td_match[1] == '|+') ps('
else ps(' if (typeof td_match[3] != 'undefined') { ps(' ' + td_match[3]) match_i = 4 } else match_i = 2 ps('>') if (td_match[1] != '|+') { // use || or !! as a cell separator depending on context // NOTE: when split() is passed a regexp make sure to use non-capturing brackets td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/) ps(parse_inline_nowiki(td_line.shift())) while (td_line.length) ll.unshift(td_match[1] + td_line.pop()) } else ps(td_match[match_i]) var tc = 0, td = [] for (;remain(); td.push(sh())) if ($('|')) { if (!tc) break // we're at the outer-most level (no nested tables), skip to td parse else if (_(1)=='}') tc-- } else if (!tc && $('!')) break else if ($('{|')) tc++ if (td.length) ps(Insta.convert(td)) } function parse_pre() { ps('')
do endl(parse_inline_nowiki(ll[0].substring(1)) + "\n"); while (remain() && $(' '))
ps('')
}
function parse_block_image()
{
ps(parse_image(sh()))
}
function parse_image(str)
{
//
// get what's in between "Image:" and ""
var tag = str.substring(str.indexOf(':') + 1, str.length - 2);
var width;
var attr = [], filename, caption = '';
var thumb=0, frame=0, center=0;
var align='';
if (tag.match(/\|/)) {
// manage nested links
var nesting = 0;
var last_attr;
for (var i = tag.length-1; i > 0; i--) {
if (tag.charAt(i) == '|' && !nesting) {
last_attr = tag.substr(i+1);
tag = tag.substring(0, i);
break;
} else switch (tag.substr(i-1, 2)) {
case ']]':
nesting++;
i--;
break;
case '[[':
nesting--;
i--;
}
}
attr = tag.split(/\s*\|\s*/);
attr.push(last_attr);
filename = attr.shift();
var w_match;
for (;attr.length; attr.shift())
if (w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/)) width = w_match[1]
else switch(attr[0]) {
case 'thumb':
case 'thumbnail':
thumb=true;
case 'frame':
frame=true;
break;
case 'none':
case 'right':
case 'left':
center=false;
align=attr[0];
break;
case 'center':
center=true;
align='none';
break;
default:
if (attr.length == 1) caption = attr[0];
}
} else filename = tag;
var o='';
if (frame) {
if (align=='') align = 'right';
o += f("
if (thumb) {
if (!width) width = Insta.conf.wiki.default_thumb_width;
o += f("
f("
",Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename,
Insta.conf.paths.magnify_icon,
parse_inline_nowiki(caption)
)
} else {
o += '
}
o += '
} else if (align != '') {
o += f("
} else {
return make_image(filename, caption, width);
}
return center? f("
//
}
function parse_inline_nowiki(str)
{
var start, lastend=0
var substart=0, nestlev=0, open, close, subloop;
var html='';
while (-1 != (start = str.indexOf('
html += parse_inline_wiki(str.substring(lastend, start));
start += 8;
substart = start;
subloop = true;
do {
open = str.indexOf('
close = str.indexOf('', substart);
if (close<=open || open==-1) {
if (close==-1) {
return html + html_entities(str.substr(start));
}
substart = close+9;
if (nestlev) {
nestlev--;
} else {
lastend = substart;
html += html_entities(str.substring(start, lastend-9));
subloop = false;
}
} else {
substart = open+8;
nestlev++;
}
} while (subloop)
}
return html + parse_inline_wiki(str.substr(lastend));
}
function make_image(filename, caption, width)
{
//
// uppercase first letter in file name
filename = filename.charAt(0).toUpperCase() + filename.substr(1);
// replace spaces with underscores
filename = filename.replace(/ /g, '_');
caption = strip_inline_wiki(caption);
var md5 = hex_md5(filename);
var source = md5.charAt(0) + '/' + md5.substr(0,2) + '/' + filename;
if (width) width = "width='" + width + "px'";
var img = f("", Insta.conf.paths.images_fallback + source, Insta.conf.paths.images + source, (caption!=)? "alt='" + caption + "'" : , width);
return f("?", (caption!=)? "title='" + caption + "'" : , Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename, img);
//
}
function parse_inline_images(str)
{
//
var start, substart=0, nestlev=0;
var loop, close, open, wiki, html;
while (-1 != (start=str.indexOf('[[', substart))) {
if(str.substr(start+2).match(RegExp('^(Image|File|' + Insta.conf.locale.image + '):','i'))) {
loop=true;
substart=start;
do {
substart+=2;
close=str.indexOf(']]',substart);
open=str.indexOf('[[',substart);
if (close<=open||open==-1) {
if (close==-1) return str;
substart=close;
if (nestlev) {
nestlev--;
} else {
wiki=str.substring(start,close+2);
html=parse_image(wiki);
str=str.replace(wiki,html);
substart=start+html.length;
loop=false;
}
} else {
substart=open;
nestlev++;
}
} while (loop)
} else break;
}
//
return str;
}
// the output of this function doesn't respect the FILO structure of HTML
// but since most browsers can handle it I'll save myself the hassle
function parse_inline_formatting(str)
{
var em,st,i,li,o='';
while ((i=str.indexOf("''",li))+1) {
o += str.substring(li,i);
li=i+2;
if (str.charAt(i+2)=="'") {
li++;
st=!st;
o+=st?'':'';
} else {
em=!em;
o+=em?'':'';
}
}
return o+str.substr(li);
}
function parse_inline_wiki(str)
{
var aux_match;
str = parse_inline_images(str);
str = parse_inline_formatting(str);
// math
while (aux_match = str.match(/<(?:)math>(.*?)<\/math>/i)) {
var math_md5 = hex_md5(aux_match[1]);
str = str.replace(aux_match[0], f("", Insta.conf.paths.math+math_md5));
}
// Build a Mediawiki-formatted date string
var date = new Date;
var minutes = date.getUTCMinutes();
if (minutes < 10) minutes = '0' + minutes;
var date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), Insta.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear());
// text formatting
return str.
// signatures
replace(/~{5}(?!~)/g, date).
replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date).
replace(/~{3}(?!~)/g, Insta.conf.user.name).
// :Category:..., :Image:..., etc...
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):[^|]*?)\\]\\](\w*)','gi'), "$1$2").
// remove straight category and interwiki tags
replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),'').
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):.*?)\\|([^\\]]+?)\\]\\](\\w*)','gi'), "$2$3").
replace(/\[\[(\/[^|]*?)\]\]/g, f("$1", Insta.conf.baseUrl)).
replace(/\[\[(\/.*?)\|(.+?)\]\]/g, f("$2", Insta.conf.baseUrl)).
// Common links
replace(/\[\[([^|]*?)\]\](\w*)/g, f("$1$2", Insta.conf.paths.articles)).
// Links
replace(/\[\[(.*?)\|([^\]]+?)\]\](\w*)/g, f("$2$3", Insta.conf.paths.articles)).
// Namespace
replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, f("$2", Insta.conf.paths.articles)).
// External links
replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, "$4").
replace(/\[http:\/\/(.*?)\]/g, "[#]").
replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, "$1:$2$3").
replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*[^.,!?;: $])/g, "$1$2:$3$4").
replace('__NOTOC__','').
replace('__NOEDITSECTION__','');
}
/*
- /
function strip_inline_wiki(str)
{
return str
.replace(/\[\^\*\|(.*?)\]\]/g,'$1')
.replace(/\[\[(.*?)\]\]/g,'$1')
.replace(/(.*?)/g,'$1');
}
// begin parsing
for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) {
p=0
endl(f('
} else if ($(/^[*#:;]/)) {
p=0
parse_list()
} else if ($(' ')) {
p=0
parse_pre()
} else if ($('{|')) {
p=0
parse_table()
} else if ($(/^----+$/)) {
p=0
endl('
')
} else if ($(Insta.BLOCK_IMAGE)) {
p=0
parse_block_image()
} else {
// handle paragraphs
if ($$('')) {
if (p = (remain()>1 && ll[1]==(''))) endl('
')
} else {
if(!p) {
ps('
')
p=1
}
ps(parse_inline_nowiki(ll[0]) + ' ')
}
sh();
}
return o
};
window.wiki2html=function(txt,baseurl) {
Insta.conf.baseUrl=baseurl;
return Insta.convert(txt);
};
// ENDFILE: livepreview.js
// STARTFILE: pageinfo.js
//
function popupFilterPageSize(data) {
return formatBytes(data.length);
}
function popupFilterCountLinks(data) {
var num=countLinks(data);
return String(num) + ' ' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink'));
}
function popupFilterCountImages(data) {
var num=countImages(data);
return String(num) + ' ' + ((num!=1)?popupString('images'):popupString('image'));
}
function popupFilterCountCategories(data) {
var num=countCategories(data);
return String(num) + ' ' + ((num!=1)?popupString('categories'):popupString('category'));
}
function popupFilterLastModified(data,download) {
var lastmod=download.lastModified;
var now=new Date();
var age=now-lastmod;
if (lastmod && getValueOf('popupLastModified')) {
return (tprintf('%s old', [formatAge(age)])).replace(RegExp(' ','g'), ' ');
}
return '';
}
function formatAge(age) {
// coerce into a number
var a=0+age, aa=a;
var seclen = 1000;
var minlen = 60*seclen;
var hourlen = 60*minlen;
var daylen = 24*hourlen;
var weeklen = 7*daylen;
var numweeks = (a-a%weeklen)/weeklen; a = a-numweeks*weeklen; var sweeks = addunit(numweeks, 'week');
var numdays = (a-a%daylen)/daylen; a = a-numdays*daylen; var sdays = addunit(numdays, 'day');
var numhours = (a-a%hourlen)/hourlen; a = a-numhours*hourlen; var shours = addunit(numhours,'hour');
var nummins = (a-a%minlen)/minlen; a = a-nummins*minlen; var smins = addunit(nummins, 'minute');
var numsecs = (a-a%seclen)/seclen; a = a-numsecs*seclen; var ssecs = addunit(numsecs, 'second');
if (aa > 4*weeklen) { return sweeks; }
if (aa > weeklen) { return sweeks + ' ' + sdays; }
if (aa > daylen) { return sdays + ' ' + shours; }
if (aa > 6*hourlen) { return shours; }
if (aa > hourlen) { return shours + ' ' + smins; }
if (aa > 10*minlen) { return smins; }
if (aa > minlen) { return smins + ' ' + ssecs; }
return ssecs;
}
function addunit(num,str) { return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;}
function runPopupFilters(list, data, download) {
var ret=[];
for (var i=0; i if (list[i] && typeof list[i] == 'function') { var s=list[i](data, download, download.owner.article); if (s) { ret.push(s); } } } return ret; } function getPageInfo(data, download) { if (!data || data.length === 0) { return popupString('Empty page'); } var popupFilters=getValueOf('popupFilters') || []; var extraPopupFilters = getValueOf('extraPopupFilters') || []; var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download); var pageInfo=pageInfoArray.join(', '); if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); } return pageInfo; } // this could be improved! function countLinks(wikiText) { return wikiText.split('[[').length - 1; } // if N = # matches, n = # brackets, then // String.parenSplit(regex) intersperses the N+1 split elements // with Nn other elements. So total length is // L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1). function countImages(wikiText) { return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1); } function countCategories(wikiText) { return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1); } function popupFilterStubDetect(data, download, article) { var counts=stubCount(data, article); if (counts.real) { return popupString('stub'); } if (counts.sect) { return popupString('section stub'); } return ''; } function popupFilterDisambigDetect(data, download, article) { if (getValueOf('popupOnlyArticleDabStub') && article.namespace()) { return ''; } return (isDisambig(data, article)) ? popupString('disambig') : ''; } function formatBytes(num) { return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +' ' + popupString('bytes')) ; } // // ENDFILE: pageinfo.js // STARTFILE: titles.js /** @fileoverview Defines the {@link Title} class, and associated crufty functions. forms. {@link Stringwrapper} is the parent class of neater. /** Creates a new Stringwrapper. @constructor @class the Stringwrapper class. This base class is not really useful on its own; it just wraps various common string operations. function Stringwrapper() { /** Wrapper for this.toString().indexOf() @param {String} x @type integer */ this.indexOf=function(x){return this.toString().indexOf(x);}; /** Returns this.value. @type String */ this.toString=function(){return this.value;}; /** Wrapper for {@link String#parenSplit} applied to this.toString() @param {RegExp} x @type Array */ this.parenSplit=function(x){return this.toString().parenSplit(x);}; /** Wrapper for this.toString().substring() @param {String} x @param {String} y (optional) @type String */ this.substring=function(x,y){ if (typeof y=='undefined') { return this.toString().substring(x); } return this.toString().substring(x,y); }; /** Wrapper for this.toString().split() @param {String} x @type Array */ this.split=function(x){return this.toString().split(x);}; /** Wrapper for this.toString().replace() @param {String} x @param {String} y @type String */ this.replace=function(x,y){ return this.toString().replace(x,y); }; } /** Creates a new @constructor @class The Title class. Holds article titles and converts them into various forms. Also deals with anchors, by which we mean the bits of the article URL after a # character, representing locations within an article. @param {String} value The initial value to assign to the article. This must be the canonical title (see {@link Title#value}. Omit this in the constructor and use another function to set the title if this is unavailable. function Title(val) { /** The canonical article title. This must be in UTF-8 with no entities, escaping or nasties. Also, underscores should be replaced with spaces. @type String @private */ this.value=null; /** The canonical form of the anchor. This should be exactly as it appears in the URL, i.e. with the .C3.0A bits in. @type String */ this.anchor=''; this.setUtf(val); } Title.prototype=new Stringwrapper(); /** Returns the canonical representation of the article title, optionally without anchor. @param {boolean} omitAnchor @fixme Decide specs for anchor @return String The article title and the anchor. Title.prototype.toString=function(omitAnchor) { return this.value + ( (!omitAnchor && this.anchor) ? '#' + this.anchorString() : '' ); }; Title.prototype.anchorString=function() { if (!this.anchor) { return ''; } var split=this.anchor.parenSplit(/((?:[.][0-9A-F]{2})+)/); var len=split.length; for (var j=1; j // FIXME s/decodeURI/decodeURIComponent/g ? split[j]=decodeURIComponent(split[j].split('.').join('%')).split('_').join(' '); } return split.join(''); }; Title.prototype.urlAnchor=function() { var split=this.anchor.parenSplit('/((?:[%][0-9A-F]{2})+)/'); var len=split.length; for (var j=1; j split[j]=split[j].split('%').join('.'); } return split.join(''); }; Title.prototype.anchorFromUtf=function(str) { this.anchor=encodeURIComponent(str.split(' ').join('_')) .split('%3A').join(':').split("'").join('%27').split('%').join('.'); }; Title.fromURL=function(h) { return new Title().fromURL(h); }; Title.prototype.fromURL=function(h) { if (typeof h != 'string') { this.value=null; return this; } // NOTE : playing with decodeURI, encodeURI, escape, unescape, // we seem to be able to replicate the IE borked encoding // IE doesn't do this new-fangled utf-8 thing. // and it's worse than that. // IE seems to treat the query string differently to the rest of the url // the query is treated as bona-fide utf8, but the first bit of the url is pissed around with // we fix up & for all browsers, just in case. var splitted=h.split('?'); splitted[0]=splitted[0].split('&').join('%26'); if (pg.flag.linksLikeIE6) { splitted[0]=encodeURI(decode_utf8(splitted[0])); } h=splitted.join('?'); var contribs=pg.re.contribs.exec(h); if (contribs !== null) { if (contribs[1]=='title=') { contribs[3]=contribs[3].split('+').join(' '); } var u=new Title(contribs[3]); this.setUtf(this.decodeNasties(pg.ns.user + ':' + u.stripNamespace())); return this; } var email=pg.re.email.exec(h); if (email !== null) { this.setUtf(this.decodeNasties(pg.ns.user + ':' + new Title(email[3]).stripNamespace())); return this; } var backlinks=pg.re.backlinks.exec(h); if (backlinks) { this.setUtf(this.decodeNasties(new Title(backlinks[3]))); return this; } // no more special cases to check -- // hopefully it's not a disguised user-related or specially treated special page var m=pg.re.main.exec(h); if(m===null) { this.value=null; } else { var fromBotInterface = /[?](.+[&])?title=/.test(h); if (fromBotInterface) { m[2]=m[2].split('+').join('_'); } var extracted = m[2] + (m[3] ? '#' + m[3] : ''); if (pg.flag.isSafari && /%25[0-9A-Fa-f]{2}/.test(extracted)) { // Fix Safari issue // Safari sometimes encodes % as %25 in UTF-8 encoded strings like %E5%A3 -> %25E5%25A3. this.setUtf(decodeURIComponent(unescape(extracted))); } else { this.setUtf(this.decodeNasties(extracted)); } } return this; }; Title.prototype.decodeNasties=function(txt) { var ret= this.decodeEscapes(decodeURI(txt)); ret = ret.replace(/[_ ]*$/, ''); return ret; }; Title.prototype.decodeEscapes=function(txt) { var split=txt.parenSplit(/((?:[%][0-9A-Fa-f]{2})+)/); var len=split.length; for (var i=1; i // FIXME is decodeURIComponent better? split[i]=unescape(split[i]); } return split.join(''); }; Title.fromAnchor=function(a) { return new Title().fromAnchor(a); }; Title.prototype.fromAnchor=function(a) { if (!a) { this.value=null; return this; } return this.fromURL(a.href); }; Title.fromWikiText=function(txt) { return new Title().fromWikiText(txt); }; Title.prototype.fromWikiText=function(txt) { // FIXME - testing needed if (!pg.flag.linksLikeIE6) { txt=myDecodeURI(txt); } this.setUtf(txt); return this; }; Title.prototype.hintValue=function(){ if(!this.value) { return ''; } return safeDecodeURI(this.value); }; // Title.prototype.toUserName=function(withNs) { if (this.namespace() != pg.ns.user && this.namespace() != pg.ns.usertalk) { this.value=null; return; } this.value = (withNs ? pg.ns.user + ':' : '') + this.stripNamespace().split('/')[0]; }; Title.prototype.userName=function(withNs) { var t=(new Title(this.value)); t.toUserName(withNs); if (t.value) { return t; } return null; }; Title.prototype.toTalkPage=function() { // convert article to a talk page, or if we can't return null // or, in other words, return null if this ALREADY IS a talk page // and return the corresponding talk page otherwise if (this.value===null) { return null; } var talkRegex=namespaceListToRegex(pg.ns.talkList); if (talkRegex.exec(this.value)) { this.value=null; return null;} var nsReg=namespaceListToRegex(pg.ns.withTalkList); var splitted=this.value.parenSplit(nsReg); if (splitted.length<2) { this.value= (pg.ns.talkList[0]+':'+this.value).split(' ').join('_'); return this.value; } for (var i=0; i< pg.ns.withTalkList.length; ++i) { if (splitted[1]==pg.ns.withTalkList[i]) { splitted[1]=pg.ns.talkList[i]; this.value=splitted.join(':').substring(1).split(' ').join('_'); return this.value; } } this.value=null; return null; }; // Title.prototype.namespace=function() { var n=this.value.indexOf(':'); if (n<0) { return ''; } var list=pg.ns.list; for (var i=0; i if (upcaseFirst(list[i]) == this.value.substring(0,n)) { return list[i]; } } return ''; }; // Title.prototype.talkPage=function() { var t=new Title(this.value); t.toTalkPage(); if (t.value) { return t; } return null; }; Title.prototype.isTalkPage=function() { if (this.talkPage()===null) { return true; } return false; }; Title.prototype.toArticleFromTalkPage=function() { var talkRegex=namespaceListToRegex(pg.ns.talkList); var splitted=this.value.parenSplit(talkRegex); if (splitted.length < 2 || splitted[0].length > 0) { this.value=null; return null; } if (splitted[1]==pg.ns.talkList[0]) { splitted[1]=''; this.value=splitted.join(':').substring(2).split(' ').join('_'); return this.value; } for (var i=1; i< pg.ns.talkList.length; ++i) { if (splitted[1]==pg.ns.talkList[i] || splitted[1]==pg.ns.talkList[i].split(' ').join('_')) { splitted[1]=pg.ns.withTalkList[i]; this.value= splitted.join(':').substring(1).split(' ').join('_'); return this.value; } } this.value=null; return this.value; }; Title.prototype.articleFromTalkPage=function() { var t=new Title(this.value); t.toArticleFromTalkPage(); if (t.value) { return t; } return null; }; Title.prototype.articleFromTalkOrArticle=function() { var t=new Title(this.value); if ( t.toArticleFromTalkPage() ) { return t; } return this; }; Title.prototype.isIpUser=function() { return pg.re.ipUser.test(this.userName()); }; // Title.prototype.stripNamespace=function(){ // returns a string, not a Title var n=this.value.indexOf(':'); if (n<0) { return this.value; } var list=pg.ns.list; for (var i=0; i if (upcaseFirst(list[i]) == this.value.substring(0,n)) { return this.value.substring(n+1); } } return this.value; }; Title.prototype.setUtf=function(value){ if (!value) { this.value=''; return; } var anch=value.indexOf('#'); if(anch < 0) { this.value=value.split('_').join(' '); this.anchor=''; return; } this.value=value.substring(0,anch).split('_').join(' '); this.anchor=value.substring(anch+1); this.ns=null; // wait until namespace() is called }; Title.prototype.setUrl=function(urlfrag) { var anch=urlfrag.indexOf('#'); this.value=safeDecodeURI(urlfrag.substring(0,anch)); this.anchor=value.substring(anch+1); }; Title.prototype.append=function(x){ this.setUtf(this.value + x); }; Title.prototype.urlString=function(x) { x || ( x={} ); var v=this.toString(true); if (!x.omitAnchor && this.anchor) { v+= '#' + this.urlAnchor(); } if (!x.keepSpaces) { v=v.split(' ').join('_'); } return encodeURI(v).split('&').join('%26').split('?').join('%3F').split('+').join('%2B'); }; Title.prototype.removeAnchor=function() { return new Title(this.toString(true)); }; Title.prototype.toUrl=function() { return pg.wiki.titlebase + this.urlString(); }; function paramValue(param, url) { var s=url.parenSplit(RegExp('[?&]' + literalizeRegex(param) + '=([^?&]*)')); if (!url) { return null; } return s[1] || null; } function parseParams(url) { var ret={}; if (url.indexOf('?')==-1) { return ret; } var s=url.split('?').slice(1).join(); var t=s.split('&'); for (var i=0; i var z=t[i].split('='); z.push(null); ret[z[0]]=z[1]; } return ret; } // all sorts of stuff here // FIXME almost everything needs to be rewritten function oldidFromAnchor(a) { return paramValue('oldid', a.href); } //function diffFromAnchor(a) { return paramValue('diff', a.href); } function wikiMarkupToAddressFragment (str) { // for images var ret = safeDecodeURI(str); ret = ret.split(' ').join('_'); ret = encodeURI(ret); return ret; } // (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup) // (b) change spaces to underscores // (c) encodeURI (just the straight one, no pg.re.urlNoPopup) function myDecodeURI (str) { var ret; // FIXME decodeURIComponent?? try { ret=decodeURI(str.toString()); } catch (summat) { return str; } for (var i=0; i var from=pg.misc.decodeExtras[i].from; var to=pg.misc.decodeExtras[i].to; ret=ret.split(from).join(to); } return ret; } function safeDecodeURI(str) { var ret=myDecodeURI(str); return ret || str; } /////////// // TESTS // /////////// // function isIpUser(user) {return pg.re.ipUser.test(user);} function isDisambig(data, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } return ! article.isTalkPage() && pg.re.disambig.test(data); } function stubCount(data, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } var sectStub=0; var realStub=0; if (pg.re.stub.test(data)) { var s=data.parenSplit(pg.re.stub); for (var i=1; i if (s[i]) { ++sectStub; } else { ++realStub; } } } return { real: realStub, sect: sectStub }; } function isValidImageName(str){ // extend as needed... return ( str.indexOf('{') == -1 ); } function isInStrippableNamespace(article) { return ( findInArray( pg.ns.nonArticleList, article.namespace() ) > -1 ); } function isInMainNamespace(article) { return !isInStrippableNamespace(article); } function anchorContainsImage(a) { // iterate over children of anchor a // see if any are images if (a===null) { return false; } kids=a.childNodes; for (var i=0; i return false; } // function isPopupLink(a) { // NB for performance reasons, TOC links generally return true // they should be stripped out later if (!markNopopupSpanLinks.done) { markNopopupSpanLinks(); } if (a.inNopopupSpan || a.className=='sortheader') { return false; } // FIXME is this faster inline? if (a.onmousedown || a.getAttribute('nopopup')) { return false; } var h=a.href; if (!pg.re.basenames.test(h)) { return false; } if ( !pg.re.urlNoPopup.test(h) ) { return true; } return ( (pg.re.email.test(h) || pg.re.contribs.test(h) || pg.re.backlinks.test(h)) && h.indexOf('&limit=') == -1 ); } function markNopopupSpanLinks() { if( !getValueOf('popupOnlyArticleLinks')) fixVectorMenuPopups(); var s=getElementsByClassName(document, '*', "nopopups") for (var i=0; i var as=s[i].getElementsByTagName('a'); for (var j=0; j as[j].inNopopupSpan=true; } } markNopopupSpanLinks.done=true; } function fixVectorMenuPopups() { var vmenus = getElementsByClassName( document, 'div', 'vectorMenu'); for( i= 0; vmenus && i< vmenus.length; i++ ) { var h5 = vmenus[i].getElementsByTagName('h5')[0]; if( h5) var a = h5.getElementsByTagName('a')[0]; if( a ) a.inNopopupSpan=true; } } // ENDFILE: titles.js // STARTFILE: cookies.js // ////////////////////////////////////////////////// // Cookie handling // from http://www.quirksmode.org/js/cookies.html var Cookie= { create: function(name,value,days) { var expires; if (days) { var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); expires = "; expires="+date.toGMTString(); } else { expires = ""; } document.cookie = name+"="+value+expires+"; path=/"; }, read: function(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') { c = c.substring(1,c.length); } if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); } } return null; }, erase: function(name) { Cookie.create(name,"",-1); } }; // // ENDFILE: cookies.js // STARTFILE: getpage.js ////////////////////////////////////////////////// // Wiki-specific downloading // // Schematic for a getWiki call // // getWiki->-getPageWithCaching // | // false | true // getPage<-[findPictureInCache]->-onComplete(a fake download) // \. // (async)->addPageToCache(download)->-onComplete(download) /** @todo {document} @param {Title} article @param {Function} onComplete @param {integer} oldid @param {Navapopup} owner function getWiki(article, onComplete, oldid, owner) { // set ctype=text/css to get around opera gzip bug var url = pg.wiki.titlebase + article.removeAnchor().urlString() + '&action=raw&ctype=text/css'; if (oldid || oldid===0 || oldid==='0') { url += '&oldid='+oldid; } url += '&maxage=0&smaxage=0'; getPageWithCaching(url, onComplete, owner); } // check cache to see if page exists function getPageWithCaching(url, onComplete, owner) { log('getPageWithCaching, url='+url); var i=findInPageCache(url); if (i > -1) { var d=fakeDownload(url, owner.idNumber, onComplete, pg.cache.pages[i].data, pg.cache.pages[i].lastModified, owner); } else { var d=getPage(url, onComplete, owner); if (d && owner && owner.addDownload) { owner.addDownload(d); d.owner=owner; } } } function getPage(url, onComplete, owner) { log('getPage'); var callback= function (d) { if (!d.aborted) {addPageToCache(d); onComplete(d);} }; return startDownload(url, owner.idNumber, callback); } function findInPageCache(url) { for (var i=0; i if (url==pg.cache.pages[i].url) { return i; } } return -1; } function addPageToCache(download) { log('addPageToCache '+download.url); var page = {url: download.url, data: download.data, lastModified: download.lastModified}; return pg.cache.pages.push(page); } // ENDFILE: getpage.js // STARTFILE: md5-2.2alpha.js // /* * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message * Digest Algorithm, as defined in RFC 1321. * Version 2.2-alpha Copyright (C) Paul Johnston 1999 - 2005 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet * Distributed under the BSD License * See http://pajhome.org.uk/crypt/md5 for more info. */ /* * Configurable variables. You may need to tweak these to be compatible with * the server-side, but the defaults work in most cases. */ var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ /* * These are the functions you'll usually want to call * They take string arguments and return either hex or base-64 encoded strings */ function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); } function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); } function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); } function hex_hmac_md5(k, d) { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } function b64_hmac_md5(k, d) { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } function any_hmac_md5(k, d, e) { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } /* * Perform a simple self-test to see if the VM is working */ function md5_vm_test() { return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; } /* * Calculate the MD5 of a raw string */ function rstr_md5(s) { return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); } /* * Calculate the HMAC-MD5, of a key and some data (raw strings) */ function rstr_hmac_md5(key, data) { var bkey = rstr2binl(key); if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); } /* * Convert a raw string to a hex string */ function rstr2hex(input) { var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var output = ""; var x; for(var i = 0; i < input.length; i++) { x = input.charCodeAt(i); output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt( x & 0x0F); } return output; } /* * Convert a raw string to a base-64 string */ function rstr2b64(input) { var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var output = ""; var len = input.length; for(var i = 0; i < len; i += 3) { var triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i+2) : 0); for(var j = 0; j < 4; j++) { if(i * 8 + j * 6 > input.length * 8) output += b64pad; else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); } } return output; } /* * Convert a raw string to an arbitrary string encoding */ function rstr2any(input, encoding) { var divisor = encoding.length; var remainders = Array(); var i, q, x, quotient; /* Convert to an array of 16-bit big-endian values, forming the dividend */ var dividend = Array(input.length / 2); for(i = 0; i < dividend.length; i++) { dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); } /* * Repeatedly perform a long division. The binary array forms the dividend, * the length of the encoding is the divisor. Once computed, the quotient * forms the dividend for the next step. We stop when the dividend is zero. * All remainders are stored for later use. */ while(dividend.length > 0) { quotient = Array(); x = 0; for(i = 0; i < dividend.length; i++) { x = (x << 16) + dividend[i]; q = Math.floor(x / divisor); x -= q * divisor; if(quotient.length > 0 || q > 0) quotient[quotient.length] = q; } remainders[remainders.length] = x; dividend = quotient; } /* Convert the remainders to the output string */ var output = ""; for(i = remainders.length - 1; i >= 0; i--) output += encoding.charAt(remainders[i]); return output; } /* * Encode a string as utf-8. * For efficiency, this assumes the input is valid utf-16. */ function str2rstr_utf8(input) { var output = ""; var i = -1; var x, y; while(++i < input.length) { /* Decode utf-16 surrogate pairs */ x = input.charCodeAt(i); y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) { x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); i++; } /* Encode output as utf-8 */ if(x <= 0x7F) output += String.fromCharCode(x); else if(x <= 0x7FF) output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), 0x80 | ( x & 0x3F)); else if(x <= 0xFFFF) output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), 0x80 | ((x >>> 6 ) & 0x3F), 0x80 | ( x & 0x3F)); else if(x <= 0x1FFFFF) output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), 0x80 | ((x >>> 12) & 0x3F), 0x80 | ((x >>> 6 ) & 0x3F), 0x80 | ( x & 0x3F)); } return output; } /* * Encode a string as utf-16 */ function str2rstr_utf16le(input) { var output = ""; for(var i = 0; i < input.length; i++) output += String.fromCharCode( input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF); return output; } function str2rstr_utf16be(input) { var output = ""; for(var i = 0; i < input.length; i++) output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF); return output; } /* * Convert a raw string to an array of little-endian words * Characters >255 have their high-byte silently ignored. */ function rstr2binl(input) { var output = Array(input.length >> 2); for(var i = 0; i < output.length; i++) output[i] = 0; for(var i = 0; i < input.length * 8; i += 8) output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); return output; } /* * Convert an array of little-endian words to a string */ function binl2rstr(input) { var output = ""; for(var i = 0; i < input.length * 32; i += 8) output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); return output; } /* * Calculate the MD5 of an array of little-endian words, and a bit length. */ function binl_md5(x, len) { /* append padding */ x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); c = md5_ff(c, d, a, b, x[i+10], 17, -42063); b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d); } /* * These functions implement the four basic operations the algorithm uses. */ function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); } function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); } function md5_gg(a, b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); } function md5_hh(a, b, c, d, x, s, t) { return md5_cmn(b ^ c ^ d, a, b, x, s, t); } function md5_ii(a, b, c, d, x, s, t) { return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); } /* * Add integers, wrapping at 2^32. This uses 16-bit operations internally * to work around bugs in some JS interpreters. */ function safe_add(x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); } /* * Bitwise rotate a 32-bit number to the left. */ function bit_rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); } // // ENDFILE: md5-2.2alpha.js // STARTFILE: parensplit.js ////////////////////////////////////////////////// // parenSplit // String.prototype.parenSplit should do what ECMAscript says // String.prototype.split does, interspersing paren matches between // the split elements if (String('abc'.split(/(b)/))!='a,b,c') { // broken String.split, e.g. konq, IE String.prototype.parenSplit=function (re) { re=nonGlobalRegex(re); var s=this; var m=re.exec(s); var ret=[]; while (m && s) { // without the following loop, we have // 'ab'.parenSplit(/a|(b)/) != 'ab'.split(/a|(b)/) for(var i=0; i if (typeof m[i]=='undefined') m[i]=''; } ret.push(s.substring(0,m.index)); ret = ret.concat(m.slice(1)); s=s.substring(m.index + m[0].length); m=re.exec(s); } ret.push(s); return ret; }; } else { String.prototype.parenSplit=function (re) { return this.split(re); }; String.prototype.parenSplit.isNative=true; } function nonGlobalRegex(re) { var s=re.toString(); flags=''; for (var j=s.length; s.charAt(j) != '/'; --j) { if (s.charAt(j) != 'g') { flags += s.charAt(j); } } var t=s.substring(1,j); return RegExp(t,flags); } // ENDFILE: parensplit.js // STARTFILE: tools.js // IE madness with encoding // ======================== // // suppose throughout that the page is in utf8, like wikipedia // // if a is an anchor DOM element and a.href should consist of // // http://host.name.here/wiki/foo?bar=baz // // then IE gives foo as "latin1-encoded" utf8; we have foo = decode_utf8(decodeURI(foo_ie)) // but IE gives bar=baz correctly as plain utf8 // // --------------------------------- // // IE's xmlhttp doesn't understand utf8 urls. Have to use encodeURI here. // // --------------------------------- // // summat else // Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm // function encode_utf8(rohtext) { // dient der Normalisierung des Zeilenumbruchs rohtext = rohtext.replace(/\r\n/g,"\n"); var utftext = ""; for(var n=0; n { // ermitteln des Unicodes des aktuellen Zeichens var c=rohtext.charCodeAt(n); // alle Zeichen von 0-127 => 1byte if (c<128) utftext += String.fromCharCode(c); // alle Zeichen von 127 bis 2047 => 2byte else if((c>127) && (c<2048)) { utftext += String.fromCharCode((c>>6)|192); utftext += String.fromCharCode((c&63)|128);} // alle Zeichen von 2048 bis 66536 => 3byte else { utftext += String.fromCharCode((c>>12)|224); utftext += String.fromCharCode(((c>>6)&63)|128); utftext += String.fromCharCode((c&63)|128);} } return utftext; } function getJsObj(json) { try { var json_ret = eval('(' + json + ')'); } catch (someError) { errlog('Something went wrong with getJsobj, json='+json); return 1; } if( json_ret['warnings'] ) { for( var w=0; w < json_ret['warnings'].length; w++ ) { log( json_ret['warnings'][w]['*'] ); } } else if ( json_ret['error'] ) { errlog( json_ret['error'].code + ': ' + json_ret['error'].info ); } return json_ret; } function anyChild(obj) { for (var p in obj) { return obj[p]; } return null; } // function decode_utf8(utftext) { var plaintext = ""; var i=0, c=0, c1=0, c2=0; // while-Schleife, weil einige Zeichen uebersprungen werden while(i { c = utftext.charCodeAt(i); if (c<128) { plaintext += String.fromCharCode(c); i++;} else if((c>191) && (c<224)) { c2 = utftext.charCodeAt(i+1); plaintext += String.fromCharCode(((c&31)<<6) | (c2&63)); i+=2;} else { c2 = utftext.charCodeAt(i+1); c3 = utftext.charCodeAt(i+2); plaintext += String.fromCharCode(((c&15)<<12) | ((c2&63)<<6) | (c3&63)); i+=3;} } return plaintext; } function upcaseFirst(str) { if (typeof str != typeof || str==) return ''; return str.charAt(0).toUpperCase() + str.substring(1); } function findInArray(arr, foo) { if (!arr || !arr.length) { return -1; } var len=arr.length; for (var i=0; i return -1; } function nextOne (array, value) { // NB if the array has two consecutive entries equal // then this will loop on successive calls var i=findInArray(array, value); if (i<0) { return null; } return array[i+1]; } function literalizeRegex(str){ return str.replace(RegExp('([-.|()\\\\+?*^${}\\[\\]])', 'g'), '\\$1'); } String.prototype.entify=function() { //var shy=''; return this.split('&').join('&').split('<').join('<').split('>').join('>'/*+shy*/).split('"').join('"'); }; function findThis(array, value) { if (typeof array.length == 'undefined') { return null; } for (var i=0; i if (array[i]==value) { return i; } } return null; } function removeNulls(list) { var ret=[]; for (var i=0; i if (list[i]) { ret.push(list[i]); } } return ret; } function joinPath(list) { return removeNulls(list).join('/'); } function simplePrintf(str, subs) { if (!str || !subs) { return str; } var ret=[]; var s=str.parenSplit(/(%s|\$[0-9]+)/); var i=0; do { ret.push(s.shift()); if ( !s.length ) { break; } var cmd=s.shift(); if (cmd == '%s') { if ( i < subs.length ) { ret.push(subs[i]); } else { ret.push(cmd); } ++i; } else { var j=parseInt( cmd.replace('$', ''), 10 ) - 1; if ( j > -1 && j < subs.length ) { ret.push(subs[j]); } else { ret.push(cmd); } } } while (s.length > 0); return ret.join(''); } function max(a,b){return a
function min(a,b){return a>b ? b : a;} function isString(x) { return (typeof x === 'string' || x instanceof String); } //function isNumber(x) { return (typeof x === 'number' || x instanceof Number); } function isRegExp(x) { return x instanceof RegExp; } function isArray (x) { return x instanceof Array; } function isObject(x) { return x instanceof Object; } function isFunction(x) { return !isRegExp(x) && (typeof x === 'function' || x instanceof Function); } function repeatString(s,mult) { var ret=''; for (var i=0; i return ret; } function zeroFill(s, min) { min = min || 2; var t=s.toString(); return repeatString('0', min - t.length) + t; } function map(f, o) { if (isArray(o)) { return map_array(f,o); } return map_object(f,o); } function map_array(f,o) { var ret=[]; for (var i=0; i ret.push(f(o[i])); } return ret; } function map_object(f,o) { var ret={}; for (var i in o) { ret[o]=f(o[i]); } return ret; } // ENDFILE: tools.js // STARTFILE: dab.js // ////////////////////////////////////////////////// // Dab-fixing code // function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) { log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget); return changeLinkTargetLink( {newTarget: newTarget, text: newTarget.split(' ').join(' '), hint: tprintf('disambigHint', [newTarget]), summary: simplePrintf( getValueOf('popupFixDabsSummary'), [friendlyCurrentArticleName, newTarget ]), clickButton: 'wpDiff', minor: true, oldTarget: oldTarget, watch: getValueOf('popupWatchDisambiggedPages'), title: titleToEdit}); } function listLinks(wikitext, oldTarget, titleToEdit) { // mediawiki strips trailing spaces, so we do the same // testcase: http://en.wikipedia.org/w/index.php?title=Radial&oldid=97365633 var reg=RegExp('\\[\\[([^|]*?) *(\\||\\]\\])', 'gi'); var ret=[]; var splitted=wikitext.parenSplit(reg); // ^[a-z]+ should match interwiki links, hopefully (case-insensitive) // and ^[a-z]* should match those and :Category... style links too var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory'); var friendlyCurrentArticleName= oldTarget.toString(); var wikPos = getValueOf('popupDabWiktionary'); for (var i=1; i if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) { ret.push( retargetDab(splitted[i], oldTarget, friendlyCurrentArticleName, titleToEdit) ); } /* if */ } /* for loop */ ret = rmDupesFromSortedList(ret.sort()); if (wikPos) { var wikTarget='wiktionary:' + friendlyCurrentArticleName.replace( RegExp('^(.+)\\s+[(][^)]+[)]\\s*$'), '$1' ); var meth; if (wikPos.toLowerCase() == 'first') { meth = 'unshift'; } else { meth = 'push'; } ret[meth]( retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) ); } ret.push(changeLinkTargetLink( { newTarget: null, text: popupString('remove this link').split(' ').join(' '), hint: popupString("remove all links to this disambig page from this article"), clickButton: "wpDiff", oldTarget: oldTarget, summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName]), watch: getValueOf('popupWatchDisambiggedPages'), title: titleToEdit })); return ret; } function rmDupesFromSortedList(list) { var ret=[]; for (var i=0; i if (ret.length===0 || list[i]!=ret[ret.length-1]) { ret.push(list[i]); } } return ret; } function makeFixDab(data, navpop) { // grab title from parent popup if there is one; default exists in changeLinkTargetLink var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString()); var list=listLinks(data, navpop.originalArticle, titleToEdit); if (list.length===0) { log('listLinks returned empty list'); return null; } var html=' html+=list.join(', '); return html; } function makeFixDabs(wikiText, navpop) { if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) && Title.fromURL(location.href).namespace() != pg.ns.special && navpop.article.talkPage() ) { setPopupHTML(makeFixDab(wikiText, navpop), 'popupFixDab', navpop.idNumber); } } function popupRedlinkHTML(article) { return changeLinkTargetLink( { newTarget: null, text: popupString('remove this link').split(' ').join(' '), hint: popupString("remove all links to this page from this article"), clickButton: "wpDiff", oldTarget: article.toString(), summary: simplePrintf(getValueOf('popupRedlinkSummary'), [article.toString()])}); } // // ENDFILE: dab.js // STARTFILE: htmloutput.js function appendPopupContent(obj, elementId, popupId, onSuccess) { return setPopupHTML(obj, elementId, popupId, onSuccess, true); } // this has to use a timer loop as we don't know if the DOM element exists when we want to set the text function setPopupHTML (str, elementId, popupId, onSuccess, append) { if (elementId=='popupPreview') { } if (typeof popupId === 'undefined') { //console.error('popupId is not defined in setPopupHTML, html='+str.substring(0,100)); popupId = pg.idNumber; } var popupElement=document.getElementById(elementId+popupId); if (popupElement) { if (!append) { popupElement.innerHTML=''; } if (isString(str)) { popupElement.innerHTML+=str; } else { popupElement.appendChild(str); } if (onSuccess) { onSuccess(); } setTimeout(checkPopupPosition, 100); return true; } else { // call this function again in a little while... setTimeout(function(){ setPopupHTML(str,elementId,popupId,onSuccess); }, 600); } return null; } // function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);} // function fillEmptySpans(args) { return fillEmptySpans2(args); } // args.navpopup is mandatory // optional: args.redir, args.redirTarget // FIXME: ye gods, this is ugly stuff function fillEmptySpans2(args) { // if redir is present and true then redirTarget is mandatory var redir=true; if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; } var a=args.navpopup.parentAnchor; var article, hint=null, oldid=null, params={}; if (redir && typeof args.redirTarget == typeof {}) { article=args.redirTarget; //hint=article.hintValue(); } else { article=(new Title()).fromAnchor(a); hint=a.originalTitle || article.hintValue(); params=parseParams(a.href); oldid=(getValueOf('popupHistoricalLinks')) ? params.oldid : null; rcid=params.rcid; } var x={ article:article, hint: hint, oldid: oldid, rcid: rcid, navpop:args.navpopup, params:params }; var structure=pg.structures[getValueOf('popupStructure')]; if (typeof structure != 'object') { setPopupHTML('popupError', 'Unknown structure (this should never happen): '+ pg.option.popupStructure, args.navpopup.idNumber); return; } var spans=flatten(pg.misc.layout); var numspans = spans.length; var redirs=pg.misc.redirSpans; for (var i=0; i var f=findThis(redirs, spans[i]); //log('redir='+redir+', f='+f+', spans[i]='+spans[i]); if ( (f!==null && !redir) || (f===null && redir) ) { //log('skipping this set of the loop'); continue; } var structurefn=structure[spans[i]]; var setfn = setPopupHTML; if (getValueOf('popupActiveNavlinks') && (spans[i].indexOf('popupTopLinks')==0 || spans[i].indexOf('popupRedirTopLinks')==0) ) { setfn = setPopupTipsAndHTML; } switch (typeof structurefn) { case 'function': //log('running '+spans[i]+'({article:'+x.article+', hint:'+x.hint+', oldid: '+x.oldid+'})'); setfn(structurefn(x), spans[i], args.navpopup.idNumber); break; case 'string': setfn(structurefn, spans[i], args.navpopup.idNumber); break; default: errlog('unknown thing with label '+spans[i]); break; } } } // flatten an array function flatten(list, start) { var ret=[]; if (typeof start == 'undefined') { start=0; } for (var i=start; i if (typeof list[i] == typeof []) { return ret.concat(flatten(list[i])).concat(flatten(list, i+1)); } else { ret.push(list[i]); } } return ret; } // Generate html for whole popup function popupHTML (a) { getValueOf('popupStructure'); var structure=pg.structures[pg.option.popupStructure]; if (typeof structure != 'object') { //return 'Unknown structure: '+pg.option.popupStructure; // override user choice pg.option.popupStructure=pg.optionDefault.popupStructure; return popupHTML(a); } if (typeof structure.popupLayout != 'function') { return 'Bad layout'; } pg.misc.layout=structure.popupLayout(); if (typeof structure.popupRedirSpans == 'function') { pg.misc.redirSpans=structure.popupRedirSpans(); } else { pg.misc.redirSpans=[]; } return makeEmptySpans(pg.misc.layout, a.navpopup); } function makeEmptySpans (list, navpop) { var ret=''; for (var i=0; i if (typeof list[i] == typeof '') { ret += emptySpanHTML(list[i], navpop.idNumber, 'div'); } else if (typeof list[i] == typeof [] && list[i].length > 0 ) { ret = ret.parenSplit(RegExp('([^>]*?>$)')).join(makeEmptySpans(list[i], navpop)); } else if (typeof list[i] == typeof {} && list[i].nodeType ) { ret += emptySpanHTML(list[i].name, navpop.idNumber, list[i].nodeType); } } return ret; } function emptySpanHTML(name, id, tag, classname) { tag = tag || 'span'; if (!classname) { classname = emptySpanHTML.classAliases[name]; } classname = classname || name; if (name == getValueOf('popupDragHandle')) { classname += ' popupDragHandle'; } return simplePrintf('<%s id="%s" class="%s">%s>', [tag, name + id, classname, tag]); } emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' }; // generate html for popup image // where n=idNumber function imageHTML(article, idNumber) { return simplePrintf('' + ' '', [ idNumber ]); } function popTipsSoonFn(id, when, popData) { when || ( when=250 ); var popTips=function(){ setupTooltips(document.getElementById(id), false, true, popData); }; return function() { setTimeout( popTips, when, popData ); }; } function setPopupTipsAndHTML(html, divname, idnumber, popData) { setPopupHTML(html, divname, idnumber, getValueOf('popupSubpopups') ? popTipsSoonFn(divname + idnumber, null, popData) : null); } // ENDFILE: htmloutput.js // STARTFILE: mouseout.js ////////////////////////////////////////////////// // fuzzy checks function fuzzyCursorOffMenus(x,y, fuzz, parent) { if (!parent) { return null; } var uls=parent.getElementsByTagName('ul'); for (var i=0; i if (uls[i].className=='popup_menu') { if (uls[i].offsetWidth > 0) return false; } // else {document.title+='.';} } return true; } function checkPopupPosition () { // stop the popup running off the right of the screen // FIXME avoid pg.current.link pg.current.link && pg.current.link.navpopup && pg.current.link.navpopup.limitHorizontalPosition(); } function mouseOutWikiLink () { if (!window.popupsReady || !window.popupsReady()) { return; } //console ('mouseOutWikiLink'); var a=this; if (a.navpopup==null) return; if ( ! a.navpopup.isVisible() ) { a.navpopup.banish(); return; } restoreTitle(a); Navpopup.tracker.addHook(posCheckerHook(a.navpopup)); } function posCheckerHook(navpop) { return function() { if (!navpop.isVisible()) { return true; /* remove this hook */ } if (Navpopup.tracker.dirty) { return false; } var x=Navpopup.tracker.x, y=Navpopup.tracker.y; var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) || !fuzzyCursorOffMenus(x,y,navpop.fuzz, navpop.mainDiv); // FIXME it'd be prettier to do this internal to the Navpopup objects var t=getValueOf('popupHideDelay'); if (t) { t = t * 1000; } if (!t) { if(!mouseOverNavpop) { navpop.banish(); return true; /* remove this hook */ } return false; } // we have a hide delay set var d=+(new Date()); if ( !navpop.mouseLeavingTime ) { navpop.mouseLeavingTime = d; return false; } if ( mouseOverNavpop ) { navpop.mouseLeavingTime=null; return false; } if (d - navpop.mouseLeavingTime > t) { navpop.mouseLeavingTime=null; navpop.banish(); return true; /* remove this hook */ } return false; }; } function runStopPopupTimer(navpop) { // at this point, we should have left the link but remain within the popup // so we call this function again until we leave the popup. if (!navpop.stopPopupTimer) { navpop.stopPopupTimer=setInterval(posCheckerHook(navpop), 500); navpop.addHook(function(){clearInterval(navpop.stopPopupTimer);}, 'hide', 'before'); } } // ENDFILE: mouseout.js // STARTFILE: previewmaker.js /** @fileoverview Defines the {@link Previewmaker} object, which generates short previews from wiki markup. /** Creates a new Previewmaker @constructor @class The Previewmaker class. Use an instance of this to generate short previews from Wikitext. @param {String} wikiText The Wikitext source of the page we wish to preview. @param {String} baseUrl The url we should prepend when creating relative urls. @param {Navpopup} owner The navpop associated to this preview generator function Previewmaker(wikiText, baseUrl, owner) { /** The wikitext which is manipulated to generate the preview. */ this.originalData=wikiText; this.setData(); this.baseUrl=baseUrl; this.owner=owner; this.maxCharacters=getValueOf('popupMaxPreviewCharacters'); this.maxSentences=getValueOf('popupMaxPreviewSentences'); } Previewmaker.prototype.setData=function() { var maxSize=max(10000, 2*this.maxCharacters); this.data=this.originalData.substring(0,maxSize); }; /** Remove HTML comments @private Previewmaker.prototype.killComments = function () { // this also kills one trailing newline, eg diamyo this.data=this.data.replace(RegExp('\\n?', 'g'), ''); }; /** @private Previewmaker.prototype.killDivs = function () { // say goodbye, divs (can be nested, so use * not *?) this.data=this.data.replace(RegExp('< *div[^>]* *>[\\s\\S]*?< */ *div *>', 'gi'), ''); }; /** @private Previewmaker.prototype.killGalleries = function () { this.data=this.data.replace(RegExp('< *gallery[^>]* *>[\\s\\S]*?< */ *gallery *>', 'gi'), ''); }; /** @private Previewmaker.prototype.kill = function(opening, closing, subopening, subclosing, repl) { var oldk=this.data; var k=this.killStuff(this.data, opening, closing, subopening, subclosing, repl); while (k.length < oldk.length) { oldk=k; k=this.killStuff(k, opening, closing, subopening, subclosing, repl); } this.data=k; }; /** @private Previewmaker.prototype.killStuff = function (txt, opening, closing, subopening, subclosing, repl) { var op=this.makeRegexp(opening); var cl=this.makeRegexp(closing, '^'); var sb=subopening ? this.makeRegexp(subopening, '^') : null; var sc=subclosing ? this.makeRegexp(subclosing, '^') : cl; if (!op || !cl) { alert('Navigation Popups error: op or cl is null! something is wrong.'); return; } if (!op.test(txt)) { return txt; } var ret=''; var opResult = op.exec(txt); ret = txt.substring(0,opResult.index); txt=txt.substring(opResult.index+opResult[0].length); var depth = 1; while (txt.length > 0) { var removal=0; if (depth==1 && cl.test(txt)) { depth--; removal=cl.exec(txt)[0].length; } else if (depth > 1 && sc.test(txt)) { depth--; removal=sc.exec(txt)[0].length; }else if (sb && sb.test(txt)) { depth++; removal=sb.exec(txt)[0].length; } if ( !removal ) { removal = 1; } txt=txt.substring(removal); if (depth==0) { break; } } return ret + (repl || '') + txt; }; /** @private Previewmaker.prototype.makeRegexp = function (x, prefix, suffix) { prefix = prefix || ''; suffix = suffix || ''; var reStr=''; var flags=''; if (isString(x)) { reStr=prefix + literalizeRegex(x) + suffix; } else if (isRegExp(x)) { var s=x.toString().substring(1); var sp=s.split('/'); flags=sp[sp.length-1]; sp[sp.length-1]=''; s=sp.join('/'); s=s.substring(0,s.length-1); reStr= prefix + s + suffix; } else { log ('makeRegexp failed'); } log ('makeRegexp: got reStr=' + reStr + ', flags=' + flags); return RegExp(reStr, flags); }; /** @private Previewmaker.prototype.killBoxTemplates = function () { // taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general // also, have float_begin, ... float_end this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'), /[}][}]\s*/, '{{'); // infoboxes etc // from User:Zyxw/popups.js: kill frames too this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{'); }; /** @private Previewmaker.prototype.killTemplates = function () { this.kill('{{', '}}', '{', '}', ' '); }; /** @private Previewmaker.prototype.killTables = function () { // tables are bad, too // this can be slow, but it's an inprovement over a browser hang // torture test: Comparison_of_Intel_Central_Processing_Units this.kill('{|', /[|]}\s*/, '{|'); this.kill(/ // remove lines starting with a pipe for the hell of it (?) this.data=this.data.replace(RegExp('^[|].*$', 'mg'), ''); }; /** @private Previewmaker.prototype.killImages = function () { // images and categories are a nono this.kill(RegExp('[[][[]\\s*(Image|File|' + pg.ns.image + '|' + pg.ns.category + ')\\s*:', 'i'), /\]\]\s*/, '[', ']'); }; /** @private Previewmaker.prototype.killHTML = function () { // kill ... this.kill(/]*?>/i, /<\/ref>/i); // let's also delete entire lines starting with <. it's worth a try. this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n'); // and those pesky html tags, but not var splitted=this.data.parenSplit(/(<.*?>)/); var len=splitted.length; for (var i=1; i switch (splitted[i]) { case ' case '': break; default: if (! /^< *\/? *blockquote\b/i.test(splitted[i])) { splitted[i]=''; } } } this.data=splitted.join(''); }; /** @private Previewmaker.prototype.killChunks = function() { // heuristics alert // chunks of italic text? you crazy, man? var italicChunkRegex=new RegExp ("((^|\\n)\\s*:*\\s*[^']([^']|'|'[^']){20}(.|\\n[^\\n])*''[.!?\\s]*\\n)+", 'g'); // keep stuff separated, though, so stick in \n (fixes Union Jack? this.data=this.data.replace(italicChunkRegex, '\n'); }; /** @private Previewmaker.prototype.mopup = function () { // we simply *can't* be doing with horizontal rules right now this.data=this.data.replace(RegExp('^-{4,}','mg'),''); // no indented lines this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), ''); // replace __TOC__, __NOTOC__ and whatever else there is // this'll probably do this.data=this.data.replace(RegExp('^__[A-Z_]*__ *$', 'gmi'),''); }; /** @private Previewmaker.prototype.firstBit = function () { // dont't be givin' me no subsequent paragraphs, you hear me? /// first we "normalize" section headings, removing whitespace after, adding before var d=this.data; if (getValueOf('popupPreviewCutHeadings')) { this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 '); /// then we want to get rid of paragraph breaks whose text ends badly this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n'); this.data=this.data.replace(RegExp('^[\\s\\n]*'), ''); stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data); if (stuff) { d = stuff[0]; } if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; } /// now put \n\n after sections so that bullets and numbered lists work d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n'); } // superfluous sentences are RIGHT OUT. // note: exactly 1 set of parens here needed to make the slice work d = d.parenSplit(RegExp('([!?.]+["'+"'"+']*\\s)','g')); // leading space is bad, mmkay? d[0]=d[0].replace(RegExp('^\\s*'), ''); var notSentenceEnds=RegExp('([^.][a-z][.] *[a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|op|cit|\\^\\*|\\s[A-Zvclm])$', 'i'); d = this.fixSentenceEnds(d, notSentenceEnds); this.fullLength=d.join('').length; var maxChars=getValueOf('popupMaxPreviewCharacters') + this.extraCharacters; var n=this.maxSentences; var dd=this.firstSentences(d,n); do { dd=this.firstSentences(d,n); --n; } while ( dd.length > this.maxCharacters && n != 0 ); this.data = dd; }; /** @private Previewmaker.prototype.fixSentenceEnds = function(strs, reg) { // take an array of strings, strs // join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg var abbrevRe=/\b[a-z][^a-z]*$/i; for (var i=0; i if (reg.test(strs[i])) { a=[]; for (var j=0; j if (j
if (j==i) a[i]=strs[i]+strs[i+1]+strs[i+2]; if (j>i+2) a[j-2]=strs[j]; } return this.fixSentenceEnds(a,reg); } // BUGGY STUFF - trying to fix up S. C. Johnson & Son preview if (false && abbrevRe.test(strs[i])) { var j=i, buf=''; do { buf=buf+strs[i]+strs[i+1]; i=i+2; } while (i strs[i]=buf+strs[i]; var a=(j?strs.slice(0,j-1):[]).concat(strs.slice(i)); return this.fixSentenceEnds(a,reg); } } return strs; }; /** @private Previewmaker.prototype.firstSentences = function(strs, howmany) { var t=strs.slice(0, 2*howmany); return t.join(''); }; /** @private Previewmaker.prototype.killBadWhitespace = function() { // also cleans up isolated , eg Suntory Sungoliath this.data=this.data.replace(RegExp('^ *\'+ *$', 'gm'), ''); }; /** Runs the various methods to generate the preview. The preview is stored in the Title
deals with article titles and their variousTitle
, which exists simply to make things a little
Title
.
' + popupString('Click to disambiguate this link to:') + '
';
html