MediaWiki:Gadget-popups.js: различия между версиями

>Edward Chernenko
м тест новой версии из enwiki
>Edward Chernenko
м rv к прежней версии. Она работала, в новой ещё копаться и копаться
Строка 1: Строка 1:
var popupVersion="MediaWiki:Gadget-popups.js 2009-08-30 23:33:10 (UTC)"
importScript('Участник:Edward_Chernenko/strings-ru.js');
 
var popupVersion="Sat Mar 10 21:40:16 UTC 2007";
// STARTFILE: main.js
// STARTFILE: main.js
// **********************************************************************
// **********************************************************************
Строка 15: Строка 17:
// **                                                                  **
// **                                                                  **
// **********************************************************************
// **********************************************************************
 
////////////////////////////////////////////////////////////////////
// Import stylesheet(s)
//
 
 
if ( window.localCSS ) {
document.write('<link rel="stylesheet" type="text/css" href="http://localhost:8080/js/navpop.css">');
} else {
document.write('<link rel="stylesheet" type="text/css" href="' +
      'http://en.wikipedia.org/w/index.php?title=User:Lupin/navpop.css' +
      '&action=raw&ctype=text/css&dontcountme=s">');
}
 
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// Globals
// Globals
//
//
 
// Trying to shove as many of these as possible into the pg (popup globals) object
// Trying to shove as many of these as possible into the pg (popup globals) object
function pg(){}; // dummy to stop errors
function pg(){}; // dummy to stop errors
Строка 49: Строка 64:
return true;
return true;
}
}
////////////////////////////////////////////////////////////////////
// Run things
////////////////////////////////////////////////////////////////////
 
hookEvent('load', setupPopups);
 
/// Local Variables: ///
/// Local Variables: ///
/// mode:c ///
/// mode:c ///
Строка 60: Строка 80:
//<NOLITE>
//<NOLITE>
// the main initial call
// the main initial call
if (getValueOf('popupOnEditSelection') && window.doSelectionPopup && document && document.editform && document.editform.wpTextbox1) {
if (getValueOf('popupOnEditSelection') && window.doSelectionPopup ) {
document.editform.wpTextbox1.onmouseup=doSelectionPopup;
try {
document.editform.wpTextbox1.onmouseup=function() { doSelectionPopup(); };
} catch (neverMind) {}
}
}
//</NOLITE>
//</NOLITE>
Строка 67: Строка 89:
container = defaultPopupsContainer();
container = defaultPopupsContainer();
}
}
 
if (!remove && !force && container.ranSetupTooltipsAlready) { return; }
if (!remove && !force && container.ranSetupTooltipsAlready) { return; }
container.ranSetupTooltipsAlready = !remove;
container.ranSetupTooltipsAlready = !remove;
 
var anchors;
var anchors;
anchors=container.getElementsByTagName('A');
anchors=container.getElementsByTagName('A');
setupTooltipsLoop(anchors, 0, 250, 100, remove, popData);
setupTooltipsLoop(anchors, 0, 250, 100, remove, popData);
}
}
 
function defaultPopupsContainer() {
function defaultPopupsContainer() {
     if (getValueOf('popupOnlyArticleLinks')) {
     if (getValueOf('popupOnlyArticleLinks')) {
    return document.getElementById('article') ||
    return document.getElementById('article') ||
    document.getElementById('content') ||
    document.getElementById('content') || document;
    document.getElementById('mw_content') || document;
     }
     }
     return  document;
     return  document;
}
}
 
function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) {
function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) {
log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments));
log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments));
Строка 113: Строка 134:
}
}
}
}
 
// eliminate popups from the TOC
// eliminate popups from the TOC
// This also kills any onclick stuff that used to be going on in the toc
// This also kills any onclick stuff that used to be going on in the toc
Строка 126: Строка 147:
}
}
}
}
 
function addTooltip(a, popData) {
function addTooltip(a, popData) {
if ( !isPopupLink(a) ) { return; }
if ( !isPopupLink(a) ) { return; }
Строка 135: Строка 156:
a.popData = popData;
a.popData = popData;
}
}
 
function removeTooltip(a) {
function removeTooltip(a) {
if ( !a.hasPopup ) { return; }
if ( !a.hasPopup ) { return; }
Строка 143: Строка 164:
a.hasPopup=false;
a.hasPopup=false;
}
}
 
function removeTitle(a) {
function removeTitle(a) {
if (a.originalTitle) { return; }
if (a.originalTitle) { return; }
Строка 149: Строка 170:
a.title='';
a.title='';
}
}
 
function restoreTitle(a) {
function restoreTitle(a) {
if ( a.title || !a.originalTitle ) { return; }
if ( a.title || !a.originalTitle ) { return; }
Строка 155: Строка 176:
a.originalTitle='';
a.originalTitle='';
}
}
 
function registerHooks(np) {
function registerHooks(np) {
var popupMaxWidth=getValueOf('popupMaxWidth');
var popupMaxWidth=getValueOf('popupMaxWidth');
 
if (typeof popupMaxWidth == 'number') {
if (typeof popupMaxWidth == 'number') {
var setMaxWidth = function () {
var setMaxWidth = function () {
np.mainDiv.style.maxWidth = popupMaxWidth + 'px';
np.mainDiv.style.maxWidth = popupMaxWidth + 'px';
np.maxWidth = popupMaxWidth;
np.maxWidth = popupMaxWidth;
 
            try {
// hack for IE
// hack for IE
// see http://www.svendtofte.com/code/max_width_in_ie/
// see http://www.svendtofte.com/code/max_width_in_ie/
// use setExpression as documented here on msdn: http://tinyurl dot com/dqljn
// use setExpression as documented here on msdn: http://tinyurl dot com/dqljn
 
if (np.mainDiv.style.setExpression) {
if (np.mainDiv.style.setExpression) {
np.mainDiv.style.setExpression(
np.mainDiv.style.setExpression(
'width', 'document.body.clientWidth > ' +
'width', 'document.body.clientWidth > ' +
popupMaxWidth + ' ? "' +popupMaxWidth + 'px": "auto"');
popupMaxWidth + ' ? "' +popupMaxWidth + 'px": "auto"');
}
}
            }
            catch (errors) {
            errlog( "Running on IE8 are we not?: " + errors );
            }
};
};
np.addHook(setMaxWidth, 'unhide', 'before');
np.addHook(setMaxWidth, 'unhide', 'before');
Строка 188: Строка 204:
//</NOLITE>
//</NOLITE>
}
}
 
 
function mouseOverWikiLink(evt) {
function mouseOverWikiLink(evt) {
if (!window.popupsReady || !window.popupsReady()) { return; }
if (!window.popupsReady || !window.popupsReady()) { return; }
Строка 195: Строка 211:
return mouseOverWikiLink2(this, evt);
return mouseOverWikiLink2(this, evt);
}
}
 
function footnoteTarget(a) {
function footnoteTarget(a) {
var aTitle=Title.fromAnchor(a);
var aTitle=Title.fromAnchor(a);
// We want ".3A" rather than "%3A" or "?" here, so use the anchor property directly
// We want ".3A" rather than "%3A" or "?" here, so use the anchor property directly
var anch = aTitle.anchor;
var anch = aTitle.anchor;
if ( ! /^(cite_note-|_note-|endnote)/.test(anch) ) { return false; }
if ( ! /^(_note-|endnote)/.test(anch) ) { return false; }
 
var lTitle=Title.fromURL(location.href);
var lTitle=Title.fromURL(location.href);
if ( lTitle.toString(true) != aTitle.toString(true) ) { return false; }
if ( lTitle.toString(true) != aTitle.toString(true) ) { return false; }
 
var el=document.getElementById(anch);
var el=document.getElementById(anch);
while ( el && typeof el.nodeName == 'string') {
while ( el && typeof el.nodeName == 'string') {
Строка 215: Строка 231:
return false;
return false;
}
}
 
function footnotePreview(x, navpop) {
function footnotePreview(x, navpop) {
setPopupHTML('<hr>' + x.innerHTML, 'popupPreview',  navpop.idNumber,
setPopupHTML('<hr>' + x.innerHTML, 'popupPreview',  navpop.idNumber,
Строка 222: Строка 238:
} : null);
} : null);
}
}
 
// var modid=0;
// var modid=0;
// if(!window.opera) { window.opera={postError: console.log}; }
// if(!window.opera) { window.opera={postError: console.log}; }
 
function modifierKeyHandler(a) {
function modifierKeyHandler(a) {
return function(evt) {
return function(evt) {
// opera.postError('modifierKeyHandler called' + (++modid));
// opera.postError('modifierKeyHandler called' + (++modid));
// opera.postError(''+evt + modid);
// opera.postError(''+evt + modid);
// for (var i in evt) {
// for (var i in evt) {
// opera.postError('' + modid + ' ' + i + ' ' + evt[i]);
// opera.postError('' + modid + ' ' + i + ' ' + evt[i]);
// }
// }
// opera.postError(''+evt.ctrlKey + modid);
// opera.postError(''+evt.ctrlKey + modid);
var mod=getValueOf('popupModifier');
var mod=getValueOf('popupModifier');
if (!mod) { return true; }
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};
if (!evt && window.event) {evt=window.event};
// opera.postError('And now....'+modid);
// opera.postError('And now....'+modid);
// opera.postError(''+evt+modid);
// opera.postError(''+evt+modid);
// opera.postError(''+evt.ctrlKey+modid);
// opera.postError(''+evt.ctrlKey+modid);
if ( evt && mod && !evt[mod.toLowerCase() + 'Key'] ) { return true; }
return ( evt && mod && evt[mod.toLowerCase() + 'Key'] );
 
mouseOverWikiLink2(a, evt);
};
}
}
 
function dealWithModifier(a,evt) {
function mouseOverWikiLink2(a, evt) {
if (!getValueOf('popupModifier')) { return false; }
// try not to duplicate effort
var action = getValueOf('popupModifierAction');
var mod=getValueOf('popupModifier');
if ( action == 'enable' && !modifierPressed(evt) ||
if ( evt && mod && !evt[mod.toLowerCase() + 'Key'] ) {
    action == 'disable' && modifierPressed(evt) ) {
// if the modifier is needed and not pressed, listen for it until
// if the modifier is needed and not pressed, listen for it until
// we mouseout of this link.
// we mouseout of this link.
Строка 285: Строка 281:
return;
return;
}
}
 
a.modifierKeyHandler=modifierKeyHandler(a);
a.modifierKeyHandler=modifierKeyHandler(a);
document[addHandler](on+'keydown', a.modifierKeyHandler, false);
switch (action) {
a[addHandler](on+'mouseout', function() {
case 'enable':
document[rmHandler](on+'keydown',
document[addHandler](on+'keydown', a.modifierKeyHandler, false);
    a.modifierKeyHandler, false);
a[addHandler](on+'mouseout', function() {
}, true);
document[rmHandler](on+'keydown',
return;
    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 ( getValueOf('removeTitles') ) { removeTitle(a); }
if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; }
if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; }
pg.current.link=a;
pg.current.link=a;
 
if (getValueOf('simplePopups') && pg.option.popupStructure===null) {
if (getValueOf('simplePopups') && pg.option.popupStructure===null) {
// reset *default value* of popupStructure
// reset *default value* of popupStructure
setDefault('popupStructure', 'original');
setDefault('popupStructure', 'original');
}
}
 
var article=(new Title()).fromAnchor(a);
var article=(new Title()).fromAnchor(a);
// set global variable (ugh) to hold article (wikipage)
// set global variable (ugh) to hold article (wikipage)
Строка 324: Строка 307:
pg.counter.checkImages=0;
pg.counter.checkImages=0;
}
}
 
if (!a.navpopup) {
if (!a.navpopup) {
// FIXME: this doesn't behave well if you mouse out of a popup
// FIXME: this doesn't behave well if you mouse out of a popup
Строка 342: Строка 325:
}
}
a.navpopup.showSoonIfStable(a.navpopup.delay);
a.navpopup.showSoonIfStable(a.navpopup.delay);
 
getValueOf('popupInitialWidth');
getValueOf('popupInitialWidth');
 
clearInterval(pg.timer.checkPopupPosition);
clearInterval(pg.timer.checkPopupPosition);
pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600);
pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600);
 
if(getValueOf('simplePopups')) {
if(getValueOf('simplePopups')) { return; }
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 ) {
if (a.navpopup.pending!==0 ) {
    nonsimplePopupContent(a, article);
    nonsimplePopupContent(a, article);
}
}
}
}
 
// simplePopupContent: the content that is shown even when simplePopups is true
// simplePopupContent: the content that is shown even when simplePopups is true
function simplePopupContent(a, article) {
function simplePopupContent(a, article) {
Строка 375: Строка 343:
a.navpopup.setInnerHTML(popupHTML(a));
a.navpopup.setInnerHTML(popupHTML(a));
fillEmptySpans({navpopup:a.navpopup});
fillEmptySpans({navpopup:a.navpopup});
 
if (getValueOf('popupDraggable'))
var dragHandle = getValueOf('popupDragHandle') || null;
{
if (dragHandle && dragHandle != 'all') {
var dragHandle = getValueOf('popupDragHandle') || null;
dragHandle += a.navpopup.idNumber;
if (dragHandle && dragHandle != 'all') {
dragHandle += a.navpopup.idNumber;
}
setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150);
}
}
setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150);
//<NOLITE>
//<NOLITE>
if (getValueOf('popupRedlinkRemoval') && a.className=='new') {
if (getValueOf('popupRedlinkRemoval') && a.className=='new') {
Строка 391: Строка 355:
//</NOLITE>
//</NOLITE>
}
}
 
function debugData(navpopup) {
function debugData(navpopup) {
if(getValueOf('popupDebugging') && navpopup.idNumber) {
if(getValueOf('popupDebugging') && navpopup.idNumber) {
Строка 398: Строка 362:
}
}
}
}
 
function newNavpopup(a, article) {
function newNavpopup(a, article) {
var navpopup = new Navpopup();
var navpopup = new Navpopup();
Строка 411: Строка 375:
return navpopup;
return navpopup;
}
}
 
 
function nonsimplePopupContent(a, article) {
function nonsimplePopupContent(a, article) {
var diff=null, history=null;
var diff=null, history=null;
Строка 421: Строка 385:
diff=params.diff;
diff=params.diff;
}
}
if(getValueOf('popupPreviewHistory')) {
if(getValueOf('popupPreviewHistory') && getValueOf('popupUseQueryInterface')) {
history=(params.action=='history');
history=(params.action=='history');
}
}
//</NOLITE>
//</NOLITE>
a.navpopup.pending=0;
a.navpopup.pending=0;
var previewImage=true;
var x;
var x;
pg.misc.gImage=null;
pg.misc.gImage=null;
Строка 432: Строка 397:
//<NOLITE>
//<NOLITE>
} else if ( diff || diff === 0 ) {
} else if ( diff || diff === 0 ) {
//alert([article,oldid,diff]);
loadDiff(article, oldid, diff, a.navpopup);
loadDiff(article, oldid, diff, a.navpopup);
} else if ( history ) {
} else if ( history && getValueOf('popupUseQueryInterface') ) {
loadAPIPreview('history', article, a.navpopup);
loadQueryPreview('history', article, a.navpopup);
} else if ( pg.re.contribs.test(a.href) ) {
} else if ( pg.re.contribs.test(a.href) && getValueOf('popupUseQueryInterface')) {
loadAPIPreview('contribs', article, a.navpopup);
loadQueryPreview('contribs', article, a.navpopup);
} else if ( pg.re.backlinks.test(a.href) ) {
} else if ( pg.re.backlinks.test(a.href) && getValueOf('popupUseQueryInterface')) {
loadAPIPreview('backlinks', article, a.navpopup);
loadQueryPreview('backlinks', article, a.navpopup);
    } else if ( // FIXME should be able to get all preview combinations with options
} else if ( // FIXME should be able to get all preview combinations with options
article.namespace()==pg.ns.image &&
article.namespace()==pg.ns.image &&
( getValueOf('imagePopupsForImages') || ! anchorContainsImage(a) )
( getValueOf('imagePopupsForImages') || ! anchorContainsImage(a) )
) {
) {
loadAPIPreview('imagepagepreview', article, a.navpopup);
if (getValueOf('popupUseQueryInterface')) {
loadQueryPreview('imagepagepreview', article, a.navpopup);
} else { startArticlePreview(article, oldid, a.navpopup); }
loadImages(article);
loadImages(article);
//</NOLITE>
//</NOLITE>
} else {
} else if (article.namespace() == pg.ns.category &&
if (article.namespace() == pg.ns.category &&
  getValueOf('popupCategoryMembers')) {
getValueOf('popupCategoryMembers')) {
getValueOf('popupUseQueryInterface') &&
loadAPIPreview('category', article, a.navpopup);
loadQueryPreview('category', article, a.navpopup);
} else if ((article.namespace() == pg.ns.user || article.namespace() == pg.ns.usertalk) &&
startArticlePreview(article, oldid, a.navpopup);
getValueOf('popupUserInfo')) {
}
loadAPIPreview('userinfo', article, a.navpopup);
else if (!article.namespace()!=pg.ns.image && previewImage ) {
}
startArticlePreview(article, oldid, a.navpopup);
startArticlePreview(article, oldid, a.navpopup);
}
}
}
}
 
function pendingNavpopTask(navpop) {
function pendingNavpopTask(navpop) {
if (navpop && navpop.pending===null) { navpop.pending=0; }
if (navpop && navpop.pending===null) { navpop.pending=0; }
Строка 463: Строка 430:
debugData(navpop);
debugData(navpop);
}
}
 
function completedNavpopTask(navpop) {
function completedNavpopTask(navpop) {
if (navpop && navpop.pending) { --navpop.pending; }
if (navpop && navpop.pending) { --navpop.pending; }
debugData(navpop);
debugData(navpop);
}
}
 
function startArticlePreview(article, oldid, navpop) {
function startArticlePreview(article, oldid, navpop) {
navpop.redir=0;
navpop.redir=0;
loadPreview(article, oldid, navpop);
loadPreview(article, oldid, navpop);
}
}
 
function loadPreview(article, oldid, navpop) {
function loadPreview(article, oldid, navpop) {
pendingNavpopTask(navpop);
pendingNavpopTask(navpop);
Строка 486: Строка 453:
}
}
}
}
 
function loadPreviewFromRedir(redirMatch, navpop) {
function loadPreviewFromRedir(redirMatch, navpop) {
// redirMatch is a regex match
// redirMatch is a regex match
Строка 506: Строка 473:
return loadPreview(target, null,  navpop);
return loadPreview(target, null,  navpop);
}
}
 
function insertPreview(download) {
function insertPreview(download) {
if (!download.owner) { return; }
if (!download.owner) { return; }
 
var redirMatch = pg.re.redirect.exec(download.data);
var redirMatch = pg.re.redirect.exec(download.data);
if (download.owner.redir===0 && redirMatch) {
if (download.owner.redir===0 && redirMatch) {
Строка 516: Строка 483:
return;
return;
}
}
 
if (download.owner.visible || !getValueOf('popupLazyPreviews')) {
if (download.owner.visible || !getValueOf('popupLazyPreviews')) {
    insertPreviewNow(download);
    insertPreviewNow(download);
Строка 525: Строка 492:
}
}
}
}
 
function insertPreviewNow(download) {
function insertPreviewNow(download) {
if (!download.owner) { return; }
if (!download.owner) { return; }
Строка 532: Строка 499:
completedNavpopTask(navpop);
completedNavpopTask(navpop);
var art=navpop.redirTarget || navpop.originalArticle;
var art=navpop.redirTarget || navpop.originalArticle;
 
//<NOLITE>
//<NOLITE>
makeFixDabs(wikiText, navpop);
makeFixDabs(wikiText, navpop);
Строка 539: Строка 506:
setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber);
setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber);
}
}
 
var imagePage='';
var imagePage='';
if (art.namespace()==pg.ns.image) { imagePage=art.toString(); }
if (art.namespace()==pg.ns.image) { imagePage=art.toString(); }
Строка 545: Строка 512:
if(imagePage) { loadImages(Title.fromWikiText(imagePage)); }
if(imagePage) { loadImages(Title.fromWikiText(imagePage)); }
//</NOLITE>
//</NOLITE>
 
if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); }
if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); }
 
}
}
 
function insertArticlePreview(download, art, navpop) {
function insertArticlePreview(download, art, navpop) {
if (download && typeof download.data == typeof ''){
if (download && typeof download.data == typeof ''){
Строка 563: Строка 530:
}
}
}
}
 
function prepPreviewmaker(data, article, navpop) {
function prepPreviewmaker(data, article, navpop) {
// deal with tricksy anchors
// deal with tricksy anchors
Строка 571: Строка 538:
return p;
return p;
}
}
 
 
// Try to imitate the way mediawiki generates HTML anchors from section titles
// Try to imitate the way mediawiki generates HTML anchors from section titles
function anchorize(d, anch) {
function anchorize(d, anch) {
Строка 579: Строка 546:
var match=d.match(anchRe);
var match=d.match(anchRe);
if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); }
if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); }
 
// now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom
// now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom
var lines=d.split('\n');
var lines=d.split('\n');
Строка 591: Строка 558:
return d;
return d;
}
}
 
function killPopup() {
function killPopup() {
if (getValueOf('popupShortcutKeys') && window.rmPopupShortcuts) { rmPopupShortcuts(); }
if (getValueOf('popupShortcutKeys') && window.rmPopupShortcuts) { rmPopupShortcuts(); }
Строка 612: Строка 579:
   @fileoverview
   @fileoverview
   The {@link Drag} object, which enables objects to be dragged around.
   The {@link Drag} object, which enables objects to be dragged around.
 
   <pre>
   <pre>
   *************************************************
   *************************************************
Строка 623: Строка 590:
   *************************************************
   *************************************************
   Pared down, some hooks added by [[User:Lupin]]
   Pared down, some hooks added by [[User:Lupin]]
 
   Copyright Aaron Boodman.
   Copyright Aaron Boodman.
   Saying stupid things daily since March 2001.
   Saying stupid things daily since March 2001.
   </pre>
   </pre>
*/
*/
 
/**
/**
   Creates a new Drag object. This is used to make various DOM elements draggable.
   Creates a new Drag object. This is used to make various DOM elements draggable.
Строка 647: Строка 614:
this.endHook = null;
this.endHook = null;
}
}
 
/**
/**
   Gets an event in a cross-browser manner.
   Gets an event in a cross-browser manner.
Строка 669: Строка 636:
o.onmousedown    = function(e) { dragObj.start.apply( dragObj, [e]); };
o.onmousedown    = function(e) { dragObj.start.apply( dragObj, [e]); };
o.dragging      = false;
o.dragging      = false;
o.popups_draggable     = true;
o.draggable     = true;
o.hmode          = true;
o.hmode          = true;
o.vmode          = true;
o.vmode          = true;
 
o.root = oRoot && oRoot !== null ? oRoot : o ;
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.left, 10))) { o.root.style.left  = "0px"; }
if (isNaN(parseInt(o.root.style.top,  10))) { o.root.style.top    = "0px"; }
if (isNaN(parseInt(o.root.style.top,  10))) { o.root.style.top    = "0px"; }
 
o.root.onthisStart  = function(){};
o.root.onthisStart  = function(){};
o.root.onthisEnd    = function(){};
o.root.onthisEnd    = function(){};
o.root.onthis      = function(){};
o.root.onthis      = function(){};
};
};
 
/**
/**
   Starts the drag.
   Starts the drag.
Строка 695: Строка 662:
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10);
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10);
o.root.onthisStart(x, y);
o.root.onthisStart(x, y);
 
o.lastMouseX    = e.clientX;
o.lastMouseX    = e.clientX;
o.lastMouseY    = e.clientY;
o.lastMouseY    = e.clientY;
 
var dragObj      = this;
var dragObj      = this;
o.onmousemoveDefault    = document.onmousemove;
o.onmousemoveDefault    = document.onmousemove;
Строка 714: Строка 681:
e = this.fixE(e);
e = this.fixE(e);
var o = this.obj;
var o = this.obj;
 
var ey    = e.clientY;
var ey    = e.clientY;
var ex    = e.clientX;
var ex    = e.clientX;
Строка 720: Строка 687:
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10 );
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10 );
var nx, ny;
var nx, ny;
 
nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
ny = y + ((ey - o.lastMouseY) * (o.vmode ? 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.hmode ? "left" : "right"] = nx + "px";
this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
this.obj.lastMouseX    = ex;
this.obj.lastMouseX    = ex;
this.obj.lastMouseY    = ey;
this.obj.lastMouseY    = ey;
 
this.obj.root.onthis(nx, ny);
this.obj.root.onthis(nx, ny);
return false;
return false;
};
};
 
/**
/**
   Ends the drag.
   Ends the drag.
Строка 780: Строка 747:
pg.structures.original.popupRedirTitle=pg.structures.original.popupTitle;
pg.structures.original.popupRedirTitle=pg.structures.original.popupTitle;
pg.structures.original.popupRedirTopLinks=pg.structures.original.popupTopLinks;
pg.structures.original.popupRedirTopLinks=pg.structures.original.popupTopLinks;
 
 
function copyStructure(oldStructure, newStructure) {
function copyStructure(oldStructure, newStructure) {
pg.structures[newStructure]={};
pg.structures[newStructure]={};
Строка 788: Строка 755:
}
}
}
}
 
copyStructure('original', 'nostalgia');
copyStructure('original', 'nostalgia');
pg.structures.nostalgia.popupTopLinks=function(x)  {
pg.structures.nostalgia.popupTopLinks=function(x)  {
var str='';
var str='';
str += '<b><<mainlink|shortcut= >></b>';
str += '<b><<mainlink|shortcut= >></b>';
 
// user links
// user links
// contribs - log - count - email - block
// contribs - log - count - email - block
Строка 800: Строка 767:
str+='if(wikimedia){*<<count|shortcut=#>>}';
str+='if(wikimedia){*<<count|shortcut=#>>}';
str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>}}';
str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>}}';
 
// editing links
// editing links
// talkpage  -> edit|new - history - un|watch - article|edit
// talkpage  -> edit|new - history - un|watch - article|edit
Строка 809: Строка 776:
var historystr='<<history|shortcut=h>>';
var historystr='<<history|shortcut=h>>';
var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
 
str+='<br>if(talk){' +
str+='<br>if(talk){' +
editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' +
editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' +
Строка 817: Строка 784:
'<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
'<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
+ '}';
+ '}';
 
// misc links
// misc links
str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>';
str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>';
str += 'if(admin){<br>}else{*}<<move|shortcut=m>>';
str += 'if(admin){<br>}else{*}<<move|shortcut=m>>';
 
// admin links
// admin links
str += 'if(admin){*<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*' +
str += 'if(admin){*<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*' +
Строка 828: Строка 795:
};
};
pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks;
pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks;
 
/** -- fancy -- **/
/** -- fancy -- **/
copyStructure('original', 'fancy');
copyStructure('original', 'fancy');
Строка 850: Строка 817:
user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+
user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+
popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}';
popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}';
 
var normal='<<whatLinksHere|shortcut=l|links here>>*<<relatedChanges|shortcut=r|related>>';
var normal='<<whatLinksHere|shortcut=l|links here>>*<<relatedChanges|shortcut=r|related>>';
return navlinkStringToHTML('<br>if(user){' + user + '*}if(admin){'+admin+'if(user){<br>}else{*}}' + normal,
return navlinkStringToHTML('<br>if(user){' + user + '*}if(admin){'+admin+'if(user){<br>}else{*}}' + normal,
Строка 858: Строка 825:
pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks;
pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks;
pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks;
pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks;
 
 
/** -- fancy2 -- **/
/** -- fancy2 -- **/
// hack for [[User:MacGyverMagic]]
// hack for [[User:MacGyverMagic]]
Строка 872: Строка 839:
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
};
};
 
/** -- menus -- **/
/** -- menus -- **/
copyStructure('original', 'menus');
copyStructure('original', 'menus');
Строка 919: Строка 886:
var newTopic='if(talk){<<new|shortcut=+|new topic>>}';
var newTopic='if(talk){<<new|shortcut=+|new topic>>}';
var protectDelete='if(admin){' + protect + del + '}';
var protectDelete='if(admin){' + protect + del + '}';
 
if (getValueOf('popupActionsMenu')) {
if (getValueOf('popupActionsMenu')) {
s.push( '<<mainlink>>*' + dropdiv + menuTitle('actions'));
s.push( '<<mainlink>>*' + dropdiv + menuTitle('actions'));
Строка 936: Строка 903:
      'else{<<talk|shortcut=t|talk page>><<editTalk|edit talk>>' +
      'else{<<talk|shortcut=t|talk page>><<editTalk|edit talk>>' +
      '<<newTalk|shortcut=+|new topic>>}</menu>' + enddiv);
      '<<newTalk|shortcut=+|new topic>>}</menu>' + enddiv);
 
// user menu starts here
// user menu starts here
var email='<<email|shortcut=E|email user>>';
var email='<<email|shortcut=E|email user>>';
var contribs= 'if(wikimedia){<menurow>}<<contribs|shortcut=c|contributions>>if(wikimedia){</menurow>}' +
var contribs= 'if(wikimedia){<menurow>}<<contribs|shortcut=c|contributions>>' +
'if(admin){<menurow><<deletedContribs>></menurow>}';
'if(wikimedia){|<<contribsTree|tree>></menurow>}';
 
s.push('if(user){*' + dropdiv + menuTitle('user'));
s.push('if(user){*' + dropdiv + menuTitle('user'));
s.push('<menu>'); +
s.push('<menu>'); +
Строка 955: Строка 921:
s.push('<<blocklog|shortcut=B|block log>>' + getValueOf('popupExtraUserMenu'));
s.push('<<blocklog|shortcut=B|block log>>' + getValueOf('popupExtraUserMenu'));
s.push('</menu>'  + enddiv + '}');
s.push('</menu>'  + enddiv + '}');
 
// popups menu starts here
// popups menu starts here
if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) {
if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) {
Строка 967: Строка 933:
return navlinkStringToHTML(s.join(''), x.article, x.params);
return navlinkStringToHTML(s.join(''), x.article, x.params);
};
};
 
function menuTitle(s) {
function menuTitle(s) {
return '<a href="#" noPopup=1>' + popupString(s) + '</a>';
return '<a href="#" noPopup=1>' + popupString(s) + '</a>';
}
}
 
pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle;
pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle;
pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks;
pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks;
 
copyStructure('menus', 'shortmenus');
copyStructure('menus', 'shortmenus');
pg.structures.shortmenus.popupTopLinks=function(x) {
pg.structures.shortmenus.popupTopLinks=function(x) {
Строка 980: Строка 946:
};
};
pg.structures.shortmenus.popupRedirTopLinks=pg.structures.shortmenus.popupTopLinks;
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;
//</NOLITE>
//</NOLITE>
pg.structures.lite={};
pg.structures.lite={};
Строка 1012: Строка 966:
if (m) {
if (m) {
try {
try {
return decodeURIComponent(m[1]);
return decodeURI(m[1]);
} catch (someError) {}
} catch (someError) {}
}
}
return null;
return null;
}
}
 
function substitute(data,cmdBody) {
function substitute(data,cmdBody) {
// alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags);
// alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags);
Строка 1023: Строка 977:
return data.replace(fromRe, cmdBody.to);
return data.replace(fromRe, cmdBody.to);
}
}
 
function execCmds(data, cmdList) {
function execCmds(data, cmdList) {
for (var i=0; i<cmdList.length; ++i) {
for (var i=0; i<cmdList.length; ++i) {
Строка 1030: Строка 984:
return data;
return data;
}
}
 
function parseCmd(str) {
function parseCmd(str) {
// returns a list of commands
// returns a list of commands
Строка 1045: Строка 999:
return false;
return false;
}
}
 
function unEscape(str, sep) {
function unEscape(str, sep) {
return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n');
return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n');
}
}
 
 
function parseSubstitute(str) {
function parseSubstitute(str) {
// takes a string like s/a/b/flags;othercmds and parses it
// takes a string like s/a/b/flags;othercmds and parses it
 
var from,to,flags,tmp;
var from,to,flags,tmp;
 
if (str.length<4) { return false; }
if (str.length<4) { return false; }
var sep=str.charAt(1);
var sep=str.charAt(1);
str=str.substring(2);
str=str.substring(2);
 
tmp=skipOver(str,sep);
tmp=skipOver(str,sep);
if (tmp) { from=tmp.segment; str=tmp.remainder; }
if (tmp) { from=tmp.segment; str=tmp.remainder; }
else { return false; }
else { return false; }
 
tmp=skipOver(str,sep);
tmp=skipOver(str,sep);
if (tmp) { to=tmp.segment; str=tmp.remainder; }
if (tmp) { to=tmp.segment; str=tmp.remainder; }
else { return false; }
else { return false; }
 
flags='';
flags='';
if (str.length) {
if (str.length) {
Строка 1073: Строка 1027:
if (tmp) {flags=tmp.segment; str=tmp.remainder; }
if (tmp) {flags=tmp.segment; str=tmp.remainder; }
}
}
 
return {action: substitute, from: from, to: to, flags: flags, remainder: str};
return {action: substitute, from: from, to: to, flags: flags, remainder: str};
 
}
}
 
function skipOver(str,sep) {
function skipOver(str,sep) {
var endSegment=findNext(str,sep);
var endSegment=findNext(str,sep);
Строка 1084: Строка 1038:
return {segment: segment, remainder: str.substring(endSegment+1)};
return {segment: segment, remainder: str.substring(endSegment+1)};
}
}
 
function skipToEnd(str,sep) {
function skipToEnd(str,sep) {
return {segment: str, remainder: ''};
return {segment: str, remainder: ''};
}
}
 
function findNext(str, ch) {
function findNext(str, ch) {
for (var i=0; i<str.length; ++i) {
for (var i=0; i<str.length; ++i) {
Строка 1096: Строка 1050:
return -1;
return -1;
}
}
 
function setCheckbox(param, box) {
function setCheckbox(param, box) {
var val=getParamValue(param);
var val=getParamValue(param);
Строка 1109: Строка 1063:
}
}
}
}
 
function autoEdit() {
function autoEdit() {
if (!setupPopups.completed) { setupPopups(); }
if (!setupPopups.completed) { setupPopups(); }
if (!document.editform || !window.wgEnableAPI || !wgEnableAPI ) { return false; }
if (!document.editform) { return false; }
if (window.autoEdit.alreadyRan) { return false; }
if (window.autoEdit.alreadyRan) { return false; }
window.autoEdit.alreadyRan=true;
window.autoEdit.alreadyRan=true;
Строка 1124: Строка 1078:
var output=execCmds(input, cmdList);
var output=execCmds(input, cmdList);
editbox.value=output;
editbox.value=output;
// wikEd user script compatibility
if (typeof(wikEdUseWikEd) != 'undefined') {
if (wikEdUseWikEd == true) {
WikEdUpdateFrame();
}
}
}
}
setCheckbox('autominor', document.editform.wpMinoredit);
setCheckbox('autominor', document.editform.wpMinoredit);
setCheckbox('autowatch', document.editform.wpWatchthis);
setCheckbox('autowatch', document.editform.wpWatchthis);
 
var rvid = getParamValue('autorv');
var rvid = getParamValue('autorv');
if (rvid) {
if (getValueOf('popupUseQueryInterface') && getParamValue('autorv')) {
var url=pg.wiki.wikibase + '/api.php?action=query&format=json&prop=revisions&revids='+rvid;
var url=pg.wiki.wikibase + '/query.php?format=json&what=revisions&revids='+rvid;
startDownload(url, null, autoEdit2);
startDownload(url, null, autoEdit2);
} else { autoEdit2(); }
} else { autoEdit2(); }
}
}
 
function autoEdit2(d) {
function autoEdit2(d) {
var summary=getParamValue('autosummary');
var summary=getParamValue('autosummary');
Строка 1165: Строка 1113:
setTimeout(autoEdit3, 100);
setTimeout(autoEdit3, 100);
}
}
 
function autoClickToken() {
    return document.cookie.substr(document.cookie.indexOf("session=")+8,4);
}
function autoEdit3() {
function autoEdit3() {
    if( getParamValue('actoken') != autoClickToken()) return;
var btn=getParamValue('autoclick');
var btn=getParamValue('autoclick');
if (btn) {
if (btn) {
Строка 1188: Строка 1130:
}
}
}
}
 
function bannerMessage(s) {
function bannerMessage(s) {
var headings=document.getElementsByTagName('h1');
var headings=document.getElementsByTagName('h1');
Строка 1197: Строка 1139:
}
}
}
}
 
function getRvSummary(template, json) {
function getRvSummary(template, json) {
var o=getJsObj(json);
try {
try {
    var o=getJsObj(json);
var edit = anyChild(o.pages).revisions[0];
    var edit = anyChild(o.query.pages).revisions[0];
} catch (badness) {return false;}
} catch (badness) {return false;}
var timestamp = edit.timestamp.split(/[A-Z]/g).join(' ').replace(/^ *| *$/g, '');
var timestamp = edit.timestamp.split(/[A-Z]/g).join(' ').replace(/^ *| *$/g, '');
return simplePrintf(template, [edit.revid, timestamp, edit.user]);
return simplePrintf(template, [edit.revid, timestamp, edit.user]);
}
}
 
hookEvent('load', autoEdit);
 
//</NOLITE>
//</NOLITE>
// ENDFILE: autoedit.js
// ENDFILE: autoedit.js
Строка 1214: Строка 1158:
   {@link Downloader}, a xmlhttprequest wrapper, and helper functions.
   {@link Downloader}, a xmlhttprequest wrapper, and helper functions.
*/
*/
 
/**
/**
   Creates a new Downloader
   Creates a new Downloader
Строка 1225: Строка 1169:
/** xmlhttprequest object which we're wrapping */
/** xmlhttprequest object which we're wrapping */
this.http = false;
this.http = false;
 
/*@cc_on @*/
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
/*@if (@_jscript_version >= 5)
Строка 1241: Строка 1185:
}
}
@end @*/
@end @*/
 
if (! this.http && typeof XMLHttpRequest!='undefined') { this.http = new XMLHttpRequest(); }
if (! this.http && typeof XMLHttpRequest!='undefined') { this.http = new XMLHttpRequest(); }
/**
/**
Строка 1287: Строка 1231:
this.async=true;
this.async=true;
}
}
 
new Downloader();
new Downloader();
 
/** Submits the http request. */
/** Submits the http request. */
Downloader.prototype.send = function (x) {
Downloader.prototype.send = function (x) {
Строка 1310: Строка 1254:
/** Gets the state of the download. */
/** Gets the state of the download. */
Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;};
Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;};
 
pg.misc.downloadsInProgress = { };
pg.misc.downloadsInProgress = { };
 
/** Starts the download.
/** Starts the download.
     Note that setTarget {@link Downloader#setTarget} must be run first
     Note that setTarget {@link Downloader#setTarget} must be run first
Строка 1321: Строка 1265:
this.http.send(null);
this.http.send(null);
};
};
 
/** Gets the 'Last-Modified' date from the download headers.
/** Gets the 'Last-Modified' date from the download headers.
     Should be run after the download completes.
     Should be run after the download completes.
Строка 1336: Строка 1280:
return null;
return null;
};
};
 
/** Sets the callback function.
/** Sets the callback function.
     @param {Function} f callback function, called as <code>f(this)</code> on success
     @param {Function} f callback function, called as <code>f(this)</code> on success
Строка 1344: Строка 1288:
this.http.onreadystatechange = f;
this.http.onreadystatechange = f;
};
};
 
Downloader.prototype.getStatus = function() { if (!this.http) { return null; } return this.http.status; };
Downloader.prototype.getStatus = function() { if (!this.http) { return null; } return this.http.status; };
 
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// helper functions
// helper functions
 
/** Creates a new {@link Downloader} and prepares it for action.
/** Creates a new {@link Downloader} and prepares it for action.
     @param {String} url The url to download
     @param {String} url The url to download
Строка 1402: Строка 1346:
return callback(d);
return callback(d);
}
}
 
/**
/**
   Starts a download.
   Starts a download.
Строка 1416: Строка 1360:
return d;
return d;
}
}
 
/**
/**
   Aborts all downloads which have been started.
   Aborts all downloads which have been started.
Строка 1432: Строка 1376:
// STARTFILE: livepreview.js
// STARTFILE: livepreview.js
// TODO: location is often not correct (eg relative links in previews)
// TODO: location is often not correct (eg relative links in previews)
 
/**
/**
  * InstaView - a Mediawiki to HTML converter in JavaScript
  * InstaView - a Mediawiki to HTML converter in JavaScript
Строка 1464: Строка 1408:
  * - Support for coloured links (AJAX)
  * - Support for coloured links (AJAX)
  */
  */
 
 
var Insta = {}
var Insta = {}
 
function setupLivePreview() {
function setupLivePreview() {
 
     // options
     // options
     Insta.conf =
     Insta.conf =
{
{
    baseUrl: '',
    baseUrl: '',
 
    user: {},
    user: {},
 
    wiki: {
    wiki: {
lang: pg.wiki.lang,
lang: pg.wiki.lang,
Строка 1482: Строка 1426:
default_thumb_width: 180
default_thumb_width: 180
    },
    },
 
    paths: {
    paths: {
articles: '/' + joinPath([pg.wiki.prePath, pg.wiki.articlePath]) + '/',
articles: '/' + joinPath([pg.wiki.prePath, pg.wiki.articlePath]) + '/',
Строка 1490: Строка 1434:
magnify_icon: 'skins/common/images/magnify-clip.png'
magnify_icon: 'skins/common/images/magnify-clip.png'
    },
    },
 
    locale: {
    locale: {
user: pg.ns.user,
user: pg.ns.user,
Строка 1499: Строка 1443:
    }
    }
}
}
 
     // options with default values or backreferences
     // options with default values or backreferences
     with (Insta.conf) {
     with (Insta.conf) {
user.name = user.name || 'Absurdmeister'
user.name = user.name || 'Wikipedian'
user.signature = '[['+locale.user+':'+user.name+'|'+user.name+']]'
user.signature = '[['+locale.user+':'+user.name+'|'+user.name+']]'
//paths.images = 'http://upload.wikimedia.org/wikipedia/' + wiki.lang + '/'
//paths.images = 'http://upload.wikimedia.org/wikipedia/' + wiki.lang + '/'
     }
     }
 
     // define constants
     // define constants
     Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:File|Image|'+Insta.conf.locale.image+
     Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:Image|'+Insta.conf.locale.image+
      '):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i');
      '):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i');
 
}
}
 
 
Insta.dump = function(from, to)
Insta.dump = function(from, to)
{
{
Строка 1520: Строка 1464:
to.innerHTML = this.convert(from.value)
to.innerHTML = this.convert(from.value)
}
}
 
Insta.convert = function(wiki)
Insta.convert = function(wiki)
{
{
Строка 1527: Строка 1471:
p=0, // para flag
p=0, // para flag
$r // result of passing a regexp to $()
$r // result of passing a regexp to $()
 
// some shorthands
// some shorthands
function remain() { return ll.length }
function remain() { return ll.length }
function sh() { return ll.shift() } // shift
function sh() { return ll.shift() } // shift
function ps(s) { o+=s } // push
function ps(s) { o+=s } // push
 
function f() // similar to C's printf, uses ? as placeholders, ?? to escape question marks
function f() // similar to C's printf, uses ? as placeholders, ?? to escape question marks
{
{
Строка 1544: Строка 1488:
return o+f
return o+f
}
}
 
function html_entities(s) { return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;") }
function html_entities(s) { return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;") }
 
function max(a,b) { return (a>b)?a:b }
function max(a,b) { return (a>b)?a:b }
function min(a,b) { return (a<b)?a:b }
function min(a,b) { return (a<b)?a:b }
 
// return the first non matching character position between two strings
// return the first non matching character position between two strings
function str_imatch(a, b)
function str_imatch(a, b)
Строка 1556: Строка 1500:
return i
return i
}
}
 
// compare current line against a string or regexp
// compare current line against a string or regexp
// if passed a string it will compare only the first string.length characters
// if passed a string it will compare only the first string.length characters
// if passed a regexp the result is stored in $r
// 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 (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 $$(c) { return ll[0]==c } // compare current line against a string
function _(p) { return ll[0].charAt(p) } // return char at pos p
function _(p) { return ll[0].charAt(p) } // return char at pos p
 
function endl(s) { ps(s); sh() }
function endl(s) { ps(s); sh() }
 
function parse_list()
function parse_list()
{
{
var prev='';
var prev='';
 
while (remain() && $(/^([*#:;]+)(.*)$/)) {
while (remain() && $(/^([*#:;]+)(.*)$/)) {
 
var l_match = $r
var l_match = $r
 
sh()
sh()
 
var ipos = str_imatch(prev, l_match[1])
var ipos = str_imatch(prev, l_match[1])
 
// close uncontinued lists
// close uncontinued lists
for (var i=prev.length-1; i >= ipos; i--) {
for (var i=prev.length-1; i >= ipos; i--) {
 
var pi = prev.charAt(i)
var pi = prev.charAt(i)
 
if (pi=='*') ps('</ul>')
if (pi=='*') ps('</ul>')
else if (pi=='#') ps('</ol>')
else if (pi=='#') ps('</ol>')
Строка 1589: Строка 1533:
else switch (l_match[1].charAt(i)) { case'':case'*':case'#': ps('</dl>') }
else switch (l_match[1].charAt(i)) { case'':case'*':case'#': ps('</dl>') }
}
}
 
// open new lists
// open new lists
for (var i=ipos; i<l_match[1].length; i++) {
for (var i=ipos; i<l_match[1].length; i++) {
 
var li = l_match[1].charAt(i)
var li = l_match[1].charAt(i)
 
if (li=='*') ps('<ul>')
if (li=='*') ps('<ul>')
else if (li=='#') ps('<ol>')
else if (li=='#') ps('<ol>')
Строка 1600: Строка 1544:
else switch(prev.charAt(i)) { case'':case'*':case'#': ps('<dl>') }
else switch(prev.charAt(i)) { case'':case'*':case'#': ps('<dl>') }
}
}
 
switch (l_match[1].charAt(l_match[1].length-1)) {
switch (l_match[1].charAt(l_match[1].length-1)) {
 
case '*': case '#':
case '*': case '#':
ps('<li>' + parse_inline_nowiki(l_match[2])); break
ps('<li>' + parse_inline_nowiki(l_match[2])); break
 
case ';':
case ';':
ps('<dt>')
ps('<dt>')
 
var dt_match
var dt_match
 
// handle ;dt :dd format
// handle ;dt :dd format
if (dt_match = l_match[2].match(/(.*?)(:.*?)$/)) {
if (dt_match = l_match[2].match(/(.*?)(:.*?)$/)) {
 
ps(parse_inline_nowiki(dt_match[1]))
ps(parse_inline_nowiki(dt_match[1]))
ll.unshift(dt_match[2])
ll.unshift(dt_match[2])
 
} else ps(parse_inline_nowiki(l_match[2]))
} else ps(parse_inline_nowiki(l_match[2]))
 
break
break
 
case ':':
case ':':
ps('<dd>' + parse_inline_nowiki(l_match[2]))
ps('<dd>' + parse_inline_nowiki(l_match[2]))
}
}
 
prev=l_match[1]
prev=l_match[1]
}
}
 
// close remaining lists
// close remaining lists
for (var i=prev.length-1; i>=0; i--)
for (var i=prev.length-1; i>=0; i--)
ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl')))
ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl')))
}
}
 
function parse_table()
function parse_table()
{
{
endl(f('<table?>', $(/^\{\|( .*)$/)? $r[1]: ''))
endl(f('<table?>', $(/^\{\|( .*)$/)? $r[1]: ''))
 
for (;remain();) if ($('|')) switch (_(1)) {
for (;remain();) if ($('|')) switch (_(1)) {
case '}': endl('</table>'); return
case '}': endl('</table>'); return
Строка 1645: Строка 1589:
else sh()
else sh()
}
}
 
function parse_table_data()
function parse_table_data()
{
{
var td_line, match_i
var td_line, match_i
 
// 1: "|+", '|' or '+'
// 1: "|+", '|' or '+'
// 2: ??
// 2: ??
Строка 1655: Строка 1599:
// TODO: finish commenting this regexp
// TODO: finish commenting this regexp
var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/)
var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/)
 
if (td_match[1] == '|+') ps('<caption');
if (td_match[1] == '|+') ps('<caption');
else ps('<t' + ((td_match[1]=='|')?'d':'h'))
else ps('<t' + ((td_match[1]=='|')?'d':'h'))
 
if (typeof td_match[3] != 'undefined') {
if (typeof td_match[3] != 'undefined') {
 
ps(' ' + td_match[3])
ps(' ' + td_match[3])
match_i = 4
match_i = 4
 
} else match_i = 2
} else match_i = 2
 
ps('>')
ps('>')
 
if (td_match[1] != '|+') {
if (td_match[1] != '|+') {
 
// use || or !! as a cell separator depending on context
// use || or !! as a cell separator depending on context
// NOTE: when split() is passed a regexp make sure to use non-capturing brackets
// NOTE: when split() is passed a regexp make sure to use non-capturing brackets
td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/)
td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/)
 
ps(parse_inline_nowiki(td_line.shift()))
ps(parse_inline_nowiki(td_line.shift()))
 
while (td_line.length) ll.unshift(td_match[1] + td_line.pop())
while (td_line.length) ll.unshift(td_match[1] + td_line.pop())
 
} else ps(td_match[match_i])
} else ps(td_match[match_i])
 
var tc = 0, td = []
var tc = 0, td = []
 
for (;remain(); td.push(sh()))
for (;remain(); td.push(sh()))
if ($('|')) {
if ($('|')) {
Строка 1689: Строка 1633:
else if (!tc && $('!')) break
else if (!tc && $('!')) break
else if ($('{|')) tc++
else if ($('{|')) tc++
 
if (td.length) ps(Insta.convert(td))
if (td.length) ps(Insta.convert(td))
}
}
 
function parse_pre()
function parse_pre()
{
{
Строка 1699: Строка 1643:
ps('</pre>')
ps('</pre>')
}
}
 
function parse_block_image()
function parse_block_image()
{
{
ps(parse_image(sh()))
ps(parse_image(sh()))
}
}
 
function parse_image(str)
function parse_image(str)
{
{
//<NOLITE>
//<NOLITE>
// get what's in between "[[Image:" and "]]"
// get what's in between "[[Image:" and "]]"
var tag = str.substring(str.indexOf(':') + 1, str.length - 2);
var tag = str.substring(Insta.conf.locale.image.length + 3, str.length - 2);
 
var width;
var width;
var attr = [], filename, caption = '';
var attr = [], filename, caption = '';
var thumb=0, frame=0, center=0;
var thumb=0, frame=0, center=0;
var align='';
var align='';
 
if (tag.match(/\|/)) {
if (tag.match(/\|/)) {
// manage nested links
// manage nested links
Строка 1735: Строка 1679:
}
}
}
}
 
attr = tag.split(/\s*\|\s*/);
attr = tag.split(/\s*\|\s*/);
attr.push(last_attr);
attr.push(last_attr);
filename = attr.shift();
filename = attr.shift();
 
var w_match;
var w_match;
 
for (;attr.length; attr.shift())
for (;attr.length; attr.shift())
if (w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/)) width = w_match[1]
if (w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/)) width = w_match[1]
Строка 1764: Строка 1708:
if (attr.length == 1) caption = attr[0];
if (attr.length == 1) caption = attr[0];
}
}
 
} else filename = tag;
} else filename = tag;
 
 
var o='';
var o='';
 
if (frame) {
if (frame) {
 
if (align=='') align = 'right';
if (align=='') align = 'right';
 
o += f("<div class='thumb t?'>", align);
o += f("<div class='thumb t?'>", align);
 
if (thumb) {
if (thumb) {
if (!width) width = Insta.conf.wiki.default_thumb_width;
if (!width) width = Insta.conf.wiki.default_thumb_width;
 
o += f("<div style='width:?px;'>?", 2+width*1, make_image(filename, caption, width)) +
o += f("<div style='width:?px;'>?", 2+width*1, make_image(filename, caption, width)) +
f("<div class='thumbcaption'><div class='magnify' style='float:right'><a href='?' class='internal' title='Enlarge'><img src='?'></a></div>?</div>",
f("<div class='thumbcaption'><div class='magnify' style='float:right'><a href='?' class='internal' title='Enlarge'><img src='?'></a></div>?</div>",
Строка 1788: Строка 1732:
o += '<div>' + make_image(filename, caption) + f("<div class='thumbcaption'>?</div>", parse_inline_nowiki(caption))
o += '<div>' + make_image(filename, caption) + f("<div class='thumbcaption'>?</div>", parse_inline_nowiki(caption))
}
}
 
o += '</div></div>';
o += '</div></div>';
 
} else if (align != '') {
} else if (align != '') {
o += f("<div class='float?'><span>?</span></div>", align, make_image(filename, caption, width));
o += f("<div class='float?'><span>?</span></div>", align, make_image(filename, caption, width));
Строка 1796: Строка 1740:
return make_image(filename, caption, width);
return make_image(filename, caption, width);
}
}
 
return center? f("<div class='center'>?</div>", o): o;
return center? f("<div class='center'>?</div>", o): o;
//</NOLITE>
//</NOLITE>
}
}
 
function parse_inline_nowiki(str)
function parse_inline_nowiki(str)
{
{
Строка 1806: Строка 1750:
var substart=0, nestlev=0, open, close, subloop;
var substart=0, nestlev=0, open, close, subloop;
var html='';
var html='';
 
while (-1 != (start = str.indexOf('<nowiki>', substart))) {
while (-1 != (start = str.indexOf('<nowiki>', substart))) {
html += parse_inline_wiki(str.substring(lastend, start));
html += parse_inline_wiki(str.substring(lastend, start));
Строка 1833: Строка 1777:
} while (subloop)
} while (subloop)
}
}
 
return html + parse_inline_wiki(str.substr(lastend));
return html + parse_inline_wiki(str.substr(lastend));
}
}
 
function make_image(filename, caption, width)
function make_image(filename, caption, width)
{
{
Строка 1844: Строка 1788:
// replace spaces with underscores
// replace spaces with underscores
filename = filename.replace(/ /g, '_');
filename = filename.replace(/ /g, '_');
 
caption = strip_inline_wiki(caption);
caption = strip_inline_wiki(caption);
 
var md5 = hex_md5(filename);
var md5 = hex_md5(filename);
 
var source = md5.charAt(0) + '/' + md5.substr(0,2) + '/' + filename;
var source = md5.charAt(0) + '/' + md5.substr(0,2) + '/' + filename;
 
if (width) width = "width='" + width + "px'";
if (width) width = "width='" + width + "px'";
 
var img = f("<img onerror=\"this.onerror=null;this.src='?'\" src='?' ? ?>", Insta.conf.paths.images_fallback + source, Insta.conf.paths.images + source, (caption!='')? "alt='" + caption + "'" : '', width);
var img = f("<img onerror=\"this.onerror=null;this.src='?'\" src='?' ? ?>", Insta.conf.paths.images_fallback + source, Insta.conf.paths.images + source, (caption!='')? "alt='" + caption + "'" : '', width);
 
return f("<a class='image' ? href='?'>?</a>", (caption!='')? "title='" + caption + "'" : '', Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename, img);
return f("<a class='image' ? href='?'>?</a>", (caption!='')? "title='" + caption + "'" : '', Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename, img);
//</NOLITE>
//</NOLITE>
}
}
 
function parse_inline_images(str)
function parse_inline_images(str)
{
{
Строка 1864: Строка 1808:
var start, substart=0, nestlev=0;
var start, substart=0, nestlev=0;
var loop, close, open, wiki, html;
var loop, close, open, wiki, html;
 
while (-1 != (start=str.indexOf('[[', substart))) {
while (-1 != (start=str.indexOf('[[', substart))) {
if(str.substr(start+2).match(RegExp('^(Image|File|' + Insta.conf.locale.image + '):','i'))) {
if(str.substr(start+2).match(RegExp('^' + Insta.conf.locale.image + ':','i'))) {
loop=true;
loop=true;
substart=start;
substart=start;
Строка 1890: Строка 1834:
}
}
} while (loop)
} while (loop)
 
} else break;
} else break;
}
}
 
//</NOLITE>
//</NOLITE>
return str;
return str;
}
}
 
// the output of this function doesn't respect the FILO structure of HTML
// 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
// but since most browsers can handle it I'll save myself the hassle
Строка 1917: Строка 1861:
return o+str.substr(li);
return o+str.substr(li);
}
}
 
function parse_inline_wiki(str)
function parse_inline_wiki(str)
{
{
var aux_match;
var aux_match;
 
str = parse_inline_images(str);
str = parse_inline_images(str);
str = parse_inline_formatting(str);
str = parse_inline_formatting(str);
 
// math
// math
while (aux_match = str.match(/<(?:)math>(.*?)<\/math>/i)) {
while (aux_match = str.match(/<(?:)math>(.*?)<\/math>/i)) {
Строка 1930: Строка 1874:
str = str.replace(aux_match[0], f("<img src='?.png'>", Insta.conf.paths.math+math_md5));
str = str.replace(aux_match[0], f("<img src='?.png'>", Insta.conf.paths.math+math_md5));
}
}
 
// Build a Mediawiki-formatted date string
// Build a Mediawiki-formatted date string
var date = new Date;
var date = new Date;
Строка 1936: Строка 1880:
if (minutes < 10) minutes = '0' + minutes;
if (minutes < 10) minutes = '0' + minutes;
var date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), Insta.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear());
var date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), Insta.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear());
 
// text formatting
// text formatting
return str.
return str.
Строка 1943: Строка 1887:
replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date).
replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date).
replace(/~{3}(?!~)/g, Insta.conf.user.name).
replace(/~{3}(?!~)/g, Insta.conf.user.name).
 
// [[:Category:...]], [[:Image:...]], etc...
// [[:Category:...]], [[:Image:...]], etc...
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):[^|]*?)\\]\\](\w*)','gi'), "<a href='"+Insta.conf.paths.articles+"$1'>$1$2</a>").
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):[^|]*?)\\]\\](\w*)','gi'), "<a href='"+Insta.conf.paths.articles+"$1'>$1$2</a>").
// remove straight category and interwiki tags
// remove straight category and interwiki tags
replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),'').
replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),'').
 
// [[:Category:...|Links]], [[:Image:...|Links]], etc...
// [[:Category:...|Links]], [[:Image:...|Links]], etc...
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):.*?)\\|([^\\]]+?)\\]\\](\\w*)','gi'), "<a href='"+Insta.conf.paths.articles+"$1'>$2$3</a>").
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):.*?)\\|([^\\]]+?)\\]\\](\\w*)','gi'), "<a href='"+Insta.conf.paths.articles+"$1'>$2$3</a>").
 
// [[/Relative links]]
// [[/Relative links]]
replace(/\[\[(\/[^|]*?)\]\]/g, f("<a href='?$1'>$1</a>", Insta.conf.baseUrl)).
replace(/\[\[(\/[^|]*?)\]\]/g, f("<a href='?$1'>$1</a>", Insta.conf.baseUrl)).
 
// [[/Replaced|Relative links]]
// [[/Replaced|Relative links]]
replace(/\[\[(\/.*?)\|(.+?)\]\]/g, f("<a href='?$1'>$2</a>", Insta.conf.baseUrl)).
replace(/\[\[(\/.*?)\|(.+?)\]\]/g, f("<a href='?$1'>$2</a>", Insta.conf.baseUrl)).
 
// [[Common links]]
// [[Common links]]
replace(/\[\[([^|]*?)\]\](\w*)/g, f("<a href='?$1'>$1$2</a>", Insta.conf.paths.articles)).
replace(/\[\[([^|]*?)\]\](\w*)/g, f("<a href='?$1'>$1$2</a>", Insta.conf.paths.articles)).
 
// [[Replaced|Links]]
// [[Replaced|Links]]
replace(/\[\[(.*?)\|([^\]]+?)\]\](\w*)/g, f("<a href='?$1'>$2$3</a>", Insta.conf.paths.articles)).
replace(/\[\[(.*?)\|([^\]]+?)\]\](\w*)/g, f("<a href='?$1'>$2$3</a>", Insta.conf.paths.articles)).
 
// [[Stripped:Namespace|Namespace]]
// [[Stripped:Namespace|Namespace]]
replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, f("<a href='?$1$2$3'>$2</a>", Insta.conf.paths.articles)).
replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, f("<a href='?$1$2$3'>$2</a>", Insta.conf.paths.articles)).
 
// External links
// External links
replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, "<a class='external' href='$1:$2$3'>$4</a>").
replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, "<a class='external' href='$1:$2$3'>$4</a>").
Строка 1972: Строка 1916:
replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, "<a class='external' href='$1:$2$3'>$1:$2$3</a>").
replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, "<a class='external' href='$1:$2$3'>$1:$2$3</a>").
replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*[^.,!?;: $])/g, "$1<a class='external' href='$2:$3$4'>$2:$3$4</a>").
replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*[^.,!?;: $])/g, "$1<a class='external' href='$2:$3$4'>$2:$3$4</a>").
 
replace('__NOTOC__','').
replace('__NOTOC__','').
replace('__NOEDITSECTION__','');
replace('__NOEDITSECTION__','');
}
}
/*
 
*/
function strip_inline_wiki(str)
function strip_inline_wiki(str)
{
{
Строка 1985: Строка 1928:
.replace(/''(.*?)''/g,'$1');
.replace(/''(.*?)''/g,'$1');
}
}
 
// begin parsing
// begin parsing
for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) {
for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) {
p=0
p=0
endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3]))
endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3]))
 
} else if ($(/^[*#:;]/)) {
} else if ($(/^[*#:;]/)) {
p=0
p=0
parse_list()
parse_list()
 
} else if ($(' ')) {
} else if ($(' ')) {
p=0
p=0
parse_pre()
parse_pre()
 
} else if ($('{|')) {
} else if ($('{|')) {
p=0
p=0
parse_table()
parse_table()
 
} else if ($(/^----+$/)) {
} else if ($(/^----+$/)) {
p=0
p=0
endl('<hr>')
endl('<hr>')
 
} else if ($(Insta.BLOCK_IMAGE)) {
} else if ($(Insta.BLOCK_IMAGE)) {
p=0
p=0
parse_block_image()
parse_block_image()
 
} else {
} else {
 
// handle paragraphs
// handle paragraphs
if ($$('')) {
if ($$('')) {
Строка 2023: Строка 1966:
ps(parse_inline_nowiki(ll[0]) + ' ')
ps(parse_inline_nowiki(ll[0]) + ' ')
}
}
 
sh();
sh();
}
}
 
return o
return o
};
};
 
window.wiki2html=function(txt,baseurl) {
window.wiki2html=function(txt,baseurl) {
     Insta.conf.baseUrl=baseurl;
     Insta.conf.baseUrl=baseurl;
Строка 2040: Строка 1983:
return formatBytes(data.length);
return formatBytes(data.length);
}
}
 
function popupFilterCountLinks(data) {
function popupFilterCountLinks(data) {
var num=countLinks(data);
var num=countLinks(data);
return String(num) + '&nbsp;' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink'));
return String(num) + '&nbsp;' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink'));
}
}
 
function popupFilterCountImages(data) {
function popupFilterCountImages(data) {
var num=countImages(data);
var num=countImages(data);
return String(num) + '&nbsp;' + ((num!=1)?popupString('images'):popupString('image'));
return String(num) + '&nbsp;' + ((num!=1)?popupString('images'):popupString('image'));
}
}
 
function popupFilterCountCategories(data) {
function popupFilterCountCategories(data) {
var num=countCategories(data);
var num=countCategories(data);
return String(num) + '&nbsp;' + ((num!=1)?popupString('categories'):popupString('category'));
return String(num) + '&nbsp;' + ((num!=1)?popupString('categories'):popupString('category'));
}
}
 
 
function popupFilterLastModified(data,download) {
function popupFilterLastModified(data,download) {
var lastmod=download.lastModified;
var lastmod=download.lastModified;
Строка 2066: Строка 2009:
return '';
return '';
}
}
 
function formatAge(age) {
function formatAge(age) {
// coerce into a number
// coerce into a number
var a=0+age, aa=a;
var a=0+age, aa=a;
 
var seclen  = 1000;
var seclen  = 1000;
var minlen  = 60*seclen;
var minlen  = 60*seclen;
Строка 2076: Строка 2019:
var daylen  = 24*hourlen;
var daylen  = 24*hourlen;
var weeklen = 7*daylen;
var weeklen = 7*daylen;
 
var numweeks = (a-a%weeklen)/weeklen; a = a-numweeks*weeklen; var sweeks = addunit(numweeks, 'week');
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 numdays  = (a-a%daylen)/daylen;  a = a-numdays*daylen;  var sdays  = addunit(numdays, 'day');
Строка 2082: Строка 2025:
var nummins  = (a-a%minlen)/minlen;  a = a-nummins*minlen;  var smins  = addunit(nummins, 'minute');
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');
var numsecs  = (a-a%seclen)/seclen;  a = a-numsecs*seclen;  var ssecs  = addunit(numsecs, 'second');
 
if (aa > 4*weeklen) { return sweeks; }
if (aa > 4*weeklen) { return sweeks; }
if (aa > weeklen)  { return sweeks + ' ' + sdays; }
if (aa > weeklen)  { return sweeks + ' ' + sdays; }
Строка 2092: Строка 2035:
return ssecs;
return ssecs;
}
}
 
function addunit(num,str) { return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;}
function addunit(num,str) { return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;}
 
function runPopupFilters(list, data, download) {
function runPopupFilters(list, data, download) {
var ret=[];
var ret=[];
Строка 2105: Строка 2048:
return ret;
return ret;
}
}
 
function getPageInfo(data, download) {
function getPageInfo(data, download) {
if (!data || data.length === 0) { return popupString('Empty page'); }
if (!data || data.length === 0) { return popupString('Empty page'); }
 
var popupFilters=getValueOf('popupFilters') || [];
var popupFilters=getValueOf('popupFilters') || [];
var extraPopupFilters = getValueOf('extraPopupFilters') || [];
var extraPopupFilters = getValueOf('extraPopupFilters') || [];
var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download);
var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download);
 
var pageInfo=pageInfoArray.join(', ');
var pageInfo=pageInfoArray.join(', ');
if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); }
if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); }
return pageInfo;
return pageInfo;
}
}
 
 
// this could be improved!
// this could be improved!
function countLinks(wikiText) { return wikiText.split('[[').length - 1; }
function countLinks(wikiText) { return wikiText.split('[[').length - 1; }
 
// if N = # matches, n = # brackets, then
// if N = # matches, n = # brackets, then
// String.parenSplit(regex) intersperses the N+1 split elements
// String.parenSplit(regex) intersperses the N+1 split elements
// with Nn other elements. So total length is
// with Nn other elements. So total length is
// L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1).
// L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1).
 
function countImages(wikiText) {
function countImages(wikiText) {
return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1);
return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1);
}
}
 
function countCategories(wikiText) {
function countCategories(wikiText) {
return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1);
return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1);
}
}
 
function popupFilterStubDetect(data, download, article)    {
function popupFilterStubDetect(data, download, article)    {
var counts=stubCount(data, article);
var counts=stubCount(data, article);
Строка 2141: Строка 2084:
return '';
return '';
}
}
 
function popupFilterDisambigDetect(data, download, article) {
function popupFilterDisambigDetect(data, download, article) {
if (getValueOf('popupOnlyArticleDabStub') && article.namespace()) { return ''; }
if (getValueOf('popupOnlyArticleDabStub') && article.namespace()) { return ''; }
return (isDisambig(data, article)) ? popupString('disambig') : '';
return (isDisambig(data, article)) ? popupString('disambig') : '';
}
}
 
function formatBytes(num) {
function formatBytes(num) {
return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +'&nbsp;' + popupString('bytes')) ;
return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +'&nbsp;' + popupString('bytes')) ;
Строка 2155: Строка 2098:
/**
/**
   @fileoverview Defines the {@link Title} class, and associated crufty functions.
   @fileoverview Defines the {@link Title} class, and associated crufty functions.
 
   <code>Title</code> deals with article titles and their various
   <code>Title</code> deals with article titles and their various
   forms.  {@link Stringwrapper} is the parent class of
   forms.  {@link Stringwrapper} is the parent class of
   <code>Title</code>, which exists simply to make things a little
   <code>Title</code>, which exists simply to make things a little
   neater.
   neater.
 
*/
*/
 
/**
/**
   Creates a new Stringwrapper.
   Creates a new Stringwrapper.
   @constructor
   @constructor
 
   @class the Stringwrapper class. This base class is not really
   @class the Stringwrapper class. This base class is not really
   useful on its own; it just wraps various common string operations.
   useful on its own; it just wraps various common string operations.
Строка 2212: Строка 2155:
this.replace=function(x,y){ return this.toString().replace(x,y); };
this.replace=function(x,y){ return this.toString().replace(x,y); };
}
}
 
 
/**
/**
   Creates a new <code>Title</code>.
   Creates a new <code>Title</code>.
   @constructor
   @constructor
 
   @class The Title class. Holds article titles and converts them into
   @class The Title class. Holds article titles and converts them into
   various forms. Also deals with anchors, by which we mean the bits
   various forms. Also deals with anchors, by which we mean the bits
   of the article URL after a # character, representing locations
   of the article URL after a # character, representing locations
   within an article.
   within an article.
 
   @param {String} value The initial value to assign to the
   @param {String} value The initial value to assign to the
   article. This must be the canonical title (see {@link
   article. This must be the canonical title (see {@link
Строка 2243: Строка 2186:
*/
*/
this.anchor='';
this.anchor='';
 
this.setUtf(val);
this.setUtf(val);
}
}
Строка 2275: Строка 2218:
};
};
Title.prototype.anchorFromUtf=function(str) {
Title.prototype.anchorFromUtf=function(str) {
this.anchor=encodeURIComponent(str.split(' ').join('_'))
this.anchor=encodeURIComponent(str).split('.').join('%2E').split('%').join('.');
.split('%3A').join(':').split("'").join('%27').split('%').join('.');
};
};
Title.fromURL=function(h) {
Title.fromURL=function(h) {
Строка 2286: Строка 2228:
return this;
return this;
}
}
 
// NOTE : playing with decodeURI, encodeURI, escape, unescape,
// NOTE : playing with decodeURI, encodeURI, escape, unescape,
// we seem to be able to replicate the IE borked encoding
// we seem to be able to replicate the IE borked encoding
 
// IE doesn't do this new-fangled utf-8 thing.
// IE doesn't do this new-fangled utf-8 thing.
// and it's worse than that.
// and it's worse than that.
// IE seems to treat the query string differently to the rest of the url
// 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
// 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.
// we fix up & for all browsers, just in case.
var splitted=h.split('?');
var splitted=h.split('?');
splitted[0]=splitted[0].split('&').join('%26');
splitted[0]=splitted[0].split('&').join('%26');
 
if (pg.flag.linksLikeIE6) {
if (pg.flag.linksLikeIE6) {
splitted[0]=encodeURI(decode_utf8(splitted[0]));
splitted[0]=encodeURI(decode_utf8(splitted[0]));
}
}
 
h=splitted.join('?');
h=splitted.join('?');
 
var contribs=pg.re.contribs.exec(h);
var contribs=pg.re.contribs.exec(h);
if (contribs !== null) {
if (contribs !== null) {
Строка 2312: Строка 2254:
return this;
return this;
}
}
 
var email=pg.re.email.exec(h);
var email=pg.re.email.exec(h);
if (email !== null) {
if (email !== null) {
Строка 2318: Строка 2260:
return this;
return this;
}
}
 
var backlinks=pg.re.backlinks.exec(h);
var backlinks=pg.re.backlinks.exec(h);
if (backlinks) {
if (backlinks) {
Строка 2324: Строка 2266:
return this;
return this;
}
}
 
// no more special cases to check --
// no more special cases to check --
// hopefully it's not a disguised user-related or specially treated special page
// hopefully it's not a disguised user-related or specially treated special page
Строка 2330: Строка 2272:
if(m===null) { this.value=null; }
if(m===null) { this.value=null; }
else {
else {
        var fromBotInterface = /[?](.+[&])?title=/.test(h);
    var fromBotInterface = /[?](.+[&])?title=/.test(h);
        if (fromBotInterface) {
    if (fromBotInterface) {
            m[2]=m[2].split('+').join('_');
    m[2]=m[2].split('+').join('_');
        }
    }
        var extracted = m[2] + (m[3] ? '#' + m[3] : '');
    var extracted = m[2] + (m[3] ? '#' + m[3] : '');
        if (pg.flag.isSafari && /%25[0-9A-Fa-f]{2}/.test(extracted)) {
    this.setUtf(this.decodeNasties(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;
return this;
};
};
Строка 2400: Строка 2336:
var talkRegex=namespaceListToRegex(pg.ns.talkList);
var talkRegex=namespaceListToRegex(pg.ns.talkList);
if (talkRegex.exec(this.value)) { this.value=null; return null;}
if (talkRegex.exec(this.value)) { this.value=null; return null;}
 
var nsReg=namespaceListToRegex(pg.ns.withTalkList);
var nsReg=namespaceListToRegex(pg.ns.withTalkList);
var splitted=this.value.parenSplit(nsReg);
var splitted=this.value.parenSplit(nsReg);
Строка 2473: Строка 2409:
//</NOLITE>
//</NOLITE>
Title.prototype.stripNamespace=function(){ // returns a string, not a Title
Title.prototype.stripNamespace=function(){ // returns a string, not a Title
var n=this.value.indexOf(':');
// this isn't very sophisticated
if (n<0) { return this.value; }
// it just removes everything up to the final :
var list=pg.ns.list;
// BUG: probably does silly things for images with colons in the name - check it out
for (var i=0; i<list.length; ++i) {
var list = this.value.split(':');
if (upcaseFirst(list[i]) == this.value.substring(0,n)) { return this.value.substring(n+1); }
return list[list.length-1];
}
};
return this.value;
Title.prototype.setUtf=function(value){
};
Title.prototype.setUtf=function(value){
if (!value) { this.value=''; return; }
if (!value) { this.value=''; return; }
var anch=value.indexOf('#');
var anch=value.indexOf('#');
Строка 2510: Строка 2444:
return pg.wiki.titlebase + this.urlString();
return pg.wiki.titlebase + this.urlString();
};
};
 
 
function paramValue(param, url) {
function paramValue(param, url) {
var s=url.parenSplit(RegExp('[?&]' + literalizeRegex(param) + '=([^?&]*)'));
var s=url.parenSplit(RegExp('[?&]' + literalizeRegex(param) + '=([^?&]*)'));
Строка 2517: Строка 2451:
return s[1] || null;
return s[1] || null;
}
}
 
function parseParams(url) {
function parseParams(url) {
var ret={};
var ret={};
Строка 2530: Строка 2464:
return ret;
return ret;
}
}
 
// all sorts of stuff here
// all sorts of stuff here
// FIXME almost everything needs to be rewritten
// FIXME almost everything needs to be rewritten
 
function oldidFromAnchor(a) { return paramValue('oldid', a.href); }
function oldidFromAnchor(a) { return paramValue('oldid', a.href); }
//function diffFromAnchor(a) { return paramValue('diff', a.href); }
//function diffFromAnchor(a) { return paramValue('diff', a.href); }
 
 
function wikiMarkupToAddressFragment (str) { // for images
function wikiMarkupToAddressFragment (str) { // for images
var ret = safeDecodeURI(str);
var ret = safeDecodeURI(str);
Строка 2544: Строка 2478:
return ret;
return ret;
}
}
 
// (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup)
// (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup)
// (b) change spaces to underscores
// (b) change spaces to underscores
// (c) encodeURI (just the straight one, no pg.re.urlNoPopup)
// (c) encodeURI (just the straight one, no pg.re.urlNoPopup)
 
function myDecodeURI (str) {
function myDecodeURI (str) {
var ret;
var ret;
Строка 2561: Строка 2495:
return ret;
return ret;
}
}
 
function safeDecodeURI(str) { var ret=myDecodeURI(str); return ret || str; }
function safeDecodeURI(str) { var ret=myDecodeURI(str); return ret || str; }
 
///////////
///////////
// TESTS //
// TESTS //
///////////
///////////
 
//<NOLITE>
//<NOLITE>
function isIpUser(user) {return pg.re.ipUser.test(user);}
function isIpUser(user) {return pg.re.ipUser.test(user);}
 
function isDisambig(data, article) {
function isDisambig(data, article) {
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
return ! article.isTalkPage() && pg.re.disambig.test(data);
return ! article.isTalkPage() && pg.re.disambig.test(data);
}
}
 
function stubCount(data, article) {
function stubCount(data, article) {
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
Строка 2589: Строка 2523:
return { real: realStub, sect: sectStub };
return { real: realStub, sect: sectStub };
}
}
 
function isValidImageName(str){ // extend as needed...
function isValidImageName(str){ // extend as needed...
return ( str.indexOf('{') == -1 );
return ( str.indexOf('{') == -1 );
}
}
 
function isInStrippableNamespace(article) {
function isInStrippableNamespace(article) {
return ( findInArray( pg.ns.nonArticleList, article.namespace() ) > -1 );
return ( findInArray( pg.ns.nonArticleList, article.namespace() ) > -1 );
}
}
 
function isInMainNamespace(article) { return !isInStrippableNamespace(article); }
function isInMainNamespace(article) { return !isInStrippableNamespace(article); }
 
function anchorContainsImage(a) {
function anchorContainsImage(a) {
// iterate over children of anchor a
// iterate over children of anchor a
Строка 2612: Строка 2546:
// NB for performance reasons, TOC links generally return true
// NB for performance reasons, TOC links generally return true
// they should be stripped out later
// they should be stripped out later
 
if (!markNopopupSpanLinks.done) { markNopopupSpanLinks(); }
if (!markNopopupSpanLinks.done) { markNopopupSpanLinks(); }
if (a.inNopopupSpan || a.className=='sortheader') { return false; }
if (a.inNopopupSpan || a.className=='sortheader') { return false; }
 
// FIXME is this faster inline?
// FIXME is this faster inline?
if (a.onmousedown || a.getAttribute('nopopup')) { return false; }
if (a.onmousedown || a.getAttribute('nopopup')) { return false; }
Строка 2625: Строка 2559:
h.indexOf('&limit=') == -1 );
h.indexOf('&limit=') == -1 );
}
}
 
function markNopopupSpanLinks() {
function markNopopupSpanLinks() {
if( !getValueOf('popupOnlyArticleLinks'))
var s=document.getElementsByTagName('span');
fixVectorMenuPopups();
var s=getElementsByClassName(document, '*', "nopopups")
for (var i=0; i<s.length; ++i) {
for (var i=0; i<s.length; ++i) {
var as=s[i].getElementsByTagName('a');
if (s[i].className && s[i].className.toLowerCase()=='nopopups') {
for (var j=0; j<as.length; ++j) {
var as=s[i].getElementsByTagName('a');
as[j].inNopopupSpan=true;
for (var j=0; j<as.length; ++j) {
as[j].inNopopupSpan=true;
}
}
}
}
}
markNopopupSpanLinks.done=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
// ENDFILE: titles.js
Строка 2655: Строка 2578:
// Cookie handling
// Cookie handling
// from http://www.quirksmode.org/js/cookies.html
// from http://www.quirksmode.org/js/cookies.html
 
var Cookie= {
var Cookie= {
create: function(name,value,days)
create: function(name,value,days)
Строка 2669: Строка 2592:
document.cookie = name+"="+value+expires+"; path=/";
document.cookie = name+"="+value+expires+"; path=/";
},
},
 
read: function(name)
read: function(name)
{
{
Строка 2682: Строка 2605:
return null;
return null;
},
},
 
erase: function(name)
erase: function(name)
{
{
Строка 2694: Строка 2617:
// Wiki-specific downloading
// Wiki-specific downloading
//
//
 
// Schematic for a getWiki call
// Schematic for a getWiki call
//
//
Строка 2703: Строка 2626:
//  \.
//  \.
//    (async)->addPageToCache(download)->-onComplete(download)
//    (async)->addPageToCache(download)->-onComplete(download)
 
 
/** @todo {document}
/** @todo {document}
     @param {Title} article
     @param {Title} article
Строка 2717: Строка 2640:
if (oldid || oldid===0 || oldid==='0') { url += '&oldid='+oldid; }
if (oldid || oldid===0 || oldid==='0') { url += '&oldid='+oldid; }
url += '&maxage=0&smaxage=0';
url += '&maxage=0&smaxage=0';
 
getPageWithCaching(url, onComplete, owner);
getPageWithCaching(url, onComplete, owner);
}
}
 
// check cache to see if page exists
// check cache to see if page exists
 
function getPageWithCaching(url, onComplete, owner) {
function getPageWithCaching(url, onComplete, owner) {
log('getPageWithCaching, url='+url);
log('getPageWithCaching, url='+url);
Строка 2738: Строка 2661:
}
}
}
}
 
function getPage(url, onComplete, owner) {
function getPage(url, onComplete, owner) {
log('getPage');
log('getPage');
Строка 2744: Строка 2667:
return startDownload(url, owner.idNumber, callback);
return startDownload(url, owner.idNumber, callback);
}
}
 
function findInPageCache(url) {
function findInPageCache(url) {
for (var i=0; i<pg.cache.pages.length; ++i) {
for (var i=0; i<pg.cache.pages.length; ++i) {
Строка 2751: Строка 2674:
return -1;
return -1;
}
}
 
function addPageToCache(download) {
function addPageToCache(download) {
log('addPageToCache '+download.url);
log('addPageToCache '+download.url);
Строка 2768: Строка 2691:
  * See http://pajhome.org.uk/crypt/md5 for more info.
  * See http://pajhome.org.uk/crypt/md5 for more info.
  */
  */
 
/*
/*
  * Configurable variables. You may need to tweak these to be compatible with
  * Configurable variables. You may need to tweak these to be compatible with
Строка 2775: Строка 2698:
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase     */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase     */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance  */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance  */
 
/*
/*
  * These are the functions you'll usually want to call
  * These are the functions you'll usually want to call
Строка 2789: Строка 2712:
function any_hmac_md5(k, d, e)
function any_hmac_md5(k, d, e)
   { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(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
  * Perform a simple self-test to see if the VM is working
Строка 2797: Строка 2720:
   return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
   return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}
}
 
/*
/*
  * Calculate the MD5 of a raw string
  * Calculate the MD5 of a raw string
Строка 2805: Строка 2728:
   return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
   return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
}
}
 
/*
/*
  * Calculate the HMAC-MD5, of a key and some data (raw strings)
  * Calculate the HMAC-MD5, of a key and some data (raw strings)
Строка 2813: Строка 2736:
   var bkey = rstr2binl(key);
   var bkey = rstr2binl(key);
   if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
   if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
 
   var ipad = Array(16), opad = Array(16);
   var ipad = Array(16), opad = Array(16);
   for(var i = 0; i < 16; i++)
   for(var i = 0; i < 16; i++)
Строка 2820: Строка 2743:
     opad[i] = bkey[i] ^ 0x5C5C5C5C;
     opad[i] = bkey[i] ^ 0x5C5C5C5C;
   }
   }
 
   var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
   var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
   return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
   return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
}
}
 
/*
/*
  * Convert a raw string to a hex string
  * Convert a raw string to a hex string
Строка 2841: Строка 2764:
   return output;
   return output;
}
}
 
/*
/*
  * Convert a raw string to a base-64 string
  * Convert a raw string to a base-64 string
Строка 2863: Строка 2786:
   return output;
   return output;
}
}
 
/*
/*
  * Convert a raw string to an arbitrary string encoding
  * Convert a raw string to an arbitrary string encoding
Строка 2872: Строка 2795:
   var remainders = Array();
   var remainders = Array();
   var i, q, x, quotient;
   var i, q, x, quotient;
 
   /* Convert to an array of 16-bit big-endian values, forming the dividend */
   /* Convert to an array of 16-bit big-endian values, forming the dividend */
   var dividend = Array(input.length / 2);
   var dividend = Array(input.length / 2);
Строка 2879: Строка 2802:
     dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
     dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
   }
   }
 
   /*
   /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * Repeatedly perform a long division. The binary array forms the dividend,
Строка 2901: Строка 2824:
     dividend = quotient;
     dividend = quotient;
   }
   }
 
   /* Convert the remainders to the output string */
   /* Convert the remainders to the output string */
   var output = "";
   var output = "";
   for(i = remainders.length - 1; i >= 0; i--)
   for(i = remainders.length - 1; i >= 0; i--)
     output += encoding.charAt(remainders[i]);
     output += encoding.charAt(remainders[i]);
 
   return output;
   return output;
}
}
 
/*
/*
  * Encode a string as utf-8.
  * Encode a string as utf-8.
Строка 2919: Строка 2842:
   var i = -1;
   var i = -1;
   var x, y;
   var x, y;
 
   while(++i < input.length)
   while(++i < input.length)
   {
   {
Строка 2930: Строка 2853:
       i++;
       i++;
     }
     }
 
     /* Encode output as utf-8 */
     /* Encode output as utf-8 */
     if(x <= 0x7F)
     if(x <= 0x7F)
Строка 2949: Строка 2872:
   return output;
   return output;
}
}
 
/*
/*
  * Encode a string as utf-16
  * Encode a string as utf-16
Строка 2961: Строка 2884:
   return output;
   return output;
}
}
 
function str2rstr_utf16be(input)
function str2rstr_utf16be(input)
{
{
Строка 2970: Строка 2893:
   return output;
   return output;
}
}
 
/*
/*
  * Convert a raw string to an array of little-endian words
  * Convert a raw string to an array of little-endian words
Строка 2984: Строка 2907:
   return output;
   return output;
}
}
 
/*
/*
  * Convert an array of little-endian words to a string
  * Convert an array of little-endian words to a string
Строка 2995: Строка 2918:
   return output;
   return output;
}
}
 
/*
/*
  * Calculate the MD5 of an array of little-endian words, and a bit length.
  * Calculate the MD5 of an array of little-endian words, and a bit length.
Строка 3004: Строка 2927:
   x[len >> 5] |= 0x80 << ((len) % 32);
   x[len >> 5] |= 0x80 << ((len) % 32);
   x[(((len + 64) >>> 9) << 4) + 14] = len;
   x[(((len + 64) >>> 9) << 4) + 14] = len;
 
   var a =  1732584193;
   var a =  1732584193;
   var b = -271733879;
   var b = -271733879;
   var c = -1732584194;
   var c = -1732584194;
   var d =  271733878;
   var d =  271733878;
 
   for(var i = 0; i < x.length; i += 16)
   for(var i = 0; i < x.length; i += 16)
   {
   {
Строка 3016: Строка 2939:
     var oldc = c;
     var oldc = c;
     var oldd = d;
     var oldd = d;
 
     a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
     a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
     d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
     d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
Строка 3033: Строка 2956:
     c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
     c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
     b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
     b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
 
     a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
     a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
     d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
     d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
Строка 3050: Строка 2973:
     c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
     c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
     b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
     b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
 
     a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
     a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
     d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
     d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
Строка 3067: Строка 2990:
     c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
     c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
     b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
     b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
 
     a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
     a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
     d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
     d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
Строка 3084: Строка 3007:
     c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
     c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
     b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
     b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
 
     a = safe_add(a, olda);
     a = safe_add(a, olda);
     b = safe_add(b, oldb);
     b = safe_add(b, oldb);
Строка 3092: Строка 3015:
   return Array(a, b, c, d);
   return Array(a, b, c, d);
}
}
 
/*
/*
  * These functions implement the four basic operations the algorithm uses.
  * These functions implement the four basic operations the algorithm uses.
Строка 3116: Строка 3039:
   return md5_cmn(c ^ (b | (~d)), a, b, 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
  * Add integers, wrapping at 2^32. This uses 16-bit operations internally
Строка 3127: Строка 3050:
   return (msw << 16) | (lsw & 0xFFFF);
   return (msw << 16) | (lsw & 0xFFFF);
}
}
 
/*
/*
  * Bitwise rotate a 32-bit number to the left.
  * Bitwise rotate a 32-bit number to the left.
Строка 3140: Строка 3063:
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// parenSplit
// parenSplit
 
// String.prototype.parenSplit should do what ECMAscript says
// String.prototype.parenSplit should do what ECMAscript says
// String.prototype.split does, interspersing paren matches between
// String.prototype.split does, interspersing paren matches between
// the split elements
// the split elements
 
if (String('abc'.split(/(b)/))!='a,b,c') {
if (String('abc'.split(/(b)/))!='a,b,c') {
// broken String.split, e.g. konq, IE
// broken String.split, e.g. konq, IE
Строка 3170: Строка 3093:
String.prototype.parenSplit.isNative=true;
String.prototype.parenSplit.isNative=true;
}
}
 
function nonGlobalRegex(re) {
function nonGlobalRegex(re) {
var s=re.toString();
var s=re.toString();
Строка 3201: Строка 3124:
//
//
// summat else
// summat else
 
// Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm
// Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm
 
//<NOLITE>
//<NOLITE>
function encode_utf8(rohtext) {
function encode_utf8(rohtext) {
Строка 3228: Строка 3151:
return utftext;
return utftext;
}
}
 
 
function getJsObj(json) {
function getJsObj(json) {
var jsobj;
try {
try {
var json_ret = eval('(' + json + ')');
eval('jsobj='+json);
return jsobj;
} catch (someError) {
} catch (someError) {
errlog('Something went wrong with getJsobj, json='+json);
log('Something went wrong with getJsobj, json='+json);
return 1;
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) {
function anyChild(obj) {
for (var p in obj) {
for (var p in obj) {
Строка 3252: Строка 3170:
return null;
return null;
}
}
 
//</NOLITE>
//</NOLITE>
 
function decode_utf8(utftext) {
function decode_utf8(utftext) {
var plaintext = ""; var i=0, c=0, c1=0, c2=0;
var plaintext = ""; var i=0, c=0, c1=0, c2=0;
Строка 3275: Строка 3193:
return plaintext;
return plaintext;
}
}
 
 
function upcaseFirst(str) {
function upcaseFirst(str) {
if (typeof str != typeof '' || str=='') return '';
if (typeof str != typeof '' || str=='') return '';
return str.charAt(0).toUpperCase() + str.substring(1);
return str.charAt(0).toUpperCase() + str.substring(1);
}
}
 
 
function findInArray(arr, foo) {
function findInArray(arr, foo) {
if (!arr || !arr.length) { return -1; }
if (!arr || !arr.length) { return -1; }
Строка 3289: Строка 3207:
return -1;
return -1;
}
}
 
function nextOne (array, value) {
function nextOne (array, value) {
// NB if the array has two consecutive entries equal
// NB if the array has two consecutive entries equal
Строка 3297: Строка 3215:
return array[i+1];
return array[i+1];
}
}
 
function literalizeRegex(str){
function literalizeRegex(str){
return str.replace(RegExp('([-.|()\\+?*^${}\\[\\]])', 'g'), '\\$1');
return str.replace(RegExp('([-.|()\\+?*^${}\\[\\]])', 'g'), '\\$1');
}
}
 
String.prototype.entify=function() {
String.prototype.entify=function() {
//var shy='&shy;';
//var shy='&shy;';
return this.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;'/*+shy*/).split('"').join('&quot;');
return this.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;'/*+shy*/).split('"').join('&quot;');
};
};
 
function findThis(array, value) {
function findThis(array, value) {
if (typeof array.length == 'undefined') { return null; }
if (typeof array.length == 'undefined') { return null; }
Строка 3314: Строка 3232:
return null;
return null;
}
}
 
function removeNulls(list) {
function removeNulls(list) {
var ret=[];
var ret=[];
Строка 3327: Строка 3245:
return removeNulls(list).join('/');
return removeNulls(list).join('/');
}
}
 
 
function simplePrintf(str, subs) {
function simplePrintf(str, subs) {
if (!str || !subs) { return str; }
if (!str || !subs) { return str; }
Строка 3348: Строка 3266:
return ret.join('');
return ret.join('');
}
}
 
function max(a,b){return a<b ? b : a;}
function max(a,b){return a<b ? b : a;}
function min(a,b){return a>b ? b : a;}
function min(a,b){return a>b ? b : a;}
 
function isString(x) { return (typeof x === 'string' || x instanceof String); }
function isString(x) { return (typeof x === 'string' || x instanceof String); }
//function isNumber(x) { return (typeof x === 'number' || x instanceof Number); }
//function isNumber(x) { return (typeof x === 'number' || x instanceof Number); }
Строка 3360: Строка 3278:
     return !isRegExp(x) && (typeof x === 'function' || x instanceof Function);
     return !isRegExp(x) && (typeof x === 'function' || x instanceof Function);
}
}
 
function repeatString(s,mult) {
function repeatString(s,mult) {
var ret='';
var ret='';
Строка 3366: Строка 3284:
return ret;
return ret;
}
}
 
function zeroFill(s, min) {
function zeroFill(s, min) {
min = min || 2;
min = min || 2;
Строка 3372: Строка 3290:
return repeatString('0', min - t.length) + t;
return repeatString('0', min - t.length) + t;
}
}
 
function map(f, o) {
function map(f, o) {
if (isArray(o)) { return map_array(f,o); }
if (isArray(o)) { return map_array(f,o); }
Строка 3395: Строка 3313:
// Dab-fixing code
// Dab-fixing code
//
//
 
 
function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) {
function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) {
log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget);
log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget);
Строка 3409: Строка 3327:
title: titleToEdit});
title: titleToEdit});
}
}
 
function listLinks(wikitext, oldTarget, titleToEdit) {
function listLinks(wikitext, oldTarget, titleToEdit) {
// mediawiki strips trailing spaces, so we do the same
// mediawiki strips trailing spaces, so we do the same
Строка 3420: Строка 3338:
var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory');
var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory');
var friendlyCurrentArticleName= oldTarget.toString();
var friendlyCurrentArticleName= oldTarget.toString();
var wikPos = getValueOf('popupDabWiktionary');
 
for (var i=1; i<splitted.length; i=i+3) {
for (var i=1; i<splitted.length; i=i+3) {
if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) {
if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) {
Строка 3427: Строка 3344:
} /* if */
} /* if */
} /* for loop */
} /* for loop */
 
ret = rmDupesFromSortedList(ret.sort());
ret = rmDupesFromSortedList(ret.sort());
 
if (wikPos) {
var wikTarget='wiktionary:' + friendlyCurrentArticleName.replace( RegExp('^(.+)\\s+[(][^)]+[)]\\s*$'), '$1' );
var wikTarget='wiktionary:' +
ret.push( retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) );
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(
ret.push(changeLinkTargetLink(
{ newTarget: null,
{ newTarget: null,
Строка 3452: Строка 3361:
return ret;
return ret;
}
}
 
function rmDupesFromSortedList(list) {
function rmDupesFromSortedList(list) {
var ret=[];
var ret=[];
Строка 3460: Строка 3369:
return ret;
return ret;
}
}
 
function makeFixDab(data, navpop) {
function makeFixDab(data, navpop) {
// grab title from parent popup if there is one; default exists in changeLinkTargetLink
// grab title from parent popup if there is one; default exists in changeLinkTargetLink
var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString());
var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString());  
var list=listLinks(data, navpop.originalArticle, titleToEdit);
var list=listLinks(data, navpop.originalArticle, titleToEdit);
if (list.length===0) { log('listLinks returned empty list'); return null; }
if (list.length===0) { log('listLinks returned empty list'); return null; }
Строка 3470: Строка 3379:
return html;
return html;
}
}
 
 
function makeFixDabs(wikiText, navpop) {
function makeFixDabs(wikiText, navpop) {
if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) &&
if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) &&
Строка 3479: Строка 3388:
}
}
}
}
 
function popupRedlinkHTML(article) {
function popupRedlinkHTML(article) {
return changeLinkTargetLink(
return changeLinkTargetLink(
Строка 3491: Строка 3400:
// ENDFILE: dab.js
// ENDFILE: dab.js
// STARTFILE: htmloutput.js
// STARTFILE: htmloutput.js
 
function appendPopupContent(obj, elementId, popupId, onSuccess) {
function appendPopupContent(obj, elementId, popupId, onSuccess) {
return setPopupHTML(obj, elementId, popupId, onSuccess, true);
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
// 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) {
function setPopupHTML (str, elementId, popupId, onSuccess, append) {
Строка 3504: Строка 3413:
popupId = pg.idNumber;
popupId = pg.idNumber;
}
}
 
var popupElement=document.getElementById(elementId+popupId);
var popupElement=document.getElementById(elementId+popupId);
if (popupElement) {
if (popupElement) {
Строка 3524: Строка 3433:
return null;
return null;
}
}
 
//<NOLITE>
//<NOLITE>
function setImageStatus(str, id) {return; } // setPopupHTML(str, 'popupImageStatus', id);}
function setImageStatus(str, id) {return; } // setPopupHTML(str, 'popupImageStatus', id);}
function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);}
function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);}
//</NOLITE>
//</NOLITE>
 
 
function fillEmptySpans(args) { return fillEmptySpans2(args); }
function fillEmptySpans(args) { return fillEmptySpans2(args); }
 
// args.navpopup is mandatory
// args.navpopup is mandatory
// optional: args.redir, args.redirTarget
// optional: args.redir, args.redirTarget
Строка 3540: Строка 3449:
if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; }
if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; }
var a=args.navpopup.parentAnchor;
var a=args.navpopup.parentAnchor;
 
var article, hint=null, oldid=null, params={};
var article, hint=null, oldid=null, params={};
if (redir && typeof args.redirTarget == typeof {}) {
if (redir && typeof args.redirTarget == typeof {}) {
Строка 3553: Строка 3462:
}
}
var x={ article:article, hint: hint, oldid: oldid, rcid: rcid, navpop:args.navpopup, params:params };
var x={ article:article, hint: hint, oldid: oldid, rcid: rcid, navpop:args.navpopup, params:params };
 
var structure=pg.structures[getValueOf('popupStructure')];
var structure=pg.structures[getValueOf('popupStructure')];
if (typeof structure != 'object') {
if (typeof structure != 'object') {
Строка 3563: Строка 3472:
var numspans = spans.length;
var numspans = spans.length;
var redirs=pg.misc.redirSpans;
var redirs=pg.misc.redirSpans;
 
for (var i=0; i<numspans; ++i) {
for (var i=0; i<numspans; ++i) {
var f=findThis(redirs, spans[i]);
var f=findThis(redirs, spans[i]);
Строка 3573: Строка 3482:
var structurefn=structure[spans[i]];
var structurefn=structure[spans[i]];
var setfn = setPopupHTML;
var setfn = setPopupHTML;
if (getValueOf('popupActiveNavlinks') &&  
if (getValueOf('popupActiveNavlinks') && spans[i].indexOf('popupTopLinks')==0) {
    (spans[i].indexOf('popupTopLinks')==0 || spans[i].indexOf('popupRedirTopLinks')==0)
    ) {
setfn = setPopupTipsAndHTML;
setfn = setPopupTipsAndHTML;
}
}
Строка 3592: Строка 3499:
}
}
}
}
 
// flatten an array
// flatten an array
function flatten(list, start) {
function flatten(list, start) {
Строка 3605: Строка 3512:
return ret;
return ret;
}
}
 
// Generate html for whole popup
// Generate html for whole popup
function popupHTML (a) {
function popupHTML (a) {
Строка 3622: Строка 3529:
return makeEmptySpans(pg.misc.layout, a.navpopup);
return makeEmptySpans(pg.misc.layout, a.navpopup);
}
}
 
function makeEmptySpans (list, navpop) {
function makeEmptySpans (list, navpop) {
var ret='';
var ret='';
Строка 3636: Строка 3543:
return ret;
return ret;
}
}
 
 
function emptySpanHTML(name, id, tag, classname) {
function emptySpanHTML(name, id, tag, classname) {
tag = tag || 'span';
tag = tag || 'span';
Строка 3646: Строка 3553:
}
}
emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' };
emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' };
 
// generate html for popup image
// generate html for popup image
// <a id="popupImageLinkn"><img id="popupImagen">
// <a id="popupImageLinkn"><img id="popupImagen">
Строка 3655: Строка 3562:
    '</a>', [ idNumber ]);
    '</a>', [ idNumber ]);
}
}
 
function popTipsSoonFn(id, when, popData) {
function popTipsSoonFn(id, when, popData) {
when || ( when=250 );
when || ( when=250 );
Строка 3661: Строка 3568:
return function() { setTimeout( popTips, when, popData ); };
return function() { setTimeout( popTips, when, popData ); };
}
}
 
function setPopupTipsAndHTML(html, divname, idnumber, popData) {
function setPopupTipsAndHTML(html, divname, idnumber, popData) {
setPopupHTML(html, divname, idnumber,
setPopupHTML(html, divname, idnumber,
Строка 3672: Строка 3579:
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// fuzzy checks
// fuzzy checks
 
function fuzzyCursorOffMenus(x,y, fuzz, parent) {
function fuzzyCursorOffMenus(x,y, fuzz, parent) {
if (!parent) { return null; }
if (!parent) { return null; }
Строка 3683: Строка 3590:
return true;
return true;
}
}
 
function checkPopupPosition () { // stop the popup running off the right of the screen
function checkPopupPosition () { // stop the popup running off the right of the screen
// FIXME avoid pg.current.link
// FIXME avoid pg.current.link
Строка 3689: Строка 3596:
    pg.current.link.navpopup.limitHorizontalPosition();
    pg.current.link.navpopup.limitHorizontalPosition();
}
}
 
function mouseOutWikiLink () {
function mouseOutWikiLink () {
if (!window.popupsReady || !window.popupsReady()) { return; }
if (!window.popupsReady || !window.popupsReady()) { return; }
Строка 3701: Строка 3608:
Navpopup.tracker.addHook(posCheckerHook(a.navpopup));
Navpopup.tracker.addHook(posCheckerHook(a.navpopup));
}
}
 
function posCheckerHook(navpop) {
function posCheckerHook(navpop) {
return function() {
return function() {
Строка 3711: Строка 3618:
var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) ||
var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) ||
    !fuzzyCursorOffMenus(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
// FIXME it'd be prettier to do this internal to the Navpopup objects
var t=getValueOf('popupHideDelay');
var t=getValueOf('popupHideDelay');
Строка 3739: Строка 3646:
};
};
}
}
 
function runStopPopupTimer(navpop) {
function runStopPopupTimer(navpop) {
// at this point, we should have left the link but remain within the popup
// at this point, we should have left the link but remain within the popup
Строка 3755: Строка 3662:
   Defines the {@link Previewmaker} object, which generates short previews from wiki markup.
   Defines the {@link Previewmaker} object, which generates short previews from wiki markup.
*/
*/
 
/**
/**
   Creates a new Previewmaker
   Creates a new Previewmaker
Строка 3868: Строка 3775:
log ('makeRegexp failed');
log ('makeRegexp failed');
}
}
 
log ('makeRegexp: got reStr=' + reStr + ', flags=' + flags);
log ('makeRegexp: got reStr=' + reStr + ', flags=' + flags);
return RegExp(reStr, flags);
return RegExp(reStr, flags);
Строка 3876: Строка 3783:
*/
*/
Previewmaker.prototype.killBoxTemplates = function () {
Previewmaker.prototype.killBoxTemplates = function () {
 
// taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general
// taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general
// also, have float_begin, ... float_end
// also, have float_begin, ... float_end
this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'), /[}][}]\s*/, '{{');
this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'), /[}][}]\s*/, '{{');
 
// infoboxes etc
// infoboxes etc
// from [[User:Zyxw/popups.js]]: kill frames too
// from [[User:Zyxw/popups.js]]: kill frames too
this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{');
this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{');
 
};
};
/**
/**
Строка 3909: Строка 3816:
Previewmaker.prototype.killImages = function () {
Previewmaker.prototype.killImages = function () {
// images and categories are a nono
// images and categories are a nono
this.kill(RegExp('[[][[]\\s*(Image|File|' + pg.ns.image + '|' + pg.ns.category + ')\\s*:', 'i'),
this.kill(RegExp('[[][[]\\s*(' + pg.ns.image + '|' + pg.ns.category + ')\\s*:', 'i'),
  /\]\]\s*/, '[', ']');
  /\]\]\s*/, '[', ']');
};
};
Строка 3918: Строка 3825:
// kill <ref ...>...</ref>
// kill <ref ...>...</ref>
this.kill(/<ref\b.*?>/i, /<\/ref>/i);
this.kill(/<ref\b.*?>/i, /<\/ref>/i);
 
// let's also delete entire lines starting with <. it's worth a try.
// let's also delete entire lines starting with <. it's worth a try.
this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n');
this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n');
 
// and those pesky html tags, but not <nowiki> or <blockquote>
// and those pesky html tags, but not <nowiki> or <blockquote>
var splitted=this.data.parenSplit(/(<.*?>)/);
var splitted=this.data.parenSplit(/(<.*?>)/);
Строка 3954: Строка 3861:
// we simply *can't* be doing with horizontal rules right now
// we simply *can't* be doing with horizontal rules right now
this.data=this.data.replace(RegExp('^-{4,}','mg'),'');
this.data=this.data.replace(RegExp('^-{4,}','mg'),'');
 
// no indented lines
// no indented lines
this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), '');
this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), '');
 
// replace __TOC__, __NOTOC__ and whatever else there is
// replace __TOC__, __NOTOC__ and whatever else there is
// this'll probably do
// this'll probably do
Строка 3969: Строка 3876:
/// first we "normalize" section headings, removing whitespace after, adding before
/// first we "normalize" section headings, removing whitespace after, adding before
var d=this.data;
var d=this.data;
 
if (getValueOf('popupPreviewCutHeadings')) {
if (getValueOf('popupPreviewCutHeadings')) {
this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 ');
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
/// 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('([:;]) *\\n{2,}', 'g'), '$1\n');
 
this.data=this.data.replace(RegExp('^[\\s\\n]*'), '');
this.data=this.data.replace(RegExp('^[\\s\\n]*'), '');
stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data);
stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data);
if (stuff) { d = stuff[0]; }
if (stuff) { d = stuff[0]; }
if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; }
if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; }
 
/// now put \n\n after sections so that bullets and numbered lists work
/// now put \n\n after sections so that bullets and numbered lists work
d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n');
d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n');
}
}
 
 
// superfluous sentences are RIGHT OUT.
// superfluous sentences are RIGHT OUT.
// note: exactly 1 set of parens here needed to make the slice work
// note: exactly 1 set of parens here needed to make the slice work
Строка 3990: Строка 3897:
// leading space is bad, mmkay?
// leading space is bad, mmkay?
d[0]=d[0].replace(RegExp('^\\s*'), '');
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');
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);
d = this.fixSentenceEnds(d, notSentenceEnds);
 
this.fullLength=d.join('').length;
this.fullLength=d.join('').length;
var maxChars=getValueOf('popupMaxPreviewCharacters') + this.extraCharacters;
var maxChars=getValueOf('popupMaxPreviewCharacters') + this.extraCharacters;
var n=this.maxSentences;
var n=this.maxSentences;
var dd=this.firstSentences(d,n);  
var dd=this.firstSentences(d,n);  
 
do {
do {
dd=this.firstSentences(d,n); --n;
dd=this.firstSentences(d,n); --n;
} while ( dd.length > this.maxCharacters && n != 0 );
} while ( dd.length > this.maxCharacters && n != 0 );
 
this.data = dd;
this.data = dd;
};
};
Строка 4011: Строка 3918:
// take an array of strings, strs
// take an array of strings, strs
// join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg
// join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg
 
var abbrevRe=/\b[a-z][^a-z]*$/i;
var abbrevRe=/\b[a-z][^a-z]*$/i;
 
for (var i=0; i<strs.length-2; ++i) {
for (var i=0; i<strs.length-2; ++i) {
if (reg.test(strs[i])) {
if (reg.test(strs[i])) {
Строка 4058: Строка 3965:
*/
*/
Previewmaker.prototype.makePreview = function() {
Previewmaker.prototype.makePreview = function() {
if (this.owner.article.namespace()!=pg.ns.template &&
if (this.owner.article.namespace()!=pg.ns.template) {
this.owner.article.namespace()!=pg.ns.image ) {
this.killComments();
this.killComments();
this.killDivs();
this.killDivs();
this.killGalleries();
this.killGalleries();
this.killBoxTemplates();
this.killBoxTemplates();
 
if (getValueOf('popupPreviewKillTemplates')) {
if (getValueOf('popupPreviewKillTemplates')) {
this.killTemplates();
this.killTemplates();
Строка 4075: Строка 3981:
this.killChunks();
this.killChunks();
this.mopup();
this.mopup();
 
this.firstBit();
this.firstBit();
this.killBadWhitespace();
this.killBadWhitespace();
}
else
{
this.killHTML();
}
}
this.html=wiki2html(this.data, this.baseUrl); // needs livepreview
this.html=wiki2html(this.data, this.baseUrl); // needs livepreview
Строка 4087: Строка 3989:
this.stripLongTemplates();
this.stripLongTemplates();
};
};
/**
 
  @private
*/
Previewmaker.prototype.esWiki2HtmlPart = function(data) {
  var reLinks = /(?:\[\[([^|\]]*)(?:\|([^|\]]*))*]]([a-z]*))/gi; //match a wikilink
  reLinks.lastIndex = 0; //reset regex
  var match;
  var result = "";
  var postfixIndex = 0;
  while ((match = reLinks.exec(data)) != null) //match all wikilinks
  {
    //FIXME: the way that link is built here isn't perfect. It is clickable, but popups preview won't recognize it in some cases.
    result += escapeQuotesHTML(data.substring(postfixIndex, match.index)) +
              "<a href='"+Insta.conf.paths.articles+match[1]+"'>"+escapeQuotesHTML((match[2]?match[2]:match[1])+match[3])+"</a>";
    postfixIndex = reLinks.lastIndex;
  }
  //append the rest
  result += escapeQuotesHTML(data.substring(postfixIndex));
  return result;
};
Previewmaker.prototype.editSummaryPreview=function() {
Previewmaker.prototype.editSummaryPreview=function() {
var reAes  = /\/\* *(.*?) *\*\//g; //match the first section marker
var c=this.data;
reAes.lastIndex = 0; //reset regex
var re=/^\/[*] +(.*?) +[*]\/(.*)/;
if (re.test(c)) {
var match;
var section=c.replace(re, '$1');
match = reAes.exec(this.data);
if (match)
{
//we have a section link. Split it, process it, combine it.
var prefix = this.data.substring(0,match.index-1);
var section = match[1];
var postfix = this.data.substring(reAes.lastIndex);
var start = "<span class='autocomment'>";
var end = "</span>";
if (prefix.length>0) start = this.esWiki2HtmlPart(prefix) + " " + start + "- ";
if (postfix.length>0) end = ": " + end + this.esWiki2HtmlPart(postfix);
var t=new Title().fromURL(this.baseUrl);
var t=new Title().fromURL(this.baseUrl);
t.anchorFromUtf(section);
t.anchorFromUtf(section);
var sectionLink = Insta.conf.paths.articles + t.toString(true).split("'").join('%27') + '#' + t.anchor.split("'").join('%27');
// work around livepreview brokenness with anchors:
return start + "<a href='"+sectionLink+"'>&rarr;</a> "+escapeQuotesHTML(section) + end;
// pass .-escaped anchor instead of literal value
c=c.replace(re, '[[' + t.toString(true).split("'").join('%27') +
    '#' + t.anchor.split("'").join('%27') + '|&rarr;]]' +
    '<span class=autocomment>$1</span>$2');
}
}
this.html=wiki2html(c, this.baseUrl);
//else there's no section link, htmlify the whole thing.
return this.html;
return this.esWiki2HtmlPart(this.data);
};
};
 
//<NOLITE>
//<NOLITE>
/** Test function for debugging preview problems one step at a time.
/** Test function for debugging preview problems one step at a time.
Строка 4160: Строка 4028:
p.killGalleries(); if (!confirm('done killGalleries(). Continue?\n---\n' + p.data)) { return; }
p.killGalleries(); if (!confirm('done killGalleries(). Continue?\n---\n' + p.data)) { return; }
p.killBoxTemplates(); if (!confirm('done killBoxTemplates(). Continue?\n---\n' + p.data)) { return; }
p.killBoxTemplates(); if (!confirm('done killBoxTemplates(). Continue?\n---\n' + p.data)) { return; }
 
if (getValueOf('popupPreviewKillTemplates')) {
if (getValueOf('popupPreviewKillTemplates')) {
p.killTemplates(); if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { return; }
p.killTemplates(); if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { return; }
Строка 4166: Строка 4034:
p.killMultilineTemplates(); if (!confirm('done killMultilineTemplates(). Continue?\n---\n' + p.data)) { return; }
p.killMultilineTemplates(); if (!confirm('done killMultilineTemplates(). Continue?\n---\n' + p.data)) { return; }
}
}
 
p.killTables(); if (!confirm('done killTables(). Continue?\n---\n' + p.data)) { return; }
p.killTables(); if (!confirm('done killTables(). Continue?\n---\n' + p.data)) { return; }
p.killImages(); if (!confirm('done killImages(). Continue?\n---\n' + p.data)) { return; }
p.killImages(); if (!confirm('done killImages(). Continue?\n---\n' + p.data)) { return; }
Строка 4172: Строка 4040:
p.killChunks(); if (!confirm('done killChunks(). Continue?\n---\n' + p.data)) { return; }
p.killChunks(); if (!confirm('done killChunks(). Continue?\n---\n' + p.data)) { return; }
p.mopup(); if (!confirm('done mopup(). Continue?\n---\n' + p.data)) { return; }
p.mopup(); if (!confirm('done mopup(). Continue?\n---\n' + p.data)) { return; }
 
p.firstBit(); if (!confirm('done firstBit(). Continue?\n---\n' + p.data)) { return; }
p.firstBit(); if (!confirm('done firstBit(). Continue?\n---\n' + p.data)) { return; }
p.killBadWhitespace(); if (!confirm('done killBadWhitespace(). Continue?\n---\n' + p.data)) { return; }
p.killBadWhitespace(); if (!confirm('done killBadWhitespace(). Continue?\n---\n' + p.data)) { return; }
}
}
 
p.html=wiki2html(p.data, base); // needs livepreview
p.html=wiki2html(p.data, base); // needs livepreview
p.fixHTML(); if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { return; }
p.fixHTML(); if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { return; }
Строка 4183: Строка 4051:
}
}
//</NOLITE>
//</NOLITE>
 
/**
/**
   Works around a quoting bug in livepreview.
   Works around a quoting bug in livepreview.
Строка 4207: Строка 4075:
/**
/**
   Generates the preview and displays it in the current popup.
   Generates the preview and displays it in the current popup.
 
   Does nothing if the generated preview is invalid or consists of whitespace only.
   Does nothing if the generated preview is invalid or consists of whitespace only.
   Also activates wikilinks in the preview for subpopups if the popupSubpopups option is true.
   Also activates wikilinks in the preview for subpopups if the popupSubpopups option is true.
Строка 4236: Строка 4104:
return a;
return a;
}
}
 
/**
/**
   @private
   @private
Строка 4255: Строка 4123:
// ENDFILE: previewmaker.js
// ENDFILE: previewmaker.js
// STARTFILE: querypreview.js
// STARTFILE: querypreview.js
function loadAPIPreview(queryType, article, navpop) {
//<NOLITE>
function loadQueryPreview(queryType, article, navpop) {
var art=new Title(article).urlString();
var art=new Title(article).urlString();
var url=pg.wiki.wikibase + '/api.php?format=json&action=query&';
var url=pg.wiki.wikibase + '/query.php?format=json&';
var htmlGenerator=function(a,d){alert('invalid html generator');};
var htmlGenerator=function(a,d){alert('invalid html generator');};
switch (queryType) {
switch (queryType) {
case 'history':
case 'history':
url += 'meta=userinfo&uiprop=options&titles=' + art + '&prop=revisions&rvlimit=' +
url += 'titles=' + art + '&what=revisions|userinfo&uioptions=timecorrection&rvcomments&rvlimit=' +
getValueOf('popupHistoryPreviewLimit');
getValueOf('popupHistoryPreviewLimit');
htmlGenerator=APIhistoryPreviewHTML;
htmlGenerator=historyPreviewHTML;
break;
case 'imagelinks':
// redundant case
url += 'titles=' + art + '&what=imagelinks&ilfilter=all';
htmlGenerator=imagelinksPreviewHTML;
break;
break;
case 'category':
case 'category':
url += 'list=categorymembers&cmtitle=' + art;
url += 'what=category&cptitle=' + art;
htmlGenerator=APIcategoryPreviewHTML;
htmlGenerator=categoryPreviewHTML;
break;
case 'userinfo':
var usernameart = encodeURIComponent( new Title( article ).userName() );
url += 'list=users&usprop=blockinfo|groups|editcount|registration&ususers=' + usernameart;
htmlGenerator=APIuserInfoPreviewHTML;
break;
break;
case 'contribs':
case 'contribs':
    var usernameart = encodeURIComponent( new Title( article ).userName() );
url += 'what=usercontribs|userinfo&uioptions=timecorrection&titles=' + art + '&uccomments' +
url += 'list=usercontribs&meta=userinfo&uiprop=options&ucuser=' + usernameart +
'&uclimit=' + getValueOf('popupContribsPreviewLimit');
'&uclimit=' + getValueOf('popupContribsPreviewLimit');
htmlGenerator=APIcontribsPreviewHTML;
htmlGenerator=contribsPreviewHTML;
break;
break;
case 'imagepagepreview':
case 'imagepagepreview':
var trail='';
var trail='&what=imageinfo|content|imagelinks&ilfilter=all';
if (getValueOf('popupImageLinks')) { trail = '&list=imageusage&iutitle=' + art; }
if (!getValueOf('popupImageLinks')) { trail = '&what=imageinfo|content'; }
url += 'titles=' + art + '&prop=revisions|imageinfo&rvprop=content' + trail;
if (pg.wiki.commons) { trail += '&iishared'; }
htmlGenerator=APIimagepagePreviewHTML;
url += 'titles=' + art + trail;
htmlGenerator=imagepagePreviewHTML;
break;
case 'sharedimagepage':
url += 'titles=' + art + '&what=content&proxylang=' + pg.wiki.commonslang;
htmlGenerator=sharedImagePagePreviewHTML;
break;
break;
case 'backlinks':
case 'backlinks':
url += 'list=backlinks&bltitle=' + art;
url += 'what=backlinks&titles=' + art;
htmlGenerator=APIbacklinksPreviewHTML;
htmlGenerator=backlinksPreviewHTML;
break;
break;
}
}
pendingNavpopTask(navpop);
pendingNavpopTask(navpop);
if( !window.wgEnableAPI || !wgEnableAPI ) {
/* The API is not available */
htmlGenerator=function(a,d){
return 'This function of navigation popups now requires a MediaWiki ' +
'installation with the <a href="http://www.mediawiki.org/wiki/API">API</a> enabled.'; };
}
var callback=function(d){
var callback=function(d){
    log( "callback of API functions was hit" );
showQueryPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d);
showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d);
};
};
var go = function(){
var go = function(){
    getPageWithCaching(url, callback, navpop);
getPageWithCaching(url, callback, navpop);
return true;
return true;
}
}
Строка 4309: Строка 4175:
else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_'+queryType+'_QUERY_DATA'); }
else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_'+queryType+'_QUERY_DATA'); }
}
}
 
function linkList(list) {
function showQueryPreview(queryType, html, id, navpop, download) {
list.sort(function(x,y) { return (x==y ? 0 : (x<y ? -1 : 1)); });
var target='popupPreview';
var buf=[];
switch (queryType) {
for (var i=0; i<list.length; ++i) {
case 'imagelinks':
buf.push(wikiLink({article: new Title(list[i]),
case 'category':
  text:   list[i].split(' ').join('&nbsp;'),
target='popupPostPreview'; break;
  action:  'view'}));
case 'sharedimagepage':
target='popupSecondPreview'; break;
}
}
return buf.join(', ');
setPopupTipsAndHTML(html, target, id);
completedNavpopTask(navpop);
}
}
 
function getTimeOffset(tz) {
function backlinksPreviewHTML(article, download, navpop) {
if( tz ) {
var jsObj=getJsObj(download.data);
if( tz.indexOf('|') > -1 ) {
try {
// New format
var page=anyChild(jsObj.pages);
return parseInt(tz.split('|')[1],10);
var list=page.backlinks;
} else if ( tz.indexOf(':') > -1 ) {
} catch (someError) { return 'backlinksPreviewHTML went wonky'; }
// Old format
var html=[];
return( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) );
if (!list) { return popupString('No backlinks found'); }
}
for (var i=0; i<list.length; ++i) {
var t=new Title(list[i]['*']);
html.push('<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t + '</a>');
}
}
return 0;
html=html.join(', ');
if (jsObj.query && jsObj.query.backlinks && jsObj.query.backlinks.next) {
html += popupString(' and more');
}
return html;
}
 
function sharedImagePagePreviewHTML(article, download, navpop) {
var jsObj=getJsObj(download.data);
try {
var page=anyChild(jsObj.pages);
var content=(page && page.content) ? page.content['*'] : null;
} catch (someError) { return 'sharedimagepage preview failed :( is the query.php extension installed?'; }
var ret='';
if (content) {
var p=prepPreviewmaker(content, article, navpop);
p.makePreview();
if (p.html) { ret += '<hr>' + p.html; }
}
return ret;
}
 
 
function imagepagePreviewHTML(article, download, navpop) {
var jsObj=getJsObj(download.data);
try {
var page=anyChild(jsObj['pages']);
var content=(page && page.content) ? page.content['*'] : null;
var a=page.image;
var b=page.sharedimage;
} catch (someError) { return 'imagepage preview failed :( is the query.php extension installed?'; }
var ret='';
if (content) {
var p=prepPreviewmaker(content, article, navpop);
p.makePreview();
if (p.html) { ret += '<hr>' + p.html; }
}
var sharingInfo=getSharingInfo(a,b);
if (sharingInfo) { ret += '<hr>' + sharingInfo; }
if (content!==null && getValueOf('popupSummaryData')) {
var info=getPageInfo(content, download);
log(info);
setPopupTrailer(info, navpop.idNumber);
}
if (!a && b) {
loadQueryPreview('sharedimagepage', article, navpop);
}
showQueryPreview('imagelinks', imagelinksPreviewHTML(article,download), navpop.idNumber, download);
return ret;
}
}
 
function editPreviewTable(article, h, reallyContribs, timeOffset) {
function getSharingInfo(a,b) {
var html=['<table>'];
if (!pg.wiki.commons) { return ''; }
var day=null;
var sharingInfo='';
var curart=article;
if (a && b) {
for (var i=0; i<h.length; ++i) {
if (checkSameImage(a,b)) {
if (reallyContribs) {  
sharingInfo = popupString('commons dupe');
    var page=h[i]['title']; curart = new Title(page);
} else {
sharingInfo = popupString('commons conflict');
}
}
var minor=typeof h[i]['minor']=='undefined' ? '' : '<b>m </b>';
} else if (a && !b) {
var editDate=adjustDate(getDateFromTimestamp(h[i].timestamp), timeOffset);
// nothing interesting
var thisDay = dayFormat(editDate);
if (getValueOf('popupShowNonCommonsImages')) {
var thisTime = timeFormat(editDate);
sharingInfo = popupString('not commons');
if (thisDay==day) { thisDay=''; }
else { day=thisDay; }
if (thisDay) {
html.push( '<tr><td colspan=3><span class="popup_history_date">' +
  thisDay+'</span></td></tr>' );
}
}
html.push('<tr class="popup_history_row_' + ( (i%2) ? 'odd' : 'even') + '">');
} else if (!a && b) {
html.push('<td>(<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
sharingInfo = popupString('commons only');
'&diff=prev&oldid=' + h[i]['revid'] + '">' + popupString('last') + '</a>)</td>');
} else {
html.push('<td>' +
sharingInfo = popupString('No image found');
'<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
}
'&oldid=' + h[i]['revid'] + '">' + thisTime + '</a></td>');
return sharingInfo;
}
 
function checkSameImage(a,b){
return (a['size']==b['size'] && a['width']==b['width'] && a['bits']==b['bits'] &&
a['media']==b['media'] && a['mime']==b['mime']);
}
 
function imagelinksPreviewHTML(article, download) {
var jsobj=getJsObj(download.data);
try {
var list=anyChild(jsobj['pages'])['imagelinks'];
if (!list) { return popupString('No image links found'); }
} catch(someError) { return 'Image links preview generation failed :( Is the query.php extension installed?'; }
var ret=[];
for (var i=0; i<list.length; ++i) { ret.push(list[i]['*']); }
if (ret.length === 0) { return popupString('No image links found'); }
return '<h2>' + popupString('File links') + '</h2>' + linkList(ret);
}
 
function categoryPreviewHTML(article, download) {
var jsobj=getJsObj(download.data);
try{ var list=jsobj['pages']; }
catch(someError) { return 'Category preview failed :( Is the query.php extension installed?'; }
var ret=[];
for (var p in list) { ret.push(list[p]['title']); }
if (ret.length === 0) { return popupString('Empty category'); }
return '<h2>' + tprintf('Category members (%s shown)', [ret.length]) + '</h2>' +linkList(ret);
}
 
function linkList(list) {
list.sort(function(x,y) { return (x==y ? 0 : (x<y ? -1 : 1)); });
var buf=[];
for (var i=0; i<list.length; ++i) {
buf.push(wikiLink({article: new Title(list[i]),
  text:    list[i].split(' ').join('&nbsp;'),
  action:  'view'}));
}
return buf.join(', ');
}
 
function contribsPreviewHTML(article, download, navpop) {
return historyPreviewHTML(article, download, navpop, true);
}
 
function historyPreviewHTML(article, download, navpop, reallyContribs) {
var jsobj=getJsObj(download.data);
try {
var tz=jsobj.meta.user.timecorrection;
var edits=anyChild(jsobj.pages)[reallyContribs ? 'contributions' : 'revisions'];
} catch (someError) {
return 'Preview failed :-( Is the query.php extension installed?';
}
var timeOffset = getTimeOffset(tz);
Cookie.create('popTz', timeOffset, 1);
 
var ret=editPreviewTable(article, edits, reallyContribs, timeOffset);
return ret;
}
 
function getTimeOffset(tz) {
return ( tz && tz.indexOf(':') > -1 ) ? ( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) ) : 0;
}
 
function editPreviewTable(article, h, reallyContribs, timeOffset) {
var html=['<table>'];
var day=null;
var curart=article;
for (var i=0; i<h.length; ++i) {
if (reallyContribs) { var page=h[i]['*']; curart = new Title(page); }
var minor=typeof h[i]['minor']=='undefined' ? '' : '<b>m </b>';
var editDate=adjustDate(getDateFromTimestamp(h[i].timestamp), timeOffset);
var thisDay = dayFormat(editDate);
var thisTime = timeFormat(editDate);
if (thisDay==day) { thisDay=''; }
else { day=thisDay; }
if (thisDay) {
html.push( '<tr><td colspan=3><span class="popup_history_date">' +
  thisDay+'</span></td></tr>' );
}
html.push('<tr class="popup_history_row_' + ( (i%2) ? 'odd' : 'even') + '">');
html.push('<td>(<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
'&diff=prev&oldid=' + h[i]['revid'] + '">' + popupString('last') + '</a>)</td>');
html.push('<td>' +
'<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
'&oldid=' + h[i]['revid'] + '">' + thisTime + '</a></td>');
var col3url='', col3txt='';
var col3url='', col3txt='';
if (!reallyContribs) {
if (!reallyContribs) {
var user=h[i]['user'];
var user=h[i]['user'];
col3url=pg.wiki.titlebase + pg.ns.user + ':' + new Title(user).urlString();
col3url=pg.wiki.titlebase + pg.ns.user + ':' + new Title(user).urlString();
col3txt=escapeQuotesHTML(user);
col3txt=user;
} else {
} else {
col3url=pg.wiki.titlebase + curart.urlString();
col3url=pg.wiki.titlebase + curart.urlString();
col3txt=escapeQuotesHTML(page);
col3txt=page; // FIXME do we have to escape this?
}
}
html.push('<td>' + (reallyContribs ? minor : '') +
html.push('<td>' + (reallyContribs ? minor : '') +
Строка 4381: Строка 4380:
return html.join('');
return html.join('');
}
}
 
function getDateFromTimestamp(t) {
function getDateFromTimestamp(t) {
var s=t.split(/[^0-9]/);
var s=t.split(/[^0-9]/);
Строка 4395: Строка 4394:
}
}
}
}
 
function adjustDate(d, offset) {
function adjustDate(d, offset) {
// offset is in minutes
// offset is in minutes
Строка 4401: Строка 4400:
return new Date( +d + o);
return new Date( +d + o);
}
}
 
function dayFormat(editDate, utc) {
function dayFormat(editDate, utc) {
if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); }
if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); }
return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-');
return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-');
}
}
 
function timeFormat(editDate, utc) {
function timeFormat(editDate, utc) {
if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); }
if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); }
return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':');
return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':');
}
}
 
function showAPIPreview(queryType, html, id, navpop, download) {
//</NOLITE>
    // DJ: done
// ENDFILE: querypreview.js
var target='popupPreview';
// STARTFILE: debug.js
switch (queryType) {
////////////////////////////////////////////////////////////////////
case 'imagelinks':
// Debugging functions
case 'category':
////////////////////////////////////////////////////////////////////
case 'userinfo':
 
target='popupPostPreview'; break;
function log(){}; // dummy to stop errors
}
function setupDebugging() {
setPopupTipsAndHTML(html, target, id);
//<NOLITE>
completedNavpopTask(navpop);
// debugging - change DEBUG to NONE to switch off
}
if (window.popupDebug) { // popupDebug is set from .version
window.log=function(x) { //if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; };
function APIbacklinksPreviewHTML(article, download, navpop) {
if (pg.debugLevel != log.None) { window.logger.debug(x); }
    try {
}
    var jsObj=getJsObj(download.data);
window.errlog=function(x) {
      var list=jsObj.query.backlinks;
if (pg.debugLevel != log.None) { window.logger.error(x); }
} catch (someError) { return 'backlinksPreviewHTML went wonky'; }
var html=[];
if (!list) { return popupString('No backlinks found'); }
for ( i in list ) {
var t=new Title(list[i]['title']);
html.push('<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t + '</a>');
}
html=html.join(', ');
if (jsObj['query-continue'] && jsObj['query-continue'].backlinks && jsObj['query-continue'].backlinks.blcontinue) {
html += popupString(' and more');
}
return html;
}
function APIsharedImagePagePreviewHTML(obj) {
log( "APIsharedImagePagePreviewHTML" );
var popupid = obj['requestid'];
if( obj['query'] && obj['query']['pages'] )
{
var page=anyChild(obj['query']['pages']);
var content=(page && page.revisions ) ? page.revisions[0]['*'] : null;
if( content )
{
/* Not entirely safe, but the best we can do */
var p=new Previewmaker(content, pg.current.link.navpopup.article, pg.current.link.navpopup);
p.makePreview();
setPopupHTML( p.html, "popupSecondPreview", popupid );
}
}
pg.debugLevel=Log.DEBUG;
window.logger = new Log(pg.debugLevel, Log.popupLogger);
log('Initializing logger');
} else {
//</NOLITE>
window.log = function(x) {};
window.errlog = function(x) {};
//<NOLITE>
}
}
//</NOLITE>
}
}
   
// ENDFILE: debug.js
function APIimagepagePreviewHTML(article, download, navpop) {
// STARTFILE: images.js
try {
//<NOLITE>
    var jsObj=getJsObj(download.data);
// FIXME rewrite ALL of this
var page=anyChild(jsObj.query.pages);
// How the URLs for images in the popup come about
var content=(page && page.revisions ) ? page.revisions[0]['*'] : null;
 
} catch (someError) {
//  loadPreview
return 'API imagepage preview failed :(';
//          |
}
//      getWiki
var ret='';
//          |<----------------see other schematic for details
if (content) {
//    insertPreview      (insertPreview = onComplete)
var p=prepPreviewmaker(content, article, navpop);
//          |
p.makePreview();
//          |            insertPreview gets a wikiText fragment from
if (p.html) { ret += '<hr>' + p.html; }
//          |                      the wikiText downloaded by getWiki
}
//          |
if (content!==null && getValueOf('popupSummaryData')) {
// [wikiMarkupToAddressFragment]
var info=getPageInfo(content, download);
//      |
log(info);
//      |                    mouseOverWikiLink  (gets an "address fragment",
setPopupTrailer(info, navpop.idNumber);
//      |                            |            no processing needed)
}
//      \->-*loadThisImage---<----loadImages
if (page && page.imagerepository == "shared" ) {
//                  |
var art=new Title(article).urlString();
//          [image(Thumb)URL]-->--hopefully valid image urls
var shared_url = pg.wiki.commonsbase + '/api.php?format=json&callback=APIsharedImagePagePreviewHTML' +
 
'&requestid=' + navpop.idNumber +
// FIXME get rid of pg.idNumber
'&action=query&prop=revisions&rvprop=content&titles=' + art;
 
ret = ret +'<hr>' + popupString( 'Image from Commons') +
function sequentialLoadThisImage (image) {
': <a href="' + pg.wiki.commonsbase + '/index.php?title=' + art + '">' +
if (!getValueOf('popupImages')) { return false; }
popupString( 'Description page') + '</a>';
if (!isValidImageName(image)) { return false; }
importScriptURI( shared_url );
 
}
var imageUrls=getImageUrls(image);
showAPIPreview('imagelinks', APIimagelinksPreviewHTML(article,download), navpop.idNumber, download);
if (!imageUrls) { return null; }
return ret;
 
}
var img=new Image();
img.isNew=true;
function APIimagelinksPreviewHTML(article, download) {
img.pg.idNumber=pg.idNumber;
try {
img.counter=1;
var jsobj=getJsObj(download.data);
 
var list=jsobj.query.imageusage;
img.onload = function () {
if (!list) { return popupString('No image links found'); }
// clear status thingy
} catch(someError) { return 'Image links preview generation failed :('; }
setImageStatus('');
var ret=[];
 
for (var i=0; i < list.length; i++) {
var i=findThis(imageUrls, this.src);
ret.push(list[i]['title']);
var goodSrc=this.src;
}
 
if (ret.length === 0) { return popupString('No image links found'); }
var setPopupImage=function () {
return '<h2>' + popupString('File links') + '</h2>' + linkList(ret);
var popupImage=document.getElementById("popupImage"+this.pg.idNumber);
}
if (popupImage && typeof popupImage.src != 'undefined') {
clearInterval(pg.timer.image);
function APIcategoryPreviewHTML(article, download) {
popupImage.src=goodSrc;
    try{
popupImage.width=getValueOf('popupImageSize');
        var jsobj=getJsObj(download.data);
popupImage.style.display='inline';
        var list=jsobj.query.categorymembers;
setPopupImageLink(image, pg.wiki.imageSources[i].wiki);
    } catch(someError) { return 'Category preview failed :('; }
return true;
var ret=[];
} else { return false; }
for (var p=0; p < list.length; p++) {
};
  ret.push(list[p]['title']);  
pg.timer.image=setInterval(setPopupImage, 250);
}
pg.cache.images.push(goodSrc);
if (ret.length === 0) { return popupString('Empty category'); }
};
ret = '<h2>' + tprintf('Category members (%s shown)', [ret.length]) + '</h2>' +linkList(ret);
 
if (jsobj['query-continue'] && jsobj['query-continue'].categorymembers && jsobj['query-continue'].categorymembers.cmcontinue) {
img.onerror = function () {
ret += popupString(' and more');
pg.cache.badImageUrls.push(this.src);
}
};
return ret;
 
}
img.setNext = function () {
   
var currentSrc=null;
function APIuserInfoPreviewHTML(article, download) {
var newSrc;
try{
if (!this.isNew) { currentSrc=this.src; }
var jsobj=getJsObj(download.data);
this.isNew=false;
var user=anyChild(jsobj.query.users);
 
} catch(someError) { return 'Userinfo preview failed :('; }
newSrc= (currentSrc) ? nextOne(imageUrls, currentSrc) : imageUrls[0];
if (!user || user.invalid == '') {
 
return '<hr>' + popupString( 'Invalid or IP user');
while (findThis(pg.cache.badImageUrls, newSrc))  {
} else if (user.missing == '') {
newSrc=nextOne(imageUrls, newSrc);
return '<hr>' + popupString( 'Not a registered username');
if (!newSrc) {
}
setImageStatus (' :-(');
var ret=[];
return;
if( user.blockedby )
}
ret.push('<b>' + popupString('BLOCKED') + '</b>');
}
for( var i=0; (user.groups && i < user.groups.length); i++)
setImageStatus(' '+findThis(imageUrls, newSrc));
{
this.src=newSrc;
ret.push( user.groups[i] );
};
}
 
if( user.editcount || user.registration )
// start the ball rolling
ret.push( (user.editcount?user.editcount:'') + popupString(' edits since: ') + (user.registration?dayFormat(getDateFromTimestamp(user.registration)):'') );
img.setNext();
ret = '<hr>' + ret.join( ', ' );
 
return ret;
}
}
 
function APIcontribsPreviewHTML(article, download, navpop) {
function loadThisImageAtThisUrl(image, url) {
    return APIhistoryPreviewHTML(article, download, navpop, true);
log('loading "best" image:\n'+url);
}
pg.misc.gImage=new Title(image.toString());
pg.misc.imageArray = [];
function APIhistoryPreviewHTML(article, download, navpop, reallyContribs) {
pg.misc.imageArray[0] = new Image();
    try {
pg.misc.imageArray[0].src=url;
var jsobj=getJsObj(download.data);
if (pg.timer.image || pg.timer.image===0) {
var tz=jsobj.query.userinfo.options.timecorrection;
clearInterval(pg.timer.image);
if( reallyContribs )
pg.counter.checkImages=0;
    var edits=jsobj.query.usercontribs;
else
    var edits=anyChild(jsobj.query.pages)['revisions'];
} catch (someError) {
return 'History preview failed :-(';
}
var timeOffset = getTimeOffset(tz);
Cookie.create('popTz', timeOffset, 1);
var ret=editPreviewTable(article, edits, reallyContribs, timeOffset);
return ret;
}
//</NOLITE>
// ENDFILE: querypreview.js
// STARTFILE: debug.js
////////////////////////////////////////////////////////////////////
// Debugging functions
////////////////////////////////////////////////////////////////////
function log(){}; // dummy to stop errors
function setupDebugging() {
//<NOLITE>
if (window.popupDebug) { // popupDebug is set from .version
window.log=function(x) { //if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; };
window.console.log(x);
}
window.errlog=function(x) {
window.console.error(x);
}
log('Initializing logger');
} else {
//</NOLITE>
window.log = function(x) {};
window.errlog = function(x) {};
//<NOLITE>
}
}
//</NOLITE>
pg.timer.image=setInterval(checkImages, 250);
return;
}
}
// ENDFILE: debug.js
 
// STARTFILE: images.js
// methinks this is unbelievably silly
//<NOLITE>
// it dovetails with the parallel image loader function
// FIXME rewrite ALL of this
function checkImages() {
// How the URLs for images in the popup come about
//log('checkImages: pg.counter.loop='+pg.counter.loop+'; pg.counter.checkImages='+pg.counter.checkImages);
if (pg.timer.checkImages || pg.timer.checkImages===0) {
//  loadPreview
clearInterval(pg.timer.checkImages);
//          |
pg.timer.checkImages=null;
//      getWiki
if (pg.counter.loop > 10) {pg.counter.loop=0; log('too many iterations of checkImages'); return;}
//          |<----------------see other schematic for details
pg.counter.loop++;
//   insertPreview      (insertPreview = onComplete)
} else pg.counter.checkImages++;
//          |
 
//          |            insertPreview gets a wikiText fragment from
var status = ( pg.counter.checkImages % 2 ) ? ':' : '.' ;
//          |                      the wikiText downloaded by getWiki
setImageStatus(status);
//          |
 
//  [wikiMarkupToAddressFragment]
if (pg.counter.checkImages > 100) {
//      |
pg.counter.checkImages = 0;
//      |                    mouseOverWikiLink  (gets an "address fragment",
log ('pg.counter.checkImages too big in checkImages; returning');
//      |                           |           no processing needed)
clearInterval(pg.timer.image);
//      \->-*loadThisImage---<----loadImages
}
//                  |
 
//          [image(Thumb)URL]-->--hopefully valid image urls
var popupImage=null;
popupImage=document.getElementById("popupImg"+pg.idNumber);
// FIXME get rid of pg.idNumber
if (popupImage == null) {
// this doesn't seem to happen any more in practise for some reason
function sequentialLoadThisImage (image) {
// still, I'll leave it in
if (!getValueOf('popupImages')) { return false; }
log('checkImages: document.getElementById("popupImg'+pg.idNumber+'") is null! retrying in 333ms...');
if (!isValidImageName(image)) { return false; }
pg.timer.checkImages=setInterval("checkImages()",333);
return;
var imageUrls=getImageUrls(image);
}
if (!imageUrls) { return null; }
 
log('checkImages: found element popupImg'+pg.idNumber+', and src='+popupImage.src);
var img=new Image();
 
img.isNew=true;
// get the first image to successfully load
img.pg.idNumber=pg.idNumber;
// and put it in the popupImage
img.counter=1;
for(var i = 0; i < pg.misc.imageArray.length; ++i) {
if(isImageOk(pg.misc.imageArray[i])) {
img.onload = function () {
// stop all the gubbins, assign the image and return
// clear status thingy
 
setImageStatus('');
log('checkImages: got at pos '+i+', src='+pg.misc.imageArray[i].src);
clearInterval(pg.timer.image);
var i=findThis(imageUrls, this.src);
 
var goodSrc=this.src;
if(pg.misc.gImage && pg.misc.gImage.namespace() == pg.ns.image) {
popupImage.src=pg.misc.imageArray[i].src;
var setPopupImage=function () {
popupImage.width=getValueOf('popupImageSize');
var popupImage=document.getElementById("popupImage"+this.pg.idNumber);
popupImage.style.display='inline';
if (popupImage && typeof popupImage.src != 'undefined') {
// should we check to see if it's already there? maybe...
clearInterval(pg.timer.image);
pg.cache.images.push(pg.misc.imageArray[i].src);
popupImage.src=goodSrc;
 
popupImage.width=getValueOf('popupImageSize');
setPopupImageLink(pg.misc.gImage, pg.wiki.imageSources[i].wiki);
popupImage.style.display='inline';
stopImagesDownloading();
setPopupImageLink(image, pg.wiki.imageSources[i].wiki);
return true;
} else { return false; }
};
pg.timer.image=setInterval(setPopupImage, 250);
pg.cache.images.push(goodSrc);
};
img.onerror = function () {
pg.cache.badImageUrls.push(this.src);
};
img.setNext = function () {
var currentSrc=null;
var newSrc;
if (!this.isNew) { currentSrc=this.src; }
this.isNew=false;
newSrc= (currentSrc) ? nextOne(imageUrls, currentSrc) : imageUrls[0];
while (findThis(pg.cache.badImageUrls, newSrc))  {
newSrc=nextOne(imageUrls, newSrc);
if (!newSrc) {
setImageStatus (' :-(');
return;
}
}
setImageStatus('');
// reset evil nonconstant globals
delete pg.misc.imageArray; pg.misc.imageArray=[];
pg.timer.image=null;
pg.counter.checkImages=0;
pg.counter.loop=0;
return popupImage.src;
}
}
setImageStatus(' '+findThis(imageUrls, newSrc));
}
this.src=newSrc;
log('checkImages: no good image found. retrying in a tic...');
};
pg.timer.checkImages=setInterval("checkImages()",333);
// start the ball rolling
img.setNext();
}
}
 
function loadThisImageAtThisUrl(image, url) {
function stopImagesDownloading() {
log('loading "best" image:\n'+url);
pg.misc.gImage=null;
pg.misc.gImage=new Title(image.toString());
if (pg.misc.imageArray == null) { return null; }
for (var i=0; i<pg.misc.imageArray.length; ++i) {
//pg.misc.imageArray[i].src=''; // this is a REALLY BAD IDEA
delete pg.misc.imageArray[i];
//pg.misc.imageArray[i] = new Image();
}
pg.misc.imageArray = [];
pg.misc.imageArray = [];
pg.misc.imageArray[0] = new Image();
}
pg.misc.imageArray[0].src=url;
 
if (pg.timer.image || pg.timer.image===0) {
function toggleSize() {
clearInterval(pg.timer.image);
var imgContainer=this;
pg.counter.checkImages=0;
if (!imgContainer) { alert('imgContainer is null :/'); return;}
img=imgContainer.firstChild;
if (!img) { alert('img is null :/'); return;}
if (!img.style.width || img.style.width=='') { img.style.width='100%'; }
else { img.style.width=''; }
}
 
function setPopupImageLink (img, wiki) {
if( wiki === null || img === null ) { return null; }
 
var a=document.getElementById("popupImageLink"+pg.idNumber);
if (a === null) { return null; }
 
switch (getValueOf('popupThumbAction')) {
case 'imagepage':
if (pg.current.article.namespace()!=pg.ns.image) {
a.href=pg.wiki.titlebase + img.urlString();
// FIXME: unreliable pg.idNumber
popTipsSoonFn('popupImage' + pg.idNumber)();
break;
} // else fall through
case 'sizetoggle':
a.onclick=toggleSize;
a.title=popupString('Toggle image size');
return;
case 'linkfull':
var linkURL = imageURL(img, wiki);
if (linkURL) {
a.href = linkURL;
a.title=popupString('Open full-size image');
}
return;
}
}
pg.timer.image=setInterval(checkImages, 250);
return;
}
}
 
// methinks this is unbelievably silly
function isImageOk(img) {
// it dovetails with the parallel image loader function
// IE test
function checkImages() {
if (!img.complete) { return false; }
//log('checkImages: pg.counter.loop='+pg.counter.loop+'; pg.counter.checkImages='+pg.counter.checkImages);
 
if (pg.timer.checkImages || pg.timer.checkImages===0) {
// gecko test
clearInterval(pg.timer.checkImages);
if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) { return false; }
pg.timer.checkImages=null;
 
if (pg.counter.loop > 10) {pg.counter.loop=0; log('too many iterations of checkImages'); return;}
// test for konqueror and opera
pg.counter.loop++;
 
} else pg.counter.checkImages++;
// note that img.width must not be defined in the html with a width="..."
// for this to work.
var status =  ( pg.counter.checkImages % 2 ) ? ':' : '.' ;
 
setImageStatus(status);
// konq seems to give "broken images" width 16, presumably an icon width
// this test would probably work in gecko too, *except for very small images*
if (pg.counter.checkImages > 100) {
if (typeof img.width == 'undefined' || img.width <= 16) { return false; }
pg.counter.checkImages = 0;
 
log ('pg.counter.checkImages too big in checkImages; returning');
// No other way of checking: assume it's ok.
clearInterval(pg.timer.image);
return true;
}
 
// those odd a/a5/ bits of image urls
function imagePathComponent(article) { // article is string, no namespace
// FIXME needs testing with odd characters
var forhash=article.split(' ').join('_');
var hash=hex_md5(forhash);
return hash.substring(0,1) + '/' + hash.substring(0,2) + '/';
}
 
function getImageUrlStart(wiki) { // this returns a trailing slash
switch (wiki) {
case 'en.wikipedia.org'return 'http://upload.wikimedia.org/wikipedia/en/';
case pg.wiki.commons:    return 'http://upload.wikimedia.org/wikipedia/commons/';
case 'en.wiktionary.org': return 'http://en.wiktionary.org/upload/en/';
case 'secure.wikimedia.org':
    return joinPath(['http://upload.wikimedia.org', pg.wiki.prePath]) + '/'; break;
default: // unsupported - take a guess
if (pg.wiki.wikimedia) {
return 'http://upload.wikimedia.org/wikipedia/' + pg.wiki.lang +'/';
}
/* this should work for wikicities */
return 'http://' + wiki + '/images/';
}
}
var popupImage=null;
popupImage=document.getElementById("popupImg"+pg.idNumber);
if (popupImage == null) {
// this doesn't seem to happen any more in practise for some reason
// still, I'll leave it in
log('checkImages: document.getElementById("popupImg'+pg.idNumber+'") is null! retrying in 333ms...');
pg.timer.checkImages=setInterval("checkImages()",333);
return;
}
log('checkImages: found element popupImg'+pg.idNumber+', and src='+popupImage.src);
// get the first image to successfully load
// and put it in the popupImage
for(var i = 0; i < pg.misc.imageArray.length; ++i) {
if(isImageOk(pg.misc.imageArray[i])) {
// stop all the gubbins, assign the image and return
log('checkImages: got at pos '+i+', src='+pg.misc.imageArray[i].src);
clearInterval(pg.timer.image);
if(pg.misc.gImage && pg.misc.gImage.namespace() == pg.ns.image) {
popupImage.src=pg.misc.imageArray[i].src;
popupImage.width=getValueOf('popupImageSize');
popupImage.style.display='inline';
// should we check to see if it's already there? maybe...
pg.cache.images.push(pg.misc.imageArray[i].src);
setPopupImageLink(pg.misc.gImage, pg.wiki.imageSources[i].wiki);
stopImagesDownloading();
}
setImageStatus('');
// reset evil nonconstant globals
delete pg.misc.imageArray; pg.misc.imageArray=[];
pg.timer.image=null;
pg.counter.checkImages=0;
pg.counter.loop=0;
return popupImage.src;
}
}
log('checkImages: no good image found. retrying in a tic...');
pg.timer.checkImages=setInterval("checkImages()",333);
}
}
 
function stopImagesDownloading() {
function imageURL(img, wiki) {
pg.misc.gImage=null;
if (getValueOf('popupImagesFromThisWikiOnly') && wiki != pg.wiki.hostname) return null;
if (pg.misc.imageArray == null) { return null; }
var imgurl=null;
for (var i=0; i<pg.misc.imageArray.length; ++i) {
var pathcpt = imagePathComponent(img.stripNamespace());
//pg.misc.imageArray[i].src=''; // this is a REALLY BAD IDEA
imgurl=getImageUrlStart(wiki) + pathcpt + img.stripNamespace().split(' ').join('_');
delete pg.misc.imageArray[i];
return imgurl;
//pg.misc.imageArray[i] = new Image();
}
 
function imageThumbURL(img, wiki, width) {
//
// eg http://upload.wikimedia.org/wikipedia/en/thumb/6/61/
//          Rubiks_cube_solved.jpg/120px-Rubiks_cube_solved.jpg
//          ^^^^^^^^^^^^^^^^^^^^^^^
//          wikicities omits this bit
//  AND wikicities needs a new pathcpt for each filename including thumbs
 
if (getValueOf('popupImagesFromThisWikiOnly') && wiki != pg.wiki.hostname) return null;
if (getValueOf('popupNeverGetThumbs')) return null;
 
var imgurl=null;
var stripped=img.stripNamespace();
var pathcpt;
if (pg.wiki.wikimedia) pathcpt = imagePathComponent(stripped);
else pathcpt = imagePathComponent(width+'px-'+stripped);
imgurl=getImageUrlStart(wiki) +  "thumb/" + pathcpt;
if (pg.wiki.wikimedia) imgurl += stripped + '/';
imgurl += width +"px-" + stripped;
return imgurl;
}
 
function loadImages(image) {
if (typeof image.stripNamespace != 'function') { alert('loadImages bad'); }
if (getValueOf('popupLoadImagesSequentially')) { return sequentialLoadThisImage(image); }
return parallelLoadThisImage(image);
}
 
function getImageUrls(image) {
if (typeof image.stripNamespace != 'function') { alert('getImageUrls bad'); }
var imageUrls=[];
for (var i=0; i<pg.wiki.imageSources.length; ++i) {
var url;
if (pg.wiki.imageSources[i].thumb) {
url=imageThumbURL(image, pg.wiki.imageSources[i].wiki, pg.wiki.imageSources[i].width);
} else { url=imageURL(image, pg.wiki.imageSources[i].wiki); }
for (var j=0; j<pg.cache.images.length; ++j) {
if (url == pg.cache.images[j]) {
loadThisImageAtThisUrl(image, url);
return null;
}
}
if (url!=null) imageUrls.push(url);
}
}
pg.misc.imageArray = [];
return imageUrls;
}
}
 
function toggleSize() {
 
var imgContainer=this;
// this is probably very wasteful indeed of bandwidth
if (!imgContainer) { alert('imgContainer is null :/'); return;}
// hey ho
img=imgContainer.firstChild;
 
if (!img) { alert('img is null :/'); return;}
function parallelLoadThisImage (image) {
if (!img.style.width || img.style.width=='') { img.style.width='100%'; }
if (typeof image.stripNamespace != 'function') { alert('parallelLoadThisImage bad'); }
else { img.style.width=''; }
if (!getValueOf('popupImages')) return;
}
if (!isValidImageName(image)) return false;
 
function setPopupImageLink (img, wiki) {
var imageUrls=getImageUrls(image);
if( wiki === null || img === null ) { return null; }
if (!imageUrls) return null;
 
var a=document.getElementById("popupImageLink"+pg.idNumber);
for (var i=0; i<imageUrls.length; ++i) {
if (a === null) { return null; }
var url = imageUrls[i];
pg.misc.imageArray[i]=new Image();
switch (getValueOf('popupThumbAction')) {
pg.misc.imageArray[i].src=url;
case 'imagepage':
}
if (pg.current.article.namespace()!=pg.ns.image) {
if (pg.timer.image != null) {
a.href=pg.wiki.titlebase + img.urlString();
clearInterval(pg.timer.image);
// FIXME: unreliable pg.idNumber
pg.counter.checkImages=0;
popTipsSoonFn('popupImage' + pg.idNumber)();
break;
} // else fall through
case 'sizetoggle':
a.onclick=toggleSize;
a.title=popupString('Toggle image size');
return;
case 'linkfull':
var linkURL = imageURL(img, wiki);
if (linkURL) {
a.href = linkURL;
a.title=popupString('Open full-size image');
}
return;
}
}
}
pg.misc.gImage=new Title(image.toString());
pg.timer.image=setInterval("checkImages()", 250);
function isImageOk(img) {
// IE test
if (!img.complete) { return false; }
// gecko test
if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) { return false; }
// test for konqueror and opera
// note that img.width must not be defined in the html with a width="..."
// for this to work.
// konq seems to give "broken images" width 16, presumably an icon width
// this test would probably work in gecko too, *except for very small images*
if (typeof img.width == 'undefined' || img.width <=  16) { return false; }
// No other way of checking: assume it's ok.
return true;
return true;
}
}
 
// those odd a/a5/ bits of image urls
function getValidImageFromWikiText(wikiText) {
function imagePathComponent(article) { // article is string, no namespace
var imagePage=null;
// FIXME needs testing with odd characters
// nb in pg.re.image we're interested in the second bracketed expression
var forhash=article.split(' ').join('_');
// this may change if the regex changes :-(
var hash=hex_md5(forhash);
//var match=pg.re.image.exec(wikiText);
return hash.substring(0,1) + '/' + hash.substring(0,2) + '/';
var matched=null;
}
var match;
// strip html comments, used by evil bots :-(
function getImageUrlStart(wiki) { // this returns a trailing slash
var t = removeMatchesUnless(wikiText, RegExp('(<!--[\\s\\S]*?-->)'), 1,
switch (wiki) {
    RegExp('^<!--[^[]*popup', 'i'));
case 'en.wikipedia.org':  return 'http://upload.wikimedia.org/wikipedia/en/';
 
case pg.wiki.commons:    return 'http://upload.wikimedia.org/wikipedia/commons/';
while ( match = pg.re.image.exec(t) ) {
case 'en.wiktionary.org': return 'http://en.wiktionary.org/upload/en/';
// now find a sane image name - exclude templates by seeking {
case 'secure.wikimedia.org':
var m = match[2] || match[6];
    return joinPath(['http://upload.wikimedia.org', pg.wiki.prePath]) + '/'; break;
var pxWidth=match[4];
default: // unsupported - take a guess
if ( isValidImageName(m) &&
if (pg.wiki.wikimedia) {
    (!pxWidth || parseInt(pxWidth,10) >= getValueOf('popupMinImageWidth')) ) {
return 'http://upload.wikimedia.org/wikipedia/' + pg.wiki.lang +'/';
matched=m;
break;
}
}
/* this should work for wikicities */
return 'http://' + wiki + '/images/';
}
}
pg.re.image.lastIndex=0;
if (!matched) { return null; }
return pg.ns.image+':'+upcaseFirst(matched);
}
}
 
function imageURL(img, wiki) {
function removeMatchesUnless(str, re1, parencount, re2) {
if (getValueOf('popupImagesFromThisWikiOnly') && wiki != pg.wiki.hostname) return null;
    var split=str.parenSplit(re1);
var imgurl=null;
    var c=parencount + 1;
var pathcpt = imagePathComponent(img.stripNamespace());
    for (var i=0; i<split.length; ++i) {
imgurl=getImageUrlStart(wiki) + pathcpt + img.stripNamespace().split(' ').join('_');
if ( i%c === 0 || re2.test(split[i]) ) { continue; }
return imgurl;
split[i]='';
    }
    return split.join('');
}
}
 
function imageThumbURL(img, wiki, width) {
//</NOLITE>
//
// ENDFILE: images.js
// eg http://upload.wikimedia.org/wikipedia/en/thumb/6/61/
// STARTFILE: namespaces.js
//           Rubiks_cube_solved.jpg/120px-Rubiks_cube_solved.jpg
// Set up namespaces and other non-strings.js localization
//           ^^^^^^^^^^^^^^^^^^^^^^^
// (currently that means redirs too)
//          wikicities omits this bit
 
// AND wikicities needs a new pathcpt for each filename including thumbs
// Put the right namespace list into pg.ns.list, based on pg.wiki.lang
// Default to english if nothing seems to fit
if (getValueOf('popupImagesFromThisWikiOnly') && wiki != pg.wiki.hostname) return null;
function setNamespaceList() {
if (getValueOf('popupNeverGetThumbs')) return null;
var m="Media";
var list = [m, "Special", "Talk", "User", "User talk", "Wikipedia", "Wikipedia talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk", "Portal", "Portal talk"];
var imgurl=null;
var nsIndex = { '': 0, 'Special': 1,
var stripped=img.stripNamespace();
'Talk': 2, 'User': 3, 'User talk': 4, 'Wikipedia': 5,
var pathcpt;
'Wikipedia talk': 6, 'Image': 7, 'Image talk': 8, 'MediaWiki': 9,
if (pg.wiki.wikimedia) pathcpt = imagePathComponent(stripped);
'MediaWiki talk': 10, 'Template': 11, 'Template talk': 12,
else pathcpt = imagePathComponent(width+'px-'+stripped);
'Help': 13, 'Help talk': 14, 'Category': 15, 'Category talk':16,
imgurl=getImageUrlStart(wiki) +  "thumb/" + pathcpt;
'Portal': 17, 'Portal talk': 18};
if (pg.wiki.wikimedia) imgurl += stripped + '/';
var nsLists = {
imgurl += width +"px-" + stripped;
//<NOLITE>
return imgurl;
"af": [m, "Spesiaal", "Bespreking", "Gebruiker", "Gebruikerbespreking", "Wikipedia", "Wikipediabespreking", "Beeld", "Beeldbespreking", "MediaWiki", "MediaWikibespreking", "Sjabloon", "Sjabloonbespreking", "Hulp", "Hulpbespreking", "Kategorie", "Kategoriebespreking"],
}
"als": [m, "Spezial", "Diskussion", "Benutzer", "Benutzer Diskussion", "Wikipedia", "Wikipedia Diskussion", "Bild", "Bild Diskussion", "MediaWiki", "MediaWiki Diskussion", "Vorlage", "Vorlage Diskussion", "Hilfe", "Hilfe Diskussion", "Kategorie", "Kategorie Diskussion"],
"ar": ["ملف", "خاص", "نقاش", "مستخدم", "نقاش المستخدم", "ويكيبيديا", "نقاش ويكيبيديا", "صورة", "نقاش الصورة", "ميدياويكي", "نقاش ميدياويكي", "Template", "نقاش Template", "مساعدة", "نقاش المساعدة", "تصنيف", "نقاش التصنيف"],
function loadImages(image) {
"ast": [m, "Especial", "Discusión", "Usuariu", "Usuariu discusión", "Uiquipedia", "Uiquipedia discusión", "Imaxen", "Imaxen discusión", "MediaWiki", "MediaWiki discusión", "Plantilla", "Plantilla discusión", "Ayuda", "Ayuda discusión", "Categoría", "Categoría discusión"],
if (typeof image.stripNamespace != 'function') { alert('loadImages bad'); }
"be": ["Мэдыя", "Спэцыяльныя", "Абмеркаваньне", "Удзельнік", "Гутаркі ўдзельніка", "Вікіпэдыя", "Абмеркаваньне Вікіпэдыя", "Выява", "Абмеркаваньне выявы", "MediaWiki", "Абмеркаваньне MediaWiki", "Шаблён", "Абмеркаваньне шаблёну", "Дапамога", "Абмеркаваньне дапамогі", "Катэгорыя", "Абмеркаваньне катэгорыі"],
if (getValueOf('popupLoadImagesSequentially')) { return sequentialLoadThisImage(image); }
"bg": ["Медия", "Специални", "Беседа", "Потребител", "Потребител беседа", "Уикипедия", "Уикипедия беседа", "Картинка", "Картинка беседа", "МедияУики", "МедияУики беседа", "Шаблон", "Шаблон беседа", "Помощ", "Помощ беседа", "Категория", "Категория беседа"],
return parallelLoadThisImage(image);
"bm": [m, "Special", "Discuter", "Utilisateur", "Discussion Utilisateur", "Wikipedia", "Discussion Wikipedia", "Image", "Discussion Image", "MediaWiki", "Discussion MediaWiki", "Modèle", "Discussion Modèle", "Aide", "Discussion Aide", "Catégorie", "Discussion Catégorie"],
}
"bn": ["বিশেষ", "আলাপ", "ব্যবহারকারী", "ব্যবহারকারী আলাপ", "উইকিপেডিয়া", "উইকিপেডিয়া আলাপ", "চিত্র", "চিত্র আলাপ", "MediaWik i আলাপ", m, "MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"br": [m, "Dibar", "Kaozeal", "Implijer", "Kaozeadenn Implijer", "Wikipedia", "Kaozeadenn Wikipedia", "Skeudenn", "Kaozeadenn Skeudenn", "MediaWiki", "Kaozeadenn MediaWiki", "Patrom", "Kaozeadenn Patrom", "Skoazell", "Kaozeadenn Skoazell", "Rummad", "Kaozeadenn Rummad"],
function getImageUrls(image) {
"ca": [m, "Especial", "Discussió", "Usuari", "Usuari Discussió", "Viquipèdia", "Viquipèdia Discussió", "Imatge", "Imatge Discussió", "MediaWiki", "MediaWiki Discussió", "Template", "Template Discussió", "Ajuda", "Ajuda Discussió", "Categoria", "Categoria Discussió"],
if (typeof image.stripNamespace != 'function') { alert('getImageUrls bad'); }
"cs": ["Média", "Speciální", "Diskuse", "Wikipedista", "Wikipedista diskuse", "Wikipedie", "Wikipedie diskuse", "Soubor", "Soubor diskuse", "MediaWiki", "MediaWiki diskuse", "Šablona", "Šablona diskuse", "Nápověda", "Nápověda diskuse", "Kategorie", "Kategorie diskuse"],
var imageUrls=[];
"csb": [m, "Specjalnô", "Diskùsëjô", "Brëkòwnik", "Diskùsëjô brëkòwnika", "Wiki", "Diskùsëjô Wiki", "Òbrôzk", "Diskùsëjô òbrôzków", "MediaWiki", "Diskùsëjô MediaWiki", "Szablóna", "Diskùsëjô Szablónë", "Pòmòc", "Diskùsëjô Pòmòcë", "Kategòrëjô", "Diskùsëjô Kategòrëji"],
for (var i=0; i<pg.wiki.imageSources.length; ++i) {
"cv": ["Медиа", "Ятарлă", "Сӳтсе явасси", "Хутшăнакан", "Хутшăнаканăн канашлу страници", "Wikipedia", "0", "Ӳкерчĕк", "Ӳкерчĕке сӳтсе явмалли", "MediaWiki", "MediaWiki сӳтсе явмалли", "Шаблон", "Шаблона сӳтсе явмалли", "Пулăшу", "Пулăшăва сӳтсе явмалли", "Категори", "Категорине сӳтсе явмалли"],
var url;
"cy": [m, "Arbennig", "Sgwrs", "Defnyddiwr", "Sgwrs Defnyddiwr", "Wicipedia", "Sgwrs Wicipedia", "Delwedd", "Sgwrs Delwedd", "MediaWiki", "Sgwrs MediaWiki", "Nodyn", "Sgwrs Nodyn", "Help", "Help talk", "Category", "Category talk"],
if (pg.wiki.imageSources[i].thumb) {
"da": [m, "Speciel", "Diskussion", "Bruger", "Brugerdiskussion", "Wikipedia", "Wikipedia-diskussion", "Billede", "Billeddiskussion", "MediaWiki", "MediaWiki-diskussion", "Skabelon", "Skabelondiskussion", "Hjælp", "Hjælpdiskussion", "Kategori", "Kategoridiskussion", "Portal", "Portaldiskussion"],
url=imageThumbURL(image, pg.wiki.imageSources[i].wiki, pg.wiki.imageSources[i].width);
"de": [m, "Spezial", "Diskussion", "Benutzer", "Benutzer Diskussion", "Wikipedia", "Wikipedia Diskussion", "Bild", "Bild Diskussion", "MediaWiki", "MediaWiki Diskussion", "Vorlage", "Vorlage Diskussion", "Hilfe", "Hilfe Diskussion", "Kategorie", "Kategorie Diskussion", "Portal", "Portal Diskussion"],
} else { url=imageURL(image, pg.wiki.imageSources[i].wiki); }
"el": ["Μέσον", "Ειδικό", "Συζήτηση", "Χρήστης", "Συζήτηση χρήστη", "Βικιπαίδεια", "Βικιπαίδεια συζήτηση", "Εικόνα", "Συζήτηση εικόνας", "MediaWiki", "MediaWiki talk", "Πρότυπο", "Συζήτηση προτύπου", "Βοήθεια", "Συζήτηση βοήθειας", "Κατηγορία", "Συζήτηση κατηγορίας"],
for (var j=0; j<pg.cache.images.length; ++j) {
"eo": [m, "Speciala", "Diskuto", "Vikipediisto", "Vikipediista diskuto", "Vikipedio", "Vikipedio diskuto", "Dosiero", "Dosiera diskuto", "MediaWiki", "MediaWiki diskuto", "Ŝablono", "Ŝablona diskuto", "Helpo", "Helpa diskuto", "Kategorio", "Kategoria diskuto"],
if (url == pg.cache.images[j]) {
"es": [m, "Especial", "Discusión", "Usuario", "Usuario Discusión", "Wikipedia", "Wikipedia Discusión", "Imagen", "Imagen Discusión", "MediaWiki", "MediaWiki Discusión", "Plantilla", "Plantilla Discusión", "Ayuda", "Ayuda Discusión", "Categoría", "Categoría Discusión"],
loadThisImageAtThisUrl(image, url);
"et": ["Meedia", "Eri", "Arutelu", "Kasutaja", "Kasutaja arutelu", "Vikipeedia", "Vikipeedia arutelu", "Pilt", "Pildi arutelu", "MediaWiki", "MediaWiki arutelu", "Mall", "Malli arutelu", "Juhend", "Juhendi arutelu", "Kategooria", "Kategooria arutelu"],
return null;
"eu": [m, "Aparteko", "Eztabaida", "Lankide", "Lankide eztabaida", "Wikipedia", "Wikipedia eztabaida", "Irudi", "Irudi eztabaida", "MediaWiki", "MediaWiki eztabaida", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
}
"fa": ["مدیا", "ویژه", "بحث", "کاربر", "بحث کاربر", "ویکی‌پدیا", "بحث ویکی‌پدیا", "تصویر", "بحث تصویر", "مدیاویکی", "بحث مدیاویکی", "الگو", "بحث الگو", "راهنما", "بحث راهنما", "رده", "بحث رده"],
}
"fi": [m, "Toiminnot", "Keskustelu", "Käyttäjä", "Keskustelu käyttäjästä", "Wikipedia", "Keskustelu Wikipediasta", "Kuva", "Keskustelu kuvasta", "MediaWiki", "MediaWiki talk", "Malline", "Keskustelu mallineesta", "Ohje", "Keskustelu ohjeesta", "Luokka", "Keskustelu luokasta"],
if (url!=null) imageUrls.push(url);
"fo": ["Miðil", "Serstakur", "Kjak", "Brúkari", "Brúkari kjak", "Wikipedia", "Wikipedia kjak", "Mynd", "Mynd kjak", "MidiaWiki", "MidiaWiki kjak", "Fyrimynd", "Fyrimynd kjak", "Hjálp", "Hjálp kjak", "Bólkur", "Bólkur kjak"],
}
"fr": [m, "Special", "Discuter", "Utilisateur", "Discussion Utilisateur", "Wikipédia", "Discussion Wikipédia", "Image", "Discussion Image", "MediaWiki", "Discussion MediaWiki", "Modèle", "Discussion Modèle", "Aide", "Discussion Aide", "Catégorie", "Discussion Catégorie", "Portail", "Discussion Portail"],
return imageUrls;
"fur": [m, "Speciâl", "Discussion", "Utent", "Discussion utent", "Vichipedie", "Discussion Vichipedie", "Figure", "Discussion figure", "MediaWiki", "Discussion MediaWiki", "Model", "Discussion model", "Jutori", "Discussion jutori", "Categorie", "Discussion categorie"],
}
"fy": [m, "Wiki", "Oerlis", "Meidogger", "Meidogger oerlis", "Wikipedy", "Wikipedy oerlis", "Ofbyld", "Ofbyld oerlis", "MediaWiki", "MediaWiki oerlis", "Berjocht", "Berjocht oerlis", "Hulp", "Hulp oerlis", "Kategory", "Kategory oerlis"],
"ga": ["Meán", "Speisialta", "Plé", "Úsáideoir", "Plé úsáideora", "Vicipéid", "Plé Vicipéide", "Íomhá", "Plé íomhá", "MediaWiki", "Plé MediaWiki", "Teimpléad", "Plé teimpléid", "Cabhair", "Plé cabhrach", "Catagóir", "Plé catagóire"],
"gu": [m, "Special", "Talk", "User", "User talk", "વિકિપીડિયા", "વિકિપીડિયા talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
// this is probably very wasteful indeed of bandwidth
"he": [m, "מיוחד", "שיחה", "משתמש", "שיחת משתמש", "ויקיפדיה", "שיחת ויקיפדיה", "תמונה", "שיחת תמונה", "MediaWiki", "שיחת MediaWiki", "תבנית", "שיחת תבנית", "עזרה", "שיחת עזרה", "קטגוריה", "שיחת קטגוריה"],
// hey ho
"hi": [m, "विशेष", "वार्ता", "सदस्य", "सदस्य वार्ता", "विकिपीडिया", "विकिपीडिया वार्ता", "चित्र", "चित्र वार्ता", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "श्रेणी", "श्रेणी वार्ता", "Help", "Help talk"],
"hr": ["Mediji", "Posebno", "Razgovor", "Suradnik", "Razgovor sa suradnikom", "Wikipedia", "Razgovor Wikipedia", "Slika", "Razgovor o slici", "MediaWiki", "MediaWiki razgovor", "Predložak", "Razgovor o predlošku", "Pomoć", "Razgovor o pomoći", "Kategorija", "Razgovor o kategoriji"],
function parallelLoadThisImage (image) {
"hu": ["Média", "Speciális", "Vita", "User", "User vita", "Wikipédia", "Wikipédia vita", "Kép", "Kép vita", "MediaWiki", "MediaWiki vita", "Sablon", "Sablon vita", "Segítség", "Segítség vita", "Kategória", "Kategória vita"],
if (typeof image.stripNamespace != 'function') { alert('parallelLoadThisImage bad'); }
"ia": [m, "Special", "Discussion", "Usator", "Discussion Usator", "Wikipedia", "Discussion Wikipedia", "Imagine", "Discussion Imagine", "MediaWiki", "Discussion MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
if (!getValueOf('popupImages')) return;
"id": [m, "Istimewa", "Bicara", "Pengguna", "Bicara Pengguna", "Wikipedia", "Pembicaraan Wikipedia", "Gambar", "Pembicaraan Gambar", "MediaWiki", "Pembicaraan MediaWiki", "Templat", "Pembicaraan Templat", "Bantuan", "Pembicaraan Bantuan", "Kategori", "Pembicaraan Kategori"],
if (!isValidImageName(image)) return false;
"is": ["Miðill", "Kerfissíða", "Spjall", "Notandi", "Notandaspjall", "Wikipedia", "Wikipediaspjall", "Mynd", "Myndaspjall", "Melding", "Meldingarspjall", "Snið", "Sniðaspjall", "Hjálp", "Hjálparspjall", "Flokkur", "Flokkaspjall"],
"it": [m, "Speciale", "Discussione", "Utente", "Discussioni utente", "Wikipedia", "Discussioni Wikipedia", "Immagine", "Discussioni immagine", "MediaWiki", "Discussioni MediaWiki", "Template", "Discussioni template", "Aiuto", "Discussioni aiuto", "Categoria", "Discussioni categoria"],
var imageUrls=getImageUrls(image);
"ja": [m, "特別", "ノート", "利用者", "利用者‐会話", "Wikipedia", "Wikipedia‐ノート", "画像", "画像‐ノート", "MediaWiki", "MediaWiki‐ノート", "Template", "Template‐ノート", "Help", "Help‐ノート", "Category", "Category‐ノート"],
if (!imageUrls) return null;
"ka": ["მედია", "სპეციალური", "განხილვა", "მომხმარებელი", "მომხმარებელი განხილვა", "ვიკიპედია", "ვიკიპედია განხილვა", "სურათი", "სურათი განხილვა", "მედიავიკი", "მედიავიკი განხილვა", "თარგი", "თარგი განხილვა", "დახმარება", "დახმარება განხილვა", "კატეგორია", "კატეგორია განხილვა"],
"ko": [m, "특수기능", "토론", "사용자", "사용자토론", "위키백과", "위키백과토론", "그림", "그림토론", "분류", "분류토론", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk"],
for (var i=0; i<imageUrls.length; ++i) {
"ku": ["Medya", "Taybet", "Nîqaş", "Bikarhêner", "Bikarhêner nîqaş", "Wîkîpediya", "Wîkîpediya nîqaş", "Wêne", "Wêne nîqaş", "MediaWiki", "MediaWiki nîqaş", "Şablon", "Şablon nîqaş", "Alîkarî", "Alîkarî nîqaş", "Kategorî", "Kategorî nîqaş"],
var url = imageUrls[i];
"la": ["Specialis", "Disputatio", "Usor", "Disputatio Usoris", "Vicipaedia", "Disputatio Vicipaediae", "Imago", "Disputatio Imaginis", "MediaWiki", "Disputatio MediaWiki", "Formula", "Disputatio Formulae", "Auxilium", "Disputatio Auxilii", "Categoria", "Disputatio Categoriae", m],
pg.misc.imageArray[i]=new Image();
"li": [m, "Speciaal", "Euverlik", "Gebroeker", "Euverlik gebroeker", "Wikipedia", "Euverlik Wikipedia", "Aafbeilding", "Euverlik afbeelding", "MediaWiki", "Euverlik MediaWiki", "Sjabloon", "Euverlik sjabloon", "Help", "Euverlik help", "Kategorie", "Euverlik kategorie"],
pg.misc.imageArray[i].src=url;
"lt": ["Medija", "Specialus", "Aptarimas", "Naudotojas", "Naudotojo aptarimas", "Wikipedia", "Wikipedia aptarimas", "Vaizdas", "Vaizdo aptarimas", "MediaWiki", "MediaWiki aptarimas", "Šablonas", "Šablono aptarimas", "Pagalba", "Pagalbos aptarimas", "Kategorija", "Kategorijos aptarimas"],
}
"mk": ["Медија", "Специјални", "Разговор", "Корисник", "Корисник разговор", "Wikipedia", "Wikipedia разговор", "Слика", "Слика разговор", "МедијаВики", "МедијаВики разговор", "Шаблон", "Шаблон разговор", "Помош", "Помош разговор", "Категорија", "Категорија разговор"],
if (pg.timer.image != null) {
"ms": [m, "Istimewa", "Perbualan", "Pengguna", "Perbualan Pengguna", "Wikipedia", "Perbualan Wikipedia", "Imej", "Imej Perbualan", "MediaWiki", "MediaWiki Perbualan", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
clearInterval(pg.timer.image);
"mt": [m, "Special", "Talk", "User", "User talk", "Wikipedija", "Wikipedija talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
pg.counter.checkImages=0;
"nap": [m, "Speciale", "Discussione", "Utente", "Discussioni utente", "Wikipedia", "Discussioni Wikipedia", "Immagine", "Discussioni immagine", "MediaWiki", "Discussioni MediaWiki", "Template", "Discussioni template", "Aiuto", "Discussioni aiuto", "Categoria", "Discussioni categoria"],
}
"nds": [m, "Spezial", "Diskuschoon", "Bruker", "Bruker Diskuschoon", "Wikipedia", "Wikipedia Diskuschoon", "Bild", "Bild Diskuschoon", "MediaWiki", "MediaWiki Diskuschoon", "Vörlaag", "Vörlaag Diskuschoon", "Hülp", "Hülp Diskuschoon", "Kategorie", "Kategorie Diskuschoon"],
pg.misc.gImage=new Title(image.toString());
"nl": [m, "Speciaal", "Overleg", "Gebruiker", "Overleg gebruiker", "Wikipedia", "Overleg Wikipedia", "Afbeelding", "Overleg afbeelding", "MediaWiki", "Overleg MediaWiki", "Sjabloon", "Overleg sjabloon", "Help", "Overleg help", "Categorie", "Overleg categorie"],
pg.timer.image=setInterval("checkImages()", 250);
"nn": ["Filpeikar", "Spesial", "Diskusjon", "Brukar", "Brukardiskusjon", "Wikipedia", "Wikipedia-diskusjon", "Fil", "Fildiskusjon", "MediaWiki", "MediaWiki-diskusjon", "Mal", "Maldiskusjon", "Hjelp", "Hjelpdiskusjon", "Kategori", "Kategoridiskusjon"],
return true;
"no": ["Medium", "Spesial", "Diskusjon", "Bruker", "Brukerdiskusjon", "Wikipedia", "Wikipedia-diskusjon", "Bilde", "Bildediskusjon", "MediaWiki", "MediaWiki-diskusjon", "Mal", "Maldiskusjon", "Hjelp", "Hjelpdiskusjon", "Kategori", "Kategoridiskusjon"],
"nv": [m, "Special", "Naaltsoos baa yinísht'į́", "Choinish'įįhí", "Choinish'įįhí baa yinísht'į́", "Wikiibíídiiya", "Wikiibíídiiya baa yinísht'į́", "E'elyaaígíí", "E'elyaaígíí baa yinísht'į́", "MediaWiki", "MediaWiki baa yinísht'į́", "Template", "Template talk", "Aná'álwo'", "Aná'álwo' baa yinísht'į́", "T'ááłáhági át'éego", "T'ááłáhági át'éego baa yinísht'į́"],
"oc": ["Especial", "Discutir", "Utilisator", "Discutida Utilisator", "Oiquipedià", "Discutida Oiquipedià", "Image", "Discutida Image", "MediaWiki", "MediaWiki talk", "Template", "Template talk", m, "Help", "Help talk", "Category", "Category talk"],
"os": [m, "Сæрмагонд", "Дискусси", "Архайæг", "Архайæджы дискусси", "Wikipedia", "0", "Ныв", "Нывы тыххæй дискусси", "MediaWiki", "Дискусси MediaWiki", "Шаблон", "Шаблоны тыххæй дискусси", "Æххуыс", "Æххуысы тыххæй дискусси", "Категори", "Категорийы тыххæй дискусси"],
"pa": ["ਮੀਡੀਆ", "ਖਾਸ", "ਚਰਚਾ", "ਮੈਂਬਰ", "ਮੈਂਬਰ ਚਰਚਾ", "Wikipedia", "Wikipedia ਚਰਚਾ", "ਤਸਵੀਰ", "ਤਸਵੀਰ ਚਰਚਾ", "ਮੀਡੀਆਵਿਕਿ", "ਮੀਡੀਆਵਿਕਿ ਚਰਚਾ", "ਨਮੂਨਾ", "ਨਮੂਨਾ ਚਰਚਾ", "ਮਦਦ", "ਮਦਦ ਚਰਚਾ", "ਸ਼੍ਰੇਣੀ", "ਸ਼੍ਰੇਣੀ ਚਰਚਾ"],
"pl": [m, "Specjalna", "Dyskusja", "Wikipedysta", "Dyskusja Wikipedysty", "Wikipedia", "Dyskusja Wikipedii", "Grafika", "Dyskusja grafiki", "MediaWiki", "Dyskusja MediaWiki", "Szablon", "Dyskusja szablonu", "Pomoc", "Dyskusja pomocy", "Kategoria", "Dyskusja kategorii", "Portal", "Dyskusja portalu"],
"pt": [m, "Especial", "Discussão", "Usuário", "Usuário Discussão", "Wikipedia", "Wikipedia Discussão", "Imagem", "Imagem Discussão", "MediaWiki", "MediaWiki Discussão", "Predefinição", "Predefinição Discussão", "Ajuda", "Ajuda Discussão", "Categoria", "Categoria Discussão"],
"ro": [m, "Special", "Discuţie", "Utilizator", "Discuţie Utilizator", "Wikipedia", "Discuţie Wikipedia", "Imagine", "Discuţie Imagine", "MediaWiki", "Discuţie MediaWiki", "Format", "Discuţie Format", "Ajutor", "Discuţie Ajutor", "Categorie", "Discuţie Categorie"],
"ru": ["Медиа", "Служебная", "Обсуждение", "Участник", "Обсуждение участника", "Википедия", "Обсуждение Википедии", "Изображение", "Обсуждение изображения", "MediaWiki", "Обсуждение MediaWiki", "Шаблон", "Обсуждение шаблона", "Справка", "Обсуждение справки", "Категория", "Обсуждение категории"],
"sc": ["Speciale", "Contièndha", "Utente", "Utente discussioni", "Wikipedia", "Wikipedia discussioni", "Immàgini", "Immàgini contièndha", m, "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"sk": ["Médiá", "Špeciálne", "Diskusia", "Redaktor", "Diskusia s redaktorom", "Wikipédia", "Diskusia k Wikipédii", "Obrázok", "Diskusia k obrázku", "MediaWiki", "Diskusia k MediaWiki", "Šablóna", "Diskusia k šablóne", "Pomoc", "Diskusia k pomoci", "Kategória", "Diskusia ku kategórii"],
"sl": [m, "Posebno", "Pogovor", "Uporabnik", "Uporabniški pogovor", "Wikipedija", "Pogovor k Wikipediji", "Slika", "Pogovor k sliki", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"sq": [m, "Speciale", "Diskutim", "Përdoruesi", "Përdoruesi diskutim", "Wikipedia", "Wikipedia diskutim", "Figura", "Figura diskutim", "MediaWiki", "MediaWiki diskutim", "Stampa", "Stampa diskutim", "Ndihmë", "Ndihmë diskutim", "Category", "Category talk"],
"sr": [m, "Посебно", "Разговор", "Корисник", "Разговор са корисником", "Википедија", "Разговор о Википедији", "Слика", "Разговор о слици", "МедијаВики", "Разговор о МедијаВикију", "Шаблон", "Разговор о шаблону", "Помоћ", "Разговор о помоћи", "Категорија", "Разговор о категорији", "Портал", "Разговор о порталу"],
"sv": [m, "Special", "Diskussion", "Användare", "Användardiskussion", "Wikipedia", "Wikipediadiskussion", "Bild", "Bilddiskussion", "MediaWiki", "MediaWiki diskussion", "Mall", "Malldiskussion", "Hjälp", "Hjälp diskussion", "Kategori", "Kategoridiskussion"],
"ta": ["ஊடகம்", "சிறப்பு", "பேச்சு", "பயனர்", "பயனர் பேச்சு", "Wikipedia", "Wikipedia பேச்சு", "படிமம்", "படிமப் பேச்சு", "மீடியாவிக்கி", "மீடியாவிக்கி பேச்சு", "வார்ப்புரு", "வார்ப்புரு பேச்சு", "உதவி", "உதவி பேச்சு", "பகுப்பு", "பகுப்பு பேச்சு"],
"th": [m, "พิเศษ", "พูดคุย", "ผู้ใช้", "คุยเกี่ยวกับผู้ใช้", "Wikipedia", "Wikipedia talk", "ภาพ", "คุยเกี่ยวกับภาพ", "MediaWiki", "คุยเกี่ยวกับ MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"tlh": ["Doch", "le'", "ja'chuq", "lo'wI'", "lo'wI' ja'chuq", "wIqIpe'DIya", "wIqIpe'DIya ja'chuq", "nagh beQ", "nagh beQ ja'chuq", "MediaWiki", "MediaWiki ja'chuq", "chen'ay'", "chen'ay' ja'chuq", "QaH", "QaH ja'chuq", "Segh", "Segh ja'chuq"],
"tr": [m, "Özel", "Tartışma", "Kullanıcı", "Kullanıcı mesaj", "Vikipedi", "Vikipedi tartışma", "Resim", "Resim tartışma", "MedyaViki", "MedyaViki tartışma", "Şablon", "Şablon tartışma", "Yardım", "Yardım tartışma", "Kategori", "Kategori tartışma"],
"tt": [m, "Maxsus", "Bäxäs", "Äğzä", "Äğzä bäxäse", "Wikipedia", "Wikipedia bäxäse", "Räsem", "Räsem bäxäse", "MediaWiki", "MediaWiki bäxäse", "Ürnäk", "Ürnäk bäxäse", "Yärdäm", "Yärdäm bäxäse", "Törkem", "Törkem bäxäse"],
"uk": ["Медіа", "Спеціальні", "Обговорення", "Користувач", "Обговорення користувача", "Wikipedia", "Обговорення Wikipedia", "Зображення", "Обговорення зображення", "MediaWiki", "Обговорення MediaWiki", "Шаблон", "Обговорення шаблону", "Довідка", "Обговорення довідки", "Категорія", "Обговорення категорії"],
"vi": ["Phương tiện", "Đặc biệt", "Thảo luận", "Thành viên", "Thảo luận Thành viên", "Wikipedia", "Thảo luận Wikipedia", "Hình", "Thảo luận Hình", "MediaWiki", "Thảo luận MediaWiki", "Tiêu bản", "Thảo luận Tiêu bản", "Trợ giúp", "Thảo luận Trợ giúp", "Thể loại", "Thảo luận Thể loại"],
"wa": [m, "Sipeciås", "Copene", "Uzeu", "Uzeu copene", "Wikipedia", "Wikipedia copene", "Imådje", "Imådje copene", "MediaWiki", "MediaWiki copene", "Modele", "Modele copene", "Aidance", "Aidance copene", "Categoreye", "Categoreye copene"]
//</NOLITE>
};
pg.ns.list = nsLists[pg.wiki.lang] || list;
pg.ns.index = nsIndex;
}
}
 
function getValidImageFromWikiText(wikiText) {
function namespaceListToRegex(list) {return RegExp('^('+list.join('|').split(' ').join('[ _]')+'):');};
var imagePage=null;
// function setNamespaceList is ugly as sin, moved to later in the code
// nb in pg.re.image we're interested in the second bracketed expression
 
// this may change if the regex changes :-(
function setNamespaces() {
//var match=pg.re.image.exec(wikiText);
setNamespaceList();
var matched=null;
pg.ns.withTalkList=[null]; // NB root (article) corresponds with this entry, null
var match;
pg.ns.talkList=[pg.ns.list[2]];
// strip html comments, used by evil bots :-(
 
var t = removeMatchesUnless(wikiText, RegExp('(<!--[\\s\\S]*?-->)'), 1,
// if the number of namespaces changes then this will have to be changed
    RegExp('^<!--[^[]*popup', 'i'));
// maybe the easiest way is to specify the arrays by hand as in the comments following the loop
 
while ( match = pg.re.image.exec(t) ) {
for (var i=3; i+1<pg.ns.list.length; i=i+2) {
// now find a sane image name - exclude templates by seeking {
pg.ns.withTalkList.push(pg.ns.list[i]);
var m = match[2] || match[6];
pg.ns.talkList.push(pg.ns.list[i+1]);
var pxWidth=match[4];
if ( isValidImageName(m) &&
    (!pxWidth || parseInt(pxWidth,10) >= getValueOf('popupMinImageWidth')) ) {
matched=m;
break;
}
}
}
pg.re.image.lastIndex=0;
 
if (!matched) { return null; }
// ALERT! SILLY HARDCODED VALUES FOLLOW!
return pg.ns.image+':'+upcaseFirst(matched);
pg.ns.special  = pg.ns.list[pg.ns.index.Special];
pg.ns.image     = pg.ns.list[pg.ns.index.Image];
pg.ns.user      = pg.ns.list[pg.ns.index.User];
pg.ns.usertalk  = pg.ns.list[pg.ns.index['User talk']];
pg.ns.category  = pg.ns.list[pg.ns.index.Category];
pg.ns.template  = pg.ns.list[pg.ns.index.Template];
pg.ns.nonArticleList=pg.ns.list.slice(0,2).concat(pg.ns.list.slice(2));
}
}
 
function removeMatchesUnless(str, re1, parencount, re2) {
 
    var split=str.parenSplit(re1);
function setRedirs() {
    var c=parencount + 1;
var r='redirect';
    for (var i=0; i<split.length; ++i) {
var R='REDIRECT';
if ( i%c === 0 || re2.test(split[i]) ) { continue; }
var redirLists={
split[i]='';
//<NOLITE>
    }
'ar': [ R, 'تحويل' ],
    return split.join('');
'be'[ r, 'перанакіраваньне' ],
}
'bg':  [ r, 'пренасочване', 'виж' ],
'bs':  [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ],
//</NOLITE>
'cs':  [ R, 'PŘESMĚRUJ' ],
// ENDFILE: images.js
'cy':  [ r, 'ail-cyfeirio' ],
// STARTFILE: namespaces.js
'et':  [ r, 'suuna' ],
// Set up namespaces and other non-strings.js localization
'ga':  [ r, 'athsheoladh' ],
// (currently that means redirs too)
'he':  [ R, 'הפניה' ],
   
'is':  [ r, 'tilvísun', 'TILVÍSUN' ],
// Put the right namespace list into pg.ns.list, based on pg.wiki.lang
'mk': [ r, 'пренасочување', 'види' ],
// Default to english if nothing seems to fit
'nds': [ r, 'wiederleiden' ],
function setNamespaceList() {
'nn': [ r, 'omdiriger' ],
var m="Media";
'pt': [ R, 'redir' ],
var list = [m, "Special", "Talk", "User", "User talk", "Absurdopedia", "Absurdopedia talk", "File", "File talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk", "Portal", "Portal talk"];
'ru': [ R, 'ПЕРЕНАПРАВЛЕНИЕ', 'ПЕРЕНАПР' ],
var nsIndex = { '': 0, 'Special': 1,
'sk': [ r, 'presmeruj' ],
'Talk': 2, 'User': 3, 'User talk': 4, 'Wikipedia': 5,
'sr': [ r, 'Преусмери', 'преусмери', 'ПРЕУСМЕРИ', 'Preusmeri', 'preusmeri', 'PREUSMERI' ],
'Wikipedia talk': 6, 'Image': 7, 'File': 7, 'Image talk': 8, 'File talk' : 8, 'MediaWiki': 9,
'tt': [ 'yünältü' ],
'MediaWiki talk': 10, 'Template': 11, 'Template talk': 12,
'vi': [ r, 'đổi' ] // no comma
'Help': 13, 'Help talk': 14, 'Category': 15, 'Category talk':16,
//</NOLITE>
'Portal': 17, 'Portal talk': 18};
};
var nsLists = {
var redirList=redirLists[ pg.wiki.lang ] || [r, R];
// Mediawiki is very tolerant about what comes after the #redirect at the start
pg.re.redirect=RegExp('^\\s*[#](' + redirList.join('|') + ').*?\\[{2}([^\\|\\]]*)(|[^\\]]*)?\\]{2}\\s*(.*)', 'i');
}
 
function setInterwiki() {
if (pg.wiki.wikimedia) {
pg.wiki.interwiki='aa|ab|af|ak|als|am|an|ang|ar|arc|as|ast|av|ay|az|ba|be|ber|bg|bh|bi|bm|bn|bdf|bo|br|bs|ca|ce|ceb|ch|cho|chr|chy|co|commons|cr|cs|csb|cu|cv|cy|da|de|dv|dz|el|en|eo|es|et|eu|fa|ff|fi|fiu-vro|fj|fo|fr|fur|fy|ga|gd|gil|gl|gn|got|gu|gv|ha|haw|he|hi|ho|hr|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|io|is|it|iu|ja|jbo|jv|ka|kg|ki|kj|kk|kl|km|kn|ko|kr|ks|ku|kv|kw|ky|la|lad|lan|lb|lg|li|ln|lo|lt|lu|lv|mg|mh|mi|mk|ml|mn|mo|mr|ms|mt|mus|my|na|nah|nap|nb|nd|nds|ne|ng|nl|nn|no|nr|nv|ny|oc|oj|om|or|os|pa|pam|pi|pl|ps|pt|qu|rm|rn|ro|roa-rup|ru|rw|sa|sc|scn|sco|sd|se|sg|sh|si|simple|sk|sl|sm|smg|sn|so|sq|sr|ss|st|su|sv|sw|ta|te|tg|th|ti|tk|tl|tlh|tn|to|tpi|tr|ts|tt|tum|tw|ty|ug|uk|ur|uz|ve|vi|vk|vo|wa|war|wen|wo|xh|yi|yo|za|zh|zh-min-nan|zu';
pg.re.interwiki=RegExp('^'+pg.wiki.interwiki+':');
} else {
pg.wiki.interwiki=null;
pg.re.interwiki=RegExp('^$');
}
}
 
function nsRe(label) {
var l=upcaseFirst(label);
return nsRegexString(pg.ns.list[pg.ns.index[l]], l);
}
 
function nsRegexString(str, extra) {
return '(?:' + str + '|' + encodeURI(str) + (extra ? '|' + extra : '') + ')';
}
 
function nsRegex(str, extra) {
return RegExp(nsRegexString(str, extra));
}
// ENDFILE: namespaces.js
// STARTFILE: selpop.js
//<NOLITE>
//<NOLITE>
"af": [m, "Spesiaal", "Bespreking", "Gebruiker", "Gebruikerbespreking", "Wikipedia", "Wikipediabespreking", "Beeld", "Beeldbespreking", "MediaWiki", "MediaWikibespreking", "Sjabloon", "Sjabloonbespreking", "Hulp", "Hulpbespreking", "Kategorie", "Kategoriebespreking"],
function getEditboxSelection() {
"als": [m, "Spezial", "Diskussion", "Benutzer", "Benutzer Diskussion", "Wikipedia", "Wikipedia Diskussion", "Bild", "Bild Diskussion", "MediaWiki", "MediaWiki Diskussion", "Vorlage", "Vorlage Diskussion", "Hilfe", "Hilfe Diskussion", "Kategorie", "Kategorie Diskussion"],
// see http://www.webgurusforum.com/8/12/0
"ar": ["ملف", "خاص", "نقاش", "مستخدم", "نقاش المستخدم", "ويكيبيديا", "نقاش ويكيبيديا", "صورة", "نقاش الصورة", "ميدياويكي", "نقاش ميدياويكي", "Template", "نقاش Template", "مساعدة", "نقاش المساعدة", "تصنيف", "نقاش التصنيف"],
try {
"ast": [m, "Especial", "Discusión", "Usuariu", "Usuariu discusión", "Uiquipedia", "Uiquipedia discusión", "Imaxen", "Imaxen discusión", "MediaWiki", "MediaWiki discusión", "Plantilla", "Plantilla discusión", "Ayuda", "Ayuda discusión", "Categoría", "Categoría discusión"],
var editbox=document.editform.wpTextbox1;
"be": ["Мэдыя", "Спэцыяльныя", "Абмеркаваньне", "Удзельнік", "Гутаркі ўдзельніка", "Вікіпэдыя", "Абмеркаваньне Вікіпэдыя", "Выява", "Абмеркаваньне выявы", "MediaWiki", "Абмеркаваньне MediaWiki", "Шаблён", "Абмеркаваньне шаблёну", "Дапамога", "Абмеркаваньне дапамогі", "Катэгорыя", "Абмеркаваньне катэгорыі"],
} catch (dang) { return; }
"bg": ["Медия", "Специални", "Беседа", "Потребител", "Потребител беседа", "Уикипедия", "Уикипедия беседа", "Картинка", "Картинка беседа", "МедияУики", "МедияУики беседа", "Шаблон", "Шаблон беседа", "Помощ", "Помощ беседа", "Категория", "Категория беседа"],
// IE, Opera
"bm": [m, "Special", "Discuter", "Utilisateur", "Discussion Utilisateur", "Wikipedia", "Discussion Wikipedia", "Image", "Discussion Image", "MediaWiki", "Discussion MediaWiki", "Modèle", "Discussion Modèle", "Aide", "Discussion Aide", "Catégorie", "Discussion Catégorie"],
if (document.selection) { return document.selection.createRange().text; }
"bn": ["বিশেষ", "আলাপ", "ব্যবহারকারী", "ব্যবহারকারী আলাপ", "উইকিপেডিয়া", "উইকিপেডিয়া আলাপ", "চিত্র", "চিত্র আলাপ", "MediaWik i আলাপ", m, "MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
// Mozilla
"br": [m, "Dibar", "Kaozeal", "Implijer", "Kaozeadenn Implijer", "Wikipedia", "Kaozeadenn Wikipedia", "Skeudenn", "Kaozeadenn Skeudenn", "MediaWiki", "Kaozeadenn MediaWiki", "Patrom", "Kaozeadenn Patrom", "Skoazell", "Kaozeadenn Skoazell", "Rummad", "Kaozeadenn Rummad"],
var selStart = editbox.selectionStart;
"ca": [m, "Especial", "Discussió", "Usuari", "Usuari Discussió", "Viquipèdia", "Viquipèdia Discussió", "Imatge", "Imatge Discussió", "MediaWiki", "MediaWiki Discussió", "Template", "Template Discussió", "Ajuda", "Ajuda Discussió", "Categoria", "Categoria Discussió"],
var selEnd = editbox.selectionEnd;
"cs": ["Média", "Speciální", "Diskuse", "Wikipedista", "Wikipedista diskuse", "Wikipedie", "Wikipedie diskuse", "Soubor", "Soubor diskuse", "MediaWiki", "MediaWiki diskuse", "Šablona", "Šablona diskuse", "Nápověda", "Nápověda diskuse", "Kategorie", "Kategorie diskuse"],
return (editbox.value).substring(selStart, selEnd);
"csb": [m, "Specjalnô", "Diskùsëjô", "Brëkòwnik", "Diskùsëjô brëkòwnika", "Wiki", "Diskùsëjô Wiki", "Òbrôzk", "Diskùsëjô òbrôzków", "MediaWiki", "Diskùsëjô MediaWiki", "Szablóna", "Diskùsëjô Szablónë", "Pòmòc", "Diskùsëjô Pòmòcë", "Kategòrëjô", "Diskùsëjô Kategòrëji"],
}
"cv": ["Медиа", "Ятарлă", "Сӳтсе явасси", "Хутшăнакан", "Хутшăнаканăн канашлу страници", "Wikipedia", "0", "Ӳкерчĕк", "Ӳкерчĕке сӳтсе явмалли", "MediaWiki", "MediaWiki сӳтсе явмалли", "Шаблон", "Шаблона сӳтсе явмалли", "Пулăшу", "Пулăшăва сӳтсе явмалли", "Категори", "Категорине сӳтсе явмалли"],
 
"cy": [m, "Arbennig", "Sgwrs", "Defnyddiwr", "Sgwrs Defnyddiwr", "Wicipedia", "Sgwrs Wicipedia", "Delwedd", "Sgwrs Delwedd", "MediaWiki", "Sgwrs MediaWiki", "Nodyn", "Sgwrs Nodyn", "Help", "Help talk", "Category", "Category talk"],
function doSelectionPopup() {
"da": [m, "Speciel", "Diskussion", "Bruger", "Brugerdiskussion", "Wikipedia", "Wikipedia-diskussion", "Billede", "Billeddiskussion", "MediaWiki", "MediaWiki-diskussion", "Skabelon", "Skabelondiskussion", "Hjælp", "Hjælpdiskussion", "Kategori", "Kategoridiskussion", "Portal", "Portaldiskussion"],
// popup if the selection looks like [[foo|anything afterwards at all
"de": [m, "Spezial", "Diskussion", "Benutzer", "Benutzer Diskussion", "Wikipedia", "Wikipedia Diskussion", "Bild", "Bild Diskussion", "MediaWiki", "MediaWiki Diskussion", "Vorlage", "Vorlage Diskussion", "Hilfe", "Hilfe Diskussion", "Kategorie", "Kategorie Diskussion", "Portal", "Portal Diskussion"],
// or [[foo|bar]]text without ']]'
"el": ["Μέσον", "Ειδικό", "Συζήτηση", "Χρήστης", "Συζήτηση χρήστη", "Βικιπαίδεια", "Βικιπαίδεια συζήτηση", "Εικόνα", "Συζήτηση εικόνας", "MediaWiki", "MediaWiki talk", "Πρότυπο", "Συζήτηση προτύπου", "Βοήθεια", "Συζήτηση βοήθειας", "Κατηγορία", "Συζήτηση κατηγορίας"],
// or [[foo|bar]]
"eo": [m, "Speciala", "Diskuto", "Vikipediisto", "Vikipediista diskuto", "Vikipedio", "Vikipedio diskuto", "Dosiero", "Dosiera diskuto", "MediaWiki", "MediaWiki diskuto", "Ŝablono", "Ŝablona diskuto", "Helpo", "Helpa diskuto", "Kategorio", "Kategoria diskuto"],
var sel=getEditboxSelection();
"es": [m, "Especial", "Discusión", "Usuario", "Usuario Discusión", "Wikipedia", "Wikipedia Discusión", "Imagen", "Imagen Discusión", "MediaWiki", "MediaWiki Discusión", "Plantilla", "Plantilla Discusión", "Ayuda", "Ayuda Discusión", "Categoría", "Categoría Discusión"],
var open=sel.indexOf('[[');
"et": ["Meedia", "Eri", "Arutelu", "Kasutaja", "Kasutaja arutelu", "Vikipeedia", "Vikipeedia arutelu", "Pilt", "Pildi arutelu", "MediaWiki", "MediaWiki arutelu", "Mall", "Malli arutelu", "Juhend", "Juhendi arutelu", "Kategooria", "Kategooria arutelu"],
var pipe=sel.indexOf('|');
"eu": [m, "Aparteko", "Eztabaida", "Lankide", "Lankide eztabaida", "Wikipedia", "Wikipedia eztabaida", "Irudi", "Irudi eztabaida", "MediaWiki", "MediaWiki eztabaida", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
var close=sel.indexOf(']]');
"fa": ["مدیا", "ویژه", "بحث", "کاربر", "بحث کاربر", "ویکی‌پدیا", "بحث ویکی‌پدیا", "تصویر", "بحث تصویر", "مدیاویکی", "بحث مدیاویکی", "الگو", "بحث الگو", "راهنما", "بحث راهنما", "رده", "بحث رده"],
if (open == -1 || ( pipe == -1 && close == -1) ) { return; }
"fi": [m, "Toiminnot", "Keskustelu", "Käyttäjä", "Keskustelu käyttäjästä", "Wikipedia", "Keskustelu Wikipediasta", "Kuva", "Keskustelu kuvasta", "MediaWiki", "MediaWiki talk", "Malline", "Keskustelu mallineesta", "Ohje", "Keskustelu ohjeesta", "Luokka", "Keskustelu luokasta"],
if (pipe != -1 && open > pipe || close != -1 && open > close) { return; }
"fo": ["Miðil", "Serstakur", "Kjak", "Brúkari", "Brúkari kjak", "Wikipedia", "Wikipedia kjak", "Mynd", "Mynd kjak", "MidiaWiki", "MidiaWiki kjak", "Fyrimynd", "Fyrimynd kjak", "Hjálp", "Hjálp kjak", "Bólkur", "Bólkur kjak"],
if (getValueOf('popupOnEditSelection')=='boxpreview') {
"fr": [m, "Spécial", "Discuter", "Utilisateur", "Discussion Utilisateur", "Wikipédia", "Discussion Wikipédia", "Image", "Discussion Image", "MediaWiki", "Discussion MediaWiki", "Modèle", "Discussion Modèle", "Aide", "Discussion Aide", "Catégorie", "Discussion Catégorie", "Portail", "Discussion Portail"],
return doSeparateSelectionPopup(sel);
"fur": [m, "Speciâl", "Discussion", "Utent", "Discussion utent", "Vichipedie", "Discussion Vichipedie", "Figure", "Discussion figure", "MediaWiki", "Discussion MediaWiki", "Model", "Discussion model", "Jutori", "Discussion jutori", "Categorie", "Discussion categorie"],
}
"fy": [m, "Wiki", "Oerlis", "Meidogger", "Meidogger oerlis", "Wikipedy", "Wikipedy oerlis", "Ofbyld", "Ofbyld oerlis", "MediaWiki", "MediaWiki oerlis", "Berjocht", "Berjocht oerlis", "Hulp", "Hulp oerlis", "Kategory", "Kategory oerlis"],
var article=new Title(sel.substring(open+2, (pipe < 0) ? close : pipe)).urlString();
"ga": ["Meán", "Speisialta", "Plé", "Úsáideoir", "Plé úsáideora", "Vicipéid", "Plé Vicipéide", "Íomhá", "Plé íomhá", "MediaWiki", "Plé MediaWiki", "Teimpléad", "Plé teimpléid", "Cabhair", "Plé cabhrach", "Catagóir", "Plé catagóire"],
if (close > 0 && sel.substring(close+2).indexOf('[[') >= 0) {
"gu": [m, "Special", "Talk", "User", "User talk", "વિકિપીડિયા", "વિકિપીડિયા talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
return;
"he": [m, "מיוחד", "שיחה", "משתמש", "שיחת משתמש", "ויקיפדיה", "שיחת ויקיפדיה", "תמונה", "שיחת תמונה", "MediaWiki", "שיחת MediaWiki", "תבנית", "שיחת תבנית", "עזרה", "שיחת עזרה", "קטגוריה", "שיחת קטגוריה"],
}
"hi": [m, "विशेष", "वार्ता", "सदस्य", "सदस्य वार्ता", "विकिपीडिया", "विकिपीडिया वार्ता", "चित्र", "चित्र वार्ता", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "श्रेणी", "श्रेणी वार्ता", "Help", "Help talk"],
var a=document.createElement('a');
"hr": ["Mediji", "Posebno", "Razgovor", "Suradnik", "Razgovor sa suradnikom", "Wikipedia", "Razgovor Wikipedia", "Slika", "Razgovor o slici", "MediaWiki", "MediaWiki razgovor", "Predložak", "Razgovor o predlošku", "Pomoć", "Razgovor o pomoći", "Kategorija", "Razgovor o kategoriji"],
a.href=pg.wiki.titlebase + article;
"hu": [ "Média", "Speciális", "Vita", "Szerkesztő", "Szerkesztővita", "Wikipédia", "Wikipédia-vita", "Kép", "Képvita", "MediaWiki", "MediaWiki-vita", "Sablon", "Sablonvita", "Segítség", "Segítségvita", "Kategória", "Kategóriavita", "Portál", "Portálvita"],
mouseOverWikiLink2(a);
"ia": [m, "Special", "Discussion", "Usator", "Discussion Usator", "Wikipedia", "Discussion Wikipedia", "Imagine", "Discussion Imagine", "MediaWiki", "Discussion MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
if (a.navpopup) {
"id": [m, "Istimewa", "Bicara", "Pengguna", "Bicara Pengguna", "Wikipedia", "Pembicaraan Wikipedia", "Gambar", "Pembicaraan Gambar", "MediaWiki", "Pembicaraan MediaWiki", "Templat", "Pembicaraan Templat", "Bantuan", "Pembicaraan Bantuan", "Kategori", "Pembicaraan Kategori"],
a.navpopup.addHook(function(){runStopPopupTimer(a.navpopup);}, 'unhide', 'after');
"is": ["Miðill", "Kerfissíða", "Spjall", "Notandi", "Notandaspjall", "Wikipedia", "Wikipediaspjall", "Mynd", "Myndaspjall", "Melding", "Meldingarspjall", "Snið", "Sniðaspjall", "Hjálp", "Hjálparspjall", "Flokkur", "Flokkaspjall"],
}
"it": [m, "Speciale", "Discussione", "Utente", "Discussioni utente", "Wikipedia", "Discussioni Wikipedia", "File", "Discussioni file", "MediaWiki", "Discussioni MediaWiki", "Template", "Discussioni template", "Aiuto", "Discussioni aiuto", "Categoria", "Discussioni categoria", "Portale", "Discussioni portale", "Progetto", "Discussioni progetto"],
"ja": [m, "特別", "ノート", "利用者", "利用者‐会話", "Wikipedia", "Wikipedia‐ノート", "画像", "画像‐ノート", "MediaWiki", "MediaWiki‐ノート", "Template", "Template‐ノート", "Help", "Help‐ノート", "Category", "Category‐ノート"],
"ka": ["მედია", "სპეციალური", "განხილვა", "მომხმარებელი", "მომხმარებელი განხილვა", "ვიკიპედია", "ვიკიპედია განხილვა", "სურათი", "სურათი განხილვა", "მედიავიკი", "მედიავიკი განხილვა", "თარგი", "თარგი განხილვა", "დახმარება", "დახმარება განხილვა", "კატეგორია", "კატეგორია განხილვა"],
"ko": [m, "특수기능", "토론", "사용자", "사용자토론", "위키백과", "위키백과토론", "그림", "그림토론", "분류", "분류토론", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk"],
"ku": ["Medya", "Taybet", "Nîqaş", "Bikarhêner", "Bikarhêner nîqaş", "Wîkîpediya", "Wîkîpediya nîqaş", "Wêne", "Wêne nîqaş", "MediaWiki", "MediaWiki nîqaş", "Şablon", "Şablon nîqaş", "Alîkarî", "Alîkarî nîqaş", "Kategorî", "Kategorî nîqaş"],
"la": ["Specialis", "Disputatio", "Usor", "Disputatio Usoris", "Vicipaedia", "Disputatio Vicipaediae", "Imago", "Disputatio Imaginis", "MediaWiki", "Disputatio MediaWiki", "Formula", "Disputatio Formulae", "Auxilium", "Disputatio Auxilii", "Categoria", "Disputatio Categoriae", m],
"li": [m, "Speciaal", "Euverlik", "Gebroeker", "Euverlik gebroeker", "Wikipedia", "Euverlik Wikipedia", "Aafbeilding", "Euverlik afbeelding", "MediaWiki", "Euverlik MediaWiki", "Sjabloon", "Euverlik sjabloon", "Help", "Euverlik help", "Kategorie", "Euverlik kategorie"],
"lt": ["Medija", "Specialus", "Aptarimas", "Naudotojas", "Naudotojo aptarimas", "Wikipedia", "Wikipedia aptarimas", "Vaizdas", "Vaizdo aptarimas", "MediaWiki", "MediaWiki aptarimas", "Šablonas", "Šablono aptarimas", "Pagalba", "Pagalbos aptarimas", "Kategorija", "Kategorijos aptarimas"],
"mk": ["Медија", "Специјални", "Разговор", "Корисник", "Корисник разговор", "Wikipedia", "Wikipedia разговор", "Слика", "Слика разговор", "МедијаВики", "МедијаВики разговор", "Шаблон", "Шаблон разговор", "Помош", "Помош разговор", "Категорија", "Категорија разговор"],
"ms": [m, "Istimewa", "Perbualan", "Pengguna", "Perbualan Pengguna", "Wikipedia", "Perbualan Wikipedia", "Imej", "Imej Perbualan", "MediaWiki", "MediaWiki Perbualan", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"mt": [m, "Special", "Talk", "User", "User talk", "Wikipedija", "Wikipedija talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"nap": [m, "Speciale", "Discussione", "Utente", "Discussioni utente", "Wikipedia", "Discussioni Wikipedia", "Immagine", "Discussioni immagine", "MediaWiki", "Discussioni MediaWiki", "Template", "Discussioni template", "Aiuto", "Discussioni aiuto", "Categoria", "Discussioni categoria"],
"nds": [m, "Spezial", "Diskuschoon", "Bruker", "Bruker Diskuschoon", "Wikipedia", "Wikipedia Diskuschoon", "Bild", "Bild Diskuschoon", "MediaWiki", "MediaWiki Diskuschoon", "Vörlaag", "Vörlaag Diskuschoon", "Hülp", "Hülp Diskuschoon", "Kategorie", "Kategorie Diskuschoon"],
"nl": [m, "Speciaal", "Overleg", "Gebruiker", "Overleg gebruiker", "Wikipedia", "Overleg Wikipedia", "Afbeelding", "Overleg afbeelding", "MediaWiki", "Overleg MediaWiki", "Sjabloon", "Overleg sjabloon", "Help", "Overleg help", "Categorie", "Overleg categorie"],
"nn": ["Filpeikar", "Spesial", "Diskusjon", "Brukar", "Brukardiskusjon", "Wikipedia", "Wikipedia-diskusjon", "Fil", "Fildiskusjon", "MediaWiki", "MediaWiki-diskusjon", "Mal", "Maldiskusjon", "Hjelp", "Hjelpdiskusjon", "Kategori", "Kategoridiskusjon"],
"no": ["Medium", "Spesial", "Diskusjon", "Bruker", "Brukerdiskusjon", "Wikipedia", "Wikipedia-diskusjon", "Bilde", "Bildediskusjon", "MediaWiki", "MediaWiki-diskusjon", "Mal", "Maldiskusjon", "Hjelp", "Hjelpdiskusjon", "Kategori", "Kategoridiskusjon"],
"nv": [m, "Special", "Naaltsoos baa yinísht'į́", "Choinish'įįhí", "Choinish'įįhí baa yinísht'į́", "Wikiibíídiiya", "Wikiibíídiiya baa yinísht'į́", "E'elyaaígíí", "E'elyaaígíí baa yinísht'į́", "MediaWiki", "MediaWiki baa yinísht'į́", "Template", "Template talk", "Aná'álwo'", "Aná'álwo' baa yinísht'į́", "T'ááłáhági át'éego", "T'ááłáhági át'éego baa yinísht'į́"],
"oc": ["Especial", "Discutir", "Utilisator", "Discutida Utilisator", "Oiquipedià", "Discutida Oiquipedià", "Image", "Discutida Image", "MediaWiki", "MediaWiki talk", "Template", "Template talk", m, "Help", "Help talk", "Category", "Category talk"],
"os": [m, "Сæрмагонд", "Дискусси", "Архайæг", "Архайæджы дискусси", "Wikipedia", "0", "Ныв", "Нывы тыххæй дискусси", "MediaWiki", "Дискусси MediaWiki", "Шаблон", "Шаблоны тыххæй дискусси", "Æххуыс", "Æххуысы тыххæй дискусси", "Категори", "Категорийы тыххæй дискусси"],
"pa": ["ਮੀਡੀਆ", "ਖਾਸ", "ਚਰਚਾ", "ਮੈਂਬਰ", "ਮੈਂਬਰ ਚਰਚਾ", "Wikipedia", "Wikipedia ਚਰਚਾ", "ਤਸਵੀਰ", "ਤਸਵੀਰ ਚਰਚਾ", "ਮੀਡੀਆਵਿਕਿ", "ਮੀਡੀਆਵਿਕਿ ਚਰਚਾ", "ਨਮੂਨਾ", "ਨਮੂਨਾ ਚਰਚਾ", "ਮਦਦ", "ਮਦਦ ਚਰਚਾ", "ਸ਼੍ਰੇਣੀ", "ਸ਼੍ਰੇਣੀ ਚਰਚਾ"],
"pl": [m, "Specjalna", "Dyskusja", "Wikipedysta", "Dyskusja wikipedysty", "Wikipedia", "Dyskusja Wikipedii", "Plik", "Dyskusja pliku", "MediaWiki", "Dyskusja MediaWiki", "Szablon", "Dyskusja szablonu", "Pomoc", "Dyskusja pomocy", "Kategoria", "Dyskusja kategorii", "Portal", "Dyskusja portalu","Wikiprojekt","Dyskusja Wikiprojektu"],
"pt": [m, "Especial", "Discussão", "Usuário", "Usuário Discussão", "Wikipedia", "Wikipedia Discussão", "Imagem", "Imagem Discussão", "MediaWiki", "MediaWiki Discussão", "Predefinição", "Predefinição Discussão", "Ajuda", "Ajuda Discussão", "Categoria", "Categoria Discussão"],
"ro": [m, "Special", "Discuţie", "Utilizator", "Discuţie Utilizator", "Wikipedia", "Discuţie Wikipedia", "Imagine", "Discuţie Imagine", "MediaWiki", "Discuţie MediaWiki", "Format", "Discuţie Format", "Ajutor", "Discuţie Ajutor", "Categorie", "Discuţie Categorie"],
"ru": ["Медиа", "Служебная", "Обсуждение", "Участник", "Обсуждение участника", "Абсурдопедия", "Обсуждение Абсурдопедии", "Изображение", "Обсуждение изображения", "MediaWiki", "Обсуждение MediaWiki", "Шаблон", "Обсуждение шаблона", "Справка", "Обсуждение справки", "Категория", "Обсуждение категории"],
"sc": ["Speciale", "Contièndha", "Utente", "Utente discussioni", "Wikipedia", "Wikipedia discussioni", "Immàgini", "Immàgini contièndha", m, "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"sk": ["Médiá", "Špeciálne", "Diskusia", "Redaktor", "Diskusia s redaktorom", "Wikipédia", "Diskusia k Wikipédii", "Obrázok", "Diskusia k obrázku", "MediaWiki", "Diskusia k MediaWiki", "Šablóna", "Diskusia k šablóne", "Pomoc", "Diskusia k pomoci", "Kategória", "Diskusia ku kategórii"],
"sl": [m, "Posebno", "Pogovor", "Uporabnik", "Uporabniški pogovor", "Wikipedija", "Pogovor k Wikipediji", "Slika", "Pogovor k sliki", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"sq": [m, "Speciale", "Diskutim", "Përdoruesi", "Përdoruesi diskutim", "Wikipedia", "Wikipedia diskutim", "Figura", "Figura diskutim", "MediaWiki", "MediaWiki diskutim", "Stampa", "Stampa diskutim", "Ndihmë", "Ndihmë diskutim", "Category", "Category talk"],
"sr": [m, "Посебно", "Разговор", "Корисник", "Разговор са корисником", "Википедија", "Разговор о Википедији", "Слика", "Разговор о слици", "МедијаВики", "Разговор о МедијаВикију", "Шаблон", "Разговор о шаблону", "Помоћ", "Разговор о помоћи", "Категорија", "Разговор о категорији", "Портал", "Разговор о порталу"],
"sv": [m, "Special", "Diskussion", "Användare", "Användardiskussion", "Wikipedia", "Wikipediadiskussion", "Bild", "Bilddiskussion", "MediaWiki", "MediaWiki diskussion", "Mall", "Malldiskussion", "Hjälp", "Hjälp diskussion", "Kategori", "Kategoridiskussion"],
"ta": ["ஊடகம்", "சிறப்பு", "பேச்சு", "பயனர்", "பயனர் பேச்சு", "Wikipedia", "Wikipedia பேச்சு", "படிமம்", "படிமப் பேச்சு", "மீடியாவிக்கி", "மீடியாவிக்கி பேச்சு", "வார்ப்புரு", "வார்ப்புரு பேச்சு", "உதவி", "உதவி பேச்சு", "பகுப்பு", "பகுப்பு பேச்சு"],
"th": [m, "พิเศษ", "พูดคุย", "ผู้ใช้", "คุยเกี่ยวกับผู้ใช้", "Wikipedia", "Wikipedia talk", "ภาพ", "คุยเกี่ยวกับภาพ", "MediaWiki", "คุยเกี่ยวกับ MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
"tlh": ["Doch", "le'", "ja'chuq", "lo'wI'", "lo'wI' ja'chuq", "wIqIpe'DIya", "wIqIpe'DIya ja'chuq", "nagh beQ", "nagh beQ ja'chuq", "MediaWiki", "MediaWiki ja'chuq", "chen'ay'", "chen'ay' ja'chuq", "QaH", "QaH ja'chuq", "Segh", "Segh ja'chuq"],
"tr": [m, "Özel", "Tartışma", "Kullanıcı", "Kullanıcı mesaj", "Vikipedi", "Vikipedi tartışma", "Resim", "Resim tartışma", "MedyaViki", "MedyaViki tartışma", "Şablon", "Şablon tartışma", "Yardım", "Yardım tartışma", "Kategori", "Kategori tartışma"],
"tt": [m, "Maxsus", "Bäxäs", "Äğzä", "Äğzä bäxäse", "Wikipedia", "Wikipedia bäxäse", "Räsem", "Räsem bäxäse", "MediaWiki", "MediaWiki bäxäse", "Ürnäk", "Ürnäk bäxäse", "Yärdäm", "Yärdäm bäxäse", "Törkem", "Törkem bäxäse"],
"uk": ["Медіа", "Спеціальні", "Обговорення", "Користувач", "Обговорення користувача", "Wikipedia", "Обговорення Wikipedia", "Зображення", "Обговорення зображення", "MediaWiki", "Обговорення MediaWiki", "Шаблон", "Обговорення шаблону", "Довідка", "Обговорення довідки", "Категорія", "Обговорення категорії"],
"vi": ["Phương tiện", "Đặc biệt", "Thảo luận", "Thành viên", "Thảo luận Thành viên", "Wikipedia", "Thảo luận Wikipedia", "Hình", "Thảo luận Hình", "MediaWiki", "Thảo luận MediaWiki", "Tiêu bản", "Thảo luận Tiêu bản", "Trợ giúp", "Thảo luận Trợ giúp", "Thể loại", "Thảo luận Thể loại"],
"wa": [m, "Sipeciås", "Copene", "Uzeu", "Uzeu copene", "Wikipedia", "Wikipedia copene", "Imådje", "Imådje copene", "MediaWiki", "MediaWiki copene", "Modele", "Modele copene", "Aidance", "Aidance copene", "Categoreye", "Categoreye copene"]
//</NOLITE>
};
pg.ns.list = nsLists[pg.wiki.lang] || list;
pg.ns.index = nsIndex;
}
}
 
function namespaceListToRegex(list) {return RegExp('^('+list.join('|').split(' ').join('[ _]')+'):');};
function doSeparateSelectionPopup(str) {
// function setNamespaceList is ugly as sin, moved to later in the code
var div=document.getElementById('selectionPreview');
if (!div) {
function setNamespaces() {
div = document.createElement('div');
setNamespaceList();
div.id='selectionPreview';
pg.ns.withTalkList=[null]; // NB root (article) corresponds with this entry, null
try { var box=document.editform.wpTextbox1; }
pg.ns.talkList=[pg.ns.list[2]];
catch (oopsie) { return; }
box.parentNode.insertBefore(div, box);
// if the number of namespaces changes then this will have to be changed
// maybe the easiest way is to specify the arrays by hand as in the comments following the loop
for (var i=3; i+1<pg.ns.list.length; i=i+2) {
pg.ns.withTalkList.push(pg.ns.list[i]);
pg.ns.talkList.push(pg.ns.list[i+1]);
}
}
div.innerHTML=wiki2html(str);
// ALERT! SILLY HARDCODED VALUES FOLLOW!
div.ranSetupTooltipsAlready = false;
pg.ns.special  = pg.ns.list[pg.ns.index.Special];
popTipsSoonFn('selectionPreview')();
pg.ns.image    = pg.ns.list[pg.ns.index.File];
pg.ns.user      = pg.ns.list[pg.ns.index.User];
pg.ns.usertalk  = pg.ns.list[pg.ns.index['User talk']];
pg.ns.category  = pg.ns.list[pg.ns.index.Category];
pg.ns.template  = pg.ns.list[pg.ns.index.Template];
pg.ns.nonArticleList=pg.ns.list.slice(0,2).concat(pg.ns.list.slice(2));
}
}
//</NOLITE>
// ENDFILE: selpop.js
function setRedirs() {
// STARTFILE: navpopup.js
var r='redirect';
/**
var R='REDIRECT';
  @fileoverview Defines two classes: {@link Navpopup} and {@link Mousetracker}.
var redirLists={
 
//<NOLITE>
  <code>Navpopup</code> describes popups: when they appear, where, what
'ar': [ R, 'تحويل' ],
  they look like and so on.
'be': [ r, 'перанакіраваньне' ],
 
'bg': [ r, 'пренасочване', 'виж' ],
  <code>Mousetracker</code> "captures" the mouse using
'bs': [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ],
  <code>document.onmousemove</code>.
'cs':  [ R, 'PŘESMĚRUJ' ],
*/
'cy': [ r, 'ail-cyfeirio' ],
 
'et':  [ r, 'suuna' ],
 
'ga':  [ r, 'athsheoladh' ],
/**
'he':  [ R, 'הפניה' ],
  Creates a new Mousetracker.
'hu':  [ R, 'ÁTIRÁNYÍTÁS' ],
  @constructor
'is':  [ r, 'tilvísun', 'TILVÍSUN' ],
  @class The Mousetracker class. This monitors mouse movements and manages associated hooks.
'it':  [ R, 'RINVIA', 'Rinvia'],
*/
'mk':  [ r, 'пренасочување', 'види' ],
function Mousetracker() {
'nds': [ r, 'wiederleiden' ],
/**
'nn':  [ r, 'omdiriger' ],
  Interval to regularly run the hooks anyway, in milliseconds.
'pl':  [ R, 'PATRZ', 'PRZEKIERUJ', 'TAM' ],
  @type Integer
'pt':  [ R, 'redir' ],
*/
'ru':  [ R, 'ПЕРЕНАПРАВЛЕНИЕ', 'ПЕРЕНАПР' ],
this.loopDelay=400;
'sk':  [ r, 'presmeruj' ],
 
'sr':  [ r, 'Преусмери', 'преусмери', 'ПРЕУСМЕРИ', 'Preusmeri', 'preusmeri', 'PREUSMERI' ],
/**
'tt':  [ 'yünältü' ],
  Timer for the loop.
'vi':  [ r, 'đổi' ] // no comma
  @type Timer
//</NOLITE>
*/
};
this.timer=null;
var redirList=redirLists[ pg.wiki.lang ] || [r, R];
 
// Mediawiki is very tolerant about what comes after the #redirect at the start
/**
pg.re.redirect=RegExp('^\\s*[#](' + redirList.join('|') + ').*?\\[{2}([^\\|\\]]*)(|[^\\]]*)?\\]{2}\\s*(.*)', 'i');
  Flag - are we switched on?
  @type Boolean
*/
this.active=false;
/**
  Flag - are we probably inaccurate, i.e. not reflecting the actual mouse position?
*/
this.dirty=true;
/**
  Array of hook functions.
  @private
  @type Array
*/
this.hooks=[];
}
}
 
function setInterwiki() {
/**
if (pg.wiki.wikimedia) {
  Adds a hook, to be called when we get events.
pg.wiki.interwiki='aa|ab|af|ak|als|am|an|ang|ar|arc|arz|as|ast|av|ay|az|ba|be|ber|bg|bh|bi|bm|bn|bdf|bo|br|bs|ca|ce|ceb|ch|cho|chr|chy|co|commons|cr|cs|csb|cu|cv|cy|da|de|dsb|dv|dz|el|en|eo|es|et|eu|fa|ff|fi|fiu-vro|fj|fo|fr|fur|fy|ga|gd|gil|gl|gn|got|gu|gv|ha|haw|he|hi|ho|hr|hsb|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|ilo|io|is|it|iu|ja|jbo|jv|ka|kg|ki|kj|kk|kl|km|kn|ko|kr|ks|ksh|ku|kv|kw|ky|la|lad|lan|lb|lg|li|ln|lmo|lo|lt|lu|lv|map-bms|mg|mh|mi|mk|ml|mn|mo|mr|ms|mt|stq|mus|my|na|nah|nap|nb|nd|nds|nds-nl|ne|new|ng|nl|nn|no|nr|nv|ny|oc|oj|om|or|os|pa|pam|pi|pl|pms|ps|pt|qu|rm|rn|ro|roa-rup|ru|rw|sa|sc|scn|sco|sd|se|sg|sh|si|simple|sk|sl|sm|smg|sn|so|sq|sr|ss|st|stq|su|sv|sw|szl|ta|te|tg|th|ti|tk|tl|tlh|tn|to|tpi|tr|ts|tt|tum|tw|ty|ug|uk|ur|uz|ve|vi|vk|vo|wa|war|wen|wo|xh|yi|yo|za|zh|zh-min-nan|zh-yue|zu';
  @param {Function} f A function which is called as
pg.re.interwiki=RegExp('^'+pg.wiki.interwiki+':');
  <code>f(x,y)</code>. It should return <code>true</code> when it
} else {
  wants to be removed, and <code>false</code> otherwise.
pg.wiki.interwiki=null;
*/
pg.re.interwiki=RegExp('^$');
Mousetracker.prototype.addHook = function (f) {
this.hooks.push(f);
};
 
/**
  Runs hooks, passing them the x
  and y coords of the mouse.  Hook functions that return true are
  passed to {@link Mousetracker#removeHooks} for removal.
  @private
*/
Mousetracker.prototype.runHooks = function () {
if (!this.hooks || !this.hooks.length) { return; }
//log('Mousetracker.runHooks; we got some hooks to run');
var remove=false;
var removeObj={};
// this method gets called a LOT -
// pre-cache some variables
var x=this.x, y=this.y, len = this.hooks.length;
 
for (var i=0; i<len; ++i) {
//~ run the hook function, and remove it if it returns true
if (this.hooks[i](x, y)===true) {
remove=true;
removeObj[i]=true;
}
}
}
}
if (remove) { this.removeHooks(removeObj); }
};
function nsRe(label) {
 
var l=upcaseFirst(label);
/**
return nsRegexString(pg.ns.list[pg.ns.index[l]], l);
  Removes hooks.
}
  @private
  @param {Object} removeObj An object whose keys are the index
function nsReImage() {
  numbers of functions for removal, with values that evaluate to true
var str = pg.ns.list[pg.ns.index["File"]];
*/
return '(?:' + str + '|' + encodeURI(str) + '|' + upcaseFirst(str) + '|Image|' + upcaseFirst('Image') + ')';
Mousetracker.prototype.removeHooks = function(removeObj) {
}
var newHooks=[];
var len = this.hooks.length;
function nsRegexString(str, extra) {
for (var i=0; i<len; ++i) {
return '(?:' + str + '|' + encodeURI(str) + (extra ? '|' + extra : '') + ')';
if (! removeObj[i]) { newHooks.push(this.hooks[i]); }
}
function nsRegex(str, extra) {
return RegExp(nsRegexString(str, extra));
}
// ENDFILE: namespaces.js
// STARTFILE: selpop.js
//<NOLITE>
function getEditboxSelection() {
// see http://www.webgurusforum.com/8/12/0
try {
var editbox=document.editform.wpTextbox1;
} catch (dang) { return; }
// IE, Opera
if (document.selection) { return document.selection.createRange().text; }
// Mozilla
var selStart = editbox.selectionStart;
var selEnd = editbox.selectionEnd;
return (editbox.value).substring(selStart, selEnd);
}
function doSelectionPopup() {
// popup if the selection looks like [[foo|anything afterwards at all
// or [[foo|bar]]text without ']]'
// or [[foo|bar]]
var sel=getEditboxSelection();
var open=sel.indexOf('[[');
var pipe=sel.indexOf('|');
var close=sel.indexOf(']]');
if (open == -1 || ( pipe == -1 && close == -1) ) { return; }
if (pipe != -1 && open > pipe || close != -1 && open > close) { return; }
if (getValueOf('popupOnEditSelection')=='boxpreview') {
return doSeparateSelectionPopup(sel);
}
}
var article=new Title(sel.substring(open+2, (pipe < 0) ? close : pipe)).urlString();
this.hooks=newHooks;
if (close > 0 && sel.substring(close+2).indexOf('[[') >= 0) {  
};
return;  
 
}
 
var a=document.createElement('a');
/**
a.href=pg.wiki.titlebase + article;
  Event handler for mouse wiggles.
mouseOverWikiLink2(a);
  We simply grab the event, set x and y and run the hooks.
if (a.navpopup) {
  This makes the cpu all hot and bothered :-(
a.navpopup.addHook(function(){runStopPopupTimer(a.navpopup);}, 'unhide', 'after');
  @private
  @param {Event} e Mousemove event
*/
Mousetracker.prototype.track=function (e) {
//~ Apparently this is needed in IE.
e = e || window.event;
var x, y;
if (e) {
if (e.pageX) { x=e.pageX; y=e.pageY; }
else if (typeof e.clientX!='undefined') {
var left, top, docElt = window.document.documentElement;
 
if (docElt) { left=docElt.scrollLeft; }
left = left || window.document.body.scrollLeft || window.document.scrollLeft || 0;
 
if (docElt) { top=docElt.scrollTop; }
top = top || window.document.body.scrollTop || window.document.scrollTop || 0;
 
x=e.clientX + left;
y=e.clientY + top;
} else { return; }
this.setPosition(x,y);
}
}
}
};
 
function doSeparateSelectionPopup(str) {
/**
var div=document.getElementById('selectionPreview');
  Sets the x and y coordinates stored and takes appropriate action,
if (!div) {
  running hooks as appropriate.
div = document.createElement('div');
  @param {Integer} x, y Screen coordinates to set
div.id='selectionPreview';
*/
try { var box=document.editform.wpTextbox1; }
 
catch (oopsie) { return; }
Mousetracker.prototype.setPosition=function(x,y) {
box.parentNode.insertBefore(div, box);
this.x = x;
this.y = y;
if (this.dirty || this.hooks.length === 0) { this.dirty=false; return; }
if (typeof this.lastHook_x != 'number') { this.lastHook_x = -100; this.lastHook_y=-100; }
var diff = (this.lastHook_x - x)*(this.lastHook_y - y);
diff = (diff >= 0) ? diff : -diff;
if ( diff > 1 ) {
this.lastHook_x=x;
this.lastHook_y=y;
if (this.dirty) { this.dirty = false; }
else { this.runHooks(); }
}
}
div.innerHTML=wiki2html(str);
div.ranSetupTooltipsAlready = false;
popTipsSoonFn('selectionPreview')();
}
}
//</NOLITE>
 
// ENDFILE: selpop.js
// STARTFILE: navpopup.js
/**
/**
   @fileoverview  Defines two classes: {@link Navpopup} and {@link Mousetracker}.
   Sets things in motion, unless they are already that is, registering an event handler on <code>document.onmousemove</code>.
  A half-hearted attempt is made to preserve the old event handler if there is one.
  <code>Navpopup</code> describes popups: when they appear, where, what
  they look like and so on.
  <code>Mousetracker</code> "captures" the mouse using
  <code>document.onmousemove</code>.
*/
*/
Mousetracker.prototype.enable = function () {
if (this.active) { return; }
this.active=true;
//~ Save the current handler for mousemove events. This isn't too
//~ robust, of course.
this.savedHandler=document.onmousemove;
//~ Gotta save @tt{this} again for the closure, and use apply for
//~ the member function.
var savedThis=this;
document.onmousemove=function (e) {savedThis.track.apply(savedThis, [e]);};
if (this.loopDelay) { this.timer = setInterval(function() { //log('loop delay in mousetracker is working');
    savedThis.runHooks();}, this.loopDelay); }
};
 
/**
/**
   Creates a new Mousetracker.
  Disables the tracker, removing the event handler.
*/
Mousetracker.prototype.disable = function () {
if (!this.active) { return; }
if (typeof this.savedHandler=='function') {
document.onmousemove=this.savedHandler;
} else { delete document.onmousemove; }
if (this.timer) { clearInterval(this.timer); }
this.active=false;
};
 
/**
   Creates a new Navpopup.
  Gets a UID for the popup and
  @param init Contructor object. If <code>init.draggable</code> is true or absent, the popup becomes draggable.
   @constructor
   @constructor
   @class The Mousetracker class. This monitors mouse movements and manages associated hooks.
   @class The Navpopup class. This generates popup hints, and does some management of them.
*/
*/
function Mousetracker() {
function Navpopup(init) {
/**
//alert('new Navpopup(init)');
  Interval to regularly run the hooks anyway, in milliseconds.
/** UID for each Navpopup instance.
  @type Integer
    Read-only.
    @type integer
*/
*/
this.loopDelay=400;
this.uid=Navpopup.uid++;
/**
/**
  Timer for the loop.
  Read-only flag for current visibility of the popup.
  @type Timer
  @type boolean
  @private
*/
*/
this.timer=null;
this.visible=false;
/** Flag to be set when we want to cancel a previous request to
/**
    show the popup in a little while.
  Flag - are we switched on?
    @private
  @type Boolean
    @type boolean
*/
this.noshow=false;
/** Categorised list of hooks.
    @see #runHooks
    @see #addHook
    @private
    @type Object
*/
this.hooks={
'create': [],
'unhide': [],
'hide': []
};
/** list of unique IDs of hook functions, to avoid duplicates
    @private
*/
this.hookIds={};
/** List of downloads associated with the popup.
    @private
    @type Array
*/
*/
this.active=false;
this.downloads=[];
/**
/** Number of uncompleted downloads.
  Flag - are we probably inaccurate, i.e. not reflecting the actual mouse position?
    @type integer
*/
*/
this.dirty=true;
this.pending=null;
/**
/** Tolerance in pixels when detecting whether the mouse has left the popup.
  Array of hook functions.
    @type integer
  @private
  @type Array
*/
*/
this.hooks=[];
this.fuzz=5;
}
/** Flag to toggle running {@link #limitHorizontalPosition} to regulate the popup's position.
    @type boolean
/**
*/
  Adds a hook, to be called when we get events.
this.constrained=true;
  @param {Function} f A function which is called as
/** The popup width in pixels.
  <code>f(x,y)</code>. It should return <code>true</code> when it
    @private
  wants to be removed, and <code>false</code> otherwise.
    @type integer
*/
*/
Mousetracker.prototype.addHook = function (f) {
this.width=0;
this.hooks.push(f);
/** The popup width in pixels.
};
    @private
    @type integer
/**
*/
   Runs hooks, passing them the x
this.height=0;
  and y coords of the mouse. Hook functions that return true are
/** The main content DIV element.
   passed to {@link Mousetracker#removeHooks} for removal.
    @type HTMLDivElement
*/
this.mainDiv=null;
this.createMainDiv();
 
// if (!init || typeof init.draggable=='undefined' || init.draggable) {
// this.makeDraggable(true);
// }
}
 
/**
   A UID for each Navpopup. This constructor property is just a counter.
   @type integer
   @private
   @private
*/
*/
Mousetracker.prototype.runHooks = function () {
Navpopup.uid=0;
if (!this.hooks || !this.hooks.length) { return; }
 
//log('Mousetracker.runHooks; we got some hooks to run');
/**
var remove=false;
  Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible.
var removeObj={};
  @type boolean
// this method gets called a LOT -
*/
// pre-cache some variables
Navpopup.prototype.isVisible=function() {
var x=this.x, y=this.y, len = this.hooks.length;
return this.visible;
for (var i=0; i<len; ++i) {
//~ run the hook function, and remove it if it returns true
if (this.hooks[i](x, y)===true) {
remove=true;
removeObj[i]=true;
}
}
if (remove) { this.removeHooks(removeObj); }
};
};
 
/**
/**
   Removes hooks.
   Repositions popup using CSS style.
   @private
   @private
   @param {Object} removeObj An object whose keys are the index
   @param {integer} x x-coordinate (px)
   numbers of functions for removal, with values that evaluate to true
   @param {integer} y y-coordinate (px)
  @param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition}
*/
*/
Mousetracker.prototype.removeHooks = function(removeObj) {
Navpopup.prototype.reposition= function (x,y, noLimitHor) {
var newHooks=[];
log ('reposition('+x+','+y+','+noLimitHor+')');
var len = this.hooks.length;
if (typeof x != 'undefined' && x!==null) { this.left=x; }
for (var i=0; i<len; ++i) {
if (typeof y != 'undefined' && y!==null) { this.top=y; }
if (! removeObj[i]) { newHooks.push(this.hooks[i]); }
if (typeof this.left != 'undefined' && typeof this.top != 'undefined') {
this.mainDiv.style.left=this.left + 'px';
this.mainDiv.style.top=this.top + 'px';
}
}
this.hooks=newHooks;
if (!noLimitHor) { this.limitHorizontalPosition(); }
//console.log('navpop'+this.uid+' - (left,top)=(' + this.left + ',' + this.top + '), css=('
//+ this.mainDiv.style.left + ',' + this.mainDiv.style.top + ')');
};
};
 
/**
/**
   Event handler for mouse wiggles.
   Prevents popups from being in silly locations. Hopefully.
   We simply grab the event, set x and y and run the hooks.
   Should not be run if {@link #constrained} is true.
  This makes the cpu all hot and bothered :-(
   @private
   @private
  @param {Event} e Mousemove event
*/
*/
Mousetracker.prototype.track=function (e) {
Navpopup.prototype.limitHorizontalPosition=function() {
//~ Apparently this is needed in IE.
if (!this.constrained || this.tooWide) { return; }
e = e || window.event;
this.updateDimensions();
var x, y;
var x=this.left;
if (e) {
var w=this.width;
if (e.pageX) { x=e.pageX; y=e.pageY; }
var cWidth=document.body.clientWidth;
else if (typeof e.clientX!='undefined') {
 
var left, top, docElt = window.document.documentElement;
 
// log('limitHorizontalPosition: x='+x+
if (docElt) { left=docElt.scrollLeft; }
//     ', this.left=' + this.left +
left = left || window.document.body.scrollLeft || window.document.scrollLeft || 0;
//     ', this.width=' + this.width +
//     ', cWidth=' + cWidth);
if (docElt) { top=docElt.scrollTop; }
 
top = top || window.document.body.scrollTop || window.document.scrollTop || 0;
 
if ( (x+w) >= cWidth ||
x=e.clientX + left;
    ( x > 0 && this.maxWidth && this.width < this.maxWidth && this.height > this.width
y=e.clientY + top;
      && x > cWidth - this.maxWidth ) ) {
} else { return; }
// This is a very nasty hack. There has to be a better way!
this.setPosition(x,y);
// We find the "natural" width of the div by positioning it at the far left
// then reset it so that it should be flush right (well, nearly)
this.mainDiv.style.left='-10000px';
this.mainDiv.style.width = this.maxWidth + 'px';
var naturalWidth=parseInt(this.mainDiv.offsetWidth, 10);
var newLeft=cWidth - naturalWidth - 1;
if (newLeft < 0) { newLeft = 0; this.tooWide=true; } // still unstable for really wide popups?
log ('limitHorizontalPosition: moving to ('+newLeft + ','+ this.top+');' + ' naturalWidth=' + naturalWidth + ', clientWidth=' + cWidth);
this.reposition(newLeft, null, true);
}
}
};
};
 
/**
/**
   Sets the x and y coordinates stored and takes appropriate action,
   Counter indicating the z-order of the "highest" popup.
   running hooks as appropriate.
   We start the z-index at 1000 so that popups are above everything
   @param {Integer} x, y Screen coordinates to set
  else on the screen.
   @private
  @type integer
*/
*/
Navpopup.highest=1000;
Mousetracker.prototype.setPosition=function(x,y) {
 
this.x = x;
this.y = y;
if (this.dirty || this.hooks.length === 0) { this.dirty=false; return; }
if (typeof this.lastHook_x != 'number') { this.lastHook_x = -100; this.lastHook_y=-100; }
var diff = (this.lastHook_x - x)*(this.lastHook_y - y);
diff = (diff >= 0) ? diff : -diff;
if ( diff > 1 ) {
this.lastHook_x=x;
this.lastHook_y=y;
if (this.dirty) { this.dirty = false; }
else { this.runHooks(); }
}
}
/**
/**
   Sets things in motion, unless they are already that is, registering an event handler on <code>document.onmousemove</code>.
   Brings popup to the top of the z-order.
   A half-hearted attempt is made to preserve the old event handler if there is one.
   We increment the {@link #highest} property of the contructor here.
  @private
*/
*/
Mousetracker.prototype.enable = function () {
Navpopup.prototype.raise = function () {
if (this.active) { return; }
this.mainDiv.style.zIndex=Navpopup.highest + 1;
this.active=true;
++Navpopup.highest;
//~ Save the current handler for mousemove events. This isn't too
};
//~ robust, of course.
 
this.savedHandler=document.onmousemove;
/**
//~ Gotta save @tt{this} again for the closure, and use apply for
  Shows the popup provided {@link #noshow} is not true.
//~ the member function.
  Updates the position, brings the popup to the top of the z-order and unhides it.
var savedThis=this;
*/
document.onmousemove=function (e) {savedThis.track.apply(savedThis, [e]);};
Navpopup.prototype.show = function () {
if (this.loopDelay) { this.timer = setInterval(function() { //log('loop delay in mousetracker is working');
//document.title+='s';
    savedThis.runHooks();}, this.loopDelay); }
if (this.noshow) { return; }
//document.title+='t';
this.reposition();
this.raise();
this.unhide();
};
};
 
 
/**
/**
   Disables the tracker, removing the event handler.
   Runs the {@link #show} method in a little while, unless we're
  already visible.
  @param {integer} time Delay in milliseconds
  @see #showSoonIfStable
*/
*/
Mousetracker.prototype.disable = function () {
Navpopup.prototype.showSoon = function (time) {
if (!this.active) { return; }
if (this.visible) { return; }
if (typeof this.savedHandler=='function') {
this.noshow=false;
document.onmousemove=this.savedHandler;
//~ We have to save the value of @tt{this} so that the closure below
} else { delete document.onmousemove; }
//~ works.
if (this.timer) { clearInterval(this.timer); }
var savedThis=this;
this.active=false;
//this.start_x = Navpopup.tracker.x;
//this.start_y = Navpopup.tracker.y;
setTimeout(function () {
if (Navpopup.tracker.active) {
savedThis.reposition.apply(savedThis, [Navpopup.tracker.x + 2, Navpopup.tracker.y + 2]);
}
//~ Have to use apply to invoke his member function here
savedThis.show.apply(savedThis, []);
}, time);
};
};
 
/**
/**
   Creates a new Navpopup.
   Checks to see if the mouse pointer has
  Gets a UID for the popup and
   stabilised (checking every <code>time</code>/2 milliseconds) and runs the
   @param init Contructor object. If <code>init.draggable</code> is true or absent, the popup becomes draggable.
   {@link #show} method if it has. This method makes {@link #showSoon} redundant.
   @constructor
   @param {integer} time The minimum time (ms) before the popup may be shown.
   @class The Navpopup class. This generates popup hints, and does some management of them.
*/
*/
function Navpopup(init) {
Navpopup.prototype.showSoonIfStable = function (time) {
//alert('new Navpopup(init)');
log ('showSoonIfStable, time='+time);
/** UID for each Navpopup instance.
if (this.visible) { return; }
    Read-only.
this.noshow = false;
    @type integer
 
*/
//~ initialize these variables so that we never run @tt{show} after
this.uid=Navpopup.uid++;
//~ just half the time
/**
this.stable_x = -10000; this.stable_y = -10000;
  Read-only flag for current visibility of the popup.
 
  @type boolean
var stableShow = function() {
  @private
log('stableShow called');
*/
var new_x = Navpopup.tracker.x, new_y = Navpopup.tracker.y;
this.visible=false;
var dx = savedThis.stable_x - new_x, dy = savedThis.stable_y - new_y;
/** Flag to be set when we want to cancel a previous request to
var fuzz2 = 0; // savedThis.fuzz * savedThis.fuzz;
    show the popup in a little while.
//document.title += '[' + [savedThis.stable_x,new_x, savedThis.stable_y,new_y, dx, dy, fuzz2].join(',') + '] ';
    @private
if ( dx * dx <= fuzz2 && dy * dy <= fuzz2 ) {
    @type boolean
log ('mouse is stable');
*/
clearInterval(savedThis.showSoonStableTimer);
savedThis.reposition.apply(savedThis, [new_x + 2, new_y + 2]);
savedThis.show.apply(savedThis, []);
return;
}
savedThis.stable_x = new_x; savedThis.stable_y = new_y;
};
var savedThis = this;
this.showSoonStableTimer = setInterval(stableShow, time/2);
};
 
/**
  Makes the popup unhidable until we call {@link #unstick}.
*/
Navpopup.prototype.stick=function() {
this.noshow=false;
this.noshow=false;
/** Categorised list of hooks.
this.sticky=true;
    @see #runHooks
};
    @see #addHook
 
    @private
    @type Object
*/
this.hooks={
'create': [],
'unhide': [],
'hide': []
};
/** list of unique IDs of hook functions, to avoid duplicates
    @private
*/
this.hookIds={};
/** List of downloads associated with the popup.
    @private
    @type Array
*/
this.downloads=[];
/** Number of uncompleted downloads.
    @type integer
*/
this.pending=null;
/** Tolerance in pixels when detecting whether the mouse has left the popup.
    @type integer
*/
this.fuzz=5;
/** Flag to toggle running {@link #limitHorizontalPosition} to regulate the popup's position.
    @type boolean
*/
this.constrained=true;
/** The popup width in pixels.
    @private
    @type integer
*/
this.width=0;
/** The popup width in pixels.
    @private
    @type integer
*/
this.height=0;
/** The main content DIV element.
    @type HTMLDivElement
*/
this.mainDiv=null;
this.createMainDiv();
// if (!init || typeof init.popups_draggable=='undefined' || init.popups_draggable) {
// this.makeDraggable(true);
// }
}
/**
/**
   A UID for each Navpopup. This constructor property is just a counter.
   Allows the popup to be hidden.
  @type integer
  @private
*/
*/
Navpopup.uid=0;
Navpopup.prototype.unstick=function() {
this.sticky=false;
};
 
/**
/**
   Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible.
   Sets the {@link #noshow} flag and hides the popup. This should be called
   @type boolean
   when the mouse leaves the link before
  (or after) it's actually been displayed.
*/
*/
Navpopup.prototype.isVisible=function() {
Navpopup.prototype.banish = function () {
return this.visible;
log ('banish called');
// hide and prevent showing with showSoon in the future
this.noshow=true;
if (this.showSoonStableTimer) {
log('clearing showSoonStableTimer');
clearInterval(this.showSoonStableTimer);
}
this.hide();
};
};
 
/**
/**
   Repositions popup using CSS style.
   Runs hooks added with {@link #addHook}.
   @private
   @private
   @param {integer} x x-coordinate (px)
   @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide'
  @param {integer} y y-coordinate (px)
   @param {String} when Controls exactly when the hook is run: either 'before' or 'after'
   @param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition}
*/
*/
Navpopup.prototype.reposition= function (x,y, noLimitHor) {
Navpopup.prototype.runHooks = function (key, when) {
log ('reposition('+x+','+y+','+noLimitHor+')');
if (!this.hooks[key]) { return; }
if (typeof x != 'undefined' && x!==null) { this.left=x; }
var keyHooks=this.hooks[key];
if (typeof y != 'undefined' && y!==null) { this.top=y; }
var len=keyHooks.length;
if (typeof this.left != 'undefined' && typeof this.top != 'undefined') {
for (var i=0; i< len; ++i) {
this.mainDiv.style.left=this.left + 'px';
if (keyHooks[i] && keyHooks[i].when == when) {
this.mainDiv.style.top=this.top + 'px';
if (keyHooks[i].hook.apply(this, [])) {
// remove the hook
if (keyHooks[i].hookId) {
delete this.hookIds[keyHooks[i].hookId];
}
keyHooks[i]=null;
}
}
}
}
if (!noLimitHor) { this.limitHorizontalPosition(); }
//console.log('navpop'+this.uid+' - (left,top)=(' + this.left + ',' + this.top + '), css=('
//+ this.mainDiv.style.left + ',' + this.mainDiv.style.top + ')');
};
};
 
/**
/**
   Prevents popups from being in silly locations. Hopefully.
   Adds a hook to the popup. Hook functions are run with <code>this</code> set to refer to the Navpopup instance, and no arguments.
   Should not be run if {@link #constrained} is true.
  @param {Function} hook The hook function. Functions that return true are deleted.
   @private
   @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide'
  @param {String} when Controls exactly when the hook is run: either 'before' or 'after'
   @param {String} uid A truthy string identifying the hook function; if it matches another hook in this position, it won't be added again.
*/
*/
Navpopup.prototype.limitHorizontalPosition=function() {
Navpopup.prototype.addHook = function ( hook, key, when, uid ) {
if (!this.constrained || this.tooWide) { return; }
when = when || 'after';
this.updateDimensions();
if (!this.hooks[key]) { return; }
var x=this.left;
// if uid is specified, don't add duplicates
var w=this.width;
var hookId=null;
var cWidth=document.body.clientWidth;
if (uid) {
hookId=[key,when,uid].join('|');
if (this.hookIds[hookId]) {
// log('limitHorizontalPosition: x='+x+
return;
//     ', this.left=' + this.left +
}
//     ', this.width=' + this.width +
this.hookIds[hookId]=true;
//     ', cWidth=' + cWidth);
if ( (x+w) >= cWidth ||
    ( x > 0 && this.maxWidth && this.width < this.maxWidth && this.height > this.width
      && x > cWidth - this.maxWidth ) ) {
// This is a very nasty hack. There has to be a better way!
// We find the "natural" width of the div by positioning it at the far left
// then reset it so that it should be flush right (well, nearly)
this.mainDiv.style.left='-10000px';
this.mainDiv.style.width = this.maxWidth + 'px';
var naturalWidth=parseInt(this.mainDiv.offsetWidth, 10);
var newLeft=cWidth - naturalWidth - 1;
if (newLeft < 0) { newLeft = 0; this.tooWide=true; } // still unstable for really wide popups?
log ('limitHorizontalPosition: moving to ('+newLeft + ','+ this.top+');' + ' naturalWidth=' + naturalWidth + ', clientWidth=' + cWidth);
this.reposition(newLeft, null, true);
}
}
this.hooks[key].push( {hook: hook, when: when, hookId: hookId} );
};
};
 
/**
/**
   Counter indicating the z-order of the "highest" popup.
   Creates the main DIV element, which contains all the actual popup content.
   We start the z-index at 1000 so that popups are above everything
   Runs hooks with key 'create'.
  else on the screen.
   @private
   @private
  @type integer
*/
*/
Navpopup.highest=1000;
Navpopup.prototype.createMainDiv = function () {
if (this.mainDiv) { return; }
/**
this.runHooks('create', 'before');
  Brings popup to the top of the z-order.
var mainDiv=document.createElement('div');
  We increment the {@link #highest} property of the contructor here.
 
  @private
var savedThis=this;
*/
mainDiv.onclick=function(e) {savedThis.onclickHandler(e);};
Navpopup.prototype.raise = function () {
mainDiv.className=(this.className) ? this.className : 'navpopup_maindiv';
this.mainDiv.style.zIndex=Navpopup.highest + 1;
mainDiv.id=mainDiv.className + this.uid;
++Navpopup.highest;
 
mainDiv.style.position='absolute';
mainDiv.style.display='none';
mainDiv.className='navpopup';
 
// easy access to javascript object through DOM functions
mainDiv.navpopup=this;
 
this.mainDiv=mainDiv;
document.body.appendChild(mainDiv);
this.runHooks('create', 'after');
};
};
/**
/**
   Shows the popup provided {@link #noshow} is not true.
   Calls the {@link #raise} method.
   Updates the position, brings the popup to the top of the z-order and unhides it.
   @private
*/
*/
Navpopup.prototype.show = function () {
Navpopup.prototype.onclickHandler=function(e) {
//document.title+='s';
if (this.noshow) { return; }
//document.title+='t';
this.reposition();
this.raise();
this.raise();
this.unhide();
};
};
/**
/**
   Runs the {@link #show} method in a little while, unless we're
   Makes the popup draggable, using a {@link Drag} object.
  already visible.
   @private
   @param {integer} time Delay in milliseconds
  @see #showSoonIfStable
*/
*/
Navpopup.prototype.showSoon = function (time) {
Navpopup.prototype.makeDraggable=function(handleName) {
if (this.visible) { return; }
if (!this.mainDiv) { this.createMainDiv(); }
this.noshow=false;
var drag=new Drag();
//~ We have to save the value of @tt{this} so that the closure below
if (!handleName) {
//~ works.
    drag.startCondition=function(e) {
var savedThis=this;
try { if (!e.shiftKey) { return false; } } catch (err) { return false; }
//this.start_x = Navpopup.tracker.x;
return true;
//this.start_y = Navpopup.tracker.y;
    };
setTimeout(function () {
}
if (Navpopup.tracker.active) {
var dragHandle = document.getElementById(handleName) || this.mainDiv;
savedThis.reposition.apply(savedThis, [Navpopup.tracker.x + 2, Navpopup.tracker.y + 2]);
var np=this;
}
drag.endHook=function(x,y) {
//~ Have to use apply to invoke his member function here
Navpopup.tracker.dirty=true;
savedThis.show.apply(savedThis, []);
np.reposition(x,y);
}, time);
};
drag.init(dragHandle,this.mainDiv);
};
 
/** Hides the popup using CSS. Runs hooks with key 'hide'.
    Sets {@link #visible} appropriately.    {@link #banish} should be called externally instead of this method.
 
    @private
*/
Navpopup.prototype.hide = function () {
this.runHooks('hide', 'before');
this.abortDownloads();
if (this.sticky) { return; }
if (typeof this.visible != 'undefined' && this.visible) {
this.mainDiv.style.display='none';
this.visible=false;
}
this.runHooks('hide', 'after');
};
 
/** Shows the popup using CSS. Runs hooks with key 'unhide'.
    Sets {@link #visible} appropriately.  {@link #show} should be called externally instead of this method.
    @private
*/
Navpopup.prototype.unhide = function () {
this.runHooks('unhide', 'before');
if (typeof this.visible != 'undefined' && !this.visible) {
this.mainDiv.style.display='inline';
this.visible=true;
}
this.runHooks('unhide', 'after');
};
};
 
/**
/**
   Checks to see if the mouse pointer has
   Sets the <code>innerHTML</code> attribute of the main div containing the popup content.
  stabilised (checking every <code>time</code>/2 milliseconds) and runs the
   @param {String} html The HTML to set.
  {@link #show} method if it has. This method makes {@link #showSoon} redundant.
   @param {integer} time The minimum time (ms) before the popup may be shown.
*/
*/
Navpopup.prototype.showSoonIfStable = function (time) {
Navpopup.prototype.setInnerHTML = function (html) {
log ('showSoonIfStable, time='+time);
this.mainDiv.innerHTML = html;
if (this.visible) { return; }
this.noshow = false;
//~ initialize these variables so that we never run @tt{show} after
//~ just half the time
this.stable_x = -10000; this.stable_y = -10000;
var stableShow = function() {
log('stableShow called');
var new_x = Navpopup.tracker.x, new_y = Navpopup.tracker.y;
var dx = savedThis.stable_x - new_x, dy = savedThis.stable_y - new_y;
var fuzz2 = 0; // savedThis.fuzz * savedThis.fuzz;
//document.title += '[' + [savedThis.stable_x,new_x, savedThis.stable_y,new_y, dx, dy, fuzz2].join(',') + '] ';
if ( dx * dx <= fuzz2 && dy * dy <= fuzz2 ) {
log ('mouse is stable');
clearInterval(savedThis.showSoonStableTimer);
savedThis.reposition.apply(savedThis, [new_x + 2, new_y + 2]);
savedThis.show.apply(savedThis, []);
return;
}
savedThis.stable_x = new_x; savedThis.stable_y = new_y;
};
var savedThis = this;
this.showSoonStableTimer = setInterval(stableShow, time/2);
};
};
 
/**
/**
   Makes the popup unhidable until we call {@link #unstick}.
   Updates the {@link #width} and {@link #height} attributes with the CSS properties.
  @private
*/
*/
Navpopup.prototype.stick=function() {
Navpopup.prototype.updateDimensions = function () {
this.noshow=false;
this.width=parseInt(this.mainDiv.offsetWidth, 10);
this.sticky=true;
this.height=parseInt(this.mainDiv.offsetHeight, 10);
};
};
 
/**
/**
   Allows the popup to be hidden.
   Checks if the point (x,y) is within {@link #fuzz} of the
  {@link #mainDiv}.
  @param {integer} x x-coordinate (px)
  @param {integer} y y-coordinate (px)
  @type boolean
*/
*/
Navpopup.prototype.unstick=function() {
Navpopup.prototype.isWithin = function(x,y) {
this.sticky=false;
//~ If we're not even visible, no point should be considered as
//~ being within the popup.
if (!this.visible) { return false; }
this.updateDimensions();
var fuzz=this.fuzz || 0;
//~ Use a simple box metric here.
return (x+fuzz >= this.left && x-fuzz <= this.left + this.width &&
y+fuzz >= this.top  && y-fuzz <= this.top  + this.height);
};
};
 
/**
/**
   Sets the {@link #noshow} flag and hides the popup. This should be called
   Adds a download to {@link #downloads}.
   when the mouse leaves the link before
   @param {Downloader} download
  (or after) it's actually been displayed.
*/
*/
Navpopup.prototype.banish = function () {
Navpopup.prototype.addDownload=function(download) {
log ('banish called');
if (!download) { return; }
// hide and prevent showing with showSoon in the future
this.downloads.push(download);
this.noshow=true;
if (this.showSoonStableTimer) {
log('clearing showSoonStableTimer');
clearInterval(this.showSoonStableTimer);
}
this.hide();
};
};
/**
/**
   Runs hooks added with {@link #addHook}.
   Aborts the downloads listed in {@link #downloads}.
   @private
   @see Downloader#abort
  @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide'
  @param {String} when Controls exactly when the hook is run: either 'before' or 'after'
*/
*/
Navpopup.prototype.runHooks = function (key, when) {
Navpopup.prototype.abortDownloads=function() {
if (!this.hooks[key]) { return; }
for(var i=0; i<this.downloads.length; ++i) {
var keyHooks=this.hooks[key];
var d=this.downloads[i];
var len=keyHooks.length;
if (d && d.abort) { d.abort(); }
for (var i=0; i< len; ++i) {
if (keyHooks[i] && keyHooks[i].when == when) {
if (keyHooks[i].hook.apply(this, [])) {
// remove the hook
if (keyHooks[i].hookId) {
delete this.hookIds[keyHooks[i].hookId];
}
keyHooks[i]=null;
}
}
}
}
this.downloads=[];
};
};
 
 
/**
/**
   Adds a hook to the popup. Hook functions are run with <code>this</code> set to refer to the Navpopup instance, and no arguments.
   A {@link Mousetracker} instance which is a property of the constructor (pseudo-global).
  @param {Function} hook The hook function. Functions that return true are deleted.
  @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide'
  @param {String} when Controls exactly when the hook is run: either 'before' or 'after'
  @param {String} uid A truthy string identifying the hook function; if it matches another hook in this position, it won't be added again.
*/
*/
Navpopup.prototype.addHook = function ( hook, key, when, uid ) {
Navpopup.tracker=new Mousetracker();
when = when || 'after';
// ENDFILE: navpopup.js
if (!this.hooks[key]) { return; }
// STARTFILE: diff.js
// if uid is specified, don't add duplicates
//<NOLITE>
var hookId=null;
/*
if (uid) {
* Javascript Diff Algorithm
hookId=[key,when,uid].join('|');
*  By John Resig (http://ejohn.org/) and [[:en:User:Lupin]]
if (this.hookIds[hookId]) {
*
return;
* More Info:
*  http://ejohn.org/projects/javascript-diff-algorithm/
*/
 
function delFmt(x) {
if (!x.length) { return ''; }
return "<del class='popupDiff'>" + x.join('').split('\n').join('&para;\n') +"</del>";
}
function insFmt(x) {
if (!x.length) { return ''; }
return "<ins class='popupDiff'>" + x.join('').split('\n').join('&para;\n') +"</ins>";
}
 
function countCrossings(a, b, i, eject) {
// count the crossings on the edge starting at b[i]
if (!b[i].row && b[i].row !== 0) { return -1; }
var count=0;
for (var j=0; j<a.length; ++j) {
if (!a[j].row && a[j].row !== 0) { continue; }
if ( (j-b[i].row)*(i-a[j].row) > 0) {
if(eject) { return true; }
count++;
}
}
this.hookIds[hookId]=true;
}
}
this.hooks[key].push( {hook: hook, when: when, hookId: hookId} );
return count;
};
}
 
/**
function shortenDiffString(str, context) {
  Creates the main DIV element, which contains all the actual popup content.
var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)');
  Runs hooks with key 'create'.
var splitted=str.parenSplit(re);
  @private
var ret=[''];
*/
for (var i=0; i<splitted.length; i+=2) {
Navpopup.prototype.createMainDiv = function () {
if (splitted[i].length < 2*context) {
if (this.mainDiv) { return; }
ret[ret.length-1] += splitted[i];
this.runHooks('create', 'before');
if (i+1<splitted.length) { ret[ret.length-1] += splitted[i+1]; }
var mainDiv=document.createElement('div');
continue;
}
var savedThis=this;
else {
mainDiv.onclick=function(e) {savedThis.onclickHandler(e);};
if (i > 0) { ret[ret.length-1] += splitted[i].substring(0,context); }
mainDiv.className=(this.className) ? this.className : 'navpopup_maindiv';
if (i+1 < splitted.length) {
mainDiv.id=mainDiv.className + this.uid;
    ret.push(splitted[i].substring(splitted[i].length-context) +
    splitted[i+1]);
mainDiv.style.position='absolute';
}
mainDiv.style.display='none';
}
mainDiv.className='navpopup';
// easy access to javascript object through DOM functions
mainDiv.navpopup=this;
this.mainDiv=mainDiv;
document.body.appendChild(mainDiv);
this.runHooks('create', 'after');
};
/**
  Calls the {@link #raise} method.
  @private
*/
Navpopup.prototype.onclickHandler=function(e) {
this.raise();
};
/**
  Makes the popup draggable, using a {@link Drag} object.
  @private
*/
Navpopup.prototype.makeDraggable=function(handleName) {
if (!this.mainDiv) { this.createMainDiv(); }
var drag=new Drag();
if (!handleName) {
    drag.startCondition=function(e) {
try { if (!e.shiftKey) { return false; } } catch (err) { return false; }
return true;
    };
}
}
var dragHandle = document.getElementById(handleName) || this.mainDiv;
while (ret.length > 0 && !ret[0]) { ret = ret.slice(1); }
var np=this;
return ret;
drag.endHook=function(x,y) {
}
Navpopup.tracker.dirty=true;
 
np.reposition(x,y);
 
};
function diffString( o, n, simpleSplit ) {
drag.init(dragHandle,this.mainDiv);
var splitRe=RegExp('([[]{2}|[\]]{2}|[{]{2,3}|[}]{2,3}|[|]|=|[*:]+|\\s|\\b)');
};
 
o=o.entify(); n=n.entify();
/** Hides the popup using CSS. Runs hooks with key 'hide'.
var out, i;
    Sets {@link #visible} appropriately.    {@link #banish} should be called externally instead of this method.
if (simpleSplit) { out = diff( o.split(/\b/), n.split(/\b/) ); }
else { out = diff( o.parenSplit(splitRe), n.parenSplit(splitRe) ); }
    @private
var str = "";
*/
var acc=[]; // accumulator for prettier output
Navpopup.prototype.hide = function () {
 
this.runHooks('hide', 'before');
// crossing pairings -- eg 'A B' vs 'B A' -- cause problems, so let's iron them out
this.abortDownloads();
// this doesn't always do things optimally but it should be fast enough
if (this.sticky) { return; }
var maxOutputPair=0;
if (typeof this.visible != 'undefined' && this.visible) {
for (i=0; i<out.n.length; ++i) {
this.mainDiv.style.display='none';
    if ( out.n[i].paired ) {
this.visible=false;
if( maxOutputPair > out.n[i].row ) {
    // tangle - delete pairing
    out.o[ out.n[i].row ]=out.o[ out.n[i].row ].text;
    out.n[i]=out.n[i].text;
}
if (maxOutputPair < out.n[i].row) { maxOutputPair = out.n[i].row; }
    }
}
}
this.runHooks('hide', 'after');
 
};
// output the stuff preceding the first paired old line
for (i=0; i<out.o.length && !out.o[i].paired; ++i) { acc.push( out.o[i] ); }
/** Shows the popup using CSS. Runs hooks with key 'unhide'.
str += delFmt(acc); acc=[];
    Sets {@link #visible} appropriately.  {@link #show} should be called externally instead of this method.
 
    @private
// main loop
*/
for ( i = 0; i < out.n.length; ++i ) {
Navpopup.prototype.unhide = function () {
// output unpaired new "lines"
this.runHooks('unhide', 'before');
while ( i < out.n.length && !out.n[i].paired ) { acc.push( out.n[i++] ); }
if (typeof this.visible != 'undefined' && !this.visible) {
str += insFmt(acc); acc=[];
this.mainDiv.style.display='inline';
if ( i < out.n.length ) { // this new "line" is paired with the (out.n[i].row)th old "line"
this.visible=true;
str += out.n[i].text;
}
// output unpaired old rows starting after this new line's partner
this.runHooks('unhide', 'after');
var m = out.n[i].row + 1;
};
while ( m < out.o.length && !out.o[m].paired ) { acc.push ( out.o[m++] ); }
str += delFmt(acc); acc=[];
/**
}
  Sets the <code>innerHTML</code> attribute of the main div containing the popup content.
}
  @param {String} html The HTML to set.
return str;
*/
}
Navpopup.prototype.setInnerHTML = function (html) {
 
this.mainDiv.innerHTML = html;
// see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object
};
// FIXME: use obj.hasOwnProperty instead of this kludge!
window.jsReservedProperties=RegExp('^(constructor|prototype|__((define|lookup)[GS]etter)__' +
/**
  '|eval|hasOwnProperty|propertyIsEnumerable' +
  Updates the {@link #width} and {@link #height} attributes with the CSS properties.
  '|to(Source|String|LocaleString)|(un)?watch|valueOf)$');
  @private
function diffBugAlert(word) {
*/
if (!diffBugAlert.list[word]) {
Navpopup.prototype.updateDimensions = function () {
diffBugAlert.list[word]=1;
this.width=parseInt(this.mainDiv.offsetWidth, 10);
alert('Bad word: '+word+'\n\nPlease report this bug.');
this.height=parseInt(this.mainDiv.offsetHeight, 10);
}
};
}
diffBugAlert.list={};
/**
 
  Checks if the point (x,y) is within {@link #fuzz} of the
function makeDiffHashtable(src) {
  {@link #mainDiv}.
var ret={};
  @param {integer} x x-coordinate (px)
for ( var i = 0; i < src.length; i++ ) {
  @param {integer} y y-coordinate (px)
if ( jsReservedProperties.test(src[i]) ) { src[i] += '<!-- -->'; }
  @type boolean
if ( !ret[ src[i] ] ) { ret[ src[i] ] = []; }
*/
try { ret[ src[i] ].push( i ); } catch (err) { diffBugAlert(src[i]); }
Navpopup.prototype.isWithin = function(x,y) {
}
//~ If we're not even visible, no point should be considered as
return ret;
//~ being within the popup.
}
if (!this.visible) { return false; }
 
this.updateDimensions();
function diff( o, n ) {
var fuzz=this.fuzz || 0;
 
//~ Use a simple box metric here.
// pass 1: make hashtable ns with new rows as keys
return (x+fuzz >= this.left && x-fuzz <= this.left + this.width &&
var ns = makeDiffHashtable(n);
y+fuzz >= this.top  && y-fuzz <= this.top  + this.height);
 
};
// pass 2: make hashtable os with old rows as keys
var os = makeDiffHashtable(o);
/**
 
  Adds a download to {@link #downloads}.
// pass 3: pair unique new rows and matching unique old rows
  @param {Downloader} download
var i;
*/
for ( i in ns ) {
Navpopup.prototype.addDownload=function(download) {
if ( ns[i].length == 1 && os[i] && os[i].length == 1 ) {
if (!download) { return; }
n[ ns[i][0] ] = { text: n[ ns[i][0] ], row: os[i][0], paired: true };
this.downloads.push(download);
o[ os[i][0] ] = { text: o[ os[i][0] ], row: ns[i][0], paired: true };
};
}
/**
  Aborts the downloads listed in {@link #downloads}.
  @see Downloader#abort
*/
Navpopup.prototype.abortDownloads=function() {
for(var i=0; i<this.downloads.length; ++i) {
var d=this.downloads[i];
if (d && d.abort) { d.abort(); }
}
}
this.downloads=[];
 
};
// pass 4: pair matching rows immediately following paired rows (not necessarily unique)
for ( i = 0; i < n.length - 1; i++ ) {
if ( n[i].paired && ! n[i+1].paired && n[i].row + 1 < o.length && ! o[ n[i].row + 1 ].paired &&
/**
    n[i+1] == o[ n[i].row + 1 ] ) {
  A {@link Mousetracker} instance which is a property of the constructor (pseudo-global).
n[i+1] = { text: n[i+1], row: n[i].row + 1, paired: true };
*/
o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1, paired: true };
Navpopup.tracker=new Mousetracker();
// ENDFILE: navpopup.js
// STARTFILE: diff.js
//<NOLITE>
/*
* Javascript Diff Algorithm
*  By John Resig (http://ejohn.org/) and [[:en:User:Lupin]]
*
* More Info:
*  http://ejohn.org/projects/javascript-diff-algorithm/
*/
function delFmt(x) {
if (!x.length) { return ''; }
return "<del class='popupDiff'>" + x.join('') +"</del>";
}
function insFmt(x) {
if (!x.length) { return ''; }
return "<ins class='popupDiff'>" + x.join('') +"</ins>";
}
function countCrossings(a, b, i, eject) {
// count the crossings on the edge starting at b[i]
if (!b[i].row && b[i].row !== 0) { return -1; }
var count=0;
for (var j=0; j<a.length; ++j) {
if (!a[j].row && a[j].row !== 0) { continue; }
if ( (j-b[i].row)*(i-a[j].row) > 0) {
if(eject) { return true; }
count++;
}
}
}
}
return count;
 
}
// pass 5: pair matching rows immediately preceding paired rows (not necessarily unique)
for ( i = n.length - 1; i > 0; i-- ) {
function shortenDiffString(str, context) {
if ( n[i].paired && ! n[i-1].paired && n[i].row > 0 && ! o[ n[i].row - 1 ].paired &&
var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)');
    n[i-1] == o[ n[i].row - 1 ] ) {
var splitted=str.parenSplit(re);
n[i-1] = { text: n[i-1], row: n[i].row - 1, paired: true };
var ret=[''];
o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1, paired: true };
for (var i=0; i<splitted.length; i+=2) {
if (splitted[i].length < 2*context) {
ret[ret.length-1] += splitted[i];
if (i+1<splitted.length) { ret[ret.length-1] += splitted[i+1]; }
continue;
}
else {
if (i > 0) { ret[ret.length-1] += splitted[i].substring(0,context); }
if (i+1 < splitted.length) {
    ret.push(splitted[i].substring(splitted[i].length-context) +
    splitted[i+1]);
}
}
}
}
}
while (ret.length > 0 && !ret[0]) { ret = ret.slice(1); }
 
return ret;
return { o: o, n: n };
}
}
//</NOLITE>
// ENDFILE: diff.js
function diffString( o, n, simpleSplit ) {
// STARTFILE: init.js
var splitRe=RegExp('([[]{2}|[\]]{2}|[{]{2,3}|[}]{2,3}|[|]|=|[*:]+|\\s|\\b)');
function setSiteInfo() {
if (window.popupLocalDebug) {
o=o.entify(); n=n.entify();
pg.wiki.hostname = 'en.wikipedia.org';
var out, i;
} else {
if (simpleSplit) { out = diff( o.split(/\b/), n.split(/\b/) ); }
pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?)
else { out = diff( o.parenSplit(splitRe), n.parenSplit(splitRe) ); }
var str = "";
var acc=[]; // accumulator for prettier output
// crossing pairings -- eg 'A B' vs 'B A' -- cause problems, so let's iron them out
// this doesn't always do things optimally but it should be fast enough
var maxOutputPair=0;
for (i=0; i<out.n.length; ++i) {
    if ( out.n[i].paired ) {
if( maxOutputPair > out.n[i].row ) {
    // tangle - delete pairing
    out.o[ out.n[i].row ]=out.o[ out.n[i].row ].text;
    out.n[i]=out.n[i].text;
}
if (maxOutputPair < out.n[i].row) { maxOutputPair = out.n[i].row; }
    }
}
}
pg.wiki.wikimedia=RegExp('(wiki([pm]edia|source|books|news|quote|versity)|wiktionary)[.]org').test(pg.wiki.hostname);
// output the stuff preceding the first paired old line
pg.wiki.wikia=RegExp('[.]wikia[.]com$', 'i').test(pg.wiki.hostname);
for (i=0; i<out.o.length && !out.o[i].paired; ++i) { acc.push( out.o[i] ); }
pg.wiki.isLocal=RegExp('^localhost').test(pg.wiki.hostname);
str += delFmt(acc); acc=[];
pg.wiki.commons=( pg.wiki.wikimedia && pg.wiki.hostname != 'commons.wikimedia.org') ? 'commons.wikimedia.org' : null;
pg.wiki.commonslang = pg.wiki.commons ? pg.wiki.commons.split('.')[0] : null;
// main loop
pg.wiki.lang = pg.wiki.hostname.split('.')[0];
for ( i = 0; i < out.n.length; ++i ) {
// toolDbName needs pg.wiki.lang and pg.wiki.hostname
// output unpaired new "lines"
window.toolDbName && (pg.wiki.userNameCookie=toolDbName(true) + 'UserName');
while ( i < out.n.length && !out.n[i].paired ) { acc.push( out.n[i++] ); }
pg.wiki.prePath='';
str += insFmt(acc); acc=[];
if (pg.wiki.hostname == 'secure.wikimedia.org') {
if ( i < out.n.length ) { // this new "line" is paired with the (out.n[i].row)th old "line"
    var s=document.location.href.split('/');
str += out.n[i].text;
    pg.wiki.prePath=s.slice(3,5).join('/');
// output unpaired old rows starting after this new line's partner
    pg.wiki.lang=s[4];
var m = out.n[i].row + 1;
while ( m < out.o.length && !out.o[m].paired ) { acc.push ( out.o[m++] ); }
str += delFmt(acc); acc=[];
}
}
}
return str;
var port = location.port ? ':' + location.port : '';
pg.wiki.sitebase = joinPath([pg.wiki.hostname + port, pg.wiki.prePath]);
}
}
 
// see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object
function getArticlePath() {
// FIXME: use obj.hasOwnProperty instead of this kludge!
if (isFunction(window.siteArticlePath)) {
window.jsReservedProperties=RegExp('^(constructor|prototype|__((define|lookup)[GS]etter)__' +
return siteArticlePath();
  '|eval|hasOwnProperty|propertyIsEnumerable' +
  '|to(Source|String|LocaleString)|(un)?watch|valueOf)$');
function diffBugAlert(word) {
if (!diffBugAlert.list[word]) {
diffBugAlert.list[word]=1;
alert('Bad word: '+word+'\n\nPlease report this bug.');
}
}
return 'wiki';
}
}
diffBugAlert.list={};
 
function getBotInterfacePath() {
function makeDiffHashtable(src) {
if (isFunction(window.siteBotInterfacePath)) {
var ret={};
return siteBotInterfacePath();
for ( var i = 0; i < src.length; i++ ) {
if ( jsReservedProperties.test(src[i]) ) { src[i] += '<!-- -->'; }
if ( !ret[ src[i] ] ) { ret[ src[i] ] = []; }
try { ret[ src[i] ].push( i ); } catch (err) { diffBugAlert(src[i]); }
}
}
return ret;
var botInterfacePath = pg.wiki.articlePath.replace(/\/index[.]php$/, '');
if (pg.wiki.wikimedia) { botInterfacePath = 'w'; } // as in http://some.thing.com/w/index.php?title=foo
else if (pg.wiki.wikia) { botInterfacePath = ''; }
return botInterfacePath;
}
}
 
function diff( o, n ) {
function setTitleBase() {
var protocol = ( window.popupLocalDebug ? 'http:' : location.protocol );
// pass 1: make hashtable ns with new rows as keys
pg.wiki.articlePath = getArticlePath();  // as in http://some.thing.com/wiki/Article
var ns = makeDiffHashtable(n);
pg.wiki.botInterfacePath = getBotInterfacePath();
   
// default mediawiki setting is paths like http://some.thing.com/articlePath/index.php?title=foo
// pass 2: make hashtable os with old rows as keys
 
var os = makeDiffHashtable(o);
var titletail = joinPath([pg.wiki.botInterfacePath, 'index.php?title=']);
var titletail2 = joinPath([pg.wiki.botInterfacePath, 'wiki.phtml?title=']);
// pass 3: pair unique new rows and matching unique old rows
 
var i;
// other sites may need to add code here to set titletail depending on how their urls work
for ( i in ns ) {
 
if ( ns[i].length == 1 && os[i] && os[i].length == 1 ) {
pg.wiki.titlebase  = protocol + '//' + joinPath([pg.wiki.sitebase, titletail]);
n[ ns[i][0] ] = { text: n[ ns[i][0] ], row: os[i][0], paired: true };
pg.wiki.titlebase2 = protocol + '//' + joinPath([pg.wiki.sitebase, titletail2]);
o[ os[i][0] ] = { text: o[ os[i][0] ], row: ns[i][0], paired: true };
pg.wiki.wikibase    = protocol + '//' + joinPath([pg.wiki.sitebase, pg.wiki.botInterfacePath]);
}
pg.wiki.articlebase = protocol + '//' + joinPath([pg.wiki.sitebase, pg.wiki.articlePath]);
}
pg.re.basenames = RegExp( '^(' +
   
  map( literalizeRegex, [ pg.wiki.titlebase, pg.wiki.titlebase2,
// pass 4: pair matching rows immediately following paired rows (not necessarily unique)
  pg.wiki.articlebase ]).join('|') + ')' );
for ( i = 0; i < n.length - 1; i++ ) {
}
if ( n[i].paired && ! n[i+1].paired && n[i].row + 1 < o.length && ! o[ n[i].row + 1 ].paired &&
 
    n[i+1] == o[ n[i].row + 1 ] ) {
 
n[i+1] = { text: n[i+1], row: n[i].row + 1, paired: true };
//////////////////////////////////////////////////
o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1, paired: true };
// Global regexps
}
 
}
function setMainRegex() {
var reStart='[^:]*://';
// pass 5: pair matching rows immediately preceding paired rows (not necessarily unique)
var preTitles = joinPath([literalizeRegex(pg.wiki.botInterfacePath), '(?:index[.]php|wiki[.]phtml)[?]title=']);
for ( i = n.length - 1; i > 0; i-- ) {
// slightly ugly hack when pg.wiki.articlePath is empty
if ( n[i].paired && ! n[i-1].paired && n[i].row > 0 && ! o[ n[i].row - 1 ].paired &&
preTitles += '|' + literalizeRegex( ( pg.wiki.articlePath ? pg.wiki.articlePath + '/' : ''));
    n[i-1] == o[ n[i].row - 1 ] ) {
 
n[i-1] = { text: n[i-1], row: n[i].row - 1, paired: true };
var reEnd='/(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?';
o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1, paired: true };
pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd);
}
}
return { o: o, n: n };
}
}
//</NOLITE>
 
// ENDFILE: diff.js
function setRegexps() {
// STARTFILE: init.js
setMainRegex();
function setSiteInfo() {
var sp=nsRe('Special');
if (window.popupLocalDebug) {
pg.re.urlNoPopup=RegExp('((title=|/)' + sp +  '(?:%3A|:)|section=[0-9])') ;
pg.wiki.hostname = 'en.wikipedia.org';
pg.re.contribs  =RegExp('(title=|/)'  + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + pg.ns.user+':)(.*)') ;
} else {
pg.re.email    =RegExp('(title=|/)'  + sp + '(?:%3A|:)Emailuser'     + '(&target=|/|/(?:' + pg.ns.user+':)?)(.*)') ;
pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?)
pg.re.backlinks =RegExp('(title=|/)'  + sp + '(?:%3A|:)Whatlinkshere' + '(&target=|/)([^&]*)');
}
 
pg.wiki.wikimedia=RegExp('(wiki([pm]edia|source|books|news|quote|versity)|wiktionary|mediawiki)[.]org').test(pg.wiki.hostname);
//<NOLITE>
pg.wiki.wikia=RegExp('[.]wikia[.]com$', 'i').test(pg.wiki.hostname);
var im=nsRe('Image');
pg.wiki.isLocal=RegExp('^localhost').test(pg.wiki.hostname);
// note: tries to get images in infobox templates too, e.g. movie pages, album pages etc
pg.wiki.commons=( pg.wiki.wikimedia && pg.wiki.hostname != 'commons.wikimedia.org') ? 'commons.wikimedia.org' : null;
//                      (^|\[\[)image: *([^|\]]*[^|\] ]) *
pg.wiki.commonslang = pg.wiki.commons ? pg.wiki.commons.split('.')[0] : null;
//                      (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)?
pg.wiki.lang = pg.wiki.hostname.split('.')[0];
//                                                        $4 = 120 as in 120px
// toolDbName needs pg.wiki.lang and pg.wiki.hostname
pg.re.image = RegExp('(^|\\[\\[)' + im + ': *([^|\\]]*[^|\\] ])' +
pg.wiki.prePath='';
    '([^0-9\\]]*([0-9]+) *px)?|(?:\\n *[|]?|[|]) *' +
if (pg.wiki.hostname == 'secure.wikimedia.org') {
    '(' + getValueOf('popupImageVarsRegexp') + ')' +
    var s=document.location.href.split('/');
    ' *= *(?:\\[\\[ *)?(?:' + im + ':)?' +
    pg.wiki.prePath=s.slice(3,5).join('/');
    '([^|]*?)(?:\\]\\])? *[|]? *\\n', 'img') ;
    pg.wiki.lang=s[4];
pg.re.imageBracketCount = 6;
}
 
var port = location.port ? ':' + location.port : '';
pg.re.category = RegExp('\\[\\[' +nsRe('Category') +
pg.wiki.sitebase = joinPath([pg.wiki.hostname + port, pg.wiki.prePath]);
': *([^|\\]]*[^|\\] ]) *', 'i');
pg.re.categoryBracketCount = 1;
 
pg.re.ipUser=RegExp('('+nsRe('User')+':)?' +
    '((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' +
    '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])');
 
pg.re.stub= RegExp(getValueOf('popupStubRegexp'), 'im');
pg.re.disambig=RegExp(getValueOf('popupDabRegexp'), 'im');
 
//</NOLITE>
// FIXME replace with general parameter parsing function, this is daft
pg.re.oldid=RegExp('[?&]oldid=([^&]*)');
pg.re.diff=RegExp('[?&]diff=([^&]*)');
}
}
 
function getArticlePath() {
 
if (isFunction(window.siteArticlePath)) {
//<NOLITE>
return siteArticlePath();
//////////////////////////////////////////////////
}
// Image sources
return 'wiki';
 
}
function setImageSources() {
   
pg.wiki.imageSources=[];
function getBotInterfacePath() {
 
if (isFunction(window.siteBotInterfacePath)) {
// frequently seen thumbs
return siteBotInterfacePath();
pg.wiki.imageSources.push(
{wiki: pg.wiki.hostname, thumb: true,  width: 180}, // default
{wiki: pg.wiki.hostname, thumb: true,  width: 120} // gallery
);
 
// frequently seen thumbs on commons
if (pg.wiki.commons) {
pg.wiki.imageSources.push(
{wiki: pg.wiki.commons, thumb: true,  width: 180},
{wiki: pg.wiki.commons, thumb: true,  width: 120}
);
}
 
// unusual thumb sizes and full-size
pg.wiki.imageSources.push(
{wiki: pg.wiki.hostname, thumb: true,  width: 200}, // common?
{wiki: pg.wiki.hostname, thumb: true,  width: 250}, // common?
{wiki: pg.wiki.hostname, thumb: true,  width: 300},
{wiki: pg.wiki.hostname, thumb: true,  width: 210},
{wiki: pg.wiki.hostname, thumb: true, width: 230},
{wiki: pg.wiki.hostname, thumb: false, width: 0} // no comma
);
 
// full-size on commons
if (pg.wiki.commons) {
pg.wiki.imageSources.push({wiki: pg.wiki.commons, thumb: false, width: 0});
}
}
var botInterfacePath = pg.wiki.articlePath.replace(/\/index[.]php$/, '');
if (pg.wiki.wikimedia) { botInterfacePath = 'w'; } // as in http://some.thing.com/w/index.php?title=foo
else if (pg.wiki.wikia) { botInterfacePath = ''; }
return botInterfacePath;
}
}
//</NOLITE>
function setTitleBase() {
 
var protocol = ( window.popupLocalDebug ? 'http:' : location.protocol );
pg.wiki.articlePath = getArticlePath();  // as in http://some.thing.com/wiki/Article
pg.wiki.botInterfacePath = getBotInterfacePath();
// default mediawiki setting is paths like http://some.thing.com/articlePath/index.php?title=foo
var titletail = joinPath([pg.wiki.botInterfacePath, 'index.php?title=']);
var titletail2 = joinPath([pg.wiki.botInterfacePath, 'wiki.phtml?title=']);
// other sites may need to add code here to set titletail depending on how their urls work
pg.wiki.titlebase  = protocol + '//' + joinPath([pg.wiki.sitebase, titletail]);
pg.wiki.titlebase2  = protocol + '//' + joinPath([pg.wiki.sitebase, titletail2]);
pg.wiki.wikibase    = protocol + '//' + joinPath([pg.wiki.sitebase, pg.wiki.botInterfacePath]);
pg.wiki.articlebase = protocol + '//' + joinPath([pg.wiki.sitebase, pg.wiki.articlePath]);
pg.wiki.commonsbase = protocol + '//' + joinPath([pg.wiki.commons, pg.wiki.botInterfacePath]);
pg.re.basenames = RegExp( '^(' +
  map( literalizeRegex, [ pg.wiki.titlebase, pg.wiki.titlebase2,
  pg.wiki.articlebase ]).join('|') + ')' );
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// Global regexps
// miscellany
 
function setMainRegex() {
function setupCache() {
var reStart='[^:]*://';
// page caching
var preTitles = joinPath([literalizeRegex(pg.wiki.botInterfacePath), '(?:index[.]php|wiki[.]phtml)[?]title=']);
pg.cache.pages = [];
// slightly ugly hack when pg.wiki.articlePath is empty
pg.cache.images = [];
preTitles += '|' + literalizeRegex( ( pg.wiki.articlePath ? pg.wiki.articlePath + '/' : ''));
 
// global array for 404'ed image urls
var reEnd='/(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?';
pg.cache.badImageUrls=[];
pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd);
}
}
 
function setRegexps() {
function setMisc() {
setMainRegex();
pg.current.link=null;
var sp=nsRe('Special');
pg.current.links=[];
pg.re.urlNoPopup=RegExp('((title=|/)' + sp +  '(?:%3A|:)|section=[0-9])') ;
pg.current.linksHash={};
pg.re.contribs  =RegExp('(title=|/)'  + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + pg.ns.user+':)(.*)') ;
 
pg.re.email    =RegExp('(title=|/)'  + sp + '(?:%3A|:)Emailuser'    + '(&target=|/|/(?:' + pg.ns.user+':)?)(.*)') ;
// downloading images are put here
pg.re.backlinks =RegExp('(title=|/)'  + sp + '(?:%3A|:)Whatlinkshere' + '(&target=|/)([^&]*)');
pg.misc.imageArray=[];
 
//<NOLITE>
setupCache();
var im=nsReImage();
// FIXME what is this for?
// note: tries to get images in infobox templates too, e.g. movie pages, album pages etc
pg.misc.gImage=null; // global for image
//                     (^|\[\[)image: *([^|\]]*[^|\] ]) *
 
//                      (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)?
// check to see if images are done with this timer
//                                                       $4 = 120 as in 120px
pg.timer.image=null;
pg.re.image = RegExp('(^|\\[\\[)' + im + ': *([^|\\]]*[^|\\] ])' +
 
    '([^0-9\\]]*([0-9]+) *px)?|(?:\\n *[|]?|[|]) *' +
// These are for checkImages()
    '(' + getValueOf('popupImageVarsRegexp') + ')' +
pg.counter.checkImages=0;
    ' *= *(?:\\[\\[ *)?(?:' + im + ':)?' +
pg.timer.checkImages=null;
    '([^|]*?)(?:\\]\\])? *[|]? *\\n', 'img') ;
pg.timer.checkPopupPosition=null;
pg.re.imageBracketCount = 6;
pg.counter.loop=0;
 
pg.re.category = RegExp('\\[\\[' +nsRe('Category') +
// ids change with each popup: popupImage0, popupImage1 etc
': *([^|\\]]*[^|\\] ]) *', 'i');
pg.idNumber=0;
pg.re.categoryBracketCount = 1;
 
// for myDecodeURI
pg.re.ipUser=RegExp('('+nsRe('User')+':)?' +
pg.misc.decodeExtras = [
    '((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' +
{from: '%2C', to: ',' },
    '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])');
{from: '_',  to: ' ' },
{from: '%24', to: '$'},
pg.re.stub= RegExp(getValueOf('popupStubRegexp'), 'im');
{from: '%26',   to: '&' } // no ,
pg.re.disambig=RegExp(getValueOf('popupDabRegexp'), 'im');
];
 
//</NOLITE>
// FIXME replace with general parameter parsing function, this is daft
pg.re.oldid=RegExp('[?&]oldid=([^&]*)');
pg.re.diff=RegExp('[?&]diff=([^&]*)');
}
}
 
function leadingInteger(s){
//<NOLITE>
var n=s.match(/^(\d*)/)[1];
//////////////////////////////////////////////////
if (n) { return +n; }
// Image sources
return null;
function setImageSources() {
pg.wiki.imageSources=[];
// frequently seen thumbs
pg.wiki.imageSources.push(
{wiki: pg.wiki.hostname, thumb: true,  width: 180}, // default
{wiki: pg.wiki.hostname, thumb: true,  width: 120} // gallery
);
// frequently seen thumbs on commons
if (pg.wiki.commons) {
pg.wiki.imageSources.push(
{wiki: pg.wiki.commons, thumb: true,  width: 180},
{wiki: pg.wiki.commons, thumb: true,  width: 120}
);
}
// unusual thumb sizes and full-size
pg.wiki.imageSources.push(
{wiki: pg.wiki.hostname, thumb: true,  width: 200}, // common?
{wiki: pg.wiki.hostname, thumb: true,  width: 250}, // common?
{wiki: pg.wiki.hostname, thumb: true,  width: 300},
{wiki: pg.wiki.hostname, thumb: true,  width: 210},
{wiki: pg.wiki.hostname, thumb: true,  width: 230},
{wiki: pg.wiki.hostname, thumb: false, width: 0} // no comma
);
// full-size on commons
if (pg.wiki.commons) {
pg.wiki.imageSources.push({wiki: pg.wiki.commons, thumb: false, width: 0});
}
}
}
//</NOLITE>
 
function setBrowserHacks() {
//////////////////////////////////////////////////
var useOriginal=false;
// miscellany
// browser-specific hacks
if (typeof window.opera != 'undefined') {
function setupCache() {
//if (leadingInteger(opera.version()) < 9)
// page caching
{ useOriginal=true; } // v9 beta still seems to have buggy css
pg.cache.pages = [];
setDefault('popupNavLinkSeparator', ' &#183; ');
pg.cache.images = [];
} else if (navigator.appName=='Konqueror') {
// global array for 404'ed image urls
pg.cache.badImageUrls=[];
}
function setMisc() {
pg.current.link=null;
pg.current.links=[];
pg.current.linksHash={};
// downloading images are put here
pg.misc.imageArray=[];
setupCache();
// FIXME what is this for?
pg.misc.gImage=null; // global for image
// check to see if images are done with this timer
pg.timer.image=null;
// These are for checkImages()
pg.counter.checkImages=0;
pg.timer.checkImages=null;
pg.timer.checkPopupPosition=null;
pg.counter.loop=0;
// ids change with each popup: popupImage0, popupImage1 etc
pg.idNumber=0;
// for myDecodeURI
pg.misc.decodeExtras = [
{from: '%2C', to: ',' },
{from: '_',  to: ' ' },
{from: '%24', to: '$'},
{from: '%26',  to: '&' } // no ,
];
}
function leadingInteger(s){
var n=s.match(/^(\d*)/)[1];
if (n) { return +n; }
return null;
}
function setBrowserHacks() {
var useOriginal=false;
// browser-specific hacks
if (typeof window.opera != 'undefined') {
//if (leadingInteger(opera.version()) < 9)
{ useOriginal=true; } // v9 beta still seems to have buggy css
setDefault('popupNavLinkSeparator', ' &#183; ');
} else if (navigator.appName=='Konqueror') {
setDefault('popupNavLinkSeparator', ' &bull; ');
setDefault('popupNavLinkSeparator', ' &bull; ');
pg.flag.isKonq=true;
pg.flag.isKonq=true;
Строка 6243: Строка 6079:
pg.flag.IEVersion=ver;
pg.flag.IEVersion=ver;
}
}
if ((pg.flag.isIE && pg.flag.IEVersion < 7) || pg.flag.isKonq || (pg.flag.isSafari && webkit < 420)) {
if (pg.flag.isIE && pg.flag.IEVersion < 7 || pg.flag.isKonq || pg.flag.isSafari) {
pg.flag.linksLikeIE6=true;
pg.flag.linksLikeIE6=true;
}
}
Строка 6250: Строка 6086:
}
}
}
}
 
function setupPopups() {
function setupPopups() {
// NB translatable strings should be set up first (strings.js)
// NB translatable strings should be set up first (strings.js)
// basics
// basics
setupDebugging();
setupDebugging();
Строка 6258: Строка 6095:
setTitleBase();
setTitleBase();
setOptions(); // see options.js
setOptions(); // see options.js
 
// namespaces etc
// namespaces etc
setNamespaces();
setNamespaces();
setInterwiki();
setInterwiki();
 
// regexps
// regexps
setRegexps();
setRegexps();
setRedirs();
setRedirs();
 
// other stuff
// other stuff
window.setImageSources && setImageSources();
window.setImageSources && setImageSources();
Строка 6272: Строка 6109:
setMisc();
setMisc();
setupLivePreview();
setupLivePreview();
 
// main deal here
// main deal here
setupTooltips();
setupTooltips();
Navpopup.tracker.enable();
Navpopup.tracker.enable();
 
setupPopups.completed = true;
setupPopups.completed = true;
}
}
Строка 6285: Строка 6122:
// navlinks... let the fun begin
// navlinks... let the fun begin
//
//
 
function defaultNavlinkSpec() {
function defaultNavlinkSpec() {
var str='';
var str='';
Строка 6292: Строка 6129:
str += '*<<lastEdit|shortcut=/>>|<<lastContrib>>|<<sinceMe>>if(oldid){|<<oldEdit>>|<<diffCur>>}';
str += '*<<lastEdit|shortcut=/>>|<<lastContrib>>|<<sinceMe>>if(oldid){|<<oldEdit>>|<<diffCur>>}';
}
}
 
// user links
// user links
// contribs - log - count - email - block
// contribs - log - count - email - block
Строка 6299: Строка 6136:
str+='if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}';
str+='if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}';
str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>|<<blocklog|log>>}}';
str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>|<<blocklog|log>>}}';
 
// editing links
// editing links
// talkpage  -> edit|new - history - un|watch - article|edit
// talkpage  -> edit|new - history - un|watch - article|edit
Строка 6307: Строка 6144:
var historystr='<<history|shortcut=h>>if(mainspace_en){|<<editors|shortcut=E|>>}';
var historystr='<<history|shortcut=h>>if(mainspace_en){|<<editors|shortcut=E|>>}';
var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
 
str+='<br>if(talk){' +
str+='<br>if(talk){' +
editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' +
editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' +
Строка 6315: Строка 6152:
'<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
'<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
+ '}';
+ '}';
 
// misc links
// misc links
str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>';
str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>';
 
// admin links
// admin links
str += 'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>|<<protectlog|log>>*' +
str += 'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>|<<protectlog|log>>*' +
Строка 6324: Строка 6161:
return str;
return str;
}
}
 
function navLinksHTML (article, hint, params) { //oldid, rcid) {
function navLinksHTML (article, hint, params) { //oldid, rcid) {
var str = '<span class="popupNavLinks">' + defaultNavlinkSpec() + '</span>';
var str = '<span class="popupNavLinks">' + defaultNavlinkSpec() + '</span>';
Строка 6330: Строка 6167:
return navlinkStringToHTML(str, article, params);
return navlinkStringToHTML(str, article, params);
}
}
 
function expandConditionalNavlinkString(s,article,z,recursionCount) {
function expandConditionalNavlinkString(s,article,z,recursionCount) {
var oldid=z.oldid, rcid=z.rcid, diff=z.diff;
var oldid=z.oldid, rcid=z.rcid, diff=z.diff;
Строка 6347: Строка 6184:
var ret = splitted[0];
var ret = splitted[0];
for (var i=1; i<splitted.length; i=i+numParens+1) {
for (var i=1; i<splitted.length; i=i+numParens+1) {
 
var testString=splitted[i+2-1];
var testString=splitted[i+2-1];
var trueString=splitted[i+3-1];
var trueString=splitted[i+3-1];
Строка 6353: Строка 6190:
if (typeof falseString=='undefined' || !falseString) { falseString=''; }
if (typeof falseString=='undefined' || !falseString) { falseString=''; }
var testResult=null;
var testResult=null;
 
switch (testString) {
switch (testString) {
case 'user':
case 'user':
Строка 6384: Строка 6221:
break;
break;
}
}
 
switch(testResult) {
switch(testResult) {
case null: ret+=splitted[i];  break;
case null: ret+=splitted[i];  break;
Строка 6390: Строка 6227:
case false: ret+=falseString; break;
case false: ret+=falseString; break;
}
}
 
// append non-conditional string
// append non-conditional string
ret += splitted[i+numParens];
ret += splitted[i+numParens];
Строка 6399: Строка 6236:
return ret;
return ret;
}
}
 
function navlinkStringToArray(s, article, params) {
function navlinkStringToArray(s, article, params) {
s=expandConditionalNavlinkString(s,article,params);
s=expandConditionalNavlinkString(s,article,params);
Строка 6432: Строка 6269:
return ret;
return ret;
}
}
 
 
function navlinkSubstituteHTML(s) {
function navlinkSubstituteHTML(s) {
return s.split('*').join(getValueOf('popupNavLinkSeparator'))
return s.split('*').join(getValueOf('popupNavLinkSeparator'))
Строка 6440: Строка 6277:
.split('<menu>').join('<ul class="popup_menu">')
.split('<menu>').join('<ul class="popup_menu">')
.split('</menu>').join('</ul>');
.split('</menu>').join('</ul>');
 
}
}
 
function navlinkDepth(magic,s) {
function navlinkDepth(magic,s) {
return s.split('<' + magic + '>').length - s.split('</' + magic + '>').length;
return s.split('<' + magic + '>').length - s.split('</' + magic + '>').length;
}
}
 
 
// navlinkString: * becomes the separator
// navlinkString: * becomes the separator
//                <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz'
//                <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz'
//                                      and visible text 'fubar'
//                                      and visible text 'fubar'
//                if(test){...} and if(test){...}else{...} work too (nested ok)
//                if(test){...} and if(test){...}else{...} work too (nested ok)
 
function navlinkStringToHTML(s,article,params) {
function navlinkStringToHTML(s,article,params) {
//limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article));
//limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article));
Строка 6482: Строка 6319:
return html;
return html;
}
}
 
function navlinkTag() {
function navlinkTag() {
this.type='navlinkTag';
this.type='navlinkTag';
}
}
 
navlinkTag.prototype.html=function () {
navlinkTag.prototype.html=function () {
this.getNewWin();
this.getNewWin();
Строка 6508: Строка 6345:
return opening + html + closing;
return opening + html + closing;
};
};
 
navlinkTag.prototype.getNewWin=function() {
navlinkTag.prototype.getNewWin=function() {
getValueOf('popupLinksNewWindow');
getValueOf('popupLinksNewWindow');
Строка 6514: Строка 6351:
this.newWin=pg.option.popupLinksNewWindow[this.id];
this.newWin=pg.option.popupLinksNewWindow[this.id];
}
}
 
navlinkTag.prototype.getPrintFunction=function() { //think about this some more
navlinkTag.prototype.getPrintFunction=function() { //think about this some more
// this.id and this.article should already be defined
// this.id and this.article should already be defined
Строка 6520: Строка 6357:
var html='';
var html='';
var a,t;
var a,t;
 
this.noPopup=1;
this.noPopup=1;
switch (this.id) {
switch (this.id) {
case 'contribs': case 'history': case 'whatLinksHere':
case 'contribs': case 'history': case 'whatLinksHere':
if (!getValueOf('popupUseQueryInterface')) { break; }
case 'userPage': case 'monobook': case 'userTalk':
case 'userPage': case 'monobook': case 'userTalk':
case 'talk': case 'article': case 'lastEdit':
case 'talk': case 'article': case 'lastEdit':
Строка 6530: Строка 6368:
switch (this.id) {
switch (this.id) {
case 'email':    case 'contribs':  case 'block':    case 'unblock':
case 'email':    case 'contribs':  case 'block':    case 'unblock':
case 'userlog':  case 'userSpace': case 'deletedContribs':
case 'userlog':  case 'userSpace':
this.article=this.article.userName();
this.article=this.article.userName();
}
}
 
switch (this.id) {
switch (this.id) {
case 'userTalk': case 'newUserTalk': case 'editUserTalk':
case 'userTalk': case 'newUserTalk': case 'editUserTalk':
Строка 6542: Строка 6380:
delete this.oldid;
delete this.oldid;
}
}
 
if (this.id=='editMonobook' || this.id=='monobook') { this.article.append('/monobook.js'); }
if (this.id=='editMonobook' || this.id=='monobook') { this.article.append('/monobook.js'); }
 
if (this.id != 'mainlink') {
if (this.id != 'mainlink') {
// FIXME anchor handling should be done differently with Title object
// FIXME anchor handling should be done differently with Title object
Строка 6550: Строка 6388:
// if (typeof this.text=='undefined') this.text=popupString(this.id);
// if (typeof this.text=='undefined') this.text=popupString(this.id);
}
}
 
switch (this.id) {
switch (this.id) {
case 'undelete':      this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break;
case 'undelete':      this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break;
Строка 6557: Строка 6395:
case 'move':          this.print=specialLink; this.specialpage='Movepage'; break;
case 'move':          this.print=specialLink; this.specialpage='Movepage'; break;
case 'contribs':      this.print=specialLink; this.specialpage='Contributions'; break;
case 'contribs':      this.print=specialLink; this.specialpage='Contributions'; break;
case 'deletedContribs':this.print=specialLink; this.specialpage='Deletedcontributions'; break;
case 'email':          this.print=specialLink; this.specialpage='Emailuser'; break;
case 'email':          this.print=specialLink; this.specialpage='Emailuser'; break;
case 'block':          this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break;
case 'block':          this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break;
Строка 6566: Строка 6403:
case 'protectlog':    this.print=specialLink; this.specialpage='Log'; this.sep='&type=protect&page='; break;
case 'protectlog':    this.print=specialLink; this.specialpage='Log'; this.sep='&type=protect&page='; break;
case 'deletelog':      this.print=specialLink; this.specialpage='Log'; this.sep='&type=delete&page='; break;
case 'deletelog':      this.print=specialLink; this.specialpage='Log'; this.sep='&type=delete&page='; break;
case 'userSpace':      this.print=specialLink; this.specialpage='Prefixindex'; this.sep='&namespace=2&prefix='; break;
case 'userSpace':      this.print=specialLink; this.specialpage='Prefixindex'; this.sep='&namespace=2&from='; break;
case 'search':        this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break;
case 'search':        this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break;
case 'history': case 'historyfeed': case 'unwatch': case 'watch':
case 'history': case 'historyfeed': case 'unwatch': case 'watch':
case 'unprotect': case 'protect':
case 'unprotect': case 'protect':
this.print=wikiLink; this.action=this.id; break;
this.print=wikiLink; this.action=this.id; break;
 
case 'delete':
case 'delete':
this.print=wikiLink; this.action='delete';
this.print=wikiLink; this.action='delete';
Строка 6579: Строка 6416:
}
}
break;
break;
 
case 'markpatrolled':
case 'markpatrolled':
case 'edit': // editOld should keep the oldid, but edit should not.
case 'edit': // editOld should keep the oldid, but edit should not.
Строка 6627: Строка 6464:
this.print=arinLink; break;
this.print=arinLink; break;
case 'count':
case 'count':
this.print=editCounterLink; break;
this.print=kateLink; break;
case 'google':
case 'google':
this.print=googleLink; break;
this.print=googleLink; break;
case 'contribsTree':
this.print=contribsTreeLink; break;
case 'editors':
case 'editors':
this.print=editorListLink; break;
this.print=editorListLink; break;
Строка 6692: Строка 6531:
return false; // swallow keypress
return false; // swallow keypress
}
}
 
var letter=String.fromCharCode(keyCode);
var letter=String.fromCharCode(keyCode);
var links=pg.current.link.navpopup.mainDiv.getElementsByTagName('A');
var links=pg.current.link.navpopup.mainDiv.getElementsByTagName('A');
var startLink=0;
var startLink=0;
var i,j;
var i,j;
 
if (popupHandleKeypress.lastPopupLinkSelected) {
if (popupHandleKeypress.lastPopupLinkSelected) {
for (i=0; i<links.length; ++i) {
for (i=0; i<links.length; ++i) {
Строка 6712: Строка 6551:
}
}
}
}
 
// pass keypress on
// pass keypress on
if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); }
if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); }
return true;
return true;
}
}
 
function addPopupShortcuts() {
function addPopupShortcuts() {
if (document.onkeypress!=popupHandleKeypress) {
if (document.onkeypress!=popupHandleKeypress) {
Строка 6724: Строка 6563:
document.onkeypress=popupHandleKeypress;
document.onkeypress=popupHandleKeypress;
}
}
 
function rmPopupShortcuts() {
function rmPopupShortcuts() {
popupHandleKeypress.lastPopupLinkSelected=null;
popupHandleKeypress.lastPopupLinkSelected=null;
Строка 6736: Строка 6575:
} catch (nasties) { /* IE goes here */ }
} catch (nasties) { /* IE goes here */ }
}
}
 
 
function addLinkProperty(html, property) {
function addLinkProperty(html, property) {
// take "<a href=...>...</a> and add a property
// take "<a href=...>...</a> and add a property
Строка 6745: Строка 6584:
return html.substring(0,i) + ' ' + property + html.substring(i);
return html.substring(0,i) + ' ' + property + html.substring(i);
}
}
 
function addPopupShortcut(html, key) {
function addPopupShortcut(html, key) {
if (!getValueOf('popupShortcutKeys')) { return html; }
if (!getValueOf('popupShortcutKeys')) { return html; }
Строка 6784: Строка 6623:
oldRev = oldRev || 0;
oldRev = oldRev || 0;
newRev = newRev || 0;
newRev = newRev || 0;
 
var go = function() {
var go = function() {
pendingNavpopTask(navpop);
pendingNavpopTask(navpop);
getWiki(article, doneDiffNew, newRev, navpop);
getWiki(article, doneDiffNew, newRev, navpop);
 
pendingNavpopTask(navpop);
pendingNavpopTask(navpop);
getWiki(article, doneDiffOld, oldRev, navpop);
getWiki(article, doneDiffOld, oldRev, navpop);
 
var tz = Cookie.read('popTz');
var tz = Cookie.read('popTz');
if ( (window.wgEnableAPI || wgEnableAPI) && getValueOf('popupAdjustDiffDates') && tz===null) {
if (getValueOf('popupUseQueryInterface') && getValueOf('popupAdjustDiffDates') && tz===null) {
    pendingNavpopTask(navpop);
    pendingNavpopTask(navpop);
    getPageWithCaching(pg.wiki.wikibase + '/api.php?format=json&action=query&meta=userinfo&uiprop=options',
    getPageWithCaching(pg.wiki.wikibase + '/query.php?format=json&what=userinfo&uioptions=timecorrection',
      function(d) {
      function(d) {
      completedNavpopTask(navpop);
      completedNavpopTask(navpop);
Строка 6807: Строка 6646:
else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); }
else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); }
}
}
 
function setTimecorrectionCookie(d) {
function setTimecorrectionCookie(d) {
try {
Cookie.create('popTz', getTimeOffset(getJsObj(d.data).meta.user.timecorrection), 1);
var jsobj=getJsObj(d.data);
var tz=jsobj.query.userinfo.options.timecorrection;
} catch (someError) {
logerr( 'setTimecorretion failed' );
return;
}
    Cookie.create( 'popTz', getTimeOffset(tz), 1);
}
}
 
function doneDiff(download, isOld) {
function doneDiff(download, isOld) {
if (!download.owner || !download.owner.diffData) { return; }
if (!download.owner || !download.owner.diffData) { return; }
Строка 6828: Строка 6660:
if (diffDownloadsComplete(navpop)) { insertDiff(navpop); }
if (diffDownloadsComplete(navpop)) { insertDiff(navpop); }
}
}
 
function diffDownloadsComplete(navpop) {
function diffDownloadsComplete(navpop) {
if ( Cookie.read('popTz')===null) { return false; }
if (getValueOf('popupUseQueryInterface') && Cookie.read('popTz')===null) { return false; }
return navpop.diffData.Old && navpop.diffData.New;
return navpop.diffData.Old && navpop.diffData.New;
}
}
 
function doneDiffNew(download) { doneDiff(download, false); }
function doneDiffNew(download) { doneDiff(download, false); }
function doneDiffOld(download) { doneDiff(download, true);  }
function doneDiffOld(download) { doneDiff(download, true);  }
 
function rmBoringLines(a,b,context) {
function rmBoringLines(a,b,context) {
 
if (typeof context == 'undefined') { context=2; }
if (typeof context == 'undefined') { context=2; }
// this is fairly slow... i think it's quicker than doing a word-based diff from the off, though
// this is fairly slow... i think it's quicker than doing a word-based diff from the off, though
Строка 6844: Строка 6676:
var bb=[], bbb=[];
var bb=[], bbb=[];
var i, j;
var i, j;
 
// first, gather all disconnected nodes in a and all crossing nodes in a and b
// first, gather all disconnected nodes in a and all crossing nodes in a and b
for (i=0; i<a.length; ++i ) {
for (i=0; i<a.length; ++i ) {
Строка 6853: Строка 6685:
}
}
}
}
 
// pick up remaining disconnected nodes in b
// pick up remaining disconnected nodes in b
for (i=0; i<b.length; ++i ) {
for (i=0; i<b.length; ++i ) {
Строка 6859: Строка 6691:
if(!b[i].paired) { bb[i]=1; }
if(!b[i].paired) { bb[i]=1; }
}
}
 
// another pass to gather context: we want the neighbours of included nodes which are not yet included
// another pass to gather context: we want the neighbours of included nodes which are not yet included
// we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass
// we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass
Строка 6869: Строка 6701:
}
}
}
}
 
for (i=0; i<a.length; ++i) {
for (i=0; i<a.length; ++i) {
if ( aa[i] == 1 ) {
if ( aa[i] == 1 ) {
Строка 6877: Строка 6709:
}
}
}
}
 
for (i=0; i<bb.length; ++i) {
for (i=0; i<bb.length; ++i) {
if (bb[i] > 0) { // it's a row we need
if (bb[i] > 0) { // it's a row we need
Строка 6894: Строка 6726:
}
}
}
}
 
return { a: aaa, b: bbb};
return { a: aaa, b: bbb};
}
}
 
function stripOuterCommonLines(a,b,context) {
function stripOuterCommonLines(a,b,context) {
var i=0;
var i=0;
Строка 6903: Строка 6735:
var j=a.length-1; var k=b.length-1;
var j=a.length-1; var k=b.length-1;
while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; }
while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; }
 
return { a: a.slice(max(0,i - 1 - context), min(a.length+1, j + context+1)),
return { a: a.slice(max(0,i - 1 - context), min(a.length+1, j + context+1)),
    b: b.slice(max(0,i - 1 - context), min(b.length+1, k + context+1)) };
    b: b.slice(max(0,i - 1 - context), min(b.length+1, k + context+1)) };
}
}
 
function insertDiff(navpop) {
function insertDiff(navpop) {
// for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff
// for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff
Строка 6925: Строка 6757:
oldlines=inner.a; newlines=inner.b;
oldlines=inner.a; newlines=inner.b;
}
}
 
var lineDiff=diff(oldlines, newlines);
var lineDiff=diff(oldlines, newlines);
var lines2=rmBoringLines(lineDiff.o, lineDiff.n);
var lines2=rmBoringLines(lineDiff.o, lineDiff.n);
var oldlines2=lines2.a; var newlines2=lines2.b;
var oldlines2=lines2.a; var newlines2=lines2.b;
 
var simpleSplit = !String.prototype.parenSplit.isNative;
var simpleSplit = !String.prototype.parenSplit.isNative;
var html='<hr>';
var html='<hr>';
Строка 6943: Строка 6775:
    'popupPreview', navpop.idNumber);
    'popupPreview', navpop.idNumber);
}
}
 
function diffDatesTable( oldDl, newDl ) {
function diffDatesTable( oldDl, newDl ) {
var html='<table class="popup_diff_dates">';
var html='<table class="popup_diff_dates">';
Строка 6985: Строка 6817:
// LINK GENERATION //
// LINK GENERATION //
/////////////////////
/////////////////////
 
// titledDiffLink --> titledWikiLink --> generalLink
// titledDiffLink --> titledWikiLink --> generalLink
// wikiLink      --> titledWikiLink --> generalLink
// wikiLink      --> titledWikiLink --> generalLink
// editCounterLink --> generalLink
// kateLink --> generalLink
 
function titledDiffLink(l) { // article, text, title, from, to) {
function titledDiffLink(l) { // article, text, title, from, to) {
return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from,
return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from,
Строка 6998: Строка 6830:
actionName: 'diff'});
actionName: 'diff'});
}
}
 
 
function wikiLink(l) {
function wikiLink(l) {
//{article:article, action:action, text:text, oldid, newid}) {
//{article:article, action:action, text:text, oldid, newid}) {
if (! (typeof l.article == typeof {}
if (! (typeof l.article == typeof {}
      && typeof l.action == typeof '' && typeof l.text==typeof '')) return null;
      && typeof l.action == typeof '' && typeof l.text==typeof '')) return null;
if (typeof l.oldid == 'undefined') { l.oldid=null; }
if (typeof l.oldid == 'undefined') l.oldid=null;
var savedOldid = l.oldid;
if (!/^((edit|view|revert|render)$|(raw))/.test(l.action)) { l.oldid=null; }
if (!/^(edit|view|revert|render)$|^raw/.test(l.action)) { l.oldid=null; }
var hint=popupString(l.action + 'Hint'); // revertHint etc etc etc
var hint=popupString(l.action + 'Hint'); // revertHint etc etc etc
var oldidData=[l.oldid, safeDecodeURI(l.article)];
var oldidData=[l.oldid, safeDecodeURI(l.article)];
Строка 7014: Строка 6845:
case 'edit&section=new': hint = popupString('newSectionHint');  break;
case 'edit&section=new': hint = popupString('newSectionHint');  break;
case 'edit&undo=':
case 'edit&undo=':
if (l.diff && l.diff != 'prev' && savedOldid ) {
l.action += l.diff; hint = popupString('undoHint');
  l.action += l.diff + '&undoafter=' + savedOldid;
} else if (savedOldid) {
  l.action += savedOldid;
}
hint = popupString('undoHint');
break;
break;
case 'raw&ctype=text/css': hint=popupString('rawHint'); break;
case 'raw&ctype=text/css': hint=popupString('rawHint'); break;
case 'revert':
case 'revert':
    if (!window.wgEnableAPI || !wgEnableAPI) {
var p=parseParams(pg.current.link.href);
    alert( 'This function of navigation popups now requires a MediaWiki ' +
l.action='edit&autoclick=wpSave&autosummary=' + revertSummary(l.oldid, p.diff);
'installation with the API enabled.');
break;
    }
var p=parseParams(pg.current.link.href);
l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autosummary=' + revertSummary(l.oldid, p.diff);
if (p.diff=='prev') {
if (p.diff=='prev') {
l.action += '&direction=prev';
l.action += '&direction=prev';
Строка 7039: Строка 6860:
break;
break;
case 'nullEdit':
case 'nullEdit':
l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autosummary=null';
l.action='edit&autoclick=wpSave&autosummary=null';
break;
break;
case 'historyfeed':
case 'historyfeed':
Строка 7047: Строка 6868:
l.action='markpatrolled&rcid='+l.rcid;
l.action='markpatrolled&rcid='+l.rcid;
}
}
 
if (hint) {
if (hint) {
if (l.oldid) {
if (l.oldid) {
Строка 7059: Строка 6880:
hint = safeDecodeURI(l.article + '&action=' + l.action) + (l.oldid) ? '&oldid='+l.oldid : '';
hint = safeDecodeURI(l.article + '&action=' + l.action) + (l.oldid) ? '&oldid='+l.oldid : '';
}
}
 
return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin,
return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin,
title: hint, oldid: l.oldid, noPopup: l.noPopup});
title: hint, oldid: l.oldid, noPopup: l.noPopup});
}
}
 
function revertSummary(oldid, diff) {
function revertSummary(oldid, diff) {
if (getValueOf('popupUseQueryInterface')) { return revertSummaryQueried(oldid, diff); }
if (typeof getValueOf('popupTimeOffset') == 'number' && /[?&]action=history/.test(document.location.href)) {
var links=document.links;
var numlinks=links.length;
var date=null, editor=null;
var dateRe = RegExp('^([0-9]{2}:[0-9]{2}),\s*(.*[1-3][0-9]{3})$');
for (var i=0; i<numlinks-1; ++i) {
if (RegExp('oldid='+oldid).test(links[i].href) && dateRe.test(links[i].innerHTML)) {
// help konqueror out by putting the time at the end
var ds = links[i].innerHTML.replace(dateRe, '$2 $1');
// d is parsed according to current locale, in FF at least
// this is only OK if the user has set the time offset in prefs!
var d=new Date(+(new Date(ds)) - 1000*3600*getValueOf('popupTimeOffset'));
// strip out zero seconds and timezone in date, since they're prolly bogus
date=d.toString().replace(/([0-9]{2}:[0-9]{2}):00.*/, '$1');
editor=Title.fromURL(links[i+1].href).userName();
break;
}
}
if (date && editor && diff != 'prev') {
return simplePrintf(getValueOf('popupExtendedRevertSummary'), [date, editor, oldid]);
}
}
if (diff != 'prev') {
return simplePrintf(getValueOf('popupRevertSummary'), [ oldid ]);
}
return simplePrintf(getValueOf('popupRevertToPreviousSummary'), [ oldid ]);
}
function revertSummaryQueried(oldid, diff) {
var ret='';
var ret='';
if (diff == 'prev') {
if (diff == 'prev') {
Строка 7071: Строка 6922:
return ret + '&autorv=' + oldid;
return ret + '&autorv=' + oldid;
}
}
 
function titledWikiLink(l) {
function titledWikiLink(l) {
// possible properties of argument:
// possible properties of argument:
// article, action, text, title, oldid, actionName, className, noPopup
// article, action, text, title, oldid, actionName, className, noPopup
// oldid = null is fine here
// oldid = null is fine here
 
// article and action are mandatory args
// article and action are mandatory args
 
if (typeof l.article == 'undefined' || typeof l.action=='undefined') {
if (typeof l.article == 'undefined' || typeof l.action=='undefined') {
errlog('got undefined article or action in titledWikiLink');
errlog('got undefined article or action in titledWikiLink');
return null;
return null;
}
}
 
var base = pg.wiki.titlebase +  l.article.urlString();
var base = pg.wiki.titlebase +  l.article.urlString();
var url=base;
var url=base;
 
if (typeof l.actionName=='undefined' || !l.actionName) { l.actionName='action'; }
if (typeof l.actionName=='undefined' || !l.actionName) { l.actionName='action'; }
 
// no need to add &action=view, and this confuses anchors
// no need to add &action=view, and this confuses anchors
if (l.action != 'view') { url = base + '&' + l.actionName + '=' + l.action; }
if (l.action != 'view') { url = base + '&' + l.actionName + '=' + l.action; }
 
if (typeof l.oldid!='undefined' && l.oldid) { url+='&oldid='+l.oldid; }
if (typeof l.oldid!='undefined' && l.oldid) { url+='&oldid='+l.oldid; }
 
var cssClass=pg.misc.defaultNavlinkClassname;
var cssClass=pg.misc.defaultNavlinkClassname;
if (typeof l.className!='undefined' && l.className) { cssClass=l.className; }
if (typeof l.className!='undefined' && l.className) { cssClass=l.className; }
 
return generalNavLink({url: url, newWin: l.newWin,
return generalNavLink({url: url, newWin: l.newWin,
title: (typeof l.title != 'undefined') ? l.title : null,
title: (typeof l.title != 'undefined') ? l.title : null,
Строка 7102: Строка 6953:
className: cssClass, noPopup:l.noPopup});
className: cssClass, noPopup:l.noPopup});
}
}
 
function getLastContrib(wikipage, newWin) {
function getLastContrib(wikipage, newWin) {
getHistoryInfo(wikipage, function(x){processLastContribInfo(x,{page: wikipage, newWin: newWin})});
getHistoryInfo(wikipage, function(x){processLastContribInfo(x,{page: wikipage, newWin: newWin})});
Строка 7137: Строка 6988:
else { document.location=url; }
else { document.location=url; }
}
}
 
function purgePopups() {
function purgePopups() {
processAllPopups(true);
processAllPopups(true);
Строка 7144: Строка 6995:
abortAllDownloads();
abortAllDownloads();
}
}
 
function processAllPopups(nullify, banish) {
function processAllPopups(nullify, banish) {
for (var i=0; i<pg.current.links.length; ++i) {
for (var i=0; i<pg.current.links.length; ++i) {
if (!pg.current.links[i].navpopup) { continue; }
if (!pg.current.links[i].navpopup) { continue; }
(nullify || banish) && pg.current.links[i].navpopup.banish();
(nullify || banish) && pg.current.links[i].navpopup.banish();
pg.current.links[i].simpleNoMore=false;
nullify && (pg.current.links[i].navpopup=null);
nullify && (pg.current.links[i].navpopup=null);
}
}
}
}
 
function disablePopups(){
function disablePopups(){
processAllPopups(false, true);
processAllPopups(false, true);
setupTooltips(null, true);
setupTooltips(null, true);
}
}
 
function togglePreviews() {
function togglePreviews() {
processAllPopups(true, true);
processAllPopups(true, true);
Строка 7164: Строка 7014:
abortAllDownloads();
abortAllDownloads();
}
}
 
function magicHistoryLink(l) {
function magicHistoryLink(l) {
// FIXME use onclick change href trick to sort this out instead of window.open
// FIXME use onclick change href trick to sort this out instead of window.open
 
var jsUrl='', title='';
var jsUrl='', title='';
switch(l.id) {
switch(l.id) {
Строка 7181: Строка 7031:
break;
break;
}
}
 
return generalNavLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think
return generalNavLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think
title: title, text: l.text, noPopup: l.noPopup});
title: title, text: l.text, noPopup: l.noPopup});
}
}
 
function popupMenuLink(l) {
function popupMenuLink(l) {
var jsUrl=simplePrintf('javascript:%s()', [l.id]);
var jsUrl=simplePrintf('javascript:%s()', [l.id]);
Строка 7191: Строка 7041:
return generalNavLink({url: jsUrl, newWin:false, title:title, text:l.text, noPopup:l.noPopup});
return generalNavLink({url: jsUrl, newWin:false, title:title, text:l.text, noPopup:l.noPopup});
}
}
 
function specialLink(l) {
function specialLink(l) {
// properties: article, specialpage, text, sep
// properties: article, specialpage, text, sep
Строка 7214: Строка 7064:
if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]);
if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]);
else hint = safeDecodeURI(l.specialpage+':'+l.article) ;
else hint = safeDecodeURI(l.specialpage+':'+l.article) ;
 
var url = base + l.sep + article;
var url = base + l.sep + article;
return generalNavLink({url: url, title: hint, text: l.text, newWin:l.newWin, noPopup:l.noPopup});
return generalNavLink({url: url, title: hint, text: l.text, newWin:l.newWin, noPopup:l.noPopup});
}
}
 
function generalLink(l) {
function generalLink(l) {
// l.url, l.text, l.title, l.newWin, l.className, l.noPopup
// l.url, l.text, l.title, l.newWin, l.className, l.noPopup
if (typeof l.url=='undefined') return null;
if (typeof l.url=='undefined') return null;
 
// only quotation marks in the url can screw us up now... I think
// only quotation marks in the url can screw us up now... I think
var url=l.url.split('"').join('%22');
var url=l.url.split('"').join('%22');
 
var ret='<a href="' + url + '"';
var ret='<a href="' + url + '"';
if (typeof l.title!='undefined' && l.title) { ret += ' title="' + l.title + '"'; }
if (typeof l.title!='undefined' && l.title) { ret += ' title="' + l.title + '"'; }
Строка 7239: Строка 7089:
return ret;
return ret;
}
}
 
function appendParamsToLink(linkstr, params) {
function appendParamsToLink(linkstr, params) {
var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i'));
var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i'));
Строка 7248: Строка 7098:
return ret;
return ret;
}
}
 
function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor, title (optional) {
function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor, title (optional) {
if (x.newTarget) {
if (x.newTarget) {
Строка 7255: Строка 7105:
// optional: oldTarget (in wikitext)
// optional: oldTarget (in wikitext)
// if x.newTarget omitted or null, remove the link
// if x.newTarget omitted or null, remove the link
 
//x.text=encodeURI(x.text);  // this buggers things up on zh.wikipedia.org and doesn't seem necessary
//x.text=encodeURI(x.text);  // this buggers things up on zh.wikipedia.org and doesn't seem necessary
x.clickButton=encodeURI(x.clickButton);
x.clickButton=encodeURI(x.clickButton);
 
// FIXME: first character of page title as well as namespace should be case insensitive
// FIXME: first character of page title as well as namespace should be case insensitive
// eg [[category:foo]] and [[Category:Foo]] are equivalent
// eg [[category:foo]] and [[Category:Foo]] are equivalent
Строка 7265: Строка 7115:
var chs=cA.charAt(0).toUpperCase();
var chs=cA.charAt(0).toUpperCase();
chs='['+chs + chs.toLowerCase()+']';
chs='['+chs + chs.toLowerCase()+']';
var currentArticleRegexBit=encodeURIComponent(chs+cA.substring(1));
var currentArticleRegexBit=chs+cA.substring(1);
currentArticleRegexBit=currentArticleRegexBit
currentArticleRegexBit=currentArticleRegexBit
.split(RegExp('[_ ]+', 'g')).join('[_ ]+')
.split(RegExp('[_ ]+', 'g')).join('[_ ]+')
Строка 7273: Строка 7123:
currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + '(?:#[^\\[\\|]*)?)\\s*';
currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + '(?:#[^\\[\\|]*)?)\\s*';
// e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s*
// e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s*
 
// autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g
// autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g
 
var title=x.title || wgPageName.split('_').join(' ');
var title=x.title || wgPageName.split('_').join(' ');
var lk=titledWikiLink({article: new Title(title), newWin:x.newWin,
var lk=titledWikiLink({article: new Title(title), newWin:x.newWin,
Строка 7286: Строка 7136:
if (x.newTarget) {
if (x.newTarget) {
// escape '&' and other nasties
// escape '&' and other nasties
var t=encodeURIComponent(x.newTarget);
var t=encodeURI(x.newTarget);
var s=encodeURIComponent(literalizeRegex(x.newTarget));
var s=encodeURI(literalizeRegex(x.newTarget));
cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~[['+t+'|$1]]~g;';
cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~[['+t+'|$1]]~g;';
cmd += 's~\\[\\['+currentArticleRegexBit+'[|]~[['+t+'|~g;';
cmd += 's~\\[\\['+currentArticleRegexBit+'[|]~[['+t+'|~g;';
Строка 7295: Строка 7145:
cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g';
cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g';
}
}
cmd += '&autoclick='+x.clickButton + '&actoken=' + autoClickToken();
cmd += '&autoclick='+x.clickButton;
cmd += ( x.minor == null ) ? '' : '&autominor='+x.minor;
cmd += ( x.minor == null ) ? '' : '&autominor='+x.minor;
cmd += ( x.watch == null ) ? '' : '&autowatch='+x.watch;
cmd += ( x.watch == null ) ? '' : '&autowatch='+x.watch;
cmd += '&autosummary='+encodeURIComponent(x.summary);
cmd += '&autosummary='+x.summary;
return appendParamsToLink(lk, 'autoedit='+cmd);
return appendParamsToLink(lk, 'autoedit='+cmd);
}
}
 
 
function redirLink(redirMatch, article) {
function redirLink(redirMatch, article) {
// NB redirMatch is in wikiText
// NB redirMatch is in wikiText
var ret='';
var ret='';
 
if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) {
if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) {
ret += '<hr>';
ret += '<hr>';
Строка 7315: Строка 7165:
{newTarget: redirMatch, text: popupString('Redirects'),
{newTarget: redirMatch, text: popupString('Redirects'),
hint: popupString('Fix this redirect'),
hint: popupString('Fix this redirect'),
summary: simplePrintf(getValueOf('popupFixRedirsSummary'),
summary: simplePrintf(getValueOf('popupFixRedirsSummary'),
      [article.toString(), redirMatch ]),
      [article.toString(), redirMatch ]),
oldTarget: article.toString(),
oldTarget: article.toString(),
clickButton: getValueOf('popupRedirAutoClick'), minor: true,
clickButton: getValueOf('popupRedirAutoClick'), minor: true,
watch: getValueOf('popupWatchRedirredPages')})
watch: getValueOf('popupWatchRedirredPages')})
, 'R');
, 'R');
ret += popupString(' to ');
ret += popupString(' to ');
}
}
else ret += popupString('Redirects') + popupString(' to ');
else ret += popupString('Redirects') + popupString(' to ');
return ret;
return ret;
}
}
 
else return '<br> ' + popupString('Redirects') + popupString(' to ') +
else return '<br> ' + popupString('Redirects') + popupString(' to ') +
    titledWikiLink({article: new Title().fromWikiText(redirMatch), action: 'view',  /* FIXME: newWin */
    titledWikiLink({article: new Title().fromWikiText(redirMatch), action: 'view',  /* FIXME: newWin */
      text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')});
      text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')});
}
}
 
function arinLink(l) {
function arinLink(l) {
if (!saneLinkCheck(l)) { return null; }
if (!saneLinkCheck(l)) { return null; }
if ( ! l.article.isIpUser() || ! pg.wiki.wikimedia) return null;
if ( ! l.article.isIpUser() || ! pg.wiki.wikimedia) return null;
 
var uN=l.article.userName();
var uN=l.article.userName();
 
return generalNavLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + encodeURIComponent(uN), newWin:l.newWin,
return generalNavLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + escape(uN), newWin:l.newWin,
title: tprintf('Look up %s in ARIN whois database', [uN]),
title: tprintf('Look up %s in ARIN whois database', [uN]),
text: l.text, noPopup:1});
text: l.text, noPopup:1});
}
}
 
function toolDbName(cookieStyle) {
function toolDbName(cookieStyle) {
var ret=null;
var ret=null;
var theWiki=pg.wiki.hostname.split('.')[1];
var theWiki=pg.wiki.hostname.split('.')[1];
if (pg.wiki.hostname==pg.wiki.commons) {
if (pg.wiki.hostname==pg.wiki.commons) {
ret = 'commonswiki';
ret = 'commonswiki';
} else {
} else {
switch(theWiki) {
switch(theWiki) {
case 'wikipedia':
case 'wikipedia':
case 'wikimedia':
case 'wikimedia':
ret = pg.wiki.lang + 'wiki';
ret = pg.wiki.lang + 'wiki';
break;
break;
default:
default:
ret = pg.wiki.lang + theWiki;
ret = pg.wiki.lang + theWiki;
break;
break;
}
}
if (!cookieStyle) { ret+= '_p'; }
return ret;
}
 
function saneLinkCheck(l) {
if (typeof l.article != typeof {} || typeof l.text != typeof '') { return false; }
return true;
}
function kateLink(l) {
if(!saneLinkCheck(l)) return null;
if (! pg.wiki.wikimedia) return null;
var uN=l.article.userName();
var tool=getValueOf('popupEditCounterTool');
var url;
var defaultToolUrl='http://tools.wikimedia.de/~$3/cgi-bin/count_edits?dbname=$2&user=$1';
 
switch(tool) {
case 'custom':
url=simplePrintf(getValueOf('popupEditCounterUrl'), [ escape(uN), toolDbName() ]);
break;
default:
url=simplePrintf(defaultToolUrl, [ escape(uN), toolDbName(), tool ]);
}
return generalNavLink({url:url, title: tprintf('katelinkHint', [uN]),
newWin:l.newWin, text: l.text, noPopup:1});
}
 
 
function contribsTreeLink(l) {
if(!saneLinkCheck(l)) return null;
if (! pg.wiki.wikimedia) return null;
var uN=l.article.userName();
 
var url='http://tools.wikimedia.de/~interiot/cgi-bin/contribution_tree?dbname=';
url += toolDbName() + '&user='+ escape(uN);
 
return generalNavLink({url:url, title: tprintf('contribsTreeHint', [uN]), newWin:l.newWin, text: l.text,
noPopup:1});
}
 
function globalSearchLink(l) {
if(!saneLinkCheck(l)) return null;
 
var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search=';
var article=l.article.urlString({keepSpaces:true});
 
return generalNavLink({url:base + article, newWin:l.newWin,
title: tprintf('globalSearchHint', [article]),
text: l.text, noPopup:1});
}
 
function googleLink(l) {
if(!saneLinkCheck(l)) return null;
 
var base='http://www.google.com/search?q=';
var article=l.article.urlString({keepSpaces:true});
 
return generalNavLink({url:base + '%22' + article + '%22', newWin:l.newWin,
title: tprintf('googleSearchHint', [article]),
text: l.text, noPopup:1});
}
 
function editorListLink(l) {
if(!saneLinkCheck(l)) return null;
var article= l.article.articleFromTalkPage() || l.article;
var base='http://tools.wikimedia.de/~tim/counter/?page=';
return generalNavLink({url:base+article.urlString(),
title: tprintf('editorListHint', [article]),
newWin:l.newWin, text: l.text, noPopup:1});
}
 
function generalNavLink(l) {
l.className = (l.className==null) ? 'popupNavLink' : l.className;
return generalLink(l);
}
 
//////////////////////////////////////////////////
// magic history links
//
 
function getHistoryInfo(wikipage, whatNext) {
log('getHistoryInfo');
getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory);
}
 
// FIXME eliminate pg.idNumber ... how? :-(
 
function getHistory(wikipage, onComplete) {
log('getHistory');
var url;
if (getValueOf('popupUseQueryInterface')) {
url = pg.wiki.wikibase + '/query.php?format=json&what=revisions&titles=' +
new Title(wikipage).urlString() + '&rvlimit=' + getValueOf('popupHistoryLimit');
} else {
url = pg.wiki.titlebase + new Title(wikipage).urlString() +
'&action=history' + '&limit=' + getValueOf('popupHistoryLimit');
}
log('getHistory: url='+url);
return startDownload(url, pg.idNumber+'history', onComplete);
}
 
function processHistory(download) {
if (getValueOf('popupUseQueryInterface')) {
return processHistoryQuery(download);
}
return processHistoryScreenScrape(download);
}
 
function processHistoryScreenScrape(download) {
// screen scrape alert
 
var d=download.data;
// pg.misc.data=d; // for debugging
 
var edits=[];
var split=d.split('<li>');
 
for (var i=0; i<split.length; ++i) {
var histRe=RegExp(
'^[(].*?type="radio" value="([0-9]*)".*?class=\'history-user\'>' +
'<a href="(/wiki/User:|/w/index.php[?]title=(Special:Contributions&amp;target=|User:))([^&"]*)');
var match=histRe.exec(split[i]);
if (match) {
edits.push({ oldid: match[1], editor: match[4] });
}
}
}
}
if (!cookieStyle) { ret+= '_p'; }
var userName=getValueOf('popupUserName') ||
return ret;
    Cookie.read(pg.wiki.userNameCookie).split('+').join('_');
}
return finishProcessHistory(edits, userName);
function saneLinkCheck(l) {
if (typeof l.article != typeof {} || typeof l.text != typeof '') { return false; }
return true;
}
function editCounterLink(l) {
if(!saneLinkCheck(l)) return null;
if (! pg.wiki.wikimedia) return null;
var uN=l.article.userName();
var tool=getValueOf('popupEditCounterTool');
var url;
var soxredToolUrl='http://toolserver.org/~soxred93/count/index.php?name=$1&lang=$2&wiki=$3';
var kateToolUrl='http://toolserver.org/~$3/cgi-bin/Tool1/wannabe_kate?username=$1&site=en.wikipedia.org&$2';
switch(tool) {
case 'custom':
url=simplePrintf(getValueOf('popupEditCounterUrl'), [ encodeURIComponent(uN), toolDbName() ]);
break;
case 'kate':
case 'interiot':
url=simplePrintf(kateToolUrl, [ encodeURIComponent(uN), toolDbName(), tool ]);
break;
default:
    var theWiki=pg.wiki.hostname.split('.');
url=simplePrintf(soxredToolUrl, [ encodeURIComponent(uN), theWiki[0], theWiki[1] ]);
}
return generalNavLink({url:url, title: tprintf('editCounterLinkHint', [uN]),
newWin:l.newWin, text: l.text, noPopup:1});
}
function globalSearchLink(l) {
if(!saneLinkCheck(l)) return null;
var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search=';
var article=l.article.urlString({keepSpaces:true});
return generalNavLink({url:base + article, newWin:l.newWin,
title: tprintf('globalSearchHint', [article]),
text: l.text, noPopup:1});
}
function googleLink(l) {
if(!saneLinkCheck(l)) return null;
var base='http://www.google.com/search?q=';
var article=l.article.urlString({keepSpaces:true});
return generalNavLink({url:base + '%22' + article + '%22', newWin:l.newWin,
title: tprintf('googleSearchHint', [article]),
text: l.text, noPopup:1});
}
function editorListLink(l) {
if(!saneLinkCheck(l)) return null;
var article= l.article.articleFromTalkPage() || l.article;
var base='http://toolserver.org/~tim/cgi-bin/contribution-counter?page=';
return generalNavLink({url:base+article.urlString(),
title: tprintf('editorListHint', [article]),
newWin:l.newWin, text: l.text, noPopup:1});
}
function generalNavLink(l) {
l.className = (l.className==null) ? 'popupNavLink' : l.className;
return generalLink(l);
}
//////////////////////////////////////////////////
// magic history links
//
function getHistoryInfo(wikipage, whatNext) {
log('getHistoryInfo');
getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory);
}
// FIXME eliminate pg.idNumber ... how? :-(
function getHistory(wikipage, onComplete) {
log('getHistory');
if( !window.wgEnableAPI || !wgEnableAPI ) {
alert( 'This function of navigation popups now requires a MediaWiki ' +  
'installation with the API enabled.');
return false;
}
var url = pg.wiki.wikibase + '/api.php?format=json&action=query&prop=revisions&titles=' +
new Title(wikipage).urlString() + '&rvlimit=' + getValueOf('popupHistoryLimit');
log('getHistory: url='+url);
return startDownload(url, pg.idNumber+'history', onComplete);
}
}
 
function processHistory(download) {
function processHistoryQuery(download) {
var jsobj = getJsObj(download.data);
log ('processHistoryQuery');
var d=download.data;
log('d='+d);
var jsobj;
try {
try {
log('trying to parse JSON');
log('jsobj=' + d);
eval('jsobj=' + d);
log('done eval; jsobj='+jsobj);
window.x=jsobj;
window.x=jsobj;
var p=jsobj['query']['pages']
var p=jsobj['pages'];
log('got p');
for (var pageid in p) {
for (var pageid in p) {
var revisions=p[pageid]['revisions'];
var revisions=p[pageid]['revisions'];
Строка 7463: Строка 7358:
break;
break;
}
}
log('got revisions');
log(revisions.length +' of them');
} catch (someError) {
} catch (someError) {
log('Something went wrong with JSON business');
log('Something went wrong with JSON business');
Строка 7472: Строка 7369:
}
}
log('processed ' + edits.length + ' edits');
log('processed ' + edits.length + ' edits');
return finishProcessHistory(edits, wgUserName);
var userName=getValueOf('popupUserName') ||
    unescape(Cookie.read(pg.wiki.userNameCookie).split('+').join(' '));
return finishProcessHistory(edits, userName);
}
}
 
 
function finishProcessHistory(edits, userName) {
function finishProcessHistory(edits, userName) {
var histInfo={};
var histInfo={};
 
histInfo.edits=edits;
histInfo.edits=edits;
histInfo.userName=userName;
histInfo.userName=userName;
 
for (var i=0; i<edits.length; ++i) {
for (var i=0; i<edits.length; ++i) {
if (typeof histInfo.myLastEdit == 'undefined' && userName && edits[i].editor==userName) {
if (typeof histInfo.myLastEdit == 'undefined' && userName && edits[i].editor==userName) {
Строка 7498: Строка 7397:
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// options
// options
 
// check for cookies and existing value, else use default
// check for cookies and existing value, else use default
function defaultize(x) {
function defaultize(x) {
Строка 7514: Строка 7413:
}
}
}
}
 
function newOption(x, def) {
function newOption(x, def) {
pg.optionDefault[x]=def;
pg.optionDefault[x]=def;
}
}
 
function setDefault(x, def) {
function setDefault(x, def) {
return newOption(x, def);
return newOption(x, def);
}
}
 
function getValueOf(varName) {
function getValueOf(varName) {
defaultize(varName);
defaultize(varName);
return pg.option[varName];
return pg.option[varName];
}
}
 
function useDefaultOptions() { // for testing
function useDefaultOptions() { // for testing
for (var p in pg.optionDefault) {
for (var p in pg.optionDefault) {
Строка 7534: Строка 7433:
}
}
}
}
 
function setOptions() {
function setOptions() {
// user-settable parameters and defaults
// user-settable parameters and defaults
 
// Basic options
// Basic options
newOption('popupDelay',              0.5);
newOption('popupDelay',              0.5);
Строка 7556: Строка 7455:
newOption('popupTocLinks',            false);
newOption('popupTocLinks',            false);
newOption('popupSubpopups',          true);
newOption('popupSubpopups',          true);
newOption('popupUserName',            ''); // should be magically detected with cookies if this isn't set
newOption('popupDragHandle',          false /* 'popupTopLinks'*/);
newOption('popupDragHandle',          false /* 'popupTopLinks'*/);
newOption('popupLazyPreviews',        true);
newOption('popupLazyPreviews',        true);
Строка 7564: Строка 7464:
newOption('popupActiveNavlinks',      true);
newOption('popupActiveNavlinks',      true);
newOption('popupModifier',            false); // ctrl, shift, alt or meta
newOption('popupModifier',            false); // ctrl, shift, alt or meta
newOption('popupModifierAction',      'enable'); // or 'disable'
 
newOption('popupDraggable',          true);
//<NOLITE>
//<NOLITE>
// images
// images
Строка 7578: Строка 7476:
newOption('popupThumbAction',            'imagepage'); //'sizetoggle');
newOption('popupThumbAction',            'imagepage'); //'sizetoggle');
newOption('popupImageSize',              60);
newOption('popupImageSize',              60);
newOption('popupShowNonCommonsImages',  false);
 
// redirs, dabs, reversion
// redirs, dabs, reversion
newOption('popupFixRedirs',            false);
newOption('popupFixRedirs',            false);
Строка 7588: Строка 7487:
newOption('popupWatchDisambiggedPages', null);
newOption('popupWatchDisambiggedPages', null);
newOption('popupWatchRedirredPages',    null);
newOption('popupWatchRedirredPages',    null);
newOption('popupDabWiktionary',        'last');
 
// navlinks
// navlinks
newOption('popupNavLinks',          true);
newOption('popupNavLinks',          true);
newOption('popupNavLinkSeparator',  ' &sdot; ');
newOption('popupNavLinkSeparator',  ' &sdot; ');
newOption('popupLastEditLink',      true);
newOption('popupLastEditLink',      true);
newOption('popupEditCounterTool',  'soxred');
newOption('popupEditCounterTool',  'interiot');
newOption('popupEditCounterUrl',   '');
newOption('popupEditCounterUrl',   '');
newOption('popupExtraUserMenu',    '');
newOption('popupExtraUserMenu',    '');
//</NOLITE>
//</NOLITE>
 
// previews etc
// previews etc
newOption('popupPreviews',            true);
newOption('popupPreviews',            true);
Строка 7606: Строка 7504:
newOption('popupLastModified',        true);
newOption('popupLastModified',        true);
newOption('popupPreviewKillTemplates', true);
newOption('popupPreviewKillTemplates', true);
newOption('popupPreviewRawTemplates',  true);
newOption('popupPreviewRawTemplates',  false);
newOption('popupPreviewFirstParOnly',  true);
newOption('popupPreviewFirstParOnly',  true);
newOption('popupPreviewCutHeadings',  true);
newOption('popupPreviewCutHeadings',  true);
newOption('popupPreviewButton',        false);
 
newOption('popupPreviewButtonEvent',  'click');
//<NOLITE>
//<NOLITE>
// diffs
// diffs
Строка 7620: Строка 7516:
newOption('popupDiffDates',            true);
newOption('popupDiffDates',            true);
newOption('popupDiffDatePrinter',      'toLocaleString');
newOption('popupDiffDatePrinter',      'toLocaleString');
 
// edit summaries. God, these are ugly.
// edit summaries. God, these are ugly.
newOption('popupFixDabsSummary',          popupString('defaultpopupFixDabsSummary') );
newOption('popupFixDabsSummary',          popupString('defaultpopupFixDabsSummary') );
Строка 7642: Строка 7538:
      popupFilterLastModified]);
      popupFilterLastModified]);
newOption('extraPopupFilters',        []);
newOption('extraPopupFilters',        []);
newOption('popupOnEditSelection', 'cursor');
newOption('popupOnEditSelection',     'cursor');
newOption('popupUseQueryInterface',  true);
newOption('popupPreviewHistory',      true);
newOption('popupPreviewHistory',      true);
newOption('popupImageLinks',          true);
newOption('popupImageLinks',          true);
newOption('popupCategoryMembers',    true);
newOption('popupCategoryMembers',    true);
newOption('popupUserInfo',            true);
newOption('popupHistoryPreviewLimit', 25);
newOption('popupHistoryPreviewLimit', 25);
newOption('popupContribsPreviewLimit',25);
newOption('popupContribsPreviewLimit',25);
//</NOLITE>
//</NOLITE>
 
// new windows
// new windows
newOption('popupNewWindows',    false);
newOption('popupNewWindows',    false);
newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true});
newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true});
 
// regexps
// regexps
newOption('popupDabRegexp', '([{][{]\\s*disambig|disambig\\s*[}][}]|disamb\\s*[}][}]|dab\\s*[}][}])|[{][{]\\s*(((geo|hn|road?|school|number)dis)|[234][lc][acw]|shipindex)(\\s*[|][^}]*)?\\s*[}][}]|is a .*disambiguation.*page');
newOption('popupDabRegexp', '([{][{]\\s*disambig|disambig\\s*[}][}]|disamb\\s*[}][}]|dab\\s*[}][}])|[{][{]\\s*(((geo|hn|road?|school|number)dis)|[234][lc][acw]|shipindex)(\\s*[|][^}]*)?\\s*[}][}]|is a .*disambiguation.*page');
Строка 7669: Строка 7565:
// See instructions at
// See instructions at
// http://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation
// http://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation
 
pg.string = {
pg.string = {
/////////////////////////////////////
/////////////////////////////////////
Строка 7707: Строка 7603:
'popupsMenu': 'popups',
'popupsMenu': 'popups',
'togglePreviewsHint': 'Toggle preview generation in popups on this page',
'togglePreviewsHint': 'Toggle preview generation in popups on this page',
'enable previews': 'enable previews',
'disable preview': 'disable previews',
'toggle previews': 'toggle previews',
'toggle previews': 'toggle previews',
'show preview': 'show preview',
'reset': 'reset',
'reset': 'reset',
'more...': 'more...',
'more...': 'more...',
Строка 7838: Строка 7731:
'No image links found': 'No image links found',
'No image links found': 'No image links found',
'File links': 'File links',
'File links': 'File links',
'not commons': 'There is no file with this name on the Wikimedia Commons.',
'commons only': 'This file is from the Wikimedia Commons.',
'No image found': 'No image found',
'No image found': 'No image found',
'Image from Commons': 'Image from Commons',
'commons dupe': 'The same file appears to be available on the Wikimedia Commons.',
'Description page': 'Description page',
'commons conflict': 'A different file with the same name is available on the Wikimedia Commons.',
/////////////////////////////////////
/////////////////////////////////////
// user-related actions and info
// user-related actions and info
Строка 7854: Строка 7749:
'space': 'space', // short form for userSpace link
'space': 'space', // short form for userSpace link
'PrefixindexHint': 'Show pages in the userspace of %s',
'PrefixindexHint': 'Show pages in the userspace of %s',
'count': 'count',            ///// contributions, log
'count': 'count',            ///// contributions, tree, log
'edit counter': 'edit counter',
'edit counter': 'edit counter',
'editCounterLinkHint': 'Count the contributions made by %s',
'katelinkHint': 'Count the countributions made by %s',
'contribs': 'contribs',
'contribs': 'contribs',
'contributions': 'contributions',
'contributions': 'contributions',
'deletedContribs': 'deleted contributions',
'DeletedcontributionsHint': 'List deleted edits made by %s',
'ContributionsHint': 'List the contributions made by %s',
'ContributionsHint': 'List the contributions made by %s',
'tree': 'tree',
'contribsTreeHint': 'Explore %s\'s contributions by namespace and by article',
'log': 'log',
'log': 'log',
'user log': 'user log',
'user log': 'user log',
Строка 7883: Строка 7778:
'undoHint': 'undo this edit',
'undoHint': 'undo this edit',
'Download preview data': 'Download preview data',
'Download preview data': 'Download preview data',
'Invalid or IP user': 'Invalid or IP user',
'Not a registered username': 'Not a registered username',
'BLOCKED': 'BLOCKED',
' edits since: ': ' edits since: ',
/////////////////////////////////////
/////////////////////////////////////
// Autoediting
// Autoediting
Строка 7900: Строка 7791:
'zxy': 'zxy'
'zxy': 'zxy'
};
};
 
 
function popupString(str) {
function popupString(str) {
if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { return popupStrings[str]; }
if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { return popupStrings[str]; }
Строка 7907: Строка 7798:
return str;
return str;
}
}
 
 
function tprintf(str,subs) {
function tprintf(str,subs) {
if (typeof subs != typeof []) { subs = [subs]; }
if (typeof subs != typeof []) { subs = [subs]; }
return simplePrintf(popupString(str), subs);
return simplePrintf(popupString(str), subs);
}
}
 
//</NOLITE>
//</NOLITE>
// ENDFILE: strings.js
// ENDFILE: strings.js
////////////////////////////////////////////////////////////////////
// Run things
////////////////////////////////////////////////////////////////////
hookEvent('load', setupPopups);
hookEvent('load', autoEdit);