MediaWiki:Gadget-popups.js and MediaWiki talk:Gadget-popups.js/sandbox: Difference between pages
(Difference between pages)
Content deleted Content added
changed my mind. this has @file so should be /** |
disable category in comment |
||
Line 14: | Line 14: | ||
// ** ** |
// ** ** |
||
// ********************************************************************** |
// ********************************************************************** |
||
/* eslint-env browser */ |
|||
/* global $, jQuery, mw, window */ |
|||
// Fix later |
|||
/* global log, errlog, popupStrings, wikEdUseWikEd, WikEdUpdateFrame */ |
|||
$(function () { |
$(function () { |
||
////////////////////////////////////////////////// |
|||
// Globals |
|||
// |
|||
// Trying to shove as many of these as possible into the pg (popup globals) object |
|||
var pg = { |
|||
re: {}, // regexps |
|||
api: {}, // MediaWiki API requests |
|||
ns: {}, // namespaces |
|||
string: {}, // translatable strings |
|||
ns: {}, // namespaces |
|||
wiki: {}, // local site info |
|||
misc: {}, // YUCK PHOOEY |
|||
option: {}, // options, see newOption etc |
|||
optionDefault: {}, // default option values |
|||
flag: {}, // misc flags |
|||
option: {}, // options, see newOption etc |
|||
cache: {}, // page and image cache |
|||
optionDefault: {}, // default option values |
|||
structures: {}, // navlink structures |
|||
timer: {}, // all sorts of timers (too damn many) |
|||
cache: {}, // page and image cache |
|||
counter: {}, // .. and all sorts of counters |
|||
structures: {}, // navlink structures |
|||
current: {}, // state info |
|||
fn: {}, // functions |
|||
endoflist: null |
|||
current: {}, // state info |
|||
}; |
|||
fn: {}, // functions |
|||
var pop = { // wrap various functions in here |
|||
endoflist: null, |
|||
init: {}, |
|||
}; |
|||
util: {}, |
|||
endoflist: null |
|||
}; |
|||
/* Export to global context */ |
|||
window.pg = pg; |
|||
function popupsReady() { |
|||
/* Bail if the gadget/script is being loaded twice */ |
|||
if (!pg.flag) { return false; } |
|||
/* An element with id "pg" would add a window.pg property, ignore such property */ |
|||
if (!pg.flag.finishedLoading) { return false; } |
|||
if (window.pg && !(window.pg instanceof HTMLElement)) { |
|||
return true; |
|||
} |
|||
/// Local Variables: /// |
|||
/// mode:c /// |
|||
/// End: /// |
|||
// ENDFILE: main.js |
|||
// STARTFILE: actions.js |
|||
function setupTooltips(container, remove, force, popData) { |
|||
log('setupTooltips, container='+container+', remove='+remove); |
|||
if (!container) { |
|||
//<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; } |
|||
/* Export to global context */ |
|||
container.ranSetupTooltipsAlready = !remove; |
|||
window.pg = pg; |
|||
var anchors; |
|||
/// Local Variables: /// |
|||
anchors=container.getElementsByTagName('A'); |
|||
/// mode:c /// |
|||
setupTooltipsLoop(anchors, 0, 250, 100, remove, popData); |
|||
/// End: /// |
|||
} |
|||
// ENDFILE: main.js |
|||
function defaultPopupsContainer() { |
|||
// STARTFILE: actions.js |
|||
if (getValueOf('popupOnlyArticleLinks')) { |
|||
function setupTooltips(container, remove, force, popData) { |
|||
return document.getElementById('mw_content') || |
|||
log('setupTooltips, container=' + container + ', remove=' + remove); |
|||
document.getElementById('content') || |
|||
if (!container) { |
|||
document.getElementById('article') || document; |
|||
// the main initial call |
|||
} |
|||
if ( |
|||
return document; |
|||
getValueOf('popupOnEditSelection') && |
|||
} |
|||
document && |
|||
document.editform && |
|||
function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) { |
|||
document.editform.wpTextbox1 |
|||
log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments)); |
|||
) { |
|||
var finish=begin+howmany; |
|||
document.editform.wpTextbox1.onmouseup = doSelectionPopup; |
|||
var loopend = min(finish, anchors.length); |
|||
var j=loopend - begin; |
|||
log ('setupTooltips: anchors.length=' + anchors.length + ', begin=' + begin + |
|||
', howmany=' + howmany + ', loopend=' + loopend + ', remove=' + remove); |
|||
var doTooltip= remove ? removeTooltip : addTooltip; |
|||
// try a faster (?) loop construct |
|||
if (j > 0) { |
|||
do { |
|||
var a=anchors[loopend - j]; |
|||
if (typeof a==='undefined' || !a || !a.href) { |
|||
log('got null anchor at index ' + loopend - j); |
|||
continue; |
|||
} |
} |
||
doTooltip(a, popData); |
|||
// article/content is a structure-dependent thing |
|||
} while (--j); |
|||
container = defaultPopupsContainer(); |
|||
} |
|||
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 |
|||
if (!remove && !force && container.ranSetupTooltipsAlready) { |
|||
// This also kills any onclick stuff that used to be going on in the toc |
|||
return; |
|||
function rmTocTooltips() { |
|||
var toc=document.getElementById('toc'); |
|||
if (toc) { |
|||
var tocLinks=toc.getElementsByTagName('A'); |
|||
var tocLen = tocLinks.length; |
|||
for (j=0; j<tocLen; ++j) { |
|||
removeTooltip(tocLinks[j], true); |
|||
} |
} |
||
container.ranSetupTooltipsAlready = !remove; |
|||
var anchors; |
|||
anchors = container.getElementsByTagName('A'); |
|||
setupTooltipsLoop(anchors, 0, 250, 100, remove, popData); |
|||
} |
} |
||
} |
|||
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) { |
|||
if (getValueOf('popupOnlyArticleLinks')) { |
|||
a.originalTitle=a.title; |
|||
return ( |
|||
document.querySelector('.skin-vector-2022 .vector-body') || |
|||
document.getElementById('mw_content') || |
|||
document.getElementById('content') || |
|||
document.getElementById('article') || |
|||
document |
|||
); |
|||
} |
|||
return document; |
|||
} |
} |
||
a.title=''; |
|||
} |
|||
function restoreTitle(a) { |
|||
if ( a.title || !a.originalTitle ) { return; } |
|||
a.title = a.originalTitle; |
|||
} |
|||
function registerHooks(np) { |
|||
function setupTooltipsLoop(anchors, begin, howmany, sleep, remove, popData) { |
|||
var popupMaxWidth=getValueOf('popupMaxWidth'); |
|||
log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments)); |
|||
var finish = begin + howmany; |
|||
if (typeof popupMaxWidth === 'number') { |
|||
var loopend = Math.min(finish, anchors.length); |
|||
var |
var setMaxWidth = function () { |
||
np.mainDiv.style.maxWidth = popupMaxWidth + 'px'; |
|||
log( |
|||
np.maxWidth = popupMaxWidth; |
|||
'setupTooltips: anchors.length=' + |
|||
anchors.length + |
|||
try { |
|||
// hack for IE |
|||
// see http://www.svendtofte.com/code/max_width_in_ie/ |
|||
', howmany=' + |
|||
// use setExpression as documented here on msdn: http://tinyurl dot com/dqljn |
|||
howmany + |
|||
', loopend=' + |
|||
if (np.mainDiv.style.setExpression) { |
|||
loopend + |
|||
np.mainDiv.style.setExpression( |
|||
', remove=' + |
|||
'width', 'document.body.clientWidth > ' + |
|||
remove |
|||
popupMaxWidth + ' ? "' +popupMaxWidth + 'px": "auto"'); |
|||
); |
|||
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(); |
|||
} |
} |
||
catch (errors) { |
|||
pg.flag.finishedLoading = true; |
|||
errlog( "Running on IE8 are we not?: " + errors ); |
|||
} |
|||
} |
|||
// 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); |
|||
} |
} |
||
} |
}; |
||
np.addHook(setMaxWidth, 'unhide', 'before'); |
|||
} |
} |
||
//<NOLITE> |
|||
np.addHook(addPopupShortcuts, 'unhide', 'after'); |
|||
np.addHook(rmPopupShortcuts, 'hide', 'before'); |
|||
//</NOLITE> |
|||
} |
|||
function addTooltip(a, popData) { |
|||
if (!isPopupLink(a)) { |
|||
return; |
|||
} |
|||
a.onmouseover = mouseOverWikiLink; |
|||
a.onmouseout = mouseOutWikiLink; |
|||
a.onmousedown = killPopup; |
|||
a.hasPopup = true; |
|||
a.popData = popData; |
|||
} |
|||
function mouseOverWikiLink(evt) { |
|||
if (!evt && window.event) {evt=window.event;} |
|||
if (!a.hasPopup) { |
|||
return mouseOverWikiLink2(this, evt); |
|||
return; |
|||
} |
|||
a.onmouseover = null; |
|||
a.onmouseout = null; |
|||
if (a.originalTitle) { |
|||
a.title = a.originalTitle; |
|||
} |
|||
a.hasPopup = false; |
|||
} |
|||
/** |
|||
function removeTitle(a) { |
|||
* Gets the references list item that the provided footnote link targets. This |
|||
if (!a.originalTitle) { |
|||
* is typically a li element within the ol.references element inside the reflist. |
|||
a.originalTitle = a.title; |
|||
* @param {Element} a - A footnote link. |
|||
} |
|||
* @returns {Element|boolean} The targeted element, or false if one can't be found. |
|||
a.title = ''; |
|||
*/ |
|||
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); |
|||
function restoreTitle(a) { |
|||
if ( lTitle.toString(true) !== aTitle.toString(true) ) { return false; } |
|||
if (a.title || !a.originalTitle) { |
|||
return; |
|||
var el=document.getElementById(anch); |
|||
} |
|||
while ( el && typeof el.nodeName === 'string') { |
|||
a.title = a.originalTitle; |
|||
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); |
|||
var popupMaxWidth = getValueOf('popupMaxWidth'); |
|||
} |
|||
// var modid=0; |
|||
if (typeof popupMaxWidth === 'number') { |
|||
// if(!window.opera) { window.opera={postError: console.log}; } |
|||
var setMaxWidth = function () { |
|||
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 modifierKeyHandler(a) { |
|||
return function(evt) { |
|||
//remove listeners for modifier key if any that were added in mouseOverWikiLink |
|||
// opera.postError('modifierKeyHandler called' + (++modid)); |
|||
document.removeEventListener('keydown', a.modifierKeyHandler, false); |
|||
// opera.postError(''+evt + modid); |
|||
document.removeEventListener('keyup', a.modifierKeyHandler, false); |
|||
// for (var i in evt) { |
|||
} |
|||
// opera.postError('' + modid + ' ' + i + ' ' + evt[i]); |
|||
// } |
|||
// opera.postError(''+evt.ctrlKey + modid); |
|||
var mod=getValueOf('popupModifier'); |
|||
if (!mod) { return true; } |
|||
if (!evt && window.event) {evt=window.event;} |
|||
function mouseOverWikiLink(evt) { |
|||
// opera.postError('And now....'+modid); |
|||
if (!evt && window.event) { |
|||
// opera.postError(''+evt+modid); |
|||
evt = window.event; |
|||
// opera.postError(''+evt.ctrlKey+modid); |
|||
} |
|||
var modPressed = modifierPressed(evt); |
|||
// if the modifier is needed, listen for it, |
|||
var action = getValueOf('popupModifierAction'); |
|||
// 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); |
|||
} |
|||
// FIXME: probable bug - modifierPressed should be modPressed below? |
|||
return mouseOverWikiLink2(this, evt); |
|||
if ( action === 'disable' && modifierPressed ) { return true; } |
|||
} |
|||
if ( action === 'enable' && !modifierPressed ) { return true; } |
|||
mouseOverWikiLink2(a, 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. |
|||
* @return {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; |
|||
} |
|||
function modifierPressed(evt) { |
|||
var lTitle = Title.fromURL(location.href); |
|||
var mod=getValueOf('popupModifier'); |
|||
if (lTitle.toString(true) !== aTitle.toString(true)) { |
|||
if (!mod) { return false; } |
|||
} |
|||
if (!evt && window.event) {evt=window.event;} |
|||
var el = document.getElementById(anch); |
|||
// opera.postError('And now....'+modid); |
|||
while (el && typeof el.nodeName === 'string') { |
|||
// opera.postError(''+evt+modid); |
|||
var nt = el.nodeName.toLowerCase(); |
|||
// opera.postError(''+evt.ctrlKey+modid); |
|||
if (nt === 'li') { |
|||
return el; |
|||
} else if (nt === 'body') { |
|||
return false; |
|||
} else if (el.parentNode) { |
|||
el = el.parentNode; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
return ( evt && mod && evt[mod.toLowerCase() + 'Key'] ); |
|||
function footnotePreview(x, navpop) { |
|||
setPopupHTML('<hr />' + x.innerHTML, 'popupPreview', navpop.idNumber); |
|||
} |
|||
function dealWithModifier(a,evt) { |
|||
if (!getValueOf('popupModifier')) { return false; } |
|||
var action = getValueOf('popupModifierAction'); |
|||
if (!mod) { |
|||
if ( action == 'enable' && !modifierPressed(evt) || |
|||
return false; |
|||
action == 'disable' && modifierPressed(evt) ) { |
|||
// if the modifier is needed and not pressed, listen for it until |
|||
// we mouseout of this link. |
|||
restoreTitle(a); |
|||
var addHandler='addEventListener'; |
|||
var rmHandler='removeEventListener'; |
|||
var on=''; |
|||
if (!document.addEventListener) { |
|||
addHandler='attachEvent'; |
|||
rmHandler='detachEvent'; |
|||
on='on'; |
|||
} |
|||
if (!document[addHandler]) { // forget it |
|||
return; |
|||
} |
} |
||
a.modifierKeyHandler=modifierKeyHandler(a); |
|||
if (!evt && window.event) { |
|||
evt = window.event; |
|||
switch (action) { |
|||
case 'enable': |
|||
document[addHandler](on+'keydown', a.modifierKeyHandler, false); |
|||
a[addHandler](on+'mouseout', function() { |
|||
document[rmHandler](on+'keydown', |
|||
a.modifierKeyHandler, false); |
|||
}, true); |
|||
break; |
|||
case 'disable': |
|||
document[addHandler](on+'keyup', a.modifierKeyHandler, false); |
|||
} |
} |
||
return true; |
|||
return evt && mod && evt[mod.toLowerCase() + 'Key']; |
|||
} |
} |
||
return false; |
|||
} |
|||
function mouseOverWikiLink2(a, evt) { |
|||
// Checks if the correct modifier pressed/unpressed if needed |
|||
if (dealWithModifier(a,evt)) { return; } |
|||
if ( getValueOf('removeTitles') ) { removeTitle(a); } |
|||
if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; } |
|||
return true; |
|||
pg.current.link=a; |
|||
} |
|||
// if popupModifierAction = enable, we should popup when the modifier is pressed |
|||
if (getValueOf('simplePopups') && pg.option.popupStructure === null) { |
|||
// if popupModifierAction = disable, we should popup unless the modifier is pressed |
|||
// reset *default value* of popupStructure |
|||
var action = getValueOf('popupModifierAction'); |
|||
setDefault('popupStructure', 'original'); |
|||
return ( |
|||
(action == 'enable' && modifierPressed(evt)) || (action == 'disable' && !modifierPressed(evt)) |
|||
); |
|||
} |
} |
||
var article=(new Title()).fromAnchor(a); |
|||
function mouseOverWikiLink2(a, evt) { |
|||
// set global variable (ugh) to hold article (wikipage) |
|||
if (!isCorrectModifier(a, evt)) { |
|||
pg.current.article = article; |
|||
return; |
|||
} |
|||
if (getValueOf('removeTitles')) { |
|||
removeTitle(a); |
|||
} |
|||
if (a == pg.current.link && a.navpopup && a.navpopup.isVisible()) { |
|||
return; |
|||
} |
|||
pg.current.link = a; |
|||
if (!a.navpopup) { |
|||
if (getValueOf('simplePopups') && !pg.option.popupStructure) { |
|||
// FIXME: this doesn't behave well if you mouse out of a popup |
|||
// reset *default value* of popupStructure |
|||
// directly into a link with the same href |
|||
setDefault('popupStructure', 'original'); |
|||
if (pg.current.linksHash[a.href] && false) { |
|||
a.navpopup = pg.current.linksHash[a.href]; |
|||
} |
} |
||
else { |
|||
a.navpopup=newNavpopup(a, article); |
|||
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.linksHash[a.href] = a.navpopup; |
||
pg.current.links.push(a); |
pg.current.links.push(a); |
||
} |
} |
||
} |
|||
if (a.navpopup.pending === null || a.navpopup.pending !== 0) { |
|||
if (a.navpopup.pending === null || a.navpopup.pending !== 0) { |
|||
// either fresh popups or those with unfinshed business are redone from scratch |
|||
// either fresh popups or those with unfinshed business are redone from scratch |
|||
simplePopupContent(a, article); |
|||
simplePopupContent(a, article); |
|||
} |
|||
} |
|||
a.navpopup.showSoonIfStable(a.navpopup.delay); |
|||
a.navpopup.showSoonIfStable(a.navpopup.delay); |
|||
getValueOf('popupInitialWidth'); |
|||
clearInterval(pg.timer.checkPopupPosition); |
|||
pg.timer.checkPopupPosition = setInterval(checkPopupPosition, 600); |
|||
clearInterval(pg.timer.checkPopupPosition); |
|||
if (getValueOf('simplePopups')) { |
|||
pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600); |
|||
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(getValueOf('simplePopups')) { |
|||
if (a.navpopup.pending !== 0) { |
|||
if (getValueOf('popupPreviewButton') && !a.simpleNoMore) { |
|||
nonsimplePopupContent(a, article); |
|||
var d=document.createElement('div'); |
|||
d.className='popupPreviewButtonDiv'; |
|||
var s=document.createElement('span'); |
|||
d.appendChild(s); |
|||
s.className='popupPreviewButton'; |
|||
s['on' + getValueOf('popupPreviewButtonEvent')] = function() { |
|||
a.simpleNoMore=true; |
|||
nonsimplePopupContent(a,article); |
|||
}; |
|||
s.innerHTML=popupString('show preview'); |
|||
setPopupHTML(d, 'popupPreview', a.navpopup.idNumber); |
|||
} |
} |
||
return; |
|||
} |
} |
||
if (a.navpopup.pending !== 0 ) { |
|||
// simplePopupContent: the content that do not require additional download |
|||
nonsimplePopupContent(a, article); |
|||
// (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 }); |
|||
// simplePopupContent: the content that is shown even when simplePopups is true |
|||
if (getValueOf('popupDraggable')) { |
|||
function simplePopupContent(a, article) { |
|||
var dragHandle = getValueOf('popupDragHandle') || null; |
|||
/* FIXME hack */ a.navpopup.hasPopupMenu=false; |
|||
if (dragHandle && dragHandle != 'all') { |
|||
a.navpopup.setInnerHTML(popupHTML(a)); |
|||
fillEmptySpans({navpopup:a.navpopup}); |
|||
} |
|||
setTimeout(function () { |
|||
a.navpopup.makeDraggable(dragHandle); |
|||
}, 150); |
|||
} |
|||
if (getValueOf('popupDraggable')) |
|||
{ |
|||
setPopupHTML('<br>' + popupRedlinkHTML(article), 'popupRedlink', a.navpopup.idNumber); |
|||
var dragHandle = getValueOf('popupDragHandle') || null; |
|||
if (dragHandle && dragHandle != 'all') { |
|||
dragHandle += a.navpopup.idNumber; |
|||
} |
} |
||
setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150); |
|||
} |
} |
||
//<NOLITE> |
|||
function debugData(navpopup) { |
|||
if (getValueOf('popupRedlinkRemoval') && a.className=='new') { |
|||
setPopupHTML('<br>'+popupRedlinkHTML(article), 'popupRedlink', a.navpopup.idNumber); |
|||
setPopupHTML( |
|||
'idNumber=' + navpopup.idNumber + ', pending=' + navpopup.pending, |
|||
'popupError', |
|||
navpopup.idNumber |
|||
); |
|||
} |
|||
} |
} |
||
//</NOLITE> |
|||
} |
|||
function debugData(navpopup) { |
|||
if(getValueOf('popupDebugging') && navpopup.idNumber) { |
|||
var navpopup = new Navpopup(); |
|||
setPopupHTML('idNumber='+navpopup.idNumber + ', pending=' + navpopup.pending, |
|||
navpopup.fuzz = 5; |
|||
'popupError', navpopup.idNumber); |
|||
navpopup.delay = getValueOf('popupDelay') * 1000; |
|||
// increment global counter now |
|||
navpopup.idNumber = ++pg.idNumber; |
|||
navpopup.parentAnchor = a; |
|||
navpopup.parentPopup = a.popData && a.popData.owner; |
|||
navpopup.article = article; |
|||
registerHooks(navpopup); |
|||
return navpopup; |
|||
} |
} |
||
} |
|||
function newNavpopup(a, article) { |
|||
// Should we show nonsimple context? |
|||
var navpopup = new Navpopup(); |
|||
// If simplePopups is set to true, then we do not show nonsimple context, |
|||
navpopup.fuzz=5; |
|||
// but if a bottom "show preview" was clicked we do show nonsimple context |
|||
navpopup.delay=getValueOf('popupDelay')*1000; |
|||
function shouldShowNonSimple(a) { |
|||
// increment global counter now |
|||
return !getValueOf('simplePopups') || a.simpleNoMore; |
|||
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 govern by the option (e.g. popupUserInfo)? |
|||
function nonsimplePopupContent(a, article) { |
|||
// If the user explicitly asked for nonsimple context by setting the option to true, |
|||
var diff=null, history=null; |
|||
// then we show it even in nonsimple mode. |
|||
var params=parseParams(a.href); |
|||
function shouldShow(a, option) { |
|||
var oldid=(typeof params.oldid=='undefined' ? null : params.oldid); |
|||
if (shouldShowNonSimple(a)) { |
|||
//<NOLITE> |
|||
return getValueOf(option); |
|||
if(getValueOf('popupPreviewDiffs')) { |
|||
} else { |
|||
diff=params.diff; |
|||
return typeof window[option] != 'undefined' && window[option]; |
|||
} |
|||
} |
} |
||
if(getValueOf('popupPreviewHistory')) { |
|||
history=(params.action=='history'); |
|||
function nonsimplePopupContent(a, article) { |
|||
} |
|||
var diff = null, |
|||
//</NOLITE> |
|||
history = null; |
|||
a.navpopup.pending=0; |
|||
var params = parseParams(a.href); |
|||
var referenceElement = footnoteTarget(a); |
|||
var oldid = typeof params.oldid == 'undefined' ? null : params.oldid; |
|||
if (referenceElement) { |
|||
if (shouldShow(a, 'popupPreviewDiffs')) { |
|||
footnotePreview(referenceElement, a.navpopup); |
|||
diff = params.diff; |
|||
//<NOLITE> |
|||
} |
|||
} else if ( diff || diff === 0 ) { |
|||
if (shouldShow(a, 'popupPreviewHistory')) { |
|||
loadDiff(article, oldid, diff, a.navpopup); |
|||
history = params.action == 'history'; |
|||
} else if ( history ) { |
|||
} |
|||
a.navpopup |
loadAPIPreview('history', article, a.navpopup); |
||
} else if ( pg.re.contribs.test(a.href) ) { |
|||
var referenceElement = footnoteTarget(a); |
|||
loadAPIPreview('contribs', article, a.navpopup); |
|||
if (referenceElement) { |
|||
} else if ( pg.re.backlinks.test(a.href) ) { |
|||
footnotePreview(referenceElement, a.navpopup); |
|||
loadAPIPreview('backlinks', article, a.navpopup); |
|||
} else if (diff || diff === 0) { |
|||
} else if ( // FIXME should be able to get all preview combinations with options |
|||
loadDiff(article, oldid, diff, a.navpopup); |
|||
article.namespaceId()==pg.nsImageId && |
|||
} else if (history) { |
|||
( getValueOf('imagePopupsForImages') || ! anchorContainsImage(a) ) |
|||
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 { |
|||
} else { |
|||
if (article.namespaceId() == pg.nsCategoryId && shouldShow(a, 'popupCategoryMembers')) { |
|||
if (article.namespaceId() == pg.nsCategoryId && |
|||
loadAPIPreview('category', article, a.navpopup); |
|||
getValueOf('popupCategoryMembers')) { |
|||
} else if ( |
|||
loadAPIPreview('category', article, a.navpopup); |
|||
(article.namespaceId() == pg.nsUserId || article.namespaceId() == pg.nsUsertalkId) && |
|||
} else if ((article.namespaceId() == pg.nsUserId || article.namespaceId() == pg.nsUsertalkId) && |
|||
shouldShow(a, 'popupUserInfo') |
|||
getValueOf('popupUserInfo')) { |
|||
) { |
|||
loadAPIPreview('userinfo', article, a.navpopup); |
|||
} |
|||
if (shouldShowNonSimple(a)) { |
|||
startArticlePreview(article, oldid, a.navpopup); |
|||
} |
|||
} |
} |
||
startArticlePreview(article, oldid, a.navpopup); |
|||
} |
} |
||
} |
|||
function pendingNavpopTask(navpop) { |
|||
if (navpop && navpop.pending === null) { navpop.pending=0; } |
|||
++navpop.pending; |
|||
debugData(navpop); |
|||
} |
|||
} |
|||
++navpop.pending; |
|||
debugData(navpop); |
|||
} |
|||
function completedNavpopTask(navpop) { |
|||
if (navpop && navpop.pending) { --navpop.pending; } |
|||
debugData(navpop); |
|||
} |
|||
debugData(navpop); |
|||
} |
|||
function startArticlePreview(article, oldid, navpop) { |
|||
navpop.redir=0; |
|||
loadPreview(article, oldid, navpop); |
|||
} |
|||
function loadPreview(article, oldid, navpop) { |
|||
pendingNavpopTask(navpop); |
|||
if (!navpop.redir) { navpop.originalArticle=article; } |
|||
if (!navpop.visible && getValueOf('popupLazyDownloads')) { |
|||
var id=(navpop.redir) ? 'DOWNLOAD_PREVIEW_REDIR_HOOK' : 'DOWNLOAD_PREVIEW_HOOK'; |
|||
navpop.addHook(function() { |
|||
getWiki(article, insertPreview, oldid, navpop); |
|||
return true; }, 'unhide', 'before', id); |
|||
} else { |
|||
getWiki(article, insertPreview, oldid, navpop); |
|||
} |
} |
||
} |
|||
function loadPreviewFromRedir(redirMatch, navpop) { |
|||
// redirMatch is a regex match |
|||
if (!navpop.redir) { |
|||
var target = new Title().fromWikiText(redirMatch[2]); |
|||
navpop.originalArticle = article; |
|||
// overwrite (or add) anchor from original target |
|||
} |
|||
// mediawiki does overwrite; eg [[User:Lupin/foo3#Done]] |
|||
article.oldid = oldid; |
|||
if ( navpop.article.anchor ) { target.anchor = navpop.article.anchor; } |
|||
loadAPIPreview('revision', article, navpop); |
|||
var trailingRubbish=redirMatch[4]; |
|||
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) { |
|||
completedNavpopTask(download.owner); |
|||
loadPreviewFromRedir(redirMatch, download.owner); |
|||
return; |
|||
} |
} |
||
if (download.owner.visible || !getValueOf('popupLazyPreviews')) { |
|||
function loadPreviewFromRedir(redirMatch, navpop) { |
|||
insertPreviewNow(download); |
|||
// redirMatch is a regex match |
|||
} else { |
|||
var target = new Title().fromWikiText(redirMatch[2]); |
|||
var id=(download.owner.redir) ? 'PREVIEW_REDIR_HOOK' : 'PREVIEW_HOOK'; |
|||
// overwrite (or add) anchor from original target |
|||
download.owner.addHook( function(){insertPreviewNow(download); return true;}, |
|||
// mediawiki does overwrite; eg [[User:Lupin/foo3#Done]] |
|||
'unhide', 'after', id ); |
|||
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 insertPreviewNow(download) { |
|||
if (!download.owner) { return; } |
|||
var wikiText=download.data; |
|||
return; |
|||
var navpop=download.owner; |
|||
} |
|||
completedNavpopTask(navpop); |
|||
var art=navpop.redirTarget || navpop.originalArticle; |
|||
//<NOLITE> |
|||
var redirMatch = pg.re.redirect.exec(download.data); |
|||
makeFixDabs(wikiText, navpop); |
|||
if (download.owner.redir === 0 && redirMatch) { |
|||
if (getValueOf('popupSummaryData')) { |
|||
loadPreviewFromRedir(redirMatch, download.owner); |
|||
var info=getPageInfo(wikiText, download); |
|||
return; |
|||
setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber); |
|||
} |
|||
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 |
|||
); |
|||
} |
|||
} |
} |
||
var imagePage=''; |
|||
function insertPreviewNow(download) { |
|||
if (art.namespaceId()==pg.nsImageId) { imagePage=art.toString(); } |
|||
if (!download.owner) { |
|||
else { imagePage=getValidImageFromWikiText(wikiText); } |
|||
return; |
|||
if(imagePage) { loadImage(Title.fromWikiText(imagePage), navpop); } |
|||
} |
|||
//</NOLITE> |
|||
var wikiText = download.data; |
|||
var navpop = download.owner; |
|||
var art = navpop.redirTarget || navpop.originalArticle; |
|||
if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); } |
|||
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); |
|||
} |
|||
function insertArticlePreview(download, art, navpop) { |
|||
if (getValueOf('popupPreviews')) { |
|||
if (download && typeof download.data == typeof ''){ |
|||
insertArticlePreview(download, art, navpop); |
|||
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 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])); |
|||
} |
|||
// Try to imitate the way mediawiki generates HTML anchors from section titles |
|||
// now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom |
|||
function anchorize(d, anch) { |
|||
var lines = d.split('\n'); |
|||
if (!anch) { return d; } |
|||
for (var i = 0; i < lines.length; ++i) { |
|||
var anchRe=RegExp('(?:=+\\s*' + literalizeRegex(anch).replace(/[_ ]/g, '[_ ]') + '\\s*=+|\\{\\{\\s*'+getValueOf('popupAnchorRegexp')+'\\s*(?:\\|[^|}]*)*?\\s*'+literalizeRegex(anch)+'\\s*(?:\\|[^}]*)?\}\})'); |
|||
lines[i] = lines[i] |
|||
var match=d.match(anchRe); |
|||
.replace(/[[]{2}([^|\]]*?[|])?(.*?)[\]]{2}/g, '$2') |
|||
if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); } |
|||
.replace(/'''([^'])/g, '$1') |
|||
.replace(/''([^'])/g, '$1'); |
|||
// now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom |
|||
if (lines[i].match(anchRe)) { |
|||
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; |
|||
} |
} |
||
return d; |
|||
} |
|||
function killPopup() { |
|||
if (getValueOf('popupShortcutKeys')) { rmPopupShortcuts(); } |
|||
removeModifierKeyHandler(this); |
|||
if (!pg) { return; } |
|||
if (getValueOf('popupShortcutKeys')) { |
|||
if (pg.current.link && pg.current.link.navpopup) { pg.current.link.navpopup.banish(); } |
|||
rmPopupShortcuts(); |
|||
pg.current.link=null; |
|||
} |
|||
abortAllDownloads(); |
|||
if (!pg) { |
|||
if (pg.timer.checkPopupPosition) { |
|||
return; |
|||
clearInterval(pg.timer.checkPopupPosition); |
|||
} |
|||
pg.timer.checkPopupPosition=null; |
|||
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 |
|||
} |
} |
||
return true; // preserve default action |
|||
// ENDFILE: actions.js |
|||
} |
|||
// ENDFILE: actions.js |
|||
// STARTFILE: domdrag.js |
|||
/** |
|||
@fileoverview |
|||
The {@link Drag} object, which enables objects to be dragged around. |
|||
<pre> |
|||
// STARTFILE: domdrag.js |
|||
************************************************* |
|||
/** |
|||
dom-drag.js |
|||
* @file |
|||
09.25.2001 |
|||
* The {@link Drag} object, which enables objects to be dragged around. |
|||
www.youngpup.net |
|||
* |
|||
************************************************** |
|||
* <pre> |
|||
10.28.2001 - fixed minor bug where events |
|||
* ************************************************* |
|||
sometimes fired off the handle, not the root. |
|||
* dom-drag.js |
|||
************************************************* |
|||
* 09.25.2001 |
|||
Pared down, some hooks added by [[User:Lupin]] |
|||
* 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> |
|||
*/ |
|||
Copyright Aaron Boodman. |
|||
/** |
|||
Saying stupid things daily since March 2001. |
|||
* Creates a new Drag object. This is used to make various DOM elements draggable. |
|||
</pre> |
|||
* @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; |
|||
} |
|||
/** |
|||
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. |
|||
* Gets an event in a cross-browser manner. |
|||
To disable this, set it to <code>null</code>. |
|||
* @param {Event} e |
|||
@type Function |
|||
*/ |
|||
this.startCondition = 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; |
|||
}; |
|||
/** |
/** |
||
Hook to be run when the drag finishes. This is passed the final coordinates of |
|||
* Initialises the Drag instance by telling it which object you want to be draggable, and what |
|||
the dragged object (two integers, x and y). To disables this, set it to <code>null</code>. |
|||
* you want to drag it by. |
|||
@type Function |
|||
* @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. |
|||
this.endHook = null; |
|||
*/ |
|||
} |
|||
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 || o; |
|||
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'; |
|||
} |
|||
if (isNaN(parseInt(o.root.style.left, 10))) { o.root.style.left = "0px"; } |
|||
o.root.onthisStart = function () {}; |
|||
if (isNaN(parseInt(o.root.style.top, 10))) { o.root.style.top = "0px"; } |
|||
o.root.onthisEnd = function () {}; |
|||
o.root.onthis = function () {}; |
|||
}; |
|||
o.root.onthisStart = function(){}; |
|||
/** |
|||
o.root.onthisEnd = function(){}; |
|||
* Starts the drag. |
|||
o.root.onthis = function(){}; |
|||
* @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; |
|||
Starts the drag. |
|||
o.lastMouseY = e.clientY; |
|||
@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; |
|||
var dragObj = this; |
|||
o.lastMouseY = e.clientY; |
|||
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; |
|||
}; |
|||
var dragObj = this; |
|||
/** |
|||
o.onmousemoveDefault = document.onmousemove; |
|||
* Does the drag. |
|||
o.dragging = true; |
|||
* @param {Event} e |
|||
document.onmousemove = function(e) { dragObj.drag.apply( dragObj, [e] ); }; |
|||
* @private |
|||
document.onmouseup = function(e) { dragObj.end.apply( dragObj, [e] ); }; |
|||
*/ |
|||
return false; |
|||
Drag.prototype.drag = function (e) { |
|||
}; |
|||
e = this.fixE(e); |
|||
/** |
|||
var o = this.obj; |
|||
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), |
|||
this.endHook( |
|||
parseInt(this.obj.root.style[this.obj. |
parseInt(this.obj.root.style[this.obj.vmode ? "top" : "bottom"], 10)); |
||
} |
|||
parseInt(this.obj.root.style[this.obj.vmode ? 'top' : 'bottom'], 10) |
|||
}; |
|||
); |
|||
// ENDFILE: domdrag.js |
|||
} |
|||
// STARTFILE: structures.js |
|||
}; |
|||
//<NOLITE> |
|||
// ENDFILE: domdrag.js |
|||
pg.structures.original={}; |
|||
pg.structures.original.popupLayout=function () { |
|||
return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', |
|||
'popupData', 'popupOtherLinks', |
|||
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', |
|||
'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], |
|||
'popupMiscTools', ['popupRedlink'], |
|||
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; |
|||
}; |
|||
pg.structures.original.popupRedirSpans=function () { |
|||
return ['popupRedir', 'popupWarnRedir', 'popupRedirTopLinks', |
|||
'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks']; |
|||
}; |
|||
pg.structures.original.popupTitle=function (x) { |
|||
log ('defaultstructure.popupTitle'); |
|||
if (!getValueOf('popupNavLinks')) { |
|||
return navlinkStringToHTML('<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; |
|||
// STARTFILE: structures.js |
|||
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{' + |
|||
var editOldidStr = |
|||
editstr + '}'; |
|||
'if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + |
|||
var historystr='<<history|shortcut=h>>'; |
|||
editstr + |
|||
var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; |
|||
'}'; |
|||
var historystr = '<<history|shortcut=h>>'; |
|||
var watchstr = '<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; |
|||
str += '<br>if(talk){' + |
|||
editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' + |
|||
'<br>if(talk){' + |
|||
'<b><<article|shortcut=a>></b>|<<editArticle|edit>>' + |
|||
editOldidStr + |
|||
'}else{' + // not a talk page |
|||
'|<<new|shortcut=+>>' + |
|||
editOldidStr + '*' + historystr + '*' + watchstr + '*' + |
|||
'*' + |
|||
'<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>}'; |
|||
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>>*' + |
|||
str += |
|||
'<<undelete|undeleteShort>>|<<delete|shortcut=d>>}'; |
|||
return navlinkStringToHTML(str, x.article, x.params); |
|||
'<<undelete|undeleteShort>>|<<delete|shortcut=d>>}'; |
|||
}; |
|||
return navlinkStringToHTML(str, x.article, x.params); |
|||
pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks; |
|||
}; |
|||
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>>if(mainspace_en){|<<editors|shortcut=E|eds>>}'; |
|||
var hist = |
|||
var watch='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; |
|||
var move='<<move|shortcut=m|move>>'; |
|||
return navlinkStringToHTML('if(talk){' + |
|||
var move = '<<move|shortcut=m|move>>'; |
|||
'<<edit|shortcut=e>>|<<new|shortcut=+|+>>*' + hist + '*' + |
|||
return navlinkStringToHTML( |
|||
'<<article|shortcut=a>>|<<editArticle|edit>>' + '*' + watch + '*' + move + |
|||
'if(talk){' + |
|||
'<<edit|shortcut=e |
'}else{<<edit|shortcut=e>>*' + hist + |
||
'*<<talk|shortcut=t|>>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>' + |
|||
hist + |
|||
'*' + watch + '*' + move+'}<br>', x.article, x.params); |
|||
'*' + |
|||
}; |
|||
'<<article|shortcut=a>>|<<editArticle|edit>>' + |
|||
pg.structures.fancy.popupOtherLinks=function(x) { |
|||
'*' + |
|||
var admin='<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*<<undelete|undeleteShort>>|<<delete|shortcut=d|del>>'; |
|||
watch + |
|||
var user='<<contribs|shortcut=c>>if(wikimedia){|<<count|shortcut=#|#>>}'; |
|||
'*' + |
|||
user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+ |
|||
move + |
|||
popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}'; |
|||
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); |
|||
'<br>if(user){' + user + '*}if(admin){' + admin + 'if(user){<br>}else{*}}' + normal, |
|||
}; |
|||
x.article, |
|||
pg.structures.fancy.popupRedirTitle=pg.structures.fancy.popupTitle; |
|||
x.params |
|||
pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks; |
|||
); |
|||
pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks; |
|||
}; |
|||
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(/<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', |
|||
]; |
|||
}; |
|||
/** -- fancy2 -- **/ |
|||
// hack for [[User:MacGyverMagic]] |
|||
copyStructure('original', 'menus'); |
|||
copyStructure('fancy', 'fancy2'); |
|||
pg.structures.menus.popupLayout = function () { |
|||
pg.structures.fancy2.popupTopLinks=function(x) { // hack out the <br> at the end and put one at the beginning |
|||
return [ |
|||
return '<br>'+pg.structures.fancy.popupTopLinks(x).replace(RegExp('<br>$','i'),''); |
|||
'popupError', |
|||
}; |
|||
'popupImage', |
|||
pg.structures.fancy2.popupLayout=function () { // move toplinks to after the title |
|||
'popupTopLinks', |
|||
return ['popupError', 'popupImage', 'popupTitle', 'popupData', 'popupTopLinks', 'popupOtherLinks', |
|||
'popupTitle', |
|||
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], |
|||
'popupOtherLinks', |
|||
'popupMiscTools', ['popupRedlink'], |
|||
'popupRedir', |
|||
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; |
|||
[ |
|||
}; |
|||
'popupWarnRedir', |
|||
'popupRedirTopLinks', |
|||
'popupRedirTitle', |
|||
'popupRedirData', |
|||
'popupRedirOtherLinks', |
|||
], |
|||
'popupUserData', |
|||
'popupData', |
|||
'popupMiscTools', |
|||
['popupRedlink'], |
|||
'popupPrePreviewSep', |
|||
'popupPreview', |
|||
'popupSecondPreview', |
|||
'popupPreviewMore', |
|||
'popupPostPreview', |
|||
'popupFixDab', |
|||
]; |
|||
}; |
|||
/** -- menus -- **/ |
|||
pg.structures.menus.popupTopLinks = function (x, shorter) { |
|||
copyStructure('original', 'menus'); |
|||
// FIXME maybe this stuff should be cached |
|||
pg.structures.menus.popupLayout=function () { |
|||
var s = []; |
|||
return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks', |
|||
var dropclass = 'popup_drop'; |
|||
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], |
|||
var enddiv = '</div>'; |
|||
'popupData', 'popupMiscTools', ['popupRedlink'], |
|||
var hist = '<<history|shortcut=h>>'; |
|||
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; |
|||
if (!shorter) { |
|||
}; |
|||
hist = '<menurow>' + hist + '|<<historyfeed|rss>>|<<editors|shortcut=E>></menurow>'; |
|||
function toggleSticky(uid) { |
|||
} |
|||
var popDiv=document.getElementById('navpopup_maindiv'+uid); |
|||
var lastedit = '<<lastEdit|shortcut=/|show last edit>>'; |
|||
if (!popDiv) { return; } |
|||
var thank = 'if(diff){<<thank|send thanks>>}'; |
|||
if (!popDiv.navpopup.sticky) { popDiv.navpopup.stick(); } |
|||
var jsHistory = '<<lastContrib|last set of edits>><<sinceMe|changes since mine>>'; |
|||
else { |
|||
var linkshere = '<<whatLinksHere|shortcut=l|what links here>>'; |
|||
popDiv.navpopup.unstick(); |
|||
var related = '<<relatedChanges|shortcut=r|related changes>>'; |
|||
popDiv.navpopup.hide(); |
|||
var search = |
|||
} |
|||
'<menurow><<search|shortcut=s>>if(wikimedia){|<<globalsearch|shortcut=g|global>>}' + |
|||
} |
|||
'|<<google|shortcut=G|web>></menurow>'; |
|||
pg.structures.menus.popupTopLinks = function (x, shorter) { |
|||
var watch = '<menurow><<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>></menurow>'; |
|||
// FIXME maybe this stuff should be cached |
|||
var protect = |
|||
var s=[]; |
|||
'<menurow><<unprotect|unprotectShort>>|' + |
|||
var dropdiv='<div class="popup_drop">'; |
|||
'<<protect|shortcut=p>>|<<protectlog|log>></menurow>'; |
|||
var enddiv='</div>'; |
|||
var endspan='</span>'; |
|||
'<menurow><<undelete|undeleteShort>>|<<delete|shortcut=d>>|<<deletelog|log>></menurow>'; |
|||
var hist='<<history|shortcut=h>>'; |
|||
if (!shorter) { hist = '<menurow>' + hist + |
|||
var nullPurge = '<menurow><<nullEdit|shortcut=n|null edit>>|<<purge|shortcut=P>></menurow>'; |
|||
'|<<historyfeed|rss>>if(mainspace_en){|<<editors|shortcut=E>>}</menurow>'; } |
|||
var lastedit='<<lastEdit|shortcut=/|show last edit>>'; |
|||
var editRow = |
|||
var thank='if(diff){<<thank|send thanks>>}'; |
|||
'if(oldid){' + |
|||
var jsHistory='<<lastContrib|last set of edits>><<sinceMe|changes since mine>>'; |
|||
'<menurow><<edit|shortcut=e>>|<<editOld|shortcut=e|this revision>></menurow>' + |
|||
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>>}' + |
|||
var markPatrolled = 'if(rcid){<<markpatrolled|mark patrolled>>}'; |
|||
'|<<google|shortcut=G|web>></menurow>'; |
|||
var watch='<menurow><<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>></menurow>'; |
|||
var protectDelete = 'if(admin){' + protect + del + '}'; |
|||
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 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(move + linkshere + related); |
|||
s.push('<hr />' + watch + protectDelete); |
|||
if (!shorter) { |
|||
s.push('<hr />' + |
|||
'if(talk){<<article|shortcut=a|view article>><<editArticle|edit article>>}' + |
|||
} |
|||
'else{<<talk|shortcut=t|talk page>><<editTalk|edit talk>>' + |
|||
if (!shorter) { |
|||
'<<newTalk|shortcut=+|new topic>>}</menu>' + enddiv); |
|||
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>}' + |
|||
var contribs = |
|||
'if(admin){<menurow><<deletedContribs>></menurow>}'; |
|||
'if(admin){<menurow><<deletedContribs>></menurow>}'; |
|||
s.push('if(user){*' + menuTitle(dropclass, 'user')); |
|||
s.push('<menu>'); |
|||
s.push('<menurow><<userPage|shortcut=u|user 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 + '}'); |
|||
s.push('if(user){*' + dropdiv + menuTitle('user')); |
|||
// popups menu starts here |
|||
s.push('<menu>'); |
|||
if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) { |
|||
s.push('<menurow><<userPage|shortcut=u|user page>>|<<userSpace|space>></menurow>'); |
|||
x.navpop.hasPopupMenu = true; |
|||
s.push('<<userTalk|shortcut=t|user talk>><<editUserTalk|edit user talk>>' + |
|||
s.push('*' + menuTitle(dropclass, 'popupsMenu') + '<menu>'); |
|||
'<<newUserTalk|shortcut=+|leave comment>>'); |
|||
if(!shorter) { s.push( 'if(ipuser){<<arin>>}else{' + email + '}' ); } |
|||
s.push('<<purgePopups|reset>>'); |
|||
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>}'); |
|||
return navlinkStringToHTML(s.join(''), x.article, x.params); |
|||
s.push('<<blocklog|shortcut=B|block log>>' + getValueOf('popupExtraUserMenu')); |
|||
}; |
|||
s.push('</menu>' + enddiv + '}'); |
|||
// popups menu starts here |
|||
function menuTitle(dropclass, s) { |
|||
if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) { |
|||
var text = popupString(s); // i18n |
|||
x.navpop.hasPopupMenu=true; |
|||
var len = text.length; |
|||
s.push('*' + dropdiv + menuTitle('popupsMenu') + '<menu>'); |
|||
return '<div class="' + dropclass + '" style="--navpop-m-len:' + len + 'ch"><a href="#" noPopup=1>' + text + '</a>'; |
|||
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) { |
|||
pg.structures.menus.popupRedirTitle = pg.structures.menus.popupTitle; |
|||
return '<a href="#" noPopup=1>' + popupString(s) + '</a>'; |
|||
pg.structures.menus.popupRedirTopLinks = pg.structures.menus.popupTopLinks; |
|||
} |
|||
pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle; |
|||
copyStructure('menus', 'shortmenus'); |
|||
pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks; |
|||
return pg.structures.menus.popupTopLinks(x, true); |
|||
}; |
|||
pg.structures.shortmenus.popupRedirTopLinks = pg.structures.shortmenus.popupTopLinks; |
|||
copyStructure('menus', 'shortmenus'); |
|||
pg.structures.lite = {}; |
|||
pg.structures.shortmenus.popupTopLinks=function(x) { |
|||
return pg.structures.menus.popupTopLinks(x,true); |
|||
return ['popupTitle', 'popupPreview']; |
|||
}; |
|||
pg.structures.shortmenus.popupRedirTopLinks=pg.structures.shortmenus.popupTopLinks; |
|||
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 |
|||
copyStructure('shortmenus', 'dabshortmenus'); |
|||
// STARTFILE: autoedit.js |
|||
pg.structures.dabshortmenus.popupLayout=function () { |
|||
function substitute(data, cmdBody) { |
|||
return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks', |
|||
// alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags); |
|||
'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], |
|||
var fromRe = RegExp(cmdBody.from, cmdBody.flags); |
|||
'popupData', 'popupMiscTools', ['popupRedlink'], 'popupFixDab', |
|||
return data.replace(fromRe, cmdBody.to); |
|||
'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview']; |
|||
} |
|||
}; |
|||
copyStructure('menus', 'dabmenus'); |
|||
function execCmds(data, cmdList) { |
|||
pg.structures.dabmenus.popupLayout=pg.structures.dabshortmenus.popupLayout; |
|||
for (var i = 0; i < cmdList.length; ++i) { |
|||
data = cmdList[i].action(data, cmdList[i]); |
|||
} |
|||
//</NOLITE> |
|||
return data; |
|||
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; |
|||
return []; |
|||
switch (str.charAt(0)) { |
|||
} |
|||
case 's': |
|||
var p = false; |
|||
p=parseSubstitute(str); |
|||
switch (str.charAt(0)) { |
|||
break; |
|||
case 's': |
|||
default: |
|||
p = parseSubstitute(str); |
|||
break; |
|||
default: |
|||
return false; |
|||
} |
|||
if (p) { |
|||
return [p].concat(parseCmd(p.remainder)); |
|||
} |
|||
return false; |
return false; |
||
} |
} |
||
if (p) { return [p].concat(parseCmd(p.remainder)); } |
|||
return false; |
|||
} |
|||
function unEscape(str, sep) { |
|||
// FIXME: Only used once here, confusing with native (and more widely-used) unescape, should probably be replaced |
|||
return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n'); |
|||
// Then again, unescape is semi-soft-deprecated, so we should look into replacing that too |
|||
} |
|||
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 |
|||
function parseSubstitute(str) { |
|||
var from, to, flags, tmp; |
|||
// 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); |
|||
if (str.length<4) { return false; } |
|||
tmp = skipOver(str, sep); |
|||
var sep=str.charAt(1); |
|||
if (tmp) { |
|||
str=str.substring(2); |
|||
from = tmp.segment; |
|||
str = tmp.remainder; |
|||
} else { |
|||
return false; |
|||
} |
|||
tmp=skipOver(str,sep); |
|||
if (tmp) { from=tmp.segment; str=tmp.remainder; } |
|||
if (tmp) { |
|||
else { return false; } |
|||
to = tmp.segment; |
|||
str = tmp.remainder; |
|||
} else { |
|||
return false; |
|||
} |
|||
tmp=skipOver(str,sep); |
|||
flags = ''; |
|||
if (tmp) { to=tmp.segment; str=tmp.remainder; } |
|||
if (str.length) { |
|||
else { return false; } |
|||
tmp = skipOver(str, ';') || skipToEnd(str, ';'); |
|||
if (tmp) { |
|||
flags = tmp.segment; |
|||
str = tmp.remainder; |
|||
} |
|||
} |
|||
flags=''; |
|||
return { |
|||
if (str.length) { |
|||
action: substitute, |
|||
tmp=skipOver(str,';') || skipToEnd(str, ';'); |
|||
from: from, |
|||
if (tmp) {flags=tmp.segment; str=tmp.remainder; } |
|||
to: to, |
|||
flags: flags, |
|||
remainder: str, |
|||
}; |
|||
} |
} |
||
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; |
|||
function skipOver(str,sep) { |
|||
} |
|||
var endSegment=findNext(str,sep); |
|||
if (endSegment<0) { return false; } |
|||
return { segment: segment, remainder: str.substring(endSegment + 1) }; |
|||
var segment=unEscape(str.substring(0,endSegment), sep); |
|||
} |
|||
return {segment: segment, remainder: str.substring(endSegment+1)}; |
|||
} |
|||
function skipToEnd(str,sep) { |
|||
return {segment: str, remainder: ''}; |
|||
} |
|||
function findNext(str, ch) { |
|||
/*eslint-disable*/ |
|||
for (var i=0; i<str.length; ++i) { |
|||
if (str.charAt(i)=='\\') { i+=2; } |
|||
return { segment: str, remainder: '' }; |
|||
if (str.charAt(i)==ch) { return i; } |
|||
} |
} |
||
return -1; |
|||
/*eslint-enable */ |
|||
} |
|||
function setCheckbox(param, box) { |
|||
var val=mw.util.getParamValue(param); |
|||
for (var i = 0; i < str.length; ++i) { |
|||
if (val) { |
|||
switch (val) { |
|||
case '1': case 'yes': case 'true': |
|||
} |
|||
box.checked=true; |
|||
if (str.charAt(i) == ch) { |
|||
break; |
|||
case '0': case 'no': case 'false': |
|||
} |
|||
box.checked=false; |
|||
} |
} |
||
return -1; |
|||
} |
} |
||
} |
|||
function autoEdit() { |
|||
if (!setupPopups.completed) { setupPopups(); } |
|||
var val = mw.util.getParamValue(param); |
|||
if (!mw.config.get('wgEnableAPI') || mw.util.getParamValue('autoimpl') !== popupString('autoedit_version') ) { return false; } |
|||
if (val) { |
|||
if (mw.util.getParamValue('autowatchlist') && mw.util.getParamValue('actoken')===autoClickToken()) { |
|||
switch (val) { |
|||
pg.fn.modifyWatchlist(mw.util.getParamValue('title'), mw.util.getParamValue('action')); |
|||
case '1': |
|||
} |
|||
case 'yes': |
|||
if (!document.editform) { return false; } |
|||
case 'true': |
|||
if (autoEdit.alreadyRan) { return false; } |
|||
box.checked = true; |
|||
autoEdit.alreadyRan=true; |
|||
break; |
|||
var cmdString=mw.util.getParamValue('autoedit'); |
|||
case '0': |
|||
if (cmdString) { |
|||
case 'no': |
|||
try { |
|||
case 'false': |
|||
var editbox=document.editform.wpTextbox1; |
|||
box.checked = false; |
|||
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'); |
|||
function autoEdit() { |
|||
if (rvid) { |
|||
setupPopups(function () { |
|||
var url=pg.wiki.apiwikibase + '?action=query&format=json&prop=revisions&revids='+rvid; |
|||
if (mw.util.getParamValue('autoimpl') !== popupString('autoedit_version')) { |
|||
startDownload(url, null, autoEdit2); |
|||
return false; |
|||
} else { autoEdit2(); } |
|||
} |
|||
} |
|||
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); |
|||
function autoEdit2(d) { |
|||
var rvid = mw.util.getParamValue('autorv'); |
|||
var summary=mw.util.getParamValue('autosummary'); |
|||
if (rvid) { |
|||
var summaryprompt=mw.util.getParamValue('autosummaryprompt'); |
|||
var url = |
|||
var summarynotice=''; |
|||
pg.wiki.apiwikibase + |
|||
if (d && d.data && mw.util.getParamValue('autorv')) { |
|||
'?action=query&format=json&formatversion=2&prop=revisions&revids=' + |
|||
var s = getRvSummary(summary, d.data); |
|||
rvid; |
|||
if (s === false) { |
|||
startDownload(url, null, autoEdit2); |
|||
summaryprompt=true; |
|||
} else { |
|||
summarynotice=popupString('Failed to get revision information, please edit manually.\n\n'); |
|||
autoEdit2(); |
|||
summary = simplePrintf(summary, [mw.util.getParamValue('autorv'), '(unknown)', '(unknown)']); |
|||
} |
|||
} else { summary = s; } |
|||
}); |
|||
} |
} |
||
if (summaryprompt) { |
|||
var txt= summarynotice + |
|||
function autoEdit2(d) { |
|||
popupString('Enter a non-empty edit summary or press cancel to abort'); |
|||
var summary = mw.util.getParamValue('autosummary'); |
|||
var response=prompt(txt, summary); |
|||
var summaryprompt = mw.util.getParamValue('autosummaryprompt'); |
|||
if (response) { summary=response; } |
|||
var summarynotice = ''; |
|||
else { return; } |
|||
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); |
|||
} |
} |
||
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; } |
|||
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.', |
|||
var msg = tprintf( |
|||
[ button.value ]); |
|||
'The %s button has been automatically clicked. Please wait for the next page to load.', |
|||
bannerMessage(msg); |
|||
[button.value] |
|||
document.title='('+document.title+')'; |
|||
); |
|||
button.click(); |
|||
} else { |
|||
document.title = '(' + document.title + ')'; |
|||
alert(tprintf('Could not find button %s. Please check the settings in your javascript file.', |
|||
button.click(); |
|||
[ btn ])); |
|||
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 === undefined ? edit.user : '(hidden)']); |
|||
.split(/[A-Z]/g) |
|||
} catch (badness) { |
|||
.join(' ') |
|||
return false; |
|||
.replace(/^ *| *$/g, ''); |
|||
return simplePrintf(template, [ |
|||
edit.revid, |
|||
timestamp, |
|||
edit.userhidden ? '(hidden)' : edit.user, |
|||
]); |
|||
} catch (badness) { |
|||
return false; |
|||
} |
|||
} |
} |
||
} |
|||
//</NOLITE> |
|||
// ENDFILE: autoedit.js |
|||
// ENDFILE: autoedit.js |
|||
// STARTFILE: downloader.js |
|||
/** |
|||
@fileoverview |
|||
{@link Downloader}, a xmlhttprequest wrapper, and helper functions. |
|||
*/ |
|||
/** |
|||
// STARTFILE: downloader.js |
|||
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 |
|||
* @file |
|||
@type String |
|||
* {@link Downloader}, a xmlhttprequest wrapper, and helper functions. |
|||
*/ |
|||
this.url = url; |
|||
/** |
/** |
||
A universally unique ID number |
|||
* Creates a new Downloader |
|||
@type integer |
|||
* @constructor |
|||
*/ |
|||
* @class The Downloader class. Create a new instance of this class to download stuff. |
|||
this.id=null; |
|||
* @param {string} url The url to download. This can be omitted and supplied later. |
|||
/** |
|||
*/ |
|||
Modification date, to be culled from the incoming headers |
|||
function Downloader(url) { |
|||
@type Date |
|||
if (typeof XMLHttpRequest != 'undefined') { |
|||
@private |
|||
this.http = new XMLHttpRequest(); |
|||
*/ |
|||
} |
|||
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 http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html for possibilities. |
|||
@type String |
|||
*/ |
|||
this.method='GET'; |
|||
/** |
|||
Async flag. |
|||
@type boolean |
|||
*/ |
|||
this.async=true; |
|||
} |
|||
new Downloader(); |
|||
/** |
|||
* The url to download |
|||
* @type {string} |
|||
*/ |
|||
this.url = url; |
|||
/** Submits the http request. */ |
|||
/** |
|||
Downloader.prototype.send = function (x) { |
|||
* A universally unique ID number |
|||
if (!this.http) { return null; } |
|||
* @type {number} |
|||
return this.http.send(x); |
|||
*/ |
|||
}; |
|||
this.id = null; |
|||
/** 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); |
|||
}; |
|||
/** Gets the state of the download. */ |
|||
Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;}; |
|||
pg.misc.downloadsInProgress = { }; |
|||
/** |
|||
* Modification date, to be culled from the incoming headers |
|||
* @type Date |
|||
* @private |
|||
*/ |
|||
this.lastModified = null; |
|||
/** Starts the download. |
|||
/** |
|||
Note that setTarget {@link Downloader#setTarget} must be run first |
|||
* What to do when the download completes successfully |
|||
*/ |
|||
* @type {Function} |
|||
Downloader.prototype.start=function () { |
|||
* @private |
|||
if (!this.http) { return; } |
|||
*/ |
|||
pg.misc.downloadsInProgress[this.id] = this; |
|||
this.callbackFunction = null; |
|||
this.http.send(null); |
|||
}; |
|||
/** Gets the 'Last-Modified' date from the download headers. |
|||
/** |
|||
Should be run after the download completes. |
|||
* What to do on failure |
|||
Returns <code>null</code> on failure. |
|||
* @type {Function} |
|||
@return {Date} |
|||
* @private |
|||
*/ |
|||
Downloader.prototype.getLastModifiedDate=function () { |
|||
this.onFailure = null; |
|||
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 |
|||
*/ |
|||
* @type {boolean} |
|||
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; }; |
|||
/** |
|||
* 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(); |
|||
// helper functions |
|||
/** Creates a new {@link Downloader} and prepares it for action. |
|||
/** Submits the http request. */ |
|||
@param {String} url The url to download |
|||
Downloader.prototype.send = function (x) { |
|||
@param {integer} id The ID of the {@link Downloader} object |
|||
if (!this.http) { |
|||
@param {Function} callback The callback function invoked on success |
|||
return null; |
|||
@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 */ } |
|||
} |
} |
||
return this.http.send(x); |
|||
}; |
}; |
||
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); |
|||
} |
|||
/** |
|||
/** Aborts the download, setting the <code>aborted</code> field to true. */ |
|||
Starts a download. |
|||
Downloader.prototype.abort = function () { |
|||
@param {String} url The url to download |
|||
if (!this.http) { |
|||
@param {integer} id The ID of the {@link Downloader} object |
|||
return null; |
|||
@param {Function} callback The callback function invoked on success |
|||
} |
|||
@return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser |
|||
this.aborted = true; |
|||
*/ |
|||
return this.http.abort(); |
|||
function startDownload(url, id, callback) { |
|||
}; |
|||
var d=newDownload(url, id, callback); |
|||
if (typeof d == typeof '' ) { return d; } |
|||
d.start(); |
|||
return d; |
|||
} |
|||
/** |
|||
/** Returns the downloaded data. */ |
|||
Aborts all downloads which have been started. |
|||
Downloader.prototype.getData = function () { |
|||
*/ |
|||
if (!this.http) { |
|||
function abortAllDownloads() { |
|||
return null; |
|||
for ( var x in pg.misc.downloadsInProgress ) { |
|||
} |
|||
try { |
|||
return this.http.responseText; |
|||
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) |
|||
/** |
|||
/** Prepares the download. */ |
|||
* InstaView - a Mediawiki to HTML converter in JavaScript |
|||
Downloader.prototype.setTarget = function () { |
|||
* Version 0.6.1 |
|||
if (!this.http) { |
|||
* Copyright (C) Pedro Fayolle 2005-2006 |
|||
return null; |
|||
* http://en.wikipedia.org/wiki/User:Pilaf |
|||
} |
|||
* Distributed under the BSD license |
|||
this.http.open(this.method, this.url, this.async); |
|||
* |
|||
this.http.setRequestHeader('Api-User-Agent', pg.api.userAgent); |
|||
* 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) |
|||
*/ |
|||
/** Gets the state of the download. */ |
|||
Downloader.prototype.getReadyState = function () { |
|||
if (!this.http) { |
|||
return null; |
|||
} |
|||
return this.http.readyState; |
|||
}; |
|||
var Insta = {}; |
|||
pg.misc.downloadsInProgress = {}; |
|||
function setupLivePreview() { |
|||
/** |
|||
* 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); |
|||
}; |
|||
// options |
|||
/** |
|||
Insta.conf = |
|||
* Gets the 'Last-Modified' date from the download headers. |
|||
{ |
|||
* Should be run after the download completes. |
|||
baseUrl: '', |
|||
* Returns <code>null</code> on failure. |
|||
* @return {Date} |
|||
user: {}, |
|||
*/ |
|||
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; |
|||
}; |
|||
wiki: { |
|||
/** |
|||
lang: pg.wiki.lang, |
|||
* Sets the callback function. |
|||
interwiki: pg.wiki.interwiki, |
|||
* @param {Function} f callback function, called as <code>f(this)</code> on success |
|||
default_thumb_width: 180 |
|||
*/ |
|||
}, |
|||
Downloader.prototype.setCallback = function (f) { |
|||
if (!this.http) { |
|||
paths: { |
|||
return; |
|||
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'] |
|||
} |
} |
||
this.http.onreadystatechange = f; |
|||
}; |
}; |
||
// options with default values or backreferences |
|||
Downloader.prototype.getStatus = function () { |
|||
Insta.conf.user.name = Insta.conf.user.name || 'Wikipedian'; |
|||
if (!this.http) { |
|||
Insta.conf.user.signature = '[['+Insta.conf.locale.user+':'+Insta.conf.user.name+'|'+Insta.conf.user.name+']]'; |
|||
return null; |
|||
//Insta.conf.paths.images = '//upload.wikimedia.org/wikipedia/' + Insta.conf.wiki.lang + '/'; |
|||
} |
|||
return this.http.status; |
|||
// define constants |
|||
}; |
|||
Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:File|Image|'+Insta.conf.locale.image+ |
|||
'):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i'); |
|||
} |
|||
////////////////////////////////////////////////// |
|||
// helper functions |
|||
/** |
|||
Insta.dump = function(from, to) |
|||
* Creates a new {@link Downloader} and prepares it for action. |
|||
{ |
|||
* @param {string} url The url to download |
|||
if (typeof from == 'string') { from = document.getElementById(from); } |
|||
* @param {number} id The ID of the {@link Downloader} object |
|||
if (typeof to == 'string') { to = document.getElementById(to); } |
|||
* @param {Function} callback The callback function invoked on success |
|||
to.innerHTML = this.convert(from.value); |
|||
* @return {string|Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser |
|||
}; |
|||
*/ |
|||
function newDownload(url, id, callback, onfailure) { |
|||
Insta.convert = function(wiki) |
|||
var d = new Downloader(url); |
|||
{ |
|||
if (!d.http) { |
|||
var ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode |
|||
return 'ohdear'; |
|||
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; |
|||
d.setTarget(); |
|||
if (!onfailure) { |
|||
onfailure = 2; |
|||
} |
|||
var f = function () { |
|||
if (d.getReadyState() == 4) { |
|||
delete pg.misc.downloadsInProgress[this.id]; |
|||
try { |
|||
if (d.getStatus() == 200) { |
|||
d.data = d.getData(); |
|||
d.lastModified = d.getLastModifiedDate(); |
|||
callback(d); |
|||
} else if (typeof onfailure == typeof 1) { |
|||
if (onfailure > 0) { |
|||
// retry |
|||
newDownload(url, id, callback, onfailure - 1); |
|||
} |
|||
} else if (typeof onfailure === 'function') { |
|||
onfailure(d, url, id, callback); |
|||
} |
|||
} catch (somerr) { |
|||
/* ignore it */ |
|||
} |
|||
} |
|||
}; |
|||
d.setCallback(f); |
|||
return d; |
|||
} |
} |
||
/** |
|||
function html_entities(s) { |
|||
* Simulates a download from cached data. |
|||
return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); |
|||
* The supplied data is put into a {@link Downloader} as if it had downloaded it. |
|||
* @param {string} url The url. |
|||
* @param {number} 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); |
|||
} |
} |
||
// Wiki text parsing to html is a nightmare. |
|||
/** |
|||
// The below functions deliberately don't escape the ampersand since this would make it more difficult, |
|||
* Starts a download. |
|||
// and we don't absolutely need to for how we need it. |
|||
* @param {string} url The url to download |
|||
// This means that any unescaped ampersands in wikitext will remain unescaped and can cause invalid HTML. |
|||
* @param {number} id The ID of the {@link Downloader} object |
|||
// Browsers should all be able to handle it though. |
|||
* @param {Function} callback The callback function invoked on success |
|||
// We also escape significant wikimarkup characters to prevent further matching on the processed text |
|||
* @return {string|Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser |
|||
function htmlescape_text(s) { |
|||
*/ |
|||
return s.replace(/</g,"<").replace(/>/g,">").replace(/:/g,":").replace(/\[/g,"[").replace(/]/g,"]"); |
|||
function startDownload(url, id, callback) { |
|||
} |
|||
var d = newDownload(url, id, callback); |
|||
function htmlescape_attr(s) { |
|||
if (typeof d == typeof '') { |
|||
return htmlescape_text(s).replace(/'/g,"'").replace(/"/g,"""); |
|||
return d; |
|||
} |
|||
d.start(); |
|||
return d; |
|||
} |
} |
||
function max(a,b) { return (a>b)?a:b; } |
|||
/** |
|||
function min(a,b) { return (a<b)?a:b; } |
|||
* Aborts all downloads which have been started. |
|||
*/ |
|||
// return the first non matching character position between two strings |
|||
function abortAllDownloads() { |
|||
function str_imatch(a, b) |
|||
for (var x in pg.misc.downloadsInProgress) { |
|||
{ |
|||
try { |
|||
for (var i=0, l=min(a.length, b.length); i<l; i++) { |
|||
pg.misc.downloadsInProgress[x].aborted = true; |
|||
if (a.charAt(i)!=b.charAt(i)) { break; } |
|||
pg.misc.downloadsInProgress[x].abort(); |
|||
delete pg.misc.downloadsInProgress[x]; |
|||
} catch (e) {} |
|||
} |
} |
||
return i; |
|||
} |
} |
||
// ENDFILE: downloader.js |
|||
// compare current line against a string or regexp |
|||
// STARTFILE: livepreview.js |
|||
// if passed a string it will compare only the first string.length characters |
|||
// TODO: location is often not correct (eg relative links in previews) |
|||
// if passed a regexp the result is stored in $r |
|||
// NOTE: removed md5 and image and math parsing. was broken, lots of bytes. |
|||
function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)); } |
|||
/** |
|||
* 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) |
|||
*/ |
|||
function $$(c) { return ll[0]==c; } // compare current line against a string |
|||
var Insta = {}; |
|||
function _(p) { return ll[0].charAt(p); } // return char at pos p |
|||
function |
function endl(s) { ps(s); sh(); } |
||
// options |
|||
Insta.conf = { |
|||
baseUrl: '', |
|||
function parse_list() |
|||
user: {}, |
|||
{ |
|||
var prev=''; |
|||
while (remain() && $(/^([*#:;]+)(.*)$/)) { |
|||
wiki: { |
|||
lang: pg.wiki.lang, |
|||
interwiki: pg.wiki.interwiki, |
|||
default_thumb_width: 180, |
|||
}, |
|||
var l_match = $r; |
|||
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/', |
|||
}, |
|||
sh(); |
|||
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', |
|||
], |
|||
}, |
|||
}; |
|||
var ipos = str_imatch(prev, l_match[1]); |
|||
// 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 + '/'; |
|||
// close uncontinued lists |
|||
// define constants |
|||
for (var prevPos=prev.length-1; prevPos >= ipos; prevPos--) { |
|||
Insta.BLOCK_IMAGE = new RegExp( |
|||
'^\\[\\[(?:File|Image|' + |
|||
Insta.conf.locale.image + |
|||
'):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', |
|||
'i' |
|||
); |
|||
} |
|||
var pi = prev.charAt(prevPos); |
|||
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); |
|||
}; |
|||
if (pi=='*') { ps('</ul>'); } |
|||
Insta.convert = function (wiki) { |
|||
else if (pi=='#') { ps('</ol>'); } |
|||
var ll = typeof wiki == 'string' ? wiki.replace(/\r/g, '').split(/\n/) : wiki, // lines of wikicode |
|||
// close a dl only if the new item is not a dl item (:, ; or empty) |
|||
o = '', // output |
|||
else if($.inArray(l_match[1].charAt(prevPos), ['','*','#'])) { ps('</dl>'); } |
|||
p = 0, // para flag |
|||
} |
|||
r; // result of passing a regexp to compareLineStringOrReg() |
|||
// |
// open new lists |
||
for (var matchPos=ipos; matchPos<l_match[1].length; matchPos++) { |
|||
function remain() { |
|||
return ll.length; |
|||
var li = l_match[1].charAt(matchPos); |
|||
} |
|||
function sh() { |
|||
return ll.shift(); |
|||
} // shift |
|||
function ps(s) { |
|||
o += s; |
|||
} // push |
|||
if (li=='*') { ps('<ul>'); } |
|||
// similar to C's printf, uses ? as placeholders, ?? to escape question marks |
|||
else if (li=='#') { ps('<ol>'); } |
|||
function f() { |
|||
// open a new dl only if the prev item is not a dl item (:, ; or empty) |
|||
var i = 1, |
|||
else if ($.inArray(prev.charAt(matchPos), ['','*','#'])) { ps('<dl>'); } |
|||
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; |
|||
} |
|||
switch (l_match[1].charAt(l_match[1].length-1)) { |
|||
function html_entities(s) { |
|||
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
|||
} |
|||
case '*': case '#': |
|||
// Wiki text parsing to html is a nightmare. |
|||
ps('<li>' + parse_inline_nowiki(l_match[2])); |
|||
// The below functions deliberately don't escape the ampersand since this would make it more |
|||
break; |
|||
// 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, '<') |
|||
.replace(/>/g, '>') |
|||
.replace(/:/g, ':') |
|||
.replace(/\[/g, '[') |
|||
.replace(/]/g, ']'); |
|||
} |
|||
function htmlescape_attr(s) { |
|||
return htmlescape_text(s).replace(/'/g, ''').replace(/"/g, '"'); |
|||
} |
|||
case ';': |
|||
// return the first non matching character position between two strings |
|||
ps('<dt>'); |
|||
function str_imatch(a, b) { |
|||
for (var i = 0, l = Math.min(a.length, b.length); i < l; i++) { |
|||
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; |
break; |
||
} |
|||
case ':': |
|||
ps('<dd>' + parse_inline_nowiki(l_match[2])); |
|||
} |
} |
||
return i; |
|||
prev=l_match[1]; |
|||
} |
} |
||
// close remaining lists |
|||
// compare current line against a string or regexp |
|||
for (var i=prev.length-1; i>=0; i--) { |
|||
// if passed a string it will compare only the first string.length characters |
|||
ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl'))); |
|||
// if passed a regexp the result is stored in r |
|||
function compareLineStringOrReg(c) { |
|||
return typeof c == 'string' ? |
|||
ll[0] && ll[0].substr(0, c.length) == c : |
|||
(r = ll[0] && ll[0].match(c)); |
|||
} |
} |
||
} |
|||
function parse_table() |
|||
{ |
|||
return ll[0] == c; |
|||
endl(f('<table>', $(/^\{\|( .*)$/)? $r[1]: '')); |
|||
} // compare current line against a string |
|||
function charAtPoint(p) { |
|||
return ll[0].charAt(p); |
|||
} // return char at pos p |
|||
for (;remain();) if ($('|')) switch (_(1)) { |
|||
function endl(s) { |
|||
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 prev = ''; |
|||
var td_line, match_i; |
|||
// 1: "|+", '|' or '+' |
|||
while (remain() && compareLineStringOrReg(/^([*#:;]+)(.*)$/)) { |
|||
// 2: ?? |
|||
var l_match = r; |
|||
// 3: attributes ?? |
|||
// TODO: finish commenting this regexp |
|||
var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/); |
|||
if (td_match[1] == '|+') ps('<caption'); |
|||
sh(); |
|||
else ps('<t' + ((td_match[1]=='|')?'d':'h')); |
|||
if (typeof td_match[3] != 'undefined') { |
|||
var ipos = str_imatch(prev, l_match[1]); |
|||
//ps(' ' + td_match[3]) |
|||
// close uncontinued lists |
|||
match_i = 4; |
|||
for (var prevPos = prev.length - 1; prevPos >= ipos; prevPos--) { |
|||
var pi = prev.charAt(prevPos); |
|||
} else match_i = 2; |
|||
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>'); |
|||
} |
|||
} |
|||
ps('>'); |
|||
// open new lists |
|||
for (var matchPos = ipos; matchPos < l_match[1].length; matchPos++) { |
|||
var li = l_match[1].charAt(matchPos); |
|||
if (td_match[1] != '|+') { |
|||
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>'); |
|||
} |
|||
} |
|||
// use || or !! as a cell separator depending on context |
|||
switch (l_match[1].charAt(l_match[1].length - 1)) { |
|||
// NOTE: when split() is passed a regexp make sure to use non-capturing brackets |
|||
case '*': |
|||
td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/); |
|||
case '#': |
|||
ps('<li>' + parse_inline_nowiki(l_match[2])); |
|||
break; |
|||
ps(parse_inline_nowiki(td_line.shift())); |
|||
case ';': |
|||
ps('<dt>'); |
|||
while (td_line.length) ll.unshift(td_match[1] + td_line.pop()); |
|||
var dt_match = l_match[2].match(/(.*?)(:.*?)$/); |
|||
} else ps(td_match[match_i]); |
|||
// 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; |
|||
var tc = 0, td = []; |
|||
case ':': |
|||
ps('<dd>' + parse_inline_nowiki(l_match[2])); |
|||
} |
|||
prev = l_match[1]; |
|||
} |
|||
while (remain()) { |
|||
// close remaining lists |
|||
td.push(sh()); |
|||
for (var i = prev.length - 1; i >= 0; i--) { |
|||
if ($('|')) { |
|||
ps(f('</?>', prev.charAt(i) == '*' ? 'ul' : prev.charAt(i) == '#' ? 'ol' : 'dl')); |
|||
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_table() { |
|||
} |
|||
endl(f('<table>', compareLineStringOrReg(/^\{\|( .*)$/) ? r[1] : '')); |
|||
function parse_pre() |
|||
for (; remain(); ) { |
|||
{ |
|||
if (compareLineStringOrReg('|')) { |
|||
ps('<pre>'); |
|||
switch (charAtPoint(1)) { |
|||
do { |
|||
case '}': |
|||
endl(parse_inline_nowiki(ll[0].substring(1)) + "\n"); |
|||
endl('</table>'); |
|||
} while (remain() && $(' ')); |
|||
return; |
|||
ps('</pre>'); |
|||
case '-': |
|||
} |
|||
endl(f('<tr>', compareLineStringOrReg(/\|-*(.*)/)[1])); |
|||
break; |
|||
function parse_block_image() |
|||
default: |
|||
{ |
|||
parse_table_data(); |
|||
ps(parse_image(sh())); |
|||
} |
|||
} |
|||
} else if (compareLineStringOrReg('!')) { |
|||
parse_table_data(); |
|||
function parse_image(str) |
|||
} else { |
|||
{ |
|||
sh(); |
|||
//<NOLITE> |
|||
// get what's in between "[[Image:" and "]]" |
|||
var tag = str.substring(str.indexOf(':') + 1, str.length - 2); |
|||
var width; |
|||
var attr = [], filename, caption = ''; |
|||
var thumb=0, frame=0, center=0; |
|||
var align=''; |
|||
if (tag.match(/\|/)) { |
|||
// manage nested links |
|||
var nesting = 0; |
|||
var last_attr; |
|||
for (var i = tag.length-1; i > 0; i--) { |
|||
if (tag.charAt(i) == '|' && !nesting) { |
|||
last_attr = tag.substr(i+1); |
|||
tag = tag.substring(0, i); |
|||
break; |
|||
} else switch (tag.substr(i-1, 2)) { |
|||
case ']]': |
|||
nesting++; |
|||
i--; |
|||
break; |
|||
case '[[': |
|||
nesting--; |
|||
i--; |
|||
} |
} |
||
} |
} |
||
} |
|||
attr = tag.split(/\s*\|\s*/); |
|||
function parse_table_data() { |
|||
attr.push(last_attr); |
|||
var td_line, match_i; |
|||
filename = attr.shift(); |
|||
var w_match; |
|||
// 1: "|+", '|' or '+' |
|||
// 2: ?? |
|||
// 3: attributes ?? |
|||
// TODO: finish commenting this regexp |
|||
var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/); |
|||
for (;attr.length; attr.shift()) { |
|||
w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/); |
|||
ps('<caption'); |
|||
if (w_match) width = w_match[1]; |
|||
} else { |
|||
else switch(attr[0]) { |
|||
ps('<t' + (td_match[1] == '|' ? 'd' : 'h')); |
|||
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; |
|||
if (typeof td_match[3] != 'undefined') { |
|||
//ps(' ' + td_match[3]) |
|||
match_i = 4; |
|||
} else { |
|||
match_i = 2; |
|||
} |
|||
ps('>'); |
|||
var o=''; |
|||
// 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] == '|' ? '||' : /(?:\|\||!!)/); |
|||
if (frame) { |
|||
ps(parse_inline_nowiki(td_line.shift())); |
|||
if (align === '') align = 'right'; |
|||
while (td_line.length) { |
|||
ll.unshift(td_match[1] + td_line.pop()); |
|||
} |
|||
} else { |
|||
ps(parse_inline_nowiki(td_match[match_i])); |
|||
} |
|||
o += f("<div class='thumb t?'>", align); |
|||
var tc = 0, |
|||
td = []; |
|||
if (thumb) { |
|||
if (!width) width = Insta.conf.wiki.default_thumb_width; |
|||
td.push(sh()); |
|||
if (compareLineStringOrReg('|')) { |
|||
if (!tc) { |
|||
break; |
|||
} |
|||
// we're at the outer-most level (no nested tables), skip to td parse |
|||
else if (charAtPoint(1) == '}') { |
|||
tc--; |
|||
} |
|||
} else if (!tc && compareLineStringOrReg('!')) { |
|||
break; |
|||
} else if (compareLineStringOrReg('{|')) { |
|||
tc++; |
|||
} |
|||
} |
|||
o += f("<div style='width:?px;'>?", 2+width*1, make_image(filename, caption, width)) + |
|||
if (td.length) { |
|||
f("<div class='thumbcaption'><div class='magnify' style='float:right'><a href='?' title='Enlarge'></a></div>?</div>", |
|||
ps(Insta.convert(td)); |
|||
htmlescape_attr(Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename), |
|||
parse_inline_nowiki(caption) |
|||
); |
|||
} else { |
|||
o += '<div>' + make_image(filename, caption) + f("<div class='thumbcaption'>?</div>", parse_inline_nowiki(caption)); |
|||
} |
} |
||
} |
|||
o += '</div></div>'; |
|||
function parse_pre() { |
|||
ps('<pre>'); |
|||
do { |
|||
endl(parse_inline_nowiki(ll[0].substring(1)) + '\n'); |
|||
} while (remain() && compareLineStringOrReg(' ')); |
|||
ps('</pre>'); |
|||
} |
|||
} else if (align !== '') { |
|||
function parse_block_image() { |
|||
o += f("<div class='float?'><span>?</span></div>", align, make_image(filename, caption, width)); |
|||
ps(parse_image(sh())); |
|||
} else { |
|||
return make_image(filename, caption, width); |
|||
} |
} |
||
return center? f("<div class='center'>?</div>", o): o; |
|||
function parse_image(str) { |
|||
//</NOLITE> |
|||
// get what's in between "[[Image:" and "]]" |
|||
} |
|||
var tag = str.substring(str.indexOf(':') + 1, str.length - 2); |
|||
var width; |
|||
function parse_inline_nowiki(str) |
|||
var attr = [], |
|||
{ |
|||
filename, |
|||
var start, lastend=0; |
|||
caption = ''; |
|||
var substart=0, nestlev=0, open, close, subloop; |
|||
var thumb = 0, |
|||
var html=''; |
|||
center = 0; |
|||
var align = ''; |
|||
while (-1 != (start = str.indexOf('<nowiki>', substart))) { |
|||
if (tag.match(/\|/)) { |
|||
html += parse_inline_wiki(str.substring(lastend, start)); |
|||
// manage nested links |
|||
start += 8; |
|||
substart = start; |
|||
subloop = true; |
|||
for (var i = tag.length - 1; i > 0; i--) { |
|||
do { |
|||
if (tag.charAt(i) == '|' && !nesting) { |
|||
open = str.indexOf('<nowiki>', substart); |
|||
close = str.indexOf('</nowiki>', substart); |
|||
if (close<=open || open==-1) { |
|||
break; |
|||
if (close==-1) { |
|||
return html + html_entities(str.substr(start)); |
|||
} |
|||
substart = close+9; |
|||
if (nestlev) { |
|||
nestlev--; |
|||
} else { |
} else { |
||
lastend = substart; |
|||
html += html_entities(str.substring(start, lastend-9)); |
|||
case ']]': |
|||
subloop = false; |
|||
i--; |
|||
break; |
|||
case '[[': |
|||
nesting--; |
|||
i--; |
|||
} |
|||
} |
} |
||
} else { |
|||
substart = open+8; |
|||
nestlev++; |
|||
} |
} |
||
} while (subloop); |
|||
} |
|||
return html + parse_inline_wiki(str.substr(lastend)); |
|||
attr = tag.split(/\s*\|\s*/); |
|||
} |
|||
attr.push(last_attr); |
|||
filename = attr.shift(); |
|||
function make_image(filename, caption, width) |
|||
var w_match; |
|||
{ |
|||
//<NOLITE> |
|||
// uppercase first letter in file name |
|||
filename = filename.charAt(0).toUpperCase() + filename.substr(1); |
|||
// replace spaces with underscores |
|||
filename = filename.replace(/ /g, '_'); |
|||
caption = strip_inline_wiki(caption); |
|||
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; |
|||
} |
|||
var md5 = hex_md5(filename); |
|||
return ''; |
|||
} |
|||
var source = md5.charAt(0) + '/' + md5.substr(0,2) + '/' + filename; |
|||
function parse_inline_nowiki(str) { |
|||
var start, |
|||
lastend = 0; |
|||
var substart = 0, |
|||
nestlev = 0, |
|||
open, |
|||
close, |
|||
subloop; |
|||
var html = ''; |
|||
if (width) width = "width='" + width + "px'"; |
|||
while ((start = str.indexOf('<nowiki>', substart)) != -1) { |
|||
html += parse_inline_wiki(str.substring(lastend, start)); |
|||
var img = "<img onerror=\""+ |
|||
start += 8; |
|||
pg.escapeQuotesHTML("this.onerror=null;this.src='"+pg.jsescape(Insta.conf.paths.images_fallback + source)+"'")+ |
|||
substart = start; |
|||
"\" src=\""+pg.escapeQuotesHTML(Insta.conf.paths.images + source)+ |
|||
subloop = true; |
|||
"\" "+(caption!=='' ? "alt=\"" +pg.escapeQuotesHTML(caption) + "\"" : '')+ |
|||
" "+width+">"; |
|||
return f("<a class='image' ? href=\"?\">?</a>", |
|||
(caption!=='')? "title=\"" + pg.escapeQuotesHTML(caption) + "\"" : '', |
|||
pg.escapeQuotesHTML(Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename), img); |
|||
//</NOLITE> |
|||
} |
|||
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 { |
do { |
||
substart+=2; |
|||
close |
close=str.indexOf(']]',substart); |
||
open=str.indexOf('[[',substart); |
|||
if (close <= open || open == -1) { |
|||
if (close<=open||open==-1) { |
|||
if (close==-1) return str; |
|||
return html + html_entities(str.substr(start)); |
|||
substart=close; |
|||
substart = close + 9; |
|||
if (nestlev) { |
if (nestlev) { |
||
nestlev--; |
nestlev--; |
||
} else { |
} else { |
||
wiki=str.substring(start,close+2); |
|||
lastend = substart; |
|||
html |
html=parse_image(wiki); |
||
str=str.replace(wiki,html); |
|||
substart=start+html.length; |
|||
loop=false; |
|||
} |
} |
||
} else { |
} else { |
||
substart |
substart=open; |
||
nestlev++; |
nestlev++; |
||
} |
} |
||
} while ( |
} while (loop); |
||
} |
|||
} else break; |
|||
return html + parse_inline_wiki(str.substr(lastend)); |
|||
} |
} |
||
//</NOLITE> |
|||
function parse_inline_images(str) { |
|||
return str; |
|||
var start, |
|||
} |
|||
substart = 0, |
|||
nestlev = 0; |
|||
var loop, close, open, wiki, html; |
|||
// the output of this function doesn't respect the FILO structure of HTML |
|||
while ((start = str.indexOf('[[', substart)) != -1) { |
|||
// but since most browsers can handle it I'll save myself the hassle |
|||
if ( |
|||
function parse_inline_formatting(str) |
|||
str.substr(start + 2).match(RegExp('^(Image|File|' + Insta.conf.locale.image + '):', 'i')) |
|||
{ |
|||
) { |
|||
var em,st,i,li,o=''; |
|||
loop = true; |
|||
while ((i=str.indexOf("''",li))+1) { |
|||
substart = start; |
|||
o += str.substring(li,i); |
|||
do { |
|||
li=i+2; |
|||
if (str.charAt(i+2)=="'") { |
|||
li++; |
|||
open = str.indexOf('[[', substart); |
|||
st=!st; |
|||
if (close <= open || open == -1) { |
|||
o+=st?'<strong>':'</strong>'; |
|||
if (close == -1) { |
|||
} else { |
|||
return str; |
|||
em=!em; |
|||
o+=em?'<em>':'</em>'; |
|||
substart = close; |
|||
if (nestlev) { |
|||
nestlev--; |
|||
} else { |
|||
wiki = str.substring(start, close + 2); |
|||
html = parse_image(wiki); |
|||
str = str.replace(wiki, html); |
|||
substart = start + html.length; |
|||
loop = false; |
|||
} |
|||
} else { |
|||
substart = open; |
|||
nestlev++; |
|||
} |
|||
} while (loop); |
|||
} else { |
|||
break; |
|||
} |
|||
} |
} |
||
return str; |
|||
} |
} |
||
return o+str.substr(li); |
|||
} |
|||
function parse_inline_wiki(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 |
|||
var aux_match; |
|||
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); |
|||
} |
|||
str = parse_inline_images(str); |
|||
str = parse_inline_formatting(str); |
|||
// math |
|||
str = str.replace(/<(?:)math>(.*?)<\/math>/ig, function(_,p1){ |
|||
return f("<img src='?.png'>", Insta.conf.paths.math+hex_md5(p1)); |
|||
}); |
|||
// 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()); |
|||
minutes = '0' + minutes; |
|||
} |
|||
date = f( |
|||
'?:?, ? ? ? (UTC)', |
|||
date.getUTCHours(), |
|||
minutes, |
|||
date.getUTCDate(), |
|||
Insta.conf.locale.months[date.getUTCMonth()], |
|||
date.getUTCFullYear() |
|||
); |
|||
// text formatting |
|||
return str. |
|||
// signatures |
|||
str |
|||
replace(/~{5}(?!~)/g, date). |
|||
// signatures |
|||
replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date). |
|||
replace(/~{3}(?!~)/g, Insta.conf.user.name). |
|||
.replace(/~{3}(?!~)/g, Insta.conf.user.name) |
|||
// [[:Category:...]], [[:Image:...]], etc... |
|||
.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('__NOINDEX__', '') |
|||
.replace('__INDEX__', '') |
|||
.replace('__NOEDITSECTION__', '') |
|||
; |
|||
return parse_inline_formatting(str); |
|||
} |
|||
// [[:Category:...]], [[:Image:...]], etc... |
|||
// begin parsing |
|||
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));}). |
|||
for (; remain(); ) { |
|||
// remove straight category and interwiki tags |
|||
if (compareLineStringOrReg(/^(={1,6})(.*)\1(.*)$/)) { |
|||
replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),''). |
|||
p = 0; |
|||
endl(f('<h?>?</h?>?', r[1].length, parse_inline_nowiki(r[2]), r[1].length, r[3])); |
|||
} else if (compareLineStringOrReg(/^[*#:;]/)) { |
|||
p = 0; |
|||
parse_list(); |
|||
} else if (compareLineStringOrReg(' ')) { |
|||
p = 0; |
|||
parse_pre(); |
|||
} else if (compareLineStringOrReg('{|')) { |
|||
p = 0; |
|||
parse_table(); |
|||
} else if (compareLineStringOrReg(/^----+$/)) { |
|||
p = 0; |
|||
endl('<hr />'); |
|||
} else if (compareLineStringOrReg(Insta.BLOCK_IMAGE)) { |
|||
p = 0; |
|||
parse_block_image(); |
|||
} else { |
|||
// handle paragraphs |
|||
if (compareLineString('')) { |
|||
p = remain() > 1 && ll[1] === ''; |
|||
if (p) { |
|||
endl('<p><br>'); |
|||
} |
|||
} else { |
|||
if (!p) { |
|||
ps('<p>'); |
|||
p = 1; |
|||
} |
|||
ps(parse_inline_nowiki(ll[0]) + ' '); |
|||
} |
|||
// [[:Category:...|Links]], [[:Image:...|Links]], etc... |
|||
sh(); |
|||
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]] |
|||
return o; |
|||
replace(/\[\[(\/[^|]*?)\]\]/g, function($0,$1){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($1)); }). |
|||
}; |
|||
// [[/Replaced|Relative links]] |
|||
function wiki2html(txt, baseurl) { |
|||
replace(/\[\[(\/.*?)\|(.+?)\]\]/g, function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($2)); }). |
|||
Insta.conf.baseUrl = baseurl; |
|||
return Insta.convert(txt); |
|||
} |
|||
// ENDFILE: livepreview.js |
|||
// [[Common links]] |
|||
// STARTFILE: pageinfo.js |
|||
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)); }). |
|||
function popupFilterPageSize(data) { |
|||
return formatBytes(data.length); |
|||
} |
|||
// [[Replaced|Links]] |
|||
function popupFilterCountLinks(data) { |
|||
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)); }). |
|||
var num = countLinks(data); |
|||
return String(num) + ' ' + (num != 1 ? popupString('wikiLinks') : popupString('wikiLink')); |
|||
} |
|||
// [[Stripped:Namespace|Namespace]] |
|||
function popupFilterCountImages(data) { |
|||
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)); }). |
|||
var num = countImages(data); |
|||
return String(num) + ' ' + (num != 1 ? popupString('images') : popupString('image')); |
|||
} |
|||
// External links |
|||
function popupFilterCountCategories(data) { |
|||
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)); }). |
|||
var num = countCategories(data); |
|||
replace(/\[http:\/\/(.*?)\]/g, function($0,$1){return f("<a class='external' href='http://?'>[#]</a>", htmlescape_attr($1)); }). |
|||
return ( |
|||
replace(/\[(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($1), htmlescape_text($2) + htmlescape_text($3)); }). |
|||
String(num) + ' ' + (num != 1 ? popupString('categories') : popupString('category')) |
|||
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__',''). |
|||
function popupFilterLastModified(data, download) { |
|||
replace('__NOEDITSECTION__',''); |
|||
var lastmod = download.lastModified; |
|||
var now = new Date(); |
|||
var age = now - lastmod; |
|||
if (lastmod && getValueOf('popupLastModified')) { |
|||
return tprintf('%s old', [formatAge(age)]).replace(/ /g, ' '); |
|||
} |
|||
return ''; |
|||
} |
} |
||
/* |
|||
*/ |
|||
function popupFilterWikibaseItem(data, download) { |
|||
function strip_inline_wiki(str) |
|||
return download.wikibaseItem ? |
|||
{ |
|||
tprintf('<a href="%s">%s</a>', [ |
|||
return str |
|||
download.wikibaseRepo.replace(/\$1/g, download.wikibaseItem), |
|||
.replace(/\[\[[^\]]*\|(.*?)\]\]/g,'$1') |
|||
download.wikibaseItem, |
|||
.replace(/\[\[(.*?)\]\]/g,'$1') |
|||
]) : |
|||
.replace(/''(.*?)''/g,'$1'); |
|||
''; |
|||
} |
} |
||
// begin parsing |
|||
function formatAge(age) { |
|||
for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) { |
|||
// coerce into a number |
|||
p=0; |
|||
endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3])); |
|||
aa = a; |
|||
} else if ($(/^[*#:;]/)) { |
|||
var seclen = 1000; |
|||
p=0; |
|||
var minlen = 60 * seclen; |
|||
parse_list(); |
|||
var hourlen = 60 * minlen; |
|||
var daylen = 24 * hourlen; |
|||
var weeklen = 7 * daylen; |
|||
} else if ($(' ')) { |
|||
var numweeks = (a - (a % weeklen)) / weeklen; |
|||
p=0; |
|||
a = a - numweeks * weeklen; |
|||
parse_pre(); |
|||
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'); |
|||
} else if ($('{|')) { |
|||
p=0; |
|||
return sweeks; |
|||
parse_table(); |
|||
} |
|||
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; |
|||
} |
|||
} else if ($(/^----+$/)) { |
|||
function addunit(num, str) { |
|||
p=0; |
|||
return String(num) + ' ' + (num != 1 ? popupString(str + 's') : popupString(str)); |
|||
endl('<hr />'); |
|||
} |
|||
} else if ($(Insta.BLOCK_IMAGE)) { |
|||
function runPopupFilters(list, data, download) { |
|||
p=0; |
|||
parse_block_image(); |
|||
for (var i = 0; i < list.length; ++i) { |
|||
if (list[i] && typeof list[i] == 'function') { |
|||
} else { |
|||
var s = list[i](data, download, download.owner.article); |
|||
if (s) { |
|||
// handle paragraphs |
|||
ret.push(s); |
|||
if ($$('')) { |
|||
} |
|||
p = (remain()>1 && ll[1]===('')); |
|||
if (p) endl('<p><br>'); |
|||
} else { |
|||
if(!p) { |
|||
ps('<p>'); |
|||
p=1; |
|||
} |
} |
||
ps(parse_inline_nowiki(ll[0]) + ' '); |
|||
} |
} |
||
return ret; |
|||
sh(); |
|||
} |
} |
||
return o; |
|||
function getPageInfo(data, download) { |
|||
}; |
|||
if (!data || data.length === 0) { |
|||
return popupString('Empty page'); |
|||
} |
|||
function wiki2html(txt,baseurl) { |
|||
var popupFilters = getValueOf('popupFilters') || []; |
|||
Insta.conf.baseUrl=baseurl; |
|||
var extraPopupFilters = getValueOf('extraPopupFilters') || []; |
|||
return Insta.convert(txt); |
|||
var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download); |
|||
} |
|||
// ENDFILE: livepreview.js |
|||
// STARTFILE: pageinfo.js |
|||
//<NOLITE> |
|||
function popupFilterPageSize(data) { |
|||
return formatBytes(data.length); |
|||
} |
|||
function popupFilterCountLinks(data) { |
|||
var pageInfo = pageInfoArray.join(', '); |
|||
var num=countLinks(data); |
|||
if (pageInfo !== '') { |
|||
return String(num) + ' ' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink')); |
|||
pageInfo = upcaseFirst(pageInfo); |
|||
} |
|||
return pageInfo; |
|||
} |
|||
function popupFilterCountImages(data) { |
|||
// this could be improved! |
|||
var num=countImages(data); |
|||
function countLinks(wikiText) { |
|||
return String(num) + ' ' + ((num!=1)?popupString('images'):popupString('image')); |
|||
return wikiText.split('[[').length - 1; |
|||
} |
|||
function popupFilterCountCategories(data) { |
|||
// if N = # matches, n = # brackets, then |
|||
var num=countCategories(data); |
|||
// String.parenSplit(regex) intersperses the N+1 split elements |
|||
return String(num) + ' ' + ((num!=1)?popupString('categories'):popupString('category')); |
|||
// 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 popupFilterLastModified(data,download) { |
|||
var lastmod=download.lastModified; |
|||
return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1); |
|||
var now=new Date(); |
|||
var age=now-lastmod; |
|||
if (lastmod && getValueOf('popupLastModified')) { |
|||
return (tprintf('%s old', [formatAge(age)])).replace(RegExp(' ','g'), ' '); |
|||
} |
} |
||
return ''; |
|||
} |
|||
function formatAge(age) { |
|||
// coerce into a number |
|||
var counts = stubCount(data, article); |
|||
var a=0+age, aa=a; |
|||
if (counts.real) { |
|||
return popupString('stub'); |
|||
var seclen = 1000; |
|||
} |
|||
var minlen = 60*seclen; |
|||
if (counts.sect) { |
|||
var hourlen = 60*minlen; |
|||
return popupString('section stub'); |
|||
var daylen = 24*hourlen; |
|||
} |
|||
var weeklen = 7*daylen; |
|||
return ''; |
|||
} |
|||
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; } |
|||
function popupFilterDisambigDetect(data, download, article) { |
|||
if (aa > weeklen) { return sweeks + ' ' + sdays; } |
|||
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { |
|||
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 isDisambig(data, article) ? popupString('disambig') : ''; |
|||
} |
} |
||
return ret; |
|||
} |
|||
function getPageInfo(data, download) { |
|||
if (!data || data.length === 0) { return popupString('Empty page'); } |
|||
return num > 949 ? |
|||
Math.round(num / 100) / 10 + popupString('kB') : |
|||
num + ' ' + popupString('bytes'); |
|||
} |
|||
// ENDFILE: pageinfo.js |
|||
var popupFilters=getValueOf('popupFilters') || []; |
|||
// STARTFILE: titles.js |
|||
var extraPopupFilters = getValueOf('extraPopupFilters') || []; |
|||
/** |
|||
var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download); |
|||
* @file 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. |
|||
*/ |
|||
var pageInfo=pageInfoArray.join(', '); |
|||
/** |
|||
if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); } |
|||
* Creates a new Stringwrapper. |
|||
return pageInfo; |
|||
* @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 {number} |
|||
*/ |
|||
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; |
|||
// this could be improved! |
|||
/** |
|||
function countLinks(wikiText) { return wikiText.split('[[').length - 1; } |
|||
* 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 = ''; |
|||
// if N = # matches, n = # brackets, then |
|||
this.setUtf(val); |
|||
// String.parenSplit(regex) intersperses the N+1 split elements |
|||
} |
|||
// with Nn other elements. So total length is |
|||
Title.prototype = new Stringwrapper(); |
|||
// L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1). |
|||
/** |
|||
* 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; |
|||
var value; |
|||
for (var j = 1; j < len; j += 2) { |
|||
// FIXME s/decodeURI/decodeURIComponent/g ? |
|||
value = split[j].split('.').join('%'); |
|||
try { |
|||
value = decodeURIComponent(value); |
|||
} catch (e) { |
|||
// cannot decode |
|||
} |
|||
split[j] = value.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; |
|||
} |
|||
function countImages(wikiText) { |
|||
// NOTE : playing with decodeURI, encodeURI, escape, unescape, |
|||
return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1); |
|||
// we seem to be able to replicate the IE borked encoding |
|||
} |
|||
function countCategories(wikiText) { |
|||
// IE doesn't do this new-fangled utf-8 thing. |
|||
return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1); |
|||
// 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 |
|||
function popupFilterStubDetect(data, download, article) { |
|||
// we fix up & for all browsers, just in case. |
|||
var counts=stubCount(data, article); |
|||
var splitted = h.split('?'); |
|||
if (counts.real) { return popupString('stub'); } |
|||
splitted[0] = splitted[0].split('&').join('%26'); |
|||
if (counts.sect) { return popupString('section stub'); } |
|||
return ''; |
|||
} |
|||
function popupFilterDisambigDetect(data, download, article) { |
|||
h = splitted.join('?'); |
|||
if (getValueOf('popupOnlyArticleDabStub') && article.namespace()) { return ''; } |
|||
return (isDisambig(data, article)) ? popupString('disambig') : ''; |
|||
} |
|||
function formatBytes(num) { |
|||
var contribs = pg.re.contribs.exec(h); |
|||
return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +' ' + popupString('bytes')) ; |
|||
if (contribs) { |
|||
} |
|||
if (contribs[1] == 'title=') { |
|||
//</NOLITE> |
|||
contribs[3] = contribs[3].split('+').join(' '); |
|||
// ENDFILE: pageinfo.js |
|||
} |
|||
// STARTFILE: titles.js |
|||
var u = new Title(contribs[3]); |
|||
/** |
|||
this.setUtf( |
|||
@fileoverview Defines the {@link Title} class, and associated crufty functions. |
|||
this.decodeNasties( |
|||
mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + u.stripNamespace() |
|||
) |
|||
); |
|||
return this; |
|||
} |
|||
<code>Title</code> deals with article titles and their various |
|||
var email = pg.re.email.exec(h); |
|||
forms. {@link Stringwrapper} is the parent class of |
|||
if (email) { |
|||
<code>Title</code>, which exists simply to make things a little |
|||
this.setUtf( |
|||
neater. |
|||
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. |
|||
Creates a new Stringwrapper. |
|||
var specialdiff = pg.re.specialdiff.exec(h); |
|||
@constructor |
|||
if (specialdiff) { |
|||
this.setUtf( |
|||
this.decodeNasties( |
|||
new Title(mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Diff') |
|||
) |
|||
); |
|||
return this; |
|||
} |
|||
@class the Stringwrapper class. This base class is not really |
|||
// no more special cases to check -- |
|||
useful on its own; it just wraps various common string operations. |
|||
// hopefully it's not a disguised user-related or specially treated special page |
|||
*/ |
|||
// Includes references |
|||
function Stringwrapper() { |
|||
var m = pg.re.main.exec(h); |
|||
/** |
|||
if (m === null) { |
|||
Wrapper for this.toString().indexOf() |
|||
this.value = null; |
|||
@param {String} x |
|||
} else { |
|||
@type integer |
|||
var fromBotInterface = /[?](.+[&])?title=/.test(h); |
|||
*/ |
|||
if (fromBotInterface) { |
|||
this.indexOf=function(x){return this.toString().indexOf(x);}; |
|||
m[2] = m[2].split('+').join('_'); |
|||
/** |
|||
} |
|||
Returns this.value. |
|||
var extracted = m[2] + (m[3] ? '#' + m[3] : ''); |
|||
@type String |
|||
if (pg.flag.isSafari && /%25[0-9A-Fa-f]{2}/.test(extracted)) { |
|||
*/ |
|||
// Fix Safari issue |
|||
this.toString=function(){return this.value;}; |
|||
// Safari sometimes encodes % as %25 in UTF-8 encoded strings like %E5%A3 -> %25E5%25A3. |
|||
/** |
|||
this.setUtf(decodeURIComponent(unescape(extracted))); |
|||
Wrapper for {@link String#parenSplit} applied to this.toString() |
|||
} else { |
|||
@param {RegExp} x |
|||
this.setUtf(this.decodeNasties(extracted)); |
|||
@type Array |
|||
} |
|||
*/ |
|||
} |
|||
this.parenSplit=function(x){return this.toString().parenSplit(x);}; |
|||
return this; |
|||
/** |
|||
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); |
|||
}; |
}; |
||
/** |
|||
Title.prototype.decodeNasties = function (txt) { |
|||
Wrapper for this.toString().split() |
|||
// myDecodeURI uses decodeExtras, which removes _, |
|||
@param {String} x |
|||
// thus ruining citations previews, which are formated as "cite_note-1" |
|||
@type Array |
|||
try { |
|||
*/ |
|||
var ret = decodeURI(this.decodeEscapes(txt)); |
|||
this.split=function(x){return this.toString().split(x);}; |
|||
ret = ret.replace(/[_ ]*$/, ''); |
|||
/** |
|||
return ret; |
|||
Wrapper for this.toString().replace() |
|||
} catch (e) { |
|||
@param {String} x |
|||
return txt; // cannot decode |
|||
@param {String} y |
|||
} |
|||
@type String |
|||
}; |
|||
*/ |
|||
// Decode valid %-encodings, otherwise escape them |
|||
this.replace=function(x,y){ return this.toString().replace(x,y); }; |
|||
Title.prototype.decodeEscapes = function (txt) { |
|||
} |
|||
var split = txt.parenSplit(/((?:[%][0-9A-Fa-f]{2})+)/); |
|||
var len = split.length; |
|||
// No %-encoded items found, so replace the literal % |
|||
if (len === 1) { |
|||
return split[0].replace(/%(?![0-9a-fA-F][0-9a-fA-F])/g, '%25'); |
|||
} |
|||
for (var i = 1; i < len; i = i + 2) { |
|||
split[i] = decodeURIComponent(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); |
|||
}; |
|||
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; |
|||
Creates a new <code>Title</code>. |
|||
return null; |
|||
@constructor |
|||
}; |
|||
// 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; |
|||
}; |
|||
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; |
|||
} |
|||
@class The Title class. Holds article titles and converts them into |
|||
var namespaceId = this.namespaceId(); |
|||
various forms. Also deals with anchors, by which we mean the bits |
|||
if (namespaceId >= 0 && namespaceId % 2 == 1) { |
|||
of the article URL after a # character, representing locations |
|||
//non-special and talk namespace |
|||
within an article. |
|||
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; |
|||
} |
|||
} |
|||
@param {String} value The initial value to assign to the |
|||
this.value = null; |
|||
article. This must be the canonical title (see {@link |
|||
return null; |
|||
Title#value}. Omit this in the constructor and use another function |
|||
}; |
|||
to set the title if this is unavailable. |
|||
Title.prototype.articleFromTalkPage = function () { |
|||
*/ |
|||
var t = new Title(this.value); |
|||
function Title(val) { |
|||
t.toArticleFromTalkPage(); |
|||
/** |
|||
if (t.value) { |
|||
The canonical article title. This must be in UTF-8 with no |
|||
return t; |
|||
entities, escaping or nasties. Also, underscores should be |
|||
} |
|||
replaced with spaces. |
|||
return null; |
|||
@type String |
|||
}; |
|||
@private |
|||
Title.prototype.articleFromTalkOrArticle = function () { |
|||
*/ |
|||
var t = new Title(this.value); |
|||
this.value=null; |
|||
if (t.toArticleFromTalkPage()) { |
|||
/** |
|||
return t; |
|||
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; |
return this; |
||
} |
} |
||
Title.prototype.isIpUser = function () { |
|||
return pg.re.ipUser.test(this.userName()); |
|||
}; |
|||
Title.prototype.stripNamespace = function () { |
|||
// returns a string, not a Title |
|||
var n = this.value.indexOf(':'); |
|||
if (n < 0) { |
|||
return this.value; |
|||
} |
|||
var 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(); |
|||
}; |
|||
// NOTE : playing with decodeURI, encodeURI, escape, unescape, |
|||
function parseParams(url) { |
|||
// we seem to be able to replicate the IE borked encoding |
|||
var specialDiff = pg.re.specialdiff.exec(url); |
|||
if (specialDiff) { |
|||
// IE doesn't do this new-fangled utf-8 thing. |
|||
var split = specialDiff[1].split('/'); |
|||
// and it's worse than that. |
|||
if (split.length == 1) { |
|||
// IE seems to treat the query string differently to the rest of the url |
|||
return { oldid: split[0], diff: 'prev' }; |
|||
// the query is treated as bona-fide utf8, but the first bit of the url is pissed around with |
|||
} else if (split.length == 2) { |
|||
return { oldid: split[0], diff: split[1] }; |
|||
} |
|||
} |
|||
// we fix up & for all browsers, just in case. |
|||
var ret = {}; |
|||
var splitted=h.split('?'); |
|||
if (url.indexOf('?') == -1) { |
|||
splitted[0]=splitted[0].split('&').join('%26'); |
|||
return ret; |
|||
} |
|||
if (pg.flag.linksLikeIE6) { |
|||
url = url.split('#')[0]; |
|||
splitted[0]=encodeURI(decode_utf8(splitted[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; |
|||
} |
} |
||
h=splitted.join('?'); |
|||
// (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup) |
|||
// (b) change spaces to underscores |
|||
// (c) encodeURI (just the straight one, no pg.re.urlNoPopup) |
|||
var contribs=pg.re.contribs.exec(h); |
|||
function myDecodeURI(str) { |
|||
if (contribs) { |
|||
var ret; |
|||
if (contribs[1]=='title=') { contribs[3]=contribs[3].split('+').join(' '); } |
|||
// FIXME decodeURIComponent?? |
|||
var u=new Title(contribs[3]); |
|||
try { |
|||
this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + u.stripNamespace())); |
|||
ret = decodeURI(str.toString()); |
|||
return this; |
|||
} 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; |
|||
} |
} |
||
var email=pg.re.email.exec(h); |
|||
function safeDecodeURI(str) { |
|||
if (email) { |
|||
var ret = myDecodeURI(str); |
|||
this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + new Title(email[3]).stripNamespace())); |
|||
return ret || str; |
|||
return this; |
|||
} |
} |
||
var backlinks=pg.re.backlinks.exec(h); |
|||
/////////// |
|||
if (backlinks) { |
|||
// TESTS // |
|||
this.setUtf(this.decodeNasties(new Title(backlinks[3]))); |
|||
/////////// |
|||
return this; |
|||
} |
|||
//A dummy title object for a Special:Diff link. |
|||
function isDisambig(data, article) { |
|||
var specialdiff=pg.re.specialdiff.exec(h); |
|||
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { |
|||
if (specialdiff) { |
|||
return false; |
|||
this.setUtf(this.decodeNasties(new Title(mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Diff'))); |
|||
} |
|||
return this; |
|||
return !article.isTalkPage() && pg.re.disambig.test(data); |
|||
} |
} |
||
// no more special cases to check -- |
|||
function stubCount(data, article) { |
|||
// hopefully it's not a disguised user-related or specially treated special page |
|||
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { |
|||
var m=pg.re.main.exec(h); |
|||
return false; |
|||
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] : ''); |
|||
var sectStub = 0; |
|||
if (pg.flag.isSafari && /%25[0-9A-Fa-f]{2}/.test(extracted)) { |
|||
var realStub = 0; |
|||
// Fix Safari issue |
|||
if (pg.re.stub.test(data)) { |
|||
// Safari sometimes encodes % as %25 in UTF-8 encoded strings like %E5%A3 -> %25E5%25A3. |
|||
var s = data.parenSplit(pg.re.stub); |
|||
this.setUtf(decodeURIComponent(unescape(extracted))); |
|||
for (var i = 1; i < s.length; i = i + 2) { |
|||
} else { |
|||
this.setUtf(this.decodeNasties(extracted)); |
|||
++sectStub; |
|||
} else { |
|||
++realStub; |
|||
} |
|||
} |
|||
} |
} |
||
return { real: realStub, sect: sectStub }; |
|||
} |
} |
||
return this; |
|||
}; |
|||
function isValidImageName(str) { |
|||
Title.prototype.decodeNasties=function(txt) { |
|||
// extend as needed... |
|||
var ret= this.decodeEscapes(decodeURI(txt)); |
|||
return str.indexOf('{') == -1; |
|||
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(''); |
|||
}; |
|||
function isInStrippableNamespace(article) { |
|||
Title.fromAnchor=function(a) { |
|||
// Does the namespace allow subpages |
|||
return new Title().fromAnchor(a); |
|||
// Note, would be better if we had access to wgNamespacesWithSubpages |
|||
}; |
|||
return article.namespaceId() !== 0; |
|||
Title.prototype.fromAnchor=function(a) { |
|||
if (!a) { this.value=null; return this; } |
|||
return this.fromURL(a.href); |
|||
}; |
|||
Title.fromWikiText=function(txt) { |
|||
return new Title().fromWikiText(txt); |
|||
}; |
|||
Title.prototype.fromWikiText=function(txt) { |
|||
// FIXME - testing needed |
|||
if (!pg.flag.linksLikeIE6) { txt=myDecodeURI(txt); } |
|||
this.setUtf(txt); |
|||
return this; |
|||
}; |
|||
Title.prototype.hintValue=function(){ |
|||
if(!this.value) { return ''; } |
|||
return safeDecodeURI(this.value); |
|||
}; |
|||
//<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]; |
|||
}; |
|||
function isInMainNamespace(article) { |
|||
Title.prototype.userName=function(withNs) { |
|||
return article.namespaceId() === 0; |
|||
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 http://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; |
|||
function anchorContainsImage(a) { |
|||
return null; |
|||
// iterate over children of anchor a |
|||
}; |
|||
// see if any are images |
|||
//</NOLITE> |
|||
if (a === null) { |
|||
// Return canonical, localized namespace |
|||
return false; |
|||
Title.prototype.namespace=function() { |
|||
} |
|||
return mw.config.get('wgFormattedNamespaces')[this.namespaceId()]; |
|||
var kids = a.childNodes; |
|||
}; |
|||
for (var i = 0; i < kids.length; ++i) { |
|||
Title.prototype.namespaceId=function() { |
|||
if (kids[i].nodeName == 'IMG') { |
|||
var n=this.value.indexOf(':'); |
|||
return true; |
|||
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; |
|||
} |
} |
||
return false; |
|||
} |
} |
||
function isPopupLink(a) { |
|||
// NB for performance reasons, TOC links generally return true |
|||
// they should be stripped out later |
|||
this.value=null; |
|||
if (!markNopopupSpanLinks.done) { |
|||
return null; |
|||
markNopopupSpanLinks(); |
|||
}; |
|||
Title.prototype.articleFromTalkPage=function() { |
|||
if (a.inNopopupSpan) { |
|||
var t=new Title(this.value); |
|||
return false; |
|||
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=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(); |
|||
}; |
|||
// 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 paramValue(param, url) { |
|||
var s=url.parenSplit(RegExp('[?&]' + literalizeRegex(param) + '=([^?&]*)')); |
|||
if (!getValueOf('popupOnlyArticleLinks')) { |
|||
if (!url) { return null; } |
|||
fixVectorMenuPopups(); |
|||
return s[1] || null; |
|||
} |
|||
} |
|||
function parseParams(url) { |
|||
var s = $('.nopopups').toArray(); |
|||
var specialDiff = pg.re.specialdiff.exec(url); |
|||
for (var i = 0; i < s.length; ++i) { |
|||
if (specialDiff) |
|||
var as = s[i].getElementsByTagName('a'); |
|||
{ |
|||
for (var j = 0; j < as.length; ++j) { |
|||
var split= specialDiff[1].split('/'); |
|||
as[j].inNopopupSpan = true; |
|||
if (split.length==1) return {oldid:split[0], diff: 'prev'}; |
|||
} |
|||
else if (split.length==2) return {oldid: split[0], diff: split[1]}; |
|||
} |
|||
markNopopupSpanLinks.done = true; |
|||
} |
} |
||
var ret={}; |
|||
function fixVectorMenuPopups() { |
|||
if (url.indexOf('?')==-1) { return ret; } |
|||
$('nav.vector-menu h3:first a:first').prop('inNopopupSpan', true); |
|||
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 |
|||
// ENDFILE: titles.js |
|||
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; |
|||
} |
|||
// all sorts of stuff here |
|||
// STARTFILE: getpage.js |
|||
// FIXME almost everything needs to be rewritten |
|||
////////////////////////////////////////////////// |
|||
// Wiki-specific downloading |
|||
// |
|||
function oldidFromAnchor(a) { return paramValue('oldid', a.href); } |
|||
// Schematic for a getWiki call |
|||
//function diffFromAnchor(a) { return paramValue('diff', a.href); } |
|||
// |
|||
// getPageWithCaching |
|||
// | |
|||
// false | true |
|||
// getPage<-[findPictureInCache]->-onComplete(a fake download) |
|||
// \. |
|||
// (async)->addPageToCache(download)->-onComplete(download) |
|||
// check cache to see if page exists |
|||
function wikiMarkupToAddressFragment (str) { // for images |
|||
function getPageWithCaching(url, onComplete, owner) { |
|||
var ret = safeDecodeURI(str); |
|||
log('getPageWithCaching, url=' + url); |
|||
ret = ret.split(' ').join('_'); |
|||
var i = findInPageCache(url); |
|||
ret = encodeURI(ret); |
|||
var d; |
|||
return ret; |
|||
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; |
|||
} |
|||
} |
|||
} |
|||
// (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup) |
|||
function getPage(url, onComplete, owner) { |
|||
// (b) change spaces to underscores |
|||
log('getPage'); |
|||
// (c) encodeURI (just the straight one, no pg.re.urlNoPopup) |
|||
var callback = function (d) { |
|||
if (!d.aborted) { |
|||
addPageToCache(d); |
|||
onComplete(d); |
|||
} |
|||
}; |
|||
return startDownload(url, owner.idNumber, callback); |
|||
} |
|||
function myDecodeURI (str) { |
|||
var ret; |
|||
for (var i = 0; i < pg.cache.pages.length; ++i) { |
|||
// FIXME decodeURIComponent?? |
|||
if (url == pg.cache.pages[i].url) { |
|||
try { ret=decodeURI(str.toString()); } |
|||
return i; |
|||
catch (summat) { return str; } |
|||
} |
|||
for (var i=0; i<pg.misc.decodeExtras.length; ++i) { |
|||
} |
|||
var from=pg.misc.decodeExtras[i].from; |
|||
return -1; |
|||
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; } |
|||
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 |
|||
// TESTS // |
|||
////////////////////////////////////////////////// |
|||
/////////// |
|||
// parenSplit |
|||
//<NOLITE> |
|||
// String.prototype.parenSplit should do what ECMAscript says String.prototype.split does, |
|||
function isIpUser(user) {return pg.re.ipUser.test(user);} |
|||
// interspersing paren matches (regex capturing groups) between the split elements. |
|||
// i.e. 'abc'.split(/(b)/)) should return ['a','b','c'], not ['a','c'] |
|||
function isDisambig(data, article) { |
|||
if (String('abc'.split(/(b)/)) != 'a,b,c') { |
|||
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } |
|||
// broken String.split, e.g. konq, IE < 10 |
|||
return ! article.isTalkPage() && pg.re.disambig.test(data); |
|||
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 stubCount(data, article) { |
|||
if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } |
|||
var s = re.toString(); |
|||
var sectStub=0; |
|||
var realStub=0; |
|||
for (var j = s.length; s.charAt(j) != '/'; --j) { |
|||
if (pg.re.stub.test(data)) { |
|||
var s=data.parenSplit(pg.re.stub); |
|||
flags += s.charAt(j); |
|||
for (var i=1; i<s.length; i=i+2) { |
|||
} |
|||
if (s[i]) { ++sectStub; } |
|||
else { ++realStub; } |
|||
} |
} |
||
var t = s.substring(1, j); |
|||
return RegExp(t, flags); |
|||
} |
} |
||
return { real: realStub, sect: sectStub }; |
|||
// ENDFILE: parensplit.js |
|||
} |
|||
function isValidImageName(str){ // extend as needed... |
|||
// STARTFILE: tools.js |
|||
return ( str.indexOf('{') == -1 ); |
|||
// 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 |
|||
function isInStrippableNamespace(article) { |
|||
// Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm |
|||
//I believe that this method means to return whether the given article is in a namspace without subpages. Meaning, it's broken. |
|||
return ( article.namespace() !== '' ); |
|||
} |
|||
function isInMainNamespace(article) { return !isInStrippableNamespace(article); } |
|||
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 anchorContainsImage(a) { |
|||
// iterate over children of anchor a |
|||
for (var p in obj) { |
|||
// see if any are images |
|||
return obj[p]; |
|||
if (a === null) { return false; } |
|||
} |
|||
kids=a.childNodes; |
|||
return null; |
|||
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')) |
|||
if (typeof str != typeof '' || str === '') { |
|||
fixVectorMenuPopups(); |
|||
return ''; |
|||
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; |
|||
} |
} |
||
return str.charAt(0).toUpperCase() + str.substring(1); |
|||
} |
} |
||
markNopopupSpanLinks.done=true; |
|||
} |
|||
function fixVectorMenuPopups() { |
|||
$('div.vectorMenu h3:first a:first').prop('inNopopupSpan', true); |
|||
if (!arr || !arr.length) { |
|||
} |
|||
return -1; |
|||
// ENDFILE: titles.js |
|||
// STARTFILE: cookies.js |
|||
//<NOLITE> |
|||
////////////////////////////////////////////////// |
|||
// Cookie handling |
|||
// from http://www.quirksmode.org/js/cookies.html |
|||
var Cookie= { |
|||
create: function(name,value,days) |
|||
{ |
|||
var expires; |
|||
if (days) |
|||
{ |
|||
var date = new Date(); |
|||
date.setTime(date.getTime()+(days*24*60*60*1000)); |
|||
expires = "; expires="+date.toGMTString(); |
|||
} |
} |
||
else { expires = ""; } |
|||
document.cookie = name+"="+value+expires+"; path=/"; |
|||
for (var i = 0; i < len; ++i) { |
|||
}, |
|||
if (arr[i] == foo) { |
|||
return i; |
|||
} |
|||
} |
|||
return -1; |
|||
} |
|||
read: function(name) |
|||
/* eslint-disable no-unused-vars */ |
|||
{ |
|||
function nextOne(array, value) { |
|||
var nameEQ = name + "="; |
|||
// NB if the array has two consecutive entries equal |
|||
var ca = document.cookie.split(';'); |
|||
// then this will loop on successive calls |
|||
var i |
for(var i=0;i < ca.length;i++) |
||
{ |
|||
var c = ca[i]; |
|||
while (c.charAt(0)==' ') { c = c.substring(1,c.length); } |
|||
if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); } |
|||
} |
} |
||
return |
return null; |
||
} |
}, |
||
/* eslint-enable no-unused-vars */ |
|||
function |
erase: function(name) |
||
{ |
|||
return mw.util.escapeRegExp(str); |
|||
Cookie.create(name,"",-1); |
|||
} |
} |
||
}; |
|||
//</NOLITE> |
|||
// ENDFILE: cookies.js |
|||
// STARTFILE: getpage.js |
|||
////////////////////////////////////////////////// |
|||
// Wiki-specific downloading |
|||
// |
|||
// Schematic for a getWiki call |
|||
String.prototype.entify = function () { |
|||
// |
|||
//var shy='­'; |
|||
// getWiki->-getPageWithCaching |
|||
return this.split('&') |
|||
// | |
|||
.join('&') |
|||
// false | true |
|||
.split('<') |
|||
// getPage<-[findPictureInCache]->-onComplete(a fake download) |
|||
.join('<') |
|||
// \. |
|||
.split('>') |
|||
// (async)->addPageToCache(download)->-onComplete(download) |
|||
.join('>' /*+shy*/) |
|||
.split('"') |
|||
.join('"'); |
|||
}; |
|||
// Array filter function |
|||
function removeNulls(val) { |
|||
return val !== null; |
|||
} |
|||
/** @todo {document} |
|||
function joinPath(list) { |
|||
@param {Title} article |
|||
return list.filter(removeNulls).join('/'); |
|||
@param {Function} onComplete |
|||
} |
|||
@param {integer} oldid |
|||
@param {Navapopup} owner |
|||
*/ |
|||
function getWiki(article, onComplete, oldid, owner) { |
|||
// set ctype=text/css to get around opera gzip bug |
|||
var url = pg.wiki.titlebase; |
|||
if (article.namespaceId() >= 0) |
|||
url += article.removeAnchor().urlString(); |
|||
if (oldid || oldid === 0 || oldid==='0') |
|||
url += '&oldid='+oldid; |
|||
url += '&action=raw'; |
|||
getPageWithCaching(url, onComplete, owner); |
|||
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(''); |
|||
} |
|||
// check cache to see if page exists |
|||
/* eslint-disable no-unused-vars */ |
|||
function isString(x) { |
|||
return typeof x === 'string' || x instanceof String; |
|||
} |
|||
function getPageWithCaching(url, onComplete, owner) { |
|||
log('getPageWithCaching, url='+url); |
|||
return typeof x === 'number' || x instanceof Number; |
|||
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'); |
|||
return x instanceof RegExp; |
|||
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) { |
|||
return x instanceof Array; |
|||
if (url==pg.cache.pages[i].url) { return i; } |
|||
} |
} |
||
return -1; |
|||
} |
|||
function addPageToCache(download) { |
|||
log('addPageToCache '+download.url); |
|||
return x instanceof Object; |
|||
var page = {url: download.url, data: download.data, lastModified: download.lastModified}; |
|||
} |
|||
return pg.cache.pages.push(page); |
|||
} |
|||
// ENDFILE: getpage.js |
|||
// STARTFILE: md5-2.2alpha.js |
|||
//<NOLITE> |
|||
/* |
|||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message |
|||
* Digest Algorithm, as defined in RFC 1321. |
|||
* Version 2.2-alpha Copyright (C) Paul Johnston 1999 - 2005 |
|||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet |
|||
* Distributed under the BSD License |
|||
* See http://pajhome.org.uk/crypt/md5 for more info. |
|||
*/ |
|||
/* |
|||
function isFunction(x) { |
|||
* Configurable variables. You may need to tweak these to be compatible with |
|||
return !isRegExp(x) && (typeof x === 'function' || x instanceof Function); |
|||
* the server-side, but the defaults work in most cases. |
|||
} |
|||
*/ |
|||
/* eslint-enable no-unused-vars */ |
|||
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ |
|||
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ |
|||
/* |
|||
function repeatString(s, mult) { |
|||
* These are the functions you'll usually want to call |
|||
var ret = ''; |
|||
* They take string arguments and return either hex or base-64 encoded strings |
|||
for (var i = 0; i < mult; ++i) { |
|||
*/ |
|||
ret += s; |
|||
function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); } |
|||
} |
|||
function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); } |
|||
return ret; |
|||
function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); } |
|||
} |
|||
function hex_hmac_md5(k, d) |
|||
{ return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } |
|||
function b64_hmac_md5(k, d) |
|||
{ return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } |
|||
function any_hmac_md5(k, d, e) |
|||
{ return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } |
|||
/* |
|||
function zeroFill(s, min) { |
|||
* Perform a simple self-test to see if the VM is working |
|||
min = min || 2; |
|||
*/ |
|||
var t = s.toString(); |
|||
function md5_vm_test() |
|||
return repeatString('0', min - t.length) + t; |
|||
{ |
|||
} |
|||
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; |
|||
} |
|||
/* |
|||
function map(f, o) { |
|||
* Calculate the MD5 of a raw string |
|||
if (isArray(o)) { |
|||
*/ |
|||
return map_array(f, o); |
|||
function rstr_md5(s) |
|||
} |
|||
{ |
|||
return map_object(f, o); |
|||
return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); |
|||
} |
|||
} |
|||
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) { |
|||
* Calculate the HMAC-MD5, of a key and some data (raw strings) |
|||
return text |
|||
*/ |
|||
.replace(/&/g, '&') |
|||
function rstr_hmac_md5(key, data) |
|||
.replace(/"/g, '"') |
|||
{ |
|||
.replace(/</g, '<') |
|||
var bkey = rstr2binl(key); |
|||
.replace(/>/g, '>'); |
|||
if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); |
|||
}; |
|||
var ipad = Array(16), opad = Array(16); |
|||
pg.unescapeQuotesHTML = function (html) { |
|||
for(var i = 0; i < 16; i++) |
|||
// From https://stackoverflow.com/a/7394787 |
|||
{ |
|||
// This seems to be implemented correctly on all major browsers now, so we |
|||
ipad[i] = bkey[i] ^ 0x36363636; |
|||
// don't have to make our own function. |
|||
opad[i] = bkey[i] ^ 0x5C5C5C5C; |
|||
var txt = document.createElement('textarea'); |
|||
} |
|||
txt.innerHTML = html; |
|||
return txt.value; |
|||
}; |
|||
var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); |
|||
// ENDFILE: tools.js |
|||
return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); |
|||
} |
|||
/* |
|||
// STARTFILE: dab.js |
|||
* Convert a raw string to a hex string |
|||
////////////////////////////////////////////////// |
|||
*/ |
|||
// Dab-fixing code |
|||
function rstr2hex(input) |
|||
// |
|||
{ |
|||
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; |
|||
var output = ""; |
|||
var x; |
|||
for(var i = 0; i < input.length; i++) |
|||
{ |
|||
x = input.charCodeAt(i); |
|||
output += hex_tab.charAt((x >>> 4) & 0x0F) + |
|||
hex_tab.charAt( x & 0x0F); |
|||
} |
|||
return output; |
|||
} |
|||
/* |
|||
function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) { |
|||
* Convert a raw string to a base-64 string |
|||
log('retargetDab: newTarget=' + newTarget + ' oldTarget=' + oldTarget); |
|||
*/ |
|||
return changeLinkTargetLink({ |
|||
function rstr2b64(input) |
|||
newTarget: newTarget, |
|||
{ |
|||
text: newTarget.split(' ').join(' '), |
|||
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|||
hint: tprintf('disambigHint', [newTarget]), |
|||
var output = ""; |
|||
summary: simplePrintf(getValueOf('popupFixDabsSummary'), [ |
|||
var len = input.length; |
|||
friendlyCurrentArticleName, |
|||
for(var i = 0; i < len; i += 3) |
|||
newTarget, |
|||
{ |
|||
]), |
|||
var triplet = (input.charCodeAt(i) << 16) |
|||
clickButton: getValueOf('popupDabsAutoClick'), |
|||
| (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) |
|||
minor: true, |
|||
| (i + 2 < len ? input.charCodeAt(i+2) : 0); |
|||
oldTarget: oldTarget, |
|||
for(var j = 0; j < 4; j++) |
|||
watch: getValueOf('popupWatchDisambiggedPages'), |
|||
{ |
|||
title: titleToEdit, |
|||
if(i * 8 + j * 6 > input.length * 8) output += b64pad; |
|||
}); |
|||
else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); |
|||
} |
} |
||
} |
|||
return output; |
|||
} |
|||
/* |
|||
function listLinks(wikitext, oldTarget, titleToEdit) { |
|||
* Convert a raw string to an arbitrary string encoding |
|||
// mediawiki strips trailing spaces, so we do the same |
|||
*/ |
|||
// testcase: https://en.wikipedia.org/w/index.php?title=Radial&oldid=97365633 |
|||
function rstr2any(input, encoding) |
|||
var reg = /\[\[([^|]*?) *(\||\]\])/gi; |
|||
{ |
|||
var ret = []; |
|||
var divisor = encoding.length; |
|||
var remainders = Array(); |
|||
// ^[a-z]+ should match interwiki links, hopefully (case-insensitive) |
|||
var i, q, x, quotient; |
|||
// and ^[a-z]* should match those and [[:Category...]] style links too |
|||
var omitRegex = /^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory/; |
|||
var friendlyCurrentArticleName = oldTarget.toString(); |
|||
var wikPos = getValueOf('popupDabWiktionary'); |
|||
/* Convert to an array of 16-bit big-endian values, forming the dividend */ |
|||
for (var i = 1; i < splitted.length; i = i + 3) { |
|||
var dividend = Array(input.length / 2); |
|||
if ( |
|||
for(i = 0; i < dividend.length; i++) |
|||
typeof splitted[i] == typeof 'string' && |
|||
{ |
|||
splitted[i].length > 0 && |
|||
dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); |
|||
!omitRegex.test(splitted[i]) |
|||
} |
|||
) { |
|||
ret.push(retargetDab(splitted[i], oldTarget, friendlyCurrentArticleName, titleToEdit)); |
|||
} /* if */ |
|||
} /* for loop */ |
|||
/* |
|||
ret = rmDupesFromSortedList(ret.sort()); |
|||
* Repeatedly perform a long division. The binary array forms the dividend, |
|||
* the length of the encoding is the divisor. Once computed, the quotient |
|||
* forms the dividend for the next step. We stop when the dividend is zero. |
|||
* All remainders are stored for later use. |
|||
*/ |
|||
while(dividend.length > 0) |
|||
{ |
|||
quotient = Array(); |
|||
x = 0; |
|||
for(i = 0; i < dividend.length; i++) |
|||
{ |
|||
x = (x << 16) + dividend[i]; |
|||
q = Math.floor(x / divisor); |
|||
x -= q * divisor; |
|||
if(quotient.length > 0 || q > 0) |
|||
quotient[quotient.length] = q; |
|||
} |
|||
remainders[remainders.length] = x; |
|||
dividend = quotient; |
|||
} |
|||
/* Convert the remainders to the output string */ |
|||
if (wikPos) { |
|||
var output = ""; |
|||
for(i = remainders.length - 1; i >= 0; i--) |
|||
'wiktionary:' + |
|||
output += encoding.charAt(remainders[i]); |
|||
friendlyCurrentArticleName.replace(/^(.+)\s+[(][^)]+[)]\s*$/, '$1'); |
|||
return output; |
|||
var meth; |
|||
} |
|||
if (wikPos.toLowerCase() == 'first') { |
|||
meth = 'unshift'; |
|||
} else { |
|||
meth = 'push'; |
|||
} |
|||
/* |
|||
ret[meth](retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit)); |
|||
* Encode a string as utf-8. |
|||
} |
|||
* For efficiency, this assumes the input is valid utf-16. |
|||
*/ |
|||
function str2rstr_utf8(input) |
|||
{ |
|||
var output = ""; |
|||
var i = -1; |
|||
var x, y; |
|||
while(++i < input.length) |
|||
ret.push( |
|||
{ |
|||
changeLinkTargetLink({ |
|||
/* Decode utf-16 surrogate pairs */ |
|||
newTarget: null, |
|||
x = input.charCodeAt(i); |
|||
text: popupString('remove this link').split(' ').join(' '), |
|||
y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; |
|||
hint: popupString('remove all links to this disambig page from this article'), |
|||
if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) |
|||
clickButton: getValueOf('popupDabsAutoClick'), |
|||
{ |
|||
oldTarget: oldTarget, |
|||
x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); |
|||
summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName]), |
|||
i++; |
|||
watch: getValueOf('popupWatchDisambiggedPages'), |
|||
title: titleToEdit, |
|||
}) |
|||
); |
|||
return ret; |
|||
} |
} |
||
/* Encode output as utf-8 */ |
|||
function rmDupesFromSortedList(list) { |
|||
if(x <= 0x7F) |
|||
var ret = []; |
|||
output += String.fromCharCode(x); |
|||
for (var i = 0; i < list.length; ++i) { |
|||
else if(x <= 0x7FF) |
|||
if (ret.length === 0 || list[i] != ret[ret.length - 1]) { |
|||
output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), |
|||
ret.push(list[i]); |
|||
0x80 | ( x & 0x3F)); |
|||
} |
|||
else if(x <= 0xFFFF) |
|||
} |
|||
output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), |
|||
return ret; |
|||
0x80 | ((x >>> 6 ) & 0x3F), |
|||
} |
|||
0x80 | ( x & 0x3F)); |
|||
else if(x <= 0x1FFFFF) |
|||
output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), |
|||
0x80 | ((x >>> 12) & 0x3F), |
|||
0x80 | ((x >>> 6 ) & 0x3F), |
|||
0x80 | ( x & 0x3F)); |
|||
} |
|||
return output; |
|||
} |
|||
/* |
|||
function makeFixDab(data, navpop) { |
|||
* Encode a string as utf-16 |
|||
// grab title from parent popup if there is one; default exists in changeLinkTargetLink |
|||
*/ |
|||
var titleToEdit = navpop.parentPopup && navpop.parentPopup.article.toString(); |
|||
function str2rstr_utf16le(input) |
|||
var list = listLinks(data, navpop.originalArticle, titleToEdit); |
|||
{ |
|||
if (list.length === 0) { |
|||
var output = ""; |
|||
log('listLinks returned empty list'); |
|||
for(var i = 0; i < input.length; i++) |
|||
return null; |
|||
output += String.fromCharCode( input.charCodeAt(i) & 0xFF, |
|||
} |
|||
(input.charCodeAt(i) >>> 8) & 0xFF); |
|||
var html = '<hr />' + popupString('Click to disambiguate this link to:') + '<br>'; |
|||
return output; |
|||
html += list.join(', '); |
|||
} |
|||
return html; |
|||
} |
|||
function str2rstr_utf16be(input) |
|||
{ |
|||
if ( |
|||
var output = ""; |
|||
getValueOf('popupFixDabs') && |
|||
for(var i = 0; i < input.length; i++) |
|||
isDisambig(wikiText, navpop.article) && |
|||
output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, |
|||
Title.fromURL(location.href).namespaceId() != pg.nsSpecialId && |
|||
input.charCodeAt(i) & 0xFF); |
|||
navpop.article.talkPage() |
|||
return output; |
|||
) { |
|||
} |
|||
setPopupHTML(makeFixDab(wikiText, navpop), 'popupFixDab', navpop.idNumber); |
|||
} |
|||
} |
|||
/* |
|||
function popupRedlinkHTML(article) { |
|||
* Convert a raw string to an array of little-endian words |
|||
return changeLinkTargetLink({ |
|||
* Characters >255 have their high-byte silently ignored. |
|||
newTarget: null, |
|||
*/ |
|||
text: popupString('remove this link').split(' ').join(' '), |
|||
function rstr2binl(input) |
|||
hint: popupString('remove all links to this page from this article'), |
|||
{ |
|||
clickButton: getValueOf('popupRedlinkAutoClick'), |
|||
var output = Array(input.length >> 2); |
|||
oldTarget: article.toString(), |
|||
for(var i = 0; i < output.length; i++) |
|||
summary: simplePrintf(getValueOf('popupRedlinkSummary'), [article.toString()]), |
|||
output[i] = 0; |
|||
}); |
|||
for(i = 0; i < input.length * 8; i += 8) |
|||
} |
|||
output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); |
|||
// ENDFILE: dab.js |
|||
return output; |
|||
} |
|||
/* |
|||
// STARTFILE: htmloutput.js |
|||
* Convert an array of little-endian words to a string |
|||
*/ |
|||
function binl2rstr(input) |
|||
{ |
|||
var output = ""; |
|||
for(var i = 0; i < input.length * 32; i += 8) |
|||
output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); |
|||
return output; |
|||
} |
|||
/* |
|||
// this has to use a timer loop as we don't know if the DOM element exists when we want to set the text |
|||
* Calculate the MD5 of an array of little-endian words, and a bit length. |
|||
function setPopupHTML(str, elementId, popupId, onSuccess, append) { |
|||
*/ |
|||
if (typeof popupId === 'undefined') { |
|||
function binl_md5(x, len) |
|||
//console.error('popupId is not defined in setPopupHTML, html='+str.substring(0,100)); |
|||
{ |
|||
popupId = pg.idNumber; |
|||
/* append padding */ |
|||
} |
|||
x[len >> 5] |= 0x80 << ((len) % 32); |
|||
x[(((len + 64) >>> 9) << 4) + 14] = len; |
|||
var a = 1732584193; |
|||
var popupElement = document.getElementById(elementId + popupId); |
|||
var b = -271733879; |
|||
if (popupElement) { |
|||
var c = -1732584194; |
|||
if (!append) { |
|||
var d = 271733878; |
|||
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; |
|||
} |
|||
for(var i = 0; i < x.length; i += 16) |
|||
function setPopupTrailer(str, id) { |
|||
{ |
|||
return setPopupHTML(str, 'popupData', id); |
|||
var olda = a; |
|||
} |
|||
var oldb = b; |
|||
var oldc = c; |
|||
var oldd = d; |
|||
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); |
|||
// args.navpopup is mandatory |
|||
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); |
|||
// optional: args.redir, args.redirTarget |
|||
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); |
|||
// FIXME: ye gods, this is ugly stuff |
|||
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); |
|||
function fillEmptySpans(args) { |
|||
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); |
|||
// if redir is present and true then redirTarget is mandatory |
|||
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); |
|||
var redir = true; |
|||
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); |
|||
var rcid; |
|||
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); |
|||
if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { |
|||
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); |
|||
redir = false; |
|||
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); |
|||
} |
|||
c = md5_ff(c, d, a, b, x[i+10], 17, -42063); |
|||
var a = args.navpopup.parentAnchor; |
|||
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); |
|||
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); |
|||
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); |
|||
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); |
|||
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); |
|||
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); |
|||
var article, |
|||
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); |
|||
hint = null, |
|||
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); |
|||
oldid = null, |
|||
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); |
|||
params = {}; |
|||
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); |
|||
if (redir && typeof args.redirTarget == typeof {}) { |
|||
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); |
|||
article = args.redirTarget; |
|||
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); |
|||
//hint=article.hintValue(); |
|||
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); |
|||
} else { |
|||
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); |
|||
article = new Title().fromAnchor(a); |
|||
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); |
|||
hint = a.originalTitle || article.hintValue(); |
|||
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); |
|||
params = parseParams(a.href); |
|||
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); |
|||
oldid = getValueOf('popupHistoricalLinks') ? params.oldid : null; |
|||
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); |
|||
rcid = params.rcid; |
|||
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); |
|||
} |
|||
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); |
|||
var x = { |
|||
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); |
|||
article: article, |
|||
hint: hint, |
|||
oldid: oldid, |
|||
rcid: rcid, |
|||
navpop: args.navpopup, |
|||
params: params, |
|||
}; |
|||
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); |
|||
var structure = pg.structures[getValueOf('popupStructure')]; |
|||
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); |
|||
if (typeof structure != 'object') { |
|||
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); |
|||
setPopupHTML( |
|||
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); |
|||
'popupError', |
|||
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); |
|||
'Unknown structure (this should never happen): ' + pg.option.popupStructure, |
|||
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); |
|||
args.navpopup.idNumber |
|||
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); |
|||
); |
|||
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); |
|||
return; |
|||
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); |
|||
} |
|||
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); |
|||
var spans = flatten(pg.misc.layout); |
|||
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); |
|||
var numspans = spans.length; |
|||
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); |
|||
var redirs = pg.misc.redirSpans; |
|||
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); |
|||
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); |
|||
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); |
|||
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); |
|||
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); |
|||
for (var i = 0; i < numspans; ++i) { |
|||
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); |
|||
var found = redirs && redirs.indexOf(spans[i]) !== -1; |
|||
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); |
|||
//log('redir='+redir+', found='+found+', spans[i]='+spans[i]); |
|||
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); |
|||
if ((found && !redir) || (!found && redir)) { |
|||
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); |
|||
//log('skipping this set of the loop'); |
|||
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); |
|||
continue; |
|||
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); |
|||
} |
|||
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); |
|||
var structurefn = structure[spans[i]]; |
|||
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); |
|||
if (structurefn === undefined) { |
|||
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); |
|||
// nothing to do for this structure part |
|||
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); |
|||
continue; |
|||
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); |
|||
} |
|||
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); |
|||
var setfn = setPopupHTML; |
|||
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); |
|||
if ( |
|||
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); |
|||
getValueOf('popupActiveNavlinks') && |
|||
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); |
|||
(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; |
|||
} |
|||
} |
|||
} |
|||
a = safe_add(a, olda); |
|||
// flatten an array |
|||
b = safe_add(b, oldb); |
|||
function flatten(list, start) { |
|||
c = safe_add(c, oldc); |
|||
var ret = []; |
|||
d = safe_add(d, oldd); |
|||
if (typeof start == 'undefined') { |
|||
} |
|||
start = 0; |
|||
return Array(a, b, c, d); |
|||
} |
|||
} |
|||
for (var i = start; i < list.length; ++i) { |
|||
if (typeof list[i] == typeof []) { |
|||
/* |
|||
return ret.concat(flatten(list[i])).concat(flatten(list, i + 1)); |
|||
* These functions implement the four basic operations the algorithm uses. |
|||
} else { |
|||
*/ |
|||
ret.push(list[i]); |
|||
function md5_cmn(q, a, b, x, s, t) |
|||
{ |
|||
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); |
|||
} |
|||
function md5_ff(a, b, c, d, x, s, t) |
|||
{ |
|||
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); |
|||
} |
|||
function md5_gg(a, b, c, d, x, s, t) |
|||
{ |
|||
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); |
|||
} |
|||
function md5_hh(a, b, c, d, x, s, t) |
|||
{ |
|||
return md5_cmn(b ^ c ^ d, a, b, x, s, t); |
|||
} |
|||
function md5_ii(a, b, c, d, x, s, t) |
|||
{ |
|||
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); |
|||
} |
|||
/* |
|||
* Add integers, wrapping at 2^32. This uses 16-bit operations internally |
|||
* to work around bugs in some JS interpreters. |
|||
*/ |
|||
function safe_add(x, y) |
|||
{ |
|||
var lsw = (x & 0xFFFF) + (y & 0xFFFF); |
|||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16); |
|||
return (msw << 16) | (lsw & 0xFFFF); |
|||
} |
|||
/* |
|||
* Bitwise rotate a 32-bit number to the left. |
|||
*/ |
|||
function bit_rol(num, cnt) |
|||
{ |
|||
return (num << cnt) | (num >>> (32 - cnt)); |
|||
} |
|||
//</NOLITE> |
|||
// ENDFILE: md5-2.2alpha.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 |
|||
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; |
return ret; |
||
}; |
|||
} else { |
|||
String.prototype.parenSplit=function (re) { return this.split(re); }; |
|||
String.prototype.parenSplit.isNative=true; |
|||
} |
|||
function nonGlobalRegex(re) { |
|||
var s=re.toString(); |
|||
flags=''; |
|||
for (var j=s.length; s.charAt(j) != '/'; --j) { |
|||
if (s.charAt(j) != 'g') { flags += s.charAt(j); } |
|||
} |
} |
||
var t=s.substring(1,j); |
|||
return RegExp(t,flags); |
|||
} |
|||
// ENDFILE: parensplit.js |
|||
// STARTFILE: tools.js |
|||
// IE madness with encoding |
|||
// ======================== |
|||
// |
|||
// suppose throughout that the page is in utf8, like wikipedia |
|||
// |
|||
// if a is an anchor DOM element and a.href should consist of |
|||
// |
|||
// http://host.name.here/wiki/foo?bar=baz |
|||
// |
|||
// then IE gives foo as "latin1-encoded" utf8; we have foo = decode_utf8(decodeURI(foo_ie)) |
|||
// but IE gives bar=baz correctly as plain utf8 |
|||
// |
|||
// --------------------------------- |
|||
// |
|||
// IE's xmlhttp doesn't understand utf8 urls. Have to use encodeURI here. |
|||
// |
|||
// --------------------------------- |
|||
// |
|||
// summat else |
|||
// Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm |
|||
// Generate html for whole popup |
|||
function popupHTML(a) { |
|||
//<NOLITE> |
|||
getValueOf('popupStructure'); |
|||
function encode_utf8(rohtext) { |
|||
var structure = pg.structures[pg.option.popupStructure]; |
|||
// dient der Normalisierung des Zeilenumbruchs |
|||
if (typeof structure != 'object') { |
|||
rohtext = rohtext.replace(/\r\n/g,"\n"); |
|||
//return 'Unknown structure: '+pg.option.popupStructure; |
|||
var utftext = ""; |
|||
// override user choice |
|||
for(var n=0; n<rohtext.length; n++) |
|||
pg.option.popupStructure = pg.optionDefault.popupStructure; |
|||
{ |
|||
return popupHTML(a); |
|||
// ermitteln des Unicodes des aktuellen Zeichens |
|||
} |
|||
var c=rohtext.charCodeAt(n); |
|||
if (typeof structure.popupLayout != 'function') { |
|||
// alle Zeichen von 0-127 => 1byte |
|||
return 'Bad layout'; |
|||
if (c<128) |
|||
} |
|||
utftext += String.fromCharCode(c); |
|||
pg.misc.layout = structure.popupLayout(); |
|||
// alle Zeichen von 127 bis 2047 => 2byte |
|||
if (typeof structure.popupRedirSpans === 'function') { |
|||
else if((c>127) && (c<2048)) { |
|||
pg.misc.redirSpans = structure.popupRedirSpans(); |
|||
utftext += String.fromCharCode((c>>6)|192); |
|||
} else { |
|||
utftext += String.fromCharCode((c&63)|128);} |
|||
pg.misc.redirSpans = []; |
|||
// alle Zeichen von 2048 bis 66536 => 3byte |
|||
} |
|||
else { |
|||
return makeEmptySpans(pg.misc.layout, a.navpopup); |
|||
utftext += String.fromCharCode((c>>12)|224); |
|||
utftext += String.fromCharCode(((c>>6)&63)|128); |
|||
utftext += String.fromCharCode((c&63)|128);} |
|||
} |
} |
||
return utftext; |
|||
} |
|||
function getJsObj(json) { |
|||
try { |
|||
var ret = ''; |
|||
var json_ret = JSON.parse(json); |
|||
if( json_ret.warnings ) { |
|||
for( var w=0; w < json_ret.warnings.length; w++ ) { |
|||
ret += emptySpanHTML(list[i], navpop.idNumber, 'div'); |
|||
log( json_ret.warnings[w]['*'] ); |
|||
} else if (typeof list[i] == typeof [] && list[i].length > 0) { |
|||
ret = ret.parenSplit(/(<\/[^>]*?>$)/).join(makeEmptySpans(list[i], navpop)); |
|||
} else if (typeof list[i] == typeof {} && list[i].nodeType) { |
|||
ret += emptySpanHTML(list[i].name, navpop.idNumber, list[i].nodeType); |
|||
} |
} |
||
} else if ( json_ret.error ) { |
|||
errlog( json_ret.error.code + ': ' + json_ret.error.info ); |
|||
} |
} |
||
return |
return json_ret; |
||
} catch (someError) { |
|||
errlog('Something went wrong with getJsObj, json='+json); |
|||
return 1; |
|||
} |
} |
||
} |
|||
function anyChild(obj) { |
|||
for (var p in obj) { |
|||
tag = tag || 'span'; |
|||
return obj[p]; |
|||
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]); |
|||
} |
} |
||
return null; |
|||
emptySpanHTML.classAliases = { popupSecondPreview: 'popupPreview' }; |
|||
} |
|||
//</NOLITE> |
|||
// 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 decode_utf8(utftext) { |
|||
var plaintext = ""; var i=0, c=0, c1=0, c2=0; |
|||
if (!when) { |
|||
// while-Schleife, weil einige Zeichen uebersprungen werden |
|||
when = 250; |
|||
while(i<utftext.length) |
|||
} |
|||
{ |
|||
var popTips = function () { |
|||
c = utftext.charCodeAt(i); |
|||
setupTooltips(document.getElementById(id), false, true, popData); |
|||
if (c<128) { |
|||
}; |
|||
plaintext += String.fromCharCode(c); |
|||
return function () { |
|||
i++;} |
|||
setTimeout(popTips, when, popData); |
|||
else if((c>191) && (c<224)) { |
|||
}; |
|||
c2 = utftext.charCodeAt(i+1); |
|||
plaintext += String.fromCharCode(((c&31)<<6) | (c2&63)); |
|||
i+=2;} |
|||
else { |
|||
c2 = utftext.charCodeAt(i+1); c3 = utftext.charCodeAt(i+2); |
|||
plaintext += String.fromCharCode(((c&15)<<12) | ((c2&63)<<6) | (c3&63)); |
|||
i+=3;} |
|||
} |
} |
||
return plaintext; |
|||
} |
|||
function setPopupTipsAndHTML(html, divname, idnumber, popData) { |
|||
setPopupHTML( |
|||
html, |
|||
divname, |
|||
idnumber, |
|||
getValueOf('popupSubpopups') ? popTipsSoonFn(divname + idnumber, null, popData) : null |
|||
); |
|||
} |
|||
// ENDFILE: htmloutput.js |
|||
function upcaseFirst(str) { |
|||
// STARTFILE: mouseout.js |
|||
if (typeof str != typeof '' || str === '') return ''; |
|||
////////////////////////////////////////////////// |
|||
return str.charAt(0).toUpperCase() + str.substring(1); |
|||
// 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 findInArray(arr, foo) { |
|||
if (!arr || !arr.length) { return -1; } |
|||
// stop the popup running off the right of the screen |
|||
var len=arr.length; |
|||
// FIXME avoid pg.current.link |
|||
for (var i=0; i<len; ++i) { if (arr[i]==foo) { return i; } } |
|||
if (pg.current.link && pg.current.link.navpopup) { |
|||
return -1; |
|||
pg.current.link.navpopup.limitHorizontalPosition(); |
|||
} |
|||
} |
|||
function nextOne (array, value) { |
|||
// NB if the array has two consecutive entries equal |
|||
//console ('mouseOutWikiLink'); |
|||
// then this will loop on successive calls |
|||
var a = this; |
|||
var i=findInArray(array, value); |
|||
if (i<0) { return null; } |
|||
return array[i+1]; |
|||
} |
|||
function literalizeRegex(str){ |
|||
removeModifierKeyHandler(a); |
|||
return str.replace(RegExp('([-.|()\\\\+?*^${}\\[\\]])', 'g'), '\\$1'); |
|||
} |
|||
String.prototype.entify=function() { |
|||
if (a.navpopup === null || typeof a.navpopup === 'undefined') { |
|||
//var shy='­'; |
|||
return; |
|||
return this.split('&').join('&').split('<').join('<').split('>').join('>'/*+shy*/).split('"').join('"'); |
|||
} |
|||
}; |
|||
if (!a.navpopup.isVisible()) { |
|||
a.navpopup.banish(); |
|||
return; |
|||
} |
|||
restoreTitle(a); |
|||
Navpopup.tracker.addHook(posCheckerHook(a.navpopup)); |
|||
} |
|||
function findThis(array, value) { |
|||
if (typeof array.length == 'undefined') { return null; } |
|||
return function () { |
|||
for (var i=0; i<array.length; ++i) { |
|||
if (!navpop.isVisible()) { |
|||
if (array[i]==value) { return i; } |
|||
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 = Date.now(); |
|||
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; |
|||
}; |
|||
} |
} |
||
return null; |
|||
} |
|||
function removeNulls(list) { |
|||
var ret=[]; |
|||
// at this point, we should have left the link but remain within the popup |
|||
for (var i=0; i<list.length; ++i) { |
|||
// so we call this function again until we leave the popup. |
|||
if ( |
if (list[i]) { |
||
ret.push(list[i]); |
|||
navpop.stopPopupTimer = setInterval(posCheckerHook(navpop), 500); |
|||
navpop.addHook( |
|||
function () { |
|||
clearInterval(navpop.stopPopupTimer); |
|||
}, |
|||
'hide', |
|||
'before' |
|||
); |
|||
} |
} |
||
} |
} |
||
return ret; |
|||
// ENDFILE: mouseout.js |
|||
} |
|||
function joinPath(list) { |
|||
return removeNulls(list).join('/'); |
|||
} |
|||
// STARTFILE: previewmaker.js |
|||
/** |
|||
* @file |
|||
* Defines the {@link Previewmaker} object, which generates short previews from wiki markup. |
|||
*/ |
|||
function simplePrintf(str, subs) { |
|||
/** |
|||
if (!str || !subs) { return str; } |
|||
* Creates a new Previewmaker |
|||
var ret=[]; |
|||
* @constructor |
|||
var s=str.parenSplit(/(%s|\$[0-9]+)/); |
|||
* @class The Previewmaker class. Use an instance of this to generate short previews from Wikitext. |
|||
var i=0; |
|||
* @param {string} wikiText The Wikitext source of the page we wish to preview. |
|||
do { |
|||
* @param {string} baseUrl The url we should prepend when creating relative urls. |
|||
ret.push(s.shift()); |
|||
* @param {Navpopup} owner The navpop associated to this preview generator |
|||
if ( !s.length ) { break; } |
|||
*/ |
|||
var cmd=s.shift(); |
|||
function Previewmaker(wikiText, baseUrl, owner) { |
|||
if (cmd == '%s') { |
|||
/** The wikitext which is manipulated to generate the preview. */ |
|||
if ( i < subs.length ) { ret.push(subs[i]); } else { ret.push(cmd); } |
|||
this.originalData = wikiText; |
|||
++i; |
|||
this.baseUrl = baseUrl; |
|||
} else { |
|||
this.owner = owner; |
|||
var j=parseInt( cmd.replace('$', ''), 10 ) - 1; |
|||
if ( j > -1 && j < subs.length ) { ret.push(subs[j]); } else { ret.push(cmd); } |
|||
} |
|||
} while (s.length > 0); |
|||
return ret.join(''); |
|||
} |
|||
function max(a,b){return a<b ? b : a;} |
|||
this.maxCharacters = getValueOf('popupMaxPreviewCharacters'); |
|||
function min(a,b){return a>b ? b : a;} |
|||
this.maxSentences = getValueOf('popupMaxPreviewSentences'); |
|||
function isString(x) { return (typeof x === 'string' || x instanceof String); } |
|||
this.setData(); |
|||
//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); |
|||
} |
|||
function repeatString(s,mult) { |
|||
Previewmaker.prototype.setData = function () { |
|||
var ret=''; |
|||
var maxSize = Math.max(10000, 2 * this.maxCharacters); |
|||
for (var i=0; i<mult; ++i) { ret += s; } |
|||
this.data = this.originalData.substring(0, maxSize); |
|||
return ret; |
|||
}; |
|||
} |
|||
function zeroFill(s, min) { |
|||
/** |
|||
min = min || 2; |
|||
* Remove HTML comments |
|||
var t=s.toString(); |
|||
* @private |
|||
return repeatString('0', min - t.length) + t; |
|||
*/ |
|||
} |
|||
Previewmaker.prototype.killComments = function () { |
|||
// this also kills one trailing newline, eg [[diamyo]] |
|||
this.data = this.data.replace( |
|||
/^<!--[^$]*?-->\n|\n<!--[^$]*?-->(?=\n)|<!--[^$]*?-->/g, |
|||
'' |
|||
); |
|||
}; |
|||
function map(f, o) { |
|||
/** |
|||
if (isArray(o)) { return map_array(f,o); } |
|||
* @private |
|||
return map_object(f,o); |
|||
*/ |
|||
} |
|||
Previewmaker.prototype.killDivs = function () { |
|||
function map_array(f,o) { |
|||
// say goodbye, divs (can be nested, so use * not *?) |
|||
var ret=[]; |
|||
this.data = this.data.replace(/< *div[^>]* *>[\s\S]*?< *\/ *div *>/gi, ''); |
|||
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 |
|||
* @private |
|||
.replace(/&/g, "&") |
|||
*/ |
|||
.replace(/"/g, """) |
|||
Previewmaker.prototype.killGalleries = function () { |
|||
.replace(/</g, "<") |
|||
this.data = this.data.replace(/< *gallery[^>]* *>[\s\S]*?< *\/ *gallery *>/gi, ''); |
|||
.replace(/>/g, ">"); |
|||
}; |
|||
}; |
|||
pg.jsescape = function(s) |
|||
/** |
|||
{ |
|||
* @private |
|||
if (typeof s !== "string") throw "Invalid type in pg.jsescape"; |
|||
*/ |
|||
var res = ""; |
|||
Previewmaker.prototype.kill = function (opening, closing, subopening, subclosing, repl) { |
|||
//this can be optimized by copying substrings instead of char by char! |
|||
var oldk = this.data; |
|||
for (var i=0; i<s.length; i++) |
|||
var k = this.killStuff(this.data, opening, closing, subopening, subclosing, repl); |
|||
{ |
|||
while (k.length < oldk.length) { |
|||
var c = s[i]; |
|||
switch (c) |
|||
k = this.killStuff(k, opening, closing, subopening, subclosing, repl); |
|||
{ |
|||
} |
|||
case '\b': res += '\\b'; continue; |
|||
this.data = k; |
|||
case '\f': res += '\\f'; continue; |
|||
}; |
|||
case '\n': res += '\\n'; continue; |
|||
case '\0': res += '\\0'; continue; |
|||
/** |
|||
case '\r': res += '\\r'; continue; |
|||
* @private |
|||
case '\t': res += '\\t'; continue; |
|||
*/ |
|||
case '\v': res += '\\v'; continue; |
|||
Previewmaker.prototype.killStuff = function ( |
|||
case '\\': res += '\\\\'; continue; |
|||
txt, |
|||
case '\"': res += '\\\"'; continue; |
|||
opening, |
|||
case '\'': res += '\\\''; continue; |
|||
closing, |
|||
default: |
|||
subopening, |
|||
if (c < ' ' || c==='<' || c==='>' || c==="'") |
|||
subclosing, |
|||
{ |
|||
var unicodeChar = c.charCodeAt(0).toString(16).toUpperCase(); |
|||
) { |
|||
res += "\\u" + (unicodeChar.length>1?"00":"000") + unicodeChar; |
|||
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; |
|||
} |
} |
||
else |
|||
if (!removal) { |
|||
{ |
|||
removal = 1; |
|||
res += c; |
|||
} |
} |
||
} |
|||
txt = txt.substring(removal); |
|||
} |
|||
if (depth === 0) { |
|||
return res; |
|||
break; |
|||
}; |
|||
} |
|||
// ENDFILE: tools.js |
|||
} |
|||
// STARTFILE: dab.js |
|||
return ret + (repl || '') + txt; |
|||
//<NOLITE> |
|||
}; |
|||
////////////////////////////////////////////////// |
|||
// Dab-fixing code |
|||
// |
|||
/** |
|||
* @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'); |
|||
} |
|||
function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) { |
|||
log('makeRegexp: got reStr=' + reStr + ', flags=' + flags); |
|||
log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget); |
|||
return RegExp(reStr, flags); |
|||
return changeLinkTargetLink( |
|||
}; |
|||
{newTarget: newTarget, |
|||
text: newTarget.split(' ').join(' '), |
|||
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 |
|||
* @private |
|||
// testcase: http://en.wikipedia.org/w/index.php?title=Radial&oldid=97365633 |
|||
*/ |
|||
var reg=RegExp('\\[\\[([^|]*?) *(\\||\\]\\])', 'gi'); |
|||
Previewmaker.prototype.killBoxTemplates = function () { |
|||
var ret=[]; |
|||
// taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general |
|||
var splitted=wikitext.parenSplit(reg); |
|||
// also, have float_begin, ... float_end |
|||
// ^[a-z]+ should match interwiki links, hopefully (case-insensitive) |
|||
this.kill(/[{][{][^{}\s|]*?(float|box)[_ ](begin|start)/i, /[}][}]\s*/, '{{'); |
|||
// 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) { |
|||
// infoboxes etc |
|||
if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) { |
|||
// from [[User:Zyxw/popups.js]]: kill frames too |
|||
ret.push( retargetDab(splitted[i], oldTarget, friendlyCurrentArticleName, titleToEdit) ); |
|||
this.kill(/[{][{][^{}\s|]*?(infobox|elementbox|frame)[_ ]/i, /[}][}]\s*/, '{{'); |
|||
} /* if */ |
|||
}; |
|||
} /* for loop */ |
|||
ret = rmDupesFromSortedList(ret.sort()); |
|||
/** |
|||
* @private |
|||
*/ |
|||
Previewmaker.prototype.killTemplates = function () { |
|||
this.kill('{{', '}}', '{', '}', ' '); |
|||
}; |
|||
if (wikPos) { |
|||
/** |
|||
var wikTarget='wiktionary:' + |
|||
* @private |
|||
friendlyCurrentArticleName.replace( RegExp('^(.+)\\s+[(][^)]+[)]\\s*$'), '$1' ); |
|||
*/ |
|||
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(/^[|].*$/mg, ''); |
|||
}; |
|||
var meth; |
|||
/** |
|||
if (wikPos.toLowerCase() == 'first') { meth = 'unshift'; } |
|||
* @private |
|||
else { meth = 'push'; } |
|||
*/ |
|||
Previewmaker.prototype.killImages = function () { |
|||
var forbiddenNamespaceAliases = []; |
|||
$.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! |
|||
}); |
|||
ret[meth]( retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) ); |
|||
// images and categories are a nono |
|||
} |
|||
this.kill( |
|||
RegExp('[[][[]\\s*(' + forbiddenNamespaceAliases.join('|') + ')\\s*:', 'i'), |
|||
/\]\]\s*/, |
|||
'[', |
|||
']' |
|||
); |
|||
}; |
|||
ret.push(changeLinkTargetLink( |
|||
/** |
|||
{ newTarget: null, |
|||
* @private |
|||
text: popupString('remove this link').split(' ').join(' '), |
|||
*/ |
|||
hint: popupString("remove all links to this disambig page from this article"), |
|||
Previewmaker.prototype.killHTML = function () { |
|||
clickButton: "wpDiff", oldTarget: oldTarget, |
|||
// kill <ref ...>...</ref> |
|||
summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName]), |
|||
this.kill(/<ref\b[^/>]*?>/i, /<\/ref>/i); |
|||
watch: getValueOf('popupWatchDisambiggedPages'), |
|||
title: titleToEdit |
|||
})); |
|||
return ret; |
|||
} |
|||
function rmDupesFromSortedList(list) { |
|||
// let's also delete entire lines starting with <. it's worth a try. |
|||
var ret=[]; |
|||
this.data = this.data.replace(/(^|\n) *<.*/g, '\n'); |
|||
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) { |
|||
// and those pesky html tags, but not <nowiki> or <blockquote> |
|||
// grab title from parent popup if there is one; default exists in changeLinkTargetLink |
|||
var splitted = this.data.parenSplit(/(<[\w\W]*?(?:>|$|(?=<)))/); |
|||
var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString()); |
|||
var len = splitted.length; |
|||
var list=listLinks(data, navpop.originalArticle, titleToEdit); |
|||
for (var i = 1; i < len; i = i + 2) { |
|||
if (list.length === 0) { log('listLinks returned empty list'); return null; } |
|||
switch (splitted[i]) { |
|||
var html='<hr />' + popupString('Click to disambiguate this link to:') + '<br>'; |
|||
case '<nowiki>': |
|||
html+=list.join(', '); |
|||
case '</nowiki>': |
|||
return html; |
|||
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 = /((^|\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'); |
|||
}; |
|||
function makeFixDabs(wikiText, navpop) { |
|||
/** |
|||
if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) && |
|||
* @private |
|||
Title.fromURL(location.href).namespaceId() != pg.nsSpecialId && |
|||
*/ |
|||
navpop.article.talkPage() ) { |
|||
Previewmaker.prototype.mopup = function () { |
|||
setPopupHTML(makeFixDab(wikiText, navpop), 'popupFixDab', navpop.idNumber); |
|||
// we simply *can't* be doing with horizontal rules right now |
|||
} |
|||
this.data = this.data.replace(/^-{4,}/mg, ''); |
|||
} |
|||
function popupRedlinkHTML(article) { |
|||
// no indented lines |
|||
return changeLinkTargetLink( |
|||
this.data = this.data.replace(/(^|\n) *:[^\n]*/g, ''); |
|||
{ newTarget: null, text: popupString('remove this link').split(' ').join(' '), |
|||
hint: popupString("remove all links to this page from this article"), |
|||
clickButton: "wpDiff", |
|||
oldTarget: article.toString(), |
|||
summary: simplePrintf(getValueOf('popupRedlinkSummary'), [article.toString()])}); |
|||
} |
|||
//</NOLITE> |
|||
// ENDFILE: dab.js |
|||
// STARTFILE: htmloutput.js |
|||
function appendPopupContent(obj, elementId, popupId, onSuccess) { |
|||
// replace __TOC__, __NOTOC__ and whatever else there is |
|||
return setPopupHTML(obj, elementId, popupId, onSuccess, true); |
|||
// this'll probably do |
|||
} |
|||
this.data = this.data.replace(/^__[A-Z_]*__ *$/gmi, ''); |
|||
}; |
|||
// 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) { |
|||
* @private |
|||
if (elementId=='popupPreview') { |
|||
*/ |
|||
} |
|||
Previewmaker.prototype.firstBit = function () { |
|||
if (typeof popupId === 'undefined') { |
|||
// dont't be givin' me no subsequent paragraphs, you hear me? |
|||
//console.error('popupId is not defined in setPopupHTML, html='+str.substring(0,100)); |
|||
/// first we "normalize" section headings, removing whitespace after, adding before |
|||
popupId = pg.idNumber; |
|||
} |
|||
if (getValueOf('popupPreviewCutHeadings')) { |
|||
this.data = this.data.replace(/\s*(==+[^=]*==+)\s*/g, '\n\n$1 '); |
|||
/// then we want to get rid of paragraph breaks whose text ends badly |
|||
this.data = this.data.replace(/([:;]) *\n{2,}/g, '$1\n'); |
|||
var popupElement=document.getElementById(elementId+popupId); |
|||
this.data = this.data.replace(/^[\s\n]*/, ''); |
|||
if (popupElement) { |
|||
var stuff = /^([^\n]|\n[^\n\s])*/.exec(this.data); |
|||
if (!append) { popupElement.innerHTML=''; } |
|||
if (stuff) { |
|||
if (isString(str)) { |
|||
d = stuff[0]; |
|||
popupElement.innerHTML+=str; |
|||
} |
|||
} else { |
|||
if (!getValueOf('popupPreviewFirstParOnly')) { |
|||
popupElement.appendChild(str); |
|||
d = this.data; |
|||
} |
|||
/// now put \n\n after sections so that bullets and numbered lists work |
|||
d = d.replace(/(==+[^=]*==+)\s*/g, '$1\n\n'); |
|||
} |
} |
||
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> |
|||
// Split sentences. Superfluous sentences are RIGHT OUT. |
|||
function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);} |
|||
// note: exactly 1 set of parens here needed to make the slice work |
|||
//</NOLITE> |
|||
d = d.parenSplit(/([!?.]+["']*\s)/g); |
|||
// leading space is bad, mmkay? |
|||
d[0] = d[0].replace(/^\s*/, ''); |
|||
var notSentenceEnds = /([^.][a-z][.] *[a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|op|cit|\[[^\]]*|\s[A-Zvclm])$/i; |
|||
d = this.fixSentenceEnds(d, notSentenceEnds); |
|||
function fillEmptySpans(args) { return fillEmptySpans2(args); } |
|||
this.fullLength = d.join('').length; |
|||
var n = this.maxSentences; |
|||
var dd = this.firstSentences(d, n); |
|||
// args.navpopup is mandatory |
|||
do { |
|||
// optional: args.redir, args.redirTarget |
|||
dd = this.firstSentences(d, n); |
|||
// FIXME: ye gods, this is ugly stuff |
|||
--n; |
|||
function fillEmptySpans2(args) { // if redir is present and true then redirTarget is mandatory |
|||
} while (dd.length > this.maxCharacters && n !== 0); |
|||
var redir=true; |
|||
if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; } |
|||
var a=args.navpopup.parentAnchor; |
|||
var article, hint=null, oldid=null, params={}; |
|||
this.data = dd; |
|||
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') { |
|||
* @private |
|||
setPopupHTML('popupError', 'Unknown structure (this should never happen): '+ |
|||
*/ |
|||
pg.option.popupStructure, args.navpopup.idNumber); |
|||
Previewmaker.prototype.fixSentenceEnds = function (strs, reg) { |
|||
return; |
|||
// take an array of strings, strs |
|||
} |
|||
// join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg |
|||
var spans=flatten(pg.misc.layout); |
|||
var numspans = spans.length; |
|||
var redirs=pg.misc.redirSpans; |
|||
for (var i=0; i<numspans; ++i) { |
|||
var f=findThis(redirs, spans[i]); |
|||
//log('redir='+redir+', f='+f+', spans[i]='+spans[i]); |
|||
var a = []; |
|||
if ( (f && !redir) || (!f && redir) ) { |
|||
//log('skipping this set of the loop'); |
|||
if (j < i) { |
|||
continue; |
|||
a[j] = strs[j]; |
|||
} |
|||
var structurefn=structure[spans[i]]; |
|||
if (j == i) { |
|||
var setfn = setPopupHTML; |
|||
a[i] = strs[i] + strs[i + 1] + strs[i + 2]; |
|||
if (getValueOf('popupActiveNavlinks') && |
|||
} |
|||
(spans[i].indexOf('popupTopLinks')===0 || spans[i].indexOf('popupRedirTopLinks')===0) |
|||
if (j > i + 2) { |
|||
) { |
|||
a[j - 2] = strs[j]; |
|||
setfn = setPopupTipsAndHTML; |
|||
} |
|||
} |
|||
return this.fixSentenceEnds(a, reg); |
|||
} |
|||
} |
} |
||
switch (typeof structurefn) { |
|||
return strs; |
|||
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) { |
|||
* @private |
|||
var ret=[]; |
|||
*/ |
|||
if (typeof start == 'undefined') { start=0; } |
|||
Previewmaker.prototype.firstSentences = function (strs, howmany) { |
|||
for (var i=start; i<list.length; ++i) { |
|||
var t = strs.slice(0, 2 * howmany); |
|||
if (typeof list[i] == typeof []) { |
|||
return t.join(''); |
|||
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) { |
|||
* @private |
|||
getValueOf('popupStructure'); |
|||
*/ |
|||
var structure=pg.structures[pg.option.popupStructure]; |
|||
Previewmaker.prototype.killBadWhitespace = function () { |
|||
if (typeof structure != 'object') { |
|||
// also cleans up isolated '''', eg [[Suntory Sungoliath]] |
|||
//return 'Unknown structure: '+pg.option.popupStructure; |
|||
this.data = this.data.replace(/^ *'+ *$/gm, ''); |
|||
// 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=''; |
|||
* Runs the various methods to generate the preview. |
|||
for (var i=0; i<list.length; ++i) { |
|||
* The preview is stored in the <code>html</html> field. |
|||
if (typeof list[i] == typeof '') { |
|||
* @private |
|||
ret += emptySpanHTML(list[i], navpop.idNumber, 'div'); |
|||
*/ |
|||
} else if (typeof list[i] == typeof [] && list[i].length > 0 ) { |
|||
Previewmaker.prototype.makePreview = function () { |
|||
ret = ret.parenSplit(RegExp('(</[^>]*?>$)')).join(makeEmptySpans(list[i], navpop)); |
|||
if ( |
|||
} else if (typeof list[i] == typeof {} && list[i].nodeType ) { |
|||
this.owner.article.namespaceId() != pg.nsTemplateId && |
|||
ret += emptySpanHTML(list[i].name, navpop.idNumber, list[i].nodeType); |
|||
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 |
|||
return ret; |
|||
this.fixHTML(); |
|||
} |
|||
this.stripLongTemplates(); |
|||
}; |
|||
/** |
|||
* @private |
|||
*/ |
|||
Previewmaker.prototype.esWiki2HtmlPart = function (data) { |
|||
var reLinks = /(?:\[\[([^|\]]*)(?:\|([^|\]]*))*]]([a-z]*))/gi; //match a wikilink |
|||
reLinks.lastIndex = 0; //reset regex |
|||
function emptySpanHTML(name, id, tag, classname) { |
|||
var match; |
|||
tag = tag || 'span'; |
|||
if (!classname) { classname = emptySpanHTML.classAliases[name]; } |
|||
var postfixIndex = 0; |
|||
classname = classname || name; |
|||
while ((match = reLinks.exec(data))) { |
|||
if (name == getValueOf('popupDragHandle')) { classname += ' popupDragHandle'; } |
|||
//match all wikilinks |
|||
return simplePrintf('<%s id="%s" class="%s"></%s>', [tag, name + id, classname, tag]); |
|||
//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 += |
|||
emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' }; |
|||
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)); |
|||
// generate html for popup image |
|||
return result; |
|||
// <a id="popupImageLinkn"><img id="popupImagen"> |
|||
}; |
|||
// where n=idNumber |
|||
Previewmaker.prototype.editSummaryPreview = function () { |
|||
function imageHTML(article, idNumber) { |
|||
var reAes = /\/\* *(.*?) *\*\//g; //match the first section marker |
|||
return simplePrintf('<a id="popupImageLink$1">' + |
|||
reAes.lastIndex = 0; //reset regex |
|||
'<img align="right" valign="top" id="popupImg$1" style="display: none;"></img>' + |
|||
'</a>', [ idNumber ]); |
|||
} |
|||
function popTipsSoonFn(id, when, popData) { |
|||
var match; |
|||
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) { |
|||
match = reAes.exec(this.data); |
|||
setPopupHTML(html, divname, idnumber, |
|||
if (match) { |
|||
getValueOf('popupSubpopups') ? |
|||
//we have a section link. Split it, process it, combine it. |
|||
popTipsSoonFn(divname + idnumber, null, popData) : |
|||
var prefix = this.data.substring(0, match.index - 1); |
|||
null); |
|||
var section = match[1]; |
|||
} |
|||
var postfix = this.data.substring(reAes.lastIndex); |
|||
// ENDFILE: htmloutput.js |
|||
// STARTFILE: mouseout.js |
|||
////////////////////////////////////////////////// |
|||
// fuzzy checks |
|||
function fuzzyCursorOffMenus(x,y, fuzz, parent) { |
|||
var start = "<span class='autocomment'>"; |
|||
if (!parent) { return null; } |
|||
var end = '</span>'; |
|||
var uls=parent.getElementsByTagName('ul'); |
|||
if (prefix.length > 0) { |
|||
for (var i=0; i<uls.length; ++i) { |
|||
start = this.esWiki2HtmlPart(prefix) + ' ' + start + '- '; |
|||
if (uls[i].className=='popup_menu') { |
|||
} |
|||
if ( |
if (uls[i].offsetWidth > 0) return false; |
||
} // else {document.title+='.';} |
|||
end = ': ' + end + this.esWiki2HtmlPart(postfix); |
|||
} |
|||
return true; |
|||
} |
|||
function checkPopupPosition () { // stop the popup running off the right of the screen |
|||
var t = new Title().fromURL(this.baseUrl); |
|||
// FIXME avoid pg.current.link |
|||
t.anchorFromUtf(section); |
|||
if (pg.current.link && pg.current.link.navpopup) |
|||
var sectionLink = |
|||
pg.current.link.navpopup.limitHorizontalPosition(); |
|||
Insta.conf.paths.articles + |
|||
} |
|||
pg.escapeQuotesHTML(t.toString(true)) + |
|||
'#' + |
|||
pg.escapeQuotesHTML(t.anchor); |
|||
return ( |
|||
start + '<a href="' + sectionLink + '">→</a> ' + pg.escapeQuotesHTML(section) + end |
|||
); |
|||
} |
|||
function mouseOutWikiLink () { |
|||
//else there's no section link, htmlify the whole thing. |
|||
//console ('mouseOutWikiLink'); |
|||
return this.esWiki2HtmlPart(this.data); |
|||
var a=this; |
|||
}; |
|||
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) { |
|||
/** Test function for debugging preview problems one step at a time. */ |
|||
return function() { |
|||
/*eslint-disable */ |
|||
if (!navpop.isVisible()) { return true; /* remove this hook */ } |
|||
function previewSteps(txt) { |
|||
if (Navpopup.tracker.dirty) { |
|||
try { |
|||
return false; |
|||
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'); |
|||
} |
|||
} |
} |
||
var x=Navpopup.tracker.x, y=Navpopup.tracker.y; |
|||
txt = txt.substring(0, 10000); |
|||
var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) || |
|||
var base = pg.wiki.articlebase + Title.fromURL(document.location.href).urlString(); |
|||
!fuzzyCursorOffMenus(x,y,navpop.fuzz, navpop.mainDiv); |
|||
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; |
|||
} |
|||
// FIXME it'd be prettier to do this internal to the Navpopup objects |
|||
if (getValueOf('popupPreviewKillTemplates')) { |
|||
var t=getValueOf('popupHideDelay'); |
|||
p.killTemplates(); |
|||
if (t) { t = t * 1000; } |
|||
if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { |
|||
if (!t) { |
|||
return; |
|||
if(!mouseOverNavpop) { |
|||
} |
|||
if(navpop.parentAnchor) { |
|||
} else { |
|||
restoreTitle( navpop.parentAnchor ); |
|||
p.killMultilineTemplates(); |
|||
if (!confirm('done killMultilineTemplates(). Continue?\n---\n' + p.data)) { |
|||
return; |
|||
} |
} |
||
navpop.banish(); |
|||
return true; /* remove this hook */ |
|||
} |
} |
||
return false; |
|||
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; |
|||
} |
|||
} |
} |
||
// we have a hide delay set |
|||
var d=+(new Date()); |
|||
p.html = wiki2html(p.data, base); // needs livepreview |
|||
if ( !navpop.mouseLeavingTime ) { |
|||
p.fixHTML(); |
|||
navpop.mouseLeavingTime = d; |
|||
if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { |
|||
return; |
return false; |
||
} |
} |
||
if ( mouseOverNavpop ) { |
|||
p.stripLongTemplates(); |
|||
navpop.mouseLeavingTime=null; |
|||
if (!confirm('done stripLongTemplates(). Continue?\n---\n' + p.html)) { |
|||
return; |
return false; |
||
} |
|||
if (d - navpop.mouseLeavingTime > t) { |
|||
navpop.mouseLeavingTime=null; |
|||
navpop.banish(); return true; /* remove this hook */ |
|||
} |
} |
||
return false; |
|||
alert('finished preview - end result follows.\n---\n' + p.html); |
|||
}; |
|||
} |
|||
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'); |
|||
} |
} |
||
} |
|||
/*eslint-enable */ |
|||
// ENDFILE: mouseout.js |
|||
// STARTFILE: previewmaker.js |
|||
/** |
|||
@fileoverview |
|||
Defines the {@link Previewmaker} object, which generates short previews from wiki markup. |
|||
*/ |
|||
/** |
|||
Creates a new Previewmaker |
|||
* Works around livepreview bugs. |
|||
@constructor |
|||
* @private |
|||
@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. |
|||
Previewmaker.prototype.fixHTML = function () { |
|||
@param {String} baseUrl The url we should prepend when creating relative urls. |
|||
if (!this.html) { |
|||
@param {Navpopup} owner The navpop associated to this preview generator |
|||
return; |
|||
*/ |
|||
function Previewmaker(wikiText, baseUrl, owner) { |
|||
/** The wikitext which is manipulated to generate the preview. */ |
|||
this.originalData=wikiText; |
|||
this.setData(); |
|||
this.baseUrl=baseUrl; |
|||
this.owner=owner; |
|||
this.maxCharacters=getValueOf('popupMaxPreviewCharacters'); |
|||
this.maxSentences=getValueOf('popupMaxPreviewSentences'); |
|||
} |
|||
Previewmaker.prototype.setData=function() { |
|||
var maxSize=max(10000, 2*this.maxCharacters); |
|||
this.data=this.originalData.substring(0,maxSize); |
|||
}; |
|||
/** Remove HTML comments |
|||
@private |
|||
*/ |
|||
Previewmaker.prototype.killComments = function () { |
|||
// this also kills one trailing newline, eg [[diamyo]] |
|||
this.data=this.data.replace(RegExp('^<!--[^$]*?-->\\n|\\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); |
|||
var ret = this.html; |
|||
return RegExp(reStr, flags); |
|||
}; |
|||
/** |
|||
@private |
|||
*/ |
|||
Previewmaker.prototype.killBoxTemplates = function () { |
|||
// taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general |
|||
// fix question marks in wiki links |
|||
// also, have float_begin, ... float_end |
|||
// maybe this'll break some stuff :-( |
|||
this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'), /[}][}]\s*/, '{{'); |
|||
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 |
|||
// infoboxes etc |
|||
this.html = ret; |
|||
// from [[User:Zyxw/popups.js]]: kill frames too |
|||
}; |
|||
this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{'); |
|||
}; |
|||
/** |
|||
/** |
|||
* Generates the preview and displays it in the current popup. |
|||
@private |
|||
* |
|||
*/ |
|||
* Does nothing if the generated preview is invalid or consists of whitespace only. |
|||
Previewmaker.prototype.killTemplates = function () { |
|||
* Also activates wikilinks in the preview for subpopups if the popupSubpopups option is true. |
|||
this.kill('{{', '}}', '{', '}', ' '); |
|||
*/ |
|||
}; |
|||
Previewmaker.prototype.showPreview = function () { |
|||
/** |
|||
this.makePreview(); |
|||
@private |
|||
if (typeof this.html != typeof '') { |
|||
*/ |
|||
return; |
|||
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]=''; |
|||
} |
} |
||
} |
|||
if (/^\s*$/.test(this.html)) { |
|||
this.data=splitted.join(''); |
|||
return; |
|||
}; |
|||
/** |
|||
setPopupHTML('<hr />', 'popupPrePreviewSep', this.owner.idNumber); |
|||
@private |
|||
setPopupTipsAndHTML(this.html, 'popupPreview', this.owner.idNumber, { |
|||
*/ |
|||
owner: this.owner, |
|||
Previewmaker.prototype.killChunks = function() { // heuristics alert |
|||
}); |
|||
// chunks of italic text? you crazy, man? |
|||
var more = this.fullLength > this.data.length ? this.moreLink() : ''; |
|||
var italicChunkRegex=new RegExp |
|||
setPopupHTML(more, 'popupPreviewMore', this.owner.idNumber); |
|||
("((^|\\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'), ''); |
|||
* @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; |
|||
}; |
|||
// replace __TOC__, __NOTOC__ and whatever else there is |
|||
/** |
|||
// this'll probably do |
|||
* @private |
|||
this.data=this.data.replace(RegExp('^__[A-Z_]*__ *$', 'gmi'),''); |
|||
*/ |
|||
}; |
|||
Previewmaker.prototype.stripLongTemplates = function () { |
|||
/** |
|||
// operates on the HTML! |
|||
@private |
|||
this.html = this.html.replace( |
|||
*/ |
|||
/^.{0,1000}[{][{][^}]*?(<(p|br)( \/)?>\s*){2,}([^{}]*?[}][}])?/gi, |
|||
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 |
|||
this.html = this.html.split('\n').join(' '); // workaround for <pre> templates |
|||
var d=this.data; |
|||
this.html = this.html.replace(/[{][{][^}]*<pre>[^}]*[}][}]/gi, ''); |
|||
}; |
|||
if (getValueOf('popupPreviewCutHeadings')) { |
|||
/** |
|||
this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 '); |
|||
* @private |
|||
/// then we want to get rid of paragraph breaks whose text ends badly |
|||
*/ |
|||
this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n'); |
|||
Previewmaker.prototype.killMultilineTemplates = function () { |
|||
this.kill('{{{', '}}}'); |
|||
this.kill(/\s*[{][{][^{}]*\n/, '}}', '{{'); |
|||
}; |
|||
// ENDFILE: previewmaker.js |
|||
this.data=this.data.replace(RegExp('^[\\s\\n]*'), ''); |
|||
// STARTFILE: querypreview.js |
|||
stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data); |
|||
function loadAPIPreview(queryType, article, navpop) { |
|||
if (stuff) { d = stuff[0]; } |
|||
var art = new Title(article).urlString(); |
|||
if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; } |
|||
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&rvslots=main&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&meta=wikibase&rvslots=main&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'); |
|||
if (queryType === 'userinfo') { |
|||
// We need to do another API request |
|||
fetchUserGroupNames(d.data).then(function () { |
|||
showAPIPreview(queryType, htmlGenerator(article, d, navpop), navpop.idNumber, navpop, d); |
|||
}); |
|||
return; |
|||
} |
|||
showAPIPreview(queryType, htmlGenerator(article, d, navpop), navpop.idNumber, navpop, d); |
|||
}; |
|||
var go = function () { |
|||
getPageWithCaching(url, callback, navpop); |
|||
return true; |
|||
}; |
|||
/// now put \n\n after sections so that bullets and numbered lists work |
|||
if (navpop.visible || !getValueOf('popupLazyDownloads')) { |
|||
d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n'); |
|||
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(' '), |
|||
action: 'view', |
|||
}) |
|||
); |
|||
} |
|||
return buf.join(', '); |
|||
} |
|||
// Split sentences. Superfluous sentences are RIGHT OUT. |
|||
function getTimeOffset() { |
|||
// note: exactly 1 set of parens here needed to make the slice work |
|||
var tz = mw.user.options.get('timecorrection'); |
|||
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'); |
|||
if (tz) { |
|||
d = this.fixSentenceEnds(d, notSentenceEnds); |
|||
if (tz.indexOf('|') > -1) { |
|||
// New format |
|||
return parseInt(tz.split('|')[1], 10); |
|||
} |
|||
} |
|||
return 0; |
|||
} |
|||
this.fullLength=d.join('').length; |
|||
function getTimeZone() { |
|||
var maxChars=getValueOf('popupMaxPreviewCharacters') + this.extraCharacters; |
|||
if (!pg.user.timeZone) { |
|||
var n=this.maxSentences; |
|||
var tz = mw.user.options.get('timecorrection'); |
|||
var dd=this.firstSentences(d,n); |
|||
pg.user.timeZone = 'UTC'; |
|||
do { |
|||
if (tz) { |
|||
dd=this.firstSentences(d,n); --n; |
|||
var tzComponents = tz.split('|'); |
|||
} while ( dd.length > this.maxCharacters && n !== 0 ); |
|||
pg.user.timeZone = tzComponents[2]; |
|||
this.data = dd; |
|||
} else { |
|||
}; |
|||
errlog('Unexpected timezone information: ' + tz); |
|||
/** |
|||
} |
|||
@private |
|||
*/ |
|||
Previewmaker.prototype.fixSentenceEnds = function(strs, reg) { |
|||
// take an array of strings, strs |
|||
// join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg |
|||
var abbrevRe=/\b[a-z][^a-z]*$/i; |
|||
for (var i=0; i<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); |
|||
} |
|||
// BUGGY STUFF - trying to fix up [[S. C. Johnson & Son]] preview |
|||
if (false && abbrevRe.test(strs[i])) { |
|||
var prevI=i, buf=''; |
|||
do { |
|||
buf=buf+strs[i]+strs[i+1]; |
|||
i=i+2; |
|||
} while (i<strs.length-2 && abbrevRe.test(strs[i])); |
|||
strs[i]=buf+strs[i]; |
|||
return this.fixSentenceEnds((prevI?strs.slice(0,prevI-1):[]).concat(strs.slice(i)), |
|||
reg); |
|||
} |
} |
||
return pg.user.timeZone; |
|||
} |
} |
||
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(); |
|||
* Should we use an offset or can we use proper timezones |
|||
} else { |
|||
*/ |
|||
this.killMultilineTemplates(); |
|||
function useTimeOffset() { |
|||
if (typeof Intl.DateTimeFormat.prototype.formatToParts === 'undefined') { |
|||
// IE 11 |
|||
return true; |
|||
} |
} |
||
this.killTables(); |
|||
var tz = mw.user.options.get('timecorrection'); |
|||
this.killImages(); |
|||
if (tz && tz.indexOf('ZoneInfo|') === -1) { |
|||
this.killHTML(); |
|||
// System| Default system time, default for users who didn't configure timezone |
|||
this.killChunks(); |
|||
// Offset| Manual defined offset by user |
|||
this.mopup(); |
|||
return true; |
|||
} |
|||
this.firstBit(); |
|||
return false; |
|||
this.killBadWhitespace(); |
|||
} |
} |
||
else |
|||
{ |
|||
this.killHTML(); |
|||
* Array of locales for the purpose of javascript locale based formatting |
|||
* Filters down to those supported by the browser. Empty [] === System's default locale |
|||
*/ |
|||
function getLocales() { |
|||
if (!pg.user.locales) { |
|||
var userLanguage = document.querySelector('html').getAttribute('lang'); // make sure we have HTML locale |
|||
if (getValueOf('popupLocale')) { |
|||
userLanguage = getValueOf('popupLocale'); |
|||
} else if (userLanguage === 'en') { |
|||
// en.wp tends to treat this as international english / unspecified |
|||
// but we have more specific settings in user options |
|||
if (getMWDateFormat() === 'mdy') { |
|||
userLanguage = 'en-US'; |
|||
} else { |
|||
userLanguage = 'en-GB'; |
|||
} |
|||
} |
|||
pg.user.locales = Intl.DateTimeFormat.supportedLocalesOf([userLanguage, navigator.language]); |
|||
} |
|||
return pg.user.locales; |
|||
} |
} |
||
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 = ""; |
|||
* Retrieve configured MW date format for this user |
|||
var postfixIndex = 0; |
|||
* These can be |
|||
while ((match = reLinks.exec(data))) //match all wikilinks |
|||
* default |
|||
{ |
|||
* dmy: time, dmy |
|||
//FIXME: the way that link is built here isn't perfect. It is clickable, but popups preview won't recognize it in some cases. |
|||
* mdy: time, mdy |
|||
result += pg.escapeQuotesHTML(data.substring(postfixIndex, match.index)) + |
|||
* ymd: time, ymd |
|||
'<a href="'+Insta.conf.paths.articles+pg.escapeQuotesHTML(match[1])+'">'+pg.escapeQuotesHTML((match[2]?match[2]:match[1])+match[3])+"</a>"; |
|||
* dmyt: dmy, time |
|||
postfixIndex = reLinks.lastIndex; |
|||
* dmyts: dmy, time + seconds |
|||
} |
|||
* ISO 8601: YYYY-MM-DDThh:mm:ss (local time) |
|||
//append the rest |
|||
* |
|||
result += pg.escapeQuotesHTML(data.substring(postfixIndex)); |
|||
* This isn't too useful for us, as JS doesn't have formatters to match these private specifiers |
|||
return result; |
|||
function getMWDateFormat() { |
|||
}; |
|||
return mw.user.options.get('date'); |
|||
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+'">→</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. |
|||
* 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 |
|||
function previewSteps(txt) { |
|||
* @param {boolean} reallyContribs - true only if we're displaying user contributions |
|||
try { |
|||
*/ |
|||
txt=txt || document.editform.wpTextbox1.value; |
|||
function editPreviewTable(article, h, reallyContribs) { |
|||
} catch (err) { |
|||
var html = ['<table>']; |
|||
if (pg.cache.pages.length > 0) { |
|||
var day = null; |
|||
txt=pg.cache.pages[pg.cache.pages.length-1].data; |
|||
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 += ' | '; |
|||
result += |
|||
'<a href="' + |
|||
pg.wiki.titlebase + |
|||
new Title(currentRevision.title).urlString() + |
|||
'&action=history">' + |
|||
popupString('hist') + |
|||
'</a>'; |
|||
result += ')'; |
|||
return result; |
|||
}; |
|||
} else { |
} else { |
||
alert('provide text or use an edit page'); |
|||
// 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 += ' | '; |
|||
result += |
|||
'<a href="' + |
|||
pg.wiki.titlebase + |
|||
new Title(curart).urlString() + |
|||
'&diff=prev&oldid=' + |
|||
currentRevision.revid + |
|||
'">' + |
|||
popupString('last') + |
|||
'</a>'; |
|||
result += ')'; |
|||
return result; |
|||
}; |
|||
} |
} |
||
} |
|||
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')) { |
|||
for (var i = 0; i < h.length; ++i) { |
|||
p.killTemplates(); if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { return; } |
|||
if (reallyContribs) { |
|||
} else { |
|||
page = h[i].title; |
|||
p.killMultilineTemplates(); if (!confirm('done killMultilineTemplates(). Continue?\n---\n' + p.data)) { return; } |
|||
curart = new Title(page); |
|||
} |
|||
var minor = h[i].minor ? '<b>m </b>' : ''; |
|||
var editDate = new Date(h[i].timestamp); |
|||
var thisDay = formattedDate(editDate); |
|||
var thisTime = formattedTime(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 || ( typeof h[i].slots !== 'undefined' ? h[i].slots.main.content : null ); |
|||
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(''); |
|||
} |
|||
p.killTables(); if (!confirm('done killTables(). Continue?\n---\n' + p.data)) { return; } |
|||
function adjustDate(d, offset) { |
|||
p.killImages(); if (!confirm('done killImages(). Continue?\n---\n' + p.data)) { return; } |
|||
// offset is in minutes |
|||
p.killHTML(); if (!confirm('done killHTML(). Continue?\n---\n' + p.data)) { return; } |
|||
var o = offset * 60 * 1000; |
|||
p.killChunks(); if (!confirm('done killChunks(). Continue?\n---\n' + p.data)) { return; } |
|||
return new Date(Number(d) + o); |
|||
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; } |
|||
* This relies on the Date parser understanding en-US dates, |
|||
* which is pretty safe assumption, but not perfect. |
|||
*/ |
|||
function convertTimeZone(date, timeZone) { |
|||
return new Date(date.toLocaleString('en-US', { timeZone: timeZone })); |
|||
} |
} |
||
p.html=wiki2html(p.data, base); // needs livepreview |
|||
function formattedDateTime(date) { |
|||
p.fixHTML(); if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { return; } |
|||
// fallback for IE11 and unknown timezones |
|||
p.stripLongTemplates(); if (!confirm('done stripLongTemplates(). Continue?\n---\n' + p.html)) { return; } |
|||
if (useTimeOffset()) { |
|||
alert('finished preview - end result follows.\n---\n' + p.html); |
|||
return formattedDate(date) + ' ' + formattedTime(date); |
|||
} |
|||
//</NOLITE> |
|||
/** |
|||
if (getMWDateFormat() === 'ISO 8601') { |
|||
Works around livepreview bugs. |
|||
var d2 = convertTimeZone(date, getTimeZone()); |
|||
@private |
|||
return ( |
|||
*/ |
|||
map(zeroFill, [d2.getFullYear(), d2.getMonth() + 1, d2.getDate()]).join('-') + |
|||
Previewmaker.prototype.fixHTML = function() { |
|||
'T' + |
|||
if(!this.html) return; |
|||
map(zeroFill, [d2.getHours(), d2.getMinutes(), d2.getSeconds()]).join(':') |
|||
); |
|||
} |
|||
var ret = this.html; |
|||
var options = getValueOf('popupDateTimeFormatterOptions'); |
|||
options.timeZone = getTimeZone(); |
|||
return date.toLocaleString(getLocales(), options); |
|||
} |
|||
// fix question marks in wiki links |
|||
function formattedDate(date) { |
|||
// maybe this'll break some stuff :-( |
|||
// fallback for IE11 and unknown timezones |
|||
ret=ret.replace(RegExp('\(<a href="' + pg.wiki.articlePath + '/[^"]*\)[?]\(.*?"\)', 'g'), '$1%3F$2'); |
|||
if (useTimeOffset()) { |
|||
ret=ret.replace(RegExp('\(<a href=\'' + pg.wiki.articlePath + '/[^\']*\)[?]\(.*?\'\)', 'g'), '$1%3F$2'); |
|||
// we adjust the UTC time, so we print the adjusted UTC, but not really UTC values |
|||
// FIXME fix up % too |
|||
var d2 = adjustDate(date, getTimeOffset()); |
|||
return map(zeroFill, [d2.getUTCFullYear(), d2.getUTCMonth() + 1, d2.getUTCDate()]).join('-'); |
|||
} |
|||
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. |
|||
if (getMWDateFormat() === 'ISO 8601') { |
|||
Also activates wikilinks in the preview for subpopups if the popupSubpopups option is true. |
|||
var d2 = convertTimeZone(date, getTimeZone()); |
|||
*/ |
|||
return map(zeroFill, [d2.getFullYear(), d2.getMonth() + 1, d2.getDate()]).join('-'); |
|||
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&action=query&'; |
|||
var htmlGenerator=function(a,d){alert('invalid html generator');}; |
|||
var usernameart = ''; |
|||
switch (queryType) { |
|||
case 'history': |
|||
url += 'meta=userinfo&uiprop=options&titles=' + art + '&prop=revisions&rvlimit=' + |
|||
getValueOf('popupHistoryPreviewLimit'); |
|||
htmlGenerator=APIhistoryPreviewHTML; |
|||
break; |
|||
case 'category': |
|||
url += 'list=categorymembers&rawcontinue=&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&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&meta=userinfo&uiprop=options&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&rawcontinue=&bltitle=' + art; |
|||
htmlGenerator=APIbacklinksPreviewHTML; |
|||
break; |
|||
} |
|||
pendingNavpopTask(navpop); |
|||
if( !mw.config.get('wgEnableAPI') ) { |
|||
/* The API is not available */ |
|||
htmlGenerator=function(a,d){ |
|||
return 'This function of navigation popups now requires a MediaWiki ' + |
|||
'installation with the <a href="http://www.mediawiki.org/wiki/API">API</a> enabled.'; }; |
|||
} |
|||
var callback=function(d){ |
|||
log( "callback of API functions was hit" ); |
|||
showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d); |
|||
}; |
|||
if (pg.flag.isIE) { |
|||
url = url + '&*'; //to circumvent https://bugzilla.wikimedia.org/show_bug.cgi?id=28840 |
|||
} |
|||
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) { |
|||
var options = getValueOf('popupDateFormatterOptions'); |
|||
list.sort(function(x,y) { return (x==y ? 0 : (x<y ? -1 : 1)); }); |
|||
options.timeZone = getTimeZone(); |
|||
var buf=[]; |
|||
return date.toLocaleDateString(getLocales(), options); |
|||
for (var i=0; i<list.length; ++i) { |
|||
buf.push(wikiLink({article: new Title(list[i]), |
|||
text: list[i].split(' ').join(' '), |
|||
action: 'view'})); |
|||
} |
} |
||
return buf.join(', '); |
|||
} |
|||
function getTimeOffset(tz) { |
|||
if( tz ) { |
|||
// fallback for IE11 and unknown timezones |
|||
if ( |
if( tz.indexOf('|') > -1 ) { |
||
// New format |
|||
// we adjust the UTC time, so we print the adjusted UTC, but not really UTC values |
|||
return parseInt(tz.split('|')[1],10); |
|||
var d2 = adjustDate(date, getTimeOffset()); |
|||
} else if ( tz.indexOf(':') > -1 ) { |
|||
return map(zeroFill, [d2.getUTCHours(), d2.getUTCMinutes(), d2.getUTCSeconds()]).join(':'); |
|||
// Old format |
|||
return( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) ); |
|||
} |
} |
||
} |
|||
return 0; |
|||
} |
|||
/* |
|||
if (getMWDateFormat() === 'ISO 8601') { |
|||
* Creates a HTML table that's shown in the history and user-contribs popups. |
|||
var d2 = convertTimeZone(date, getTimeZone()); |
|||
* @param {Object[]} h - a list of revisions, returned from the API |
|||
return map(zeroFill, [d2.getHours(), d2.getMinutes(), d2.getSeconds()]).join(':'); |
|||
* @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; |
|||
var options = getValueOf('popupTimeFormatterOptions'); |
|||
if(reallyContribs) { |
|||
options.timeZone = getTimeZone(); |
|||
return date.toLocaleTimeString(getLocales(), options); |
|||
// 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 += ' | '; |
|||
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=' + h[i].revid + '">' + popupString('cur') + '</a>'; |
|||
result += ' | '; |
|||
result += '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() + |
|||
'&diff=prev&oldid=' + h[i].revid + '">' + popupString('last') + '</a>'; |
|||
result += ')'; |
|||
return result; |
|||
}; |
|||
} |
} |
||
for (var i=0; i<h.length; ++i) { |
|||
// Get the proper groupnames for the technicalgroups |
|||
if (reallyContribs) { |
|||
function fetchUserGroupNames(userinfoResponse) { |
|||
page = h[i].title; |
|||
var queryObj = getJsObj(userinfoResponse).query; |
|||
curart = new Title(page); |
|||
} |
|||
var messages = []; |
|||
var minor = (typeof h[i].minor == 'undefined') ? '' : '<b>m </b>'; |
|||
if (user.groups) { |
|||
var editDate = adjustDate(getDateFromTimestamp(h[i].timestamp), timeOffset); |
|||
user.groups.forEach(function (groupName) { |
|||
var thisDay = dayFormat(editDate); |
|||
if (['*', 'user', 'autoconfirmed', 'extendedconfirmed', 'named'].indexOf(groupName) === -1) { |
|||
var thisTime = timeFormat(editDate); |
|||
messages.push('group-' + groupName + '-member'); |
|||
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( typeof h[i].userhidden == "undefined" ) { |
|||
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 : '') + |
|||
if (queryObj.globaluserinfo && queryObj.globaluserinfo.groups) { |
|||
'<a href="' + col3url + '">' + col3txt + '</a></td>'); |
|||
queryObj.globaluserinfo.groups.forEach(function (groupName) { |
|||
var comment=''; |
|||
messages.push('group-' + groupName + '-member'); |
|||
var c=h[i].comment || h[i]['*']; |
|||
}); |
|||
if (c) { |
|||
comment=new Previewmaker(c, new Title(curart).toUrl()).editSummaryPreview(); |
|||
} else if (typeof h[i].commenthidden != "undefined" ) { |
|||
comment=popupString('revdel'); |
|||
} |
} |
||
html.push('<td>' + (!reallyContribs ? minor : '') + comment + '</td>'); |
|||
return getMwApi().loadMessagesIfMissing(messages); |
|||
html.push('</tr>'); |
|||
html=[html.join('')]; |
|||
} |
} |
||
html.push('</table>'); |
|||
return html.join(''); |
|||
} |
|||
function getDateFromTimestamp(t) { |
|||
function showAPIPreview(queryType, html, id, navpop, download) { |
|||
var s=t.split(/[^0-9]/); |
|||
// DJ: done |
|||
switch(s.length) { |
|||
var target = 'popupPreview'; |
|||
case 0: return null; |
|||
completedNavpopTask(navpop); |
|||
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) { |
|||
switch (queryType) { |
|||
if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); } |
|||
case 'imagelinks': |
|||
return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-'); |
|||
case 'category': |
|||
} |
|||
target = 'popupPostPreview'; |
|||
break; |
|||
function timeFormat(editDate, utc) { |
|||
case 'userinfo': |
|||
if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); } |
|||
target = 'popupUserData'; |
|||
return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':'); |
|||
break; |
|||
} |
|||
case 'revision': |
|||
insertPreview(download); |
|||
function showAPIPreview(queryType, html, id, navpop, download) { |
|||
return; |
|||
// DJ: done |
|||
} |
|||
var target='popupPreview'; |
|||
setPopupTipsAndHTML(html, target, id); |
|||
switch (queryType) { |
|||
case 'imagelinks': |
|||
case 'category': |
|||
case 'userinfo': |
|||
target='popupPostPreview'; break; |
|||
} |
} |
||
setPopupTipsAndHTML(html, target, id); |
|||
completedNavpopTask(navpop); |
|||
} |
|||
function APIbacklinksPreviewHTML(article, download, navpop) { |
|||
try { |
|||
var jsObj=getJsObj(download.data); |
|||
var list=jsObj.query.backlinks; |
|||
if (page.missing) { |
|||
var html=[]; |
|||
// TODO we need to fix this proper later on |
|||
if (!list) { return popupString('No backlinks found'); } |
|||
download.owner = null; |
|||
for ( var i=0; i < list.length; i++ ) { |
|||
return; |
|||
var t=new Title(list[i].title); |
|||
} |
|||
html.push('<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t + '</a>'); |
|||
var content = |
|||
page && page.revisions && page.revisions[0] && |
|||
page.revisions[0].slots && page.revisions[0].slots.main && |
|||
page.revisions[0].slots.main.contentmodel === 'wikitext' ? |
|||
page.revisions[0].slots.main.content : |
|||
null; |
|||
if (typeof content === 'string') { |
|||
download.data = content; |
|||
download.lastModified = new Date(page.revisions[0].timestamp); |
|||
} |
|||
if (page.pageprops.wikibase_item) { |
|||
download.wikibaseItem = page.pageprops.wikibase_item; |
|||
download.wikibaseRepo = jsObj.query.wikibase.repo.url.base + |
|||
jsObj.query.wikibase.repo.url.articlepath; |
|||
} |
|||
} catch (someError) { |
|||
return 'Revision preview failed :('; |
|||
} |
} |
||
html=html.join(', '); |
|||
if (jsObj['query-continue'] && jsObj['query-continue'].backlinks && jsObj['query-continue'].backlinks.blcontinue) { |
|||
html += popupString(' and more'); |
|||
} |
|||
return html; |
|||
} catch (someError) { |
|||
return 'backlinksPreviewHTML went wonky'; |
|||
} |
} |
||
} |
|||
pg.fn.APIsharedImagePagePreviewHTML = function APIsharedImagePagePreviewHTML(obj) { |
|||
function APIbacklinksPreviewHTML(article, download /*, navpop*/) { |
|||
log( "APIsharedImagePagePreviewHTML" ); |
|||
try { |
|||
var popupid = obj.requestid; |
|||
var jsObj = getJsObj(download.data); |
|||
if( obj.query && obj.query.pages ) |
|||
{ |
|||
var page=anyChild(obj.query.pages ); |
|||
var content=(page && page.revisions ) ? page.revisions[0]['*'] : null; |
|||
if (!list) { |
|||
if( content ) |
|||
return popupString('No backlinks found'); |
|||
{ |
|||
/* Not entirely safe, but the best we can do */ |
|||
for (var i = 0; i < list.length; i++) { |
|||
var p=new Previewmaker(content, pg.current.link.navpopup.article, pg.current.link.navpopup); |
|||
var t = new Title(list[i].title); |
|||
p.makePreview(); |
|||
setPopupHTML( p.html, "popupSecondPreview", popupid ); |
|||
'<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t.toString().entify() + '</a>' |
|||
); |
|||
} |
|||
html = html.join(', '); |
|||
if (jsObj.continue && jsObj.continue.blcontinue) { |
|||
html += popupString(' and more'); |
|||
} |
|||
return html; |
|||
} catch (someError) { |
|||
return 'backlinksPreviewHTML went wonky'; |
|||
} |
} |
||
} |
} |
||
}; |
|||
function APIimagepagePreviewHTML(article, download, navpop) { |
|||
pg.fn.APIsharedImagePagePreviewHTML = function APIsharedImagePagePreviewHTML(obj) { |
|||
try { |
|||
log('APIsharedImagePagePreviewHTML'); |
|||
var |
var jsObj=getJsObj(download.data); |
||
var page=anyChild(jsObj.query.pages); |
|||
var content=(page && page.revisions ) ? page.revisions[0]['*'] : null; |
|||
var page = anyChild(obj.query.pages); |
|||
var ret=''; |
|||
var alt=''; |
|||
page && page.revisions && page.revisions[0] && |
|||
try{alt=navpop.parentAnchor.childNodes[0].alt;} catch(e){} |
|||
page.revisions[0].slots && page.revisions[0].slots.main && |
|||
if (alt) { |
|||
page.revisions[0].slots.main.contentmodel === 'wikitext' ? |
|||
ret = ret + '<hr /><b>' + popupString('Alt text:') + '</b> ' + pg.escapeQuotesHTML(alt); |
|||
page.revisions[0].slots.main.content : |
|||
} |
|||
null; |
|||
if (content) { |
|||
var p=prepPreviewmaker(content, article, navpop); |
|||
p.makePreview(); |
|||
pg && |
|||
if (p.html) { ret += '<hr />' + p.html; } |
|||
pg.current && |
|||
if (getValueOf('popupSummaryData')) { |
|||
pg.current.link && |
|||
var info=getPageInfo(content, download); |
|||
pg.current.link.navpopup |
|||
) |
log(info); |
||
setPopupTrailer(info, navpop.idNumber); |
|||
/* 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); |
|||
} |
} |
||
} |
} |
||
if (page && page.imagerepository == "shared" ) { |
|||
}; |
|||
var art=new Title(article); |
|||
var encart = encodeURIComponent( "File:" + art.stripNamespace() ); |
|||
function APIimagepagePreviewHTML(article, download, navpop) { |
|||
var shared_url = pg.wiki.apicommonsbase + '?format=json&callback=pg.fn.APIsharedImagePagePreviewHTML' + |
|||
try { |
|||
'&requestid=' + navpop.idNumber + |
|||
var jsObj = getJsObj(download.data); |
|||
'&action=query&prop=revisions&rvprop=content&titles=' + encart; |
|||
var page = anyChild(jsObj.query.pages); |
|||
if (pg.flag.isIE) { |
|||
shared_url = shared_url + '&*'; //to circumvent https://bugzilla.wikimedia.org/show_bug.cgi?id=28840 |
|||
page && page.revisions && page.revisions[0] && |
|||
page.revisions[0].slots && page.revisions[0].slots.main && |
|||
page.revisions[0].slots.main.contentmodel === 'wikitext' ? |
|||
page.revisions[0].slots.main.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&rvslots=main&rvprop=content&titles=' + |
|||
encart; |
|||
ret = ret +'<hr />' + popupString( 'Image from Commons') + |
|||
ret = |
|||
': <a href="' + pg.wiki.commonsbase + '?title=' + encart + '">' + |
|||
ret + |
|||
' |
popupString( 'Description page') + '</a>'; |
||
mw.loader.load( shared_url ); |
|||
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 :('; |
|||
} |
} |
||
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'); |
|||
} |
} |
||
if (ret.length === 0) { return popupString('No image links found'); } |
|||
} catch (someError) { |
|||
return ' |
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 :('; |
|||
} |
} |
||
if (ret.length === 0) { return popupString('Empty category'); } |
|||
ret = '<h2>' + tprintf('Category members (%s shown)', [ret.length]) + '</h2>' +linkList(ret); |
|||
if (jsobj['query-continue'] && jsobj['query-continue'].categorymembers && jsobj['query-continue'].categorymembers.cmcontinue) { |
|||
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 :('; } |
|||
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 ) |
|||
ret.push('<b>' + popupString('BLOCKED') + '</b>'); |
|||
var user = anyChild(queryobj.users); |
|||
if( globaluserinfo && ( 'locked' in globaluserinfo || 'hidden' in globaluserinfo ) ) { |
|||
if (user) { |
|||
var lockedSulAccountIsAttachedToThis = true; |
|||
var globaluserinfo = queryobj.globaluserinfo; |
|||
for( var i=0; globaluserinfo.unattached && i < globaluserinfo.unattached.length; i++) { |
|||
if (user.invalid === '') { |
|||
if ( globaluserinfo.unattached[i].wiki === mw.config.get('wgDBname') ) { |
|||
ret.push(popupString('Invalid user')); |
|||
lockedSulAccountIsAttachedToThis=false; |
|||
} else if (user.missing === '') { |
|||
break; |
|||
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 (lockedSulAccountIsAttachedToThis) { |
|||
if (globaluserinfo && ('locked' in globaluserinfo || 'hidden' in globaluserinfo)) { |
|||
if ( 'locked' in globaluserinfo ) ret.push('<b><i>' + popupString('LOCKED') + '</i></b>'); |
|||
var lockedSulAccountIsAttachedToThis = true; |
|||
if ( 'hidden' in globaluserinfo ) ret.push('<b><i>' + popupString('HIDDEN') + '</i></b>'); |
|||
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) { |
|||
if( getValueOf('popupShowGender') && user.gender ) { |
|||
switch( user.gender ) { |
|||
case 'male': |
|||
case "male": ret.push( popupString( "\u2642" ) ); break; |
|||
case "female": ret.push( popupString( "\u2640" ) ); break; |
|||
break; |
|||
} |
|||
case 'female': |
|||
} |
|||
ret.push(popupString('she/her') + ' · '); |
|||
if( user.groups ) { |
|||
break; |
|||
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 (user.groups) { |
|||
if( globaluserinfo && globaluserinfo.groups ) { |
|||
user.groups.forEach(function (groupName) { |
|||
for( var k=0; k < globaluserinfo.groups.length; k++) { |
|||
if (['*', 'user', 'autoconfirmed', 'extendedconfirmed', 'named'].indexOf(groupName) === -1) { |
|||
ret.push( '<i>'+pg.escapeQuotesHTML(globaluserinfo.groups[k])+'</i>' ); |
|||
ret.push( |
|||
pg.escapeQuotesHTML(mw.message('group-' + groupName + '-member', user.gender).text()) |
|||
); |
|||
} |
|||
}); |
|||
} |
|||
if (globaluserinfo && globaluserinfo.groups) { |
|||
globaluserinfo.groups.forEach(function (groupName) { |
|||
ret.push( |
|||
'<i>' + |
|||
pg.escapeQuotesHTML( |
|||
mw.message('group-' + groupName + '-member', user.gender).text() |
|||
) + |
|||
'</i>' |
|||
); |
|||
}); |
|||
} |
|||
if (user.registration) { |
|||
ret.push( |
|||
pg.escapeQuotesHTML( |
|||
(user.editcount ? user.editcount : '0') + |
|||
popupString(' edits since: ') + |
|||
(user.registration ? formattedDate(new Date(user.registration)) : '') |
|||
) |
|||
); |
|||
} |
} |
||
} |
} |
||
if( user.registration ) |
|||
ret.push( pg.escapeQuotesHTML((user.editcount?user.editcount:'0') + popupString(' edits since: ') + (user.registration?dayFormat(getDateFromTimestamp(user.registration)):'')) ); |
|||
} |
|||
if (queryobj.usercontribs.length) { |
|||
ret.push( popupString('last edit on ') + dayFormat(getDateFromTimestamp(queryobj.usercontribs[0].timestamp)) ); |
|||
ret.push( |
|||
} |
|||
popupString('last edit on ') + formattedDate(new Date(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++) { |
|||
ret.push('<b>' + popupString(queryobj.blocks[l].rangestart === queryobj.blocks[l].rangeend ? 'BLOCKED' : 'RANGEBLOCKED') + '</b>' ); |
|||
} |
} |
||
} |
|||
ret = '<hr />' + ret.join( ', ' ); |
|||
return ret; |
|||
} |
|||
function APIcontribsPreviewHTML(article, download, navpop) { |
|||
if (queryobj.blocks) { |
|||
return APIhistoryPreviewHTML(article, download, navpop, true); |
|||
ret.push(popupString('IP user')); //we only request list=blocks for IPs |
|||
} |
|||
for (var l = 0; l < queryobj.blocks.length; l++) { |
|||
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>'); |
|||
} |
|||
} |
|||
function APIhistoryPreviewHTML(article, download, navpop, reallyContribs) { |
|||
// if any element of ret ends with ' · ', merge it with the next element to avoid |
|||
try { |
|||
// the .join(', ') call inserting a comma after it |
|||
var jsobj=getJsObj(download.data); |
|||
for (var m = 0; m < ret.length - 1; m++) { |
|||
var tz=jsobj.query.userinfo.options.timecorrection; |
|||
if (ret[m].length > 3 && ret[m].substring(ret[m].length - 3) === ' · ') { |
|||
var edits = []; |
|||
if( reallyContribs ) { |
|||
ret.splice(m + 1, 1); // delete element at index m+1 |
|||
edits=jsobj.query.usercontribs; |
|||
m--; |
|||
} else { |
|||
edits=anyChild(jsobj.query.pages).revisions; |
|||
} |
} |
||
var timeOffset = getTimeOffset(tz); |
|||
Cookie.create('popTz', timeOffset, 1); |
|||
var ret=editPreviewTable(article, edits, reallyContribs, timeOffset); |
|||
ret = '<hr />' + ret.join(', '); |
|||
return ret; |
return ret; |
||
} catch (someError) { |
|||
return 'History preview failed :-('; |
|||
} |
} |
||
} |
|||
function APIcontribsPreviewHTML(article, download, navpop) { |
|||
return APIhistoryPreviewHTML(article, download, navpop, true); |
|||
} |
|||
//</NOLITE> |
|||
function APIhistoryPreviewHTML(article, download, navpop, reallyContribs) { |
|||
// ENDFILE: querypreview.js |
|||
try { |
|||
// STARTFILE: debug.js |
|||
var jsobj = getJsObj(download.data); |
|||
//////////////////////////////////////////////////////////////////// |
|||
var edits = []; |
|||
// Debugging functions |
|||
if (reallyContribs) { |
|||
//////////////////////////////////////////////////////////////////// |
|||
edits = jsobj.query.usercontribs; |
|||
} else { |
|||
edits = anyChild(jsobj.query.pages).revisions; |
|||
} |
|||
function setupDebugging() { |
|||
var ret = editPreviewTable(article, edits, reallyContribs); |
|||
//<NOLITE> |
|||
return ret; |
|||
if (window.popupDebug) { // popupDebug is set from .version |
|||
} catch (someError) { |
|||
window.log=function(x) { //if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; }; |
|||
return popupString('History preview failed'); |
|||
window.console.log(x); |
|||
} |
|||
}; |
|||
window.errlog=function(x) { |
|||
window.console.error(x); |
|||
}; |
|||
log('Initializing logger'); |
|||
} else { |
|||
//</NOLITE> |
|||
window.log = function(x) {}; |
|||
window.errlog = function(x) {}; |
|||
//<NOLITE> |
|||
} |
} |
||
//</NOLITE> |
|||
} |
|||
// ENDFILE: debug.js |
|||
// STARTFILE: images.js |
|||
// load image of type Title. |
|||
// ENDFILE: querypreview.js |
|||
function loadImage(image, navpop) { |
|||
if (typeof image.stripNamespace != 'function') { alert('loadImages bad'); } |
|||
// API call to retrieve image info. |
|||
if ( !getValueOf('popupImages') || !mw.config.get('wgEnableAPI') ) return; |
|||
// STARTFILE: debug.js |
|||
if ( !isValidImageName(image) ) return false; |
|||
//////////////////////////////////////////////////////////////////// |
|||
// Debugging functions |
|||
var art=image.urlString(); |
|||
//////////////////////////////////////////////////////////////////// |
|||
var url=pg.wiki.apiwikibase + '?format=json&action=query'; |
|||
function setupDebugging() { |
|||
url += '&prop=imageinfo&iiprop=url|mime&iiurlwidth=' + getValueOf('popupImageSizeLarge'); |
|||
if (window.popupDebug) { |
|||
url += '&titles=' + art; |
|||
// popupDebug is set from .version |
|||
if (pg.flag.isIE) { |
|||
window.log = function (x) { |
|||
url = url + '&*'; //to circumvent https://bugzilla.wikimedia.org/show_bug.cgi?id=28840 |
|||
//if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; }; |
|||
window.console.log(x); |
|||
}; |
|||
window.errlog = function (x) { |
|||
window.console.error(x); |
|||
}; |
|||
log('Initializing logger'); |
|||
} else { |
|||
window.log = function () {}; |
|||
window.errlog = function () {}; |
|||
} |
|||
} |
} |
||
// ENDFILE: debug.js |
|||
pendingNavpopTask(navpop); |
|||
// STARTFILE: images.js |
|||
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'); } |
|||
} |
|||
// load image of type Title. |
|||
function loadImage(image, navpop) { |
|||
if (typeof image.stripNamespace != 'function') { |
|||
alert('loadImages bad'); |
|||
} |
|||
// API call to retrieve image info. |
|||
function popupsInsertImage(id, navpop, download) { |
|||
if (!getValueOf('popupImages')) { |
|||
log( "popupsInsertImage"); |
|||
return; |
|||
var imageinfo; |
|||
} |
|||
try { |
|||
if (!isValidImageName(image)) { |
|||
var jsObj=getJsObj(download.data); |
|||
return false; |
|||
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); |
|||
var art = image.urlString(); |
|||
if (!popupImage) { |
|||
log( "could not find insertion point for image"); |
|||
var url = pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query'; |
|||
return; |
|||
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'); |
|||
} |
|||
} |
} |
||
popupImage.width=getValueOf('popupImageSize'); |
|||
function popupsInsertImage(id, navpop, download) { |
|||
popupImage.style.display='inline'; |
|||
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; |
|||
} |
|||
// Set the source for the image. |
|||
var popupImage = document.getElementById('popupImg' + id); |
|||
if( imageinfo.thumburl ) |
|||
if (!popupImage) { |
|||
popupImage.src=imageinfo.thumburl; |
|||
log('could not find insertion point for image'); |
|||
else if( imageinfo.mime.indexOf("image") === 0 ){ |
|||
return; |
|||
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"); |
|||
popupImage.width = getValueOf('popupImageSize'); |
|||
popupImage.style.display = 'inline'; |
|||
var a=document.getElementById("popupImageLink"+id); |
|||
// Set the source for the image. |
|||
if (a === null) { return null; } |
|||
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"); |
|||
} |
|||
// Determine the action of the surrouding imagelink. |
|||
var a = document.getElementById('popupImageLink' + id); |
|||
switch (getValueOf('popupThumbAction')) { |
|||
if (a === null) { |
|||
case 'imagepage': |
|||
return null; |
|||
if (pg.current.article.namespaceId()!=pg.nsImageId) { |
|||
} |
|||
a.href=imageinfo.descriptionurl; |
|||
// FIXME: unreliable pg.idNumber |
|||
// Determine the action of the surrouding imagelink. |
|||
popTipsSoonFn('popupImage' + id)(); |
|||
switch (getValueOf('popupThumbAction')) { |
|||
break; |
|||
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; |
|||
} |
} |
||
/* 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; |
|||
} |
|||
// Toggles the image between inline small and navpop fullwidth. |
|||
if (!img.style.width || img.style.width === '') { |
|||
// It's the same image, no actual sizechange occurs, only display width. |
|||
img.style.width = '100%'; |
|||
function toggleSize() { |
|||
} else { |
|||
var imgContainer=this; |
|||
img.style.width = ''; |
|||
if (!imgContainer) { |
|||
} |
|||
alert('imgContainer is null :/'); |
|||
return; |
|||
} |
|||
img=imgContainer.firstChild; |
|||
if (!img) { |
|||
alert('img is null :/'); |
|||
return; |
|||
} |
} |
||
if (!img.style.width || img.style.width==='') { |
|||
// Returns one title of an image from wikiText. |
|||
img.style.width='100%'; |
|||
function getValidImageFromWikiText(wikiText) { |
|||
} else { |
|||
// nb in pg.re.image we're interested in the second bracketed expression |
|||
img.style.width=''; |
|||
// this may change if the regex changes :-( |
|||
} |
|||
//var match=pg.re.image.exec(wikiText); |
|||
} |
|||
var matched = null; |
|||
var match; |
|||
// Returns one title of an image from wikiText. |
|||
// strip html comments, used by evil bots :-( |
|||
function getValidImageFromWikiText(wikiText) { |
|||
var t = removeMatchesUnless( |
|||
// nb in pg.re.image we're interested in the second bracketed expression |
|||
wikiText, |
|||
// this may change if the regex changes :-( |
|||
/(<!--[\s\S]*?-->)/, |
|||
//var match=pg.re.image.exec(wikiText); |
|||
1, |
|||
var matched=null; |
|||
/^<!--[^[]*popup/i |
|||
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); |
|||
} |
} |
||
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]=''; |
|||
continue; |
|||
} |
|||
split[i] = ''; |
|||
} |
|||
return split.join(''); |
|||
} |
} |
||
return split.join(''); |
|||
} |
|||
//</NOLITE> |
|||
// ENDFILE: images.js |
|||
// ENDFILE: images.js |
|||
// STARTFILE: namespaces.js |
|||
// Set up namespaces and other non-strings.js localization |
|||
// (currently that means redirs too) |
|||
// STARTFILE: namespaces.js |
|||
// Set up namespaces and other non-strings.js localization |
|||
// (currently that means redirs too) |
|||
function namespaceListToRegex(list) { |
|||
return RegExp('^('+list.join('|').split(' ').join('[ _]')+'):'); |
|||
pg.nsSpecialId = -1; |
|||
} |
|||
pg.nsMainspaceId = 0; |
|||
pg.nsImageId = 6; |
|||
pg.nsUserId = 2; |
|||
pg.nsUsertalkId = 3; |
|||
pg.nsCategoryId = 14; |
|||
pg.nsTemplateId = 10; |
|||
} |
|||
function setNamespaces() { |
|||
pg.nsSpecialId = -1; |
|||
var r = 'redirect'; |
|||
pg.nsMainspaceId = 0; |
|||
var R = 'REDIRECT'; |
|||
pg.nsImageId = 6; |
|||
var redirLists = { |
|||
pg.nsUserId = 2; |
|||
ar: [R, 'تحويل'], |
|||
pg.nsUsertalkId = 3; |
|||
be: [r, 'перанакіраваньне'], |
|||
pg.nsCategoryId = 14; |
|||
bg: [r, 'пренасочване', 'виж'], |
|||
pg.nsTemplateId = 10; |
|||
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'], |
|||
'nds-nl': [R, 'DEURVERWIEZING', 'DUURVERWIEZING'], |
|||
nl: [R, 'DOORVERWIJZING'], |
|||
nn: [r, 'omdiriger'], |
|||
pl: [R, 'PATRZ', 'PRZEKIERUJ', 'TAM'], |
|||
pt: [R, 'redir'], |
|||
ru: [R, 'ПЕРЕНАПРАВЛЕНИЕ', 'ПЕРЕНАПР'], |
|||
sk: [r, 'presmeruj'], |
|||
sr: [r, 'Преусмери', 'преусмери', 'ПРЕУСМЕРИ', 'Preusmeri', 'preusmeri', 'PREUSMERI'], |
|||
tr: [R, 'YÖNLENDİRME', 'yönlendirme', 'YÖNLENDİR', 'yönlendir'], |
|||
tt: [R, 'yünältü', 'перенаправление', 'перенапр'], |
|||
uk: [R, 'ПЕРЕНАПРАВЛЕННЯ', 'ПЕРЕНАПР'], |
|||
vi: [r, 'đổi'], |
|||
yi: [R, 'ווייטערפירן'], |
|||
zh: [R, '重定向'], // no comma |
|||
}; |
|||
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 |
|||
//en.wikipedia.org/w/api.php?action=sitematrix&format=json&smtype=language&smlangprop=code&formatversion=2 |
|||
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 = /^$/; |
|||
} |
|||
} |
|||
function setRedirs() { |
|||
// return a regexp pattern matching all variants to write the given namespace |
|||
var r='redirect'; |
|||
function nsRe(namespaceId) { |
|||
var R='REDIRECT'; |
|||
var imageNamespaceVariants = []; |
|||
var redirLists={ |
|||
$.each(mw.config.get('wgNamespaceIds'), function (_localizedNamespaceLc, _namespaceId) { |
|||
//<NOLITE> |
|||
if (_namespaceId != namespaceId) { |
|||
'ar': [ R, 'تحويل' ], |
|||
return; |
|||
'be': [ r, 'перанакіраваньне' ], |
|||
} |
|||
'bg': [ r, 'пренасочване', 'виж' ], |
|||
_localizedNamespaceLc = upcaseFirst(_localizedNamespaceLc); |
|||
'bs': [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ], |
|||
imageNamespaceVariants.push( |
|||
'cs': [ R, 'PŘESMĚRUJ' ], |
|||
mw.util.escapeRegExp(_localizedNamespaceLc).split(' ').join('[ _]') |
|||
'cy': [ r, 'ail-cyfeirio' ], |
|||
); |
|||
'de': [ R, 'WEITERLEITUNG' ], |
|||
imageNamespaceVariants.push(mw.util.escapeRegExp(encodeURI(_localizedNamespaceLc))); |
|||
'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() { |
|||
return '(?:' + imageNamespaceVariants.join('|') + ')'; |
|||
if (pg.wiki.wikimedia) { |
|||
// From http://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 nsReImage() { |
|||
function nsRe(namespaceId) { |
|||
var imageNamespaceVariants = []; |
|||
jQuery.each(mw.config.get('wgNamespaceIds'), function(_localizedNamespaceLc, _namespaceId) { |
|||
if (_namespaceId!=namespaceId) return; |
|||
//todo: escape regexp fragments! |
|||
_localizedNamespaceLc = upcaseFirst(_localizedNamespaceLc); |
|||
imageNamespaceVariants.push(_localizedNamespaceLc.split(' ').join('[ _]')); |
|||
imageNamespaceVariants.push(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(); |
|||
// ENDFILE: namespaces.js |
|||
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) { |
|||
// STARTFILE: selpop.js |
|||
var div=document.getElementById('selectionPreview'); |
|||
function getEditboxSelection() { |
|||
if (!div) { |
|||
// see http://www.webgurusforum.com/8/12/0 |
|||
div = document.createElement('div'); |
|||
var editbox; |
|||
div.id='selectionPreview'; |
|||
try { |
try { |
||
var box=document.editform.wpTextbox1; |
|||
box.parentNode.insertBefore(div, box); |
|||
} catch (dang) { |
|||
} catch (error) { |
|||
return; |
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); |
|||
} |
} |
||
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 |
|||
function doSelectionPopup() { |
|||
they look like and so on. |
|||
// popup if the selection looks like [[foo|anything afterwards at all |
|||
// or [[foo|bar]]text without ']]' |
|||
<code>Mousetracker</code> "captures" the mouse using |
|||
// or [[foo|bar]] |
|||
<code>document.onmousemove</code>. |
|||
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; |
|||
} |
|||
var article = new Title(sel.substring(open + 2, pipe < 0 ? close : pipe)); |
|||
if (getValueOf('popupOnEditSelection') == 'boxpreview') { |
|||
return doSeparateSelectionPopup(sel, article); |
|||
} |
|||
if (close > 0 && sel.substring(close + 2).indexOf('[[') >= 0) { |
|||
return; |
|||
} |
|||
var a = document.createElement('a'); |
|||
a.href = pg.wiki.titlebase + article.urlString(); |
|||
mouseOverWikiLink2(a); |
|||
if (a.navpopup) { |
|||
a.navpopup.addHook( |
|||
function () { |
|||
runStopPopupTimer(a.navpopup); |
|||
}, |
|||
'unhide', |
|||
'after' |
|||
); |
|||
} |
|||
} |
|||
function doSeparateSelectionPopup(str, article) { |
|||
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; |
|||
} |
|||
} |
|||
var p = prepPreviewmaker(str, article, newNavpopup(document.createElement('a'), article)); |
|||
p.makePreview(); |
|||
if (p.html) { |
|||
div.innerHTML = p.html; |
|||
} |
|||
div.ranSetupTooltipsAlready = false; |
|||
popTipsSoonFn('selectionPreview')(); |
|||
} |
|||
// ENDFILE: selpop.js |
|||
/** |
|||
// STARTFILE: navpopup.js |
|||
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. |
|||
* @file Defines two classes: {@link Navpopup} and {@link Mousetracker}. |
|||
@type Integer |
|||
* |
|||
*/ |
|||
* <code>Navpopup</code> describes popups: when they appear, where, what |
|||
this.loopDelay=400; |
|||
* they look like and so on. |
|||
* |
|||
* <code>Mousetracker</code> "captures" the mouse using |
|||
* <code>document.onmousemove</code>. |
|||
*/ |
|||
/** |
/** |
||
Timer for the loop. |
|||
* Creates a new Mousetracker. |
|||
@type Timer |
|||
*/ |
|||
* @class The Mousetracker class. This monitors mouse movements and manages associated hooks. |
|||
this.timer=null; |
|||
*/ |
|||
function Mousetracker() { |
|||
/** |
|||
* Interval to regularly run the hooks anyway, in milliseconds. |
|||
* @type {number} |
|||
*/ |
|||
this.loopDelay = 400; |
|||
/** |
|||
Flag - are we switched on? |
|||
* Timer for the loop. |
|||
@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. |
|||
* Flag - are we switched on? |
|||
@param {Function} f A function which is called as |
|||
* @type {boolean} |
|||
<code>f(x,y)</code>. It should return <code>true</code> when it |
|||
*/ |
|||
wants to be removed, and <code>false</code> otherwise. |
|||
this.active = false; |
|||
*/ |
|||
Mousetracker.prototype.addHook = function (f) { |
|||
this.hooks.push(f); |
|||
}; |
|||
/** |
|||
Runs hooks, passing them the x |
|||
* Flag - are we probably inaccurate, i.e. not reflecting the actual mouse position? |
|||
and y coords of the mouse. Hook functions that return true are |
|||
*/ |
|||
passed to {@link Mousetracker#removeHooks} for removal. |
|||
this.dirty = true; |
|||
@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 |
|||
* Array of hook functions. |
|||
if (this.hooks[i](x, y)===true) { |
|||
* @private |
|||
remove=true; |
|||
* @type {Array} |
|||
removeObj[i]=true; |
|||
*/ |
|||
} |
|||
this.hooks = []; |
|||
} |
} |
||
if (remove) { this.removeHooks(removeObj); } |
|||
}; |
|||
/** |
|||
Removes hooks. |
|||
* Adds a hook, to be called when we get events. |
|||
@private |
|||
* @param {Function} f A function which is called as |
|||
@param {Object} removeObj An object whose keys are the index |
|||
* <code>f(x,y)</code>. It should return <code>true</code> when it |
|||
numbers of functions for removal, with values that evaluate to true |
|||
* wants to be removed, and <code>false</code> otherwise. |
|||
*/ |
|||
Mousetracker.prototype.removeHooks = function(removeObj) { |
|||
var newHooks=[]; |
|||
this.hooks.push(f); |
|||
var len = this.hooks.length; |
|||
}; |
|||
for (var i=0; i<len; ++i) { |
|||
if (! removeObj[i]) { newHooks.push(this.hooks[i]); } |
|||
} |
|||
this.hooks=newHooks; |
|||
}; |
|||
/** |
|||
* 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) { |
|||
Event handler for mouse wiggles. |
|||
//~ run the hook function, and remove it if it returns true |
|||
We simply grab the event, set x and y and run the hooks. |
|||
if (this.hooks[i](x, y) === true) { |
|||
This makes the cpu all hot and bothered :-( |
|||
remove = true; |
|||
@private |
|||
removeObj[i] = true; |
|||
@param {Event} e Mousemove event |
|||
} |
|||
*/ |
|||
} |
|||
Mousetracker.prototype.track=function (e) { |
|||
if (remove) { |
|||
//~ Apparently this is needed in IE. |
|||
this.removeHooks(removeObj); |
|||
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; |
|||
* 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; |
|||
}; |
|||
if (docElt) { top=docElt.scrollTop; } |
|||
/** |
|||
top = top || document.body.scrollTop || document.scrollTop || 0; |
|||
* 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; |
|||
x=e.clientX + left; |
|||
if (docElt) { |
|||
y=e.clientY + top; |
|||
left = docElt.scrollLeft; |
|||
} else { return; } |
|||
} |
|||
this.setPosition(x,y); |
|||
left = left || document.body.scrollLeft || document.scrollLeft || 0; |
|||
} |
|||
}; |
|||
/** |
|||
if (docElt) { |
|||
Sets the x and y coordinates stored and takes appropriate action, |
|||
top = docElt.scrollTop; |
|||
running hooks as appropriate. |
|||
} |
|||
@param {Integer} x, y Screen coordinates to set |
|||
top = top || document.body.scrollTop || document.scrollTop || 0; |
|||
*/ |
|||
Mousetracker.prototype.setPosition=function(x,y) { |
|||
x = e.clientX + left; |
|||
this.x = x; |
|||
y = e.clientY + top; |
|||
this.y = y; |
|||
} else { |
|||
if (this.dirty || this.hooks.length === 0) { this.dirty=false; return; } |
|||
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); |
|||
this.setPosition(x, 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>. |
|||
* Sets the x and y coordinates stored and takes appropriate action, |
|||
A half-hearted attempt is made to preserve the old event handler if there is one. |
|||
* running hooks as appropriate. |
|||
*/ |
|||
* @param {number} x Screen coordinates to set |
|||
Mousetracker.prototype.enable = function () { |
|||
* @param {number} y Screen coordinates to set |
|||
if (this.active) { return; } |
|||
*/ |
|||
this.active=true; |
|||
Mousetracker.prototype.setPosition = function (x, y) { |
|||
//~ Save the current handler for mousemove events. This isn't too |
|||
this.x = x; |
|||
//~ robust, of course. |
|||
this.y = y; |
|||
this.savedHandler=document.onmousemove; |
|||
if (this.dirty || this.hooks.length === 0) { |
|||
//~ Gotta save @tt{this} again for the closure, and use apply for |
|||
this.dirty = false; |
|||
//~ the member function. |
|||
return; |
|||
var savedThis=this; |
|||
} |
|||
document.onmousemove=function (e) {savedThis.track.apply(savedThis, [e]);}; |
|||
if (typeof this.lastHook_x != 'number') { |
|||
if (this.loopDelay) { this.timer = setInterval(function() { //log('loop delay in mousetracker is working'); |
|||
this.lastHook_x = -100; |
|||
savedThis.runHooks();}, this.loopDelay); } |
|||
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(); |
|||
} |
|||
} |
|||
}; |
|||
/** |
|||
Disables the tracker, removing the event handler. |
|||
*/ |
|||
* <code>document.onmousemove</code>. A half-hearted attempt is made to preserve the old event |
|||
Mousetracker.prototype.disable = function () { |
|||
* handler if there is one. |
|||
if (!this.active) { return; } |
|||
*/ |
|||
if ($.isFunction(this.savedHandler)) { |
|||
Mousetracker.prototype.enable = function () { |
|||
document.onmousemove=this.savedHandler; |
|||
if (this.active) { |
|||
} else { delete document.onmousemove; } |
|||
return; |
|||
if (this.timer) { clearInterval(this.timer); } |
|||
} |
|||
this.active=false; |
|||
}; |
|||
//~ Save the current handler for mousemove events. This isn't too |
|||
//~ robust, of course. |
|||
this.savedHandler = document.onmousemove; |
|||
//~ Gotta save @tt{this} again for the closure, and use apply for |
|||
//~ the member function. |
|||
var savedThis = this; |
|||
document.onmousemove = function (e) { |
|||
savedThis.track.apply(savedThis, [e]); |
|||
}; |
|||
if (this.loopDelay) { |
|||
this.timer = setInterval(function () { |
|||
//log('loop delay in mousetracker is working'); |
|||
savedThis.runHooks(); |
|||
}, this.loopDelay); |
|||
} |
|||
}; |
|||
/** |
|||
Creates a new 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. |
|||
* Disables the tracker, removing the event handler. |
|||
@type boolean |
|||
*/ |
|||
@private |
|||
Mousetracker.prototype.disable = function () { |
|||
*/ |
|||
if (!this.active) { |
|||
this.visible=false; |
|||
return; |
|||
/** Flag to be set when we want to cancel a previous request to |
|||
} |
|||
show the popup in a little while. |
|||
if (typeof this.savedHandler === 'function') { |
|||
@private |
|||
document.onmousemove = this.savedHandler; |
|||
@type boolean |
|||
} else { |
|||
*/ |
|||
delete document.onmousemove; |
|||
this.noshow=false; |
|||
} |
|||
/** Categorised list of hooks. |
|||
if (this.timer) { |
|||
@see #runHooks |
|||
clearInterval(this.timer); |
|||
@see #addHook |
|||
} |
|||
@private |
|||
this.active = false; |
|||
@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); |
|||
* 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)'); |
|||
/** |
|||
A UID for each Navpopup. This constructor property is just a counter. |
|||
@type integer |
|||
* Read-only. |
|||
@private |
|||
* @type {number} |
|||
*/ |
|||
Navpopup.uid=0; |
|||
this.uid = Navpopup.uid++; |
|||
/** |
|||
Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible. |
|||
* Read-only flag for current visibility of the popup. |
|||
@type boolean |
|||
*/ |
|||
* @private |
|||
Navpopup.prototype.isVisible=function() { |
|||
*/ |
|||
return this.visible; |
|||
}; |
|||
/** |
|||
/** Flag to be set when we want to cancel a previous request to |
|||
Repositions popup using CSS style. |
|||
@private |
|||
@param {integer} x x-coordinate (px) |
|||
* @type {boolean} |
|||
@param {integer} y y-coordinate (px) |
|||
*/ |
|||
@param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition} |
|||
this.noshow = false; |
|||
*/ |
|||
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 + ')'); |
|||
}; |
|||
/** |
|||
/** Categorised list of hooks. |
|||
Prevents popups from being in silly locations. Hopefully. |
|||
* @see #runHooks |
|||
Should not be run if {@link #constrained} is true. |
|||
* @see #addHook |
|||
@private |
|||
*/ |
|||
* @type {Object} |
|||
Navpopup.prototype.limitHorizontalPosition=function() { |
|||
*/ |
|||
if (!this.constrained || this.tooWide) { return; } |
|||
this.hooks = { |
|||
this.updateDimensions(); |
|||
create: [], |
|||
var x=this.left; |
|||
unhide: [], |
|||
var w=this.width; |
|||
hide: [], |
|||
var cWidth=document.body.clientWidth; |
|||
}; |
|||
/** |
|||
* list of unique IDs of hook functions, to avoid duplicates |
|||
* @private |
|||
*/ |
|||
this.hookIds = {}; |
|||
// log('limitHorizontalPosition: x='+x+ |
|||
/** List of downloads associated with the popup. |
|||
// ', this.left=' + this.left + |
|||
* @private |
|||
// ', this.width=' + this.width + |
|||
* @type {Array} |
|||
// ', cWidth=' + cWidth); |
|||
*/ |
|||
this.downloads = []; |
|||
/** |
|||
* Number of uncompleted downloads. |
|||
* @type {number} |
|||
*/ |
|||
this.pending = null; |
|||
if ( (x+w) >= cWidth || |
|||
/** |
|||
( x > 0 && |
|||
* Tolerance in pixels when detecting whether the mouse has left the popup. |
|||
this.maxWidth && |
|||
* @type {number} |
|||
this.width < this.maxWidth && |
|||
*/ |
|||
this. |
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 |
|||
* Flag to toggle running {@link #limitHorizontalPosition} to regulate the popup's position. |
|||
// then reset it so that it should be flush right (well, nearly) |
|||
* @type {boolean} |
|||
this.mainDiv.style.left='-10000px'; |
|||
*/ |
|||
this. |
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? |
|||
* The popup width in pixels. |
|||
log ('limitHorizontalPosition: moving to ('+newLeft + ','+ this.top+');' + ' naturalWidth=' + naturalWidth + ', clientWidth=' + cWidth); |
|||
* @private |
|||
this.reposition(newLeft, null, true); |
|||
* @type {number} |
|||
*/ |
|||
this.width = 0; |
|||
/** |
|||
* The popup width in pixels. |
|||
* @private |
|||
* @type {number} |
|||
*/ |
|||
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); |
|||
// } |
|||
} |
} |
||
}; |
|||
/** |
|||
Counter indicating the z-order of the "highest" popup. |
|||
* A UID for each Navpopup. This constructor property is just a counter. |
|||
We start the z-index at 1000 so that popups are above everything |
|||
* @type {number} |
|||
else on the screen. |
|||
* @private |
|||
@private |
|||
*/ |
|||
@type integer |
|||
Navpopup.uid = 0; |
|||
*/ |
|||
Navpopup.highest=1000; |
|||
/** |
|||
Brings popup to the top of the z-order. |
|||
* Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible. |
|||
We increment the {@link #highest} property of the contructor here. |
|||
* @type {boolean} |
|||
@private |
|||
*/ |
|||
*/ |
|||
Navpopup.prototype.isVisible = function () { |
|||
Navpopup.prototype.raise = function () { |
|||
return this.visible; |
|||
this.mainDiv.style.zIndex=Navpopup.highest + 1; |
|||
}; |
|||
++Navpopup.highest; |
|||
}; |
|||
/** |
|||
Shows the popup provided {@link #noshow} is not true. |
|||
* Repositions popup using CSS style. |
|||
Updates the position, brings the popup to the top of the z-order and unhides it. |
|||
* @private |
|||
*/ |
|||
* @param {number} x x-coordinate (px) |
|||
Navpopup.prototype.show = function () { |
|||
* @param {number} y y-coordinate (px) |
|||
//document.title+='s'; |
|||
* @param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition} |
|||
if (this.noshow) { return; } |
|||
*/ |
|||
//document.title+='t'; |
|||
Navpopup.prototype.reposition = function (x, y, noLimitHor) { |
|||
this.reposition(); |
|||
this.raise(); |
|||
if (typeof x != 'undefined' && x !== null) { |
|||
this.unhide(); |
|||
}; |
|||
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+ |
|||
Runs the {@link #show} method in a little while, unless we're |
|||
// ', this.left=' + this.left + |
|||
already visible. |
|||
// ', this.width=' + this.width + |
|||
@param {integer} time Delay in milliseconds |
|||
// ', cWidth=' + cWidth); |
|||
@see #showSoonIfStable |
|||
*/ |
|||
if ( |
|||
Navpopup.prototype.showSoon = function (time) { |
|||
x + w >= cWidth || |
|||
if (this.visible) { return; } |
|||
(x > 0 && |
|||
this.noshow=false; |
|||
//~ We have to save the value of @tt{this} so that the closure below |
|||
this.width < this.maxWidth && |
|||
//~ works. |
|||
this.height > this.width && |
|||
var savedThis=this; |
|||
x > cWidth - this.maxWidth) |
|||
//this.start_x = Navpopup.tracker.x; |
|||
) { |
|||
//this.start_y = Navpopup.tracker.y; |
|||
// This is a very nasty hack. There has to be a better way! |
|||
setTimeout(function () { |
|||
// We find the "natural" width of the div by positioning it at the far left |
|||
if (Navpopup.tracker.active) { |
|||
// then reset it so that it should be flush right (well, nearly) |
|||
savedThis.reposition.apply(savedThis, [Navpopup.tracker.x + 2, Navpopup.tracker.y + 2]); |
|||
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); |
|||
} |
} |
||
//~ Have to use apply to invoke his member function here |
|||
}; |
|||
savedThis.show.apply(savedThis, []); |
|||
}, time); |
|||
}; |
|||
/** |
|||
Checks to see if the mouse pointer has |
|||
* Counter indicating the z-order of the "highest" popup. |
|||
stabilised (checking every <code>time</code>/2 milliseconds) and runs the |
|||
* We start the z-index at 1000 so that popups are above everything |
|||
{@link #show} method if it has. This method makes {@link #showSoon} redundant. |
|||
* else on the screen. |
|||
@param {integer} time The minimum time (ms) before the popup may be shown. |
|||
* @private |
|||
*/ |
|||
* @type {number} |
|||
Navpopup.prototype.showSoonIfStable = function (time) { |
|||
*/ |
|||
log ('showSoonIfStable, time='+time); |
|||
Navpopup.highest = 1000; |
|||
if (this.visible) { return; } |
|||
this.noshow = false; |
|||
//~ initialize these variables so that we never run @tt{show} after |
|||
/** |
|||
//~ just half the time |
|||
* Brings popup to the top of the z-order. |
|||
this.stable_x = -10000; this.stable_y = -10000; |
|||
* We increment the {@link #highest} property of the contructor here. |
|||
* @private |
|||
*/ |
|||
Navpopup.prototype.raise = function () { |
|||
this.mainDiv.style.zIndex = Navpopup.highest + 1; |
|||
++Navpopup.highest; |
|||
}; |
|||
var stableShow = function() { |
|||
/** |
|||
log('stableShow called'); |
|||
* Shows the popup provided {@link #noshow} is not true. |
|||
var new_x = Navpopup.tracker.x, new_y = Navpopup.tracker.y; |
|||
* Updates the position, brings the popup to the top of the z-order and unhides it. |
|||
var dx = savedThis.stable_x - new_x, dy = savedThis.stable_y - new_y; |
|||
*/ |
|||
var fuzz2 = 0; // savedThis.fuzz * savedThis.fuzz; |
|||
Navpopup.prototype.show = function () { |
|||
//document.title+=' |
//document.title += '[' + [savedThis.stable_x,new_x, savedThis.stable_y,new_y, dx, dy, fuzz2].join(',') + '] '; |
||
if ( dx * dx <= fuzz2 && dy * dy <= fuzz2 ) { |
|||
if (this.noshow) { |
|||
log ('mouse is stable'); |
|||
clearInterval(savedThis.showSoonStableTimer); |
|||
savedThis.reposition.apply(savedThis, [new_x + 2, new_y + 2]); |
|||
savedThis.show.apply(savedThis, []); |
|||
return; |
return; |
||
} |
} |
||
savedThis.stable_x = new_x; savedThis.stable_y = new_y; |
|||
//document.title+='t'; |
|||
this.reposition(); |
|||
this.raise(); |
|||
this.unhide(); |
|||
}; |
}; |
||
var savedThis = this; |
|||
this.showSoonStableTimer = setInterval(stableShow, time/2); |
|||
}; |
|||
/** |
|||
Makes the popup unhidable until we call {@link #unstick}. |
|||
* Checks to see if the mouse pointer has |
|||
*/ |
|||
* stabilised (checking every <code>time</code>/2 milliseconds) and runs the |
|||
Navpopup.prototype.stick=function() { |
|||
* {@link #show} method if it has. |
|||
this.noshow=false; |
|||
* @param {number} time The minimum time (ms) before the popup may be shown. |
|||
this.sticky=true; |
|||
*/ |
|||
}; |
|||
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 |
|||
Allows the popup to be hidden. |
|||
//~ just half the time |
|||
*/ |
|||
this.stable_x = -10000; |
|||
Navpopup.prototype.unstick=function() { |
|||
this.stable_y = -10000; |
|||
this.sticky=false; |
|||
}; |
|||
/** |
|||
var stableShow = function () { |
|||
Sets the {@link #noshow} flag and hides the popup. This should be called |
|||
log('stableShow called'); |
|||
when the mouse leaves the link before |
|||
var new_x = Navpopup.tracker.x, |
|||
(or after) it's actually been displayed. |
|||
new_y = Navpopup.tracker.y; |
|||
*/ |
|||
var dx = savedThis.stable_x - new_x, |
|||
Navpopup.prototype.banish = function () { |
|||
dy = savedThis.stable_y - new_y; |
|||
log ('banish called'); |
|||
var fuzz2 = 0; // savedThis.fuzz * savedThis.fuzz; |
|||
// hide and prevent showing with showSoon in the future |
|||
//document.title += '[' + [savedThis.stable_x,new_x, savedThis.stable_y,new_y, dx, dy, fuzz2].join(',') + '] '; |
|||
this.noshow=true; |
|||
if (dx * dx <= fuzz2 && dy * dy <= fuzz2) { |
|||
if (this.showSoonStableTimer) { |
|||
log('mouse is stable'); |
|||
log('clearing showSoonStableTimer'); |
|||
clearInterval(this.showSoonStableTimer); |
|||
savedThis.reposition.apply(savedThis, [new_x + 2, new_y + 2]); |
|||
} |
|||
savedThis.show.apply(savedThis, []); |
|||
this.hide(); |
|||
savedThis.limitHorizontalPosition.apply(savedThis, []); |
|||
}; |
|||
return; |
|||
} |
|||
savedThis.stable_x = new_x; |
|||
savedThis.stable_y = new_y; |
|||
}; |
|||
var savedThis = this; |
|||
this.showSoonStableTimer = setInterval(stableShow, time / 2); |
|||
}; |
|||
/** |
|||
Runs hooks added with {@link #addHook}. |
|||
* Sets the {@link #noshow} flag and hides the popup. This should be called |
|||
@private |
|||
* when the mouse leaves the link before |
|||
@param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide' |
|||
* (or after) it's actually been displayed. |
|||
@param {String} when Controls exactly when the hook is run: either 'before' or 'after' |
|||
*/ |
|||
*/ |
|||
Navpopup.prototype.banish = function () { |
|||
Navpopup.prototype.runHooks = function (key, when) { |
|||
log('banish called'); |
|||
if (!this.hooks[key]) { return; } |
|||
// hide and prevent showing with showSoon in the future |
|||
var keyHooks=this.hooks[key]; |
|||
this.noshow = true; |
|||
var len=keyHooks.length; |
|||
if (this.showSoonStableTimer) { |
|||
for (var i=0; i< len; ++i) { |
|||
log('clearing showSoonStableTimer'); |
|||
if (keyHooks[i] && keyHooks[i].when == when) { |
|||
clearInterval(this.showSoonStableTimer); |
|||
if (keyHooks[i].hook.apply(this, [])) { |
|||
} |
|||
// remove the hook |
|||
this.hide(); |
|||
if (keyHooks[i].hookId) { |
|||
}; |
|||
delete this.hookIds[keyHooks[i].hookId]; |
|||
/** |
|||
* 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; |
|||
} |
} |
||
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. |
|||
* Navpopup instance, and no arguments. |
|||
@param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide' |
|||
* @param {Function} hook The hook function. Functions that return true are deleted. |
|||
@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. |
|||
*/ |
|||
* @param {String} uid A truthy string identifying the hook function; if it matches another hook |
|||
Navpopup.prototype.addHook = function ( hook, key, when, uid ) { |
|||
* in this position, it won't be added again. |
|||
when = when || 'after'; |
|||
*/ |
|||
if (!this.hooks[key]) { return; } |
|||
Navpopup.prototype.addHook = function (hook, key, when, uid) { |
|||
// if uid is specified, don't add duplicates |
|||
when = when || 'after'; |
|||
var hookId=null; |
|||
if (!this.hooks[key]) { |
|||
if (uid) { |
|||
hookId=[key,when,uid].join('|'); |
|||
if (this.hookIds[hookId]) { |
|||
return; |
return; |
||
} |
} |
||
this.hookIds[hookId]=true; |
|||
// if uid is specified, don't add duplicates |
|||
} |
|||
var hookId = null; |
|||
this.hooks[key].push( {hook: hook, when: when, hookId: hookId} ); |
|||
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'); |
|||
return; |
|||
var mainDiv=document.createElement('div'); |
|||
} |
|||
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'; |
|||
savedThis.onclickHandler(e); |
|||
mainDiv.id=mainDiv.className + this.uid; |
|||
}; |
|||
mainDiv.className = this.className ? this.className : 'navpopup_maindiv'; |
|||
mainDiv.id = mainDiv.className + this.uid; |
|||
mainDiv.style.position='absolute'; |
|||
mainDiv.style.display='none'; |
|||
mainDiv.className='navpopup'; |
|||
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 |
|||
* Calls the {@link #raise} method. |
|||
*/ |
|||
* @private |
|||
Navpopup.prototype.onclickHandler=function(e) { |
|||
*/ |
|||
this.raise(); |
|||
Navpopup.prototype.onclickHandler = function (/*e*/) { |
|||
}; |
|||
this.raise(); |
|||
/** |
|||
}; |
|||
Makes the popup draggable, using a {@link Drag} object. |
|||
@private |
|||
/** |
|||
*/ |
|||
* Makes the popup draggable, using a {@link Drag} object. |
|||
Navpopup.prototype.makeDraggable=function(handleName) { |
|||
* @private |
|||
if (!this.mainDiv) { this.createMainDiv(); } |
|||
*/ |
|||
var drag=new Drag(); |
|||
Navpopup.prototype.makeDraggable = function (handleName) { |
|||
if (!handleName) { |
|||
drag.startCondition=function(e) { |
|||
this.createMainDiv(); |
|||
try { if (!e.shiftKey) { return false; } } catch (err) { return false; } |
|||
} |
|||
return true; |
|||
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); |
|||
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. |
|||
* 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'); |
|||
}; |
|||
@private |
|||
/** |
|||
*/ |
|||
* Shows the popup using CSS. Runs hooks with key 'unhide'. |
|||
Navpopup.prototype.hide = function () { |
|||
* Sets {@link #visible} appropriately. {@link #show} should be called externally instead of this method. |
|||
this.runHooks('hide', 'before'); |
|||
* @private |
|||
this.abortDownloads(); |
|||
*/ |
|||
if (this.sticky) { return; } |
|||
Navpopup.prototype.unhide = function () { |
|||
if (typeof this.visible != 'undefined' && this.visible) { |
|||
this.runHooks('unhide', 'before'); |
|||
this.mainDiv.style.display='none'; |
|||
if (typeof this.visible != 'undefined' && !this.visible) { |
|||
this.visible=false; |
|||
} |
|||
this.visible = true; |
|||
this.runHooks('hide', 'after'); |
|||
} |
|||
}; |
|||
this.runHooks('unhide', '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. |
|||
* Sets the <code>innerHTML</code> attribute of the main div containing the popup content. |
|||
@private |
|||
* @param {string} html The HTML to set. |
|||
*/ |
|||
Navpopup.prototype.unhide = function () { |
|||
this.runHooks('unhide', 'before'); |
|||
this.mainDiv.innerHTML = html; |
|||
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. |
|||
* Updates the {@link #width} and {@link #height} attributes with the CSS properties. |
|||
@param {String} html The HTML to set. |
|||
* @private |
|||
*/ |
|||
Navpopup.prototype.setInnerHTML = function (html) { |
|||
this.mainDiv.innerHTML = html; |
|||
this.width = parseInt(this.mainDiv.offsetWidth, 10); |
|||
}; |
|||
this.height = parseInt(this.mainDiv.offsetHeight, 10); |
|||
}; |
|||
/** |
|||
Updates the {@link #width} and {@link #height} attributes with the CSS properties. |
|||
@private |
|||
* {@link #mainDiv}. |
|||
*/ |
|||
* @param {number} x x-coordinate (px) |
|||
Navpopup.prototype.updateDimensions = function () { |
|||
* @param {number} y y-coordinate (px) |
|||
this.width=parseInt(this.mainDiv.offsetWidth, 10); |
|||
* @type {boolean} |
|||
this.height=parseInt(this.mainDiv.offsetHeight, 10); |
|||
*/ |
|||
}; |
|||
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 |
|||
); |
|||
}; |
|||
/** |
|||
Checks if the point (x,y) is within {@link #fuzz} of the |
|||
* Adds a download to {@link #downloads}. |
|||
{@link #mainDiv}. |
|||
* @param {Downloader} download |
|||
@param {integer} x x-coordinate (px) |
|||
*/ |
|||
@param {integer} y y-coordinate (px) |
|||
Navpopup.prototype.addDownload = function (download) { |
|||
@type boolean |
|||
if (!download) { |
|||
*/ |
|||
return; |
|||
Navpopup.prototype.isWithin = function(x,y) { |
|||
} |
|||
//~ If we're not even visible, no point should be considered as |
|||
this.downloads.push(download); |
|||
//~ 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; } |
|||
for (var i = 0; i < this.downloads.length; ++i) { |
|||
this.downloads.push(download); |
|||
}; |
|||
if (d && d.abort) { |
|||
/** |
|||
d.abort(); |
|||
Aborts the downloads listed in {@link #downloads}. |
|||
} |
|||
@see Downloader#abort |
|||
} |
|||
*/ |
|||
this.downloads = []; |
|||
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 |
|||
A {@link Mousetracker} instance which is a property of the constructor (pseudo-global). |
|||
/* |
|||
*/ |
|||
* Javascript Diff Algorithm |
|||
Navpopup.tracker=new Mousetracker(); |
|||
* By John Resig (http://ejohn.org/) and [[:en:User:Lupin]] |
|||
// ENDFILE: navpopup.js |
|||
* |
|||
// STARTFILE: diff.js |
|||
* More Info: |
|||
//<NOLITE> |
|||
* http://ejohn.org/projects/javascript-diff-algorithm/ |
|||
/* |
|||
*/ |
|||
* 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>"; |
|||
return ''; |
|||
} |
|||
function insFmt(x) { |
|||
return "<del class='popupDiff'>" + x.join('') + '</del>'; |
|||
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 (!x.length) { |
|||
if (!b[i].row && b[i].row !== 0) { return -1; } |
|||
return ''; |
|||
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 "<ins class='popupDiff'>" + x.join('') + '</ins>'; |
|||
} |
} |
||
return count; |
|||
} |
|||
function shortenDiffString(str, context) { |
|||
var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)'); |
|||
// count the crossings on the edge starting at b[i] |
|||
var splitted=str.parenSplit(re); |
|||
if (!b[i].row && b[i].row !== 0) { |
|||
var ret=['']; |
|||
return -1; |
|||
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 { |
|||
var count = 0; |
|||
if (i > 0) { ret[ret.length-1] += splitted[i].substring(0,context); } |
|||
if ( |
if (i+1 < splitted.length) { |
||
ret.push(splitted[i].substring(splitted[i].length-context) + |
|||
continue; |
|||
splitted[i+1]); |
|||
} |
|||
if ((j - b[i].row) * (i - a[j].row) > 0) { |
|||
if (eject) { |
|||
return true; |
|||
} |
|||
count++; |
|||
} |
} |
||
} |
} |
||
return count; |
|||
} |
} |
||
while (ret.length > 0 && !ret[0]) { ret = ret.slice(1); } |
|||
return ret; |
|||
} |
|||
function shortenDiffString(str, context) { |
|||
var re = /(<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 = ""; |
|||
nSplitted[i] = nSplitted[i].entify(); |
|||
var acc=[]; // accumulator for prettier output |
|||
} |
|||
// crossing pairings -- eg 'A B' vs 'B A' -- cause problems, so let's iron them out |
|||
out = diff(oSplitted, nSplitted); |
|||
// this doesn't always do things optimally but it should be fast enough |
|||
var str = ''; |
|||
var maxOutputPair=0; |
|||
var acc = []; // accumulator for prettier output |
|||
for (i=0; i<out.n.length; ++i) { |
|||
if ( out.n[i].paired ) { |
|||
// crossing pairings -- eg 'A B' vs 'B A' -- cause problems, so let's iron them out |
|||
if( maxOutputPair > out.n[i].row ) { |
|||
// this doesn't always do things optimally but it should be fast enough |
|||
// tangle - delete pairing |
|||
var maxOutputPair = 0; |
|||
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) { |
|||
// 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; |
|||
} |
|||
} |
|||
} |
} |
||
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; |
|||
} |
} |
||
// output the stuff preceding the first paired old line |
|||
// see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object |
|||
for (i=0; i<out.o.length && !out.o[i].paired; ++i) { acc.push( out.o[i] ); } |
|||
// FIXME: use obj.hasOwnProperty instead of this kludge! |
|||
str += delFmt(acc); acc=[]; |
|||
var jsReservedProperties = RegExp( |
|||
'^(constructor|prototype|__((define|lookup)[GS]etter)__' + |
|||
'|eval|hasOwnProperty|propertyIsEnumerable' + |
|||
'|to(Source|String|LocaleString)|(un)?watch|valueOf)$' |
|||
); |
|||
// main loop |
|||
function diffBugAlert(word) { |
|||
for ( i = 0; i < out.n.length; ++i ) { |
|||
if (!diffBugAlert.list[word]) { |
|||
// output unpaired new "lines" |
|||
diffBugAlert.list[word] = 1; |
|||
while ( i < out.n.length && !out.n[i].paired ) { acc.push( out.n[i++] ); } |
|||
alert('Bad word: ' + word + '\n\nPlease report this bug.'); |
|||
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 |
|||
diffBugAlert.list = {}; |
|||
// 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]); } |
|||
} |
|||
if (!ret[src[i]]) { |
|||
ret[src[i]] = []; |
|||
} |
|||
try { |
|||
ret[src[i]].push(i); |
|||
} catch (err) { |
|||
diffBugAlert(src[i]); |
|||
} |
|||
} |
|||
return ret; |
|||
} |
} |
||
return ret; |
|||
} |
|||
function diff( o, n ) { |
|||
// pass 1: make hashtable ns with new rows as keys |
|||
var ns = makeDiffHashtable(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); |
|||
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 3: pair unique new rows and matching unique old rows |
|||
var i; |
|||
for (i = 0; i < n.length - 1; i++) { |
|||
for ( i in ns ) { |
|||
if ( |
|||
if ( ns[i].length == 1 && os[i] && os[i].length == 1 ) { |
|||
n[i].paired && |
|||
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 }; |
|||
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 }; |
|||
} |
} |
||
// ENDFILE: diff.js |
|||
// pass 4: pair matching rows immediately following paired rows (not necessarily unique) |
|||
// STARTFILE: init.js |
|||
for ( i = 0; i < n.length - 1; i++ ) { |
|||
function setSiteInfo() { |
|||
if ( n[i].paired && ! n[i+1].paired && n[i].row + 1 < o.length && ! o[ n[i].row + 1 ].paired && |
|||
if (window.popupLocalDebug) { |
|||
n[i+1] == o[ n[i].row + 1 ] ) { |
|||
pg.wiki.hostname = 'en.wikipedia.org'; |
|||
n[i+1] = { text: n[i+1], row: n[i].row + 1, paired: true }; |
|||
} else { |
|||
o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1, paired: true }; |
|||
pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?) |
|||
} |
} |
||
pg.wiki.wikimedia = /(wiki([pm]edia|source|books|news|quote|versity|species|voyage|data)|metawiki|wiktionary|mediawiki)[.]org/.test(pg.wiki.hostname); |
|||
pg.wiki.wikia = /[.]wikia[.]com$/i.test(pg.wiki.hostname); |
|||
pg.wiki.isLocal = /^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; |
|||
} |
} |
||
// pass 5: pair matching rows immediately preceding paired rows (not necessarily unique) |
|||
function setUserInfo() { |
|||
for ( i = n.length - 1; i > 0; i-- ) { |
|||
var params = { |
|||
if ( n[i].paired && ! n[i-1].paired && n[i].row > 0 && ! o[ n[i].row - 1 ].paired && |
|||
action: 'query', |
|||
n[i-1] == o[ n[i].row - 1 ] ) { |
|||
list: 'users', |
|||
n[i-1] = { text: n[i-1], row: n[i].row - 1, paired: true }; |
|||
ususers: mw.config.get('wgUserName'), |
|||
o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1, paired: true }; |
|||
usprop: 'rights', |
|||
}; |
|||
pg.user.canReview = false; |
|||
if (getValueOf('popupReview')) { |
|||
getMwApi() |
|||
.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') ? |
|||
}); |
|||
} |
} |
||
} |
} |
||
return { o: o, n: n }; |
|||
function fetchSpecialPageNames() { |
|||
} |
|||
var params = { |
|||
//</NOLITE> |
|||
action: 'query', |
|||
// ENDFILE: diff.js |
|||
meta: 'siteinfo', |
|||
// STARTFILE: init.js |
|||
siprop: 'specialpagealiases', |
|||
function setSiteInfo() { |
|||
formatversion: 2, |
|||
if (window.popupLocalDebug) { |
|||
// cache for an hour |
|||
pg.wiki.hostname = 'en.wikipedia.org'; |
|||
uselang: 'content', |
|||
} else { |
|||
maxage: 3600, |
|||
pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?) |
|||
}; |
|||
return getMwApi() |
|||
.get(params) |
|||
.then(function (data) { |
|||
pg.wiki.specialpagealiases = data.query.specialpagealiases; |
|||
}); |
|||
} |
} |
||
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 setTitleBase() { |
|||
var protocol = ( window.popupLocalDebug ? 'http:' : location.protocol ); |
|||
pg.wiki.articlePath = mw.config.get('wgArticlePath').replace(/\/\$1/, ""); // as in http://some.thing.com/wiki/Article |
|||
pg.wiki.botInterfacePath = mw.config.get('wgScript'); |
|||
pg.wiki.APIPath = mw.config.get('wgScriptPath') +"/api.php"; |
|||
// default mediawiki setting is paths like http://some.thing.com/articlePath/index.php?title=foo |
|||
var titletail = pg.wiki.botInterfacePath + '?title='; |
|||
//var titletail2 = joinPath([pg.wiki.botInterfacePath, 'wiki.phtml?title=']); |
|||
// other sites may need to add code here to set titletail depending on how their urls work |
|||
pg.wiki.titlebase = protocol + '//' + pg.wiki.sitebase + titletail; |
|||
//pg.wiki.titlebase2 = protocol + '//' + joinPath([pg.wiki.sitebase, titletail2]); |
|||
pg.wiki.wikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.botInterfacePath; |
|||
pg.wiki.apiwikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.APIPath; |
|||
pg.wiki.articlebase = protocol + '//' + pg.wiki.sitebase + pg.wiki.articlePath; |
|||
pg.wiki.commonsbase = protocol + '//' + pg.wiki.commons + pg.wiki.botInterfacePath; |
|||
pg.wiki.apicommonsbase = protocol + '//' + pg.wiki.commons + pg.wiki.APIPath; |
|||
pg.re.basenames = RegExp( '^(' + |
|||
map( literalizeRegex, [ pg.wiki.titlebase, //pg.wiki.titlebase2, |
|||
'^(' + |
|||
pg.wiki.articlebase ]).join('|') + ')' ); |
|||
map(literalizeRegex, [ |
|||
} |
|||
pg.wiki.titlebase, //pg.wiki.titlebase2, |
|||
pg.wiki.articlebase, |
|||
]).join('|') + |
|||
')' |
|||
); |
|||
} |
|||
////////////////////////////////////////////////// |
|||
// Global regexps |
|||
////////////////////////////////////////////////// |
|||
function setMainRegex() { |
|||
// Global regexps |
|||
var reStart = '[^:]*://'; |
|||
var preTitles = |
|||
literalizeRegex(mw.config.get('wgScriptPath')) + '/(?:index[.]php|wiki[.]phtml)[?]title='; |
|||
preTitles += '|' + literalizeRegex(pg.wiki.articlePath + '/'); |
|||
function setMainRegex() { |
|||
var reEnd = '(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?'; |
|||
var reStart='[^:]*://'; |
|||
pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd); |
|||
var preTitles = literalizeRegex( mw.config.get('wgScriptPath') ) + '/(?:index[.]php|wiki[.]phtml)[?]title='; |
|||
} |
|||
preTitles += '|' + literalizeRegex( pg.wiki.articlePath + '/' ); |
|||
var reEnd='(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?'; |
|||
function buildSpecialPageGroup(specialPageObj) { |
|||
pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd); |
|||
var variants = []; |
|||
} |
|||
variants.push(mw.util.escapeRegExp(specialPageObj.realname)); |
|||
variants.push(mw.util.escapeRegExp(encodeURI(specialPageObj.realname))); |
|||
specialPageObj.aliases.forEach(function (alias) { |
|||
variants.push(mw.util.escapeRegExp(alias)); |
|||
variants.push(mw.util.escapeRegExp(encodeURI(alias))); |
|||
}); |
|||
return variants.join('|'); |
|||
} |
|||
function setRegexps() { |
|||
setMainRegex(); |
|||
var sp=nsRe(pg.nsSpecialId); |
|||
pg.re.urlNoPopup=RegExp('((title=|/)' + sp + '(?:%3A|:)|section=[0-9]|^#$)') ; |
|||
pg.re.contribs =RegExp('(title=|/)' + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + mw.config.get('wgFormattedNamespaces')[pg.nsUserId]+':)(.*)') ; |
|||
pg.re.email =RegExp('(title=|/)' + sp + '(?:%3A|:)EmailUser' + '(&target=|/|/(?:' + mw.config.get('wgFormattedNamespaces')[pg.nsUserId]+':)?)(.*)') ; |
|||
pg.wiki.specialpagealiases.forEach(function (specialpage) { |
|||
pg.re.backlinks =RegExp('(title=|/)' + sp + '(?:%3A|:)WhatLinksHere' + '(&target=|/)([^&]*)'); |
|||
if (specialpage.realname === 'Contributions') { |
|||
pg.re.specialdiff=RegExp('/' + sp + '(?:%3A|:)Diff/([^?#]*)'); |
|||
pg.re.contribs = RegExp( |
|||
'(title=|/)' + |
|||
sp + |
|||
'(?:%3A|:)(?:' + |
|||
buildSpecialPageGroup(specialpage) + |
|||
')' + |
|||
'(&target=|/|/' + |
|||
nsRe(pg.nsUserId) + |
|||
':)(.*)', |
|||
'i' |
|||
); |
|||
} else if (specialpage.realname === 'Diff') { |
|||
pg.re.specialdiff = RegExp( |
|||
'/' + sp + '(?:%3A|:)(?:' + buildSpecialPageGroup(specialpage) + ')/([^?#]*)', |
|||
'i' |
|||
); |
|||
} else if (specialpage.realname === 'Emailuser') { |
|||
pg.re.email = RegExp( |
|||
'(title=|/)' + |
|||
sp + |
|||
'(?:%3A|:)(?:' + |
|||
buildSpecialPageGroup(specialpage) + |
|||
')' + |
|||
'(&target=|/|/(?:' + |
|||
nsRe(pg.nsUserId) + |
|||
':)?)(.*)', |
|||
'i' |
|||
); |
|||
} else if (specialpage.realname === 'Whatlinkshere') { |
|||
pg.re.backlinks = RegExp( |
|||
'(title=|/)' + |
|||
sp + |
|||
'(?:%3A|:)(?:' + |
|||
buildSpecialPageGroup(specialpage) + |
|||
')' + |
|||
'(&target=|/)([^&]*)', |
|||
'i' |
|||
); |
|||
} |
|||
}); |
|||
//<NOLITE> |
|||
var im = nsReImage(); |
|||
var im=nsReImage(); |
|||
// note: tries to get images in infobox templates too, e.g. movie pages, album pages etc |
|||
// note: tries to get images in infobox templates too, e.g. movie pages, album pages etc |
|||
// (^|\[\[)image: *([^|\]]*[^|\] ]) * |
|||
// (^|\[\[)image: *([^|\]]*[^|\] ]) * |
|||
// (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)? |
|||
// $4 = 120 as in 120px |
|||
// $4 = 120 as in 120px |
|||
pg.re.image = RegExp( |
|||
pg.re.image = RegExp('(^|\\[\\[)' + im + ': *([^|\\]]*[^|\\] ])' + |
|||
'([^0-9\\]]*([0-9]+) *px)?|(?:\\n *[|]?|[|]) *' + |
|||
im + |
|||
' |
'(' + getValueOf('popupImageVarsRegexp') + ')' + |
||
'([ |
' *= *(?:\\[\\[ *)?(?:' + im + ':)?' + |
||
'([^|]*?)(?:\\]\\])? *[|]? *\\n', 'img') ; |
|||
'(' + |
|||
pg.re.imageBracketCount = 6; |
|||
getValueOf('popupImageVarsRegexp') + |
|||
')' + |
|||
' *= *(?:\\[\\[ *)?(?:' + |
|||
im + |
|||
':)?' + |
|||
'([^|]*?)(?:\\]\\])? *[|]? *\\n', |
|||
'img' |
|||
); |
|||
pg.re.imageBracketCount = 6; |
|||
pg.re.category = RegExp('\\[\\[' +nsRe(pg.nsCategoryId) + |
|||
': *([^|\\]]*[^|\\] ]) *', 'i'); |
|||
pg.re.categoryBracketCount = 1; |
|||
pg.re.ipUser=RegExp('^' + |
|||
'^' + |
|||
// IPv6 |
// IPv6 |
||
'(?::(?::|(?::[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})' + |
'(?::(?::|(?::[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 |
// IPv4 |
||
'|(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' + |
'|(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' + |
||
'(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))$' |
'(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))$'); |
||
); |
|||
pg.re.stub= RegExp(getValueOf('popupStubRegexp'), 'im'); |
|||
pg.re.disambig=RegExp(getValueOf('popupDabRegexp'), 'im'); |
|||
//</NOLITE> |
|||
// FIXME replace with general parameter parsing function, this is daft |
|||
// FIXME replace with general parameter parsing function, this is daft |
|||
pg.re.oldid = /[?&]oldid=([^&]*)/; |
|||
pg.re.oldid=RegExp('[?&]oldid=([^&]*)'); |
|||
pg.re.diff=RegExp('[?&]diff=([^&]*)'); |
|||
} |
|||
} |
|||
////////////////////////////////////////////////// |
|||
// miscellany |
|||
////////////////////////////////////////////////// |
|||
function setupCache() { |
|||
// miscellany |
|||
// page caching |
|||
pg.cache.pages = []; |
|||
} |
|||
function setupCache() { |
|||
// page caching |
|||
pg.current.link = null; |
|||
pg.cache.pages = []; |
|||
} |
|||
pg.current.linksHash = {}; |
|||
function setMisc() { |
|||
setupCache(); |
|||
pg.current.link=null; |
|||
pg.current.links=[]; |
|||
pg.current.linksHash={}; |
|||
setupCache(); |
|||
pg.timer.checkPopupPosition = null; |
|||
pg.counter.loop = 0; |
|||
pg.timer.checkPopupPosition=null; |
|||
// ids change with each popup: popupImage0, popupImage1 etc |
|||
pg.counter.loop=0; |
|||
// ids change with each popup: popupImage0, popupImage1 etc |
|||
// for myDecodeURI |
|||
pg.idNumber=0; |
|||
pg.misc.decodeExtras = [ |
|||
{ from: '%2C', to: ',' }, |
|||
// for myDecodeURI |
|||
{ from: '_', to: ' ' }, |
|||
pg.misc.decodeExtras = [ |
|||
{ from: '%24', to: '$' }, |
|||
{from: '%2C', to: ',' }, |
|||
{from: '_', to: ' ' }, |
|||
{from: '%24', to: '$'}, |
|||
{from: '%26', to: '&' } // no , |
|||
]; |
]; |
||
} |
|||
} |
|||
function getMwApi() { |
|||
if (!pg.api.client) { |
|||
function leadingInteger(s){ |
|||
pg.api.userAgent = 'Navigation popups/1.0 (' + mw.config.get('wgServerName') + ')'; |
|||
var n=s.match(/^(\d*)/)[1]; |
|||
pg.api.client = new mw.Api({ |
|||
if (n) { return +n; } |
|||
ajax: { |
|||
return null; |
|||
headers: { |
|||
} |
|||
'Api-User-Agent': pg.api.userAgent, |
|||
}, |
|||
function setBrowserHacks() { |
|||
}, |
|||
var useOriginal=false; |
|||
}); |
|||
var webkitUnder420 = false; |
|||
// browser-specific hacks |
|||
if (typeof window.opera != 'undefined') { |
|||
//if (leadingInteger(opera.version()) < 9) |
|||
{ useOriginal=true; } // v9 beta still seems to have buggy css |
|||
setDefault('popupNavLinkSeparator', ' · '); |
|||
} else if (navigator.appName=='Konqueror') { |
|||
setDefault('popupNavLinkSeparator', ' • '); |
|||
pg.flag.isKonq=true; |
|||
} else if ( navigator.vendor && navigator.vendor.toLowerCase().indexOf('apple computer')===0) { |
|||
pg.flag.isSafari=true; |
|||
var webkit=+navigator.userAgent.replace(RegExp('^.*AppleWebKit[/](\\d+).*', 'i'), '$1'); |
|||
if (webkit < 420) { |
|||
useOriginal=true; |
|||
webkitUnder420 = true; |
|||
} |
} |
||
} else if (navigator.appName.indexOf("Microsoft")!=-1) { |
|||
return pg.api.client; |
|||
setDefault('popupNavLinkSeparator', ' · '); |
|||
var ver=+navigator.userAgent.replace(RegExp('^.*MSIE (\\d+).*'), '$1'); |
|||
pg.flag.isIE=true; |
|||
pg.flag.IEVersion=ver; |
|||
} |
} |
||
if (pg.flag.isIE && pg.flag.IEVersion < 8) { |
|||
useOriginal=true; |
|||
} |
|||
if ((pg.flag.isIE && pg.flag.IEVersion < 7) || pg.flag.isKonq || (pg.flag.isSafari && webkitUnder420)) { |
|||
pg.flag.linksLikeIE6=true; |
|||
} |
|||
if (useOriginal && pg.structures.original) { |
|||
setDefault('popupStructure','original'); |
|||
} |
|||
} |
|||
// We need a callback since this might end up asynchronous because of |
|||
// the mw.loader.using() call. |
|||
function setupPopups( callback ) { |
|||
mw.loader.using( 'mediawiki.user', function() { |
|||
if (setupPopups.completed) { |
|||
// NB translatable strings should be set up first (strings.js) |
|||
if (typeof callback === 'function') { |
|||
// basics |
|||
callback(); |
|||
setupDebugging(); |
|||
} |
|||
setSiteInfo(); |
|||
return; |
|||
setTitleBase(); |
|||
} |
|||
setOptions(); // see options.js |
|||
// These dependencies should alse be enforced from the gadget, |
|||
// but not everyone loads this as a gadget, so double check |
|||
mw.loader |
|||
.using([ |
|||
'mediawiki.util', |
|||
'mediawiki.api', |
|||
'mediawiki.user', |
|||
'user.options', |
|||
'mediawiki.jqueryMsg', |
|||
]) |
|||
.then(fetchSpecialPageNames) |
|||
.then(function () { |
|||
// NB translatable strings should be set up first (strings.js) |
|||
// basics |
|||
setupDebugging(); |
|||
setSiteInfo(); |
|||
setTitleBase(); |
|||
setOptions(); // see options.js |
|||
setUserInfo(); |
|||
// namespaces etc |
|||
setNamespaces(); |
|||
setInterwiki(); |
|||
// regexps |
|||
setRegexps(); |
|||
setRedirs(); |
|||
// other stuff |
|||
setBrowserHacks(); |
|||
setupLivePreview(); |
setMisc(); |
||
setupLivePreview(); |
|||
// main deal here |
|||
setupTooltips(); |
|||
log('In setupPopups(), just called setupTooltips()'); |
|||
Navpopup.tracker.enable(); |
|||
setupPopups.completed = true; |
|||
if ( $.isFunction( callback ) ) { |
|||
callback(); |
|||
} |
|||
}); |
|||
} |
|||
// ENDFILE: init.js |
|||
// STARTFILE: navlinks.js |
|||
//<NOLITE> |
|||
////////////////////////////////////////////////// |
|||
// navlinks... let the fun begin |
|||
// |
|||
function defaultNavlinkSpec() { |
|||
var str=''; |
|||
str += '<b><<mainlink|shortcut= >></b>'; |
|||
if (getValueOf('popupLastEditLink')) { |
|||
str += '*<<lastEdit|shortcut=/>>|<<lastContrib>>|<<sinceMe>>if(oldid){|<<oldEdit>>|<<diffCur>>}'; |
|||
} |
} |
||
// ENDFILE: init.js |
|||
// user links |
|||
// STARTFILE: navlinks.js |
|||
// contribs - log - count - email - block |
|||
////////////////////////////////////////////////// |
|||
// count only if applicable; block only if popupAdminLinks |
|||
// navlinks... let the fun begin |
|||
str += 'if(user){<br><<contribs|shortcut=c>>*<<userlog|shortcut=L|log>>'; |
|||
// |
|||
str+='if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}'; |
|||
str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>|<<blocklog|log>>}}'; |
|||
// editing links |
|||
function defaultNavlinkSpec() { |
|||
// talkpage -> edit|new - history - un|watch - article|edit |
|||
var str = ''; |
|||
// other page -> edit - history - un|watch - talk|edit|new |
|||
str += '<b><<mainlink|shortcut= >></b>'; |
|||
var editstr='<<edit|shortcut=e>>'; |
|||
if (getValueOf('popupLastEditLink')) { |
|||
var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + editstr + '}'; |
|||
str += |
|||
var historystr='<<history|shortcut=h>>if(mainspace_en){|<<editors|shortcut=E|>>}'; |
|||
var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; |
|||
} |
|||
str+='<br>if(talk){' + |
|||
// user links |
|||
editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' + |
|||
// contribs - log - count - email - block |
|||
'<b><<article|shortcut=a>></b>|<<editArticle|edit>>' + |
|||
// count only if applicable; block only if popupAdminLinks |
|||
'}else{' + // not a talk page |
|||
str += 'if(user){<br><<contribs|shortcut=c>>*<<userlog|shortcut=L|log>>'; |
|||
editOldidStr + '*' + historystr + '*' + watchstr + '*' + |
|||
str += 'if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}'; |
|||
'<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>}'; |
|||
str += |
|||
'if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>|<<blocklog|log>>}}'; |
|||
// misc links |
|||
str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>'; |
|||
// 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>>|<<editors|shortcut=E|>>'; |
|||
var watchstr = '<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; |
|||
// admin links |
|||
str += |
|||
str += 'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>|<<protectlog|log>>*' + |
|||
'<br>if(talk){' + |
|||
'<<undelete|undeleteShort>>|<<delete|shortcut=d>>|<<deletelog|log>>}'; |
|||
editOldidStr + |
|||
return str; |
|||
'|<<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>>}'; |
|||
function navLinksHTML (article, hint, params) { //oldid, rcid) { |
|||
// misc links |
|||
var str = '<span class="popupNavLinks">' + defaultNavlinkSpec() + '</span>'; |
|||
str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>'; |
|||
// BAM |
|||
return navlinkStringToHTML(str, article, params); |
|||
} |
|||
function expandConditionalNavlinkString(s,article,z,recursionCount) { |
|||
// admin links |
|||
var oldid=z.oldid, rcid=z.rcid, diff=z.diff; |
|||
str += |
|||
// nested conditionals (up to 10 deep) are ok, hopefully! (work from the inside out) |
|||
'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>|<<protectlog|log>>*' + |
|||
if (typeof recursionCount!=typeof 0) { recursionCount=0; } |
|||
'<<undelete|undeleteShort>>|<<delete|shortcut=d>>|<<deletelog|log>>}'; |
|||
var conditionalSplitRegex=RegExp( |
|||
return str; |
|||
//(1 if \\( (2 2) \\) {(3 3)} (4 else {(5 5)} 4)1) |
|||
} |
|||
'(;?\\s*if\\s*\\(\\s*([\\w]*)\\s*\\)\\s*\\{([^{}]*)\\}(\\s*else\\s*\\{([^{}]*?)\\}|))', 'i'); |
|||
var splitted=s.parenSplit(conditionalSplitRegex); |
|||
// $1: whole conditional |
|||
// $2: test condition |
|||
// $3: true expansion |
|||
// $4: else clause (possibly empty) |
|||
// $5: false expansion (possibly null) |
|||
var numParens=5; |
|||
var ret = splitted[0]; |
|||
for (var i=1; i<splitted.length; i=i+numParens+1) { |
|||
var testString=splitted[i+2-1]; |
|||
function navLinksHTML(article, hint, params) { |
|||
var trueString=splitted[i+3-1]; |
|||
//oldid, rcid) { |
|||
var falseString=splitted[i+5-1]; |
|||
var str = '<span class="popupNavLinks">' + defaultNavlinkSpec() + '</span>'; |
|||
if (typeof falseString=='undefined' || !falseString) { falseString=''; } |
|||
// BAM |
|||
var testResult=null; |
|||
return navlinkStringToHTML(str, article, params); |
|||
} |
|||
switch (testString) { |
|||
function expandConditionalNavlinkString(s, article, z, recursionCount) { |
|||
case 'user': |
|||
var oldid = z.oldid, |
|||
testResult=(article.userName())?true:false; |
|||
rcid = z.rcid, |
|||
break; |
|||
case 'talk': |
|||
// nested conditionals (up to 10 deep) are ok, hopefully! (work from the inside out) |
|||
testResult=(article.talkPage())?false:true; // talkPage converts _articles_ to talkPages |
|||
if (typeof recursionCount != typeof 0) { |
|||
break; |
|||
recursionCount = 0; |
|||
case 'admin': |
|||
testResult=getValueOf('popupAdminLinks')?true:false; |
|||
break; |
|||
case 'oldid': |
|||
testResult=(typeof oldid != 'undefined' && oldid)?true:false; |
|||
break; |
|||
case 'rcid': |
|||
testResult=(typeof rcid != 'undefined' && rcid)?true:false; |
|||
break; |
|||
case 'ipuser': |
|||
testResult=(article.isIpUser())?true:false; |
|||
break; |
|||
case 'mainspace_en': |
|||
testResult=isInMainNamespace(article) && |
|||
pg.wiki.hostname=='en.wikipedia.org'; |
|||
break; |
|||
case 'wikimedia': |
|||
testResult=(pg.wiki.wikimedia) ? true : false; |
|||
break; |
|||
case 'diff': |
|||
testResult=(typeof diff != 'undefined' && diff)?true:false; |
|||
break; |
|||
} |
} |
||
var conditionalSplitRegex = RegExp( |
|||
//(1 if \\( (2 2) \\) {(3 3)} (4 else {(5 5)} 4)1) |
|||
'(;?\\s*if\\s*\\(\\s*([\\w]*)\\s*\\)\\s*\\{([^{}]*)\\}(\\s*else\\s*\\{([^{}]*?)\\}|))', |
|||
'i' |
|||
); |
|||
var splitted = s.parenSplit(conditionalSplitRegex); |
|||
// $1: whole conditional |
|||
// $2: test condition |
|||
// $3: true expansion |
|||
// $4: else clause (possibly empty) |
|||
// $5: false expansion (possibly null) |
|||
var numParens = 5; |
|||
var ret = splitted[0]; |
|||
for (var i = 1; i < splitted.length; i = i + numParens + 1) { |
|||
var testString = splitted[i + 2 - 1]; |
|||
var trueString = splitted[i + 3 - 1]; |
|||
var falseString = splitted[i + 5 - 1]; |
|||
if (typeof falseString == 'undefined' || !falseString) { |
|||
falseString = ''; |
|||
} |
|||
var testResult = null; |
|||
switch(testResult) { |
|||
case null: ret+=splitted[i]; break; |
|||
case 'user': |
|||
case true: ret+=trueString; break; |
|||
testResult = !!article.userName(); |
|||
case false: ret+=falseString; break; |
|||
} |
|||
case 'talk': |
|||
testResult = !article.talkPage(); // talkPage converts _articles_ to talkPages |
|||
break; |
|||
case 'admin': |
|||
testResult = !!getValueOf('popupAdminLinks'); |
|||
break; |
|||
case 'oldid': |
|||
testResult = !!(typeof oldid != 'undefined' && oldid); |
|||
break; |
|||
case 'rcid': |
|||
testResult = !!(typeof rcid != 'undefined' && rcid); |
|||
break; |
|||
case 'ipuser': |
|||
testResult = !!article.isIpUser(); |
|||
break; |
|||
case 'mainspace_en': |
|||
testResult = isInMainNamespace(article) && pg.wiki.hostname == 'en.wikipedia.org'; |
|||
break; |
|||
case 'wikimedia': |
|||
testResult = !!pg.wiki.wikimedia; |
|||
break; |
|||
case 'diff': |
|||
testResult = !!(typeof diff != 'undefined' && diff); |
|||
break; |
|||
} |
|||
// append non-conditional string |
|||
switch (testResult) { |
|||
ret += splitted[i+numParens]; |
|||
case null: |
|||
} |
|||
ret += splitted[i]; |
|||
if (conditionalSplitRegex.test(ret) && recursionCount < 10) { |
|||
break; |
|||
return expandConditionalNavlinkString(ret,article,z,recursionCount+1); |
|||
case true: |
|||
ret += trueString; |
|||
break; |
|||
case false: |
|||
ret += falseString; |
|||
break; |
|||
} |
|||
// append non-conditional string |
|||
ret += splitted[i + numParens]; |
|||
} |
|||
if (conditionalSplitRegex.test(ret) && recursionCount < 10) { |
|||
return expandConditionalNavlinkString(ret, article, z, recursionCount + 1); |
|||
} |
|||
return ret; |
|||
} |
} |
||
return ret; |
|||
} |
|||
function navlinkStringToArray(s, article, params) { |
|||
s=expandConditionalNavlinkString(s,article,params); |
|||
var splitted=s.parenSplit(RegExp('<<(.*?)>>')); |
|||
var ret=[]; |
|||
for (var i=0; i<splitted.length; ++i) { |
|||
if (i%2) { // i odd, so s is a tag |
|||
var t=new navlinkTag(); |
|||
// i odd, so s is a tag |
|||
var ss=splitted[i].split('|'); |
|||
t.id=ss[0]; |
|||
var ss = splitted[i].split('|'); |
|||
for (var j=1; j<ss.length; ++j) { |
|||
var sss=ss[j].split('='); |
|||
if (sss.length>1) { |
|||
t[sss[0]]=sss[1]; |
|||
t[sss[0]] = sss[1]; |
|||
} else { |
|||
// no assignment (no "="), so treat this as a title (overwriting the last one) |
|||
t.text = popupString(sss[0]); |
|||
} |
|||
} |
} |
||
else { // no assignment (no "="), so treat this as a title (overwriting the last one) |
|||
t.article = article; |
|||
t.text=popupString(sss[0]); |
|||
var oldid = params.oldid, |
|||
rcid = params.rcid, |
|||
diff = params.diff; |
|||
if (typeof oldid !== 'undefined' && oldid !== null) { |
|||
t.oldid = oldid; |
|||
} |
} |
||
if (typeof rcid !== 'undefined' && rcid !== null) { |
|||
t.rcid = rcid; |
|||
} |
|||
if (typeof diff !== 'undefined' && diff !== null) { |
|||
t.diff = diff; |
|||
} |
|||
if (!t.text && t.id !== 'mainlink') { |
|||
t.text = popupString(t.id); |
|||
} |
|||
ret.push(t); |
|||
} else { |
|||
// plain HTML |
|||
ret.push(splitted[i]); |
|||
} |
} |
||
t.article=article; |
|||
var oldid=params.oldid, rcid=params.rcid, diff=params.diff; |
|||
if (typeof oldid !== 'undefined' && oldid !== null) { t.oldid=oldid; } |
|||
if (typeof rcid !== 'undefined' && rcid !== null) { t.rcid=rcid; } |
|||
if (typeof diff !== 'undefined' && diff !== null) { t.diff=diff; } |
|||
if (!t.text && t.id !== 'mainlink') { t.text=popupString(t.id); } |
|||
ret.push(t); |
|||
} |
|||
else { // plain HTML |
|||
ret.push(splitted[i]); |
|||
} |
} |
||
return ret; |
|||
} |
} |
||
return ret; |
|||
} |
|||
function navlinkSubstituteHTML(s) { |
|||
return s |
|||
.split('*') |
|||
.join(getValueOf('popupNavLinkSeparator')) |
|||
.split('<menurow>') |
|||
.join('<li class="popup_menu_row">') |
|||
.split('</menurow>') |
|||
.join('</li>') |
|||
.split('<menu>') |
|||
.join('<ul class="popup_menu">') |
|||
.split('</menu>') |
|||
.join('</ul>'); |
|||
} |
|||
function navlinkSubstituteHTML(s) { |
|||
return s.split('*').join(getValueOf('popupNavLinkSeparator')) |
|||
.split('<menurow>').join('<li class="popup_menu_row">') |
|||
} |
|||
.split('</menurow>').join('</li>') |
|||
.split('<menu>').join('<ul class="popup_menu">') |
|||
.split('</menu>').join('</ul>'); |
|||
} |
|||
// navlinkString: * becomes the separator |
|||
// <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz' |
|||
// and visible text 'fubar' |
|||
// if(test){...} and if(test){...}else{...} work too (nested ok) |
|||
function navlinkDepth(magic,s) { |
|||
return s.split('<' + magic + '>').length - s.split('</' + magic + '>').length; |
|||
//limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article)); |
|||
} |
|||
var p = navlinkStringToArray(s, article, params); |
|||
var html = ''; |
|||
var menudepth = 0; // nested menus not currently allowed, but doesn't do any harm to code for it |
|||
var menurowdepth = 0; |
|||
for (var i = 0; i < p.length; ++i) { |
|||
if (typeof p[i] == typeof '') { |
|||
html += navlinkSubstituteHTML(p[i]); |
|||
menudepth += navlinkDepth('menu', p[i]); |
|||
menurowdepth += navlinkDepth('menurow', p[i]); |
|||
// if (menudepth === 0) { |
|||
// tagType='span'; |
|||
// } else if (menurowdepth === 0) { |
|||
// tagType='li'; |
|||
// } else { |
|||
// tagType = null; |
|||
// } |
|||
} else if (typeof p[i].type != 'undefined' && p[i].type == 'navlinkTag') { |
|||
if (menudepth > 0 && menurowdepth === 0) { |
|||
html += '<li class="popup_menu_item">' + p[i].html() + '</li>'; |
|||
} else { |
|||
html += p[i].html(); |
|||
} |
|||
} |
|||
} |
|||
return html; |
|||
} |
|||
function navlinkTag() { |
|||
this.type = 'navlinkTag'; |
|||
} |
|||
// navlinkString: * becomes the separator |
|||
navlinkTag.prototype.html = function () { |
|||
// <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz' |
|||
this.getNewWin(); |
|||
// and visible text 'fubar' |
|||
this.getPrintFunction(); |
|||
// if(test){...} and if(test){...}else{...} work too (nested ok) |
|||
var html = ''; |
|||
var opening, closing; |
|||
function navlinkStringToHTML(s,article,params) { |
|||
var tagType = 'span'; |
|||
//limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article)); |
|||
if (!tagType) { |
|||
var p=navlinkStringToArray(s,article,params); |
|||
opening = ''; |
|||
var html=''; |
|||
var menudepth = 0; // nested menus not currently allowed, but doesn't do any harm to code for it |
|||
} else { |
|||
var menurowdepth = 0; |
|||
opening = '<' + tagType + ' class="popup_' + this.id + '">'; |
|||
var wrapping = null; |
|||
closing = '</' + tagType + '>'; |
|||
for (var i=0; i<p.length; ++i) { |
|||
} |
|||
if (typeof |
if (typeof p[i] == typeof '') { |
||
html+=navlinkSubstituteHTML(p[i]); |
|||
errlog('Oh dear - invalid print function for a navlinkTag, id=' + this.id); |
|||
menudepth += navlinkDepth('menu', p[i]); |
|||
} else { |
|||
menurowdepth += navlinkDepth('menurow', p[i]); |
|||
html = this.print(this); |
|||
if ( |
// if (menudepth === 0) { |
||
// tagType='span'; |
|||
} else if ( |
// } else if (menurowdepth === 0) { |
||
// tagType='li'; |
|||
html = addPopupShortcut(html, this.shortcut); |
|||
// } else { |
|||
// tagType = null; |
|||
// } |
|||
} else if (typeof p[i].type != 'undefined' && p[i].type=='navlinkTag') { |
|||
if (menudepth > 0 && menurowdepth === 0) { |
|||
html += '<li class="popup_menu_item">' + p[i].html() + '</li>'; |
|||
} else { |
|||
html+=p[i].html(); |
|||
} |
} |
||
} |
} |
||
} |
|||
return opening + html + closing; |
|||
return html; |
|||
}; |
|||
} |
|||
function navlinkTag() { |
|||
this.type='navlinkTag'; |
|||
getValueOf('popupLinksNewWindow'); |
|||
} |
|||
if (typeof pg.option.popupLinksNewWindow[this.id] === 'undefined') { |
|||
this.newWin = null; |
|||
} |
|||
this.newWin = pg.option.popupLinksNewWindow[this.id]; |
|||
}; |
|||
navlinkTag.prototype.html=function () { |
|||
this.getNewWin(); |
|||
//think about this some more |
|||
this.getPrintFunction(); |
|||
// this.id and this.article should already be defined |
|||
var html=''; |
|||
if (typeof this.id != typeof '' || typeof this.article != typeof {}) { |
|||
var opening, closing; |
|||
return; |
|||
var tagType='span'; |
|||
} |
|||
if (!tagType) { |
|||
opening = ''; closing = ''; |
|||
} else { |
|||
opening = '<' + tagType + ' class="popup_' + this.id + '">'; |
|||
closing = '</' + tagType + '>'; |
|||
} |
|||
if (typeof this.print!='function') { |
|||
errlog ('Oh dear - invalid print function for a navlinkTag, id='+this.id); |
|||
} else { |
|||
html=this.print(this); |
|||
if (typeof html != typeof '') {html='';} |
|||
else if (typeof this.shortcut!='undefined') html=addPopupShortcut(html, this.shortcut); |
|||
} |
|||
return opening + html + closing; |
|||
}; |
|||
navlinkTag.prototype.getNewWin=function() { |
|||
this.noPopup = 1; |
|||
getValueOf('popupLinksNewWindow'); |
|||
switch (this.id) { |
|||
if (typeof pg.option.popupLinksNewWindow[this.id] === 'undefined') { this.newWin=null; } |
|||
case 'contribs': |
|||
this.newWin=pg.option.popupLinksNewWindow[this.id]; |
|||
case 'history': |
|||
}; |
|||
case 'whatLinksHere': |
|||
case 'userPage': |
|||
case 'monobook': |
|||
case 'userTalk': |
|||
case 'talk': |
|||
case 'article': |
|||
case 'lastEdit': |
|||
this.noPopup = null; |
|||
} |
|||
switch (this.id) { |
|||
case 'email': |
|||
case 'contribs': |
|||
case 'block': |
|||
case 'unblock': |
|||
case 'userlog': |
|||
case 'userSpace': |
|||
case 'deletedContribs': |
|||
this.article = this.article.userName(); |
|||
} |
|||
navlinkTag.prototype.getPrintFunction=function() { //think about this some more |
|||
switch (this.id) { |
|||
// this.id and this.article should already be defined |
|||
case 'userTalk': |
|||
if (typeof this.id!=typeof '' || typeof this.article!=typeof {} ) { return; } |
|||
case 'newUserTalk': |
|||
var html=''; |
|||
case 'editUserTalk': |
|||
var a,t; |
|||
case 'userPage': |
|||
case 'monobook': |
|||
case 'editMonobook': |
|||
case 'blocklog': |
|||
this.article = this.article.userName(true); |
|||
/* fall through */ |
|||
case 'pagelog': |
|||
case 'deletelog': |
|||
case 'protectlog': |
|||
delete this.oldid; |
|||
} |
|||
this.noPopup=1; |
|||
if (this.id == 'editMonobook' || this.id == 'monobook') { |
|||
switch (this.id) { |
|||
this.article.append('/monobook.js'); |
|||
case 'contribs': case 'history': case 'whatLinksHere': |
|||
} |
|||
case 'userPage': case 'monobook': case 'userTalk': |
|||
case 'talk': case 'article': case 'lastEdit': |
|||
this.noPopup=null; |
|||
} |
|||
switch (this.id) { |
|||
case 'email': case 'contribs': case 'block': case 'unblock': |
|||
case 'userlog': case 'userSpace': case 'deletedContribs': |
|||
this.article=this.article.userName(); |
|||
} |
|||
switch (this.id) { |
|||
case 'userTalk': case 'newUserTalk': case 'editUserTalk': |
|||
// FIXME anchor handling should be done differently with Title object |
|||
case 'userPage': case 'monobook': case 'editMonobook': case 'blocklog': |
|||
this.article = this.article.removeAnchor(); |
|||
this.article=this.article.userName(true); |
|||
/* fall through */ |
|||
} |
|||
case 'pagelog': case 'deletelog': case 'protectlog': |
|||
delete this.oldid; |
|||
} |
|||
if (this.id=='editMonobook' || this.id=='monobook') { this.article.append('/monobook.js'); } |
|||
switch (this.id) { |
|||
case 'undelete': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Undelete'; |
|||
this.sep = '/'; |
|||
break; |
|||
case 'whatLinksHere': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Whatlinkshere'; |
|||
break; |
|||
case 'relatedChanges': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Recentchangeslinked'; |
|||
break; |
|||
case 'move': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Movepage'; |
|||
break; |
|||
case 'contribs': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Contributions'; |
|||
break; |
|||
case 'deletedContribs': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Deletedcontributions'; |
|||
break; |
|||
case 'email': |
|||
this.print = specialLink; |
|||
this.specialpage = 'EmailUser'; |
|||
this.sep = '/'; |
|||
break; |
|||
case 'block': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Blockip'; |
|||
this.sep = '&ip='; |
|||
break; |
|||
case 'unblock': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Ipblocklist'; |
|||
this.sep = '&action=unblock&ip='; |
|||
break; |
|||
case 'userlog': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Log'; |
|||
this.sep = '&user='; |
|||
break; |
|||
case 'blocklog': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Log'; |
|||
this.sep = '&type=block&page='; |
|||
break; |
|||
case 'pagelog': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Log'; |
|||
this.sep = '&page='; |
|||
break; |
|||
case 'protectlog': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Log'; |
|||
this.sep = '&type=protect&page='; |
|||
break; |
|||
case 'deletelog': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Log'; |
|||
this.sep = '&type=delete&page='; |
|||
break; |
|||
case 'userSpace': |
|||
this.print = specialLink; |
|||
this.specialpage = 'PrefixIndex'; |
|||
this.sep = '&namespace=2&prefix='; |
|||
break; |
|||
case 'search': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Search'; |
|||
this.sep = '&fulltext=Search&search='; |
|||
break; |
|||
case 'thank': |
|||
this.print = specialLink; |
|||
this.specialpage = 'Thanks'; |
|||
this.sep = '/'; |
|||
this.article.value = this.diff !== 'prev' ? this.diff : this.oldid; |
|||
break; |
|||
case 'unwatch': |
|||
case 'watch': |
|||
this.print = magicWatchLink; |
|||
this.action = |
|||
this.id + |
|||
'&autowatchlist=1&autoimpl=' + |
|||
popupString('autoedit_version') + |
|||
'&actoken=' + |
|||
autoClickToken(); |
|||
break; |
|||
case 'history': |
|||
case 'historyfeed': |
|||
case 'unprotect': |
|||
case 'protect': |
|||
this.print = wikiLink; |
|||
this.action = this.id; |
|||
break; |
|||
if (this.id != 'mainlink') { |
|||
case 'delete': |
|||
// FIXME anchor handling should be done differently with Title object |
|||
this.print = wikiLink; |
|||
this.article=this.article.removeAnchor(); |
|||
this.action = 'delete'; |
|||
// if (typeof this.text=='undefined') this.text=popupString(this.id); |
|||
if (this.article.namespaceId() == pg.nsImageId) { |
|||
} |
|||
var img = this.article.stripNamespace(); |
|||
this.action += '&image=' + img; |
|||
} |
|||
break; |
|||
switch (this.id) { |
|||
case 'markpatrolled': |
|||
case 'undelete': this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break; |
|||
case 'edit': // editOld should keep the oldid, but edit should not. |
|||
case 'whatLinksHere': this.print=specialLink; this.specialpage='Whatlinkshere'; break; |
|||
delete this.oldid; |
|||
case 'relatedChanges': this.print=specialLink; this.specialpage='Recentchangeslinked'; break; |
|||
/* fall through */ |
|||
case 'move': this.print=specialLink; this.specialpage='Movepage'; break; |
|||
case 'view': |
|||
case 'contribs': this.print=specialLink; this.specialpage='Contributions'; break; |
|||
case 'purge': |
|||
case 'deletedContribs':this.print=specialLink; this.specialpage='Deletedcontributions'; break; |
|||
case 'render': |
|||
case 'email': this.print=specialLink; this.specialpage='EmailUser'; this.sep='/'; break; |
|||
this.print = wikiLink; |
|||
case 'block': this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break; |
|||
this.action = this.id; |
|||
case 'unblock': this.print=specialLink; this.specialpage='Ipblocklist'; this.sep='&action=unblock&ip='; break; |
|||
break; |
|||
case 'userlog': this.print=specialLink; this.specialpage='Log'; this.sep='&user='; break; |
|||
case 'raw': |
|||
case 'blocklog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=block&page='; break; |
|||
this.print = wikiLink; |
|||
case 'pagelog': this.print=specialLink; this.specialpage='Log'; this.sep='&page='; break; |
|||
this.action = 'raw'; |
|||
case 'protectlog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=protect&page='; break; |
|||
break; |
|||
case 'deletelog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=delete&page='; break; |
|||
case 'new': |
|||
case 'userSpace': this.print=specialLink; this.specialpage='PrefixIndex'; this.sep='&namespace=2&prefix='; break; |
|||
this.print = wikiLink; |
|||
case 'search': this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break; |
|||
this.action = 'edit§ion=new'; |
|||
case 'thank': this.print=specialLink; this.specialpage='Thanks'; this.sep='/'; this.article.value = this.diff; break; |
|||
break; |
|||
case 'unwatch': case 'watch': |
|||
this.print=magicWatchLink; this.action=this.id+'&autowatchlist=1&autoimpl=' + popupString('autoedit_version') + '&actoken='+autoClickToken(); break; |
|||
if (typeof this.text == 'undefined') { |
|||
case 'history': case 'historyfeed': |
|||
this.text = this.article.toString().entify(); |
|||
case 'unprotect': case 'protect': |
|||
} |
|||
this.print=wikiLink; this.action=this.id; break; |
|||
if (getValueOf('popupSimplifyMainLink') && isInStrippableNamespace(this.article)) { |
|||
// only show the /subpage part of the title text |
|||
var s = this.text.split('/'); |
|||
this.text = s[s.length - 1]; |
|||
if (this.text === '' && s.length > 1) { |
|||
this.text = s[s.length - 2]; |
|||
} |
|||
} |
|||
this.print = titledWikiLink; |
|||
if ( |
|||
typeof this.title === 'undefined' && |
|||
pg.current.link && |
|||
typeof pg.current.link.href !== 'undefined' |
|||
) { |
|||
this.title = safeDecodeURI( |
|||
pg.current.link.originalTitle ? pg.current.link.originalTitle : this.article |
|||
); |
|||
if (typeof this.oldid !== 'undefined' && this.oldid) { |
|||
this.title = tprintf('Revision %s of %s', [this.oldid, this.title]); |
|||
} |
|||
} |
|||
this.action = 'view'; |
|||
break; |
|||
case 'userPage': |
|||
case 'article': |
|||
case 'monobook': |
|||
case 'editMonobook': |
|||
case 'editArticle': |
|||
delete this.oldid; |
|||
//alert(this.id+'\n'+this.article + '\n'+ typeof this.article); |
|||
this.article = this.article.articleFromTalkOrArticle(); |
|||
//alert(this.id+'\n'+this.article + '\n'+ typeof this.article); |
|||
this.print = wikiLink; |
|||
if (this.id.indexOf('edit') === 0) { |
|||
this.action = 'edit'; |
|||
} else { |
|||
this.action = 'view'; |
|||
} |
|||
break; |
|||
case 'userTalk': |
|||
case 'talk': |
|||
this.article = this.article.talkPage(); |
|||
delete this.oldid; |
|||
this.print = wikiLink; |
|||
this.action = 'view'; |
|||
break; |
|||
case 'arin': |
|||
this.print = arinLink; |
|||
break; |
|||
case 'count': |
|||
this.print = editCounterLink; |
|||
break; |
|||
case 'google': |
|||
this.print = googleLink; |
|||
break; |
|||
case 'editors': |
|||
this.print = editorListLink; |
|||
break; |
|||
case 'globalsearch': |
|||
this.print = globalSearchLink; |
|||
break; |
|||
case 'lastEdit': |
|||
this.print = titledDiffLink; |
|||
this.title = popupString('Show the last edit'); |
|||
this.from = 'prev'; |
|||
this.to = 'cur'; |
|||
break; |
|||
case 'oldEdit': |
|||
this.print = titledDiffLink; |
|||
this.title = popupString('Show the edit made to get revision') + ' ' + this.oldid; |
|||
this.from = 'prev'; |
|||
this.to = this.oldid; |
|||
break; |
|||
case 'editOld': |
|||
this.print = wikiLink; |
|||
this.action = 'edit'; |
|||
break; |
|||
case 'undo': |
|||
this.print = wikiLink; |
|||
this.action = 'edit&undo='; |
|||
break; |
|||
case 'revert': |
|||
this.print = wikiLink; |
|||
this.action = 'revert'; |
|||
break; |
|||
case 'nullEdit': |
|||
this.print = wikiLink; |
|||
this.action = 'nullEdit'; |
|||
break; |
|||
case 'diffCur': |
|||
this.print = titledDiffLink; |
|||
this.title = tprintf('Show changes since revision %s', [this.oldid]); |
|||
this.from = this.oldid; |
|||
this.to = 'cur'; |
|||
break; |
|||
case 'editUserTalk': |
|||
case 'editTalk': |
|||
delete this.oldid; |
|||
this.article = this.article.talkPage(); |
|||
this.action = 'edit'; |
|||
this.print = wikiLink; |
|||
break; |
|||
case 'newUserTalk': |
|||
case 'newTalk': |
|||
this.article = this.article.talkPage(); |
|||
this.action = 'edit§ion=new'; |
|||
this.print = wikiLink; |
|||
break; |
|||
case 'lastContrib': |
|||
case 'sinceMe': |
|||
this.print = magicHistoryLink; |
|||
break; |
|||
case 'togglePreviews': |
|||
this.text = popupString(pg.option.simplePopups ? 'enable previews' : 'disable previews'); |
|||
/* fall through */ |
|||
case 'disablePopups': |
|||
case 'purgePopups': |
|||
this.print = popupMenuLink; |
|||
break; |
|||
default: |
|||
this.print = function () { |
|||
return 'Unknown navlink type: ' + String(this.id); |
|||
}; |
|||
} |
|||
}; |
|||
// |
|||
// end navlinks |
|||
////////////////////////////////////////////////// |
|||
// ENDFILE: navlinks.js |
|||
case 'delete': |
|||
// STARTFILE: shortcutkeys.js |
|||
this.print=wikiLink; this.action='delete'; |
|||
function popupHandleKeypress(evt) { |
|||
if (this.article.namespaceId()==pg.nsImageId) { |
|||
var keyCode = window.event ? window.event.keyCode : evt.keyCode ? evt.keyCode : evt.which; |
|||
var img=this.article.stripNamespace(); |
|||
if (!keyCode || !pg.current.link || !pg.current.link.navpopup) { |
|||
this.action+='&image='+img; |
|||
return; |
|||
} |
|||
if (keyCode == 27) { |
|||
// escape |
|||
killPopup(); |
|||
return false; // swallow keypress |
|||
} |
} |
||
break; |
|||
case 'markpatrolled': |
|||
var letter = String.fromCharCode(keyCode); |
|||
case 'edit': // editOld should keep the oldid, but edit should not. |
|||
var links = pg.current.link.navpopup.mainDiv.getElementsByTagName('A'); |
|||
delete this.oldid; |
|||
var startLink = 0; |
|||
/* fall through */ |
|||
var i, j; |
|||
case 'view': case 'purge': case 'render': |
|||
this.print=wikiLink; |
|||
if (popupHandleKeypress.lastPopupLinkSelected) { |
|||
this.action=this.id; break; |
|||
for (i = 0; i < links.length; ++i) { |
|||
case 'raw': |
|||
if (links[i] == popupHandleKeypress.lastPopupLinkSelected) { |
|||
this.print=wikiLink; this.action='raw&ctype=text/css'; break; |
|||
startLink = i; |
|||
case 'new': |
|||
} |
|||
this.print=wikiLink; this.action='edit§ion=new'; break; |
|||
} |
|||
case 'mainlink': |
|||
if (typeof this.text=='undefined') { this.text=this.article.toString().entify(); } |
|||
if (getValueOf('popupSimplifyMainLink') && isInStrippableNamespace(this.article)) { |
|||
var s=this.text.split('/'); this.text=s[s.length-1]; |
|||
if (this.text==='' && s.length > 1) { this.text=s[s.length-2]; } |
|||
} |
} |
||
this.print=titledWikiLink; |
|||
for (j = 0; j < links.length; ++j) { |
|||
if (typeof this.title==='undefined' && pg.current.link && typeof pg.current.link.href !== 'undefined') { |
|||
i = (startLink + j + 1) % links.length; |
|||
this.title=safeDecodeURI((pg.current.link.originalTitle)?pg.current.link.originalTitle:this.article); |
|||
if (links[i].getAttribute('popupkey') == letter) { |
|||
if (typeof this.oldid !== 'undefined' && this.oldid) { |
|||
this.title=tprintf('Revision %s of %s', [this.oldid, this.title]); |
|||
evt.preventDefault(); |
|||
} |
|||
links[i].focus(); |
|||
popupHandleKeypress.lastPopupLinkSelected = links[i]; |
|||
return false; // swallow keypress |
|||
} |
} |
||
} |
} |
||
this.action='view'; break; |
|||
case 'userPage': |
|||
// pass keypress on |
|||
case 'article': |
|||
if (document.oldPopupOnkeypress) { |
|||
case 'monobook': |
|||
return document.oldPopupOnkeypress(evt); |
|||
case 'editMonobook': |
|||
} |
|||
case 'editArticle': |
|||
return true; |
|||
delete this.oldid; |
|||
//alert(this.id+'\n'+this.article + '\n'+ typeof this.article); |
|||
this.article=this.article.articleFromTalkOrArticle(); |
|||
//alert(this.id+'\n'+this.article + '\n'+ typeof this.article); |
|||
this.print=wikiLink; |
|||
if (this.id.indexOf('edit')===0) { |
|||
this.action='edit'; |
|||
} else { this.action='view';} |
|||
break; |
|||
case 'userTalk': |
|||
case 'talk': |
|||
this.article=this.article.talkPage(); |
|||
delete this.oldid; |
|||
this.print=wikiLink; |
|||
this.action='view'; break; |
|||
case 'arin': |
|||
this.print=arinLink; break; |
|||
case 'count': |
|||
this.print=editCounterLink; break; |
|||
case 'google': |
|||
this.print=googleLink; break; |
|||
case 'editors': |
|||
this.print=editorListLink; break; |
|||
case 'globalsearch': |
|||
this.print=globalSearchLink; break; |
|||
case 'lastEdit': |
|||
this.print=titledDiffLink; |
|||
this.title=popupString('Show the last edit'); |
|||
this.from='prev'; this.to='cur'; break; |
|||
case 'oldEdit': |
|||
this.print=titledDiffLink; |
|||
this.title=popupString('Show the edit made to get revision') + ' ' + this.oldid; |
|||
this.from='prev'; this.to=this.oldid; break; |
|||
case 'editOld': |
|||
this.print=wikiLink; this.action='edit'; break; |
|||
case 'undo': |
|||
this.print=wikiLink; this.action='edit&undo='; break; |
|||
case 'markpatrolled': |
|||
this.print=wikiLink; this.action='markpatrolled'; |
|||
/* fall through */ |
|||
case 'revert': |
|||
this.print=wikiLink; this.action='revert'; break; |
|||
case 'nullEdit': |
|||
this.print=wikiLink; this.action='nullEdit'; break; |
|||
case 'diffCur': |
|||
this.print=titledDiffLink; |
|||
this.title=tprintf('Show changes since revision %s', [this.oldid]); |
|||
this.from=this.oldid; this.to='cur'; break; |
|||
case 'editUserTalk': |
|||
case 'editTalk': |
|||
delete this.oldid; |
|||
this.article=this.article.talkPage(); |
|||
this.action='edit'; this.print=wikiLink; break; |
|||
case 'newUserTalk': |
|||
case 'newTalk': |
|||
this.article=this.article.talkPage(); |
|||
this.action='edit§ion=new'; this.print=wikiLink; break; |
|||
case 'lastContrib': |
|||
case 'sinceMe': |
|||
this.print=magicHistoryLink; |
|||
break; |
|||
case 'togglePreviews': |
|||
this.text=popupString(pg.option.simplePopups ? 'enable previews' : 'disable previews'); |
|||
/* fall through */ |
|||
case 'disablePopups': case 'purgePopups': |
|||
this.print=popupMenuLink; |
|||
break; |
|||
default: |
|||
this.print=function () {return 'Unknown navlink type: '+this.id+'';}; |
|||
} |
} |
||
}; |
|||
// |
|||
function addPopupShortcuts() { |
|||
// end navlinks |
|||
if (document.onkeypress != popupHandleKeypress) { |
|||
////////////////////////////////////////////////// |
|||
document.oldPopupOnkeypress = document.onkeypress; |
|||
//</NOLITE> |
|||
} |
|||
// ENDFILE: navlinks.js |
|||
document.onkeypress = popupHandleKeypress; |
|||
// STARTFILE: shortcutkeys.js |
|||
//<NOLITE> |
|||
function popupHandleKeypress(evt) { |
|||
var keyCode = window.event ? window.event.keyCode : ( evt.keyCode ? evt.keyCode : evt.which); |
|||
if (!keyCode || !pg.current.link || !pg.current.link.navpopup) { return; } |
|||
if (keyCode==27) { // escape |
|||
killPopup(); |
|||
return false; // swallow keypress |
|||
} |
} |
||
var letter=String.fromCharCode(keyCode); |
|||
function rmPopupShortcuts() { |
|||
var links=pg.current.link.navpopup.mainDiv.getElementsByTagName('A'); |
|||
popupHandleKeypress.lastPopupLinkSelected = null; |
|||
var startLink=0; |
|||
try { |
|||
var i,j; |
|||
if (document.oldPopupOnkeypress && document.oldPopupOnkeypress == popupHandleKeypress) { |
|||
// panic |
|||
document.onkeypress = null; //function () {}; |
|||
return; |
|||
} |
|||
document.onkeypress = document.oldPopupOnkeypress; |
|||
} catch (nasties) { |
|||
/* IE goes here */ |
|||
} |
|||
} |
|||
if (popupHandleKeypress.lastPopupLinkSelected) { |
|||
function addLinkProperty(html, property) { |
|||
for (i=0; i<links.length; ++i) { |
|||
// take "<a href=...>...</a> and add a property |
|||
if (links[i]==popupHandleKeypress.lastPopupLinkSelected) { startLink=i; } |
|||
// not sophisticated at all, easily broken |
|||
var i = html.indexOf('>'); |
|||
if (i < 0) { |
|||
return html; |
|||
} |
} |
||
return html.substring(0, i) + ' ' + property + html.substring(i); |
|||
} |
} |
||
for (j=0; j<links.length; ++j) { |
|||
i=(startLink + j + 1) % links.length; |
|||
function addPopupShortcut(html, key) { |
|||
if ( |
if (links[i].getAttribute('popupkey')==letter) { |
||
if (evt && evt.preventDefault) evt.preventDefault(); |
|||
return html; |
|||
links[i].focus(); |
|||
} |
|||
popupHandleKeypress.lastPopupLinkSelected=links[i]; |
|||
var ret = addLinkProperty(html, 'popupkey="' + key + '"'); |
|||
return false; // swallow keypress |
|||
if (key == ' ') { |
|||
key = popupString('spacebar'); |
|||
} |
} |
||
return ret.replace(/^(.*?)(title=")(.*?)(".*)$/i, '$1$2$3 [' + key + ']$4'); |
|||
} |
} |
||
// ENDFILE: shortcutkeys.js |
|||
// pass keypress on |
|||
// STARTFILE: diffpreview.js |
|||
if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); } |
|||
/** |
|||
return true; |
|||
* Load diff data. |
|||
} |
|||
* |
|||
* lets jump through hoops to find the rev ids we need to retrieve |
|||
* |
|||
* @param {Title} article |
|||
* @param {string} oldid |
|||
* @param {string} diff |
|||
* @param {Navpopup} navpop |
|||
*/ |
|||
function loadDiff(article, oldid, diff, navpop) { |
|||
navpop.diffData = { oldRev: {}, newRev: {} }; |
|||
mw.loader.using('mediawiki.api').then(function () { |
|||
var api = getMwApi(); |
|||
var params = { |
|||
action: 'compare', |
|||
prop: 'ids|title', |
|||
}; |
|||
params.fromtitle = article.toString(); |
|||
function addPopupShortcuts() { |
|||
switch (diff) { |
|||
if (document.onkeypress!=popupHandleKeypress) { |
|||
case 'cur': |
|||
document.oldPopupOnkeypress=document.onkeypress; |
|||
switch (oldid) { |
|||
} |
|||
case null: |
|||
document.onkeypress=popupHandleKeypress; |
|||
case '': |
|||
} |
|||
case 'prev': |
|||
// this can only work if we have the title |
|||
// cur -> prev |
|||
params.torelative = 'prev'; |
|||
break; |
|||
default: |
|||
params.fromrev = oldid; |
|||
params.torelative = 'cur'; |
|||
break; |
|||
} |
|||
break; |
|||
case 'prev': |
|||
if (oldid && oldid !== 'cur') { |
|||
params.fromrev = oldid; |
|||
} |
|||
params.torelative = 'prev'; |
|||
break; |
|||
case 'next': |
|||
params.fromrev = oldid || 0; |
|||
params.torelative = 'next'; |
|||
break; |
|||
default: |
|||
params.fromrev = oldid || 0; |
|||
params.torev = diff || 0; |
|||
break; |
|||
} |
|||
function rmPopupShortcuts() { |
|||
popupHandleKeypress.lastPopupLinkSelected=null; |
|||
navpop.diffData.oldRev.revid = data.compare.fromrevid; |
|||
try { |
|||
navpop.diffData.newRev.revid = data.compare.torevid; |
|||
if (document.oldPopupOnkeypress && document.oldPopupOnkeypress==popupHandleKeypress) { |
|||
// panic |
|||
document.onkeypress=null; //function () {}; |
|||
return; |
|||
} |
|||
document.onkeypress=document.oldPopupOnkeypress; |
|||
} catch (nasties) { /* IE goes here */ } |
|||
} |
|||
addReviewLink(navpop, 'popupMiscTools'); |
|||
function addLinkProperty(html, property) { |
|||
// take "<a href=...>...</a> and add a property |
|||
pendingNavpopTask(navpop); |
|||
// not sophisticated at all, easily broken |
|||
var url = pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&'; |
|||
var i=html.indexOf('>'); |
|||
if (i<0) { return html; } |
|||
return html.substring(0,i) + ' ' + property + html.substring(i); |
|||
} |
|||
function addPopupShortcut(html, key) { |
|||
url += 'revids=' + navpop.diffData.oldRev.revid + '|' + navpop.diffData.newRev.revid; |
|||
if (!getValueOf('popupShortcutKeys')) { return html; } |
|||
url += '&prop=revisions&rvslots=main&rvprop=ids|timestamp|content'; |
|||
var ret= addLinkProperty(html, 'popupkey="'+key+'"'); |
|||
if (key==' ') { key=popupString('spacebar'); } |
|||
return ret.replace(RegExp('^(.*?)(title=")(.*?)(".*)$', 'i'),'$1$2$3 ['+key+']$4'); |
|||
} |
|||
//</NOLITE> |
|||
// ENDFILE: shortcutkeys.js |
|||
// STARTFILE: diffpreview.js |
|||
//<NOLITE> |
|||
function loadDiff(article, oldid, diff, navpop) { |
|||
navpop.diffData={}; |
|||
var oldRev, newRev; |
|||
switch (diff) { |
|||
case 'cur': |
|||
switch ( oldid ) { |
|||
case null: |
|||
case '': |
|||
case 'prev': |
|||
// eg newmessages diff link |
|||
oldRev='0&direction=prev'; |
|||
newRev=0; |
|||
break; |
|||
default: |
|||
oldRev = oldid; |
|||
newRev = ( oldid || 0 ) + '&direction=cur'; |
|||
} |
|||
break; |
|||
case 'prev': |
|||
oldRev = ( oldid || 0 ) + '&direction=prev'; newRev = oldid; break; |
|||
case 'next': |
|||
oldRev = oldid; newRev = oldid + '&direction=next'; |
|||
break; |
|||
default: |
|||
oldRev = oldid || 0; newRev = diff || 0; break; |
|||
} |
|||
oldRev = oldRev || 0; |
|||
newRev = newRev || 0; |
|||
var go = function() { |
|||
getPageWithCaching(url, doneDiff, navpop); |
|||
pendingNavpopTask(navpop); |
|||
getWiki(article, doneDiffNew, newRev, navpop); |
|||
pendingNavpopTask(navpop); |
|||
return true; // remove hook once run |
|||
getWiki(article, doneDiffOld, oldRev, navpop); |
|||
}; |
|||
if (navpop.visible || !getValueOf('popupLazyDownloads')) { |
|||
go(); |
|||
} else { |
|||
navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
var tz = Cookie.read('popTz'); |
|||
// Put a "mark patrolled" link to an element target |
|||
if ( mw.config.get('wgEnableAPI') && getValueOf('popupAdjustDiffDates') && tz === null) { |
|||
// TODO: Allow patrol a revision, as well as a diff |
|||
pendingNavpopTask(navpop); |
|||
function addReviewLink(navpop, target) { |
|||
getPageWithCaching(pg.wiki.apiwikibase + '?format=json&action=query&meta=userinfo&uiprop=options', |
|||
if (!pg.user.canReview) { |
|||
function(d) { |
|||
return; |
|||
completedNavpopTask(navpop); |
|||
setTimecorrectionCookie(d); |
|||
if (diffDownloadsComplete(navpop)) { insertDiff(navpop); } |
|||
}, navpop); |
|||
} |
} |
||
return true; // remove hook once run |
|||
// If 'newRev' is older than 'oldRev' than it could be confusing, so we do not show the review link. |
|||
}; |
|||
if (navpop.diffData.newRev.revid <= navpop.diffData.oldRev.revid) { |
|||
if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); } |
|||
return; |
|||
else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); } |
|||
} |
|||
} |
|||
var params = { |
|||
action: 'query', |
|||
function setTimecorrectionCookie(d) { |
|||
prop: 'info|flagged', |
|||
try { |
|||
revids: navpop.diffData.oldRev.revid, |
|||
var jsobj=getJsObj(d.data); |
|||
formatversion: 2, |
|||
var tz=jsobj.query.userinfo.options.timecorrection; |
|||
}; |
|||
Cookie.create( 'popTz', getTimeOffset(tz), 1); |
|||
getMwApi() |
|||
} catch (someError) { |
|||
.get(params) |
|||
logerr( 'setTimecorretion failed' ); |
|||
.then(function (data) { |
|||
return; |
|||
var stable_revid = |
|||
(data.query.pages[0].flagged && data.query.pages[0].flagged.stable_revid) || 0; |
|||
// The diff can be reviewed if the old version is the last reviewed version |
|||
// TODO: Other possible conditions that we may want to implement instead of this one: |
|||
// * old version is patrolled and the new version is not patrolled |
|||
// * old version is patrolled and the new version is more recent than the last reviewed version |
|||
if (stable_revid == navpop.diffData.oldRev.revid) { |
|||
var a = document.createElement('a'); |
|||
a.innerHTML = popupString('mark patrolled'); |
|||
a.title = popupString('markpatrolledHint'); |
|||
a.onclick = function () { |
|||
var params = { |
|||
action: 'review', |
|||
revid: navpop.diffData.newRev.revid, |
|||
comment: tprintf('defaultpopupReviewedSummary', [ |
|||
navpop.diffData.oldRev.revid, |
|||
navpop.diffData.newRev.revid, |
|||
]), |
|||
}; |
|||
getMwApi() |
|||
.postWithToken('csrf', params) |
|||
.done(function () { |
|||
a.style.display = 'none'; |
|||
// TODO: Update current page and other already constructed popups |
|||
}) |
|||
.fail(function () { |
|||
alert(popupString('Could not marked this edit as patrolled')); |
|||
}); |
|||
}; |
|||
setPopupHTML(a, target, navpop.idNumber, null, true); |
|||
} |
|||
}); |
|||
} |
} |
||
} |
|||
function doneDiff(download, isOld) { |
|||
if (!download.owner || !download.owner.diffData) { return; } |
|||
var navpop=download.owner; |
|||
return; |
|||
var label= (isOld) ? 'Old' : 'New'; |
|||
} |
|||
var otherLabel=(isOld) ? 'New' : 'Old'; |
|||
var navpop = download.owner; |
|||
navpop.diffData[label]=download; |
|||
completedNavpopTask(navpop); |
|||
completedNavpopTask(download.owner); |
|||
if (diffDownloadsComplete(navpop)) { insertDiff(navpop); } |
|||
} |
|||
function diffDownloadsComplete(navpop) { |
|||
var pages, |
|||
if ( Cookie.read('popTz')===null) { return false; } |
|||
revisions = []; |
|||
return navpop.diffData.Old && navpop.diffData.New; |
|||
try { |
|||
} |
|||
// Process the downloads |
|||
pages = getJsObj(download.data).query.pages; |
|||
for (var i = 0; i < pages.length; i++) { |
|||
revisions = revisions.concat(pages[i].revisions); |
|||
} |
|||
for (i = 0; i < revisions.length; i++) { |
|||
if (revisions[i].revid == navpop.diffData.oldRev.revid) { |
|||
navpop.diffData.oldRev.revision = revisions[i]; |
|||
} else if (revisions[i].revid == navpop.diffData.newRev.revid) { |
|||
navpop.diffData.newRev.revision = revisions[i]; |
|||
} |
|||
} |
|||
} catch (someError) { |
|||
errlog('Could not get diff'); |
|||
} |
|||
function doneDiffNew(download) { doneDiff(download, false); } |
|||
insertDiff(navpop); |
|||
function doneDiffOld(download) { doneDiff(download, true); } |
|||
} |
|||
function rmBoringLines(a,b,context) { |
|||
if (typeof context == 'undefined') { |
|||
context = 2; |
|||
} |
|||
// this is fairly slow... i think it's quicker than doing a word-based diff from the off, though |
|||
var aa = [], |
|||
aaa = []; |
|||
var bb = [], |
|||
bbb = []; |
|||
var i, j; |
|||
if (typeof context == 'undefined') { context=2; } |
|||
// first, gather all disconnected nodes in a and all crossing nodes in a and b |
|||
// this is fairly slow... i think it's quicker than doing a word-based diff from the off, though |
|||
for (i = 0; i < a.length; ++i) { |
|||
var aa=[], aaa=[]; |
|||
if (!a[i].paired) { |
|||
var bb=[], bbb=[]; |
|||
var i, j; |
|||
} else if (countCrossings(b, a, i, true)) { |
|||
aa[i] = 1; |
|||
bb[a[i].row] = 1; |
|||
} |
|||
} |
|||
// first, gather all disconnected nodes in a and all crossing nodes in a and b |
|||
for (i=0; i<a.length; ++i ) { |
|||
if(!a[i].paired) { aa[i]=1; } |
|||
else if (countCrossings(b,a,i, true)) { |
|||
continue; |
|||
aa[i]=1; |
|||
bb[ a[i].row ] = 1; |
|||
bb[i] = 1; |
|||
} |
|||
} |
} |
||
} |
|||
// pick up remaining disconnected nodes in b |
|||
// another pass to gather context: we want the neighbours of included nodes which are not |
|||
for (i=0; i<b.length; ++i ) { |
|||
// yet included we have to add in partners of these nodes, but we don't want to add context |
|||
if (bb[i]==1) { continue; } |
|||
// for *those* nodes in the next pass |
|||
if(!b[i].paired) { bb[i]=1; } |
|||
for (i = 0; i < b.length; ++i) { |
|||
} |
|||
if (bb[i] == 1) { |
|||
for (j = Math.max(0, i - context); j < Math.min(b.length, i + context); ++j) { |
|||
// another pass to gather context: we want the neighbours of included nodes which are not yet included |
|||
if (!bb[j]) { |
|||
// we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass |
|||
bb[j] = 1; |
|||
for (i=0; i<b.length; ++i) { |
|||
aa[b[j].row] = 0.5; |
|||
if ( bb[i] == 1 ) { |
|||
} |
|||
for (j=max(0,i-context); j < min(b.length, i+context); ++j) { |
|||
} |
|||
if ( !bb[j] ) { bb[j] = 1; aa[ b[j].row ] = 0.5; } |
|||
} |
} |
||
} |
} |
||
} |
|||
for (i=0; i<a.length; ++i) { |
|||
if ( aa[i] == 1 ) { |
|||
for (j=max(0,i-context); j < min(a.length, i+context); ++j) { |
|||
if ( !aa[j] ) { aa[j] = 1; bb[ a[j].row ] = 0.5; } |
|||
aa[j] = 1; |
|||
bb[a[j].row] = 0.5; |
|||
} |
|||
} |
|||
} |
} |
||
} |
} |
||
} |
|||
for (i=0; i<bb.length; ++i) { |
|||
if (bb[i] > 0) { // it's a row we need |
|||
if (b[i].paired) { bbb.push(b[i].text); } // joined; partner should be in aa |
|||
// it's a row we need |
|||
else { |
|||
bbb.push(b[i]); |
|||
} // joined; partner should be in aa |
|||
else { |
|||
bbb.push(b[i]); |
|||
} |
|||
} |
} |
||
} |
} |
||
} |
|||
for (i = 0; i < aa.length; ++i) { |
|||
for (i=0; i<aa.length; ++i) { |
|||
if (aa[i] > 0) { // it's a row we need |
|||
if (a[i].paired) { aaa.push(a[i].text); } // joined; partner should be in aa |
|||
else { |
|||
aaa.push(a[i].text); |
|||
aaa.push(a[i]); |
|||
} // joined; partner should be in aa |
|||
else { |
|||
aaa.push(a[i]); |
|||
} |
|||
} |
} |
||
} |
} |
||
return { a: aaa, b: bbb }; |
|||
} |
} |
||
return { a: aaa, b: bbb}; |
|||
function stripOuterCommonLines(a, b, context) { |
|||
} |
|||
var i = 0; |
|||
while (i < a.length && i < b.length && a[i] == b[i]) { |
|||
++i; |
|||
} |
|||
var j = a.length - 1; |
|||
var k = b.length - 1; |
|||
while (j >= 0 && k >= 0 && a[j] == b[k]) { |
|||
--j; |
|||
--k; |
|||
} |
|||
function stripOuterCommonLines(a,b,context) { |
|||
return { |
|||
var i=0; |
|||
a: a.slice(Math.max(0, i - 1 - context), Math.min(a.length + 1, j + context + 1)), |
|||
while (i<a.length && i < b.length && a[i]==b[i]) { ++i; } |
|||
var j=a.length-1; var k=b.length-1; |
|||
}; |
|||
while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; } |
|||
} |
|||
return { a: a.slice(max(0,i - 1 - context), min(a.length+1, j + context+1)), |
|||
function insertDiff(navpop) { |
|||
b: b.slice(max(0,i - 1 - context), min(b.length+1, k + context+1)) }; |
|||
// for speed reasons, we first do a line-based diff, discard stuff that seems boring, then |
|||
} |
|||
// do a word-based diff |
|||
// FIXME: sometimes this gives misleading diffs as distant chunks are squashed together |
|||
var oldlines = navpop.diffData.oldRev.revision.slots.main.content.split('\n'); |
|||
var newlines = navpop.diffData.newRev.revision.slots.main.content.split('\n'); |
|||
var inner = stripOuterCommonLines(oldlines, newlines, getValueOf('popupDiffContextLines')); |
|||
oldlines = inner.a; |
|||
newlines = inner.b; |
|||
var truncated = false; |
|||
getValueOf('popupDiffMaxLines'); |
|||
if ( |
|||
oldlines.length > pg.option.popupDiffMaxLines || |
|||
newlines.length > pg.option.popupDiffMaxLines |
|||
) { |
|||
// truncate |
|||
truncated = true; |
|||
inner = stripOuterCommonLines( |
|||
oldlines.slice(0, pg.option.popupDiffMaxLines), |
|||
newlines.slice(0, pg.option.popupDiffMaxLines), |
|||
pg.option.popupDiffContextLines |
|||
); |
|||
oldlines = inner.a; |
|||
newlines = inner.b; |
|||
} |
|||
function insertDiff(navpop) { |
|||
var lineDiff = diff(oldlines, newlines); |
|||
// for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff |
|||
var lines2 = rmBoringLines(lineDiff.o, lineDiff.n); |
|||
// FIXME: sometimes this gives misleading diffs as distant chunks are squashed together |
|||
var oldlines2 = lines2.a; |
|||
var oldlines=navpop.diffData.Old.data.split('\n'); |
|||
var newlines2 = lines2.b; |
|||
var newlines=navpop.diffData.New.data.split('\n'); |
|||
var inner=stripOuterCommonLines(oldlines,newlines,getValueOf('popupDiffContextLines')); |
|||
var simpleSplit = !String.prototype.parenSplit.isNative; |
|||
oldlines=inner.a; newlines=inner.b; |
|||
var html = '<hr />'; |
|||
var truncated=false; |
|||
if (getValueOf('popupDiffDates')) { |
|||
getValueOf('popupDiffMaxLines'); |
|||
html += diffDatesTable(navpop); |
|||
if (oldlines.length > pg.option.popupDiffMaxLines || newlines.length > pg.option.popupDiffMaxLines) { |
|||
html += '<hr />'; |
|||
// truncate |
|||
} |
|||
truncated=true; |
|||
html += shortenDiffString( |
|||
inner=stripOuterCommonLines(oldlines.slice(0,pg.option.popupDiffMaxLines), |
|||
diffString(oldlines2.join('\n'), newlines2.join('\n'), simpleSplit), |
|||
newlines.slice(0,pg.option.popupDiffMaxLines), |
|||
getValueOf('popupDiffContextCharacters') |
|||
pg.option.popupDiffContextLines); |
|||
).join('<hr />'); |
|||
oldlines=inner.a; newlines=inner.b; |
|||
setPopupTipsAndHTML( |
|||
html.split('\n').join('<br>') + |
|||
(truncated ? |
|||
'<hr /><b>' + popupString('Diff truncated for performance reasons') + '</b>' : |
|||
''), |
|||
'popupPreview', |
|||
navpop.idNumber |
|||
); |
|||
} |
} |
||
var lineDiff=diff(oldlines, newlines); |
|||
function diffDatesTable(navpop) { |
|||
var lines2=rmBoringLines(lineDiff.o, lineDiff.n); |
|||
var html = '<table class="popup_diff_dates">'; |
|||
var oldlines2=lines2.a; var newlines2=lines2.b; |
|||
html += diffDatesTableRow(navpop.diffData.newRev.revision, tprintf('New revision')); |
|||
html += diffDatesTableRow(navpop.diffData.oldRev.revision, tprintf('Old revision')); |
|||
var simpleSplit = !String.prototype.parenSplit.isNative; |
|||
html += '</table>'; |
|||
var html='<hr />'; |
|||
if (getValueOf('popupDiffDates')) { |
|||
html += diffDatesTable(navpop.diffData.Old, navpop.diffData.New); |
|||
html += '<hr />'; |
|||
} |
} |
||
html += shortenDiffString( |
|||
function diffDatesTableRow(revision, label) { |
|||
diffString(oldlines2.join('\n'), newlines2.join('\n'), simpleSplit), |
|||
var txt = ''; |
|||
getValueOf('popupDiffContextCharacters') ).join('<hr />'); |
|||
var lastModifiedDate = new Date(revision.timestamp); |
|||
setPopupTipsAndHTML(html.split('\n').join('<br>') + |
|||
(truncated ? '<hr /><b>'+popupString('Diff truncated for performance reasons')+'</b>' : '') , |
|||
'popupPreview', navpop.idNumber); |
|||
} |
|||
function diffDatesTable( oldDl, newDl ) { |
|||
txt = formattedDateTime(lastModifiedDate); |
|||
var html='<table class="popup_diff_dates">'; |
|||
html += diffDatesTableRow( newDl, tprintf('New revision')); |
|||
var revlink = generalLink({ |
|||
html += diffDatesTableRow( oldDl, tprintf('Old revision')); |
|||
url: mw.config.get('wgScript') + '?oldid=' + revision.revid, |
|||
html += '</table>'; |
|||
text: label, |
|||
return html; |
|||
title: label, |
|||
} |
|||
}); |
|||
function diffDatesTableRow( dl, label ) { |
|||
return simplePrintf('<tr><td>%s</td><td>%s</td></tr>', [revlink, txt]); |
|||
var txt=''; |
|||
if (!dl) { |
|||
txt=popupString('Something went wrong :-('); |
|||
} else if (!dl.lastModified) { |
|||
txt= (/^\s*$/.test(dl.data)) ? |
|||
popupString('Empty revision, maybe non-existent') : popupString('Unknown date'); |
|||
} else { |
|||
var datePrint=getValueOf('popupDiffDatePrinter'); |
|||
if (typeof dl.lastModified[datePrint] == 'function') { |
|||
if (getValueOf('popupAdjustDiffDates')) { |
|||
var off = Cookie.read('popTz'); |
|||
if (off) { |
|||
var d2 = adjustDate(dl.lastModified, off); |
|||
txt = dayFormat(d2, true) + ' ' + timeFormat(d2, true); |
|||
} |
|||
} else { |
|||
txt = dl.lastModified[datePrint](); |
|||
} |
|||
} else { |
|||
txt = tprintf('Invalid %s %s', ['popupDiffDatePrinter', datePrint]); |
|||
} |
|||
} |
} |
||
var revlink = generalLink({url: dl.url.replace(/&.*?(oldid=[0-9]+(?:&direction=[^&]*)?).*/, '&$1'), |
|||
// ENDFILE: diffpreview.js |
|||
text: label, title: label}); |
|||
return simplePrintf('<tr><td>%s</td><td>%s</td></tr>', [ revlink, txt ]); |
|||
} |
|||
//</NOLITE> |
|||
// ENDFILE: diffpreview.js |
|||
// STARTFILE: links.js |
|||
//<NOLITE> |
|||
///////////////////// |
|||
// LINK GENERATION // |
|||
///////////////////// |
|||
// titledDiffLink --> titledWikiLink --> generalLink |
|||
// STARTFILE: links.js |
|||
// wikiLink --> titledWikiLink --> generalLink |
|||
///////////////////// |
|||
// editCounterLink --> generalLink |
|||
// LINK GENERATION // |
|||
///////////////////// |
|||
// TODO Make these functions return Element objects, not just raw HTML strings. |
|||
// titledDiffLink --> titledWikiLink --> generalLink |
|||
// wikiLink --> titledWikiLink --> generalLink |
|||
// editCounterLink --> generalLink |
|||
function titledDiffLink(l) { // article, text, title, from, to) { |
|||
// TODO Make these functions return Element objects, not just raw HTML strings. |
|||
return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from, |
|||
newWin: l.newWin, |
|||
noPopup: l.noPopup, |
|||
text: l.text, title: l.title, |
|||
/* hack: no oldid here */ |
|||
actionName: 'diff'}); |
|||
} |
|||
function titledDiffLink(l) { |
|||
// article, text, title, from, to) { |
|||
return titledWikiLink({ |
|||
article: l.article, |
|||
action: l.to + '&oldid=' + l.from, |
|||
newWin: l.newWin, |
|||
noPopup: l.noPopup, |
|||
text: l.text, |
|||
title: l.title, |
|||
/* hack: no oldid here */ |
|||
actionName: 'diff', |
|||
}); |
|||
} |
|||
function wikiLink(l) { |
|||
//{article:article, action:action, text:text, oldid, newid}) { |
|||
if (! (typeof l.article == typeof {} && |
|||
if ( |
|||
typeof l.action == typeof '' && |
|||
typeof l.text==typeof '')) return null; |
|||
) { |
|||
if (typeof l.oldid == 'undefined') { l.oldid=null; } |
|||
return null; |
|||
var savedOldid = l.oldid; |
|||
if (!/^(edit|view|revert|render)$|^raw/.test(l.action)) { l.oldid=null; } |
|||
var hint=popupString(l.action + 'Hint'); // revertHint etc etc etc |
|||
var oldidData=[l.oldid, safeDecodeURI(l.article)]; |
|||
var revisionString = tprintf('revision %s of %s', oldidData); |
|||
log('revisionString='+revisionString); |
|||
switch (l.action) { |
|||
case 'edit§ion=new': hint = popupString('newSectionHint'); break; |
|||
case 'edit&undo=': |
|||
if (l.diff && l.diff != 'prev' && savedOldid ) { |
|||
l.action += l.diff + '&undoafter=' + savedOldid; |
|||
} else if (savedOldid) { |
|||
l.action += savedOldid; |
|||
} |
} |
||
hint = popupString('undoHint'); |
|||
if (typeof l.oldid == 'undefined') { |
|||
break; |
|||
l.oldid = null; |
|||
case 'raw&ctype=text/css': hint=popupString('rawHint'); break; |
|||
case 'revert': |
|||
if ( !mw.config.get('wgEnableAPI') ) { |
|||
alert( 'This function of navigation popups now requires a MediaWiki ' + |
|||
'installation with the API enabled.'); |
|||
break; |
|||
} |
} |
||
var p=parseParams(pg.current.link.href); |
|||
var savedOldid = l.oldid; |
|||
l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autoimpl=' + popupString('autoedit_version') + '&autosummary=' + revertSummary(l.oldid, p.diff); |
|||
if (!/^(edit|view|revert|render)$|^raw/.test(l.action)) { |
|||
if (p.diff=='prev') { |
|||
l.oldid = null; |
|||
l.action += '&direction=prev'; |
|||
revisionString = tprintf('the revision prior to revision %s of %s', oldidData); |
|||
} |
} |
||
if (getValueOf('popupRevertSummaryPrompt')) { l.action += '&autosummaryprompt=true'; } |
|||
var hint = popupString(l.action + 'Hint'); // revertHint etc etc etc |
|||
if (getValueOf('popupMinorReverts')) { l.action += '&autominor=true'; } |
|||
var oldidData = [l.oldid, safeDecodeURI(l.article)]; |
|||
log('revisionString is now '+revisionString); |
|||
var revisionString = tprintf('revision %s of %s', oldidData); |
|||
break; |
|||
log('revisionString=' + revisionString); |
|||
case 'nullEdit': |
|||
switch (l.action) { |
|||
l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autoimpl=' + popupString('autoedit_version') + '&autosummary=null'; |
|||
case 'edit§ion=new': |
|||
break; |
|||
hint = popupString('newSectionHint'); |
|||
case 'historyfeed': |
|||
break; |
|||
l.action='history&feed=rss'; |
|||
case 'edit&undo=': |
|||
break; |
|||
if (l.diff && l.diff != 'prev' && savedOldid) { |
|||
case 'markpatrolled': |
|||
l.action += l.diff + '&undoafter=' + savedOldid; |
|||
l.action='markpatrolled&rcid='+l.rcid; |
|||
} else if (savedOldid) { |
|||
l.action += savedOldid; |
|||
} |
|||
hint = popupString('undoHint'); |
|||
break; |
|||
case 'raw&ctype=text/css': |
|||
hint = popupString('rawHint'); |
|||
break; |
|||
case 'revert': |
|||
var p = parseParams(pg.current.link.href); |
|||
l.action = |
|||
'edit&autoclick=wpSave&actoken=' + |
|||
autoClickToken() + |
|||
'&autoimpl=' + |
|||
popupString('autoedit_version') + |
|||
'&autosummary=' + |
|||
revertSummary(l.oldid, p.diff); |
|||
if (p.diff == 'prev') { |
|||
l.action += '&direction=prev'; |
|||
revisionString = tprintf('the revision prior to revision %s of %s', oldidData); |
|||
} |
|||
if (getValueOf('popupRevertSummaryPrompt')) { |
|||
l.action += '&autosummaryprompt=true'; |
|||
} |
|||
if (getValueOf('popupMinorReverts')) { |
|||
l.action += '&autominor=true'; |
|||
} |
|||
log('revisionString is now ' + revisionString); |
|||
break; |
|||
case 'nullEdit': |
|||
l.action = |
|||
'edit&autoclick=wpSave&actoken=' + |
|||
autoClickToken() + |
|||
'&autoimpl=' + |
|||
popupString('autoedit_version') + |
|||
'&autosummary=null'; |
|||
break; |
|||
case 'historyfeed': |
|||
l.action = 'history&feed=rss'; |
|||
break; |
|||
case 'markpatrolled': |
|||
l.action = 'markpatrolled&rcid=' + l.rcid; |
|||
} |
|||
if (hint) { |
|||
if (l.oldid) { |
|||
hint = simplePrintf(hint, [revisionString]); |
|||
} else { |
|||
hint = simplePrintf(hint, [safeDecodeURI(l.article)]); |
|||
} |
|||
} else { |
|||
hint = safeDecodeURI(l.article + '&action=' + l.action) + l.oldid ? '&oldid=' + l.oldid : ''; |
|||
} |
|||
return titledWikiLink({ |
|||
article: l.article, |
|||
action: l.action, |
|||
text: l.text, |
|||
newWin: l.newWin, |
|||
title: hint, |
|||
oldid: l.oldid, |
|||
noPopup: l.noPopup, |
|||
onclick: l.onclick, |
|||
}); |
|||
} |
} |
||
if (hint) { |
|||
function revertSummary(oldid, diff) { |
|||
if (l.oldid) { |
|||
var ret = ''; |
|||
hint = simplePrintf(hint, [revisionString]); |
|||
if (diff == 'prev') { |
|||
} |
|||
ret = getValueOf('popupQueriedRevertToPreviousSummary'); |
|||
else { |
|||
hint = simplePrintf(hint, [safeDecodeURI(l.article)]); |
|||
ret = getValueOf('popupQueriedRevertSummary'); |
|||
} |
} |
||
} |
|||
return ret + '&autorv=' + oldid; |
|||
else { |
|||
hint = safeDecodeURI(l.article + '&action=' + l.action) + (l.oldid) ? '&oldid='+l.oldid : ''; |
|||
} |
} |
||
return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin, |
|||
title: hint, oldid: l.oldid, noPopup: l.noPopup, onclick: l.onclick}); |
|||
// possible properties of argument: |
|||
} |
|||
// article, action, text, title, oldid, actionName, className, noPopup |
|||
// oldid = null is fine here |
|||
function revertSummary(oldid, diff) { |
|||
// article and action are mandatory args |
|||
var ret=''; |
|||
if (diff == 'prev') { |
|||
ret=getValueOf('popupQueriedRevertToPreviousSummary'); |
|||
} else { ret = getValueOf('popupQueriedRevertSummary'); } |
|||
return ret + '&autorv=' + oldid; |
|||
} |
|||
function titledWikiLink(l) { |
|||
if (typeof l.article == 'undefined' || typeof l.action == 'undefined') { |
|||
// possible properties of argument: |
|||
errlog('got undefined article or action in titledWikiLink'); |
|||
// article, action, text, title, oldid, actionName, className, noPopup |
|||
return null; |
|||
// oldid = null is fine here |
|||
} |
|||
// article and action are mandatory args |
|||
var base = pg.wiki.titlebase + l.article.urlString(); |
|||
var url = base; |
|||
if (typeof l.article == 'undefined' || typeof l.action=='undefined') { |
|||
errlog('got undefined article or action in titledWikiLink'); |
|||
l.actionName = 'action'; |
|||
return null; |
|||
} |
|||
} |
|||
var base = pg.wiki.titlebase + l.article.urlString(); |
|||
// no need to add &action=view, and this confuses anchors |
|||
var url=base; |
|||
if (l.action != 'view') { |
|||
url = base + '&' + l.actionName + '=' + l.action; |
|||
} |
|||
if (typeof l.actionName=='undefined' || !l.actionName) { l.actionName='action'; } |
|||
url += '&oldid=' + l.oldid; |
|||
} |
|||
// no need to add &action=view, and this confuses anchors |
|||
var cssClass = pg.misc.defaultNavlinkClassname; |
|||
if (l.action != 'view') { url = base + '&' + l.actionName + '=' + l.action; } |
|||
if (typeof l.className != 'undefined' && l.className) { |
|||
cssClass = l.className; |
|||
} |
|||
if (typeof l.oldid!='undefined' && l.oldid) { url+='&oldid='+l.oldid; } |
|||
return generalNavLink({ |
|||
url: url, |
|||
newWin: l.newWin, |
|||
title: typeof l.title != 'undefined' ? l.title : null, |
|||
text: typeof l.text != 'undefined' ? l.text : null, |
|||
className: cssClass, |
|||
noPopup: l.noPopup, |
|||
onclick: l.onclick, |
|||
}); |
|||
} |
|||
var cssClass=pg.misc.defaultNavlinkClassname; |
|||
pg.fn.getLastContrib = function getLastContrib(wikipage, newWin) { |
|||
if (typeof l.className!='undefined' && l.className) { cssClass=l.className; } |
|||
getHistoryInfo(wikipage, function (x) { |
|||
processLastContribInfo(x, { page: wikipage, newWin: newWin }); |
|||
}); |
|||
}; |
|||
return generalNavLink({url: url, newWin: l.newWin, |
|||
function processLastContribInfo(info, stuff) { |
|||
title: (typeof l.title != 'undefined') ? l.title : null, |
|||
if (!info.edits || !info.edits.length) { |
|||
text: (typeof l.text!='undefined')?l.text:null, |
|||
alert('Popups: an odd thing happened. Please retry.'); |
|||
className: cssClass, noPopup:l.noPopup, onclick:l.onclick}); |
|||
return; |
|||
} |
|||
if (!info.firstNewEditor) { |
|||
alert( |
|||
tprintf('Only found one editor: %s made %s edits', [ |
|||
info.edits[0].editor, |
|||
info.edits.length, |
|||
]) |
|||
); |
|||
return; |
|||
} |
|||
var newUrl = |
|||
pg.wiki.titlebase + |
|||
new Title(stuff.page).urlString() + |
|||
'&diff=cur&oldid=' + |
|||
info.firstNewEditor.oldid; |
|||
displayUrl(newUrl, stuff.newWin); |
|||
} |
|||
pg.fn.getLastContrib = function getLastContrib(wikipage, newWin) { |
|||
getHistoryInfo(wikipage, function(x) { |
|||
processLastContribInfo(x, {page: wikipage, newWin: newWin}); |
|||
}); |
|||
}; |
|||
function processLastContribInfo(info, stuff) { |
|||
if(!info.edits || !info.edits.length) { alert('Popups: an odd thing happened. Please retry.'); return; } |
|||
if(!info.firstNewEditor) { |
|||
alert('Popups: something fishy happened. Please try again.'); |
|||
alert(tprintf('Only found one editor: %s made %s edits', [info.edits[0].editor,info.edits.length])); |
|||
return; |
|||
return; |
|||
var friendlyName = stuff.page.split('_').join(' '); |
|||
if (!info.myLastEdit) { |
|||
alert( |
|||
tprintf("Couldn't find an edit by %s\nin the last %s edits to\n%s", [ |
|||
info.userName, |
|||
getValueOf('popupHistoryLimit'), |
|||
friendlyName, |
|||
]) |
|||
); |
|||
return; |
|||
} |
|||
if (info.myLastEdit.index === 0) { |
|||
alert( |
|||
tprintf('%s seems to be the last editor to the page %s', [info.userName, friendlyName]) |
|||
); |
|||
return; |
|||
} |
|||
var newUrl = |
|||
pg.wiki.titlebase + |
|||
new Title(stuff.page).urlString() + |
|||
'&diff=cur&oldid=' + |
|||
info.myLastEdit.oldid; |
|||
displayUrl(newUrl, stuff.newWin); |
|||
} |
} |
||
var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+info.firstNewEditor.oldid; |
|||
displayUrl(newUrl, stuff.newWin); |
|||
} |
|||
pg.fn.getDiffSinceMyEdit = function getDiffSinceMyEdit(wikipage, newWin) { |
|||
getHistoryInfo(wikipage, function(x){ |
|||
if (newWin) { |
|||
processDiffSinceMyEdit(x, {page: wikipage, newWin: newWin}); |
|||
window.open(url); |
|||
}); |
|||
} else { |
|||
}; |
|||
document.location = url; |
|||
} |
|||
function processDiffSinceMyEdit(info, stuff) { |
|||
if(!info.edits || !info.edits.length) { alert('Popups: something fishy happened. Please try again.'); return; } |
|||
var friendlyName=stuff.page.split('_').join(' '); |
|||
if(!info.myLastEdit) { |
|||
alert(tprintf('Couldn\'t find an edit by %s\nin the last %s edits to\n%s', |
|||
[info.userName, getValueOf('popupHistoryLimit'), friendlyName])); |
|||
return; |
|||
} |
} |
||
if(info.myLastEdit.index === 0) { |
|||
alert(tprintf("%s seems to be the last editor to the page %s", [info.userName, friendlyName])); |
|||
return; |
|||
} |
|||
var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+ info.myLastEdit.oldid; |
|||
displayUrl(newUrl, stuff.newWin); |
|||
} |
|||
function displayUrl(url, newWin){ |
|||
if(newWin) { window.open(url); } |
|||
processAllPopups(true); |
|||
else { document.location=url; } |
|||
setupCache(); // deletes all cached items (not browser cached, though...) |
|||
} |
|||
pg.option = {}; |
|||
abortAllDownloads(); |
|||
}; |
|||
pg.fn.purgePopups = function purgePopups() { |
|||
processAllPopups(true); |
|||
for (var i = 0; pg.current.links && i < pg.current.links.length; ++i) { |
|||
setupCache(); // deletes all cached items (not browser cached, though...) |
|||
if (!pg.current.links[i].navpopup) { |
|||
pg.option={}; |
|||
continue; |
|||
abortAllDownloads(); |
|||
} |
|||
}; |
|||
if (nullify || banish) { |
|||
pg.current.links[i].navpopup.banish(); |
|||
function processAllPopups(nullify, banish) { |
|||
} |
|||
for (var i=0; pg.current.links && i<pg.current.links.length; ++i) { |
|||
if (!pg.current.links[i].navpopup) { continue; } |
|||
if (nullify) { |
|||
if (nullify || banish) pg.current.links[i].navpopup.banish(); |
|||
pg.current.links[i].simpleNoMore=false; |
|||
} |
|||
if (nullify) pg.current.links[i].navpopup=null; |
|||
} |
|||
} |
} |
||
} |
|||
pg.fn.disablePopups = function disablePopups(){ |
|||
processAllPopups(false, true); |
|||
setupTooltips(null, true); |
|||
}; |
|||
pg.fn.togglePreviews = function togglePreviews() { |
|||
processAllPopups(true, true); |
|||
pg.option.simplePopups=!pg.option.simplePopups; |
|||
abortAllDownloads(); |
|||
}; |
|||
function magicWatchLink(l) { |
|||
//Yuck!! Would require a thorough redesign to add this as a click event though ... |
|||
l.onclick = simplePrintf( 'pg.fn.modifyWatchlist(\'%s\',\'%s\');return false;', [l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), this.id] ); |
|||
return wikiLink(l); |
|||
l.article.toString(true).split('\\').join('\\\\').split("'").join("\\'"), |
|||
} |
|||
this.id, |
|||
]); |
|||
return wikiLink(l); |
|||
} |
|||
pg.fn.modifyWatchlist = function modifyWatchlist(title, action) { |
|||
var reqData = { |
|||
'action': 'watch', |
|||
'format': 'json', |
|||
formatversion: 2, |
|||
'title': title, |
|||
'token': mw.user.tokens.get('watchToken'), |
|||
'uselang': mw.config.get('wgUserLanguage') |
|||
}; |
|||
}; |
|||
if (action === 'unwatch') { |
|||
if ( action === 'unwatch' ) reqData.unwatch = ''; |
|||
} |
|||
jQuery.ajax( { |
|||
url: mw.util.wikiScript( 'api' ), |
|||
dataType: 'json', |
|||
type: 'POST', |
|||
data: reqData |
|||
} ).done( function () { |
|||
// Load the Addedwatchtext or Removedwatchtext message and show it |
// Load the Addedwatchtext or Removedwatchtext message and show it |
||
var mwTitle = mw.Title.newFromText(title); |
var mwTitle = mw.Title.newFromText( title ); |
||
var messageName; |
var messageName; |
||
if (mwTitle && mwTitle.getNamespaceId() > 0 && mwTitle.getNamespaceId() % 2 === 1) { |
if ( mwTitle && mwTitle.getNamespaceId() > 0 && mwTitle.getNamespaceId() % 2 === 1 ) { |
||
messageName = action === 'watch' ? 'addedwatchtext-talk' : 'removedwatchtext-talk'; |
messageName = action === 'watch' ? 'addedwatchtext-talk' : 'removedwatchtext-talk'; |
||
} else { |
} else { |
||
messageName = action === 'watch' ? 'addedwatchtext' : 'removedwatchtext'; |
messageName = action === 'watch' ? 'addedwatchtext' : 'removedwatchtext'; |
||
} |
} |
||
mw.loader.using( [ 'mediawiki.api.messages', 'mediawiki.jqueryMsg' ] ) |
|||
$.when( |
|||
.then( function () { |
|||
getMwApi().postWithToken('watch', reqData), |
|||
return new mw.Api().loadMessagesIfMissing( [ messageName ] ) |
|||
} ) |
|||
).done(function () { |
|||
.done( function ( messages ) { |
|||
mw.notify(mw.message(messageName, title).parseDom()); |
|||
mw.notify( mw.message( messageName, title ).parseDom() ); |
|||
}); |
|||
} ); |
|||
} ); |
|||
}; |
|||
function magicHistoryLink(l) { |
|||
// FIXME use onclick change href trick to sort this out instead of window.open |
|||
var jsUrl='', title='', onClick=''; |
|||
switch(l.id) { |
|||
title = '', |
|||
case 'lastContrib': |
|||
onClick = ''; |
|||
onClick=simplePrintf('pg.fn.getLastContrib(\'%s\',%s)', |
|||
switch (l.id) { |
|||
[l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), l.newWin]); |
|||
case 'lastContrib': |
|||
title=popupString('lastContribHint'); |
|||
onClick = simplePrintf("pg.fn.getLastContrib('%s',%s)", [ |
|||
break; |
|||
l.article.toString(true).split('\\').join('\\\\').split("'").join("\\'"), |
|||
case 'sinceMe': |
|||
l.newWin, |
|||
onClick=simplePrintf('pg.fn.getDiffSinceMyEdit(\'%s\',%s)', |
|||
]); |
|||
[l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), l.newWin]); |
|||
title = popupString('lastContribHint'); |
|||
title=popupString('sinceMeHint'); |
|||
break; |
|||
break; |
|||
case 'sinceMe': |
|||
onClick = simplePrintf("pg.fn.getDiffSinceMyEdit('%s',%s)", [ |
|||
l.article.toString(true).split('\\').join('\\\\').split("'").join("\\'"), |
|||
l.newWin, |
|||
]); |
|||
title = popupString('sinceMeHint'); |
|||
break; |
|||
} |
|||
jsUrl = 'javascript:' + onClick; // jshint ignore:line |
|||
onClick += ';return false;'; |
|||
return generalNavLink({ |
|||
url: jsUrl, |
|||
newWin: false, // can't have new windows with JS links, I think |
|||
title: title, |
|||
text: l.text, |
|||
noPopup: l.noPopup, |
|||
onclick: onClick, |
|||
}); |
|||
} |
} |
||
jsUrl = 'javascript:' + onClick; // jshint ignore:line |
|||
onClick += ';return false;'; |
|||
return generalNavLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think |
|||
function popupMenuLink(l) { |
|||
title: title, text: l.text, noPopup: l.noPopup, onclick: onClick }); |
|||
var jsUrl = simplePrintf('javascript:pg.fn.%s()', [l.id]); // jshint ignore:line |
|||
} |
|||
var title = popupString(simplePrintf('%sHint', [l.id])); |
|||
var onClick = simplePrintf('pg.fn.%s();return false;', [l.id]); |
|||
function popupMenuLink(l) { |
|||
return generalNavLink({ |
|||
var jsUrl=simplePrintf('javascript:pg.fn.%s()', [l.id]); // jshint ignore:line |
|||
url: jsUrl, |
|||
var title=popupString(simplePrintf('%sHint', [l.id])); |
|||
newWin: false, |
|||
var onClick=simplePrintf('pg.fn.%s();return false;', [l.id]); |
|||
title: title, |
|||
return generalNavLink({url: jsUrl, newWin:false, title:title, text:l.text, noPopup:l.noPopup, onclick: onClick}); |
|||
text: l.text, |
|||
} |
|||
noPopup: l.noPopup, |
|||
onclick: onClick, |
|||
}); |
|||
} |
|||
function specialLink(l) { |
|||
// properties: article, specialpage, text, sep |
|||
if (typeof l.specialpage=='undefined'||!l.specialpage) return null; |
|||
var base = pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId]+':'+l.specialpage; |
|||
return null; |
|||
if (typeof l.sep == 'undefined' || l.sep === null) l.sep='&target='; |
|||
var article=l.article.urlString({keepSpaces: l.specialpage=='Search'}); |
|||
var hint=popupString(l.specialpage+'Hint'); |
|||
switch (l.specialpage) { |
|||
case 'Log': |
|||
switch (l.sep) { |
|||
case '&user=': hint=popupString('userLogHint'); break; |
|||
case '&type=block&page=': hint=popupString('blockLogHint'); break; |
|||
case '&page=': hint=popupString('pageLogHint'); break; |
|||
case '&type=protect&page=': hint=popupString('protectLogHint'); break; |
|||
case '&type=delete&page=': hint=popupString('deleteLogHint'); break; |
|||
default: log('Unknown log type, sep=' + l.sep); hint='Missing hint (FIXME)'; |
|||
} |
} |
||
break; |
|||
var base = |
|||
case 'PrefixIndex': article += '/'; break; |
|||
pg.wiki.titlebase + |
|||
mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + |
|||
':' + |
|||
l.specialpage; |
|||
if (typeof l.sep == 'undefined' || l.sep === null) { |
|||
l.sep = '&target='; |
|||
} |
|||
var article = l.article.urlString({ |
|||
keepSpaces: l.specialpage == 'Search', |
|||
}); |
|||
var hint = popupString(l.specialpage + 'Hint'); |
|||
switch (l.specialpage) { |
|||
case 'Log': |
|||
switch (l.sep) { |
|||
case '&user=': |
|||
hint = popupString('userLogHint'); |
|||
break; |
|||
case '&type=block&page=': |
|||
hint = popupString('blockLogHint'); |
|||
break; |
|||
case '&page=': |
|||
hint = popupString('pageLogHint'); |
|||
break; |
|||
case '&type=protect&page=': |
|||
hint = popupString('protectLogHint'); |
|||
break; |
|||
case '&type=delete&page=': |
|||
hint = popupString('deleteLogHint'); |
|||
break; |
|||
default: |
|||
log('Unknown log type, sep=' + l.sep); |
|||
hint = 'Missing hint (FIXME)'; |
|||
} |
|||
break; |
|||
case 'PrefixIndex': |
|||
article += '/'; |
|||
break; |
|||
} |
|||
if (hint) { |
|||
hint = simplePrintf(hint, [safeDecodeURI(l.article)]); |
|||
} else { |
|||
hint = safeDecodeURI(l.specialpage + ':' + l.article); |
|||
} |
|||
var url = base + l.sep + article; |
|||
return generalNavLink({ |
|||
url: url, |
|||
title: hint, |
|||
text: l.text, |
|||
newWin: l.newWin, |
|||
noPopup: l.noPopup, |
|||
}); |
|||
} |
} |
||
if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]); |
|||
else hint = safeDecodeURI(l.specialpage+':'+l.article) ; |
|||
var url = base + l.sep + article; |
|||
/** |
|||
return generalNavLink({url: url, title: hint, text: l.text, newWin:l.newWin, noPopup:l.noPopup}); |
|||
* Builds a link from a object representing a link |
|||
} |
|||
* @param {Object} link |
|||
* @param {string} link.url URL |
|||
* @param {string} link.text The text to show for a link |
|||
* @param {string} link.title Title of the link, this shows up |
|||
* when you hover over the link |
|||
* @param {boolean} link.newWin Should open in a new Window |
|||
* @param {number} link.noPopup Should nest new popups from link (0 or 1) |
|||
* @param {string} link.onclick |
|||
* @return {string|null} null if no url is given |
|||
*/ |
|||
function generalLink(link) { |
|||
if (typeof link.url == 'undefined') { |
|||
return null; |
|||
} |
|||
function generalLink(l) { |
|||
var elem = document.createElement( 'a' ); |
|||
// l.url, l.text, l.title, l.newWin, l.className, l.noPopup, l.onclick |
|||
if (typeof l.url=='undefined') return null; |
|||
// only quotation marks in the url can screw us up now... I think |
|||
elem.href = link.url; |
|||
var url=l.url.split('"').join('%22'); |
|||
elem.title = link.title; |
|||
// The onclick event adds raw JS in textual form to the HTML. |
|||
// TODO: We should look into removing this, and/or auditing what gets sent. |
|||
elem.setAttribute( 'onclick', link.onclick ); |
|||
var ret='<a href="' + url + '"'; |
|||
if ( link.noPopup ) { |
|||
if (typeof l.title!='undefined' && l.title) { ret += ' title="' + pg.escapeQuotesHTML(l.title) + '"'; } |
|||
elem.setAttribute('noPopup', '1' ); |
|||
if (typeof l.onclick!='undefined' && l.onclick) { ret += ' onclick="' + pg.escapeQuotesHTML(l.onclick) + '"'; } |
|||
} |
|||
if (l.noPopup) { ret += ' noPopup=1'; } |
|||
var newWin; |
|||
if (typeof l.newWin=='undefined' || l.newWin === null) { newWin=getValueOf('popupNewWindows'); } |
|||
else { newWin=l.newWin; } |
|||
if (newWin) { ret += ' target="_blank"'; } |
|||
if (typeof l.className!='undefined'&&l.className) { ret+=' class="'+l.className+'"'; } |
|||
ret += '>'; |
|||
if (typeof l.text==typeof '') { ret+= l.text; } |
|||
ret +='</a>'; |
|||
return ret; |
|||
} |
|||
function appendParamsToLink(linkstr, params) { |
|||
var newWin; |
|||
var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i')); |
|||
if (typeof link.newWin == 'undefined' || link.newWin === null) { |
|||
if (sp.length<2) return null; |
|||
newWin = getValueOf('popupNewWindows'); |
|||
var ret=sp.shift() + sp.shift(); |
|||
} else { |
|||
ret += '&' + params + '"'; |
|||
newWin = link.newWin; |
|||
ret += sp.join(''); |
|||
} |
|||
return ret; |
|||
if (newWin) { |
|||
} |
|||
elem.target = '_blank'; |
|||
} |
|||
if (link.className) { |
|||
elem.className = link.className; |
|||
} |
|||
elem.innerText = pg.unescapeQuotesHTML(link.text); |
|||
function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor, title (optional) { |
|||
return elem.outerHTML; |
|||
if (x.newTarget) { |
|||
log ('changeLinkTargetLink: newTarget=' + x.newTarget); |
|||
} |
} |
||
if (x.oldTarget !== decodeURIComponent( x.oldTarget ) ) { |
|||
log ('This might be an input problem: ' + x.oldTarget ); |
|||
function appendParamsToLink(linkstr, params) { |
|||
var sp = linkstr.parenSplit(/(href="[^"]+?)"/i); |
|||
if (sp.length < 2) { |
|||
return null; |
|||
} |
|||
var ret = sp.shift() + sp.shift(); |
|||
ret += '&' + params + '"'; |
|||
ret += sp.join(''); |
|||
return ret; |
|||
} |
} |
||
// FIXME: first character of page title as well as namespace should be case insensitive |
|||
function changeLinkTargetLink(x) { |
|||
// eg category:X1 and Category:X1 are equivalent |
|||
// newTarget, text, hint, summary, clickButton, minor, title (optional), alsoChangeLabel { |
|||
// this'll break if charAt(0) is nasty |
|||
if (x.newTarget) { |
|||
var cA=literalizeRegex(x.oldTarget); |
|||
log('changeLinkTargetLink: newTarget=' + x.newTarget); |
|||
var chs=cA.charAt(0).toUpperCase(); |
|||
} |
|||
chs='['+chs + chs.toLowerCase()+']'; |
|||
if (x.oldTarget !== decodeURIComponent(x.oldTarget)) { |
|||
var currentArticleRegexBit=chs+cA.substring(1); |
|||
log('This might be an input problem: ' + x.oldTarget); |
|||
currentArticleRegexBit=currentArticleRegexBit |
|||
} |
|||
.split(RegExp('(?:[_ ]+|%20)', 'g')).join('(?:[_ ]+|%20)') |
|||
.split('\\(').join('(?:%28|\\()') |
|||
.split('\\)').join('(?:%29|\\))'); // why does this need to match encoded strings ? links in the document ? |
|||
// leading and trailing space should be ignored, and anchor bits optional: |
|||
currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + '(?:#[^\\[\\|]*)?)\\s*'; |
|||
// e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s* |
|||
// autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g |
|||
// FIXME: first character of page title as well as namespace should be case insensitive |
|||
// eg [[:category:X1]] and [[:Category:X1]] are equivalent |
|||
// this'll break if charAt(0) is nasty |
|||
var cA = mw.util.escapeRegExp(x.oldTarget); |
|||
var chs = cA.charAt(0).toUpperCase(); |
|||
chs = '[' + chs + chs.toLowerCase() + ']'; |
|||
var currentArticleRegexBit = chs + cA.substring(1); |
|||
currentArticleRegexBit = currentArticleRegexBit |
|||
.split(/(?:[_ ]+|%20)/g) |
|||
.join('(?:[_ ]+|%20)') |
|||
.split('\\(') |
|||
.join('(?:%28|\\()') |
|||
.split('\\)') |
|||
.join('(?:%29|\\))'); // why does this need to match encoded strings ? links in the document ? |
|||
// leading and trailing space should be ignored, and anchor bits optional: |
|||
currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + '(?:#[^\\[\\|]*)?)\\s*'; |
|||
// e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s* |
|||
var title=x.title || mw.config.get('wgPageName').split('_').join(' '); |
|||
// autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g |
|||
var lk=titledWikiLink({article: new Title(title), newWin:x.newWin, |
|||
action: 'edit', |
|||
var title = x.title || mw.config.get('wgPageName').split('_').join(' '); |
|||
text: x.text, |
|||
var lk = titledWikiLink({ |
|||
title: x.hint, |
|||
className: 'popup_change_title_link' |
|||
newWin: x.newWin, |
|||
}); |
|||
action: 'edit', |
|||
var cmd=''; |
|||
text: x.text, |
|||
if (x.newTarget) { |
|||
title: x.hint, |
|||
// escape '&' and other nasties |
|||
className: 'popup_change_title_link', |
|||
var t=x.newTarget; |
|||
}); |
|||
var s=literalizeRegex(x.newTarget); |
|||
var cmd = ''; |
|||
cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~[['+t+'|$1]]~g;'; |
|||
if (x.newTarget) { |
|||
cmd += 's~\\[\\['+currentArticleRegexBit+'[|]~[['+t+'|~g;'; |
|||
// escape '&' and other nasties |
|||
cmd += 's~\\[\\['+s + '\\|' + s + '\\]\\]~[[' + t + ']]~g'; |
|||
var t = x.newTarget; |
|||
} else { |
|||
var s = mw.util.escapeRegExp(x.newTarget); |
|||
cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~$1~g;'; |
|||
if (x.alsoChangeLabel) { |
|||
cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g'; |
|||
cmd += 's~\\[\\[' + currentArticleRegexBit + '[|]~[[' + t + '|~g;'; |
|||
cmd += 's~\\[\\[' + s + '\\|' + s + '\\]\\]~[[' + t + ']]~g'; |
|||
} else { |
|||
cmd += 's~\\[\\[' + currentArticleRegexBit + '\\]\\]~[[' + t + '|$1]]~g;'; |
|||
cmd += 's~\\[\\[' + currentArticleRegexBit + '[|]~[[' + t + '|~g;'; |
|||
cmd += 's~\\[\\[' + s + '\\|' + s + '\\]\\]~[[' + t + ']]~g'; |
|||
} |
|||
} else { |
|||
cmd += 's~\\[\\[' + currentArticleRegexBit + '\\]\\]~$1~g;'; |
|||
cmd += 's~\\[\\[' + currentArticleRegexBit + '[|](.*?)\\]\\]~$2~g'; |
|||
} |
|||
// Build query |
|||
cmd = 'autoedit=' + encodeURIComponent(cmd); |
|||
cmd += |
|||
'&autoclick=' + |
|||
encodeURIComponent(x.clickButton) + |
|||
'&actoken=' + |
|||
encodeURIComponent(autoClickToken()); |
|||
cmd += x.minor === null ? '' : '&autominor=' + encodeURIComponent(x.minor); |
|||
cmd += x.watch === null ? '' : '&autowatch=' + encodeURIComponent(x.watch); |
|||
cmd += '&autosummary=' + encodeURIComponent(x.summary); |
|||
cmd += '&autoimpl=' + encodeURIComponent(popupString('autoedit_version')); |
|||
return appendParamsToLink(lk, cmd); |
|||
} |
} |
||
// Build query |
|||
cmd = 'autoedit=' + encodeURIComponent ( cmd ); |
|||
cmd += '&autoclick='+ encodeURIComponent( x.clickButton ) + '&actoken=' + encodeURIComponent( autoClickToken() ); |
|||
cmd += ( x.minor === null ) ? '' : '&autominor='+ encodeURIComponent( x.minor ); |
|||
cmd += ( x.watch === null ) ? '' : '&autowatch='+ encodeURIComponent( x.watch ); |
|||
cmd += '&autosummary='+encodeURIComponent(x.summary); |
|||
cmd += '&autoimpl='+encodeURIComponent( popupString('autoedit_version') ); |
|||
return appendParamsToLink(lk, cmd); |
|||
} |
|||
function redirLink(redirMatch, article) { |
|||
// NB redirMatch is in wikiText |
|||
var ret = ''; |
|||
function redirLink(redirMatch, article) { |
|||
if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) { |
|||
// NB redirMatch is in wikiText |
|||
ret += '<hr />'; |
|||
var ret=''; |
|||
if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) { |
|||
ret += '<hr />'; |
|||
if (getValueOf('popupFixRedirs') && typeof autoEdit != 'undefined' && autoEdit) { |
|||
log('redirLink: newTarget=' + redirMatch); |
|||
log('redirLink: newTarget=' + redirMatch); |
|||
ret += addPopupShortcut( |
|||
ret += addPopupShortcut(changeLinkTargetLink({ |
|||
newTarget: redirMatch, |
|||
text: popupString('Redirects'), |
|||
hint: popupString('Fix this redirect'), |
|||
summary: simplePrintf(getValueOf('popupFixRedirsSummary'),[article.toString(), redirMatch]), |
|||
oldTarget: article.toString(), |
|||
clickButton: getValueOf('popupRedirAutoClick'), |
|||
redirMatch, |
|||
minor: true, |
|||
watch: getValueOf('popupWatchRedirredPages') |
|||
oldTarget: article.toString(), |
|||
}), 'R'); |
|||
clickButton: getValueOf('popupRedirAutoClick'), |
|||
ret += popupString(' to '); |
|||
minor: true, |
|||
watch: getValueOf('popupWatchRedirredPages'), |
|||
}), |
|||
'R' |
|||
); |
|||
ret += popupString(' or '); |
|||
ret += addPopupShortcut( |
|||
changeLinkTargetLink({ |
|||
newTarget: redirMatch, |
|||
text: popupString('target & label'), |
|||
hint: popupString('Fix this redirect, changing the link target and label'), |
|||
summary: simplePrintf(getValueOf('popupFixRedirsSummary'), [ |
|||
article.toString(), |
|||
redirMatch, |
|||
]), |
|||
oldTarget: article.toString(), |
|||
clickButton: getValueOf('popupRedirAutoClick'), |
|||
minor: true, |
|||
watch: getValueOf('popupWatchRedirredPages'), |
|||
alsoChangeLabel: true, |
|||
}), |
|||
'R' |
|||
); |
|||
ret += popupString(')'); |
|||
} else { |
|||
ret += popupString('Redirects') + popupString(' to '); |
|||
} |
|||
return ret; |
|||
} else { |
|||
return ( |
|||
'<br> ' + |
|||
popupString('Redirects') + |
|||
popupString(' to ') + |
|||
titledWikiLink({ |
|||
article: new Title().fromWikiText(redirMatch), |
|||
action: 'view' /* FIXME: newWin */, |
|||
text: safeDecodeURI(redirMatch), |
|||
title: popupString('Bypass redirect'), |
|||
}) |
|||
); |
|||
} |
} |
||
else ret += popupString('Redirects') + popupString(' to '); |
|||
return ret; |
|||
} |
} |
||
else return '<br> ' + popupString('Redirects') + popupString(' to ') + |
|||
function arinLink(l) { |
|||
titledWikiLink({article: new Title().fromWikiText(redirMatch), action: 'view', /* FIXME: newWin */ |
|||
if (!saneLinkCheck(l)) { |
|||
text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')}); |
|||
return null; |
|||
} |
|||
if (!l.article.isIpUser() || !pg.wiki.wikimedia) { |
|||
return null; |
|||
} |
|||
function arinLink(l) { |
|||
var uN = l.article.userName(); |
|||
if (!saneLinkCheck(l)) { return null; } |
|||
if ( ! l.article.isIpUser() || ! pg.wiki.wikimedia) return null; |
|||
var uN=l.article.userName(); |
|||
return generalNavLink({ |
|||
url: 'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + encodeURIComponent(uN), |
|||
newWin: l.newWin, |
|||
title: tprintf('Look up %s in ARIN whois database', [uN]), |
|||
text: l.text, |
|||
noPopup: 1, |
|||
}); |
|||
} |
|||
return generalNavLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + encodeURIComponent(uN), newWin:l.newWin, |
|||
function toolDbName(cookieStyle) { |
|||
title: tprintf('Look up %s in ARIN whois database', [uN]), |
|||
var ret = mw.config.get('wgDBname'); |
|||
text: l.text, noPopup:1}); |
|||
if (!cookieStyle) { |
|||
} |
|||
ret += '_p'; |
|||
} |
|||
return ret; |
|||
} |
|||
function toolDbName(cookieStyle) { |
|||
var ret = mw.config.get('wgDBname'); |
|||
if (typeof l.article != typeof {} || typeof l.text != typeof '') { |
|||
if (!cookieStyle) { ret+= '_p'; } |
|||
return false; |
|||
return ret; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
function saneLinkCheck(l) { |
|||
if (typeof l.article != typeof {} || typeof l.text != typeof '') { return false; } |
|||
if (!saneLinkCheck(l)) { |
|||
return true; |
|||
} |
|||
function editCounterLink(l) { |
|||
if (!pg.wiki.wikimedia) { |
|||
if(!saneLinkCheck(l)) return null; |
|||
if (! pg.wiki.wikimedia) return null; |
|||
} |
|||
var uN=l.article.userName(); |
|||
var tool=getValueOf('popupEditCounterTool'); |
|||
var url; |
|||
var soxredToolUrl='//tools.wmflabs.org/supercount/index.php?user=$1&project=$2.$3'; |
|||
switch(tool) { |
|||
case 'custom': |
|||
url=simplePrintf(getValueOf('popupEditCounterUrl'), [ encodeURIComponent(uN), toolDbName() ]); |
|||
break; |
|||
encodeURIComponent(uN), |
|||
case 'kate': |
|||
toolDbName(), |
|||
case 'interiot': |
|||
]); |
|||
/* fall through */ |
|||
break; |
|||
default: |
|||
case 'soxred': // no longer available |
|||
var theWiki=pg.wiki.hostname.split('.'); |
|||
case 'kate': // no longer available |
|||
url=simplePrintf(soxredToolUrl, [ encodeURIComponent(uN), theWiki[0], theWiki[1] ]); |
|||
case 'interiot': // no longer available |
|||
/* fall through */ |
|||
case 'supercount': |
|||
default: |
|||
var theWiki = pg.wiki.hostname.split('.'); |
|||
url = simplePrintf(defaultToolUrl, [encodeURIComponent(uN), theWiki[0], theWiki[1]]); |
|||
} |
|||
return generalNavLink({ |
|||
url: url, |
|||
title: tprintf('editCounterLinkHint', [uN]), |
|||
newWin: l.newWin, |
|||
text: l.text, |
|||
noPopup: 1, |
|||
}); |
|||
} |
} |
||
return generalNavLink({url:url, title: tprintf('editCounterLinkHint', [uN]), |
|||
newWin:l.newWin, text: l.text, noPopup:1}); |
|||
} |
|||
function globalSearchLink(l) { |
|||
if (!saneLinkCheck(l)) { |
|||
return null; |
|||
} |
|||
function globalSearchLink(l) { |
|||
var base = 'https://global-search.toolforge.org/?uselang=' + mw.config.get('wgUserLanguage') + '&q='; |
|||
if(!saneLinkCheck(l)) return null; |
|||
var article = l.article.urlString({ keepSpaces: true }); |
|||
var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search='; |
|||
return generalNavLink({ |
|||
var article=l.article.urlString({keepSpaces:true}); |
|||
url: base + article, |
|||
newWin: l.newWin, |
|||
title: tprintf('globalSearchHint', [safeDecodeURI(l.article)]), |
|||
text: l.text, |
|||
noPopup: 1, |
|||
}); |
|||
} |
|||
return generalNavLink({url:base + article, newWin:l.newWin, |
|||
function googleLink(l) { |
|||
title: tprintf('globalSearchHint', [safeDecodeURI(l.article)]), |
|||
if (!saneLinkCheck(l)) { |
|||
text: l.text, noPopup:1}); |
|||
return null; |
|||
} |
|||
function googleLink(l) { |
|||
var base = 'https://www.google.com/search?q='; |
|||
if(!saneLinkCheck(l)) return null; |
|||
var article = l.article.urlString({ keepSpaces: true }); |
|||
var base='http://www.google.com/search?q='; |
|||
return generalNavLink({ |
|||
var article=l.article.urlString({keepSpaces:true}); |
|||
url: base + '%22' + article + '%22', |
|||
newWin: l.newWin, |
|||
title: tprintf('googleSearchHint', [safeDecodeURI(l.article)]), |
|||
text: l.text, |
|||
noPopup: 1, |
|||
}); |
|||
} |
|||
return generalNavLink({url:base + '%22' + article + '%22', newWin:l.newWin, |
|||
function editorListLink(l) { |
|||
title: tprintf('googleSearchHint', [safeDecodeURI(l.article)]), |
|||
if (!saneLinkCheck(l)) { |
|||
text: l.text, noPopup:1}); |
|||
return null; |
|||
} |
|||
var article = l.article.articleFromTalkPage() || l.article; |
|||
var url = |
|||
'https://xtools.wmflabs.org/articleinfo/' + |
|||
encodeURI(pg.wiki.hostname) + |
|||
'/' + |
|||
article.urlString() + |
|||
'?uselang=' + |
|||
mw.config.get('wgUserLanguage'); |
|||
return generalNavLink({ |
|||
url: url, |
|||
title: tprintf('editorListHint', [article]), |
|||
newWin: l.newWin, |
|||
text: l.text, |
|||
noPopup: 1, |
|||
}); |
|||
} |
|||
function editorListLink(l) { |
|||
if(!saneLinkCheck(l)) return null; |
|||
l.className = l.className === null ? 'popupNavLink' : l.className; |
|||
var article= l.article.articleFromTalkPage() || l.article; |
|||
return generalLink(l); |
|||
var theWiki=pg.wiki.hostname.split('.'); |
|||
} |
|||
var base='//tools.wmflabs.org/xtools/articleinfo/index.php?&uselang=' + mw.config.get('wgUserLanguage') + |
|||
'lang=' + theWiki[0] + '&wiki=' + theWiki[1] + '&begin=&end=&article='; |
|||
return generalNavLink({url:base+article.urlString(), |
|||
title: tprintf('editorListHint', [article]), |
|||
newWin:l.newWin, text: l.text, noPopup:1}); |
|||
} |
|||
function generalNavLink(l) { |
|||
////////////////////////////////////////////////// |
|||
l.className = (l.className === null) ? 'popupNavLink' : l.className; |
|||
// magic history links |
|||
return generalLink(l); |
|||
// |
|||
} |
|||
////////////////////////////////////////////////// |
|||
function getHistoryInfo(wikipage, whatNext) { |
|||
// magic history links |
|||
log('getHistoryInfo'); |
|||
// |
|||
getHistory( |
|||
wikipage, |
|||
whatNext ? |
|||
function (d) { |
|||
whatNext(processHistory(d)); |
|||
} : |
|||
processHistory |
|||
); |
|||
} |
|||
function getHistoryInfo(wikipage, whatNext) { |
|||
// FIXME eliminate pg.idNumber ... how? :-( |
|||
log('getHistoryInfo'); |
|||
getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory); |
|||
} |
|||
// FIXME eliminate pg.idNumber ... how? :-( |
|||
function getHistory(wikipage, onComplete) { |
|||
log('getHistory'); |
|||
function getHistory(wikipage, onComplete) { |
|||
var url = |
|||
log('getHistory'); |
|||
pg.wiki.apiwikibase + |
|||
if( !mw.config.get('wgEnableAPI') ) { |
|||
'?format=json&formatversion=2&action=query&prop=revisions&titles=' + |
|||
alert( 'This function of navigation popups now requires a MediaWiki ' + |
|||
new Title(wikipage).urlString() + |
|||
'installation with the API enabled.'); |
|||
'&rvlimit=' + |
|||
return false; |
|||
getValueOf('popupHistoryLimit'); |
|||
log('getHistory: url=' + url); |
|||
return startDownload(url, pg.idNumber + 'history', onComplete); |
|||
} |
} |
||
var url = pg.wiki.apiwikibase + '?format=json&action=query&prop=revisions&titles=' + |
|||
new Title(wikipage).urlString() + '&rvlimit=' + getValueOf('popupHistoryLimit'); |
|||
log('getHistory: url='+url); |
|||
if (pg.flag.isIE) { |
|||
url = url + '&*'; //to circumvent https://bugzilla.wikimedia.org/show_bug.cgi?id=28840 |
|||
} |
|||
return startDownload(url, pg.idNumber+'history', onComplete); |
|||
} |
|||
function processHistory(download) { |
|||
var jsobj = getJsObj(download.data); |
|||
try { |
|||
var revisions = anyChild(jsobj.query.pages).revisions; |
window.x=jsobj; |
||
var revisions = anyChild(jsobj.query.pages).revisions; |
|||
var edits=[]; |
|||
for (var i=0; i<revisions.length; ++i) { |
|||
edits.push({ oldid: revisions[i].revid, editor: revisions[i].user }); |
|||
} |
|||
log('processed ' + edits.length + ' edits'); |
|||
return finishProcessHistory(edits, mw.config.get('wgUserName')); |
|||
} catch (someError) { |
|||
log('Something went wrong with JSON business'); |
|||
return finishProcessHistory([]); |
|||
} |
} |
||
log('processed ' + edits.length + ' edits'); |
|||
return finishProcessHistory( edits, mw.config.get('wgUserName') ); |
|||
} catch (someError) { |
|||
log('Something went wrong with JSON business'); |
|||
return finishProcessHistory([]); |
|||
} |
} |
||
} |
|||
function finishProcessHistory(edits, userName) { |
|||
var histInfo = {}; |
|||
function finishProcessHistory(edits, userName) { |
|||
histInfo.edits = edits; |
|||
var histInfo={}; |
|||
histInfo.edits=edits; |
|||
for (var i = 0; i < edits.length; ++i) { |
|||
histInfo.userName=userName; |
|||
histInfo.myLastEdit = { |
|||
for (var i=0; i<edits.length; ++i) { |
|||
index: i, |
|||
if (typeof histInfo.myLastEdit === 'undefined' && userName && edits[i].editor==userName) { |
|||
oldid: edits[i].oldid, |
|||
histInfo.myLastEdit={index: i, oldid: edits[i].oldid, previd: (i === 0 ? null : edits[i-1].oldid)}; |
|||
} |
|||
if (typeof histInfo.firstNewEditor === 'undefined' && edits[i].editor != edits[0].editor) { |
|||
} |
|||
histInfo.firstNewEditor={index:i, oldid:edits[i].oldid, previd: (i === 0 ? null : edits[i-1].oldid)}; |
|||
histInfo.firstNewEditor = { |
|||
index: i, |
|||
oldid: edits[i].oldid, |
|||
previd: i === 0 ? null : edits[i - 1].oldid, |
|||
}; |
|||
} |
|||
} |
} |
||
//pg.misc.historyInfo=histInfo; |
|||
return histInfo; |
|||
} |
} |
||
//pg.misc.historyInfo=histInfo; |
|||
// ENDFILE: links.js |
|||
return histInfo; |
|||
} |
|||
//</NOLITE> |
|||
// ENDFILE: links.js |
|||
// STARTFILE: options.js |
|||
////////////////////////////////////////////////// |
|||
// options |
|||
// check for cookies and existing value, else use default |
|||
// STARTFILE: options.js |
|||
function defaultize(x) { |
|||
////////////////////////////////////////////////// |
|||
var val=null; |
|||
// options |
|||
if (x!='popupCookies') { |
|||
defaultize('popupCookies'); |
|||
// check for existing value, else use default |
|||
if (pg.option.popupCookies && (val=Cookie.read(x))) { |
|||
function defaultize(x) { |
|||
pg.option[x]=val; |
|||
return; |
|||
if (typeof window[x] != 'undefined') { |
|||
pg.option[x] = window[x]; |
|||
} else { |
|||
pg.option[x] = pg.optionDefault[x]; |
|||
} |
|||
} |
} |
||
} |
} |
||
if (pg.option[x]===null || typeof pg.option[x]=='undefined') { |
|||
if (typeof window[x] != 'undefined' ) pg.option[x]=window[x]; |
|||
function newOption(x, def) { |
|||
pg. |
else pg.option[x]=pg.optionDefault[x]; |
||
} |
} |
||
} |
|||
function newOption(x, def) { |
|||
pg.optionDefault[x]=def; |
|||
return newOption(x, def); |
|||
} |
|||
function setDefault(x, def) { |
|||
return newOption(x, def); |
|||
defaultize(varName); |
|||
} |
|||
return pg.option[varName]; |
|||
function getValueOf(varName) { |
|||
defaultize(varName); |
|||
return pg.option[varName]; |
|||
} |
|||
function useDefaultOptions() { // for testing |
|||
for (var p in pg.optionDefault) { |
|||
pg.option[p]=pg.optionDefault[p]; |
|||
if (typeof window[p]!='undefined') { delete window[p]; } |
|||
} |
} |
||
} |
|||
function setOptions() { |
|||
/*eslint-disable */ |
|||
// user-settable parameters and defaults |
|||
function useDefaultOptions() { |
|||
var userIsSysop = false; |
|||
// for testing |
|||
if ( mw.config.get('wgUserGroups') ) { |
|||
for (var p in pg.optionDefault) { |
|||
for ( var g = 0; g < mw.config.get('wgUserGroups').length; ++g ) { |
|||
pg.option[p] = pg.optionDefault[p]; |
|||
if ( |
if ( mw.config.get('wgUserGroups')[g] == "sysop" ) |
||
userIsSysop = true; |
|||
} |
|||
} |
} |
||
} |
} |
||
/*eslint-enable */ |
|||
// Basic options |
|||
function setOptions() { |
|||
newOption('popupDelay', 0.5); |
|||
// user-settable parameters and defaults |
|||
newOption('popupHideDelay', 0.5); |
|||
var userIsSysop = false; |
|||
newOption('simplePopups', false); |
|||
if (mw.config.get('wgUserGroups')) { |
|||
newOption('popupStructure', 'shortmenus'); // see later - default for popupStructure is 'original' if simplePopups is true |
|||
for (var g = 0; g < mw.config.get('wgUserGroups').length; ++g) { |
|||
newOption('popupActionsMenu', true); |
|||
if (mw.config.get('wgUserGroups')[g] == 'sysop') { |
|||
newOption('popupSetupMenu', true); |
|||
userIsSysop = true; |
|||
newOption('popupAdminLinks', userIsSysop); |
|||
} |
|||
newOption('popupShortcutKeys', false); |
|||
} |
|||
newOption('popupHistoricalLinks', true); |
|||
} |
|||
newOption('popupOnlyArticleLinks', true); |
|||
newOption('removeTitles', true); |
|||
newOption('popupMaxWidth', 350); |
|||
newOption('popupInitialWidth', false); // integer or false |
|||
newOption('popupSimplifyMainLink', true); |
|||
newOption('popupAppendRedirNavLinks', true); |
|||
newOption('popupTocLinks', false); |
|||
newOption('popupSubpopups', true); |
|||
newOption('popupDragHandle', false /* 'popupTopLinks'*/); |
|||
newOption('popupLazyPreviews', true); |
|||
newOption('popupLazyDownloads', true); |
|||
newOption('popupAllDabsStubs', false); |
|||
newOption('popupDebugging', false); |
|||
newOption('popupAdjustDiffDates', true); |
|||
newOption('popupActiveNavlinks', true); |
|||
newOption('popupModifier', false); // ctrl, shift, alt or meta |
|||
newOption('popupModifierAction', 'enable'); // or 'disable' |
|||
newOption('popupDraggable', true); |
|||
//<NOLITE> |
|||
// Basic options |
|||
// images |
|||
newOption('popupDelay', 0.5); |
|||
newOption('popupImages', true); |
|||
newOption('imagePopupsForImages', true); |
|||
newOption('popupNeverGetThumbs', false); |
|||
newOption('popupStructure', 'shortmenus'); // see later - default for popupStructure is 'original' if simplePopups is true |
|||
//newOption('popupImagesToggleSize', true); |
|||
newOption('popupThumbAction', 'imagepage'); //'sizetoggle'); |
|||
newOption('popupImageSize', 60); |
|||
newOption('popupImageSizeLarge', 200); |
|||
newOption('popupHistoricalLinks', true); |
|||
newOption('popupOnlyArticleLinks', true); |
|||
newOption('removeTitles', true); |
|||
newOption('popupMaxWidth', 350); |
|||
newOption('popupSimplifyMainLink', true); |
|||
newOption('popupAppendRedirNavLinks', true); |
|||
newOption('popupTocLinks', false); |
|||
newOption('popupSubpopups', true); |
|||
newOption('popupDragHandle', false /* 'popupTopLinks'*/); |
|||
newOption('popupLazyPreviews', true); |
|||
newOption('popupLazyDownloads', true); |
|||
newOption('popupAllDabsStubs', false); |
|||
newOption('popupDebugging', false); |
|||
newOption('popupActiveNavlinks', true); |
|||
newOption('popupModifier', false); // ctrl, shift, alt or meta |
|||
newOption('popupModifierAction', 'enable'); // or 'disable' |
|||
newOption('popupDraggable', true); |
|||
newOption('popupReview', false); |
|||
newOption('popupLocale', false); |
|||
newOption('popupDateTimeFormatterOptions', { |
|||
year: 'numeric', |
|||
month: 'long', |
|||
day: 'numeric', |
|||
hour12: false, |
|||
hour: '2-digit', |
|||
minute: '2-digit', |
|||
second: '2-digit', |
|||
}); |
|||
newOption('popupDateFormatterOptions', { |
|||
year: 'numeric', |
|||
month: 'long', |
|||
day: 'numeric', |
|||
}); |
|||
newOption('popupTimeFormatterOptions', { |
|||
hour12: false, |
|||
hour: '2-digit', |
|||
minute: '2-digit', |
|||
second: '2-digit', |
|||
}); |
|||
// redirs, dabs, reversion |
|||
// images |
|||
newOption('popupFixRedirs', false); |
|||
newOption('popupRedirAutoClick', 'wpDiff'); |
|||
newOption('popupFixDabs', false); |
|||
newOption('popupDabsAutoClick', 'wpDiff'); |
|||
newOption('popupRevertSummaryPrompt', false); |
|||
newOption('popupMinorReverts', false); |
|||
newOption('popupRedlinkRemoval', false); |
|||
newOption('popupWatchDisambiggedPages', null); |
|||
newOption('popupWatchRedirredPages', null); |
|||
newOption('popupDabWiktionary', 'last'); |
|||
// navlinks |
|||
// redirs, dabs, reversion |
|||
newOption('popupNavLinks', true); |
|||
newOption('popupNavLinkSeparator', ' ⋅ '); |
|||
newOption('popupLastEditLink', true); |
|||
newOption('popupEditCounterTool', 'soxred'); |
|||
newOption('popupEditCounterUrl', ''); |
|||
newOption('popupExtraUserMenu', ''); |
|||
//</NOLITE> |
|||
newOption('popupRedlinkRemoval', false); |
|||
newOption('popupRedlinkAutoClick', 'wpDiff'); |
|||
newOption('popupWatchDisambiggedPages', null); |
|||
newOption('popupWatchRedirredPages', null); |
|||
newOption('popupDabWiktionary', 'last'); |
|||
// previews etc |
|||
// navlinks |
|||
newOption('popupPreviews', true); |
|||
newOption('popupSummaryData', true); |
|||
newOption('popupMaxPreviewSentences', 5); |
|||
newOption('popupMaxPreviewCharacters', 600); |
|||
newOption('popupLastModified', true); |
|||
newOption('popupPreviewKillTemplates', true); |
|||
newOption('popupPreviewRawTemplates', true); |
|||
newOption('popupPreviewFirstParOnly', true); |
|||
newOption('popupPreviewCutHeadings', true); |
|||
newOption('popupPreviewButton', false); |
|||
newOption('popupPreviewButtonEvent', 'click'); |
|||
//<NOLITE> |
|||
// previews etc |
|||
// diffs |
|||
newOption('popupPreviews', true); |
|||
newOption('popupPreviewDiffs', true); |
|||
newOption('popupDiffMaxLines', 100); |
|||
newOption('popupDiffContextLines', 2); |
|||
newOption('popupDiffContextCharacters', 40); |
|||
newOption('popupDiffDates', true); |
|||
newOption('popupDiffDatePrinter', 'toLocaleString'); |
|||
newOption('popupPreviewFirstParOnly', true); |
|||
newOption('popupPreviewCutHeadings', true); |
|||
newOption('popupPreviewButton', false); |
|||
newOption('popupPreviewButtonEvent', 'click'); |
|||
// edit summaries. God, these are ugly. |
|||
// diffs |
|||
newOption('popupFixDabsSummary', popupString('defaultpopupFixDabsSummary') ); |
|||
newOption('popupPreviewDiffs', true); |
|||
newOption('popupExtendedRevertSummary', popupString('defaultpopupExtendedRevertSummary') ); |
|||
newOption('popupDiffMaxLines', 100); |
|||
newOption('popupTimeOffset', null); |
|||
newOption('popupRevertSummary', popupString('defaultpopupRevertSummary') ); |
|||
newOption('popupDiffContextCharacters', 40); |
|||
newOption('popupRevertToPreviousSummary', popupString('defaultpopupRevertToPreviousSummary') ); |
|||
newOption('popupDiffDates', true); |
|||
newOption('popupQueriedRevertSummary', popupString('defaultpopupQueriedRevertSummary') ); |
|||
newOption('popupDiffDatePrinter', 'toLocaleString'); // no longer in use |
|||
newOption('popupQueriedRevertToPreviousSummary', popupString('defaultpopupQueriedRevertToPreviousSummary') ); |
|||
newOption('popupFixRedirsSummary', popupString('defaultpopupFixRedirsSummary') ); |
|||
newOption('popupRedlinkSummary', popupString('defaultpopupRedlinkSummary') ); |
|||
newOption('popupRmDabLinkSummary', popupString('defaultpopupRmDabLinkSummary') ); |
|||
//</NOLITE> |
|||
// misc |
|||
newOption('popupCookies', false); |
|||
newOption('popupHistoryLimit', 50); |
|||
//<NOLITE> |
|||
newOption('popupFilters', [popupFilterStubDetect, popupFilterDisambigDetect, |
|||
popupFilterPageSize, popupFilterCountLinks, |
|||
popupFilterCountImages, popupFilterCountCategories, |
|||
popupFilterLastModified]); |
|||
newOption('extraPopupFilters', []); |
|||
newOption('popupOnEditSelection', 'cursor'); |
|||
newOption('popupPreviewHistory', true); |
|||
newOption('popupImageLinks', true); |
|||
newOption('popupCategoryMembers', true); |
|||
newOption('popupUserInfo', true); |
|||
newOption('popupHistoryPreviewLimit', 25); |
|||
newOption('popupContribsPreviewLimit',25); |
|||
newOption('popupRevDelUrl', '//en.wikipedia.org/wiki/Wikipedia:Revision_deletion'); |
|||
newOption('popupShowGender', true); |
|||
//</NOLITE> |
|||
// new windows |
|||
// edit summaries. God, these are ugly. |
|||
newOption('popupNewWindows', false); |
|||
newOption('popupReviewedSummary', popupString('defaultpopupReviewedSummary')); |
|||
newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true}); |
|||
newOption('popupFixDabsSummary', popupString('defaultpopupFixDabsSummary')); |
|||
newOption('popupExtendedRevertSummary', popupString('defaultpopupExtendedRevertSummary')); |
|||
newOption('popupRevertSummary', popupString('defaultpopupRevertSummary')); |
|||
newOption('popupRevertToPreviousSummary', popupString('defaultpopupRevertToPreviousSummary')); |
|||
newOption('popupQueriedRevertSummary', popupString('defaultpopupQueriedRevertSummary')); |
|||
newOption( |
|||
'popupQueriedRevertToPreviousSummary', |
|||
popupString('defaultpopupQueriedRevertToPreviousSummary') |
|||
); |
|||
newOption('popupFixRedirsSummary', popupString('defaultpopupFixRedirsSummary')); |
|||
newOption('popupRedlinkSummary', popupString('defaultpopupRedlinkSummary')); |
|||
newOption('popupRmDabLinkSummary', popupString('defaultpopupRmDabLinkSummary')); |
|||
// misc |
|||
newOption('popupHistoryLimit', 50); |
|||
newOption('popupFilters', [ |
|||
popupFilterStubDetect, |
|||
popupFilterDisambigDetect, |
|||
popupFilterPageSize, |
|||
popupFilterCountLinks, |
|||
popupFilterCountImages, |
|||
popupFilterCountCategories, |
|||
popupFilterLastModified, |
|||
popupFilterWikibaseItem, |
|||
]); |
|||
newOption('extraPopupFilters', []); |
|||
newOption('popupOnEditSelection', 'cursor'); |
|||
newOption('popupPreviewHistory', true); |
|||
newOption('popupImageLinks', true); |
|||
newOption('popupCategoryMembers', true); |
|||
newOption('popupUserInfo', true); |
|||
newOption('popupHistoryPreviewLimit', 25); |
|||
newOption('popupContribsPreviewLimit', 25); |
|||
newOption('popupRevDelUrl', '//en.wikipedia.org/wiki/Wikipedia:Revision_deletion'); |
|||
newOption('popupShowGender', true); |
|||
// regexps |
|||
// new windows |
|||
newOption('popupDabRegexp', '(\\{\\{\\s*disambig(?!uation needed)|disambig(uation|)\\s*\\}\\}|disamb\\s*\\}\\}|dab\\s*\\}\\})|\\{\\{\\s*(((geo|hn|road?|school|number)dis)|[234][lc][acw]|(road|ship)index)(\\s*[|][^}]*)?\\s*[}][}]|is a .*disambiguation.*page'); |
|||
newOption('popupNewWindows', false); |
|||
newOption('popupAnchorRegexp', 'anchors?'); //how to identify an anchors template |
|||
newOption('popupLinksNewWindow', { lastContrib: true, sinceMe: true }); |
|||
newOption('popupStubRegexp', '(sect)?stub[}][}]|This .*-related article is a .*stub'); |
|||
newOption('popupImageVarsRegexp', 'image|image_(?:file|skyline|name|flag|seal)|cover|badge|logo'); |
|||
} |
|||
// ENDFILE: options.js |
|||
// STARTFILE: strings.js |
|||
//<NOLITE> |
|||
////////////////////////////////////////////////// |
|||
// Translatable strings |
|||
////////////////////////////////////////////////// |
|||
// |
|||
// See instructions at |
|||
// http://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation |
|||
pg.string = { |
|||
// regexps |
|||
///////////////////////////////////// |
|||
newOption( |
|||
// summary data, searching etc. |
|||
'popupDabRegexp', |
|||
///////////////////////////////////// |
|||
'disambiguation\\}\\}|\\{\\{\\s*(d(ab|isamb(ig(uation)?)?)|(((geo|hn|road?|school|number)dis)|[234][lc][acw]|(road|ship)index))\\s*(\\|[^}]*)?\\}\\}|is a .*disambiguation.*page' |
|||
'article': 'article', |
|||
); |
|||
'category': 'category', |
|||
newOption('popupAnchorRegexp', 'anchors?'); //how to identify an anchors template |
|||
'categories': 'categories', |
|||
newOption('popupStubRegexp', '(sect)?stub[}][}]|This .*-related article is a .*stub'); |
|||
'image': 'image', |
|||
newOption( |
|||
'images': 'images', |
|||
'popupImageVarsRegexp', |
|||
'stub': 'stub', |
|||
'image|image_(?:file|skyline|name|flag|seal)|cover|badge|logo' |
|||
'section stub': 'section stub', |
|||
); |
|||
'Empty page': 'Empty page', |
|||
} |
|||
'kB': 'kB', |
|||
// ENDFILE: options.js |
|||
'bytes': 'bytes', |
|||
'day': 'day', |
|||
'days': 'days', |
|||
'hour': 'hour', |
|||
'hours': 'hours', |
|||
'minute': 'minute', |
|||
'minutes': 'minutes', |
|||
'second': 'second', |
|||
'seconds': 'seconds', |
|||
'week': 'week', |
|||
'weeks': 'weeks', |
|||
'search': 'search', |
|||
'SearchHint': 'Find English Wikipedia articles containing %s', |
|||
'web': 'web', |
|||
'global': 'global', |
|||
'globalSearchHint': 'Search across Wikipedias in different languages for %s', |
|||
'googleSearchHint': 'Google for %s', |
|||
///////////////////////////////////// |
|||
// article-related actions and info |
|||
// (some actions also apply to user pages) |
|||
///////////////////////////////////// |
|||
'actions': 'actions', ///// view articles and view talk |
|||
'popupsMenu': 'popups', |
|||
'togglePreviewsHint': 'Toggle preview generation in popups on this page', |
|||
'enable previews': 'enable previews', |
|||
'disable previews': 'disable previews', |
|||
'toggle previews': 'toggle previews', |
|||
'show preview': 'show preview', |
|||
'reset': 'reset', |
|||
'more...': 'more...', |
|||
'disable': 'disable popups', |
|||
'disablePopupsHint': 'Disable popups on this page. Reload page to re-enable.', |
|||
'historyfeedHint': 'RSS feed of recent changes to this page', |
|||
'purgePopupsHint': 'Reset popups, clearing all cached popup data.', |
|||
'PopupsHint': 'Reset popups, clearing all cached popup data.', |
|||
'spacebar': 'space', |
|||
'view': 'view', |
|||
'view article': 'view article', |
|||
'viewHint': 'Go to %s', |
|||
'talk': 'talk', |
|||
'talk page': 'talk page', |
|||
'this revision': 'this revision', |
|||
'revision %s of %s': 'revision %s of %s', |
|||
'Revision %s of %s': 'Revision %s of %s', |
|||
'the revision prior to revision %s of %s': 'the revision prior to revision %s of %s', |
|||
'Toggle image size': 'Click to toggle image size', |
|||
'del': 'del', ///// delete, protect, move |
|||
'delete': 'delete', |
|||
'deleteHint': 'Delete %s', |
|||
'undeleteShort': 'un', |
|||
'UndeleteHint': 'Show the deletion history for %s', |
|||
'protect': 'protect', |
|||
'protectHint': 'Restrict editing rights to %s', |
|||
'unprotectShort': 'un', |
|||
'unprotectHint': 'Allow %s to be edited by anyone again', |
|||
'send thanks': 'send thanks', |
|||
'ThanksHint': 'Send a thank you notification to this user', |
|||
'move': 'move', |
|||
'move page': 'move page', |
|||
'MovepageHint': 'Change the title of %s', |
|||
'edit': 'edit', ///// edit articles and talk |
|||
'edit article': 'edit article', |
|||
'editHint': 'Change the content of %s', |
|||
'edit talk': 'edit talk', |
|||
'new': 'new', |
|||
'new topic': 'new topic', |
|||
'newSectionHint': 'Start a new section on %s', |
|||
'null edit': 'null edit', |
|||
'nullEditHint': 'Submit an edit to %s, making no changes ', |
|||
'hist': 'hist', ///// history, diffs, editors, related |
|||
'history': 'history', |
|||
'historyHint': 'List the changes made to %s', |
|||
'last': 'prev', // For labelling the previous revision in history pages; the key is "last" for backwards compatibility |
|||
'lastEdit': 'lastEdit', |
|||
'mark patrolled': 'mark patrolled', |
|||
'markpatrolledHint': 'Mark this edit as patrolled', |
|||
'show last edit': 'most recent edit', |
|||
'Show the last edit': 'Show the effects of the most recent change', |
|||
'lastContrib': 'lastContrib', |
|||
'last set of edits': 'latest edits', |
|||
'lastContribHint': 'Show the net effect of changes made by the last editor', |
|||
'cur': 'cur', |
|||
'diffCur': 'diffCur', |
|||
'Show changes since revision %s': 'Show changes since revision %s', |
|||
'%s old': '%s old', // as in 4 weeks old |
|||
'oldEdit': 'oldEdit', |
|||
'purge': 'purge', |
|||
'purgeHint': 'Demand a fresh copy of %s', |
|||
'raw': 'source', |
|||
'rawHint': 'Download the source of %s', |
|||
'render': 'simple', |
|||
'renderHint': 'Show a plain HTML version of %s', |
|||
'Show the edit made to get revision': 'Show the edit made to get revision', |
|||
'sinceMe': 'sinceMe', |
|||
'changes since mine': 'diff my edit', |
|||
'sinceMeHint': 'Show changes since my last edit', |
|||
'Couldn\'t find an edit by %s\nin the last %s edits to\n%s': 'Couldn\'t find an edit by %s\nin the last %s edits to\n%s', |
|||
'eds': 'eds', |
|||
'editors': 'editors', |
|||
'editorListHint': 'List the users who have edited %s', |
|||
'related': 'related', |
|||
'relatedChanges': 'relatedChanges', |
|||
'related changes': 'related changes', |
|||
'RecentchangeslinkedHint': 'Show changes in articles related to %s', |
|||
'editOld': 'editOld', ///// edit old version, or revert |
|||
'rv': 'rv', |
|||
'revert': 'revert', |
|||
'revertHint': 'Revert to %s', |
|||
'defaultpopupRedlinkSummary': 'Removing link to empty page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupFixDabsSummary': 'Disambiguate [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupFixRedirsSummary': 'Redirect bypass from [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupExtendedRevertSummary': 'Revert to revision dated %s by %s, oldid %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupRevertToPreviousSummary': 'Revert to the revision prior to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupRevertSummary': 'Revert to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupQueriedRevertToPreviousSummary': 'Revert to the revision prior to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupQueriedRevertSummary': 'Revert to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'defaultpopupRmDabLinkSummary': 'Remove link to dab page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
'Redirects': 'Redirects', // as in Redirects to ... |
|||
' to ': ' to ', // as in Redirects to ... |
|||
'Bypass redirect': 'Bypass redirect', |
|||
'Fix this redirect': 'Fix this redirect', |
|||
'disambig': 'disambig', ///// add or remove dab etc. |
|||
'disambigHint': 'Disambiguate this link to [[%s]]', |
|||
'Click to disambiguate this link to:': 'Click to disambiguate this link to:', |
|||
'remove this link': 'remove this link', |
|||
'remove all links to this page from this article': 'remove all links to this page from this article', |
|||
'remove all links to this disambig page from this article': 'remove all links to this disambig page from this article', |
|||
'mainlink': 'mainlink', ///// links, watch, unwatch |
|||
'wikiLink': 'wikiLink', |
|||
'wikiLinks': 'wikiLinks', |
|||
'links here': 'links here', |
|||
'whatLinksHere': 'whatLinksHere', |
|||
'what links here': 'what links here', |
|||
'WhatlinkshereHint': 'List the pages that are hyperlinked to %s', |
|||
'unwatchShort': 'un', |
|||
'watchThingy': 'watch', // called watchThingy because {}.watch is a function |
|||
'watchHint': 'Add %s to my watchlist', |
|||
'unwatchHint': 'Remove %s from my watchlist', |
|||
'Only found one editor: %s made %s edits': 'Only found one editor: %s made %s edits', |
|||
'%s seems to be the last editor to the page %s': '%s seems to be the last editor to the page %s', |
|||
'rss': 'rss', |
|||
///////////////////////////////////// |
|||
// diff previews |
|||
///////////////////////////////////// |
|||
'Diff truncated for performance reasons': 'Diff truncated for performance reasons', |
|||
'Old revision': 'Old revision', |
|||
'New revision': 'New revision', |
|||
'Something went wrong :-(': 'Something went wrong :-(', |
|||
'Empty revision, maybe non-existent': 'Empty revision, maybe non-existent', |
|||
'Unknown date': 'Unknown date', |
|||
///////////////////////////////////// |
|||
// other special previews |
|||
///////////////////////////////////// |
|||
'Empty category': 'Empty category', |
|||
'Category members (%s shown)': 'Category members (%s shown)', |
|||
'No image links found': 'No image links found', |
|||
'File links': 'File links', |
|||
'No image found': 'No image found', |
|||
'Image from Commons': 'Image from Commons', |
|||
'Description page': 'Description page', |
|||
'Alt text:': 'Alt text:', |
|||
'revdel':'Hidden revision', |
|||
///////////////////////////////////// |
|||
// user-related actions and info |
|||
///////////////////////////////////// |
|||
'user': 'user', ///// user page, talk, email, space |
|||
'user page': 'user page', |
|||
'user talk': 'user talk', |
|||
'edit user talk': 'edit user talk', |
|||
'leave comment': 'leave comment', |
|||
'email': 'email', |
|||
'email user': 'email user', |
|||
'EmailuserHint': 'Send an email to %s', |
|||
'space': 'space', // short form for userSpace link |
|||
'PrefixIndexHint': 'Show pages in the userspace of %s', |
|||
'count': 'count', ///// contributions, log |
|||
'edit counter': 'edit counter', |
|||
'editCounterLinkHint': 'Count the contributions made by %s', |
|||
'contribs': 'contribs', |
|||
'contributions': 'contributions', |
|||
'deletedContribs': 'deleted contributions', |
|||
'DeletedcontributionsHint': 'List deleted edits made by %s', |
|||
'ContributionsHint': 'List the contributions made by %s', |
|||
'log': 'log', |
|||
'user log': 'user log', |
|||
'userLogHint': 'Show %s\'s user log', |
|||
'arin': 'ARIN lookup', ///// ARIN lookup, block user or IP |
|||
'Look up %s in ARIN whois database': 'Look up %s in the ARIN whois database', |
|||
'unblockShort': 'un', |
|||
'block': 'block', |
|||
'block user': 'block user', |
|||
'IpblocklistHint': 'Unblock %s', |
|||
'BlockipHint': 'Prevent %s from editing', |
|||
'block log': 'block log', |
|||
'blockLogHint': 'Show the block log for %s', |
|||
'protectLogHint': 'Show the protection log for %s', |
|||
'pageLogHint': 'Show the page log for %s', |
|||
'deleteLogHint': 'Show the deletion log for %s', |
|||
'Invalid %s %s': 'The option %s is invalid: %s', |
|||
'No backlinks found': 'No backlinks found', |
|||
' and more': ' and more', |
|||
'undo': 'undo', |
|||
'undoHint': 'undo this edit', |
|||
'Download preview data': 'Download preview data', |
|||
'Invalid or IP user': 'Invalid or IP user', |
|||
'Not a registered username': 'Not a registered username', |
|||
'BLOCKED': 'BLOCKED', |
|||
' edits since: ': ' edits since: ', |
|||
'last edit on ': 'last edit on ', |
|||
///////////////////////////////////// |
|||
// Autoediting |
|||
///////////////////////////////////// |
|||
'Enter a non-empty edit summary or press cancel to abort': 'Enter a non-empty edit summary or press cancel to abort', |
|||
'Failed to get revision information, please edit manually.\n\n': 'Failed to get revision information, please edit manually.\n\n', |
|||
'The %s button has been automatically clicked. Please wait for the next page to load.': 'The %s button has been automatically clicked. Please wait for the next page to load.', |
|||
'Could not find button %s. Please check the settings in your javascript file.': 'Could not find button %s. Please check the settings in your javascript file.', |
|||
///////////////////////////////////// |
|||
// Popups setup |
|||
///////////////////////////////////// |
|||
'Open full-size image': 'Open full-size image', |
|||
'zxy': 'zxy', |
|||
'autoedit_version': 'np20140416' |
|||
}; |
|||
// STARTFILE: strings.js |
|||
////////////////////////////////////////////////// |
|||
// Translatable strings |
|||
////////////////////////////////////////////////// |
|||
// |
|||
// See instructions at |
|||
// https://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation |
|||
function popupString(str) { |
|||
pg.string = { |
|||
if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { return popupStrings[str]; } |
|||
///////////////////////////////////// |
|||
if (pg.string[str]) { return pg.string[str]; } |
|||
// summary data, searching etc. |
|||
return str; |
|||
///////////////////////////////////// |
|||
} |
|||
article: 'article', |
|||
category: 'category', |
|||
categories: 'categories', |
|||
image: 'image', |
|||
images: 'images', |
|||
stub: 'stub', |
|||
'section stub': 'section stub', |
|||
'Empty page': 'Empty page', |
|||
kB: 'kB', |
|||
bytes: 'bytes', |
|||
day: 'day', |
|||
days: 'days', |
|||
hour: 'hour', |
|||
hours: 'hours', |
|||
minute: 'minute', |
|||
minutes: 'minutes', |
|||
second: 'second', |
|||
seconds: 'seconds', |
|||
week: 'week', |
|||
weeks: 'weeks', |
|||
search: 'search', |
|||
SearchHint: 'Find English Wikipedia articles containing %s', |
|||
web: 'web', |
|||
global: 'global', |
|||
globalSearchHint: 'Search across Wikipedias in different languages for %s', |
|||
googleSearchHint: 'Google for %s', |
|||
///////////////////////////////////// |
|||
// article-related actions and info |
|||
// (some actions also apply to user pages) |
|||
///////////////////////////////////// |
|||
actions: 'actions', ///// view articles and view talk |
|||
popupsMenu: 'popups', |
|||
togglePreviewsHint: 'Toggle preview generation in popups on this page', |
|||
'enable previews': 'enable previews', |
|||
'disable previews': 'disable previews', |
|||
'toggle previews': 'toggle previews', |
|||
'show preview': 'show preview', |
|||
reset: 'reset', |
|||
'more...': 'more...', |
|||
disable: 'disable popups', |
|||
disablePopupsHint: 'Disable popups on this page. Reload page to re-enable.', |
|||
historyfeedHint: 'RSS feed of recent changes to this page', |
|||
purgePopupsHint: 'Reset popups, clearing all cached popup data.', |
|||
PopupsHint: 'Reset popups, clearing all cached popup data.', |
|||
spacebar: 'space', |
|||
view: 'view', |
|||
'view article': 'view article', |
|||
viewHint: 'Go to %s', |
|||
talk: 'talk', |
|||
'talk page': 'talk page', |
|||
'this revision': 'this revision', |
|||
'revision %s of %s': 'revision %s of %s', |
|||
'Revision %s of %s': 'Revision %s of %s', |
|||
'the revision prior to revision %s of %s': 'the revision prior to revision %s of %s', |
|||
'Toggle image size': 'Click to toggle image size', |
|||
del: 'del', ///// delete, protect, move |
|||
delete: 'delete', |
|||
deleteHint: 'Delete %s', |
|||
undeleteShort: 'un', |
|||
UndeleteHint: 'Show the deletion history for %s', |
|||
protect: 'protect', |
|||
protectHint: 'Restrict editing rights to %s', |
|||
unprotectShort: 'un', |
|||
unprotectHint: 'Allow %s to be edited by anyone again', |
|||
'send thanks': 'send thanks', |
|||
ThanksHint: 'Send a thank you notification to this user', |
|||
move: 'move', |
|||
'move page': 'move page', |
|||
MovepageHint: 'Change the title of %s', |
|||
edit: 'edit', ///// edit articles and talk |
|||
'edit article': 'edit article', |
|||
editHint: 'Change the content of %s', |
|||
'edit talk': 'edit talk', |
|||
new: 'new', |
|||
'new topic': 'new topic', |
|||
newSectionHint: 'Start a new section on %s', |
|||
'null edit': 'null edit', |
|||
nullEditHint: 'Submit an edit to %s, making no changes ', |
|||
hist: 'hist', ///// history, diffs, editors, related |
|||
history: 'history', |
|||
historyHint: 'List the changes made to %s', |
|||
'History preview failed': 'History preview failed :-(', |
|||
last: 'prev', // For labelling the previous revision in history pages; the key is "last" for backwards compatibility |
|||
lastEdit: 'lastEdit', |
|||
'mark patrolled': 'mark patrolled', |
|||
markpatrolledHint: 'Mark this edit as patrolled', |
|||
'Could not marked this edit as patrolled': 'Could not marked this edit as patrolled', |
|||
'show last edit': 'most recent edit', |
|||
'Show the last edit': 'Show the effects of the most recent change', |
|||
lastContrib: 'lastContrib', |
|||
'last set of edits': 'latest edits', |
|||
lastContribHint: 'Show the net effect of changes made by the last editor', |
|||
cur: 'cur', |
|||
diffCur: 'diffCur', |
|||
'Show changes since revision %s': 'Show changes since revision %s', |
|||
'%s old': '%s old', // as in 4 weeks old |
|||
oldEdit: 'oldEdit', |
|||
purge: 'purge', |
|||
purgeHint: 'Demand a fresh copy of %s', |
|||
raw: 'source', |
|||
rawHint: 'Download the source of %s', |
|||
render: 'simple', |
|||
renderHint: 'Show a plain HTML version of %s', |
|||
'Show the edit made to get revision': 'Show the edit made to get revision', |
|||
sinceMe: 'sinceMe', |
|||
'changes since mine': 'diff my edit', |
|||
sinceMeHint: 'Show changes since my last edit', |
|||
"Couldn't find an edit by %s\nin the last %s edits to\n%s": |
|||
"Couldn't find an edit by %s\nin the last %s edits to\n%s", |
|||
eds: 'eds', |
|||
editors: 'editors', |
|||
editorListHint: 'List the users who have edited %s', |
|||
related: 'related', |
|||
relatedChanges: 'relatedChanges', |
|||
'related changes': 'related changes', |
|||
RecentchangeslinkedHint: 'Show changes in articles related to %s', |
|||
editOld: 'editOld', ///// edit old version, or revert |
|||
rv: 'rv', |
|||
revert: 'revert', |
|||
revertHint: 'Revert to %s', |
|||
defaultpopupReviewedSummary: |
|||
'Accepted by reviewing the [[Special:diff/%s/%s|difference]] between this version and previously accepted version using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupRedlinkSummary: |
|||
'Removing link to empty page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupFixDabsSummary: |
|||
'Disambiguate [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupFixRedirsSummary: |
|||
'Redirect bypass from [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupExtendedRevertSummary: |
|||
'Revert to revision dated %s by %s, oldid %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupRevertToPreviousSummary: |
|||
'Revert to the revision prior to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupRevertSummary: |
|||
'Revert to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupQueriedRevertToPreviousSummary: |
|||
'Revert to the revision prior to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupQueriedRevertSummary: |
|||
'Revert to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
defaultpopupRmDabLinkSummary: |
|||
'Remove link to dab page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', |
|||
Redirects: 'Redirects', // as in Redirects to ... |
|||
' to ': ' to ', // as in Redirects to ... |
|||
'Bypass redirect': 'Bypass redirect', |
|||
'Fix this redirect': 'Fix this redirect', |
|||
disambig: 'disambig', ///// add or remove dab etc. |
|||
disambigHint: 'Disambiguate this link to [[%s]]', |
|||
'Click to disambiguate this link to:': 'Click to disambiguate this link to:', |
|||
'remove this link': 'remove this link', |
|||
'remove all links to this page from this article': |
|||
'remove all links to this page from this article', |
|||
'remove all links to this disambig page from this article': |
|||
'remove all links to this disambig page from this article', |
|||
mainlink: 'mainlink', ///// links, watch, unwatch |
|||
wikiLink: 'wikiLink', |
|||
wikiLinks: 'wikiLinks', |
|||
'links here': 'links here', |
|||
whatLinksHere: 'whatLinksHere', |
|||
'what links here': 'what links here', |
|||
WhatlinkshereHint: 'List the pages that are hyperlinked to %s', |
|||
unwatchShort: 'un', |
|||
watchThingy: 'watch', // called watchThingy because {}.watch is a function |
|||
watchHint: 'Add %s to my watchlist', |
|||
unwatchHint: 'Remove %s from my watchlist', |
|||
'Only found one editor: %s made %s edits': 'Only found one editor: %s made %s edits', |
|||
'%s seems to be the last editor to the page %s': |
|||
'%s seems to be the last editor to the page %s', |
|||
rss: 'rss', |
|||
///////////////////////////////////// |
|||
// diff previews |
|||
///////////////////////////////////// |
|||
'Diff truncated for performance reasons': 'Diff truncated for performance reasons', |
|||
'Old revision': 'Old revision', |
|||
'New revision': 'New revision', |
|||
'Something went wrong :-(': 'Something went wrong :-(', |
|||
'Empty revision, maybe non-existent': 'Empty revision, maybe non-existent', |
|||
'Unknown date': 'Unknown date', |
|||
///////////////////////////////////// |
|||
// other special previews |
|||
///////////////////////////////////// |
|||
'Empty category': 'Empty category', |
|||
'Category members (%s shown)': 'Category members (%s shown)', |
|||
'No image links found': 'No image links found', |
|||
'File links': 'File links', |
|||
'No image found': 'No image found', |
|||
'Image from Commons': 'Image from Commons', |
|||
'Description page': 'Description page', |
|||
'Alt text:': 'Alt text:', |
|||
revdel: 'Hidden revision', |
|||
///////////////////////////////////// |
|||
// user-related actions and info |
|||
///////////////////////////////////// |
|||
user: 'user', ///// user page, talk, email, space |
|||
'user page': 'user page', |
|||
'user talk': 'user talk', |
|||
'edit user talk': 'edit user talk', |
|||
'leave comment': 'leave comment', |
|||
email: 'email', |
|||
'email user': 'email user', |
|||
EmailuserHint: 'Send an email to %s', |
|||
space: 'space', // short form for userSpace link |
|||
PrefixIndexHint: 'Show pages in the userspace of %s', |
|||
count: 'count', ///// contributions, log |
|||
'edit counter': 'edit counter', |
|||
editCounterLinkHint: 'Count the contributions made by %s', |
|||
contribs: 'contribs', |
|||
contributions: 'contributions', |
|||
deletedContribs: 'deleted contributions', |
|||
DeletedcontributionsHint: 'List deleted edits made by %s', |
|||
ContributionsHint: 'List the contributions made by %s', |
|||
log: 'log', |
|||
'user log': 'user log', |
|||
userLogHint: "Show %s's user log", |
|||
arin: 'ARIN lookup', ///// ARIN lookup, block user or IP |
|||
'Look up %s in ARIN whois database': 'Look up %s in the ARIN whois database', |
|||
unblockShort: 'un', |
|||
block: 'block', |
|||
'block user': 'block user', |
|||
IpblocklistHint: 'Unblock %s', |
|||
BlockipHint: 'Prevent %s from editing', |
|||
'block log': 'block log', |
|||
blockLogHint: 'Show the block log for %s', |
|||
protectLogHint: 'Show the protection log for %s', |
|||
pageLogHint: 'Show the page log for %s', |
|||
deleteLogHint: 'Show the deletion log for %s', |
|||
'Invalid %s %s': 'The option %s is invalid: %s', |
|||
'No backlinks found': 'No backlinks found', |
|||
' and more': ' and more', |
|||
undo: 'undo', |
|||
undoHint: 'undo this edit', |
|||
'Download preview data': 'Download preview data', |
|||
'Invalid or IP user': 'Invalid or IP user', |
|||
'Not a registered username': 'Not a registered username', |
|||
BLOCKED: 'BLOCKED', |
|||
'Has blocks': 'Has blocks', |
|||
' edits since: ': ' edits since: ', |
|||
'last edit on ': 'last edit on ', |
|||
'he/him': 'he/him', |
|||
'she/her': 'she/her', |
|||
///////////////////////////////////// |
|||
// Autoediting |
|||
///////////////////////////////////// |
|||
'Enter a non-empty edit summary or press cancel to abort': |
|||
'Enter a non-empty edit summary or press cancel to abort', |
|||
'Failed to get revision information, please edit manually.\n\n': |
|||
'Failed to get revision information, please edit manually.\n\n', |
|||
'The %s button has been automatically clicked. Please wait for the next page to load.': |
|||
'The %s button has been automatically clicked. Please wait for the next page to load.', |
|||
'Could not find button %s. Please check the settings in your javascript file.': |
|||
'Could not find button %s. Please check the settings in your javascript file.', |
|||
///////////////////////////////////// |
|||
// Popups setup |
|||
///////////////////////////////////// |
|||
'Open full-size image': 'Open full-size image', |
|||
zxy: 'zxy', |
|||
autoedit_version: 'np20140416', |
|||
}; |
|||
function popupString(str) { |
|||
if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { |
|||
return popupStrings[str]; |
|||
} |
|||
if (pg.string[str]) { |
|||
return pg.string[str]; |
|||
} |
|||
return str; |
|||
} |
|||
function tprintf(str,subs) { |
|||
if (typeof subs != typeof []) { subs = [subs]; } |
|||
return simplePrintf(popupString(str), subs); |
|||
subs = [subs]; |
|||
} |
|||
return simplePrintf(popupString(str), subs); |
|||
} |
|||
//</NOLITE> |
|||
// ENDFILE: strings.js |
|||
// ENDFILE: strings.js |
|||
// STARTFILE: run.js |
|||
//////////////////////////////////////////////////////////////////// |
|||
// Run things |
|||
//////////////////////////////////////////////////////////////////// |
|||
// STARTFILE: run.js |
|||
//////////////////////////////////////////////////////////////////// |
|||
// Run things |
|||
//////////////////////////////////////////////////////////////////// |
|||
// For some reason popups requires a fully loaded page jQuery.ready(...) causes problems for some. |
|||
// The old addOnloadHook did something similar to the below |
|||
if (document.readyState=="complete") |
|||
autoEdit(); //will setup popups |
|||
else |
|||
} |
|||
$( window ).on( 'load', autoEdit ); |
|||
//will setup popups |
|||
else { |
|||
$(window).on('load', autoEdit); |
|||
} |
|||
// Support for MediaWiki's live preview, VisualEditor's saves and Echo's flyout. |
|||
(function () { |
|||
var once = true; |
|||
function dynamicContentHandler($content) { |
|||
// Try to detect the hook fired on initial page load and disregard |
|||
// it, we already hook to onload (possibly to different parts of |
|||
// page - it's configurable) and running twice might be bad. Ugly… |
|||
if ($content.attr('id') == 'mw-content-text') { |
|||
if (once) { |
|||
once = false; |
|||
return; |
|||
} |
|||
} |
|||
// Support for MediaWiki's live preview, VisualEditor's saves and Echo's flyout. |
|||
function registerHooksForVisibleNavpops() { |
|||
( function () { |
|||
for (var i = 0; pg.current.links && i < pg.current.links.length; ++i) { |
|||
var once = true; |
|||
var navpop = pg.current.links[i].navpopup; |
|||
function dynamicContentHandler( $content ) { |
|||
if (!navpop || !navpop.isVisible()) { |
|||
// Try to detect the hook fired on initial page load and disregard |
|||
continue; |
|||
// it, we already hook to onload (possibly to different parts of |
|||
} |
|||
// page - it's configurable) and running twice might be bad. Ugly… |
|||
if ( $content.attr( 'id' ) == 'mw-content-text' ) { |
|||
Navpopup.tracker.addHook(posCheckerHook(navpop)); |
|||
if ( once ) { |
|||
} |
|||
once = false; |
|||
return; |
|||
} |
} |
||
} |
|||
function doIt () { |
|||
$content.each( function () { |
|||
registerHooksForVisibleNavpops(); |
|||
this.ranSetupTooltipsAlready = false; |
|||
$content.each(function () { |
|||
setupTooltips( this ); |
|||
this.ranSetupTooltipsAlready = false; |
|||
} ); |
|||
setupTooltips(this); |
|||
} |
|||
} |
|||
if ( !setupPopups.completed ) { |
|||
setupPopups(doIt); |
|||
setupPopups( doIt ); |
|||
} else { |
|||
doIt(); |
|||
} |
} |
||
} |
|||
// This hook is also fired after page load. |
|||
mw.hook( 'wikipage.content' ).add( dynamicContentHandler ); |
|||
mw.hook( 'ext.echo.overlay.beforeShowingOverlay' ).add( function($overlay){ |
|||
dynamicContentHandler( $overlay.find(".mw-echo-state") ); |
|||
}); |
|||
} )(); |
|||
mw.hook('ext.echo.overlay.beforeShowingOverlay').add(function ($overlay) { |
|||
dynamicContentHandler($overlay.find('.mw-echo-state')); |
|||
}); |
|||
}()); |
|||
}); |
}); |
||
// ENDFILE: run.js |
// ENDFILE: run.js |