今天是2024年11月20日 第47周 星期三

代人,时大变了。

我们生活在大地上,但我们的梦想超越天空。

變更

跳至導覽 跳至搜尋
移除 9,624 位元組 、 2020年6月5日 (五) 21:59
無編輯摘要
行 1: 行 1: −
$(function() {
+
// STARTFILE: main.js
   var pg = {
+
// **********************************************************************
     re: {},
+
// **                                  **
     ns: {},
+
// **       changes to this file affect many users.        **
     string: {},
+
// **      please discuss on the talk page before editing     **
     wiki: {},
+
// **                                  **
     user: {},
+
// **********************************************************************
     misc: {},
+
// **                                  **
     option: {},
+
// ** if you do edit this file, be sure that your editor recognizes it **
     optionDefault: {},
+
// ** as utf8, or the weird and wonderful characters in the namespaces **
     flag: {},
+
// **  below will be completely broken. You can check with the show  **
     cache: {},
+
// **       changes button before submitting the edit.       **
     structures: {},
+
// **            test: مدیا מיוחד Мэдыя            **
     timer: {},
+
// **                                  **
     counter: {},
+
// **********************************************************************
     current: {},
+
/* eslint-env browser  */
     fn: {},
+
/* global $, jQuery, mw, window */
     endoflist: null
+
 
   };
+
// Fix later
   if (window.pg) {
+
/* global log, errlog, popupStrings, wikEdUseWikEd, WikEdUpdateFrame */
     return;
+
/* eslint no-mixed-spaces-and-tabs: 0, no-empty: 0 */
 +
 
 +
$(function () {
 +
//////////////////////////////////////////////////
 +
// Globals
 +
//
 +
 
 +
// Trying to shove as many of these as possible into the pg (popup globals) object
 +
var pg = {
 +
re: {},         // regexps
 +
ns: {},         // namespaces
 +
string: {},       // translatable strings
 +
wiki: {},        // local site info
 +
user: {},        // current user info
 +
misc: {},        // YUCK PHOOEY
 +
option: {},       // options, see newOption etc
 +
optionDefault: {},   // default option values
 +
flag: {},        // misc flags
 +
cache: {},       // page and image cache
 +
structures: {},     // navlink structures
 +
timer: {},       // all sorts of timers (too damn many)
 +
counter: {},      // .. and all sorts of counters
 +
current: {},      // state info
 +
fn: {},         // functions
 +
endoflist: null
 +
};
 +
/* Bail if the gadget/script is being loaded twice */
 +
if( window.pg ) {
 +
return;
 +
}
 +
/* Export to global context */
 +
window.pg = pg;
 +
 
 +
/// Local Variables: ///
 +
/// mode:c ///
 +
/// End: ///
 +
// ENDFILE: main.js
 +
// STARTFILE: actions.js
 +
function setupTooltips(container, remove, force, popData) {
 +
log('setupTooltips, container='+container+', remove='+remove);
 +
if (!container) {
 +
//<NOLITE>
 +
// the main initial call
 +
if (getValueOf('popupOnEditSelection') && document && document.editform && document.editform.wpTextbox1) {
 +
document.editform.wpTextbox1.onmouseup=doSelectionPopup;
 +
}
 +
//</NOLITE>
 +
// article/content is a structure-dependent thing
 +
container = defaultPopupsContainer();
 +
}
 +
 
 +
if (!remove && !force && container.ranSetupTooltipsAlready) { return; }
 +
container.ranSetupTooltipsAlready = !remove;
 +
 
 +
var anchors;
 +
anchors=container.getElementsByTagName('A');
 +
setupTooltipsLoop(anchors, 0, 250, 100, remove, popData);
 +
}
 +
 
 +
function defaultPopupsContainer() {
 +
if (getValueOf('popupOnlyArticleLinks')) {
 +
return document.getElementById('mw_content') ||
 +
document.getElementById('content') ||
 +
document.getElementById('article') || document;
 +
}
 +
return  document;
 +
}
 +
 
 +
function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) {
 +
log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments));
 +
var finish=begin+howmany;
 +
var loopend = Math.min(finish, anchors.length);
 +
var j=loopend - begin;
 +
log ('setupTooltips: anchors.length=' + anchors.length + ', begin=' + begin +
 +
', howmany=' + howmany + ', loopend=' + loopend + ', remove=' + remove);
 +
var doTooltip= remove ? removeTooltip : addTooltip;
 +
// try a faster (?) loop construct
 +
if (j > 0) {
 +
do {
 +
var a=anchors[loopend - j];
 +
if (typeof a==='undefined' || !a || !a.href) {
 +
log('got null anchor at index ' + loopend - j);
 +
continue;
 +
}
 +
doTooltip(a, popData);
 +
} while (--j);
 +
}
 +
if (finish < anchors.length) {
 +
setTimeout(function() {
 +
setupTooltipsLoop(anchors,finish,howmany,sleep,remove,popData);},
 +
sleep);
 +
} else {
 +
if ( !remove && ! getValueOf('popupTocLinks')) { rmTocTooltips(); }
 +
pg.flag.finishedLoading=true;
 +
}
 +
}
 +
 
 +
// eliminate popups from the TOC
 +
// This also kills any onclick stuff that used to be going on in the toc
 +
function rmTocTooltips() {
 +
var toc=document.getElementById('toc');
 +
if (toc) {
 +
var tocLinks=toc.getElementsByTagName('A');
 +
var tocLen = tocLinks.length;
 +
for (var j=0; j<tocLen; ++j) {
 +
removeTooltip(tocLinks[j], true);
 +
}
 +
}
 +
}
 +
 
 +
function addTooltip(a, popData) {
 +
if ( !isPopupLink(a) ) { return; }
 +
a.onmouseover=mouseOverWikiLink;
 +
a.onmouseout= mouseOutWikiLink;
 +
a.onmousedown = killPopup;
 +
a.hasPopup = true;
 +
a.popData = popData;
 +
}
 +
 
 +
function removeTooltip(a) {
 +
if ( !a.hasPopup ) { return; }
 +
a.onmouseover = null;
 +
a.onmouseout = null;
 +
if (a.originalTitle) { a.title = a.originalTitle; }
 +
a.hasPopup=false;
 +
}
 +
 
 +
function removeTitle(a) {
 +
if (!a.originalTitle) {
 +
a.originalTitle=a.title;
 +
}
 +
a.title='';
 +
}
 +
 
 +
function restoreTitle(a) {
 +
if ( a.title || !a.originalTitle ) { return; }
 +
a.title = a.originalTitle;
 +
}
 +
 
 +
function registerHooks(np) {
 +
var popupMaxWidth=getValueOf('popupMaxWidth');
 +
 
 +
if (typeof popupMaxWidth === 'number') {
 +
var setMaxWidth = function () {
 +
np.mainDiv.style.maxWidth = popupMaxWidth + 'px';
 +
np.maxWidth = popupMaxWidth;
 +
};
 +
np.addHook(setMaxWidth, 'unhide', 'before');
 +
}
 +
//<NOLITE>
 +
np.addHook(addPopupShortcuts, 'unhide', 'after');
 +
np.addHook(rmPopupShortcuts, 'hide', 'before');
 +
//</NOLITE>
 +
}
 +
 
 +
function removeModifierKeyHandler(a) {
 +
//remove listeners for modifier key if any that were added in mouseOverWikiLink
 +
document.removeEventListener('keydown', a.modifierKeyHandler, false);
 +
document.removeEventListener('keyup', a.modifierKeyHandler, false);
 +
}
 +
 
 +
function mouseOverWikiLink(evt) {
 +
if (!evt && window.event) {evt=window.event;}
 +
 +
// if the modifier is needed, listen for it,
 +
// we will remove the listener when we mouseout of this link or kill popup.
 +
if (getValueOf('popupModifier')) {
 +
// if popupModifierAction = enable, we should popup when the modifier is pressed
 +
// if popupModifierAction = disable, we should popup unless the modifier is pressed
 +
   var action = getValueOf('popupModifierAction');
 +
   var key = action=='disable' ? 'keyup' : 'keydown';
 +
   var a = this;
 +
   a.modifierKeyHandler = function(evt) {
 +
mouseOverWikiLink2(a, evt);
 +
};
 +
   document.addEventListener(key, a.modifierKeyHandler, false);
 +
}
 +
 
 +
return mouseOverWikiLink2(this, evt);
 +
}
 +
 
 +
/**
 +
* Gets the references list item that the provided footnote link targets. This
 +
* is typically a li element within the ol.references element inside the reflist.
 +
* @param {Element} a - A footnote link.
 +
* @returns {Element|boolean} The targeted element, or false if one can't be found.
 +
*/
 +
function footnoteTarget(a) {
 +
var aTitle=Title.fromAnchor(a);
 +
// We want ".3A" rather than "%3A" or "?" here, so use the anchor property directly
 +
var anch = aTitle.anchor;
 +
if ( ! /^(cite_note-|_note-|endnote)/.test(anch) ) { return false; }
 +
 
 +
var lTitle=Title.fromURL(location.href);
 +
if ( lTitle.toString(true) !== aTitle.toString(true) ) { return false; }
 +
 
 +
var el=document.getElementById(anch);
 +
while ( el && typeof el.nodeName === 'string') {
 +
var nt = el.nodeName.toLowerCase();
 +
if ( nt === 'li' ) { return el; }
 +
else if ( nt === 'body' ) { return false; }
 +
else if ( el.parentNode ) { el=el.parentNode; }
 +
else { return false; }
 +
}
 +
return false;
 +
}
 +
 
 +
function footnotePreview(x, navpop) {
 +
setPopupHTML('<hr />' + x.innerHTML, 'popupPreview', navpop.idNumber);
 +
}
 +
 
 +
function modifierPressed(evt) {
 +
var mod=getValueOf('popupModifier');
 +
if (!mod) { return false; }
 +
 
 +
if (!evt && window.event) {evt=window.event;}
 +
 
 +
return ( evt && mod && evt[mod.toLowerCase() + 'Key'] );
 +
}
 +
 
 +
// Checks if the correct modifier pressed/unpressed if needed
 +
function isCorrectModifier(a,evt) {
 +
if (!getValueOf('popupModifier')) { return true; }
 +
// if popupModifierAction = enable, we should popup when the modifier is pressed
 +
// if popupModifierAction = disable, we should popup unless the modifier is pressed
 +
var action = getValueOf('popupModifierAction');
 +
return ( action ==  'enable' &&  modifierPressed(evt) ||
 +
     action == 'disable' && !modifierPressed(evt) );
 +
}
 +
 
 +
function mouseOverWikiLink2(a, evt) {
 +
if (!isCorrectModifier(a,evt)) { return; }
 +
if ( getValueOf('removeTitles') ) { removeTitle(a); }
 +
if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; }
 +
pg.current.link=a;
 +
 
 +
if (getValueOf('simplePopups') && !pg.option.popupStructure) {
 +
// reset *default value* of popupStructure
 +
setDefault('popupStructure', 'original');
 +
}
 +
 
 +
var article=(new Title()).fromAnchor(a);
 +
// set global variable (ugh) to hold article (wikipage)
 +
pg.current.article = article;
 +
 
 +
if (!a.navpopup) {
 +
a.navpopup=newNavpopup(a, article);
 +
pg.current.linksHash[a.href] = a.navpopup;
 +
pg.current.links.push(a);
 +
}
 +
if (a.navpopup.pending === null || a.navpopup.pending !== 0) {
 +
// either fresh popups or those with unfinshed business are redone from scratch
 +
simplePopupContent(a, article);
 +
}
 +
a.navpopup.showSoonIfStable(a.navpopup.delay);
 +
 
 +
clearInterval(pg.timer.checkPopupPosition);
 +
pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600);
 +
 
 +
if(getValueOf('simplePopups')) {
 +
if (getValueOf('popupPreviewButton') && !a.simpleNoMore) {
 +
var d=document.createElement('div');
 +
d.className='popupPreviewButtonDiv';
 +
var s=document.createElement('span');
 +
d.appendChild(s);
 +
s.className='popupPreviewButton';
 +
s['on' + getValueOf('popupPreviewButtonEvent')] = function() {
 +
a.simpleNoMore=true;
 +
d.style.display = "none";
 +
nonsimplePopupContent(a,article);
 +
};
 +
s.innerHTML=popupString('show preview');
 +
setPopupHTML(d, 'popupPreview', a.navpopup.idNumber);
 +
}
 +
}
 +
 
 +
if (a.navpopup.pending !== 0 ) {
 +
nonsimplePopupContent(a, article);
 +
}
 +
}
 +
 
 +
// simplePopupContent: the content that do not require additional download
 +
// (it is shown even when simplePopups is true)
 +
function simplePopupContent(a, article) {
 +
/* FIXME hack */ a.navpopup.hasPopupMenu=false;
 +
a.navpopup.setInnerHTML(popupHTML(a));
 +
fillEmptySpans({navpopup:a.navpopup});
 +
 
 +
if (getValueOf('popupDraggable'))
 +
{
 +
var dragHandle = getValueOf('popupDragHandle') || null;
 +
if (dragHandle && dragHandle != 'all') {
 +
dragHandle += a.navpopup.idNumber;
 +
}
 +
setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150);
 +
}
 +
 
 +
//<NOLITE>
 +
if (getValueOf('popupRedlinkRemoval') && a.className=='new') {
 +
setPopupHTML('<br>'+popupRedlinkHTML(article), 'popupRedlink', a.navpopup.idNumber);
 +
}
 +
//</NOLITE>
 +
}
 +
 
 +
function debugData(navpopup) {
 +
if(getValueOf('popupDebugging') && navpopup.idNumber) {
 +
setPopupHTML('idNumber='+navpopup.idNumber + ', pending=' + navpopup.pending,
 +
'popupError', navpopup.idNumber);
 +
}
 +
}
 +
 
 +
function newNavpopup(a, article) {
 +
var navpopup = new Navpopup();
 +
navpopup.fuzz=5;
 +
navpopup.delay=getValueOf('popupDelay')*1000;
 +
// increment global counter now
 +
navpopup.idNumber = ++pg.idNumber;
 +
navpopup.parentAnchor = a;
 +
navpopup.parentPopup = (a.popData && a.popData.owner);
 +
navpopup.article = article;
 +
registerHooks(navpopup);
 +
return navpopup;
 +
}
 +
 
 +
// Should we show nonsimple context?
 +
// If simplePopups is set to true, then we do not show nonsimple context,
 +
// but if a bottom "show preview" was clicked we do show nonsimple context
 +
function shouldShowNonSimple(a) {
 +
  return !getValueOf('simplePopups') || a.simpleNoMore;
 +
}
 +
 
 +
// Should we show nonsimple context govern by the option (e.g. popupUserInfo)?
 +
// If the user explicitly asked for nonsimple context by setting the option to true,
 +
// then we show it even in nonsimple mode.
 +
function shouldShow(a,option) {
 +
if (shouldShowNonSimple(a)) {
 +
return getValueOf(option);
 +
} else {
 +
return (typeof window[option] != 'undefined' )  && window[option];
 +
}
 +
}
 +
 
 +
function nonsimplePopupContent(a, article) {
 +
var diff=null, history=null;
 +
var params=parseParams(a.href);
 +
var oldid=(typeof params.oldid=='undefined' ? null : params.oldid);
 +
//<NOLITE>
 +
if(shouldShow(a,'popupPreviewDiffs')) {
 +
diff=params.diff;
 +
}
 +
if(shouldShow(a,'popupPreviewHistory')) {
 +
history=(params.action=='history');
 +
}
 +
//</NOLITE>
 +
a.navpopup.pending=0;
 +
var referenceElement = footnoteTarget(a);
 +
if (referenceElement) {
 +
footnotePreview(referenceElement, a.navpopup);
 +
//<NOLITE>
 +
} else if ( diff || diff === 0 ) {
 +
loadDiff(article, oldid, diff, a.navpopup);
 +
} else if ( history ) {
 +
loadAPIPreview('history', article, a.navpopup);
 +
} else if ( shouldShowNonSimple(a) && pg.re.contribs.test(a.href) ) {
 +
loadAPIPreview('contribs', article, a.navpopup);
 +
} else if ( shouldShowNonSimple(a) && pg.re.backlinks.test(a.href) ) {
 +
loadAPIPreview('backlinks', article, a.navpopup);
 +
} else if ( // FIXME should be able to get all preview combinations with options
 +
article.namespaceId()==pg.nsImageId &&
 +
( shouldShow(a,'imagePopupsForImages') || ! anchorContainsImage(a) )
 +
) {
 +
loadAPIPreview('imagepagepreview', article, a.navpopup);
 +
loadImage(article, a.navpopup);
 +
//</NOLITE>
 +
} else {
 +
if (article.namespaceId() == pg.nsCategoryId &&
 +
shouldShow(a,'popupCategoryMembers')) {
 +
loadAPIPreview('category', article, a.navpopup);
 +
} else if ((article.namespaceId() == pg.nsUserId || article.namespaceId() == pg.nsUsertalkId) &&
 +
shouldShow(a,'popupUserInfo')) {
 +
loadAPIPreview('userinfo', article, a.navpopup);
 +
}
 +
if (shouldShowNonSimple(a)) startArticlePreview(article, oldid, a.navpopup);
 +
}
 +
}
 +
 
 +
function pendingNavpopTask(navpop) {
 +
if (navpop && navpop.pending === null) { navpop.pending=0; }
 +
++navpop.pending;
 +
debugData(navpop);
 +
}
 +
 
 +
function completedNavpopTask(navpop) {
 +
if (navpop && navpop.pending) { --navpop.pending; }
 +
debugData(navpop);
 +
}
 +
 
 +
function startArticlePreview(article, oldid, navpop) {
 +
navpop.redir=0;
 +
loadPreview(article, oldid, navpop);
 +
}
 +
 
 +
function loadPreview(article, oldid, navpop) {
 +
if (!navpop.redir) { navpop.originalArticle=article; }
 +
article.oldid = oldid;
 +
loadAPIPreview('revision', article, navpop);
 +
}
 +
 
 +
function loadPreviewFromRedir(redirMatch, navpop) {
 +
// redirMatch is a regex match
 +
var target = new Title().fromWikiText(redirMatch[2]);
 +
// overwrite (or add) anchor from original target
 +
// mediawiki does overwrite; eg [[User:Lupin/foo3#Done]]
 +
if ( navpop.article.anchor ) { target.anchor = navpop.article.anchor; }
 +
navpop.redir++;
 +
navpop.redirTarget=target;
 +
//<NOLITE>
 +
var warnRedir = redirLink(target, navpop.article);
 +
setPopupHTML(warnRedir, 'popupWarnRedir', navpop.idNumber);
 +
//</NOLITE>
 +
navpop.article=target;
 +
fillEmptySpans({redir: true, redirTarget: target, navpopup:navpop});
 +
return loadPreview(target, null,  navpop);
 +
}
 +
 
 +
function insertPreview(download) {
 +
if (!download.owner) { return; }
 +
 
 +
var redirMatch = pg.re.redirect.exec(download.data);
 +
if (download.owner.redir === 0 && redirMatch) {
 +
loadPreviewFromRedir(redirMatch, download.owner);
 +
return;
 +
}
 +
 
 +
if (download.owner.visible || !getValueOf('popupLazyPreviews')) {
 +
insertPreviewNow(download);
 +
} else {
 +
var id=(download.owner.redir) ? 'PREVIEW_REDIR_HOOK' : 'PREVIEW_HOOK';
 +
download.owner.addHook( function(){insertPreviewNow(download); return true;},
 +
'unhide', 'after', id );
 +
}
 +
}
 +
 
 +
function insertPreviewNow(download) {
 +
if (!download.owner) { return; }
 +
var wikiText=download.data;
 +
var navpop=download.owner;
 +
var art=navpop.redirTarget || navpop.originalArticle;
 +
 
 +
//<NOLITE>
 +
makeFixDabs(wikiText, navpop);
 +
if (getValueOf('popupSummaryData')) {
 +
getPageInfo(wikiText, download);
 +
setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber);
 +
}
 +
 
 +
var imagePage='';
 +
if (art.namespaceId()==pg.nsImageId) { imagePage=art.toString(); }
 +
else { imagePage=getValidImageFromWikiText(wikiText); }
 +
if(imagePage) { loadImage(Title.fromWikiText(imagePage), navpop); }
 +
//</NOLITE>
 +
 
 +
if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); }
 +
 
 +
}
 +
 
 +
function insertArticlePreview(download, art, navpop) {
 +
if (download && typeof download.data == typeof ''){
 +
if (art.namespaceId()==pg.nsTemplateId && getValueOf('popupPreviewRawTemplates')) {
 +
// FIXME compare/consolidate with diff escaping code for wikitext
 +
var h='<hr /><span style="font-family: monospace;">' + download.data.entify().split('\\n').join('<br />\\n') + '</span>';
 +
setPopupHTML(h, 'popupPreview', navpop.idNumber);
 +
}
 +
else {
 +
var p=prepPreviewmaker(download.data, art, navpop);
 +
p.showPreview();
 +
}
 +
}
 +
}
 +
 
 +
function prepPreviewmaker(data, article, navpop) {
 +
// deal with tricksy anchors
 +
var d=anchorize(data, article.anchorString());
 +
var urlBase=joinPath([pg.wiki.articlebase, article.urlString()]);
 +
var p=new Previewmaker(d, urlBase, navpop);
 +
return p;
 +
}
 +
 
 +
 
 +
// Try to imitate the way mediawiki generates HTML anchors from section titles
 +
function anchorize(d, anch) {
 +
if (!anch) { return d; }
 +
var anchRe=RegExp('(?:=+\\s*' + literalizeRegex(anch).replace(/[_ ]/g, '[_ ]') + '\\s*=+|\\{\\{\\s*'+getValueOf('popupAnchorRegexp')+'\\s*(?:\\|[^|}]*)*?\\s*'+literalizeRegex(anch)+'\\s*(?:\\|[^}]*)?}})');
 +
var match=d.match(anchRe);
 +
if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); }
 +
 
 +
// now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom
 +
var lines=d.split('\n');
 +
for (var i=0; i<lines.length; ++i) {
 +
lines[i]=lines[i].replace(RegExp('[[]{2}([^|\\]]*?[|])?(.*?)[\\]]{2}', 'g'), '$2')
 +
.replace(/'''([^'])/g, '$1').replace(RegExp("''([^'])", 'g'), '$1');
 +
if (lines[i].match(anchRe)) {
 +
return d.split('\n').slice(i).join('\n').replace(RegExp('^[^=]*'), '');
 +
}
 +
}
 +
return d;
 +
}
 +
 
 +
function killPopup() {
 +
removeModifierKeyHandler(this);
 +
if (getValueOf('popupShortcutKeys')) { rmPopupShortcuts(); }
 +
if (!pg) { return; }
 +
if (pg.current.link && pg.current.link.navpopup) { pg.current.link.navpopup.banish(); }
 +
pg.current.link=null;
 +
abortAllDownloads();
 +
if (pg.timer.checkPopupPosition) {
 +
clearInterval(pg.timer.checkPopupPosition);
 +
pg.timer.checkPopupPosition=null;
 +
}
 +
return true; // preserve default action
 +
}
 +
// ENDFILE: actions.js
 +
// STARTFILE: domdrag.js
 +
/**
 +
  @fileoverview
 +
  The {@link Drag} object, which enables objects to be dragged around.
 +
 
 +
  <pre>
 +
  *************************************************
 +
  dom-drag.js
 +
  09.25.2001
 +
  www.youngpup.net
 +
  **************************************************
 +
  10.28.2001 - fixed minor bug where events
 +
  sometimes fired off the handle, not the root.
 +
  *************************************************
 +
  Pared down, some hooks added by [[User:Lupin]]
 +
 
 +
  Copyright Aaron Boodman.
 +
  Saying stupid things daily since March 2001.
 +
  </pre>
 +
*/
 +
 
 +
/**
 +
  Creates a new Drag object. This is used to make various DOM elements draggable.
 +
  @constructor
 +
*/
 +
function Drag () {
 +
/**
 +
  Condition to determine whether or not to drag. This function should take one parameter, an Event.
 +
  To disable this, set it to <code>null</code>.
 +
  @type Function
 +
*/
 +
this.startCondition = null;
 +
/**
 +
  Hook to be run when the drag finishes. This is passed the final coordinates of
 +
  the dragged object (two integers, x and y). To disables this, set it to <code>null</code>.
 +
  @type Function
 +
*/
 +
this.endHook = null;
 +
}
 +
 
 +
/**
 +
  Gets an event in a cross-browser manner.
 +
  @param {Event} e
 +
  @private
 +
*/
 +
Drag.prototype.fixE = function(e) {
 +
if (typeof e == 'undefined') { e = window.event; }
 +
if (typeof e.layerX == 'undefined') { e.layerX = e.offsetX; }
 +
if (typeof e.layerY == 'undefined') { e.layerY = e.offsetY; }
 +
return e;
 +
};
 +
/**
 +
  Initialises the Drag instance by telling it which object you want to be draggable, and what you want to drag it by.
 +
  @param {DOMElement} o The "handle" by which <code>oRoot</code> is dragged.
 +
  @param {DOMElement} oRoot The object which moves when <code>o</code> is dragged, or <code>o</code> if omitted.
 +
*/
 +
Drag.prototype.init = function(o, oRoot) {
 +
var dragObj   = this;
 +
this.obj = o;
 +
o.onmousedown = function(e) { dragObj.start.apply( dragObj, [e]); };
 +
o.dragging   = false;
 +
o.popups_draggable   = true;
 +
o.hmode   = true;
 +
o.vmode   = true;
 +
 
 +
o.root = oRoot ? oRoot : o ;
 +
 
 +
if (isNaN(parseInt(o.root.style.left, 10))) { o.root.style.left  = "0px"; }
 +
if (isNaN(parseInt(o.root.style.top,  10))) { o.root.style.top = "0px"; }
 +
 
 +
o.root.onthisStart  = function(){};
 +
o.root.onthisEnd = function(){};
 +
o.root.onthis   = function(){};
 +
};
 +
 
 +
/**
 +
  Starts the drag.
 +
  @private
 +
  @param {Event} e
 +
*/
 +
Drag.prototype.start = function(e) {
 +
var o = this.obj; // = this;
 +
e = this.fixE(e);
 +
if (this.startCondition && !this.startCondition(e)) { return; }
 +
var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom, 10);
 +
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10);
 +
o.root.onthisStart(x, y);
 +
 
 +
o.lastMouseX = e.clientX;
 +
o.lastMouseY = e.clientY;
 +
 
 +
var dragObj   = this;
 +
o.onmousemoveDefault = document.onmousemove;
 +
o.dragging   = true;
 +
document.onmousemove = function(e) { dragObj.drag.apply( dragObj, [e] ); };
 +
document.onmouseup   = function(e) { dragObj.end.apply( dragObj, [e] ); };
 +
return false;
 +
};
 +
/**
 +
  Does the drag.
 +
  @param {Event} e
 +
  @private
 +
*/
 +
Drag.prototype.drag = function(e) {
 +
e = this.fixE(e);
 +
var o = this.obj;
 +
 
 +
var ey = e.clientY;
 +
var ex = e.clientX;
 +
var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom, 10);
 +
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10 );
 +
var nx, ny;
 +
 
 +
nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
 +
ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
 +
 
 +
this.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
 +
this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
 +
this.obj.lastMouseX = ex;
 +
this.obj.lastMouseY = ey;
 +
 
 +
this.obj.root.onthis(nx, ny);
 +
return false;
 +
};
 +
 
 +
/**
 +
  Ends the drag.
 +
  @private
 +
*/
 +
Drag.prototype.end = function()  {
 +
document.onmousemove=this.obj.onmousemoveDefault;
 +
document.onmouseup  = null;
 +
this.obj.dragging = false;
 +
if (this.endHook) {
 +
this.endHook( parseInt(this.obj.root.style[this.obj.hmode ? "left" : "right"], 10),
 +
  parseInt(this.obj.root.style[this.obj.vmode ? "top" : "bottom"], 10));
 +
}
 +
};
 +
// ENDFILE: domdrag.js
 +
// STARTFILE: structures.js
 +
//<NOLITE>
 +
pg.structures.original={};
 +
pg.structures.original.popupLayout=function () {
 +
return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle',
 +
'popupUserData', 'popupData', 'popupOtherLinks',
 +
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks',
 +
  'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
 +
'popupMiscTools', ['popupRedlink'],
 +
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
 +
};
 +
pg.structures.original.popupRedirSpans=function () {
 +
return ['popupRedir', 'popupWarnRedir', 'popupRedirTopLinks',
 +
'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'];
 +
};
 +
pg.structures.original.popupTitle=function (x) {
 +
log ('defaultstructure.popupTitle');
 +
if (!getValueOf('popupNavLinks')) {
 +
return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params);
 +
}
 +
return '';
 +
};
 +
pg.structures.original.popupTopLinks=function (x) {
 +
log ('defaultstructure.popupTopLinks');
 +
if (getValueOf('popupNavLinks')) { return navLinksHTML(x.article, x.hint, x.params); }
 +
return '';
 +
};
 +
pg.structures.original.popupImage=function(x) {
 +
log ('original.popupImage, x.article='+x.article+', x.navpop.idNumber='+x.navpop.idNumber);
 +
return imageHTML(x.article, x.navpop.idNumber);
 +
};
 +
pg.structures.original.popupRedirTitle=pg.structures.original.popupTitle;
 +
pg.structures.original.popupRedirTopLinks=pg.structures.original.popupTopLinks;
 +
 
 +
 
 +
function copyStructure(oldStructure, newStructure) {
 +
pg.structures[newStructure]={};
 +
for (var prop in pg.structures[oldStructure]) {
 +
pg.structures[newStructure][prop]=pg.structures[oldStructure][prop];
 +
}
 +
}
 +
 
 +
copyStructure('original', 'nostalgia');
 +
pg.structures.nostalgia.popupTopLinks=function(x)  {
 +
var str='';
 +
str += '<b><<mainlink|shortcut= >></b>';
 +
 
 +
// user links
 +
// contribs - log - count - email - block
 +
// count only if applicable; block only if popupAdminLinks
 +
str += 'if(user){<br><<contribs|shortcut=c>>';
 +
str+='if(wikimedia){*<<count|shortcut=#>>}';
 +
str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>}}';
 +
 
 +
// editing links
 +
// talkpage  -> edit|new - history - un|watch - article|edit
 +
// other page -> edit - history - un|watch - talk|edit|new
 +
var editstr='<<edit|shortcut=e>>';
 +
var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' +
 +
editstr + '}';
 +
var historystr='<<history|shortcut=h>>';
 +
var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
 +
 
 +
str += '<br>if(talk){' +
 +
editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' +
 +
'<b><<article|shortcut=a>></b>|<<editArticle|edit>>' +
 +
'}else{' + // not a talk page
 +
editOldidStr + '*' + historystr + '*' + watchstr + '*' +
 +
'<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>}';
 +
 
 +
// misc links
 +
str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>';
 +
str += 'if(admin){<br>}else{*}<<move|shortcut=m>>';
 +
 
 +
// admin links
 +
str += 'if(admin){*<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*' +
 +
'<<undelete|undeleteShort>>|<<delete|shortcut=d>>}';
 +
return navlinkStringToHTML(str, x.article, x.params);
 +
};
 +
pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks;
 +
 
 +
/** -- fancy -- **/
 +
copyStructure('original', 'fancy');
 +
pg.structures.fancy.popupTitle=function (x) {
 +
return navlinkStringToHTML('<font size=+0><<mainlink>></font>',x.article,x.params);
 +
};
 +
pg.structures.fancy.popupTopLinks=function(x) {
 +
var hist='<<history|shortcut=h|hist>>|<<lastEdit|shortcut=/|last>>|<<editors|shortcut=E|eds>>';
 +
var watch='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
 +
var move='<<move|shortcut=m|move>>';
 +
return navlinkStringToHTML('if(talk){' +
 +
  '<<edit|shortcut=e>>|<<new|shortcut=+|+>>*' + hist + '*' +
 +
  '<<article|shortcut=a>>|<<editArticle|edit>>' + '*' + watch + '*' + move +
 +
  '}else{<<edit|shortcut=e>>*' + hist +
 +
  '*<<talk|shortcut=t|>>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>' +
 +
  '*' + watch + '*' + move+'}<br>', x.article, x.params);
 +
};
 +
pg.structures.fancy.popupOtherLinks=function(x) {
 +
var admin='<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*<<undelete|undeleteShort>>|<<delete|shortcut=d|del>>';
 +
var user='<<contribs|shortcut=c>>if(wikimedia){|<<count|shortcut=#|#>>}';
 +
user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+
 +
popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}';
 +
 
 +
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,
 +
  x.article, x.params);
 +
};
 +
pg.structures.fancy.popupRedirTitle=pg.structures.fancy.popupTitle;
 +
pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks;
 +
pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks;
 +
 
 +
 
 +
/** -- fancy2 -- **/
 +
// hack for [[User:MacGyverMagic]]
 +
copyStructure('fancy', 'fancy2');
 +
pg.structures.fancy2.popupTopLinks=function(x) { // hack out the <br> at the end and put one at the beginning
 +
return '<br>'+pg.structures.fancy.popupTopLinks(x).replace(RegExp('<br>$','i'),'');
 +
};
 +
pg.structures.fancy2.popupLayout=function () { // move toplinks to after the title
 +
return ['popupError', 'popupImage', 'popupTitle', 'popupUserData', 'popupData', 'popupTopLinks', 'popupOtherLinks',
 +
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
 +
'popupMiscTools', ['popupRedlink'],
 +
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
 +
};
 +
 
 +
/** -- menus -- **/
 +
copyStructure('original', 'menus');
 +
pg.structures.menus.popupLayout=function () {
 +
return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks',
 +
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
 +
'popupUserData', 'popupData', 'popupMiscTools', ['popupRedlink'],
 +
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
 +
};
 +
 
 +
pg.structures.menus.popupTopLinks = function (x, shorter) {
 +
// FIXME maybe this stuff should be cached
 +
var s=[];
 +
var dropdiv='<div class="popup_drop">';
 +
var enddiv='</div>';
 +
var hist='<<history|shortcut=h>>';
 +
if (!shorter) { hist = '<menurow>' + hist +
 +
'|<<historyfeed|rss>>|<<editors|shortcut=E>></menurow>'; }
 +
var lastedit='<<lastEdit|shortcut=/|show last edit>>';
 +
var thank='if(diff){<<thank|send thanks>>}';
 +
var jsHistory='<<lastContrib|last set of edits>><<sinceMe|changes since mine>>';
 +
var linkshere='<<whatLinksHere|shortcut=l|what links here>>';
 +
var related='<<relatedChanges|shortcut=r|related changes>>';
 +
var search='<menurow><<search|shortcut=s>>if(wikimedia){|<<globalsearch|shortcut=g|global>>}' +
 +
'|<<google|shortcut=G|web>></menurow>';
 +
var watch='<menurow><<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>></menurow>';
 +
var protect='<menurow><<unprotect|unprotectShort>>|' +
 +
'<<protect|shortcut=p>>|<<protectlog|log>></menurow>';
 +
var del='<menurow><<undelete|undeleteShort>>|<<delete|shortcut=d>>|' +
 +
'<<deletelog|log>></menurow>';
 +
var move='<<move|shortcut=m|move page>>';
 +
var nullPurge='<menurow><<nullEdit|shortcut=n|null edit>>|<<purge|shortcut=P>></menurow>';
 +
var viewOptions='<menurow><<view|shortcut=v>>|<<render|shortcut=S>>|<<raw>></menurow>';
 +
var editRow='if(oldid){' +
 +
'<menurow><<edit|shortcut=e>>|<<editOld|shortcut=e|this&nbsp;revision>></menurow>' +
 +
'<menurow><<revert|shortcut=v>>|<<undo>></menurow>' + '}else{<<edit|shortcut=e>>}';
 +
var markPatrolled='if(rcid){<<markpatrolled|mark patrolled>>}';
 +
var newTopic='if(talk){<<new|shortcut=+|new topic>>}';
 +
var protectDelete='if(admin){' + protect + del + '}';
 +
 
 +
if (getValueOf('popupActionsMenu')) {
 +
s.push( '<<mainlink>>*' + dropdiv + menuTitle('actions'));
 +
} else {
 +
s.push( dropdiv + '<<mainlink>>');
 +
}
 +
s.push( '<menu>');
 +
s.push( editRow + markPatrolled + newTopic + hist + lastedit + thank );
 +
if (!shorter) { s.push(jsHistory); }
 +
s.push( move + linkshere + related);
 +
if (!shorter) { s.push(nullPurge + search); }
 +
if (!shorter) { s.push(viewOptions); }
 +
s.push('<hr />' + watch + protectDelete);
 +
s.push('<hr />' +
 +
  'if(talk){<<article|shortcut=a|view article>><<editArticle|edit article>>}' +
 +
  'else{<<talk|shortcut=t|talk page>><<editTalk|edit talk>>' +
 +
  '<<newTalk|shortcut=+|new topic>>}</menu>' + enddiv);
 +
 
 +
// user menu starts here
 +
var email='<<email|shortcut=E|email user>>';
 +
var contribs= 'if(wikimedia){<menurow>}<<contribs|shortcut=c|contributions>>if(wikimedia){</menurow>}' +
 +
'if(admin){<menurow><<deletedContribs>></menurow>}';
 +
 
 +
 
 +
s.push('if(user){*' + dropdiv + menuTitle('user'));
 +
s.push('<menu>');
 +
s.push('<menurow><<userPage|shortcut=u|user&nbsp;page>>|<<userSpace|space>></menurow>');
 +
s.push('<<userTalk|shortcut=t|user talk>><<editUserTalk|edit user talk>>' +
 +
  '<<newUserTalk|shortcut=+|leave comment>>');
 +
if(!shorter) { s.push( 'if(ipuser){<<arin>>}else{' + email + '}' ); }
 +
else { s.push( 'if(ipuser){}else{' + email + '}' ); }
 +
s.push('<hr />' + contribs + '<<userlog|shortcut=L|user log>>');
 +
s.push('if(wikimedia){<<count|shortcut=#|edit counter>>}');
 +
s.push('if(admin){<menurow><<unblock|unblockShort>>|<<block|shortcut=b|block user>></menurow>}');
 +
s.push('<<blocklog|shortcut=B|block log>>');
 +
s.push('</menu>'  + enddiv + '}');
 +
 
 +
// popups menu starts here
 +
if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) {
 +
x.navpop.hasPopupMenu=true;
 +
s.push('*' + dropdiv + menuTitle('popupsMenu') + '<menu>');
 +
s.push('<<togglePreviews|toggle previews>>');
 +
s.push('<<purgePopups|reset>>');
 +
s.push('<<disablePopups|disable>>');
 +
s.push('</menu>'+enddiv);
 +
}
 +
return navlinkStringToHTML(s.join(''), x.article, x.params);
 +
};
 +
 
 +
function menuTitle(s) {
 +
return '<a href="#" noPopup=1>' + popupString(s) + '</a>';
 +
}
 +
 
 +
pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle;
 +
pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks;
 +
 
 +
copyStructure('menus', 'shortmenus');
 +
pg.structures.shortmenus.popupTopLinks=function(x) {
 +
return pg.structures.menus.popupTopLinks(x,true);
 +
};
 +
pg.structures.shortmenus.popupRedirTopLinks=pg.structures.shortmenus.popupTopLinks;
 +
 
 +
//</NOLITE>
 +
pg.structures.lite={};
 +
pg.structures.lite.popupLayout=function () {
 +
return ['popupTitle', 'popupPreview' ];
 +
};
 +
pg.structures.lite.popupTitle=function (x) {
 +
log (x.article + ': structures.lite.popupTitle');
 +
//return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params);
 +
return '<div><span class="popup_mainlink"><b>' + x.article.toString() + '</b></span></div>';
 +
};
 +
// ENDFILE: structures.js
 +
// STARTFILE: autoedit.js
 +
//<NOLITE>
 +
function substitute(data,cmdBody) {
 +
// alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags);
 +
var fromRe=RegExp(cmdBody.from, cmdBody.flags);
 +
return data.replace(fromRe, cmdBody.to);
 +
}
 +
 
 +
function execCmds(data, cmdList) {
 +
for (var i=0; i<cmdList.length; ++i) {
 +
data=cmdList[i].action(data, cmdList[i]);
 +
}
 +
return data;
 +
}
 +
 
 +
function parseCmd(str) {
 +
// returns a list of commands
 +
if (!str.length) { return []; }
 +
var p=false;
 +
switch (str.charAt(0)) {
 +
case 's':
 +
p=parseSubstitute(str);
 +
break;
 +
default:
 +
return false;
 +
}
 +
if (p) { return [p].concat(parseCmd(p.remainder)); }
 +
return false;
 +
}
 +
 
 +
function unEscape(str, sep) {
 +
return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n');
 +
}
 +
 
 +
 
 +
function parseSubstitute(str) {
 +
// takes a string like s/a/b/flags;othercmds and parses it
 +
 
 +
var from,to,flags,tmp;
 +
 
 +
if (str.length<4) { return false; }
 +
var sep=str.charAt(1);
 +
str=str.substring(2);
 +
 
 +
tmp=skipOver(str,sep);
 +
if (tmp) { from=tmp.segment; str=tmp.remainder; }
 +
else { return false; }
 +
 
 +
tmp=skipOver(str,sep);
 +
if (tmp) { to=tmp.segment; str=tmp.remainder; }
 +
else { return false; }
 +
 
 +
flags='';
 +
if (str.length) {
 +
tmp=skipOver(str,';') || skipToEnd(str, ';');
 +
if (tmp) {flags=tmp.segment; str=tmp.remainder; }
 +
}
 +
 
 +
return {action: substitute, from: from, to: to, flags: flags, remainder: str};
 +
 
 +
}
 +
 
 +
function skipOver(str,sep) {
 +
var endSegment=findNext(str,sep);
 +
if (endSegment<0) { return false; }
 +
var segment=unEscape(str.substring(0,endSegment), sep);
 +
return {segment: segment, remainder: str.substring(endSegment+1)};
 +
}
 +
 
 +
/*eslint-disable*/
 +
function skipToEnd(str,sep) {
 +
return {segment: str, remainder: ''};
 +
}
 +
/*eslint-enable */
 +
 
 +
function findNext(str, ch) {
 +
for (var i=0; i<str.length; ++i) {
 +
if (str.charAt(i)=='\\') { i+=2; }
 +
if (str.charAt(i)==ch) { return i; }
 +
}
 +
return -1;
 +
}
 +
 
 +
function setCheckbox(param, box) {
 +
var val=mw.util.getParamValue(param);
 +
if (val) {
 +
switch (val) {
 +
case '1': case 'yes': case 'true':
 +
box.checked=true;
 +
break;
 +
case '0': case 'no':  case 'false':
 +
box.checked=false;
 +
}
 +
}
 +
}
 +
 
 +
function autoEdit() {
 +
setupPopups( function () {
 +
if (mw.util.getParamValue('autoimpl') !== popupString('autoedit_version') ) { return false; }
 +
if (mw.util.getParamValue('autowatchlist') && mw.util.getParamValue('actoken')===autoClickToken()) {
 +
pg.fn.modifyWatchlist(mw.util.getParamValue('title'), mw.util.getParamValue('action'));
 +
}
 +
if (!document.editform) { return false; }
 +
if (autoEdit.alreadyRan) { return false; }
 +
autoEdit.alreadyRan=true;
 +
var cmdString=mw.util.getParamValue('autoedit');
 +
if (cmdString) {
 +
try {
 +
var editbox=document.editform.wpTextbox1;
 +
var cmdList=parseCmd(cmdString);
 +
var input=editbox.value;
 +
var output=execCmds(input, cmdList);
 +
editbox.value=output;
 +
} catch (dang) { return; }
 +
// wikEd user script compatibility
 +
if (typeof(wikEdUseWikEd) != 'undefined') {
 +
if (wikEdUseWikEd === true) {
 +
WikEdUpdateFrame();
 +
}
 +
}
 +
}
 +
setCheckbox('autominor', document.editform.wpMinoredit);
 +
setCheckbox('autowatch', document.editform.wpWatchthis);
 +
 +
var rvid = mw.util.getParamValue('autorv');
 +
if (rvid) {
 +
var url=pg.wiki.apiwikibase + '?action=query&format=json&formatversion=2&prop=revisions&revids='+rvid;
 +
startDownload(url, null, autoEdit2);
 +
} else { autoEdit2(); }
 +
} );
 +
}
 +
 
 +
function autoEdit2(d) {
 +
var summary=mw.util.getParamValue('autosummary');
 +
var summaryprompt=mw.util.getParamValue('autosummaryprompt');
 +
var summarynotice='';
 +
if (d && d.data && mw.util.getParamValue('autorv')) {
 +
var s = getRvSummary(summary, d.data);
 +
if (s === false) {
 +
summaryprompt=true;
 +
summarynotice=popupString('Failed to get revision information, please edit manually.\n\n');
 +
summary = simplePrintf(summary, [mw.util.getParamValue('autorv'), '(unknown)', '(unknown)']);
 +
} else { summary = s; }
 +
}
 +
if (summaryprompt) {
 +
var txt= summarynotice +
 +
popupString('Enter a non-empty edit summary or press cancel to abort');
 +
var response=prompt(txt, summary);
 +
if (response) { summary=response; }
 +
else { return; }
 +
}
 +
if (summary) { document.editform.wpSummary.value=summary; }
 +
// Attempt to avoid possible premature clicking of the save button
 +
// (maybe delays in updates to the DOM are to blame?? or a red herring)
 +
setTimeout(autoEdit3, 100);
 +
}
 +
 
 +
function autoClickToken() {
 +
return mw.user.sessionId();
 +
}
 +
 
 +
function autoEdit3() {
 +
if( mw.util.getParamValue('actoken') != autoClickToken()) { return; }
 +
 
 +
var btn=mw.util.getParamValue('autoclick');
 +
if (btn) {
 +
if (document.editform && document.editform[btn]) {
 +
var button=document.editform[btn];
 +
var msg=tprintf('The %s button has been automatically clicked. Please wait for the next page to load.',
 +
[ button.value ]);
 +
bannerMessage(msg);
 +
document.title='('+document.title+')';
 +
button.click();
 +
} else {
 +
alert(tprintf('Could not find button %s. Please check the settings in your javascript file.',
 +
  [ btn ]));
 +
}
 +
}
 +
}
 +
 
 +
function bannerMessage(s) {
 +
var headings=document.getElementsByTagName('h1');
 +
if (headings) {
 +
var div=document.createElement('div');
 +
div.innerHTML='<font size=+1><b>' + s + '</b></font>';
 +
headings[0].parentNode.insertBefore(div, headings[0]);
 +
}
 +
}
 +
 
 +
function getRvSummary(template, json) {
 +
try {
 +
var o=getJsObj(json);
 +
var edit = anyChild(o.query.pages).revisions[0];
 +
var timestamp = edit.timestamp.split(/[A-Z]/g).join(' ').replace(/^ *| *$/g, '');
 +
return simplePrintf(template, [edit.revid, timestamp, edit.userhidden ? '(hidden)' : edit.user ]);
 +
} catch (badness) {
 +
return false;
 +
}
 +
}
 +
 
 +
//</NOLITE>
 +
// ENDFILE: autoedit.js
 +
// STARTFILE: downloader.js
 +
/**
 +
  @fileoverview
 +
  {@link Downloader}, a xmlhttprequest wrapper, and helper functions.
 +
*/
 +
 
 +
/**
 +
  Creates a new Downloader
 +
  @constructor
 +
  @class The Downloader class. Create a new instance of this class to download stuff.
 +
  @param {String} url The url to download. This can be omitted and supplied later.
 +
*/
 +
function Downloader(url) {
 +
if (typeof XMLHttpRequest!='undefined') { this.http = new XMLHttpRequest(); }
 +
/**
 +
The url to download
 +
@type String
 +
*/
 +
this.url = url;
 +
/**
 +
A universally unique ID number
 +
@type integer
 +
*/
 +
this.id=null;
 +
/**
 +
Modification date, to be culled from the incoming headers
 +
@type Date
 +
@private
 +
*/
 +
this.lastModified = null;
 +
/**
 +
What to do when the download completes successfully
 +
@type Function
 +
@private
 +
*/
 +
this.callbackFunction = null;
 +
/**
 +
What to do on failure
 +
@type Function
 +
@private
 +
*/
 +
this.onFailure = null;
 +
/**
 +
Flag set on <code>abort</code>
 +
@type boolean
 +
*/
 +
this.aborted = false;
 +
/**
 +
  HTTP method. See https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html for possibilities.
 +
  @type String
 +
*/
 +
this.method='GET';
 +
/**
 +
Async flag.
 +
@type boolean
 +
*/
 +
this.async=true;
 +
}
 +
 
 +
new Downloader();
 +
 
 +
/** Submits the http request. */
 +
Downloader.prototype.send = function (x) {
 +
if (!this.http) { return null; }
 +
return this.http.send(x);
 +
};
 +
/** Aborts the download, setting the <code>aborted</code> field to true.  */
 +
Downloader.prototype.abort = function () {
 +
if (!this.http) { return null; }
 +
this.aborted=true;
 +
return this.http.abort();
 +
};
 +
/** Returns the downloaded data. */
 +
Downloader.prototype.getData = function () {if (!this.http) { return null; } return this.http.responseText;};
 +
/** Prepares the download. */
 +
Downloader.prototype.setTarget = function () {
 +
if (!this.http) { return null; }
 +
this.http.open(this.method, this.url, this.async);
 +
this.http.setRequestHeader( 'Api-User-Agent', pg.misc.userAgent );
 +
};
 +
/** Gets the state of the download. */
 +
Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;};
 +
 
 +
pg.misc.downloadsInProgress = { };
 +
 
 +
/** Starts the download.
 +
Note that setTarget {@link Downloader#setTarget} must be run first
 +
*/
 +
Downloader.prototype.start=function () {
 +
if (!this.http) { return; }
 +
pg.misc.downloadsInProgress[this.id] = this;
 +
this.http.send(null);
 +
};
 +
 
 +
/** Gets the 'Last-Modified' date from the download headers.
 +
Should be run after the download completes.
 +
Returns <code>null</code> on failure.
 +
@return {Date}
 +
*/
 +
Downloader.prototype.getLastModifiedDate=function () {
 +
if(!this.http) { return null; }
 +
var lastmod=null;
 +
try {
 +
lastmod=this.http.getResponseHeader('Last-Modified');
 +
} catch (err) {}
 +
if (lastmod) { return new Date(lastmod); }
 +
return null;
 +
};
 +
 
 +
/** Sets the callback function.
 +
@param {Function} f callback function, called as <code>f(this)</code> on success
 +
*/
 +
Downloader.prototype.setCallback = function (f) {
 +
if(!this.http) { return; }
 +
this.http.onreadystatechange = f;
 +
};
 +
 
 +
Downloader.prototype.getStatus = function() { if (!this.http) { return null; } return this.http.status; };
 +
 
 +
//////////////////////////////////////////////////
 +
// helper functions
 +
 
 +
/** Creates a new {@link Downloader} and prepares it for action.
 +
@param {String} url The url to download
 +
@param {integer} id The ID of the {@link Downloader} object
 +
@param {Function} callback The callback function invoked on success
 +
@return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser
 +
*/
 +
function newDownload(url, id, callback, onfailure) {
 +
var d=new Downloader(url);
 +
if (!d.http) { return 'ohdear'; }
 +
d.id=id;
 +
d.setTarget();
 +
if (!onfailure) {
 +
onfailure=2;
 +
}
 +
var f = function () {
 +
if (d.getReadyState() == 4) {
 +
delete pg.misc.downloadsInProgress[this.id];
 +
try {
 +
if ( d.getStatus() == 200 ) {
 +
d.data=d.getData();
 +
d.lastModified=d.getLastModifiedDate();
 +
callback(d);
 +
} else if (typeof onfailure == typeof 1) {
 +
if (onfailure > 0) {
 +
// retry
 +
newDownload(url, id, callback, onfailure - 1);
 +
}
 +
} else if ($.isFunction(onfailure)) {
 +
onfailure(d,url,id,callback);
 +
}
 +
} catch (somerr) { /* ignore it */ }
 +
}
 +
};
 +
d.setCallback(f);
 +
return d;
 +
}
 +
/** Simulates a download from cached data.
 +
The supplied data is put into a {@link Downloader} as if it had downloaded it.
 +
@param {String} url The url.
 +
@param {integer} id The ID.
 +
@param {Function} callback The callback, which is invoked immediately as <code>callback(d)</code>,
 +
where <code>d</code> is the new {@link Downloader}.
 +
@param {String} data The (cached) data.
 +
@param {Date} lastModified The (cached) last modified date.
 +
*/
 +
function fakeDownload(url, id, callback, data, lastModified, owner) {
 +
var d=newDownload(url,callback);
 +
d.owner=owner;
 +
d.id=id; d.data=data;
 +
d.lastModified=lastModified;
 +
return callback(d);
 +
}
 +
 
 +
/**
 +
  Starts a download.
 +
  @param {String} url The url to download
 +
  @param {integer} id The ID of the {@link Downloader} object
 +
  @param {Function} callback The callback function invoked on success
 +
  @return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser
 +
*/
 +
function startDownload(url, id, callback) {
 +
var d=newDownload(url, id, callback);
 +
if (typeof d == typeof '' ) { return d; }
 +
d.start();
 +
return d;
 +
}
 +
 
 +
/**
 +
  Aborts all downloads which have been started.
 +
*/
 +
function abortAllDownloads() {
 +
for ( var x in pg.misc.downloadsInProgress ) {
 +
try {
 +
pg.misc.downloadsInProgress[x].aborted=true;
 +
pg.misc.downloadsInProgress[x].abort();
 +
delete pg.misc.downloadsInProgress[x];
 +
} catch (e) {}
 +
}
 +
}
 +
// ENDFILE: downloader.js
 +
// STARTFILE: livepreview.js
 +
// TODO: location is often not correct (eg relative links in previews)
 +
// NOTE: removed md5 and image and math parsing. was broken, lots of bytes.
 +
/**
 +
* InstaView - a Mediawiki to HTML converter in JavaScript
 +
* Version 0.6.1
 +
* Copyright (C) Pedro Fayolle 2005-2006
 +
* https://en.wikipedia.org/wiki/User:Pilaf
 +
* Distributed under the BSD license
 +
*
 +
* Changelog:
 +
*
 +
* 0.6.1
 +
* - Fixed problem caused by \r characters
 +
* - Improved inline formatting parser
 +
*
 +
* 0.6
 +
* - Changed name to InstaView
 +
* - Some major code reorganizations and factored out some common functions
 +
* - Handled conversion of relative links (i.e. [[/foo]])
 +
* - Fixed misrendering of adjacent definition list items
 +
* - Fixed bug in table headings handling
 +
* - Changed date format in signatures to reflect Mediawiki's
 +
* - Fixed handling of [[:Image:...]]
 +
* - Updated MD5 function (hopefully it will work with UTF-8)
 +
* - Fixed bug in handling of links inside images
 +
*
 +
* To do:
 +
* - Better support for math tags
 +
* - Full support for <nowiki>
 +
* - Parser-based (as opposed to RegExp-based) inline wikicode handling (make it one-pass and bullet-proof)
 +
* - Support for templates (through AJAX)
 +
* - Support for coloured links (AJAX)
 +
*/
 +
 
 +
 
 +
var Insta = {};
 +
 
 +
function setupLivePreview() {
 +
 
 +
// options
 +
Insta.conf =
 +
{
 +
baseUrl: '',
 +
 
 +
user: {},
 +
 
 +
wiki: {
 +
lang: pg.wiki.lang,
 +
interwiki: pg.wiki.interwiki,
 +
default_thumb_width: 180
 +
},
 +
 
 +
paths: {
 +
articles: pg.wiki.articlePath + '/',
 +
// Only used for Insta previews with images. (not in popups)
 +
math: '/math/',
 +
images: '//upload.wikimedia.org/wikipedia/en/', // FIXME getImageUrlStart(pg.wiki.hostname),
 +
images_fallback: '//upload.wikimedia.org/wikipedia/commons/',
 +
},
 +
 
 +
locale: {
 +
user: mw.config.get('wgFormattedNamespaces')[pg.nsUserId],
 +
image: mw.config.get('wgFormattedNamespaces')[pg.nsImageId],
 +
category: mw.config.get('wgFormattedNamespaces')[pg.nsCategoryId],
 +
// shouldn't be used in popup previews, i think
 +
months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
 +
}
 +
};
 +
 
 +
// options with default values or backreferences
 +
Insta.conf.user.name = Insta.conf.user.name || 'Wikipedian';
 +
Insta.conf.user.signature = '[['+Insta.conf.locale.user+':'+Insta.conf.user.name+'|'+Insta.conf.user.name+']]';
 +
//Insta.conf.paths.images = '//upload.wikimedia.org/wikipedia/' + Insta.conf.wiki.lang + '/';
 +
 
 +
// define constants
 +
Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:File|Image|'+Insta.conf.locale.image+
 +
     '):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i');
 +
 
 +
}
 +
 
 +
 
 +
Insta.dump = function(from, to)
 +
{
 +
if (typeof from == 'string') { from = document.getElementById(from); }
 +
if (typeof to == 'string') { to = document.getElementById(to); }
 +
to.innerHTML = this.convert(from.value);
 +
};
 +
 
 +
Insta.convert = function(wiki)
 +
{
 +
var ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode
 +
o  = '', // output
 +
p  = 0, // para flag
 +
$r; // result of passing a regexp to $()
 +
 
 +
// some shorthands
 +
function remain() { return ll.length; }
 +
function sh() { return ll.shift(); } // shift
 +
function ps(s) { o += s; } // push
 +
 
 +
// similar to C's printf, uses ? as placeholders, ?? to escape question marks
 +
function f()
 +
{
 +
var i=1, a=arguments,  f=a[0], o='', c, p;
 +
for (; i<a.length; i++) {
 +
if ((p=f.indexOf('?'))+1) {
 +
// allow character escaping
 +
i -= c = f.charAt(p+1)=='?' ? 1 : 0;
 +
o += f.substring(0,p) + (c ? '?' : a[i]);
 +
f = f.substr(p+1+c);
 +
} else { break; }
 +
}
 +
return o+f;
 +
}
 +
 
 +
function html_entities(s) {
 +
return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
 +
}
 +
 +
// Wiki text parsing to html is a nightmare.
 +
// The below functions deliberately don't escape the ampersand since this would make it more difficult,
 +
// and we don't absolutely need to for how we need it.
 +
// This means that any unescaped ampersands in wikitext will remain unescaped and can cause invalid HTML.
 +
// Browsers should all be able to handle it though.
 +
// We also escape significant wikimarkup characters to prevent further matching on the processed text
 +
function htmlescape_text(s) {
 +
return s.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/:/g,"&#58;").replace(/\[/g,"&#91;").replace(/]/g,"&#93;");
 +
}
 +
function htmlescape_attr(s) {
 +
return htmlescape_text(s).replace(/'/g,"&#39;").replace(/"/g,"&quot;");
 +
}
 +
 
 +
// return the first non matching character position between two strings
 +
function str_imatch(a, b)
 +
{
 +
for (var i=0, l=Math.min(a.length, b.length); i<l; i++) {
 +
if (a.charAt(i)!=b.charAt(i)) { break; }
 +
}
 +
return i;
 +
}
 +
 
 +
// compare current line against a string or regexp
 +
// if passed a string it will compare only the first string.length characters
 +
// if passed a regexp the result is stored in $r
 +
function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)); }
 +
 
 +
function $$(c) { return ll[0]==c; } // compare current line against a string
 +
function _(p) { return ll[0].charAt(p); } // return char at pos p
 +
 
 +
function endl(s) { ps(s); sh(); }
 +
 
 +
function parse_list()
 +
{
 +
var prev='';
 +
 
 +
while (remain() && $(/^([*#:;]+)(.*)$/)) {
 +
 
 +
var l_match = $r;
 +
 
 +
sh();
 +
 
 +
var ipos = str_imatch(prev, l_match[1]);
 +
 
 +
// close uncontinued lists
 +
for (var prevPos=prev.length-1; prevPos >= ipos; prevPos--) {
 +
 
 +
var pi = prev.charAt(prevPos);
 +
 
 +
if (pi=='*') { ps('</ul>'); }
 +
else if (pi=='#') { ps('</ol>'); }
 +
// close a dl only if the new item is not a dl item (:, ; or empty)
 +
else if($.inArray(l_match[1].charAt(prevPos), ['','*','#'])) { ps('</dl>'); }
 +
}
 +
 
 +
// open new lists
 +
for (var matchPos=ipos; matchPos<l_match[1].length; matchPos++) {
 +
 
 +
var li = l_match[1].charAt(matchPos);
 +
 
 +
if (li=='*') { ps('<ul>'); }
 +
else if (li=='#') { ps('<ol>'); }
 +
// open a new dl only if the prev item is not a dl item (:, ; or empty)
 +
else if ($.inArray(prev.charAt(matchPos), ['','*','#'])) { ps('<dl>'); }
 +
}
 +
 
 +
switch (l_match[1].charAt(l_match[1].length-1)) {
 +
 
 +
case '*': case '#':
 +
ps('<li>' + parse_inline_nowiki(l_match[2]));
 +
break;
 +
 
 +
case ';':
 +
ps('<dt>');
 +
 
 +
var dt_match = l_match[2].match(/(.*?)(:.*?)$/);
 +
 
 +
// handle ;dt :dd format
 +
if (dt_match) {
 +
ps(parse_inline_nowiki(dt_match[1]));
 +
ll.unshift(dt_match[2]);
 +
 
 +
} else ps(parse_inline_nowiki(l_match[2]));
 +
break;
 +
 
 +
case ':':
 +
ps('<dd>' + parse_inline_nowiki(l_match[2]));
 +
}
 +
 
 +
prev=l_match[1];
 +
}
 +
 
 +
// close remaining lists
 +
for (var i=prev.length-1; i>=0; i--) {
 +
ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl')));
 +
}
 +
}
 +
 
 +
function parse_table()
 +
{
 +
endl(f('<table>', $(/^\{\|( .*)$/)? $r[1]: ''));
 +
 
 +
for (;remain();) if ($('|')) switch (_(1)) {
 +
case '}':
 +
endl('</table>');
 +
return;
 +
case '-':
 +
endl(f('<tr>', $(/\|-*(.*)/)[1]));
 +
break;
 +
default:
 +
parse_table_data();
 +
}
 +
else if ($('!')) { parse_table_data(); }
 +
else { sh(); }
 +
}
 +
 
 +
function parse_table_data()
 +
{
 +
var td_line, match_i;
 +
 
 +
// 1: "|+", '|' or '+'
 +
// 2: ??
 +
// 3: attributes ??
 +
// TODO: finish commenting this regexp
 +
var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/);
 +
 
 +
if (td_match[1] == '|+') ps('<caption');
 +
else ps('<t' + ((td_match[1]=='|')?'d':'h'));
 +
 
 +
if (typeof td_match[3] != 'undefined') {
 +
 
 +
//ps(' ' + td_match[3])
 +
match_i = 4;
 +
 
 +
} else match_i = 2;
 +
 
 +
ps('>');
 +
 
 +
if (td_match[1] != '|+') {
 +
 
 +
// use || or !! as a cell separator depending on context
 +
// NOTE: when split() is passed a regexp make sure to use non-capturing brackets
 +
td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/);
 +
 
 +
ps(parse_inline_nowiki(td_line.shift()));
 +
 
 +
while (td_line.length) ll.unshift(td_match[1] + td_line.pop());
 +
 
 +
} else ps(td_match[match_i]);
 +
 
 +
var tc = 0, td = [];
 +
 
 +
while (remain()) {
 +
td.push(sh());
 +
if ($('|')) {
 +
if (!tc) break; // we're at the outer-most level (no nested tables), skip to td parse
 +
else if (_(1)=='}') tc--;
 +
}
 +
else if (!tc && $('!')) break;
 +
else if ($('{|')) tc++;
 +
}
 +
 
 +
if (td.length) ps(Insta.convert(td));
 +
}
 +
 
 +
function parse_pre()
 +
{
 +
ps('<pre>');
 +
do {
 +
endl(parse_inline_nowiki(ll[0].substring(1)) + "\n");
 +
} while (remain() && $(' '));
 +
ps('</pre>');
 +
}
 +
 
 +
function parse_block_image()
 +
{
 +
ps(parse_image(sh()));
 +
}
 +
 
 +
function parse_image(str)
 +
{
 +
//<NOLITE>
 +
// get what's in between "[[Image:" and "]]"
 +
var tag = str.substring(str.indexOf(':') + 1, str.length - 2);
 +
/* eslint-disable no-unused-vars */
 +
var width;
 +
var attr = [], filename, caption = '';
 +
var thumb=0, frame=0, center=0;
 +
var align='';
 +
/* eslint-enable no-unused-vars */
 +
 
 +
if (tag.match(/\|/)) {
 +
// manage nested links
 +
var nesting = 0;
 +
var last_attr;
 +
for (var i = tag.length-1; i > 0; i--) {
 +
if (tag.charAt(i) == '|' && !nesting) {
 +
last_attr = tag.substr(i+1);
 +
tag = tag.substring(0, i);
 +
break;
 +
} else switch (tag.substr(i-1, 2)) {
 +
case ']]':
 +
nesting++;
 +
i--;
 +
break;
 +
case '[[':
 +
nesting--;
 +
i--;
 +
}
 +
}
 +
 
 +
attr = tag.split(/\s*\|\s*/);
 +
attr.push(last_attr);
 +
filename = attr.shift();
 +
 
 +
var w_match;
 +
 
 +
for (;attr.length; attr.shift()) {
 +
w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/);
 +
if (w_match) width = w_match[1];
 +
else switch(attr[0]) {
 +
case 'thumb':
 +
case 'thumbnail':
 +
thumb=true;
 +
frame=true;
 +
break;
 +
case 'frame':
 +
frame=true;
 +
break;
 +
case 'none':
 +
case 'right':
 +
case 'left':
 +
center=false;
 +
align=attr[0];
 +
break;
 +
case 'center':
 +
center=true;
 +
align='none';
 +
break;
 +
default:
 +
if (attr.length == 1) caption = attr[0];
 +
}
 +
}
 +
 
 +
} else filename = tag;
 +
 
 +
return '';
 +
//</NOLITE>
 +
}
 +
 
 +
function parse_inline_nowiki(str)
 +
{
 +
var start, lastend=0;
 +
var substart=0, nestlev=0, open, close, subloop;
 +
var html='';
 +
 
 +
while (-1 != (start = str.indexOf('<nowiki>', substart))) {
 +
html += parse_inline_wiki(str.substring(lastend, start));
 +
start += 8;
 +
substart = start;
 +
subloop = true;
 +
do {
 +
open = str.indexOf('<nowiki>', substart);
 +
close = str.indexOf('</nowiki>', substart);
 +
if (close<=open || open==-1) {
 +
if (close==-1) {
 +
return html + html_entities(str.substr(start));
 +
}
 +
substart = close+9;
 +
if (nestlev) {
 +
nestlev--;
 +
} else {
 +
lastend = substart;
 +
html += html_entities(str.substring(start, lastend-9));
 +
subloop = false;
 +
}
 +
} else {
 +
substart = open+8;
 +
nestlev++;
 +
}
 +
} while (subloop);
 +
}
 +
 
 +
return html + parse_inline_wiki(str.substr(lastend));
 +
}
 +
 
 +
function parse_inline_images(str)
 +
{
 +
//<NOLITE>
 +
var start, substart=0, nestlev=0;
 +
var loop, close, open, wiki, html;
 +
 
 +
while (-1 != (start=str.indexOf('[[', substart))) {
 +
if(str.substr(start+2).match(RegExp('^(Image|File|' + Insta.conf.locale.image + '):','i'))) {
 +
loop=true;
 +
substart=start;
 +
do {
 +
substart+=2;
 +
close=str.indexOf(']]',substart);
 +
open=str.indexOf('[[',substart);
 +
if (close<=open||open==-1) {
 +
if (close==-1) return str;
 +
substart=close;
 +
if (nestlev) {
 +
nestlev--;
 +
} else {
 +
wiki=str.substring(start,close+2);
 +
html=parse_image(wiki);
 +
str=str.replace(wiki,html);
 +
substart=start+html.length;
 +
loop=false;
 +
}
 +
} else {
 +
substart=open;
 +
nestlev++;
 +
}
 +
} while (loop);
 +
 
 +
} else break;
 +
}
 +
 
 +
//</NOLITE>
 +
return str;
 +
}
 +
 
 +
// the output of this function doesn't respect the FILO structure of HTML
 +
// but since most browsers can handle it I'll save myself the hassle
 +
function parse_inline_formatting(str)
 +
{
 +
var em,st,i,li,o='';
 +
while ((i=str.indexOf("''",li))+1) {
 +
o += str.substring(li,i);
 +
li=i+2;
 +
if (str.charAt(i+2)=="'") {
 +
li++;
 +
st=!st;
 +
o+=st?'<strong>':'</strong>';
 +
} else {
 +
em=!em;
 +
o+=em?'<em>':'</em>';
 +
}
 +
}
 +
return o+str.substr(li);
 +
}
 +
 
 +
function parse_inline_wiki(str)
 +
{
 +
str = parse_inline_images(str);
 +
str = parse_inline_formatting(str);
 +
 
 +
// math
 +
str = str.replace(/<(?:)math>(.*?)<\/math>/ig, '');
 +
 
 +
// Build a Mediawiki-formatted date string
 +
var date = new Date();
 +
var minutes = date.getUTCMinutes();
 +
if (minutes < 10) minutes = '0' + minutes;
 +
date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), Insta.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear());
 +
 
 +
// text formatting
 +
return str.
 +
// signatures
 +
replace(/~{5}(?!~)/g, date).
 +
replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date).
 +
replace(/~{3}(?!~)/g, Insta.conf.user.name).
 +
 
 +
// [[:Category:...]], [[:Image:...]], etc...
 +
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):[^|]*?)\\]\\](\\w*)','gi'), function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($1) + htmlescape_text($2));}).
 +
// remove straight category and interwiki tags
 +
replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),'').
 +
 
 +
// [[:Category:...|Links]], [[:Image:...|Links]], etc...
 +
replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):.*?)\\|([^\\]]+?)\\]\\](\\w*)','gi'), function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($2) + htmlescape_text($3));}).
 +
 
 +
// [[/Relative links]]
 +
replace(/\[\[(\/[^|]*?)\]\]/g, function($0,$1){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($1)); }).
 +
 
 +
// [[/Replaced|Relative links]]
 +
replace(/\[\[(\/.*?)\|(.+?)\]\]/g, function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($2)); }).
 +
 
 +
// [[Common links]]
 +
replace(/\[\[([^[|]*?)\]\](\w*)/g, function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($1) + htmlescape_text($2)); }).
 +
 
 +
// [[Replaced|Links]]
 +
replace(/\[\[([^[]*?)\|([^\]]+?)\]\](\w*)/g, function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($2) + htmlescape_text($3)); }).
 +
 
 +
// [[Stripped:Namespace|Namespace]]
 +
replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1) + htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($2)); }).
 +
 
 +
// External links
 +
replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, function($0,$1,$2,$3,$4){return f("<a class='external' href='?:?'>?</a>", htmlescape_attr($1), htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($4)); }).
 +
replace(/\[http:\/\/(.*?)\]/g, function($0,$1){return f("<a class='external' href='http://?'>[#]</a>", htmlescape_attr($1)); }).
 +
replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, function($0,$1,$2,$3){return f("<a class='external' href='?:?'>?:?</a>", htmlescape_attr($1), htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($1), htmlescape_text($2) + htmlescape_text($3)); }).
 +
replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*[^.,!?;: $])/g, function($0,$1,$2,$3,$4){return f("?<a class='external' href='?:?'>?:?</a>", htmlescape_text($1), htmlescape_attr($2), htmlescape_attr($3) + htmlescape_attr($4), htmlescape_text($2), htmlescape_text($3) + htmlescape_text($4)); }).
 +
 
 +
replace('__NOTOC__','').
 +
replace('__NOEDITSECTION__','');
 +
}
 +
 
 +
// begin parsing
 +
for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) {
 +
p=0;
 +
endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3]));
 +
 
 +
} else if ($(/^[*#:;]/)) {
 +
p=0;
 +
parse_list();
 +
 
 +
} else if ($(' ')) {
 +
p=0;
 +
parse_pre();
 +
 
 +
} else if ($('{|')) {
 +
p=0;
 +
parse_table();
 +
 
 +
} else if ($(/^----+$/)) {
 +
p=0;
 +
endl('<hr />');
 +
 
 +
} else if ($(Insta.BLOCK_IMAGE)) {
 +
p=0;
 +
parse_block_image();
 +
 
 +
} else {
 +
 
 +
// handle paragraphs
 +
if ($$('')) {
 +
p = (remain()>1 && ll[1]===(''));
 +
if (p) endl('<p><br>');
 +
} else {
 +
if(!p) {
 +
ps('<p>');
 +
p=1;
 +
}
 +
ps(parse_inline_nowiki(ll[0]) + ' ');
 +
}
 +
 
 +
sh();
 +
}
 +
 
 +
return o;
 +
};
 +
 
 +
function wiki2html(txt,baseurl) {
 +
Insta.conf.baseUrl=baseurl;
 +
return Insta.convert(txt);
 +
}
 +
// ENDFILE: livepreview.js
 +
// STARTFILE: pageinfo.js
 +
//<NOLITE>
 +
function popupFilterPageSize(data) {
 +
return formatBytes(data.length);
 +
}
 +
 
 +
function popupFilterCountLinks(data) {
 +
var num=countLinks(data);
 +
return String(num) + '&nbsp;' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink'));
 +
}
 +
 
 +
function popupFilterCountImages(data) {
 +
var num=countImages(data);
 +
return String(num) + '&nbsp;' + ((num!=1)?popupString('images'):popupString('image'));
 +
}
 +
 
 +
function popupFilterCountCategories(data) {
 +
var num=countCategories(data);
 +
return String(num) + '&nbsp;' + ((num!=1)?popupString('categories'):popupString('category'));
 +
}
 +
 
 +
 
 +
function popupFilterLastModified(data,download) {
 +
var lastmod=download.lastModified;
 +
var now=new Date();
 +
var age=now-lastmod;
 +
if (lastmod && getValueOf('popupLastModified')) {
 +
return (tprintf('%s old', [formatAge(age)])).replace(RegExp(' ','g'), '&nbsp;');
 +
}
 +
return '';
 +
}
 +
 
 +
function formatAge(age) {
 +
// coerce into a number
 +
var a=0+age, aa=a;
 +
 
 +
var seclen  = 1000;
 +
var minlen  = 60*seclen;
 +
var hourlen = 60*minlen;
 +
var daylen  = 24*hourlen;
 +
var weeklen = 7*daylen;
 +
 
 +
var numweeks = (a-a%weeklen)/weeklen; a = a-numweeks*weeklen; var sweeks = addunit(numweeks, 'week');
 +
var numdays  = (a-a%daylen)/daylen;  a = a-numdays*daylen;  var sdays  = addunit(numdays, 'day');
 +
var numhours = (a-a%hourlen)/hourlen; a = a-numhours*hourlen; var shours = addunit(numhours,'hour');
 +
var nummins  = (a-a%minlen)/minlen;  a = a-nummins*minlen;  var smins  = addunit(nummins, 'minute');
 +
var numsecs  = (a-a%seclen)/seclen;  a = a-numsecs*seclen;  var ssecs  = addunit(numsecs, 'second');
 +
 
 +
if (aa > 4*weeklen) { return sweeks; }
 +
if (aa > weeklen)  { return sweeks + ' ' + sdays; }
 +
if (aa > daylen) { return sdays  + ' ' + shours; }
 +
if (aa > 6*hourlen) { return shours; }
 +
if (aa > hourlen)  { return shours + ' ' + smins; }
 +
if (aa > 10*minlen) { return smins; }
 +
if (aa > minlen) { return smins  + ' ' + ssecs; }
 +
return ssecs;
 +
}
 +
 
 +
function addunit(num,str) { return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;}
 +
 
 +
function runPopupFilters(list, data, download) {
 +
var ret=[];
 +
for (var i=0; i<list.length; ++i) {
 +
if (list[i] && typeof list[i] == 'function') {
 +
var s=list[i](data, download, download.owner.article);
 +
if (s) { ret.push(s); }
 +
}
 +
}
 +
return ret;
 +
}
 +
 
 +
function getPageInfo(data, download) {
 +
if (!data || data.length === 0) { return popupString('Empty page'); }
 +
 
 +
var popupFilters=getValueOf('popupFilters') || [];
 +
var extraPopupFilters = getValueOf('extraPopupFilters') || [];
 +
var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download);
 +
 
 +
var pageInfo=pageInfoArray.join(', ');
 +
if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); }
 +
return pageInfo;
 +
}
 +
 
 +
 
 +
// this could be improved!
 +
function countLinks(wikiText) { return wikiText.split('[[').length - 1; }
 +
 
 +
// if N = # matches, n = # brackets, then
 +
// String.parenSplit(regex) intersperses the N+1 split elements
 +
// with Nn other elements. So total length is
 +
// L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1).
 +
 
 +
function countImages(wikiText) {
 +
return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1);
 +
}
 +
 
 +
function countCategories(wikiText) {
 +
return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1);
 +
}
 +
 
 +
function popupFilterStubDetect(data, download, article) {
 +
var counts=stubCount(data, article);
 +
if (counts.real) { return popupString('stub'); }
 +
if (counts.sect) { return popupString('section stub'); }
 +
return '';
 +
}
 +
 
 +
function popupFilterDisambigDetect(data, download, article) {
 +
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return ''; }
 +
return (isDisambig(data, article)) ? popupString('disambig') : '';
 +
}
 +
 
 +
function formatBytes(num) {
 +
return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +'&nbsp;' + popupString('bytes')) ;
 +
}
 +
//</NOLITE>
 +
// ENDFILE: pageinfo.js
 +
// STARTFILE: titles.js
 +
/**
 +
  @fileoverview Defines the {@link Title} class, and associated crufty functions.
 +
 
 +
  <code>Title</code> deals with article titles and their various
 +
  forms.  {@link Stringwrapper} is the parent class of
 +
  <code>Title</code>, which exists simply to make things a little
 +
  neater.
 +
 
 +
*/
 +
 
 +
/**
 +
  Creates a new Stringwrapper.
 +
  @constructor
 +
 
 +
  @class the Stringwrapper class. This base class is not really
 +
  useful on its own; it just wraps various common string operations.
 +
*/
 +
function Stringwrapper() {
 +
/**
 +
  Wrapper for this.toString().indexOf()
 +
  @param {String} x
 +
  @type integer
 +
*/
 +
this.indexOf=function(x){return this.toString().indexOf(x);};
 +
/**
 +
  Returns this.value.
 +
  @type String
 +
*/
 +
this.toString=function(){return this.value;};
 +
/**
 +
  Wrapper for {@link String#parenSplit} applied to this.toString()
 +
  @param {RegExp} x
 +
  @type Array
 +
*/
 +
this.parenSplit=function(x){return this.toString().parenSplit(x);};
 +
/**
 +
  Wrapper for this.toString().substring()
 +
  @param {String} x
 +
  @param {String} y (optional)
 +
  @type String
 +
*/
 +
this.substring=function(x,y){
 +
if (typeof y=='undefined') { return this.toString().substring(x); }
 +
return this.toString().substring(x,y);
 +
};
 +
/**
 +
  Wrapper for this.toString().split()
 +
  @param {String} x
 +
  @type Array
 +
*/
 +
this.split=function(x){return this.toString().split(x);};
 +
/**
 +
  Wrapper for this.toString().replace()
 +
  @param {String} x
 +
  @param {String} y
 +
  @type String
 +
*/
 +
this.replace=function(x,y){ return this.toString().replace(x,y); };
 +
}
 +
 
 +
 
 +
/**
 +
  Creates a new <code>Title</code>.
 +
  @constructor
 +
 
 +
  @class The Title class. Holds article titles and converts them into
 +
  various forms. Also deals with anchors, by which we mean the bits
 +
  of the article URL after a # character, representing locations
 +
  within an article.
 +
 
 +
  @param {String} value The initial value to assign to the
 +
  article. This must be the canonical title (see {@link
 +
  Title#value}. Omit this in the constructor and use another function
 +
  to set the title if this is unavailable.
 +
*/
 +
function Title(val) {
 +
/**
 +
  The canonical article title. This must be in UTF-8 with no
 +
  entities, escaping or nasties. Also, underscores should be
 +
  replaced with spaces.
 +
  @type String
 +
  @private
 +
*/
 +
this.value=null;
 +
/**
 +
  The canonical form of the anchor. This should be exactly as
 +
  it appears in the URL, i.e. with the .C3.0A bits in.
 +
  @type String
 +
*/
 +
this.anchor='';
 +
 
 +
this.setUtf(val);
 +
}
 +
Title.prototype=new Stringwrapper();
 +
/**
 +
  Returns the canonical representation of the article title, optionally without anchor.
 +
  @param {boolean} omitAnchor
 +
  @fixme Decide specs for anchor
 +
  @return String The article title and the anchor.
 +
*/
 +
Title.prototype.toString=function(omitAnchor) {
 +
return this.value + ( (!omitAnchor && this.anchor) ? '#' + this.anchorString() : '' );
 +
};
 +
Title.prototype.anchorString=function() {
 +
if (!this.anchor) { return ''; }
 +
var split=this.anchor.parenSplit(/((?:[.][0-9A-F]{2})+)/);
 +
var len=split.length;
 +
for (var j=1; j<len; j+=2) {
 +
// FIXME s/decodeURI/decodeURIComponent/g ?
 +
split[j]=decodeURIComponent(split[j].split('.').join('%')).split('_').join(' ');
 +
}
 +
return split.join('');
 +
};
 +
Title.prototype.urlAnchor=function() {
 +
var split=this.anchor.parenSplit('/((?:[%][0-9A-F]{2})+)/');
 +
var len=split.length;
 +
for (var j=1; j<len; j+=2) {
 +
split[j]=split[j].split('%').join('.');
 +
}
 +
return split.join('');
 +
};
 +
Title.prototype.anchorFromUtf=function(str) {
 +
this.anchor=encodeURIComponent(str.split(' ').join('_'))
 +
.split('%3A').join(':').split("'").join('%27').split('%').join('.');
 +
};
 +
Title.fromURL=function(h) {
 +
return new Title().fromURL(h);
 +
};
 +
Title.prototype.fromURL=function(h) {
 +
if (typeof h != 'string') {
 +
this.value=null;
 +
return this;
 +
}
 +
 
 +
// NOTE : playing with decodeURI, encodeURI, escape, unescape,
 +
// we seem to be able to replicate the IE borked encoding
 +
 
 +
// IE doesn't do this new-fangled utf-8 thing.
 +
// and it's worse than that.
 +
// IE seems to treat the query string differently to the rest of the url
 +
// the query is treated as bona-fide utf8, but the first bit of the url is pissed around with
 +
 
 +
// we fix up & for all browsers, just in case.
 +
var splitted=h.split('?');
 +
splitted[0]=splitted[0].split('&').join('%26');
 +
 
 +
h=splitted.join('?');
 +
 
 +
var contribs=pg.re.contribs.exec(h);
 +
if (contribs) {
 +
if (contribs[1]=='title=') { contribs[3]=contribs[3].split('+').join(' '); }
 +
var u=new Title(contribs[3]);
 +
this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + u.stripNamespace()));
 +
return this;
 +
}
 +
 
 +
var email=pg.re.email.exec(h);
 +
if (email) {
 +
this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + new Title(email[3]).stripNamespace()));
 +
return this;
 +
}
 +
 
 +
var backlinks=pg.re.backlinks.exec(h);
 +
if (backlinks) {
 +
this.setUtf(this.decodeNasties(new Title(backlinks[3])));
 +
return this;
 +
}
 +
 
 +
//A dummy title object for a Special:Diff link.
 +
var specialdiff=pg.re.specialdiff.exec(h);
 +
if (specialdiff) {
 +
this.setUtf(this.decodeNasties(new Title(mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Diff')));
 +
return this;
 +
}
 +
 
 +
// no more special cases to check --
 +
// hopefully it's not a disguised user-related or specially treated special page
 +
var m=pg.re.main.exec(h);
 +
if(m === null) { this.value=null; }
 +
else {
 +
var fromBotInterface = /[?](.+[&])?title=/.test(h);
 +
if (fromBotInterface) {
 +
m[2]=m[2].split('+').join('_');
 +
}
 +
var extracted = m[2] + (m[3] ? '#' + m[3] : '');
 +
if (pg.flag.isSafari && /%25[0-9A-Fa-f]{2}/.test(extracted)) {
 +
// Fix Safari issue
 +
// Safari sometimes encodes % as %25 in UTF-8 encoded strings like %E5%A3 -> %25E5%25A3.
 +
this.setUtf(decodeURIComponent(unescape(extracted)));
 +
} else {
 +
this.setUtf(this.decodeNasties(extracted));
 +
}
 +
}
 +
return this;
 +
};
 +
Title.prototype.decodeNasties=function(txt) {
 +
var ret= this.decodeEscapes(decodeURI(txt));
 +
ret = ret.replace(/[_ ]*$/, '');
 +
return ret;
 +
};
 +
Title.prototype.decodeEscapes=function(txt) {
 +
var split=txt.parenSplit(/((?:[%][0-9A-Fa-f]{2})+)/);
 +
var len=split.length;
 +
for (var i=1; i<len; i=i+2) {
 +
// FIXME is decodeURIComponent better?
 +
split[i]=unescape(split[i]);
 +
}
 +
return split.join('');
 +
};
 +
Title.fromAnchor=function(a) {
 +
return new Title().fromAnchor(a);
 +
};
 +
Title.prototype.fromAnchor=function(a) {
 +
if (!a) { this.value=null; return this; }
 +
return this.fromURL(a.href);
 +
};
 +
Title.fromWikiText=function(txt) {
 +
return new Title().fromWikiText(txt);
 +
};
 +
Title.prototype.fromWikiText=function(txt) {
 +
// FIXME - testing needed
 +
txt=myDecodeURI(txt);
 +
this.setUtf(txt);
 +
return this;
 +
};
 +
Title.prototype.hintValue=function(){
 +
if(!this.value) { return ''; }
 +
return safeDecodeURI(this.value);
 +
};
 +
//<NOLITE>
 +
Title.prototype.toUserName=function(withNs) {
 +
if (this.namespaceId() != pg.nsUserId && this.namespaceId() != pg.nsUsertalkId) {
 +
this.value=null;
 +
return;
 +
}
 +
this.value = (withNs ? mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' : '') + this.stripNamespace().split('/')[0];
 +
};
 +
Title.prototype.userName=function(withNs) {
 +
var t=(new Title(this.value));
 +
t.toUserName(withNs);
 +
if (t.value) { return t; }
 +
return null;
 +
};
 +
Title.prototype.toTalkPage=function() {
 +
// convert article to a talk page, or if we can't, return null
 +
// In other words: return null if this ALREADY IS a talk page
 +
// and return the corresponding talk page otherwise
 +
//
 +
// Per https://www.mediawiki.org/wiki/Manual:Namespace#Subject_and_talk_namespaces
 +
// * All discussion namespaces have odd-integer indices
 +
// * The discussion namespace index for a specific namespace with index n is n + 1
 +
if (this.value === null) { return null; }
 +
 +
var namespaceId = this.namespaceId();
 +
if (namespaceId>=0 && namespaceId % 2 === 0) //non-special and subject namespace
 +
{
 +
var localizedNamespace = mw.config.get('wgFormattedNamespaces')[namespaceId+1];
 +
if (typeof localizedNamespace!=='undefined')
 +
{
 +
if (localizedNamespace === '') {
 +
this.value = this.stripNamespace();
 +
} else {
 +
this.value = localizedNamespace.split(' ').join('_') + ':' + this.stripNamespace();
 +
}
 +
return this.value;
 +
}
 +
}
 +
 
 +
this.value=null;
 +
return null;
 +
};
 +
//</NOLITE>
 +
// Return canonical, localized namespace
 +
Title.prototype.namespace=function() {
 +
return mw.config.get('wgFormattedNamespaces')[this.namespaceId()];
 +
};
 +
Title.prototype.namespaceId=function() {
 +
var n=this.value.indexOf(':');
 +
if (n<0) { return 0; } //mainspace
 +
var namespaceId = mw.config.get('wgNamespaceIds')[this.value.substring(0,n).split(' ').join('_').toLowerCase()];
 +
if (typeof namespaceId=='undefined') return 0; //mainspace
 +
return namespaceId;
 +
};
 +
//<NOLITE>
 +
Title.prototype.talkPage=function() {
 +
var t=new Title(this.value);
 +
t.toTalkPage();
 +
if (t.value) { return t; }
 +
return null;
 +
};
 +
Title.prototype.isTalkPage=function() {
 +
if (this.talkPage()===null) { return true; }
 +
return false;
 +
};
 +
Title.prototype.toArticleFromTalkPage=function() {
 +
//largely copy/paste from toTalkPage above.
 +
if (this.value === null) { return null; }
 +
 +
var namespaceId = this.namespaceId();
 +
if (namespaceId >= 0 && namespaceId % 2 == 1) //non-special and talk namespace
 +
{
 +
var localizedNamespace = mw.config.get('wgFormattedNamespaces')[namespaceId-1];
 +
if (typeof localizedNamespace!=='undefined')
 +
{
 +
if (localizedNamespace === '') {
 +
this.value = this.stripNamespace();
 +
} else {
 +
this.value = localizedNamespace.split(' ').join('_') + ':' + this.stripNamespace();
 +
}
 +
return this.value;
 +
}
 +
}
 +
 
 +
this.value=null;
 +
return null;
 +
};
 +
Title.prototype.articleFromTalkPage=function() {
 +
var t=new Title(this.value);
 +
t.toArticleFromTalkPage();
 +
if (t.value) { return t; }
 +
return null;
 +
};
 +
Title.prototype.articleFromTalkOrArticle=function() {
 +
var t=new Title(this.value);
 +
if ( t.toArticleFromTalkPage() ) { return t; }
 +
return this;
 +
};
 +
Title.prototype.isIpUser=function() {
 +
return pg.re.ipUser.test(this.userName());
 +
};
 +
//</NOLITE>
 +
Title.prototype.stripNamespace=function(){ // returns a string, not a Title
 +
var n=this.value.indexOf(':');
 +
if (n<0) { return this.value; }
 +
var namespaceId = this.namespaceId();
 +
if (namespaceId === pg.nsMainspaceId) return this.value;
 +
return this.value.substring(n+1);
 +
};
 +
Title.prototype.setUtf=function(value){
 +
if (!value) { this.value=''; return; }
 +
var anch=value.indexOf('#');
 +
if(anch < 0) { this.value=value.split('_').join(' '); this.anchor=''; return; }
 +
this.value=value.substring(0,anch).split('_').join(' ');
 +
this.anchor=value.substring(anch+1);
 +
this.ns=null; // wait until namespace() is called
 +
};
 +
Title.prototype.setUrl=function(urlfrag) {
 +
var anch=urlfrag.indexOf('#');
 +
this.value=safeDecodeURI(urlfrag.substring(0,anch));
 +
this.anchor=this.value.substring(anch+1);
 +
};
 +
Title.prototype.append=function(x){
 +
this.setUtf(this.value + x);
 +
};
 +
Title.prototype.urlString=function(x) {
 +
if(!x) { x={}; }
 +
var v=this.toString(true);
 +
if (!x.omitAnchor && this.anchor) { v+= '#' + this.urlAnchor(); }
 +
if (!x.keepSpaces) { v=v.split(' ').join('_'); }
 +
return encodeURI(v).split('&').join('%26').split('?').join('%3F').split('+').join('%2B');
 +
};
 +
Title.prototype.removeAnchor=function() {
 +
return new Title(this.toString(true));
 +
};
 +
Title.prototype.toUrl=function() {
 +
return pg.wiki.titlebase + this.urlString();
 +
};
 +
 
 +
function parseParams(url) {
 +
var specialDiff = pg.re.specialdiff.exec(url);
 +
if (specialDiff)
 +
{
 +
var split= specialDiff[1].split('/');
 +
if (split.length==1) return {oldid:split[0], diff: 'prev'};
 +
else if (split.length==2) return {oldid: split[0], diff: split[1]};
 +
}
 +
 
 +
var ret={};
 +
if (url.indexOf('?')==-1) { return ret; }
 +
url = url.split('#')[0];
 +
var s=url.split('?').slice(1).join();
 +
var t=s.split('&');
 +
for (var i=0; i<t.length; ++i) {
 +
var z=t[i].split('=');
 +
z.push(null);
 +
ret[z[0]]=z[1];
 +
}
 +
//Diff revision with no oldid is interpreted as a diff to the previous revision by MediaWiki
 +
if (ret.diff && typeof(ret.oldid)==='undefined')
 +
{
 +
ret.oldid = "prev";
 +
}
 +
//Documentation seems to say something different, but oldid can also accept prev/next, and Echo is emitting such URLs. Simple fixup during parameter decoding:
 +
if (ret.oldid && (ret.oldid==='prev' || ret.oldid==='next' || ret.oldid==='cur'))
 +
{
 +
var helper = ret.diff;
 +
ret.diff = ret.oldid;
 +
ret.oldid = helper;
 +
}
 +
return ret;
 +
}
 +
 
 +
// (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup)
 +
// (b) change spaces to underscores
 +
// (c) encodeURI (just the straight one, no pg.re.urlNoPopup)
 +
 
 +
function myDecodeURI (str) {
 +
var ret;
 +
// FIXME decodeURIComponent??
 +
try { ret=decodeURI(str.toString()); }
 +
catch (summat) { return str; }
 +
for (var i=0; i<pg.misc.decodeExtras.length; ++i) {
 +
var from=pg.misc.decodeExtras[i].from;
 +
var to=pg.misc.decodeExtras[i].to;
 +
ret=ret.split(from).join(to);
 +
}
 +
return ret;
 +
}
 +
 
 +
function safeDecodeURI(str) { var ret=myDecodeURI(str); return ret || str; }
 +
 
 +
///////////
 +
// TESTS //
 +
///////////
 +
 
 +
//<NOLITE>
 +
function isDisambig(data, article) {
 +
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
 +
return ! article.isTalkPage() && pg.re.disambig.test(data);
 +
}
 +
 
 +
function stubCount(data, article) {
 +
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
 +
var sectStub=0;
 +
var realStub=0;
 +
if (pg.re.stub.test(data)) {
 +
var s=data.parenSplit(pg.re.stub);
 +
for (var i=1; i<s.length; i=i+2) {
 +
if (s[i]) { ++sectStub; }
 +
else { ++realStub; }
 +
}
 +
}
 +
return { real: realStub, sect: sectStub };
 +
}
 +
 
 +
function isValidImageName(str){ // extend as needed...
 +
return ( str.indexOf('{') == -1 );
 +
}
 +
 
 +
function isInStrippableNamespace(article) {
 +
// Does the namespace allow subpages
 +
// Note, would be better if we had access to wgNamespacesWithSubpages
 +
return ( article.namespaceId() !== 0 );
 +
}
 +
 
 +
function isInMainNamespace(article) { return article.namespaceId() === 0; }
 +
 
 +
function anchorContainsImage(a) {
 +
// iterate over children of anchor a
 +
// see if any are images
 +
if (a === null) { return false; }
 +
var kids=a.childNodes;
 +
for (var i=0; i<kids.length; ++i) { if (kids[i].nodeName=='IMG') { return true; } }
 +
return false;
 +
}
 +
//</NOLITE>
 +
function isPopupLink(a) {
 +
// NB for performance reasons, TOC links generally return true
 +
// they should be stripped out later
 +
 
 +
if (!markNopopupSpanLinks.done) { markNopopupSpanLinks(); }
 +
if (a.inNopopupSpan) { return false; }
 +
 
 +
// FIXME is this faster inline?
 +
if (a.onmousedown || a.getAttribute('nopopup')) { return false; }
 +
var h=a.href;
 +
if (h === document.location.href+'#') { return false; }
 +
if (!pg.re.basenames.test(h)) { return false; }
 +
if (!pg.re.urlNoPopup.test(h)) { return true; }
 +
return (
 +
(pg.re.email.test(h) || pg.re.contribs.test(h) || pg.re.backlinks.test(h) || pg.re.specialdiff.test(h)) &&
 +
h.indexOf('&limit=') == -1 );
 +
}
 +
 
 +
function markNopopupSpanLinks() {
 +
if( !getValueOf('popupOnlyArticleLinks'))
 +
fixVectorMenuPopups();
 +
 
 +
var s = $('.nopopups').toArray();
 +
for (var i=0; i<s.length; ++i) {
 +
var as=s[i].getElementsByTagName('a');
 +
for (var j=0; j<as.length; ++j) {
 +
as[j].inNopopupSpan=true;
 +
}
 +
}
 +
 +
markNopopupSpanLinks.done=true;
 +
}
 +
 
 +
function fixVectorMenuPopups() {
 +
$('div.vectorMenu h3:first a:first').prop('inNopopupSpan', true);
 +
}
 +
// ENDFILE: titles.js
 +
// STARTFILE: getpage.js
 +
//////////////////////////////////////////////////
 +
// Wiki-specific downloading
 +
//
 +
 
 +
// Schematic for a getWiki call
 +
//
 +
//       getPageWithCaching
 +
// |
 +
//   false |   true
 +
// getPage<-[findPictureInCache]->-onComplete(a fake download)
 +
//  \.
 +
// (async)->addPageToCache(download)->-onComplete(download)
 +
 
 +
// check cache to see if page exists
 +
 
 +
function getPageWithCaching(url, onComplete, owner) {
 +
log('getPageWithCaching, url='+url);
 +
var i=findInPageCache(url);
 +
var d;
 +
if (i > -1) {
 +
d=fakeDownload(url, owner.idNumber, onComplete,
 +
pg.cache.pages[i].data, pg.cache.pages[i].lastModified,
 +
owner);
 +
} else {
 +
d=getPage(url, onComplete, owner);
 +
if (d && owner && owner.addDownload) {
 +
owner.addDownload(d);
 +
d.owner=owner;
 +
}
 +
}
 +
}
 +
 
 +
function getPage(url, onComplete, owner) {
 +
log('getPage');
 +
var callback= function (d) { if (!d.aborted) {addPageToCache(d); onComplete(d);} };
 +
return startDownload(url, owner.idNumber, callback);
 +
}
 +
 
 +
function findInPageCache(url) {
 +
for (var i=0; i<pg.cache.pages.length; ++i) {
 +
if (url==pg.cache.pages[i].url) { return i; }
 +
}
 +
return -1;
 +
}
 +
 
 +
function addPageToCache(download) {
 +
log('addPageToCache '+download.url);
 +
var page = {url: download.url, data: download.data, lastModified: download.lastModified};
 +
return pg.cache.pages.push(page);
 +
}
 +
// ENDFILE: getpage.js
 +
// STARTFILE: parensplit.js
 +
//////////////////////////////////////////////////
 +
// parenSplit
 +
 
 +
// String.prototype.parenSplit should do what ECMAscript says String.prototype.split does,
 +
// interspersing paren matches (regex capturing groups) between the split elements.
 +
// i.e. 'abc'.split(/(b)/)) should return ['a','b','c'], not ['a','c']
 +
 
 +
if (String('abc'.split(/(b)/))!='a,b,c') {
 +
// broken String.split, e.g. konq, IE < 10
 +
String.prototype.parenSplit=function (re) {
 +
re=nonGlobalRegex(re);
 +
var s=this;
 +
var m=re.exec(s);
 +
var ret=[];
 +
while (m && s) {
 +
// without the following loop, we have
 +
// 'ab'.parenSplit(/a|(b)/) != 'ab'.split(/a|(b)/)
 +
for(var i=0; i<m.length; ++i) {
 +
if (typeof m[i]=='undefined') m[i]='';
 +
}
 +
ret.push(s.substring(0,m.index));
 +
ret = ret.concat(m.slice(1));
 +
s=s.substring(m.index + m[0].length);
 +
m=re.exec(s);
 +
}
 +
ret.push(s);
 +
return ret;
 +
};
 +
} else {
 +
String.prototype.parenSplit=function (re) { return this.split(re); };
 +
String.prototype.parenSplit.isNative=true;
 +
}
 +
 
 +
function nonGlobalRegex(re) {
 +
var s=re.toString();
 +
var flags='';
 +
for (var j=s.length; s.charAt(j) != '/'; --j) {
 +
if (s.charAt(j) != 'g') { flags += s.charAt(j); }
 +
}
 +
var t=s.substring(1,j);
 +
return RegExp(t,flags);
 +
}
 +
// ENDFILE: parensplit.js
 +
// STARTFILE: tools.js
 +
// IE madness with encoding
 +
// ========================
 +
//
 +
// suppose throughout that the page is in utf8, like wikipedia
 +
//
 +
// if a is an anchor DOM element and a.href should consist of
 +
//
 +
// http://host.name.here/wiki/foo?bar=baz
 +
//
 +
// then IE gives foo as "latin1-encoded" utf8; we have foo = decode_utf8(decodeURI(foo_ie))
 +
// but IE gives bar=baz correctly as plain utf8
 +
//
 +
// ---------------------------------
 +
//
 +
// IE's xmlhttp doesn't understand utf8 urls. Have to use encodeURI here.
 +
//
 +
// ---------------------------------
 +
//
 +
// summat else
 +
 
 +
// Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm
 +
 
 +
//<NOLITE>
 +
 
 +
 
 +
function getJsObj(json) {
 +
try {
 +
var json_ret = JSON.parse(json);
 +
if( json_ret.warnings ) {
 +
for( var w=0; w < json_ret.warnings.length; w++ ) {
 +
if( json_ret.warnings[w]['*'] ) {
 +
log( json_ret.warnings[w]['*'] );
 +
} else {
 +
log( json_ret.warnings[w]['warnings'] );
 +
}
 +
}
 +
} else if ( json_ret.error ) {
 +
errlog( json_ret.error.code + ': ' + json_ret.error.info );
 +
}
 +
return json_ret;
 +
} catch (someError) {
 +
errlog('Something went wrong with getJsObj, json='+json);
 +
return 1;
 +
}
 +
}
 +
 
 +
function anyChild(obj) {
 +
for (var p in obj) {
 +
return obj[p];
 +
}
 +
return null;
 +
}
 +
 
 +
//</NOLITE>
 +
 
 +
function upcaseFirst(str) {
 +
if (typeof str != typeof '' || str === '') return '';
 +
return str.charAt(0).toUpperCase() + str.substring(1);
 +
}
 +
 
 +
 
 +
function findInArray(arr, foo) {
 +
if (!arr || !arr.length) { return -1; }
 +
var len=arr.length;
 +
for (var i=0; i<len; ++i) { if (arr[i]==foo) { return i; } }
 +
return -1;
 +
}
 +
 
 +
/* eslint-disable no-unused-vars */
 +
function nextOne (array, value) {
 +
// NB if the array has two consecutive entries equal
 +
// then this will loop on successive calls
 +
var i=findInArray(array, value);
 +
if (i<0) { return null; }
 +
return array[i+1];
 +
}
 +
/* eslint-enable no-unused-vars */
 +
 
 +
function literalizeRegex(str){
 +
return mw.util.escapeRegExp(str);
 +
}
 +
 
 +
String.prototype.entify=function() {
 +
//var shy='&shy;';
 +
return this.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;'/*+shy*/).split('"').join('&quot;');
 +
};
 +
 
 +
// Array filter function
 +
function removeNulls(val) { return val !== null; }
 +
 
 +
function joinPath(list) {
 +
return list.filter(removeNulls).join('/');
 +
}
 +
 
 +
 
 +
function simplePrintf(str, subs) {
 +
if (!str || !subs) { return str; }
 +
var ret=[];
 +
var s=str.parenSplit(/(%s|\$[0-9]+)/);
 +
var i=0;
 +
do {
 +
ret.push(s.shift());
 +
if ( !s.length ) { break; }
 +
var cmd=s.shift();
 +
if (cmd == '%s') {
 +
if ( i < subs.length ) { ret.push(subs[i]); } else { ret.push(cmd); }
 +
++i;
 +
} else {
 +
var j=parseInt( cmd.replace('$', ''), 10 ) - 1;
 +
if ( j > -1 && j < subs.length ) { ret.push(subs[j]); } else { ret.push(cmd); }
 +
}
 +
} while (s.length > 0);
 +
return ret.join('');
 +
}
 +
/* eslint-disable no-unused-vars */
 +
function isString(x) { return (typeof x === 'string' || x instanceof String); }
 +
function isNumber(x) { return (typeof x === 'number' || x instanceof Number); }
 +
function isRegExp(x) { return x instanceof RegExp; }
 +
function isArray (x) { return x instanceof Array; }
 +
function isObject(x) { return x instanceof Object; }
 +
function isFunction(x) {
 +
return !isRegExp(x) && ($.isFunction(x) || x instanceof Function);
 +
}
 +
/* eslint-enable no-unused-vars */
 +
 
 +
function repeatString(s,mult) {
 +
var ret='';
 +
for (var i=0; i<mult; ++i) { ret += s; }
 +
return ret;
 +
}
 +
 
 +
function zeroFill(s, min) {
 +
min = min || 2;
 +
var t=s.toString();
 +
return repeatString('0', min - t.length) + t;
 +
}
 +
 
 +
function map(f, o) {
 +
if (isArray(o)) { return map_array(f,o); }
 +
return map_object(f,o);
 +
}
 +
function map_array(f,o) {
 +
var ret=[];
 +
for (var i=0; i<o.length; ++i) {
 +
ret.push(f(o[i]));
 +
}
 +
return ret;
 +
}
 +
function map_object(f,o) {
 +
var ret={};
 +
for (var i in o) { ret[o]=f(o[i]); }
 +
return ret;
 +
}
 +
 
 +
pg.escapeQuotesHTML = function ( text ) {
 +
return text
 +
.replace(/&/g, "&amp;")
 +
.replace(/"/g, "&quot;")
 +
.replace(/</g, "&lt;")
 +
.replace(/>/g, "&gt;");
 +
};
 +
 
 +
// ENDFILE: tools.js
 +
// STARTFILE: dab.js
 +
//<NOLITE>
 +
//////////////////////////////////////////////////
 +
// Dab-fixing code
 +
//
 +
 
 +
 
 +
function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) {
 +
log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget);
 +
return changeLinkTargetLink(
 +
{newTarget: newTarget,
 +
text: newTarget.split(' ').join('&nbsp;'),
 +
hint: tprintf('disambigHint', [newTarget]),
 +
summary: simplePrintf(
 +
getValueOf('popupFixDabsSummary'), [friendlyCurrentArticleName, newTarget ]),
 +
clickButton: getValueOf('popupDabsAutoClick'), minor: true, oldTarget: oldTarget,
 +
watch: getValueOf('popupWatchDisambiggedPages'),
 +
title: titleToEdit});
 +
}
 +
 
 +
function listLinks(wikitext, oldTarget, titleToEdit) {
 +
// mediawiki strips trailing spaces, so we do the same
 +
// testcase: https://en.wikipedia.org/w/index.php?title=Radial&oldid=97365633
 +
var reg=RegExp('\\[\\[([^|]*?) *(\\||\\]\\])', 'gi');
 +
var ret=[];
 +
var splitted=wikitext.parenSplit(reg);
 +
// ^[a-z]+ should match interwiki links, hopefully (case-insensitive)
 +
// and ^[a-z]* should match those and [[:Category...]] style links too
 +
var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory');
 +
var friendlyCurrentArticleName= oldTarget.toString();
 +
var wikPos = getValueOf('popupDabWiktionary');
 +
 
 +
for (var i=1; i<splitted.length; i=i+3) {
 +
if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) {
 +
ret.push( retargetDab(splitted[i], oldTarget, friendlyCurrentArticleName, titleToEdit) );
 +
} /* if */
 +
} /* for loop */
 +
 
 +
ret = rmDupesFromSortedList(ret.sort());
 +
 
 +
if (wikPos) {
 +
var wikTarget='wiktionary:' +
 +
friendlyCurrentArticleName.replace( RegExp('^(.+)\\s+[(][^)]+[)]\\s*$'), '$1' );
 +
 
 +
var meth;
 +
if (wikPos.toLowerCase() == 'first') { meth = 'unshift'; }
 +
else { meth = 'push'; }
 +
 
 +
ret[meth]( retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) );
 +
}
 +
 
 +
ret.push(changeLinkTargetLink(
 +
{ newTarget: null,
 +
text: popupString('remove this link').split(' ').join('&nbsp;'),
 +
hint: popupString("remove all links to this disambig page from this article"),
 +
clickButton: getValueOf('popupDabsAutoClick'), oldTarget: oldTarget,
 +
summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName]),
 +
watch: getValueOf('popupWatchDisambiggedPages'),
 +
title: titleToEdit
 +
}));
 +
return ret;
 +
}
 +
 
 +
function rmDupesFromSortedList(list) {
 +
var ret=[];
 +
for (var i=0; i<list.length; ++i) {
 +
if (ret.length === 0 || list[i]!=ret[ret.length-1]) { ret.push(list[i]); }
 +
}
 +
return ret;
 +
}
 +
 
 +
function makeFixDab(data, navpop) {
 +
// grab title from parent popup if there is one; default exists in changeLinkTargetLink
 +
var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString());
 +
var list=listLinks(data, navpop.originalArticle, titleToEdit);
 +
if (list.length === 0) { log('listLinks returned empty list'); return null; }
 +
var html='<hr />' + popupString('Click to disambiguate this link to:') + '<br>';
 +
html+=list.join(', ');
 +
return html;
 +
}
 +
 
 +
 
 +
function makeFixDabs(wikiText, navpop) {
 +
if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) &&
 +
Title.fromURL(location.href).namespaceId() != pg.nsSpecialId &&
 +
navpop.article.talkPage() ) {
 +
setPopupHTML(makeFixDab(wikiText, navpop), 'popupFixDab', navpop.idNumber);
 +
}
 +
}
 +
 
 +
function popupRedlinkHTML(article) {
 +
return changeLinkTargetLink(
 +
{ newTarget: null, text: popupString('remove this link').split(' ').join('&nbsp;'),
 +
hint: popupString("remove all links to this page from this article"),
 +
clickButton: getValueOf('popupRedlinkAutoClick'),
 +
oldTarget: article.toString(),
 +
summary: simplePrintf(getValueOf('popupRedlinkSummary'), [article.toString()])});
 +
}
 +
//</NOLITE>
 +
// ENDFILE: dab.js
 +
// STARTFILE: htmloutput.js
 +
 
 +
// this has to use a timer loop as we don't know if the DOM element exists when we want to set the text
 +
function setPopupHTML (str, elementId, popupId, onSuccess, append) {
 +
if (typeof popupId === 'undefined') {
 +
//console.error('popupId is not defined in setPopupHTML, html='+str.substring(0,100));
 +
popupId = pg.idNumber;
 +
}
 +
 
 +
var popupElement=document.getElementById(elementId+popupId);
 +
if (popupElement) {
 +
if (!append) { popupElement.innerHTML=''; }
 +
if (isString(str)) {
 +
popupElement.innerHTML+=str;
 +
} else {
 +
popupElement.appendChild(str);
 +
}
 +
if (onSuccess) { onSuccess(); }
 +
setTimeout(checkPopupPosition, 100);
 +
return true;
 +
} else {
 +
// call this function again in a little while...
 +
setTimeout(function(){
 +
setPopupHTML(str,elementId,popupId,onSuccess);
 +
}, 600);
 +
}
 +
return null;
 +
}
 +
 
 +
//<NOLITE>
 +
function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);}
 +
//</NOLITE>
 +
 
 +
// args.navpopup is mandatory
 +
// optional: args.redir, args.redirTarget
 +
// FIXME: ye gods, this is ugly stuff
 +
function fillEmptySpans(args) {
 +
// if redir is present and true then redirTarget is mandatory
 +
var redir=true;
 +
var rcid;
 +
if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; }
 +
var a=args.navpopup.parentAnchor;
 +
 
 +
var article, hint=null, oldid=null, params={};
 +
if (redir && typeof args.redirTarget == typeof {}) {
 +
article=args.redirTarget;
 +
//hint=article.hintValue();
 +
} else {
 +
article=(new Title()).fromAnchor(a);
 +
hint=a.originalTitle || article.hintValue();
 +
params=parseParams(a.href);
 +
oldid=(getValueOf('popupHistoricalLinks')) ? params.oldid : null;
 +
rcid=params.rcid;
 +
}
 +
var x={ article:article, hint: hint, oldid: oldid, rcid: rcid, navpop:args.navpopup, params:params };
 +
 
 +
var structure=pg.structures[getValueOf('popupStructure')];
 +
if (typeof structure != 'object') {
 +
setPopupHTML('popupError', 'Unknown structure (this should never happen): '+
 +
pg.option.popupStructure, args.navpopup.idNumber);
 +
return;
 +
}
 +
var spans=flatten(pg.misc.layout);
 +
var numspans = spans.length;
 +
var redirs=pg.misc.redirSpans;
 +
 
 +
for (var i=0; i<numspans; ++i) {
 +
var found = redirs && (redirs.indexOf( spans[i] ) !== -1);
 +
//log('redir='+redir+', found='+found+', spans[i]='+spans[i]);
 +
if ( (found && !redir) || (!found && redir) ) {
 +
//log('skipping this set of the loop');
 +
continue;
 +
}
 +
var structurefn=structure[spans[i]];
 +
var setfn = setPopupHTML;
 +
if (getValueOf('popupActiveNavlinks') &&
 +
(spans[i].indexOf('popupTopLinks')===0 || spans[i].indexOf('popupRedirTopLinks')===0)
 +
) {
 +
setfn = setPopupTipsAndHTML;
 +
}
 +
switch (typeof structurefn) {
 +
case 'function':
 +
log('running '+spans[i]+'({article:'+x.article+', hint:'+x.hint+', oldid: '+x.oldid+'})');
 +
setfn(structurefn(x), spans[i], args.navpopup.idNumber);
 +
break;
 +
case 'string':
 +
setfn(structurefn, spans[i], args.navpopup.idNumber);
 +
break;
 +
default:
 +
errlog('unknown thing with label '+spans[i] + ' (span index was ' + i + ')');
 +
break;
 +
}
 +
}
 +
}
 +
 
 +
// flatten an array
 +
function flatten(list, start) {
 +
var ret=[];
 +
if (typeof start == 'undefined') { start=0; }
 +
for (var i=start; i<list.length; ++i) {
 +
if (typeof list[i] == typeof []) {
 +
return ret.concat(flatten(list[i])).concat(flatten(list, i+1));
 +
}
 +
else { ret.push(list[i]); }
 +
}
 +
return ret;
 +
}
 +
 
 +
// Generate html for whole popup
 +
function popupHTML (a) {
 +
getValueOf('popupStructure');
 +
var structure=pg.structures[pg.option.popupStructure];
 +
if (typeof structure != 'object') {
 +
//return 'Unknown structure: '+pg.option.popupStructure;
 +
// override user choice
 +
pg.option.popupStructure=pg.optionDefault.popupStructure;
 +
return popupHTML(a);
 +
}
 +
if (typeof structure.popupLayout != 'function') { return 'Bad layout'; }
 +
pg.misc.layout=structure.popupLayout();
 +
if ($.isFunction(structure.popupRedirSpans)) { pg.misc.redirSpans=structure.popupRedirSpans(); }
 +
else { pg.misc.redirSpans=[]; }
 +
return makeEmptySpans(pg.misc.layout, a.navpopup);
 +
}
 +
 
 +
function makeEmptySpans (list, navpop) {
 +
var ret='';
 +
for (var i=0; i<list.length; ++i) {
 +
if (typeof list[i] == typeof '') {
 +
ret += emptySpanHTML(list[i], navpop.idNumber, 'div');
 +
} else if (typeof list[i] == typeof [] && list[i].length > 0 ) {
 +
ret = ret.parenSplit(RegExp('(</[^>]*?>$)')).join(makeEmptySpans(list[i], navpop));
 +
} else if (typeof list[i] == typeof {} && list[i].nodeType ) {
 +
ret += emptySpanHTML(list[i].name, navpop.idNumber, list[i].nodeType);
 +
}
 +
}
 +
return ret;
 +
}
 +
 
 +
 
 +
function emptySpanHTML(name, id, tag, classname) {
 +
tag = tag || 'span';
 +
if (!classname) { classname = emptySpanHTML.classAliases[name]; }
 +
classname = classname || name;
 +
if (name == getValueOf('popupDragHandle')) { classname += ' popupDragHandle'; }
 +
return simplePrintf('<%s id="%s" class="%s"></%s>', [tag, name + id, classname, tag]);
 +
}
 +
emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' };
 +
 
 +
// generate html for popup image
 +
// <a id="popupImageLinkn"><img id="popupImagen">
 +
// where n=idNumber
 +
function imageHTML(article, idNumber) {
 +
return simplePrintf('<a id="popupImageLink$1">' +
 +
'<img align="right" valign="top" id="popupImg$1" style="display: none;"></img>' +
 +
'</a>', [ idNumber ]);
 +
}
 +
 
 +
function popTipsSoonFn(id, when, popData) {
 +
if (!when) { when=250; }
 +
var popTips=function(){ setupTooltips(document.getElementById(id), false, true, popData); };
 +
return function() { setTimeout( popTips, when, popData ); };
 +
}
 +
 
 +
function setPopupTipsAndHTML(html, divname, idnumber, popData) {
 +
setPopupHTML(html, divname, idnumber,
 +
getValueOf('popupSubpopups') ?
 +
popTipsSoonFn(divname + idnumber, null, popData) :
 +
null);
 +
}
 +
// ENDFILE: htmloutput.js
 +
// STARTFILE: mouseout.js
 +
//////////////////////////////////////////////////
 +
// fuzzy checks
 +
 
 +
function fuzzyCursorOffMenus(x,y, fuzz, parent) {
 +
if (!parent) { return null; }
 +
var uls=parent.getElementsByTagName('ul');
 +
for (var i=0; i<uls.length; ++i) {
 +
if (uls[i].className=='popup_menu') {
 +
if (uls[i].offsetWidth > 0) return false;
 +
} // else {document.title+='.';}
 +
}
 +
return true;
 +
}
 +
 
 +
function checkPopupPosition () { // stop the popup running off the right of the screen
 +
// FIXME avoid pg.current.link
 +
if (pg.current.link && pg.current.link.navpopup)
 +
pg.current.link.navpopup.limitHorizontalPosition();
 +
}
 +
 
 +
function mouseOutWikiLink () {
 +
//console ('mouseOutWikiLink');
 +
var a=this;
 +
 +
removeModifierKeyHandler(a);
 +
 +
if (a.navpopup === null || typeof a.navpopup === 'undefined') return;
 +
if ( ! a.navpopup.isVisible() ) {
 +
a.navpopup.banish();
 +
return;
 +
}
 +
restoreTitle(a);
 +
Navpopup.tracker.addHook(posCheckerHook(a.navpopup));
 +
}
 +
 
 +
function posCheckerHook(navpop) {
 +
return function() {
 +
if (!navpop.isVisible()) { return true; /* remove this hook */ }
 +
if (Navpopup.tracker.dirty) {
 +
return false;
 +
}
 +
var x=Navpopup.tracker.x, y=Navpopup.tracker.y;
 +
var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) ||
 +
!fuzzyCursorOffMenus(x,y,navpop.fuzz, navpop.mainDiv);
 +
 
 +
// FIXME it'd be prettier to do this internal to the Navpopup objects
 +
var t=getValueOf('popupHideDelay');
 +
if (t) { t = t * 1000; }
 +
if (!t) {
 +
if(!mouseOverNavpop) {
 +
if(navpop.parentAnchor) {
 +
restoreTitle( navpop.parentAnchor );
 +
}
 +
navpop.banish();
 +
return true; /* remove this hook */
 +
}
 +
return false;
 +
}
 +
// we have a hide delay set
 +
var d=+(new Date());
 +
if ( !navpop.mouseLeavingTime ) {
 +
navpop.mouseLeavingTime = d;
 +
return false;
 +
}
 +
if ( mouseOverNavpop ) {
 +
navpop.mouseLeavingTime=null;
 +
return false;
 +
}
 +
if (d - navpop.mouseLeavingTime > t) {
 +
navpop.mouseLeavingTime=null;
 +
navpop.banish(); return true; /* remove this hook */
 +
}
 +
return false;
 +
};
 +
}
 +
 
 +
function runStopPopupTimer(navpop) {
 +
// at this point, we should have left the link but remain within the popup
 +
// so we call this function again until we leave the popup.
 +
if (!navpop.stopPopupTimer) {
 +
navpop.stopPopupTimer=setInterval(posCheckerHook(navpop), 500);
 +
navpop.addHook(function(){clearInterval(navpop.stopPopupTimer);},
 +
  'hide', 'before');
 +
}
 +
}
 +
// ENDFILE: mouseout.js
 +
// STARTFILE: previewmaker.js
 +
/**
 +
  @fileoverview
 +
  Defines the {@link Previewmaker} object, which generates short previews from wiki markup.
 +
*/
 +
 
 +
/**
 +
  Creates a new Previewmaker
 +
  @constructor
 +
  @class The Previewmaker class. Use an instance of this to generate short previews from Wikitext.
 +
  @param {String} wikiText The Wikitext source of the page we wish to preview.
 +
  @param {String} baseUrl The url we should prepend when creating relative urls.
 +
  @param {Navpopup} owner The navpop associated to this preview generator
 +
*/
 +
function Previewmaker(wikiText, baseUrl, owner) {
 +
/** The wikitext which is manipulated to generate the preview. */
 +
this.originalData=wikiText;
 +
this.baseUrl=baseUrl;
 +
this.owner=owner;
 +
 
 +
this.maxCharacters=getValueOf('popupMaxPreviewCharacters');
 +
this.maxSentences=getValueOf('popupMaxPreviewSentences');
 +
 
 +
this.setData();
 +
}
 +
Previewmaker.prototype.setData=function() {
 +
var maxSize=Math.max(10000, 2*this.maxCharacters);
 +
this.data=this.originalData.substring(0,maxSize);
 +
};
 +
/** Remove HTML comments
 +
@private
 +
*/
 +
Previewmaker.prototype.killComments = function () {
 +
// this also kills one trailing newline, eg [[diamyo]]
 +
this.data=this.data.replace(RegExp('^<!--[^$]*?-->\\n|\\n<!--[^$]*?-->(?=\\n)|<!--[^$]*?-->', 'g'), '');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killDivs = function () {
 +
// say goodbye, divs (can be nested, so use * not *?)
 +
this.data=this.data.replace(RegExp('< *div[^>]* *>[\\s\\S]*?< */ *div *>',
 +
  'gi'), '');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killGalleries = function () {
 +
this.data=this.data.replace(RegExp('< *gallery[^>]* *>[\\s\\S]*?< */ *gallery *>',
 +
  'gi'), '');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.kill = function(opening, closing, subopening, subclosing, repl) {
 +
var oldk=this.data;
 +
var k=this.killStuff(this.data, opening, closing, subopening, subclosing, repl);
 +
while (k.length < oldk.length) {
 +
oldk=k;
 +
k=this.killStuff(k, opening, closing, subopening, subclosing, repl);
 +
}
 +
this.data=k;
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killStuff = function (txt, opening, closing, subopening, subclosing, repl) {
 +
var op=this.makeRegexp(opening);
 +
var cl=this.makeRegexp(closing, '^');
 +
var sb=subopening ? this.makeRegexp(subopening, '^') : null;
 +
var sc=subclosing ? this.makeRegexp(subclosing, '^') : cl;
 +
if (!op || !cl) {
 +
alert('Navigation Popups error: op or cl is null! something is wrong.');
 +
return;
 +
}
 +
if (!op.test(txt)) { return txt; }
 +
var ret='';
 +
var opResult = op.exec(txt);
 +
ret = txt.substring(0,opResult.index);
 +
txt=txt.substring(opResult.index+opResult[0].length);
 +
var depth = 1;
 +
while (txt.length > 0) {
 +
var removal=0;
 +
if (depth==1 && cl.test(txt)) {
 +
depth--;
 +
removal=cl.exec(txt)[0].length;
 +
} else if (depth > 1 && sc.test(txt)) {
 +
depth--;
 +
removal=sc.exec(txt)[0].length;
 +
}else if (sb && sb.test(txt)) {
 +
depth++;
 +
removal=sb.exec(txt)[0].length;
 +
}
 +
if ( !removal ) { removal = 1; }
 +
txt=txt.substring(removal);
 +
if (depth === 0) { break; }
 +
}
 +
return ret + (repl || '') + txt;
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.makeRegexp = function (x, prefix, suffix) {
 +
prefix = prefix || '';
 +
suffix = suffix || '';
 +
var reStr='';
 +
var flags='';
 +
if (isString(x)) {
 +
reStr=prefix + literalizeRegex(x) + suffix;
 +
} else if (isRegExp(x)) {
 +
var s=x.toString().substring(1);
 +
var sp=s.split('/');
 +
flags=sp[sp.length-1];
 +
sp[sp.length-1]='';
 +
s=sp.join('/');
 +
s=s.substring(0,s.length-1);
 +
reStr= prefix + s + suffix;
 +
} else {
 +
log ('makeRegexp failed');
 +
}
 +
 
 +
log ('makeRegexp: got reStr=' + reStr + ', flags=' + flags);
 +
return RegExp(reStr, flags);
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killBoxTemplates = function () {
 +
 
 +
// taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general
 +
// also, have float_begin, ... float_end
 +
this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'), /[}][}]\s*/, '{{');
 +
 
 +
// infoboxes etc
 +
// from [[User:Zyxw/popups.js]]: kill frames too
 +
this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{');
 +
 
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killTemplates = function () {
 +
this.kill('{{', '}}', '{', '}', ' ');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killTables = function () {
 +
// tables are bad, too
 +
// this can be slow, but it's an inprovement over a browser hang
 +
// torture test: [[Comparison_of_Intel_Central_Processing_Units]]
 +
this.kill('{|', /[|]}\s*/, '{|');
 +
this.kill(/<table.*?>/i, /<\/table.*?>/i, /<table.*?>/i);
 +
// remove lines starting with a pipe for the hell of it (?)
 +
this.data=this.data.replace(RegExp('^[|].*$', 'mg'), '');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killImages = function () {
 +
var forbiddenNamespaceAliases = [];
 +
jQuery.each(mw.config.get('wgNamespaceIds'), function(_localizedNamespaceLc, _namespaceId) {
 +
if (_namespaceId!=pg.nsImageId && _namespaceId!=pg.nsCategoryId) return;
 +
forbiddenNamespaceAliases.push(_localizedNamespaceLc.split(' ').join('[ _]')); //todo: escape regexp fragments!
 +
});
 +
 +
// images and categories are a nono
 +
this.kill(RegExp('[[][[]\\s*(' + forbiddenNamespaceAliases.join('|') + ')\\s*:', 'i'),
 +
  /\]\]\s*/, '[', ']');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killHTML = function () {
 +
// kill <ref ...>...</ref>
 +
this.kill(/<ref\b[^/>]*?>/i, /<\/ref>/i);
 +
 
 +
// let's also delete entire lines starting with <. it's worth a try.
 +
this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n');
 +
 
 +
// and those pesky html tags, but not <nowiki> or <blockquote>
 +
var splitted=this.data.parenSplit(/(<[\w\W]*?(?:>|$|(?=<)))/);
 +
var len=splitted.length;
 +
for (var i=1; i<len; i=i+2) {
 +
switch (splitted[i]) {
 +
case '<nowiki>':
 +
case '</nowiki>':
 +
case '<blockquote>':
 +
case '</blockquote>':
 +
break;
 +
default:
 +
splitted[i]='';
 +
}
 +
}
 +
this.data=splitted.join('');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killChunks = function() { // heuristics alert
 +
// chunks of italic text? you crazy, man?
 +
var italicChunkRegex=new RegExp
 +
("((^|\\n)\\s*:*\\s*''[^']([^']|'''|'[^']){20}(.|\\n[^\\n])*''[.!?\\s]*\\n)+", 'g');
 +
// keep stuff separated, though, so stick in \n (fixes [[Union Jack]]?
 +
this.data=this.data.replace(italicChunkRegex, '\n');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.mopup = function () {
 +
// we simply *can't* be doing with horizontal rules right now
 +
this.data=this.data.replace(RegExp('^-{4,}','mg'),'');
 +
 
 +
// no indented lines
 +
this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), '');
 +
 
 +
// replace __TOC__, __NOTOC__ and whatever else there is
 +
// this'll probably do
 +
this.data=this.data.replace(RegExp('^__[A-Z_]*__ *$', 'gmi'),'');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.firstBit = function () {
 +
// dont't be givin' me no subsequent paragraphs, you hear me?
 +
/// first we "normalize" section headings, removing whitespace after, adding before
 +
var d=this.data;
 +
 
 +
if (getValueOf('popupPreviewCutHeadings')) {
 +
this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 ');
 +
/// then we want to get rid of paragraph breaks whose text ends badly
 +
this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n');
 +
 
 +
this.data=this.data.replace(RegExp('^[\\s\\n]*'), '');
 +
var stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data);
 +
if (stuff) { d = stuff[0]; }
 +
if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; }
 +
 
 +
/// now put \n\n after sections so that bullets and numbered lists work
 +
d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n');
 +
}
 +
 
 +
 
 +
// Split sentences. Superfluous sentences are RIGHT OUT.
 +
// note: exactly 1 set of parens here needed to make the slice work
 +
d = d.parenSplit(RegExp('([!?.]+["'+"'"+']*\\s)','g'));
 +
// leading space is bad, mmkay?
 +
d[0]=d[0].replace(RegExp('^\\s*'), '');
 +
 
 +
var notSentenceEnds=RegExp('([^.][a-z][.] *[a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|op|cit|\\[[^\\]]*|\\s[A-Zvclm])$', 'i');
 +
d = this.fixSentenceEnds(d, notSentenceEnds);
 +
 
 +
this.fullLength=d.join('').length;
 +
var n=this.maxSentences;
 +
var dd=this.firstSentences(d,n);
 +
 
 +
do {
 +
dd=this.firstSentences(d,n); --n;
 +
} while ( dd.length > this.maxCharacters && n !== 0 );
 +
 
 +
this.data = dd;
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.fixSentenceEnds = function(strs, reg) {
 +
// take an array of strings, strs
 +
// join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg
 +
 
 +
for (var i=0; i<strs.length-2; ++i) {
 +
if (reg.test(strs[i])) {
 +
var a=[];
 +
for (var j=0; j<strs.length; ++j) {
 +
if (j<i)  a[j]=strs[j];
 +
if (j==i)  a[i]=strs[i]+strs[i+1]+strs[i+2];
 +
if (j>i+2) a[j-2]=strs[j];
 +
}
 +
return this.fixSentenceEnds(a,reg);
 +
}
 +
}
 +
return strs;
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.firstSentences = function(strs, howmany) {
 +
var t=strs.slice(0, 2*howmany);
 +
return t.join('');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killBadWhitespace = function() {
 +
// also cleans up isolated '''', eg [[Suntory Sungoliath]]
 +
this.data=this.data.replace(RegExp('^ *\'+ *$', 'gm'), '');
 +
};
 +
/**
 +
  Runs the various methods to generate the preview.
 +
  The preview is stored in the <code>html</html> field.
 +
  @private
 +
*/
 +
Previewmaker.prototype.makePreview = function() {
 +
if (this.owner.article.namespaceId()!=pg.nsTemplateId &&
 +
this.owner.article.namespaceId()!=pg.nsImageId ) {
 +
this.killComments();
 +
this.killDivs();
 +
this.killGalleries();
 +
this.killBoxTemplates();
 +
 
 +
if (getValueOf('popupPreviewKillTemplates')) {
 +
this.killTemplates();
 +
} else {
 +
this.killMultilineTemplates();
 +
}
 +
this.killTables();
 +
this.killImages();
 +
this.killHTML();
 +
this.killChunks();
 +
this.mopup();
 +
 
 +
this.firstBit();
 +
this.killBadWhitespace();
 +
}
 +
else
 +
{
 +
this.killHTML();
 +
}
 +
this.html=wiki2html(this.data, this.baseUrl); // needs livepreview
 +
this.fixHTML();
 +
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))) //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 += pg.escapeQuotesHTML(data.substring(postfixIndex, match.index)) +
 +
  '<a href="'+Insta.conf.paths.articles+pg.escapeQuotesHTML(match[1])+'">'+pg.escapeQuotesHTML((match[2]?match[2]:match[1])+match[3])+"</a>";
 +
postfixIndex = reLinks.lastIndex;
 +
  }
 +
  //append the rest
 +
  result += pg.escapeQuotesHTML(data.substring(postfixIndex));
 +
 
 +
  return result;
 +
};
 +
Previewmaker.prototype.editSummaryPreview=function() {
 +
var reAes  = /\/\* *(.*?) *\*\//g; //match the first section marker
 +
reAes.lastIndex = 0; //reset regex
 +
 +
var match;
 +
 +
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);
 +
t.anchorFromUtf(section);
 +
var sectionLink = Insta.conf.paths.articles + pg.escapeQuotesHTML(t.toString(true)) + '#' + pg.escapeQuotesHTML(t.anchor);
 +
return start + '<a href="'+sectionLink+'">&rarr;</a> '+pg.escapeQuotesHTML(section) + end;
 +
}
 +
 +
//else there's no section link, htmlify the whole thing.
 +
return this.esWiki2HtmlPart(this.data);
 +
};
 +
 
 +
//<NOLITE>
 +
/** Test function for debugging preview problems one step at a time.
 +
*/
 +
/*eslint-disable */
 +
function previewSteps(txt) {
 +
try {
 +
txt=txt || document.editform.wpTextbox1.value;
 +
} catch (err) {
 +
if (pg.cache.pages.length > 0) {
 +
txt=pg.cache.pages[pg.cache.pages.length-1].data;
 +
} else {
 +
alert('provide text or use an edit page');
 +
}
 +
}
 +
txt=txt.substring(0,10000);
 +
var base=pg.wiki.articlebase + Title.fromURL(document.location.href).urlString();
 +
var p=new Previewmaker(txt, base, pg.current.link.navpopup);
 +
if (this.owner.article.namespaceId() != pg.nsTemplateId) {
 +
p.killComments(); if (!confirm('done killComments(). Continue?\n---\n' + p.data)) { return; }
 +
p.killDivs(); if (!confirm('done killDivs(). 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; }
 +
 
 +
if (getValueOf('popupPreviewKillTemplates')) {
 +
p.killTemplates(); if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { return; }
 +
} else {
 +
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.killImages(); if (!confirm('done killImages(). Continue?\n---\n' + p.data)) { return; }
 +
p.killHTML(); if (!confirm('done killHTML(). 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.firstBit(); if (!confirm('done firstBit(). 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.fixHTML(); if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { return; }
 +
p.stripLongTemplates(); if (!confirm('done stripLongTemplates(). Continue?\n---\n' + p.html)) { return; }
 +
alert('finished preview - end result follows.\n---\n' + p.html);
 +
}
 +
/*eslint-enable */
 +
//</NOLITE>
 +
 
 +
/**
 +
  Works around livepreview bugs.
 +
  @private
 +
*/
 +
Previewmaker.prototype.fixHTML = function() {
 +
if(!this.html) return;
 +
 
 +
  var ret = this.html;
 +
 
 +
// fix question marks in wiki links
 +
// maybe this'll break some stuff :-(
 +
ret=ret.replace(RegExp('(<a href="' + pg.wiki.articlePath + '/[^"]*)[?](.*?")', 'g'), '$1%3F$2');
 +
ret=ret.replace(RegExp('(<a href=\'' + pg.wiki.articlePath + '/[^\']*)[?](.*?\')', 'g'), '$1%3F$2');
 +
// FIXME fix up % too
 +
 +
 +
this.html=ret;
 +
};
 +
/**
 +
  Generates the preview and displays it in the current popup.
 +
 
 +
  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.
 +
*/
 +
Previewmaker.prototype.showPreview = function () {
 +
this.makePreview();
 +
if (typeof this.html != typeof '') return;
 +
if (RegExp('^\\s*$').test(this.html)) return;
 +
setPopupHTML('<hr />', 'popupPrePreviewSep', this.owner.idNumber);
 +
setPopupTipsAndHTML(this.html, 'popupPreview', this.owner.idNumber, { owner: this.owner });
 +
var more = (this.fullLength > this.data.length) ? this.moreLink() : '';
 +
setPopupHTML(more, 'popupPreviewMore', this.owner.idNumber);
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.moreLink=function() {
 +
var a=document.createElement('a');
 +
a.className='popupMoreLink';
 +
a.innerHTML=popupString('more...');
 +
var savedThis=this;
 +
a.onclick=function() {
 +
savedThis.maxCharacters+=2000;
 +
savedThis.maxSentences+=20;
 +
savedThis.setData();
 +
savedThis.showPreview();
 +
};
 +
return a;
 +
};
 +
 
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.stripLongTemplates = function() {
 +
// operates on the HTML!
 +
this.html=this.html.replace(RegExp('^.{0,1000}[{][{][^}]*?(<(p|br)( /)?>\\s*){2,}([^{}]*?[}][}])?', 'gi'), '');
 +
this.html=this.html.split('\n').join(' '); // workaround for <pre> templates
 +
this.html=this.html.replace(RegExp('[{][{][^}]*<pre>[^}]*[}][}]','gi'), '');
 +
};
 +
/**
 +
  @private
 +
*/
 +
Previewmaker.prototype.killMultilineTemplates = function() {
 +
this.kill('{{{', '}}}');
 +
this.kill(RegExp('\\s*[{][{][^{}]*\\n'), '}}', '{{');
 +
};
 +
// ENDFILE: previewmaker.js
 +
// STARTFILE: querypreview.js
 +
function loadAPIPreview(queryType, article, navpop) {
 +
var art=new Title(article).urlString();
 +
var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&';
 +
var htmlGenerator=function(/*a, d*/){alert('invalid html generator');};
 +
var usernameart = '';
 +
switch (queryType) {
 +
case 'history':
 +
url += 'titles=' + art + '&prop=revisions&rvlimit=' +
 +
getValueOf('popupHistoryPreviewLimit');
 +
htmlGenerator=APIhistoryPreviewHTML;
 +
break;
 +
case 'category':
 +
url += 'list=categorymembers&cmtitle=' + art;
 +
htmlGenerator=APIcategoryPreviewHTML;
 +
break;
 +
case 'userinfo':
 +
var username = new Title( article ).userName();
 +
usernameart = encodeURIComponent( username );
 +
if (pg.re.ipUser.test(username)) {
 +
url += 'list=blocks&bkprop=range|restrictions&bkip=' + usernameart;
 +
} else {
 +
url += 'list=users|usercontribs&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + usernameart + "&meta=globaluserinfo&guiprop=groups|unattached&guiuser="+ usernameart + "&uclimit=1&ucprop=timestamp&ucuser=" + usernameart;
 +
}
 +
htmlGenerator=APIuserInfoPreviewHTML;
 +
break;
 +
case 'contribs':
 +
usernameart = encodeURIComponent( new Title( article ).userName() );
 +
url += 'list=usercontribs&ucuser=' + usernameart +
 +
'&uclimit=' + getValueOf('popupContribsPreviewLimit');
 +
htmlGenerator=APIcontribsPreviewHTML;
 +
break;
 +
case 'imagepagepreview':
 +
var trail='';
 +
if (getValueOf('popupImageLinks')) { trail = '&list=imageusage&iutitle=' + art; }
 +
url += 'titles=' + art + '&prop=revisions|imageinfo&rvprop=content' + trail;
 +
htmlGenerator=APIimagepagePreviewHTML;
 +
break;
 +
case 'backlinks':
 +
url += 'list=backlinks&bltitle=' + art;
 +
htmlGenerator=APIbacklinksPreviewHTML;
 +
break;
 +
case 'revision':
 +
if (article.oldid) {
 +
url += 'revids=' + article.oldid;
 +
} else {
 +
url += 'titles=' + article.removeAnchor().urlString();
 +
}
 +
url += '&prop=revisions|pageprops|info|images|categories&rvprop=ids|timestamp|flags|comment|user|content&cllimit=max&imlimit=max';
 +
htmlGenerator=APIrevisionPreviewHTML;
 +
break;
 +
}
 +
pendingNavpopTask(navpop);
 +
var callback=function(d){
 +
log( "callback of API functions was hit" );
 +
showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d);
 +
};
 +
var go = function(){
 +
getPageWithCaching(url, callback, navpop);
 +
return true;
 +
};
 +
 
 +
if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); }
 +
else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_'+queryType+'_QUERY_DATA'); }
 +
}
 +
 
 +
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 getTimeOffset() {
 +
var tz = mw.user.options.get('timecorrection');
 +
 
 +
if(tz) {
 +
if( tz.indexOf('|') > -1 ) {
 +
// New format
 +
return parseInt(tz.split('|')[1],10);
 +
} else if ( tz.indexOf(':') > -1 ) {
 +
// Old format
 +
return( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) );
 +
}
 +
}
 +
return 0;
 +
}
 +
 
 +
/*
 +
* Creates a HTML table that's shown in the history and user-contribs popups.
 +
* @param {Object[]} h - a list of revisions, returned from the API
 +
* @param {boolean} reallyContribs - true only if we're displaying user contributions
 +
*/
 +
function editPreviewTable(article, h, reallyContribs, timeOffset) {
 +
var html=['<table>'];
 +
var day=null;
 +
var curart=article;
 +
var page=null;
 +
 
 +
var makeFirstColumnLinks;
 +
if(reallyContribs) {
 +
 
 +
// We're showing user contributions, so make (diff | hist) links
 +
makeFirstColumnLinks = function(currentRevision) {
 +
var result = '(';
 +
result += '<a href="' + pg.wiki.titlebase +
 +
new Title(currentRevision.title).urlString() + '&diff=prev' +
 +
'&oldid=' + currentRevision.revid + '">' + popupString('diff') + '</a>';
 +
result += '&nbsp;|&nbsp;';
 +
result += '<a href="' + pg.wiki.titlebase +
 +
new Title(currentRevision.title).urlString() + '&action=history">' +
 +
popupString('hist') + '</a>';
 +
result += ')';
 +
return result;
 +
};
 +
} else {
 +
 
 +
// It's a regular history page, so make (cur | last) links
 +
var firstRevid = h[0].revid;
 +
makeFirstColumnLinks = function(currentRevision) {
 +
var result = '(';
 +
result += '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
 +
'&diff=' + firstRevid + '&oldid=' + currentRevision.revid + '">' + popupString('cur') + '</a>';
 +
result += '&nbsp;|&nbsp;';
 +
result += '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
 +
'&diff=prev&oldid=' + currentRevision.revid + '">' + popupString('last') + '</a>';
 +
result += ')';
 +
return result;
 +
};
 +
}
 +
 
 +
for (var i=0; i<h.length; ++i) {
 +
if (reallyContribs) {
 +
page = h[i].title;
 +
curart = new Title(page);
 +
}
 +
var minor = h[i].minor ? '<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>' + makeFirstColumnLinks(h[i]) + '</td>');
 +
html.push('<td>' +
 +
'<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
 +
'&oldid=' + h[i].revid + '">' + thisTime + '</a></td>');
 +
var col3url='', col3txt='';
 +
if (!reallyContribs) {
 +
var user=h[i].user;
 +
if( !h[i].userhidden ) {
 +
if( pg.re.ipUser.test(user) ) {
 +
col3url=pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Contributions&target=' + new Title(user).urlString();
 +
} else {
 +
col3url=pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + new Title(user).urlString();
 +
}
 +
col3txt=pg.escapeQuotesHTML(user);
 +
} else {
 +
col3url=getValueOf('popupRevDelUrl');
 +
col3txt=pg.escapeQuotesHTML( popupString('revdel'));
 +
}
 +
} else {
 +
col3url=pg.wiki.titlebase + curart.urlString();
 +
col3txt=pg.escapeQuotesHTML(page);
 +
}
 +
html.push('<td>' + (reallyContribs ? minor : '') +
 +
'<a href="' + col3url + '">' + col3txt + '</a></td>');
 +
var comment='';
 +
var c=h[i].comment || h[i].content;
 +
if (c) {
 +
comment=new Previewmaker(c, new Title(curart).toUrl()).editSummaryPreview();
 +
} else if ( h[i].commenthidden ) {
 +
comment=popupString('revdel');
 +
}
 +
html.push('<td>' + (!reallyContribs ? minor : '') + comment + '</td>');
 +
html.push('</tr>');
 +
html=[html.join('')];
 +
}
 +
html.push('</table>');
 +
return html.join('');
 +
}
 +
 
 +
function getDateFromTimestamp(t) {
 +
var s=t.split(/[^0-9]/);
 +
switch(s.length) {
 +
case 0: return null;
 +
case 1: return new Date(s[0]);
 +
case 2: return new Date(s[0], s[1]-1);
 +
case 3: return new Date(s[0], s[1]-1, s[2]);
 +
case 4: return new Date(s[0], s[1]-1, s[2], s[3]);
 +
case 5: return new Date(s[0], s[1]-1, s[2], s[3], s[4]);
 +
case 6: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5]);
 +
default: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5], s[6]);
 +
}
 +
}
 +
 
 +
function adjustDate(d, offset) {
 +
// offset is in minutes
 +
var o=offset * 60 * 1000;
 +
return new Date( +d + o);
 +
}
 +
 
 +
function dayFormat(editDate, utc) {
 +
if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); }
 +
return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-');
 +
}
 +
 
 +
function timeFormat(editDate, utc) {
 +
if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); }
 +
return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':');
 +
}
 +
 
 +
function showAPIPreview(queryType, html, id, navpop, download) {
 +
// DJ: done
 +
var target='popupPreview';
 +
completedNavpopTask(navpop);
 +
 
 +
switch (queryType) {
 +
case 'imagelinks':
 +
case 'category':
 +
target='popupPostPreview'; break;
 +
case 'userinfo':
 +
target='popupUserData'; break;
 +
case 'revision':
 +
insertPreview(download);
 +
return;
 +
}
 +
setPopupTipsAndHTML(html, target, id);
 +
}
 +
 
 +
function APIrevisionPreviewHTML(article, download) {
 +
try{
 +
var jsObj=getJsObj(download.data);
 +
var page=anyChild(jsObj.query.pages);
 +
if( page.missing ) {
 +
// TODO we need to fix this proper later on
 +
download.owner = null;
 +
return;
 +
}
 +
var content = (
 +
page &&
 +
page.revisions &&
 +
page.revisions[0].contentmodel === 'wikitext'
 +
) ? page.revisions[0].content : null;
 +
if( typeof content === 'string' )
 +
{
 +
download.data = content;
 +
download.lastModified = new Date(page.revisions[0].timestamp);
 +
}
 +
} catch(someError) {
 +
return 'Revision preview failed :(';
 +
}
 +
}
 +
 
 +
function APIbacklinksPreviewHTML(article, download/*, navpop*/ ) {
 +
try {
 +
var jsObj=getJsObj(download.data);
 +
var list=jsObj.query.backlinks;
 +
 
 +
var html=[];
 +
if (!list) { return popupString('No backlinks found'); }
 +
for ( var i=0; i < list.length; i++ ) {
 +
var t=new Title(list[i].title);
 +
html.push('<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t + '</a>');
 +
}
 +
html=html.join(', ');
 +
if (jsObj['continue'] && jsObj['continue'].blcontinue) {
 +
html += popupString(' and more');
 +
}
 +
return html;
 +
} catch (someError) {
 +
return 'backlinksPreviewHTML went wonky';
 +
}
 +
}
 +
 
 +
pg.fn.APIsharedImagePagePreviewHTML = 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].contentmodel === 'wikitext'
 +
) ? page.revisions[0].content : null;
 +
if( typeof content === 'string' )
 +
{
 +
/* 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 );
 +
}
 +
}
 +
};
 +
 
 +
function APIimagepagePreviewHTML(article, download, navpop) {
 +
try {
 +
var jsObj=getJsObj(download.data);
 +
var page=anyChild(jsObj.query.pages);
 +
var content= (
 +
page &&
 +
page.revisions &&
 +
page.revisions[0].contentmodel === 'wikitext'
 +
) ? page.revisions[0].content : null;
 +
var ret='';
 +
var alt='';
 +
try{alt=navpop.parentAnchor.childNodes[0].alt;} catch(e){}
 +
if (alt) {
 +
ret = ret + '<hr /><b>' + popupString('Alt text:') + '</b> ' + pg.escapeQuotesHTML(alt);
 +
}
 +
if (typeof content === 'string') {
 +
var p=prepPreviewmaker(content, article, navpop);
 +
p.makePreview();
 +
if (p.html) { ret += '<hr />' + p.html; }
 +
if (getValueOf('popupSummaryData')) {
 +
var info=getPageInfo(content, download);
 +
log(info);
 +
setPopupTrailer(info, navpop.idNumber);
 +
}
 +
}
 +
if (page && page.imagerepository == "shared" ) {
 +
var art=new Title(article);
 +
var encart = encodeURIComponent( "File:" + art.stripNamespace() );
 +
var shared_url =  pg.wiki.apicommonsbase + '?format=json&formatversion=2' +
 +
'&callback=pg.fn.APIsharedImagePagePreviewHTML' +
 +
'&requestid=' + navpop.idNumber +
 +
'&action=query&prop=revisions&rvprop=content&titles=' + encart;
 +
 
 +
ret = ret +'<hr />' + popupString( 'Image from Commons') +
 +
': <a href="' + pg.wiki.commonsbase + '?title=' + encart + '">' +
 +
popupString( 'Description page') + '</a>';
 +
mw.loader.load( shared_url );
 +
}
 +
showAPIPreview('imagelinks', APIimagelinksPreviewHTML(article,download), navpop.idNumber, download);
 +
return ret;
 +
} catch (someError) {
 +
return 'API imagepage preview failed :(';
 +
}
 +
}
 +
 
 +
function APIimagelinksPreviewHTML(article, download) {
 +
try {
 +
var jsobj=getJsObj(download.data);
 +
var list=jsobj.query.imageusage;
 +
if (list) {
 +
var ret=[];
 +
for (var i=0; i < list.length; i++) {
 +
ret.push(list[i].title);
 +
}
 +
if (ret.length === 0) { return popupString('No image links found'); }
 +
return '<h2>' + popupString('File links') + '</h2>' + linkList(ret);
 +
} else {
 +
return popupString('No image links found');
 +
}
 +
} catch(someError) {
 +
return 'Image links preview generation failed :(';
 +
}
 +
}
 +
 
 +
function APIcategoryPreviewHTML(article, download) {
 +
try{
 +
var jsobj=getJsObj(download.data);
 +
var list=jsobj.query.categorymembers;
 +
var ret=[];
 +
for (var p=0; p < list.length; p++) {
 +
  ret.push(list[p].title);
 +
}
 +
if (ret.length === 0) { return popupString('Empty category'); }
 +
ret = '<h2>' + tprintf('Category members (%s shown)', [ret.length]) + '</h2>' +linkList(ret);
 +
if (jsobj['continue'] && jsobj['continue'].cmcontinue) {
 +
ret += popupString(' and more');
 +
}
 +
return ret;
 +
} catch(someError) {
 +
return 'Category preview failed :(';
 +
}
 +
}
 +
 
 +
function APIuserInfoPreviewHTML(article, download) {
 +
var ret=[];
 +
var queryobj = {};
 +
try{
 +
queryobj=getJsObj(download.data).query;
 +
} catch(someError) { return 'Userinfo preview failed :('; }
 +
 
 +
var user=anyChild(queryobj.users);
 +
if (user) {
 +
var globaluserinfo=queryobj.globaluserinfo;
 +
if (user.invalid === '') {
 +
ret.push( popupString( 'Invalid user') );
 +
} else if (user.missing === '') {
 +
ret.push( popupString( 'Not a registered username') );
 +
}
 +
if( user.blockedby ) {
 +
if( user.blockpartial ) {
 +
ret.push('<b>' + popupString('Has blocks') + '</b>');
 +
} else {
 +
ret.push('<b>' + popupString('BLOCKED') + '</b>');
 +
}
 +
}
 +
if( globaluserinfo && ( 'locked' in globaluserinfo || 'hidden' in globaluserinfo ) ) {
 +
var lockedSulAccountIsAttachedToThis = true;
 +
for( var i=0; globaluserinfo.unattached && i < globaluserinfo.unattached.length; i++) {
 +
if ( globaluserinfo.unattached[i].wiki === mw.config.get('wgDBname') ) {
 +
lockedSulAccountIsAttachedToThis=false;
 +
break;
 +
}
 +
}
 +
if (lockedSulAccountIsAttachedToThis) {
 +
if ( 'locked' in globaluserinfo ) ret.push('<b><i>' + popupString('LOCKED') + '</i></b>');
 +
if ( 'hidden' in globaluserinfo ) ret.push('<b><i>' + popupString('HIDDEN') + '</i></b>');
 +
}
 +
}
 +
if( getValueOf('popupShowGender') && user.gender ) {
 +
switch( user.gender ) {
 +
case "male": ret.push( popupString( "\u2642" ) ); break;
 +
case "female": ret.push( popupString( "\u2640" ) ); break;
 +
}
 +
}
 +
if( user.groups ) {
 +
for( var j=0; j < user.groups.length; j++) {
 +
var currentGroup = user.groups[j];
 +
if( ["*", "user", "autoconfirmed", "extendedconfirmed"].indexOf( currentGroup ) === -1 ) {
 +
ret.push( pg.escapeQuotesHTML(user.groups[j]) );
 +
}
 +
}
 +
}
 +
if( globaluserinfo && globaluserinfo.groups ) {
 +
for( var k=0; k < globaluserinfo.groups.length; k++) {
 +
ret.push( '<i>'+pg.escapeQuotesHTML(globaluserinfo.groups[k])+'</i>' );
 +
}
 +
}
 +
if( user.registration )
 +
ret.push( pg.escapeQuotesHTML((user.editcount?user.editcount:'0') + popupString(' edits since: ') + (user.registration?dayFormat(getDateFromTimestamp(user.registration)):'')) );
 +
}
 +
 
 +
if (queryobj.usercontribs && queryobj.usercontribs.length) {
 +
ret.push( popupString('last edit on ') + dayFormat(getDateFromTimestamp(queryobj.usercontribs[0].timestamp)) );
 +
}
 +
 +
if (queryobj.blocks) {
 +
ret.push( popupString( 'IP user') ); //we only request list=blocks for IPs
 +
for (var l=0; l<queryobj.blocks.length; l++) {
 +
console.log(queryobj);
 +
var rbstr = queryobj.blocks[l].rangestart === queryobj.blocks[l].rangeend ? 'BLOCK' : 'RANGEBLOCK';
 +
rbstr = (!Array.isArray(queryobj.blocks[l].restrictions) ? 'Has ' + rbstr.toLowerCase() + 's' : rbstr + 'ED')
 +
ret.push('<b>' + popupString(rbstr) + '</b>' );
 +
}
 +
}
 +
 +
ret = '<hr />' + ret.join( ', ' );
 +
return ret;
 +
}
 +
 
 +
function APIcontribsPreviewHTML(article, download, navpop) {
 +
return APIhistoryPreviewHTML(article, download, navpop, true);
 +
}
 +
 
 +
function APIhistoryPreviewHTML(article, download, navpop, reallyContribs) {
 +
try {
 +
var jsobj=getJsObj(download.data);
 +
var edits = [];
 +
if( reallyContribs ) {
 +
edits=jsobj.query.usercontribs;
 +
} else {
 +
edits=anyChild(jsobj.query.pages).revisions;
 +
}
 +
 
 +
var ret=editPreviewTable(article, edits, reallyContribs, getTimeOffset());
 +
return ret;
 +
} catch (someError) {
 +
return 'History preview failed :-(';
 +
}
 +
}
 +
 
 +
 
 +
//</NOLITE>
 +
// ENDFILE: querypreview.js
 +
// STARTFILE: debug.js
 +
////////////////////////////////////////////////////////////////////
 +
// Debugging functions
 +
////////////////////////////////////////////////////////////////////
 +
 
 +
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() {};
 +
window.errlog = function() {};
 +
//<NOLITE>
 +
}
 +
//</NOLITE>
 +
}
 +
// ENDFILE: debug.js
 +
// STARTFILE: images.js
 +
 
 +
// load image of type Title.
 +
function loadImage(image, navpop) {
 +
if (typeof image.stripNamespace != 'function') { alert('loadImages bad'); }
 +
// API call to retrieve image info.
 +
 
 +
if ( !getValueOf('popupImages') ) return;
 +
if ( !isValidImageName(image) ) return false;
 +
 +
var art=image.urlString();
 +
 
 +
var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query';
 +
url += '&prop=imageinfo&iiprop=url|mime&iiurlwidth=' + getValueOf('popupImageSizeLarge');
 +
url += '&titles=' + art;
 +
 
 +
pendingNavpopTask(navpop);
 +
var callback=function(d){
 +
popupsInsertImage(navpop.idNumber, navpop, d);
 +
};
 +
var go = function(){
 +
getPageWithCaching(url, callback, navpop);
 +
return true;
 +
};
 +
if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); }
 +
else { navpop.addHook(go, 'unhide', 'after', 'DOWNLOAD_IMAGE_QUERY_DATA'); }
 +
 
 +
}
 +
 
 +
function popupsInsertImage(id, navpop, download) {
 +
log( "popupsInsertImage");
 +
var imageinfo;
 +
try {
 +
var jsObj=getJsObj(download.data);
 +
var imagepage=anyChild(jsObj.query.pages);
 +
if (typeof imagepage.imageinfo === 'undefined') return;
 +
imageinfo = imagepage.imageinfo[0];
 +
} catch (someError) {
 +
log( "popupsInsertImage failed :(" );
 +
return;
 +
}
 +
 
 +
var popupImage = document.getElementById("popupImg"+id);
 +
if (!popupImage) {
 +
log( "could not find insertion point for image");
 +
return;
 +
}
 +
 
 +
popupImage.width=getValueOf('popupImageSize');
 +
popupImage.style.display='inline';
 +
 
 +
// Set the source for the image.
 +
if( imageinfo.thumburl )
 +
popupImage.src=imageinfo.thumburl;
 +
else if( imageinfo.mime.indexOf("image") === 0 ){
 +
popupImage.src=imageinfo.url;
 +
log( "a thumb could not be found, using original image" );
 +
} else log( "fullsize imagethumb, but not sure if it's an image");
 +
 
 +
 
 +
var a=document.getElementById("popupImageLink"+id);
 +
if (a === null) { return null; }
 +
 
 +
// Determine the action of the surrouding imagelink.
 +
switch (getValueOf('popupThumbAction')) {
 +
case 'imagepage':
 +
if (pg.current.article.namespaceId()!=pg.nsImageId) {
 +
a.href=imageinfo.descriptionurl;
 +
// FIXME: unreliable pg.idNumber
 +
popTipsSoonFn('popupImage' + id)();
 +
break;
 +
}
 +
/* falls through */
 +
case 'sizetoggle':
 +
a.onclick=toggleSize;
 +
a.title=popupString('Toggle image size');
 +
return;
 +
case 'linkfull':
 +
a.href = imageinfo.url;
 +
a.title=popupString('Open full-size image');
 +
return;
 +
}
 +
 
 +
}
 +
 
 +
// Toggles the image between inline small and navpop fullwidth.
 +
// It's the same image, no actual sizechange occurs, only display width.
 +
function toggleSize() {
 +
var imgContainer=this;
 +
if (!imgContainer) {
 +
alert('imgContainer is null :/');
 +
return;
 +
}
 +
var 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='';
 +
}
 +
}
 +
 
 +
// Returns one title of an image from wikiText.
 +
function getValidImageFromWikiText(wikiText) {
 +
// nb in pg.re.image we're interested in the second bracketed expression
 +
// this may change if the regex changes :-(
 +
//var match=pg.re.image.exec(wikiText);
 +
var matched=null;
 +
var match;
 +
// strip html comments, used by evil bots :-(
 +
var t = removeMatchesUnless(wikiText, RegExp('(<!--[\\s\\S]*?-->)'), 1,
 +
RegExp('^<!--[^[]*popup', 'i'));
 +
 
 +
while ( ( match = pg.re.image.exec(t) ) ) {
 +
// now find a sane image name - exclude templates by seeking {
 +
var m = match[2] || match[6];
 +
if ( isValidImageName(m) ) {
 +
matched=m;
 +
break;
 +
}
 +
}
 +
pg.re.image.lastIndex=0;
 +
if (!matched) { return null; }
 +
return mw.config.get('wgFormattedNamespaces')[pg.nsImageId]+':'+upcaseFirst(matched);
 +
}
 +
 
 +
function removeMatchesUnless(str, re1, parencount, re2) {
 +
var split=str.parenSplit(re1);
 +
var c=parencount + 1;
 +
for (var i=0; i<split.length; ++i) {
 +
if ( i%c === 0 || re2.test(split[i]) ) { continue; }
 +
split[i]='';
 +
}
 +
return split.join('');
 +
}
 +
 
 +
//</NOLITE>
 +
// ENDFILE: images.js
 +
// STARTFILE: namespaces.js
 +
// Set up namespaces and other non-strings.js localization
 +
// (currently that means redirs too)
 +
 
 +
function setNamespaces() {
 +
pg.nsSpecialId  = -1;
 +
pg.nsMainspaceId = 0;
 +
pg.nsImageId   = 6;
 +
pg.nsUserId    = 2;
 +
pg.nsUsertalkId  = 3;
 +
pg.nsCategoryId  = 14;
 +
pg.nsTemplateId  = 10;
 +
}
 +
 
 +
 
 +
function setRedirs() {
 +
var r='redirect';
 +
var R='REDIRECT';
 +
var redirLists={
 +
//<NOLITE>
 +
'ar':  [ R, 'تحويل' ],
 +
'be':  [ r, 'перанакіраваньне' ],
 +
'bg':  [ r, 'пренасочване', 'виж' ],
 +
'bs':  [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ],
 +
'bn':  [ R, 'পুনর্নির্দেশ'],
 +
'cs':  [ R, 'PŘESMĚRUJ' ],
 +
'cy':  [ r, 'ail-cyfeirio' ],
 +
'de':  [ R, 'WEITERLEITUNG' ],
 +
'el':  [ R, 'ΑΝΑΚΑΤΕΥΘΥΝΣΗ'],
 +
'eo':  [ R, 'ALIDIREKTU', 'ALIDIREKTI' ],
 +
'es':  [ R, 'REDIRECCIÓN' ],
 +
'et':  [ r, 'suuna' ],
 +
'ga':  [ r, 'athsheoladh' ],
 +
'gl':  [ r, 'REDIRECCIÓN', 'REDIRECIONAMENTO'],
 +
'he':  [ R, 'הפניה' ],
 +
'hu':  [ R, 'ÁTIRÁNYÍTÁS' ],
 +
'is':  [ r, 'tilvísun', 'TILVÍSUN' ],
 +
'it':  [ R, 'RINVIA', 'Rinvia'],
 +
'ja':  [ R, '転送' ],
 +
'mk':  [ r, 'пренасочување', 'види' ],
 +
'nds': [ r, 'wiederleiden' ],
 +
'nl':  [ R, 'DOORVERWIJZING' ],
 +
'nn':  [ r, 'omdiriger' ],
 +
'pl':  [ R, 'PATRZ', 'PRZEKIERUJ', 'TAM' ],
 +
'pt':  [ R, 'redir' ],
 +
'ru':  [ R, 'ПЕРЕНАПРАВЛЕНИЕ', 'ПЕРЕНАПР' ],
 +
'sk':  [ r, 'presmeruj' ],
 +
'sr':  [ r, 'Преусмери', 'преусмери', 'ПРЕУСМЕРИ', 'Preusmeri', 'preusmeri', 'PREUSMERI' ],
 +
'tt':  [ R, 'yünältü', 'перенаправление', 'перенапр' ],
 +
'uk':  [ R, 'ПЕРЕНАПРАВЛЕННЯ', 'ПЕРЕНАПР' ],
 +
'vi':  [ r, 'đổi' ],
 +
'zh':  [ R, '重定向'] // no comma
 +
//</NOLITE>
 +
};
 +
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) {
 +
// From https://meta.wikimedia.org/wiki/List_of_Wikipedias
 +
pg.wiki.interwiki='aa|ab|ace|af|ak|als|am|an|ang|ar|arc|arz|as|ast|av|ay|az|ba|bar|bat-smg|bcl|be|be-x-old|bg|bh|bi|bjn|bm|bn|bo|bpy|br|bs|bug|bxr|ca|cbk-zam|cdo|ce|ceb|ch|cho|chr|chy|ckb|co|cr|crh|cs|csb|cu|cv|cy|da|de|diq|dsb|dv|dz|ee|el|eml|en|eo|es|et|eu|ext|fa|ff|fi|fiu-vro|fj|fo|fr|frp|frr|fur|fy|ga|gag|gan|gd|gl|glk|gn|got|gu|gv|ha|hak|haw|he|hi|hif|ho|hr|hsb|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|ilo|io|is|it|iu|ja|jbo|jv|ka|kaa|kab|kbd|kg|ki|kj|kk|kl|km|kn|ko|koi|kr|krc|ks|ksh|ku|kv|kw|ky|la|lad|lb|lbe|lg|li|lij|lmo|ln|lo|lt|ltg|lv|map-bms|mdf|mg|mh|mhr|mi|mk|ml|mn|mo|mr|mrj|ms|mt|mus|mwl|my|myv|mzn|na|nah|nap|nds|nds-nl|ne|new|ng|nl|nn|no|nov|nrm|nv|ny|oc|om|or|os|pa|pag|pam|pap|pcd|pdc|pfl|pi|pih|pl|pms|pnb|pnt|ps|pt|qu|rm|rmy|rn|ro|roa-rup|roa-tara|ru|rue|rw|sa|sah|sc|scn|sco|sd|se|sg|sh|si|simple|sk|sl|sm|sn|so|sq|sr|srn|ss|st|stq|su|sv|sw|szl|ta|te|tet|tg|th|ti|tk|tl|tn|to|tpi|tr|ts|tt|tum|tw|ty|udm|ug|uk|ur|uz|ve|vec|vi|vls|vo|wa|war|wo|wuu|xal|xh|yi|yo|za|zea|zh|zh-classical|zh-min-nan|zh-yue|zu';
 +
pg.re.interwiki=RegExp('^'+pg.wiki.interwiki+':');
 +
} else {
 +
pg.wiki.interwiki=null;
 +
pg.re.interwiki=RegExp('^$');
 +
}
 +
}
 +
 
 +
// return a regexp pattern matching all variants to write the given namespace
 +
function nsRe(namespaceId) {
 +
var imageNamespaceVariants = [];
 +
jQuery.each(mw.config.get('wgNamespaceIds'), function(_localizedNamespaceLc, _namespaceId) {
 +
if (_namespaceId!=namespaceId) return;
 +
_localizedNamespaceLc = upcaseFirst(_localizedNamespaceLc);
 +
imageNamespaceVariants.push(mw.util.escapeRegExp(_localizedNamespaceLc).split(' ').join('[ _]'));
 +
imageNamespaceVariants.push(mw.util.escapeRegExp(encodeURI(_localizedNamespaceLc)));
 +
});
 +
 
 +
return '(?:' + imageNamespaceVariants.join('|') + ')';
 +
}
 +
 
 +
function nsReImage() {
 +
return nsRe(pg.nsImageId);
 +
}
 +
// ENDFILE: namespaces.js
 +
// STARTFILE: selpop.js
 +
//<NOLITE>
 +
function getEditboxSelection() {
 +
// see http://www.webgurusforum.com/8/12/0
 +
var editbox;
 +
try {
 +
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();
 +
if (close > 0 && sel.substring(close+2).indexOf('[[') >= 0) {
 +
return;
 +
}
 +
var a=document.createElement('a');
 +
a.href=pg.wiki.titlebase + article;
 +
mouseOverWikiLink2(a);
 +
if (a.navpopup) {
 +
a.navpopup.addHook(function(){runStopPopupTimer(a.navpopup);}, 'unhide', 'after');
 +
}
 +
}
 +
 
 +
function doSeparateSelectionPopup(str) {
 +
var div=document.getElementById('selectionPreview');
 +
if (!div) {
 +
div = document.createElement('div');
 +
div.id='selectionPreview';
 +
try {
 +
var box=document.editform.wpTextbox1;
 +
box.parentNode.insertBefore(div, box);
 +
} catch (error) {
 +
return;
 +
}
 +
}
 +
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}.
 +
 
 +
  <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>.
 +
*/
 +
 
 +
 
 +
/**
 +
  Creates a new Mousetracker.
 +
  @constructor
 +
  @class The Mousetracker class. This monitors mouse movements and manages associated hooks.
 +
*/
 +
function Mousetracker() {
 +
/**
 +
  Interval to regularly run the hooks anyway, in milliseconds.
 +
  @type Integer
 +
*/
 +
this.loopDelay=400;
 +
 
 +
/**
 +
  Timer for the loop.
 +
  @type Timer
 +
*/
 +
this.timer=null;
 +
 
 +
/**
 +
  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=[];
 +
}
 +
 
 +
/**
 +
  Adds a hook, to be called when we get events.
 +
  @param {Function} f A function which is called as
 +
  <code>f(x,y)</code>. It should return <code>true</code> when it
 +
  wants to be removed, and <code>false</code> otherwise.
 +
*/
 +
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); }
 +
};
 +
 
 +
/**
 +
  Removes hooks.
 +
  @private
 +
  @param {Object} removeObj An object whose keys are the index
 +
  numbers of functions for removal, with values that evaluate to true
 +
*/
 +
Mousetracker.prototype.removeHooks = function(removeObj) {
 +
var newHooks=[];
 +
var len = this.hooks.length;
 +
for (var i=0; i<len; ++i) {
 +
if (! removeObj[i]) { newHooks.push(this.hooks[i]); }
 +
}
 +
this.hooks=newHooks;
 +
};
 +
 
 +
 
 +
/**
 +
  Event handler for mouse wiggles.
 +
  We simply grab the event, set x and y and run the hooks.
 +
  This makes the cpu all hot and bothered :-(
 +
  @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 = document.documentElement;
 +
 
 +
if (docElt) { left=docElt.scrollLeft; }
 +
left = left || document.body.scrollLeft || document.scrollLeft || 0;
 +
 
 +
if (docElt) { top=docElt.scrollTop; }
 +
top = top || document.body.scrollTop || document.scrollTop || 0;
 +
 
 +
x=e.clientX + left;
 +
y=e.clientY + top;
 +
} else { return; }
 +
this.setPosition(x,y);
 +
}
 +
};
 +
 
 +
/**
 +
  Sets the x and y coordinates stored and takes appropriate action,
 +
  running hooks as appropriate.
 +
  @param {Integer} x, y Screen coordinates to set
 +
*/
 +
 
 +
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>.
 +
  A half-hearted attempt is made to preserve the old event handler if there is one.
 +
*/
 +
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); }
 +
};
 +
 
 +
/**
 +
  Disables the tracker, removing the event handler.
 +
*/
 +
Mousetracker.prototype.disable = function () {
 +
if (!this.active) { return; }
 +
if ($.isFunction(this.savedHandler)) {
 +
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
 +
  @class The Navpopup class. This generates popup hints, and does some management of them.
 +
*/
 +
function Navpopup(/*init*/) {
 +
//alert('new Navpopup(init)');
 +
/** UID for each Navpopup instance.
 +
Read-only.
 +
@type integer
 +
*/
 +
this.uid=Navpopup.uid++;
 +
/**
 +
  Read-only flag for current visibility of the popup.
 +
  @type boolean
 +
  @private
 +
*/
 +
this.visible=false;
 +
/** Flag to be set when we want to cancel a previous request to
 +
show the popup in a little while.
 +
@private
 +
@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.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.
 +
  @type integer
 +
  @private
 +
*/
 +
Navpopup.uid=0;
 +
 
 +
/**
 +
  Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible.
 +
  @type boolean
 +
*/
 +
Navpopup.prototype.isVisible=function() {
 +
return this.visible;
 +
};
 +
 
 +
/**
 +
  Repositions popup using CSS style.
 +
  @private
 +
  @param {integer} x x-coordinate (px)
 +
  @param {integer} y y-coordinate (px)
 +
  @param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition}
 +
*/
 +
Navpopup.prototype.reposition= function (x,y, noLimitHor) {
 +
log ('reposition('+x+','+y+','+noLimitHor+')');
 +
if (typeof x != 'undefined' && x !== null) { this.left=x; }
 +
if (typeof y != 'undefined' && y !== null) { this.top=y; }
 +
if (typeof this.left != 'undefined' && typeof this.top != 'undefined') {
 +
this.mainDiv.style.left=this.left + 'px';
 +
this.mainDiv.style.top=this.top + 'px';
 +
}
 +
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.
 +
  Should not be run if {@link #constrained} is true.
 +
  @private
 +
*/
 +
Navpopup.prototype.limitHorizontalPosition=function() {
 +
if (!this.constrained || this.tooWide) { return; }
 +
this.updateDimensions();
 +
var x=this.left;
 +
var w=this.width;
 +
var cWidth=document.body.clientWidth;
 +
 
 +
 
 +
// log('limitHorizontalPosition: x='+x+
 +
// ', this.left=' + this.left +
 +
// ', this.width=' + this.width +
 +
// ', 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);
 +
}
 +
};
 +
 
 +
/**
 +
  Counter indicating the z-order of the "highest" popup.
 +
  We start the z-index at 1000 so that popups are above everything
 +
  else on the screen.
 +
  @private
 +
  @type integer
 +
*/
 +
Navpopup.highest=1000;
 +
 
 +
/**
 +
  Brings popup to the top of the z-order.
 +
  We increment the {@link #highest} property of the contructor here.
 +
  @private
 +
*/
 +
Navpopup.prototype.raise = function () {
 +
this.mainDiv.style.zIndex=Navpopup.highest + 1;
 +
++Navpopup.highest;
 +
};
 +
 
 +
/**
 +
  Shows the popup provided {@link #noshow} is not true.
 +
  Updates the position, brings the popup to the top of the z-order and unhides it.
 +
*/
 +
Navpopup.prototype.show = function () {
 +
//document.title+='s';
 +
if (this.noshow) { return; }
 +
//document.title+='t';
 +
this.reposition();
 +
this.raise();
 +
this.unhide();
 +
};
 +
 
 +
/**
 +
  Checks to see if the mouse pointer has
 +
  stabilised (checking every <code>time</code>/2 milliseconds) and runs the
 +
  {@link #show} method if it has.
 +
  @param {integer} time The minimum time (ms) before the popup may be shown.
 +
*/
 +
Navpopup.prototype.showSoonIfStable = function (time) {
 +
log ('showSoonIfStable, time='+time);
 +
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, []);
 +
savedThis.limitHorizontalPosition.apply(savedThis, []);
 +
return;
 +
}
 +
savedThis.stable_x = new_x; savedThis.stable_y = new_y;
 +
};
 +
var savedThis = this;
 +
this.showSoonStableTimer = setInterval(stableShow, time/2);
 +
};
 +
 
 +
/**
 +
  Sets the {@link #noshow} flag and hides the popup. This should be called
 +
  when the mouse leaves the link before
 +
  (or after) it's actually been displayed.
 +
*/
 +
Navpopup.prototype.banish = function () {
 +
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();
 +
};
 +
 
 +
/**
 +
  Runs hooks added with {@link #addHook}.
 +
  @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'
 +
*/
 +
Navpopup.prototype.runHooks = function (key, when) {
 +
if (!this.hooks[key]) { return; }
 +
var keyHooks=this.hooks[key];
 +
var len=keyHooks.length;
 +
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;
 +
}
 +
}
 +
}
 +
};
 +
 
 +
/**
 +
  Adds a hook to the popup. Hook functions are run with <code>this</code> set to refer to the Navpopup instance, and no arguments.
 +
  @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 ) {
 +
when = when || 'after';
 +
if (!this.hooks[key]) { return; }
 +
// if uid is specified, don't add duplicates
 +
var hookId=null;
 +
if (uid) {
 +
hookId=[key,when,uid].join('|');
 +
if (this.hookIds[hookId]) {
 +
return;
 +
}
 +
this.hookIds[hookId]=true;
 +
}
 +
this.hooks[key].push( {hook: hook, when: when, hookId: hookId} );
 +
};
 +
 
 +
/**
 +
  Creates the main DIV element, which contains all the actual popup content.
 +
  Runs hooks with key 'create'.
 +
  @private
 +
*/
 +
Navpopup.prototype.createMainDiv = function () {
 +
if (this.mainDiv) { return; }
 +
this.runHooks('create', 'before');
 +
var mainDiv=document.createElement('div');
 +
 
 +
var savedThis=this;
 +
mainDiv.onclick=function(e) {savedThis.onclickHandler(e);};
 +
mainDiv.className=(this.className) ? this.className : 'navpopup_maindiv';
 +
mainDiv.id=mainDiv.className + this.uid;
 +
 
 +
mainDiv.style.position='absolute';
 +
mainDiv.style.minWidth = '350px';
 +
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;
 +
if (handleName) dragHandle = document.getElementById(handleName);
 +
if (!dragHandle) dragHandle = this.mainDiv;
 +
var np=this;
 +
drag.endHook=function(x,y) {
 +
Navpopup.tracker.dirty=true;
 +
np.reposition(x,y);
 +
};
 +
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 (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');
 +
};
 +
 
 +
/**
 +
  Sets the <code>innerHTML</code> attribute of the main div containing the popup content.
 +
  @param {String} html The HTML to set.
 +
*/
 +
Navpopup.prototype.setInnerHTML = function (html) {
 +
this.mainDiv.innerHTML = html;
 +
};
 +
 
 +
/**
 +
  Updates the {@link #width} and {@link #height} attributes with the CSS properties.
 +
  @private
 +
*/
 +
Navpopup.prototype.updateDimensions = function () {
 +
this.width=parseInt(this.mainDiv.offsetWidth, 10);
 +
this.height=parseInt(this.mainDiv.offsetHeight, 10);
 +
};
 +
 
 +
/**
 +
  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.isWithin = function(x,y) {
 +
//~ 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);
 +
};
 +
 
 +
/**
 +
  Adds a download to {@link #downloads}.
 +
  @param {Downloader} download
 +
*/
 +
Navpopup.prototype.addDownload=function(download) {
 +
if (!download) { return; }
 +
this.downloads.push(download);
 +
};
 +
/**
 +
  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=[];
 +
};
 +
 
 +
 
 +
/**
 +
  A {@link Mousetracker} instance which is a property of the constructor (pseudo-global).
 +
*/
 +
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;
 +
}
 +
 
 +
function shortenDiffString(str, context) {
 +
var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)');
 +
var splitted=str.parenSplit(re);
 +
var ret=[''];
 +
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;
 +
}
 +
 
 +
 
 +
function diffString( o, n, simpleSplit ) {
 +
var splitRe=RegExp('([[]{2}|[\\]]{2}|[{]{2,3}|[}]{2,3}|[|]|=|<|>|[*:]+|\\s|\\b)');
 +
 
 +
//  We need to split the strings o and n first, and entify() the parts
 +
//  individually, so that the HTML entities are never cut apart. (AxelBoldt)
 +
var out, i, oSplitted, nSplitted;
 +
if (simpleSplit) {
 +
oSplitted=o.split(/\b/);
 +
nSplitted=n.split(/\b/);
 +
} else {
 +
oSplitted=o.parenSplit(splitRe);
 +
nSplitted=n.parenSplit(splitRe);
 +
}
 +
for (i=0; i<oSplitted.length; ++i) {oSplitted[i]=oSplitted[i].entify();}
 +
for (i=0; i<nSplitted.length; ++i) {nSplitted[i]=nSplitted[i].entify();}
 +
 +
out = diff (oSplitted, nSplitted);
 +
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; }
 +
}
 +
}
 +
 
 +
// 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] ); }
 +
str += delFmt(acc); acc=[];
 +
 
 +
// main loop
 +
for ( i = 0; i < out.n.length; ++i ) {
 +
// output unpaired new "lines"
 +
while ( i < out.n.length && !out.n[i].paired ) { acc.push( out.n[i++] ); }
 +
str += insFmt(acc); acc=[];
 +
if ( i < out.n.length ) { // this new "line" is paired with the (out.n[i].row)th old "line"
 +
str += out.n[i].text;
 +
// output unpaired old rows starting after this new line's partner
 +
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;
 +
}
 +
 
 +
// see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object
 +
// FIXME: use obj.hasOwnProperty instead of this kludge!
 +
var jsReservedProperties=RegExp('^(constructor|prototype|__((define|lookup)[GS]etter)__' +
 +
  '|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.');
 +
}
 +
}
 +
diffBugAlert.list={};
 +
 
 +
function makeDiffHashtable(src) {
 +
var ret={};
 +
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;
 +
}
 +
 
 +
function diff( o, n ) {
 +
 
 +
// pass 1: make hashtable ns with new rows as keys
 +
var ns = makeDiffHashtable(n);
 +
 
 +
// pass 2: make hashtable os with old rows as keys
 +
var os = makeDiffHashtable(o);
 +
 
 +
// pass 3: pair unique new rows and matching unique old rows
 +
var i;
 +
for ( i in ns ) {
 +
if ( ns[i].length == 1 && os[i] && os[i].length == 1 ) {
 +
n[ ns[i][0] ] = { text: n[ ns[i][0] ], row: os[i][0], paired: true };
 +
o[ os[i][0] ] = { text: o[ os[i][0] ], row: ns[i][0], paired: true };
 +
}
 +
}
 +
 
 +
// 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 ] ) {
 +
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 };
 +
}
 +
}
 +
 
 +
// pass 5: pair matching rows immediately preceding paired rows (not necessarily unique)
 +
for ( i = n.length - 1; i > 0; i-- ) {
 +
if ( n[i].paired && ! n[i-1].paired && n[i].row > 0 && ! 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 };
 +
}
 +
}
 +
 
 +
return { o: o, n: n };
 +
}
 +
//</NOLITE>
 +
// ENDFILE: diff.js
 +
// STARTFILE: init.js
 +
function setSiteInfo() {
 +
if (window.popupLocalDebug) {
 +
pg.wiki.hostname = 'en.wikipedia.org';
 +
} else {
 +
pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?)
 +
}
 +
pg.wiki.wikimedia=RegExp('(wiki([pm]edia|source|books|news|quote|versity)|wiktionary|mediawiki)[.]org').test(pg.wiki.hostname);
 +
pg.wiki.wikia=RegExp('[.]wikia[.]com$', 'i').test(pg.wiki.hostname);
 +
pg.wiki.isLocal=RegExp('^localhost').test(pg.wiki.hostname);
 +
pg.wiki.commons=( pg.wiki.wikimedia && pg.wiki.hostname != 'commons.wikimedia.org') ? 'commons.wikimedia.org' : null;
 +
pg.wiki.lang = mw.config.get('wgContentLanguage');
 +
var port = location.port ? ':' + location.port : '';
 +
pg.wiki.sitebase = pg.wiki.hostname + port;
 +
}
 +
 
 +
function setUserInfo() {
 +
var api = new mw.Api( {
 +
   ajax: {
 +
     headers: { 'Api-User-Agent': pg.misc.userAgent }
 +
   }
 +
} );
 +
var params = {
 +
action: 'query',
 +
list: 'users',
 +
ususers: mw.config.get('wgUserName'),
 +
usprop: 'rights'
 +
};
 +
  
 +
pg.user.canReview = false;
 +
   if (getValueOf('popupReview')) {
 +
api.get(params).done(function(data){
 +
var rights = data.query.users[0].rights;
 +
pg.user.canReview = rights.indexOf('review') !== -1; // TODO: Should it be a getValueOf('ReviewRight') ?
 +
});
 
    }
 
    }
   window.pg = pg;
+
}
   function setupTooltips(container, remove, force, popData) {
+
 
     log("setupTooltips, container=" + container + ", remove=" + remove);
+
function setTitleBase() {
     if (!container) {
+
var protocol = ( window.popupLocalDebug ? 'http:' : location.protocol );
       if (getValueOf("popupOnEditSelection") && document && document.editform && document.editform.wpTextbox1) {
+
pg.wiki.articlePath = mw.config.get('wgArticlePath').replace(/\/\$1/, "");  // as in http://some.thing.com/wiki/Article
         document.editform.wpTextbox1.onmouseup = doSelectionPopup;
+
pg.wiki.botInterfacePath = mw.config.get('wgScript');
       }
+
pg.wiki.APIPath = mw.config.get('wgScriptPath') +"/api.php";
       container = defaultPopupsContainer();
+
// default mediawiki setting is paths like http://some.thing.com/articlePath/index.php?title=foo
     }
+
 
     if (!remove && !force && container.ranSetupTooltipsAlready) {
+
var titletail = pg.wiki.botInterfacePath + '?title=';
       return;
+
//var titletail2 = joinPath([pg.wiki.botInterfacePath, 'wiki.phtml?title=']);
     }
+
 
     container.ranSetupTooltipsAlready = !remove;
+
// other sites may need to add code here to set titletail depending on how their urls work
     var anchors;
+
 
     anchors = container.getElementsByTagName("A");
+
pg.wiki.titlebase  = protocol + '//' + pg.wiki.sitebase + titletail;
     setupTooltipsLoop(anchors, 0, 250, 100, remove, popData);
+
//pg.wiki.titlebase2  = protocol + '//' + joinPath([pg.wiki.sitebase, titletail2]);
   }
+
pg.wiki.wikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.botInterfacePath;
   function defaultPopupsContainer() {
+
pg.wiki.apiwikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.APIPath;
     if (getValueOf("popupOnlyArticleLinks")) {
+
pg.wiki.articlebase = protocol + '//' + pg.wiki.sitebase + pg.wiki.articlePath;
       return document.getElementById("mw_content") || document.getElementById("content") || document.getElementById("article") || document;
+
pg.wiki.commonsbase = protocol + '//' + pg.wiki.commons  + pg.wiki.botInterfacePath;
     }
+
pg.wiki.apicommonsbase = protocol + '//' + pg.wiki.commons  + pg.wiki.APIPath;
     return document;
+
pg.re.basenames = RegExp( '^(' +
   }
+
  map( literalizeRegex, [ pg.wiki.titlebase, //pg.wiki.titlebase2,
   function setupTooltipsLoop(anchors, begin, howmany, sleep, remove, popData) {
+
  pg.wiki.articlebase ]).join('|') + ')' );
     log(simplePrintf("setupTooltipsLoop(%s,%s,%s,%s,%s)", arguments));
+
}
     var finish = begin + howmany;
+
 
     var loopend = Math.min(finish, anchors.length);
+
 
     var j = loopend - begin;
+
//////////////////////////////////////////////////
     log("setupTooltips: anchors.length=" + anchors.length + ", begin=" + begin + ", howmany=" + howmany + ", loopend=" + loopend + ", remove=" + remove);
+
// Global regexps
     var doTooltip = remove ? removeTooltip : addTooltip;
+
 
     if (j > 0) {
+
function setMainRegex() {
       do {
+
var reStart='[^:]*://';
         var a = anchors[loopend - j];
+
var preTitles = literalizeRegex( mw.config.get('wgScriptPath') ) + '/(?:index[.]php|wiki[.]phtml)[?]title=';
         if (typeof a === "undefined" || !a || !a.href) {
+
preTitles += '|' + literalizeRegex( pg.wiki.articlePath + '/' );
           log("got null anchor at index " + loopend - j);
+
 
           continue;
+
var reEnd='(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?';
         }
+
pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd);
         doTooltip(a, popData);
+
}
       } while (--j);
+
 
     }
+
function setRegexps() {
     if (finish < anchors.length) {
+
// TODO: We shoud use an api call to get the aliases for special pages, now it does not work for non-English wikipedias:
       setTimeout(function() {
+
// E.g., https://ru.wikipedia.org/w/api.php?action=query&meta=siteinfo&siprop=specialpagealiases&formatversion=2
         setupTooltipsLoop(anchors, finish, howmany, sleep, remove, popData);
+
setMainRegex();
       }, sleep);
+
var sp=nsRe(pg.nsSpecialId);
     } else {
+
pg.re.urlNoPopup=RegExp('((title=|/)' + sp + '(?:%3A|:)|section=[0-9]|^#$)') ;
       if (!remove && !getValueOf("popupTocLinks")) {
+
pg.re.contribs  =RegExp('(title=|/)'  + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + nsRe(pg.nsUserId)+':)(.*)') ;
         rmTocTooltips();
+
pg.re.email    =RegExp('(title=|/)'  + sp + '(?:%3A|:)EmailUser' + '(&target=|/|/(?:' + nsRe(pg.nsUserId)+':)?)(.*)') ;
       }
+
pg.re.backlinks =RegExp('(title=|/)'  + sp + '(?:%3A|:)WhatLinksHere' + '(&target=|/)([^&]*)');
       pg.flag.finishedLoading = true;
+
pg.re.specialdiff=RegExp('/'      + sp + '(?:%3A|:)Diff/([^?#]*)');
     }
+
 
   }
+
//<NOLITE>
   function rmTocTooltips() {
+
var im=nsReImage();
     var toc = document.getElementById("toc");
+
// note: tries to get images in infobox templates too, e.g. movie pages, album pages etc
     if (toc) {
+
//   (^|\[\[)image: *([^|\]]*[^|\] ]) *
       var tocLinks = toc.getElementsByTagName("A");
+
//   (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)?
       var tocLen = tocLinks.length;
+
// $4 = 120 as in 120px
       for (var j = 0; j < tocLen; ++j) {
+
pg.re.image = RegExp('(^|\\[\\[)' + im + ': *([^|\\]]*[^|\\] ])' +
         removeTooltip(tocLinks[j], true);
+
'([^0-9\\]]*([0-9]+) *px)?|(?:\\n *[|]?|[|]) *' +
       }
+
'(' + getValueOf('popupImageVarsRegexp') + ')' +
     }
+
' *= *(?:\\[\\[ *)?(?:' + im + ':)?' +
   }
+
'([^|]*?)(?:\\]\\])? *[|]? *\\n', 'img') ;
   function addTooltip(a, popData) {
+
pg.re.imageBracketCount = 6;
     if (!isPopupLink(a)) {
+
 
       return;
+
pg.re.category = RegExp('\\[\\[' +nsRe(pg.nsCategoryId) +
     }
+
': *([^|\\]]*[^|\\] ]) *', 'i');
     a.onmouseover = mouseOverWikiLink;
+
pg.re.categoryBracketCount = 1;
     a.onmouseout = mouseOutWikiLink;
+
 
     a.onmousedown = killPopup;
+
pg.re.ipUser=RegExp('^' +
     a.hasPopup = true;
+
// IPv6
     a.popData = popData;
+
'(?::(?::|(?::[0-9A-Fa-f]{1,4}){1,7})|[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){0,6}::|[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){7})' +
   }
+
// IPv4
   function removeTooltip(a) {
+
'|(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' +
     if (!a.hasPopup) {
+
'(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))$');
       return;
+
 
     }
+
pg.re.stub= RegExp(getValueOf('popupStubRegexp'), 'im');
     a.onmouseover = null;
+
pg.re.disambig=RegExp(getValueOf('popupDabRegexp'), 'im');
     a.onmouseout = null;
+
 
     if (a.originalTitle) {
+
//</NOLITE>
       a.title = a.originalTitle;
+
// FIXME replace with general parameter parsing function, this is daft
     }
+
pg.re.oldid=RegExp('[?&]oldid=([^&]*)');
     a.hasPopup = false;
+
pg.re.diff=RegExp('[?&]diff=([^&]*)');
   }
+
}
   function removeTitle(a) {
+
 
     if (!a.originalTitle) {
+
 
       a.originalTitle = a.title;
+
//////////////////////////////////////////////////
     }
+
// miscellany
     a.title = "";
+
 
   }
+
function setupCache() {
   function restoreTitle(a) {
+
// page caching
     if (a.title || !a.originalTitle) {
+
pg.cache.pages = [];
       return;
+
}
     }
+
 
     a.title = a.originalTitle;
+
function setMisc() {
   }
+
pg.current.link=null;
   function registerHooks(np) {
+
pg.current.links=[];
     var popupMaxWidth = getValueOf("popupMaxWidth");
+
pg.current.linksHash={};
     if (typeof popupMaxWidth === "number") {
+
 
       var setMaxWidth = function() {
+
setupCache()
         np.mainDiv.style.maxWidth = popupMaxWidth + "px";
  −
         np.maxWidth = popupMaxWidth;
  −
       };
  −
       np.addHook(setMaxWidth, "unhide", "before");
  −
     }
  −
     np.addHook(addPopupShortcuts, "unhide", "after");
  −
     np.addHook(rmPopupShortcuts, "hide", "before");
  −
   }
  −
   function removeModifierKeyHandler(a) {
  −
     document.removeEventListener("keydown", a.modifierKeyHandler, false);
  −
     document.removeEventListener("keyup", a.modifierKeyHandler, false);
  −
   }
  −
   function mouseOverWikiLink(evt) {
  −
     if (!evt && window.event) {
  −
       evt = window.event;
  −
     }
  −
     if (getValueOf("popupModifier")) {
  −
       var action = getValueOf("popupModifierAction");
  −
       var key = action == "disable" ? "keyup" : "keydown";
  −
       var a = this;
  −
       a.modifierKeyHandler = function(evt) {
  −
         mouseOverWikiLink2(a, evt);
  −
       };
  −
       document.addEventListener(key, a.modifierKeyHandler, false);
  −
     }
  −
     return mouseOverWikiLink2(this, evt);
  −
   }
  −
   function footnoteTarget(a) {
  −
     var aTitle = Title.fromAnchor(a);
  −
     var anch = aTitle.anchor;
  −
     if (!/^(cite_note-|_note-|endnote)/.test(anch)) {
  −
       return false;
  −
     }
  −
     var lTitle = Title.fromURL(location.href);
  −
     if (lTitle.toString(true) !== aTitle.toString(true)) {
  −
       return false;
  −
     }
  −
     var el = document.getElementById(anch);
  −
     while (el && typeof el.nodeName === "string") {
  −
       var nt = el.nodeName.toLowerCase();
  −
       if (nt === "li") {
  −
         return el;
  −
       } else if (nt === "body") {
  −
         return false;
  −
       } else if (el.parentNode) {
  −
         el = el.parentNode;
  −
       } else {
  −
         return false;
  −
       }
  −
     }
  −
     return false;
  −
   }
  −
   function footnotePreview(x, navpop) {
  −
     setPopupHTML("<hr />" + x.innerHTML, "popupPreview", navpop.idNumber);
  −
   }
  −
   function modifierPressed(evt) {
  −
     var mod = getValueOf("popupModifier");
  −
     if (!mod) {
  −
       return false;
  −
     }
  −
     if (!evt && window.event) {
  −
       evt = window.event;
  −
     }
  −
     return evt && mod && evt[mod.toLowerCase() + "Key"];
  −
   }
  −
   function isCorrectModifier(a, evt) {
  −
     if (!getValueOf("popupModifier")) {
  −
       return true;
  −
     }
  −
     var action = getValueOf("popupModifierAction");
  −
     return action == "enable" && modifierPressed(evt) || action == "disable" && !modifierPressed(evt);
  −
   }
  −
   function mouseOverWikiLink2(a, evt) {
  −
     if (!isCorrectModifier(a, evt)) {
  −
       return;
  −
     }
  −
     if (getValueOf("removeTitles")) {
  −
       removeTitle(a);
  −
     }
  −
     if (a == pg.current.link && a.navpopup && a.navpopup.isVisible()) {
  −
       return;
  −
     }
  −
     pg.current.link = a;
  −
     if (getValueOf("simplePopups") && !pg.option.popupStructure) {
  −
       setDefault("popupStructure", "original");
  −
     }
  −
     var article = new Title().fromAnchor(a);
  −
     pg.current.article = article;
  −
     if (!a.navpopup) {
  −
       a.navpopup = newNavpopup(a, article);
  −
       pg.current.linksHash[a.href] = a.navpopup;
  −
       pg.current.links.push(a);
  −
     }
  −
     if (a.navpopup.pending === null || a.navpopup.pending !== 0) {
  −
       simplePopupContent(a, article);
  −
     }
  −
     a.navpopup.showSoonIfStable(a.navpopup.delay);
  −
     clearInterval(pg.timer.checkPopupPosition);
  −
     pg.timer.checkPopupPosition = setInterval(checkPopupPosition, 600);
  −
     if (getValueOf("simplePopups")) {
  −
       if (getValueOf("popupPreviewButton") && !a.simpleNoMore) {
  −
         var d = document.createElement("div");
  −
         d.className = "popupPreviewButtonDiv";
  −
         var s = document.createElement("span");
  −
         d.appendChild(s);
  −
         s.className = "popupPreviewButton";
  −
         s["on" + getValueOf("popupPreviewButtonEvent")] = function() {
  −
           a.simpleNoMore = true;
  −
           d.style.display = "none";
  −
           nonsimplePopupContent(a, article);
  −
         };
  −
         s.innerHTML = popupString("show preview");
  −
         setPopupHTML(d, "popupPreview", a.navpopup.idNumber);
  −
       }
  −
     }
  −
     if (a.navpopup.pending !== 0) {
  −
       nonsimplePopupContent(a, article);
  −
     }
  −
   }
  −
   function simplePopupContent(a, article) {
  −
     a.navpopup.hasPopupMenu = false;
  −
     a.navpopup.setInnerHTML(popupHTML(a));
  −
     fillEmptySpans({
  −
       navpopup: a.navpopup
  −
     });
  −
     if (getValueOf("popupDraggable")) {
  −
       var dragHandle = getValueOf("popupDragHandle") || null;
  −
       if (dragHandle && dragHandle != "all") {
  −
         dragHandle += a.navpopup.idNumber;
  −
       }
  −
       setTimeout(function() {
  −
         a.navpopup.makeDraggable(dragHandle);
  −
       }, 150);
  −
     }
  −
     if (getValueOf("popupRedlinkRemoval") && a.className == "new") {
  −
       setPopupHTML("<br>" + popupRedlinkHTML(article), "popupRedlink", a.navpopup.idNumber);
  −
     }
  −
   }
  −
   function debugData(navpopup) {
  −
     if (getValueOf("popupDebugging") && navpopup.idNumber) {
  −
       setPopupHTML("idNumber=" + navpopup.idNumber + ", pending=" + navpopup.pending, "popupError", navpopup.idNumber);
  −
     }
  −
   }
  −
   function newNavpopup(a, article) {
  −
     var navpopup = new Navpopup();
  −
     navpopup.fuzz = 5;
  −
     navpopup.delay = getValueOf("popupDelay") * 1e3;
  −
     navpopup.idNumber = ++pg.idNumber;
  −
     navpopup.parentAnchor = a;
  −
     navpopup.parentPopup = a.popData && a.popData.owner;
  −
     navpopup.article = article;
  −
     registerHooks(navpopup);
  −
     return navpopup;
  −
   }
  −
   function shouldShowNonSimple(a) {
  −
     return !getValueOf("simplePopups") || a.simpleNoMore;
  −
   }
  −
   function shouldShow(a, option) {
  −
     if (shouldShowNonSimple(a)) {
  −
       return getValueOf(option);
  −
     } else {
  −
       return typeof window[option] != "undefined" && window[option];
  −
     }
  −
   }
  −
   function nonsimplePopupContent(a, article) {
  −
     var diff = null,
  −
       history = null;
  −
     var params = parseParams(a.href);
  −
     var oldid = typeof params.oldid == "undefined" ? null : params.oldid;
  −
     if (shouldShow(a, "popupPreviewDiffs")) {
  −
       diff = params.diff;
  −
     }
  −
     if (shouldShow(a, "popupPreviewHistory")) {
  −
       history = params.action == "history";
  −
     }
  −
     a.navpopup.pending = 0;
  −
     var referenceElement = footnoteTarget(a);
  −
     if (referenceElement) {
  −
       footnotePreview(referenceElement, a.navpopup);
  −
     } else if (diff || diff === 0) {
  −
       loadDiff(article, oldid, diff, a.navpopup);
  −
     } else if (history) {
  −
       loadAPIPreview("history", article, a.navpopup);
  −
     } else if (shouldShowNonSimple(a) && pg.re.contribs.test(a.href)) {
  −
       loadAPIPreview("contribs", article, a.navpopup);
  −
     } else if (shouldShowNonSimple(a) && pg.re.backlinks.test(a.href)) {
  −
       loadAPIPreview("backlinks", article, a.navpopup);
  −
     } else if (article.namespaceId() == pg.nsImageId && (shouldShow(a, "imagePopupsForImages") || !anchorContainsImage(a))) {
  −
       loadAPIPreview("imagepagepreview", article, a.navpopup);
  −
       loadImage(article, a.navpopup);
  −
     } else {
  −
       if (article.namespaceId() == pg.nsCategoryId && shouldShow(a, "popupCategoryMembers")) {
  −
         loadAPIPreview("category", article, a.navpopup);
  −
       } else if ((article.namespaceId() == pg.nsUserId || article.namespaceId() == pg.nsUsertalkId) && shouldShow(a, "popupUserInfo")) {
  −
         loadAPIPreview("userinfo", article, a.navpopup);
  −
       }
  −
       if (shouldShowNonSimple(a)) startArticlePreview(article, oldid, a.navpopup);
  −
     }
  −
   }
  −
   function pendingNavpopTask(navpop) {
  −
     if (navpop && navpop.pending === null) {
  −
       navpop.pending = 0;
  −
     }
  −
     ++navpop.pending;
  −
     debugData(navpop);
  −
   }
  −
   function completedNavpopTask(navpop) {
  −
     if (navpop && navpop.pending) {
  −
       --navpop.pending;
  −
     }
  −
     debugData(navpop);
  −
   }
  −
   function startArticlePreview(article, oldid, navpop) {
  −
     navpop.redir = 0;
  −
     loadPreview(article, oldid, navpop);
  −
   }
  −
   function loadPreview(article, oldid, navpop) {
  −
     if (!navpop.redir) {
  −
       navpop.originalArticle = article;
  −
     }
  −
     article.oldid = oldid;
  −
     loadAPIPreview("revision", article, navpop);
  −
   }
  −
   function loadPreviewFromRedir(redirMatch, navpop) {
  −
     var target = new Title().fromWikiText(redirMatch[2]);
  −
     if (navpop.article.anchor) {
  −
       target.anchor = navpop.article.anchor;
  −
     }
  −
     navpop.redir++;
  −
     navpop.redirTarget = target;
  −
     var warnRedir = redirLink(target, navpop.article);
  −
     setPopupHTML(warnRedir, "popupWarnRedir", navpop.idNumber);
  −
     navpop.article = target;
  −
     fillEmptySpans({
  −
       redir: true,
  −
       redirTarget: target,
  −
       navpopup: navpop
  −
     });
  −
     return loadPreview(target, null, navpop);
  −
   }
  −
   function insertPreview(download) {
  −
     if (!download.owner) {
  −
       return;
  −
     }
  −
     var redirMatch = pg.re.redirect.exec(download.data);
  −
     if (download.owner.redir === 0 && redirMatch) {
  −
       loadPreviewFromRedir(redirMatch, download.owner);
  −
       return;
  −
     }
  −
     if (download.owner.visible || !getValueOf("popupLazyPreviews")) {
  −
       insertPreviewNow(download);
  −
     } else {
  −
       var id = download.owner.redir ? "PREVIEW_REDIR_HOOK" : "PREVIEW_HOOK";
  −
       download.owner.addHook(function() {
  −
         insertPreviewNow(download);
  −
         return true;
  −
       }, "unhide", "after", id);
  −
     }
  −
   }
  −
   function insertPreviewNow(download) {
  −
     if (!download.owner) {
  −
       return;
  −
     }
  −
     var wikiText = download.data;
  −
     var navpop = download.owner;
  −
     var art = navpop.redirTarget || navpop.originalArticle;
  −
     makeFixDabs(wikiText, navpop);
  −
     if (getValueOf("popupSummaryData")) {
  −
       getPageInfo(wikiText, download);
  −
       setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber);
  −
     }
  −
     var imagePage = "";
  −
     if (art.namespaceId() == pg.nsImageId) {
  −
       imagePage = art.toString();
  −
     } else {
  −
       imagePage = getValidImageFromWikiText(wikiText);
  −
     }
  −
     if (imagePage) {
  −
       loadImage(Title.fromWikiText(imagePage), navpop);
  −
     }
  −
     if (getValueOf("popupPreviews")) {
  −
       insertArticlePreview(download, art, navpop);
  −
     }
  −
   }
  −
   function insertArticlePreview(download, art, navpop) {
  −
     if (download && typeof download.data == typeof "") {
  −
       if (art.namespaceId() == pg.nsTemplateId && getValueOf("popupPreviewRawTemplates")) {
  −
         var h = '<hr /><span style="font-family: monospace;">' + download.data.entify().split("\\n").join("<br />\\n") + "</span>";
  −
         setPopupHTML(h, "popupPreview", navpop.idNumber);
  −
       } else {
  −
         var p = prepPreviewmaker(download.data, art, navpop);
  −
         p.showPreview();
  −
       }
  −
     }
  −
   }
  −
   function prepPreviewmaker(data, article, navpop) {
  −
     var d = anchorize(data, article.anchorString());
  −
     var urlBase = joinPath([pg.wiki.articlebase, article.urlString()]);
  −
     var p = new Previewmaker(d, urlBase, navpop);
  −
     return p;
  −
   }
  −
   function anchorize(d, anch) {
  −
     if (!anch) {
  −
       return d;
  −
     }
  −
     var anchRe = RegExp("(?:=+\\s*" + literalizeRegex(anch).replace(/[_ ]/g, "[_ ]") + "\\s*=+|\\{\\{\\s*" + getValueOf("popupAnchorRegexp") + "\\s*(?:\\|[^|}]*)*?\\s*" + literalizeRegex(anch) + "\\s*(?:\\|[^}]*)?}})");
  −
     var match = d.match(anchRe);
  −
     if (match && match.length > 0 && match[0]) {
  −
       return d.substring(d.indexOf(match[0]));
  −
     }
  −
     var lines = d.split("\n");
  −
     for (var i = 0; i < lines.length; ++i) {
  −
       lines[i] = lines[i].replace(RegExp("[[]{2}([^|\\]]*?[|])?(.*?)[\\]]{2}", "g"), "$2").replace(/'''([^'])/g, "$1").replace(RegExp("''([^'])", "g"), "$1");
  −
       if (lines[i].match(anchRe)) {
  −
         return d.split("\n").slice(i).join("\n").replace(RegExp("^[^=]*"), "");
  −
       }
  −
     }
  −
     return d;
  −
   }
  −
   function killPopup() {
  −
     removeModifierKeyHandler(this);
  −
     if (getValueOf("popupShortcutKeys")) {
  −
       rmPopupShortcuts();
  −
     }
  −
     if (!pg) {
  −
       return;
  −
     }
  −
     if (pg.current.link && pg.current.link.navpopup) {
  −
       pg.current.link.navpopup.banish();
  −
     }
  −
     pg.current.link = null;
  −
     abortAllDownloads();
  −
     if (pg.timer.checkPopupPosition) {
  −
       clearInterval(pg.timer.checkPopupPosition);
  −
       pg.timer.checkPopupPosition = null;
  −
     }
  −
     return true;
  −
   }
  −
   function Drag() {
  −
     this.startCondition = null;
  −
     this.endHook = null;
  −
   }
  −
   Drag.prototype.fixE = function(e) {
  −
     if (typeof e == "undefined") {
  −
       e = window.event;
  −
     }
  −
     if (typeof e.layerX == "undefined") {
  −
       e.layerX = e.offsetX;
  −
     }
  −
     if (typeof e.layerY == "undefined") {
  −
       e.layerY = e.offsetY;
  −
     }
  −
     return e;
  −
   };
  −
   Drag.prototype.init = function(o, oRoot) {
  −
     var dragObj = this;
  −
     this.obj = o;
  −
     o.onmousedown = function(e) {
  −
       dragObj.start.apply(dragObj, [e]);
  −
     };
  −
     o.dragging = false;
  −
     o.popups_draggable = true;
  −
     o.hmode = true;
  −
     o.vmode = true;
  −
     o.root = oRoot ? oRoot : o;
  −
     if (isNaN(parseInt(o.root.style.left, 10))) {
  −
       o.root.style.left = "0px";
  −
     }
  −
     if (isNaN(parseInt(o.root.style.top, 10))) {
  −
       o.root.style.top = "0px";
  −
     }
  −
     o.root.onthisStart = function() {};
  −
     o.root.onthisEnd = function() {};
  −
     o.root.onthis = function() {};
  −
   };
  −
   Drag.prototype.start = function(e) {
  −
     var o = this.obj;
  −
     e = this.fixE(e);
  −
     if (this.startCondition && !this.startCondition(e)) {
  −
       return;
  −
     }
  −
     var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10);
  −
     var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10);
  −
     o.root.onthisStart(x, y);
  −
     o.lastMouseX = e.clientX;
  −
     o.lastMouseY = e.clientY;
  −
     var dragObj = this;
  −
     o.onmousemoveDefault = document.onmousemove;
  −
     o.dragging = true;
  −
     document.onmousemove = function(e) {
  −
       dragObj.drag.apply(dragObj, [e]);
  −
     };
  −
     document.onmouseup = function(e) {
  −
       dragObj.end.apply(dragObj, [e]);
  −
     };
  −
     return false;
  −
   };
  −
   Drag.prototype.drag = function(e) {
  −
     e = this.fixE(e);
  −
     var o = this.obj;
  −
     var ey = e.clientY;
  −
     var ex = e.clientX;
  −
     var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10);
  −
     var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10);
  −
     var nx, ny;
  −
     nx = x + (ex - o.lastMouseX) * (o.hmode ? 1 : -1);
  −
     ny = y + (ey - o.lastMouseY) * (o.vmode ? 1 : -1);
  −
     this.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
  −
     this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
  −
     this.obj.lastMouseX = ex;
  −
     this.obj.lastMouseY = ey;
  −
     this.obj.root.onthis(nx, ny);
  −
     return false;
  −
   };
  −
   Drag.prototype.end = function() {
  −
     document.onmousemove = this.obj.onmousemoveDefault;
  −
     document.onmouseup = null;
  −
     this.obj.dragging = false;
  −
     if (this.endHook) {
  −
       this.endHook(parseInt(this.obj.root.style[this.obj.hmode ? "left" : "right"], 10), parseInt(this.obj.root.style[this.obj.vmode ? "top" : "bottom"], 10));
  −
     }
  −
   };
  −
   pg.structures.original = {};
  −
   pg.structures.original.popupLayout = function() {
  −
     return ["popupError", "popupImage", "popupTopLinks", "popupTitle", "popupUserData", "popupData", "popupOtherLinks", "popupRedir", ["popupWarnRedir", "popupRedirTopLinks", "popupRedirTitle", "popupRedirData", "popupRedirOtherLinks"], "popupMiscTools", ["popupRedlink"], "popupPrePreviewSep", "popupPreview", "popupSecondPreview", "popupPreviewMore", "popupPostPreview", "popupFixDab"];
  −
   };
  −
   pg.structures.original.popupRedirSpans = function() {
  −
     return ["popupRedir", "popupWarnRedir", "popupRedirTopLinks", "popupRedirTitle", "popupRedirData", "popupRedirOtherLinks"];
  −
   };
  −
   pg.structures.original.popupTitle = function(x) {
  −
     log("defaultstructure.popupTitle");
  −
     if (!getValueOf("popupNavLinks")) {
  −
       return navlinkStringToHTML("<b><<mainlink>></b>", x.article, x.params);
  −
     }
  −
     return "";
  −
   };
  −
   pg.structures.original.popupTopLinks = function(x) {
  −
     log("defaultstructure.popupTopLinks");
  −
     if (getValueOf("popupNavLinks")) {
  −
       return navLinksHTML(x.article, x.hint, x.params);
  −
     }
  −
     return "";
  −
   };
  −
   pg.structures.original.popupImage = function(x) {
  −
     log("original.popupImage, x.article=" + x.article + ", x.navpop.idNumber=" + x.navpop.idNumber);
  −
     return imageHTML(x.article, x.navpop.idNumber);
  −
   };
  −
   pg.structures.original.popupRedirTitle = pg.structures.original.popupTitle;
  −
   pg.structures.original.popupRedirTopLinks = pg.structures.original.popupTopLinks;
  −
   function copyStructure(oldStructure, newStructure) {
  −
     pg.structures[newStructure] = {};
  −
     for (var prop in pg.structures[oldStructure]) {
  −
       pg.structures[newStructure][prop] = pg.structures[oldStructure][prop];
  −
     }
  −
   }
  −
   copyStructure("original", "nostalgia");
  −
   pg.structures.nostalgia.popupTopLinks = function(x) {
  −
     var str = "";
  −
     str += "<b><<mainlink|shortcut= >></b>";
  −
     str += "if(user){<br><<contribs|shortcut=c>>";
  −
     str += "if(wikimedia){
   
});
 
});
 +
// ENDFILE: run.js

導覽選單