User:Lupin/popupstest.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | Documentation for this user script can be added at User:Lupin/popupstest. |
// CONTENTS
// Utility functions
// Popup stuff
// global variables
// html generation
// downloading
// link generation
// manipulation functions
// tests
// actions
// thingies
////////////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////////////
function time() {
var d=new Date();
return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() +
'.' + (d.getTime() % 1000);
};
var gMsg='';
function log(x) { if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; };
function myalert(x) { return alert(time()+'\n'+ x); };
// eg sourceJS('http://www.bosrup.com/web/overlib/overlib.js');
function sourceJS(url) {
var str='<script type="text/javascript" src="';
str += url;
str += '"></script>';
return document.write(str);
};
// eg sourceWikipediaJS('wiki.riteme.site', 'User:Lupin/overlib.js');
function sourceWikipediaJS(wiki, name) {
var url='http://' + wiki + '/w/index.php?title=';
url += name;
url += '&action=raw&ctype=text/javascript&dontcountme=s';
return sourceJS(url);
};
// eg sourceLupinJS('overlib');
function sourceLupinJS(name) {
return sourceWikipediaJS('wiki.riteme.site', 'User:Lupin/'+name + '.js');
};
////////////////////////////////////////////////////////////////////
// Popup stuff
////////////////////////////////////////////////////////////////////
sourceLupinJS('livepreview');
sourceLupinJS('overlib');
sourceLupinJS('md5-2.2alpha');
// this shouldn't be needed. maybe my cache needs purging...
function md5_hex(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); };
//////////////////////
// GLOBAL VARIABLES //
//////////////////////
// regexes
var exceptions=/((title=|\/)Special:|section=[0-9])/ ;
var contributions=/(title=|\/)Special:Contributions(&target=|\/|\/User:)(.*)/ ;
var emailuser=/(title=|\/)Special:Emailuser(&target=|\/|\/User:)(.*)/ ;
var talk=/Talk:/i ;
var imageRegex= /(^|\[\[)image: *([^|\]]*[^|\] ]) */img ;
var imageRegexBracketCount = 2;
var categoryRegex= /\[\[category: *([^|\]]*[^|\] ]) */i ;
var categoryRegexBracketCount = 1;
var stubRegex= /stub[}][}]|This .*-related article is a .*stub/im ;
var disambigRegex= /[{][{]disambig|is a .*disambiguation.*page/im ;
var re;
var splitLoc=window.location.href.split('/');
var thisWiki=splitLoc[2];
var protocol=splitLoc[0].split(':')[0];
var titletail='/w/index.php?title=';
// we're not set up for interwiki stuff yet - only affect en, commons
// and wiktionary links
if (thisWiki=='commons.wikimedia.org') {
re=/[^:]*:\/\/commons\.wikimedia\.org\/w(iki\/|\/index\.php\?title=)([^&]*)/ ;
} else if (thisWiki=='en.wiktionary.org') {
re=
/[^:]*:\/\/en\.wiktionary\.org\/w(iki\/|\/index\.php\?title=)([^&]*)/ ;
} else {
re=/[^:]*:\/\/en\.wikipedia\.org\/w(iki\/|\/index\.php\?title=)([^&]*)/ ;
}
var titlebase=protocol+'://'+thisWiki+titletail;
var wikibase=protocol+'://'+thisWiki+'/wiki/';
var imageSources=new Array ();
imageSources.push(
{active: false, wiki: thisWiki, thumb: true, width: popupImageSize},
{active: false, wiki: thisWiki, thumb: true, width: 180}, // default
{active: false, wiki: thisWiki, thumb: true, width: 120}, // gallery
{active: false, wiki: thisWiki, thumb: true, width: 200}, // common?
{active: false, wiki: thisWiki, thumb: true, width: 210},
{active: false, wiki: thisWiki, thumb: true, width: 230},
{active: false, wiki: thisWiki, thumb: true, width: 250}, // common?
{active: false, wiki: thisWiki, thumb: true, width: 300},
{active: false, wiki: thisWiki, thumb: false, width: 0} // no comma
);
if (thisWiki!='commons.wikimedia.org') {
imageSources.push(
{active: false, wiki: 'commons.wikimedia.org',
thumb: true, width: popupImageSize},
{active: false, wiki: 'commons.wikimedia.org',
thumb: true, width: 180},
{active: false, wiki: 'commons.wikimedia.org',
thumb: true, width: 120},
{active: false, wiki: 'commons.wikimedia.org',
thumb: false, width: 0} // no trailing comma
);
}
// downloading images are put here
var imageArray=new Array();
// page caching
var gCachedPages = new Array ();
var gImageCache = new Array();
// FIXME what is this for?
var gImage=null; // global for image
// check to see if images are done with this timer
var popupImageTimer=null;
// misc debug messages
var popupDebug=null;
// These are for checkImages()
var counter=0;
var checkImagesTimer=null;
var loopcounter=0;
// ids change with each popup: popupImage0, popupImage1 etc
var popupImageId=0;
var kateBase='http://kohl.wikimedia.org/~kate/cgi-bin/count_edits'
+ '?dbname=enwiki&user='
// for myDecodeURI
var decodeExtras = new Array ();
decodeExtras.push (
{from: '%2C', to: ',' },
{from: '_', to: ' ' },
{from: '%26', to: '&' } // no ,
);
// for setPopupHTML - needed for timers and stuff
var popupHTMLTimers=new Array();
var popupHTMLLoopFunctions = new Array();
// FIXME - eliminate this
var redirCount=0;
var popupImagesToggleSize=true;
var popupImageSize=60;
// user-settable parameters and defaults
if (typeof popupDelay == 'undefined') { var popupDelay=null; }
var dpopupDelay=0.5;
if (typeof popupFgColor == 'undefined') { var popupFgColor=null; }
var dpopupFgColor='#CCCCFF';
if (typeof popupBgColor == 'undefined') { var popupBgColor=null; }
var dpopupBgColor='#333399';
if (typeof removeTitles == 'undefined') { var removeTitles=null; }
var dremoveTitles=true;
if (typeof imagePopupsForImages == 'undefined') { var imagePopupsForImages=null; }
var dimagePopupsForImages=true;
if (typeof extraPageInfo == 'undefined') { var extraPageInfo = null; }
var dextraPageInfo=true;
if (typeof simplePopups == 'undefined') { var simplePopups=null; }
var dsimplePopups = false;
if (typeof downloadImages == 'undefined') { var downloadImages=null; }
var ddownloadImages=true;
if (typeof popupPreviews == 'undefined') { var popupPreviews=null; }
var dpopupPreviews=true;
/////////////////////
// HTML GENERATION //
/////////////////////
// generate html for popup image
// <a id="popupImageLinkn"><img id="popupImagen">
// where n=popupImageId
function imageHTML(article) {
var ret='';
popupImageId++;
ret+='<a id="popupImageLink' + popupImageId + '">';
ret += '<img ' + // src="' + imgurl + '" ' +
'width=' + popupImageSize +
' align="right" valign="top" + id="popupImage' + popupImageId
+ '" style="display: none;"></img>';
ret+='</a>';
return ret;
};
function isInToc(a) {
var obj = a;
var i=0;
do {obj = obj.parentNode; ++i; }
while (obj.id != 'toc' && obj.nodeName != 'HTML');
/*
log('traversed '+i+' elements,' +
'arriving at obj.nodeName=' +obj.nodeName+
', obj.id=' + obj.id);
*/
if (obj.nodeName == 'HTML') return false;
return true;
}
function articleFromAnchor(a) {
log('articleFromAnchor');
var h=a.href;
var article=null;
log('h='+h);
var contribs=contributions.exec(h);
if (contribs != null) {
article='User:'+contribs[3];
return article;
}
var email=emailuser.exec(h);
if (email != null) {
article='User:'+email[3];
return article;
}
// no more special cases to check --
// hopefully it's not a disguised user-related page
var m=re.exec(h);
if(m===null) return null;
article=m[2];
return article;
};
// Generate html for whole popup
// this is ugly
function popupHTML (a) {
var c=a.className;
// if (c=='new') alert('new!');
var article = articleFromAnchor(a);
var hint=a.originalTitle;
if (hint == '' || hint == null)
hint = myDecodeURI(article);
var html='';
html +=imageHTML(article);
var simplifyMainLink = true;
var visibleMainLinkText=myDecodeURI(article);
if ( simplifyMainLink ) {
var s= visibleMainLinkText.split('/');
visibleMainLinkText = s[s.length-1];
if (visibleMainLinkText == '' && s.length > 1)
{
// shouldn't happen...
visibleMainLinkText=s[s.length-2];
}
}
html+='<b>';
html+=titledWikiLink(article,
'view',
visibleMainLinkText,
hint);
html+='</b>';
html+='<span id="popupImageStatus'+popupImageId+'"></span>';
// Get rid of anchor now
article=removeAnchor(article);
if (userName(article) != null) {
html += '<br>' + contribsLink(article, 'contribs');
html += ' ⋅ ' + kateLink(article, 'count');
html += ' ⋅ ' + emailLink(article, 'email');
}
html += '<br>' + wikiLink(article, 'edit', 'edit');
var ta=articleFromTalkPage(article);
if (ta != null) html +='|' +
wikiLink(article, 'edit§ion=new', 'new');
html += ' ⋅ ' + wikiLink(article, 'history', 'history');
html += ' ⋅ ' + wikiLink(article, 'unwatch', 'un') + '|';
html += wikiLink(article, 'watch', 'watch');
var t=talkPage(article);
if (t != null) html += ' ⋅ ' +
'<b>' + wikiLink(t, 'view', 'talk') + '</b>' +
'|' + wikiLink(t, 'edit', 'edit') +
'|' + wikiLink(t, 'edit§ion=new', 'new');
if (ta != null) html +=' ⋅ ' +
'<b>' + wikiLink(ta, 'view', 'article') + '</b>' +
'|' + wikiLink(ta, 'edit', 'edit');
html += '<br>' + specialLink(article, 'Whatlinkshere', 'whatLinksHere');
html += ' ⋅ ' + specialLink(article, 'Recentchangeslinked', 'relatedChanges');
html += '<span id="popupWarnRedir' + popupImageId + '"></span>';
html += '<span id="popupGubbins' + popupImageId + '"></span>';
html += '<span id="popupPreview' + popupImageId + '"></span>';
return html;
};
/////////////////
// DOWNLOADING //
/////////////////
//////////////
//
// downloader
//
//
function downloader(url) {
// Source: http://jibbering.com/2002/4/httprequest.html
this.http= false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
// JScript gives us Conditional compilation,
// we can cope with old IE versions.
// and security blocked creation of the objects.
try {
this.http = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
this.http = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
// this.http = false;
}
}
@end @*/
if (! this.http && typeof XMLHttpRequest!='undefined') {
this.http = new XMLHttpRequest();
}
this.url = url;
this.id=null;
this.callbackFunction = null;
if (this.http) {
// public
this.send = this.http.send;
this.abort = this.http.abort;
}
else this.http=false;
};
new downloader();
downloader.prototype.setCallback = function (f) {
if(!this.http) return;
this.http.onreadystatechange = f;
this.callbackFunction = f;
};
downloader.prototype.runCallback = function () {
this.callbackFunction(this);
};
downloader.prototype.getData = function () {
if(!this.http) return;
return this.http.responseText;
};
downloader.prototype.setTarget = function () {
if(!this.http) return;
this.http.open("GET", this.url, true);
};
downloader.prototype.start=function () {
// alert('downloader instance got told to start()');
if(!this.http) return;
return this.http.send(null);
};
downloader.prototype.getReadyState=function () {
if(!this.http) return;
return this.http.readyState;
};
function newDownload(url, id, callback) {
var d=new downloader(url);
d.id=id;
d.setTarget();
var f = function () {
if (d.getReadyState() == 4)
{ d.data=d.getData(); callback(d);}
};
d.setCallback(f);
return d;//d.start();
};
function fakeDownload(url,id,callback,data) {
var d=newDownload(url,callback);
d.id=id;
d.data=data;
return callback(d);
};
function startDownload(url, id, callback) {
var d=newDownload(url, id, callback);
d.start();
};
//
//
// downloader
//
//////////////
// Schematic for a getWiki call
//
// getWiki->-getPageWithCaching
// |
// false | true
// getPage<-[findPictureInCache]->-onComplete(a fake download)
// \.
// (async)->addPageToCache(download)->-onComplete(download)
function getWiki(wikipage, onComplete) {
log('getWiki, wikipage='+wikipage);
var url = titlebase + removeAnchor(wikipage) + '&action=raw';
return getPageWithCaching(url, onComplete);
};
// check cache to see if page exists
function getPageWithCaching(url, onComplete) {
log ('getPageWithCaching, url='+url);
var i=findInPageCache(url);
if (i > -1) {
return fakeDownload(url, popupImageId, onComplete, gCachedPages[i].data);
}
return getPage(url, onComplete);
};
function getPage(url, onComplete) {
log ('getPage, url='+url);
var callback= function (d) {
log('callback from getPage activated');
addPageToCache(d); onComplete(d) } ;
return startDownload(url, popupImageId, callback);
};
function findInPageCache(url) {
for (var i=0; i<gCachedPages.length; ++i) {
if (url==gCachedPages[i].url) {
log('found url at index '+i);
return i;
}
}
log('did not find url='+url);
return -1;
};
function cachedPage (url,data) {
this.url=url;
this.data=data;
};
function addPageToCache(download) {
log ('addPageToCache, page.url='+download.url);
/*
log ('addPageToCache now calling findInPageCache');
if (findInPageCache(download) > -1) {
log ('not adding - already there'); return;
}
log ('new page - adding');
*/
var page = new cachedPage(download.url, download.data);
return gCachedPages.push(page);
};
/*
var gCurrentDownload = null;
function abortCurrentDownload(download) {
if (gCurrentDownload) {
try { gCurrentDownload.abort(); }
catch (anerror) {return 'could not abort download object';}
}
return true;
}
*/
/////////////////////
// LINK GENERATION //
/////////////////////
function wikiLink(article, action, text) {
var prehint=null;
switch (action) {
case 'edit': prehint = 'Edit '; break;
case 'history': prehint = 'Show history for '; break;
case 'unwatch': prehint = 'Stop watching '; break;
case 'watch': prehint = 'Watch '; break;
case 'view': prehint = 'Go to '; break;
case 'edit§ion=new': prehint = 'Start a new topic on '; break;
default: true;
}
var hint;
if (prehint != null) hint=prehint + myDecodeURI(article);
else prehint = myDecodeURI(article + '&action=' + action);
return titledWikiLink(article, action, text, hint);
};
function titledWikiLink(article, action, text, title) {
var base = titlebase + article;
var url=base;
// no need to add action&view, and this confuses anchors
if (action != 'view') url = base + '&action=' + action;
var hint;
if (title == null || title == '')
hint = ''
else
hint = 'title="' + title + '"';
return '<a href="' + url + '" ' + hint + '>' + text + '</a>';
};
function specialLink(article, specialpage, text) {
var base = titlebase + 'Special:'+specialpage;
var url = base + '&target=' + article;
var prehint=null;
switch (specialpage) {
case 'Whatlinkshere':
prehint='Show the articles which link to '; break;
case 'Recentchangeslinked':
prehint='Show recent changes in articles related to '; break;
case 'Contributions':
prehint='Show the contributions made by '; break;
case 'Emailuser':
prehint='Email '; break;
}
var hint;
if (prehint != null) hint = prehint + myDecodeURI(article);
else hint = myDecodeURI(specialpage+':'+article) ;
return '<a href="' + url + '" title="' + hint + '">' + text + '</a>';
};
function redirLink(redirMatch) { /* NB redirMatch is in wikiText */
log ('making redirLink for page [['+redirMatch+']]');
var ret=titledWikiLink(myEncodeURI(redirMatch),
'view',
myDecodeURI(redirMatch),
'Bypass redirect');
return ret;
};
function doNotRedirLink(redirPage, linkText, hintText) { /* NB redirPage is in wikiText */
log('making doNotRedirLink for page(?) [['+redirPage+']]');
var ret=titledWikiLink(myEncodeURI(redirPage),
'edit',
linkText,
hintText);
return ret;
};
function contribsLink(article, text) {
return specialLink(userName(article), 'Contributions', text);
};
function emailLink(article, text) {
return specialLink(userName(article), 'Emailuser', text);
};
function kateLink(article, text) {
var uN=myDecodeURI(userName(article));
return '<a href="' + kateBase + uN + '" title="'
+ 'Count the contributions made by ' + uN + '">' + text + '</a>';
};
////////////////////////////
// MANIPULATION FUNCTIONS //
////////////////////////////
function upcaseFirst(str) {
return str[0].toUpperCase() + str.substring(1);
};
function formatBytes(num) {
ret = (num > 949) ? (Math.round(num/100)/10+'kB') :
(num +' bytes' ) ;
return ret;
}
function getPageInfo(data) {
var numImages = countImages(data);
var numLinks = countLinks(data);
var numCategories = countCategories(data);
var stats='c. ';
stats += formatBytes(data.length);
stats += ', ';
stats +=numLinks + ' wikiLink' + ((numLinks!=1)?'s, ':', ');
stats +=numImages + ' image' + ((numImages!=1)?'s, ':', ');
stats +=numCategories + ' categor' + ((numCategories!=1)?'ies':'y');
var pageInfo='';
if (isStub(data)) pageInfo+='stub, ';
if (isDisambig(data)) pageInfo += 'disambig, ';
if (pageInfo != '' )
pageInfo = upcaseFirst(pageInfo);
return pageInfo + stats;
};
function getValidImageFromWikiText(wikiText) {
var imagePage=null;
// nb in imageRegex we're interested in the second bracketed expression
// this may change if the regex changes :-(
//var match=imageRegex.exec(wikiText);
var matched=null;
var match;
while ( match = imageRegex.exec(wikiText)) {
/* now find a sane image name - exclude templates by seeking { */
var m = match[2];
log('is '+m+' a valid name for an image?');
if ( isValidImageName(m) ) { matched=m;
log('yes!');
break;}
log('no...');
}
imageRegex.lastIndex=0;
if (!matched) return null;
if (matched[0] >= 'a' && matched[0] <= 'z') {
// upcase first character if ascii
matched = upcaseFirst(matched);
}
imagePage='Image:'+matched;
return imagePage;
};
function countLinks(wikiText) {
// this could be improved!
return wikiText.split('[[').length - 1;
};
// if N = # matches, n = # brackets, then
// String.split(regex) intersperses the N+1 split elements
// with Nn other elements. So total length is
// L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1).
function countImages(wikiText) {
return (wikiText.split(imageRegex).length - 1) /
(imageRegexBracketCount + 1);
};
function countCategories(wikiText) {
return (wikiText.split(categoryRegex).length - 1) /
(categoryRegexBracketCount + 1);
};
function talkPage(article) {
if (article.indexOf('Talk:') > -1 || article.indexOf('talk:') > -1 )
return null;
var i=article.indexOf(':');
if (i == -1) return 'Talk:'+article;
else return article.substring(0,i)+'_talk:' + article.substring(i+1);
};
function articleFromTalkPage(talkpage) {
var i=talkpage.indexOf('Talk:');
var j=talkpage.indexOf('_talk:');
if ( i == -1 && j == -1 )
return null;
if ( i > -1 ) return talkpage.substring(i+5);
return talkpage.split('_talk:').join(':');
};
function userName(article) {
var i=article.indexOf('User');
var j=article.indexOf(':');
if (i != 0 || j < -1) return null;
var k=article.indexOf('/');
if (k==-1) return article.substring(j+1);
else return article.substring(j+1,k);
};
function stripNamespace(article) {
// this isn't very sophisticated
// it just removes everything up to the final :
var list = article.split(':');
return list[list.length-1];
};
function imagePathComponent(article) {
if (isImage(article)) {
var stripped=stripNamespace(article);
var forhash=myDecodeURI(stripped).split(' ').join('_');
var hash=md5_hex(forhash);
var pathcpt=hash.substring(0,1) + '/' + hash.substring(0,2) + '/';
return pathcpt;
}
else return null;
};
function getImageUrlStart(wiki) { // this returns a trailing slash
switch (wiki) {
case 'wiki.riteme.site':
return 'http://upload.wikimedia.org/wikipedia/en/';
case 'commons.wikimedia.org':
return 'http://upload.wikimedia.org/wikipedia/commons/';
case 'en.wiktionary.org':
return 'http://en.wiktionary.org/upload/en/';
default: // unsupported - take a guess
var lang=wiki.split('.')[0];
return 'http://' + wiki + '/upload/' + lang +'/';
}
}
function imageURL(img, wiki) {
if (popupDebug > 10) alert ('imageURL\n\nimg=' + img + '\nwiki='+wiki);
var imgurl=null;
if (isImage(img)) {
var pathcpt = imagePathComponent(img);
var stripped=stripNamespace(img);
imgurl=getImageUrlStart(wiki) + pathcpt + stripped;
}
return imgurl;
};
function imageThumbURL(img, wiki, width) {
//
// eg http://upload.wikimedia.org/wikipedia/en/thumb/6/61/
// Rubiks_cube_solved.jpg/120px-Rubiks_cube_solved.jpg
var imgurl=null;
if (isImage(img)) {
var pathcpt = imagePathComponent(img);
var stripped=stripNamespace(img);
imgurl=getImageUrlStart(wiki) + "thumb/"
+ pathcpt + stripped + '/' + width +"px-" + stripped;
}
return imgurl;
};
// (a) myDecodeURI (first standard decodeURI, then exceptions)
// (b) change spaces to underscores
// (c) encodeURI (just the straight one, no exceptions)
function wikiMarkupToAddressFragment (str) { // for images
var ret = myDecodeURI(str);
ret = ret.split(' ').join('_');
ret = encodeURI(ret);
return ret;
};
function addressFragmentToWikiMarkup (str) {
// seemingly, not :( the inverse of wikiMarkupToAddressFragment
log ('addressFragmentToWikiMarkup\nstr='+str);
var ret = myDecodeURI(str);
/* ret = ret.split('_').join(' '); */
/* ret = myEncodeURI(str); */
log('addressFragmentToWikiMarkup\nret='+ret);
return ret;
};
function myDecodeURI (str) {
var ret=decodeURI(str);
for (var i=0; i<decodeExtras.length; ++i) {
var from=decodeExtras[i].from;
var to=decodeExtras[i].to;
ret=ret.split(from).join(to);
}
log ('myDecodeURI: ' +str+ ' to ' +ret);
return ret;
};
function myEncodeURI (str) {
log ('myEncodeURI: str='+str);
var ret=str;
ret=encodeURI(ret);
log (' : after encodeURI, ret=' +ret);
for (var i=0; i<decodeExtras.length; ++i) {
var from=decodeExtras[i].from;
var to=decodeExtras[i].to;
ret=ret.split(to).join(from);
}
log (' : after decodeExtras, ret='+ret);
return ret;
};
function removeAnchor(article) {
// is there a #? if not, we're done
var i=article.indexOf('#');
if (i == -1) return article;
// head#tail
var head = article.substring(0,i);
var tail = article.substring(i+1);
return head;
};
///////////
// TESTS //
///////////
function isStub(data) { return stubRegex.test(data); }
function isDisambig(data) { return disambigRegex.test(data); }
function isValidImageName(str){ // extend as needed...
return ( str.split('{').length == 1 );
};
function isInNamespace(article, namespace) {
var i=article.indexOf(namespace+':');
var j=article.indexOf(namespace+'_talk:');
if (i == -1 && j == -1) return false;
return true;
};
function isImage(thing) {
return isInNamespace(thing, 'Image');
};
function isImageOk(img)
{
// IE test
if (!img.complete)
return false;
// gecko test
if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0)
return false;
// No other way of checking: assume it's ok.
return true;
};
function anchorContainsImage(a) {
// iterate over children of anchor a
// see if any are images
if (a===null) return false;
kids=a.childNodes;
for (var i=0; i<kids.length; ++i) {
if (kids[i].nodeName=='IMG') return true;
}
return false;
};
/////////////
// ACTIONS //
/////////////
var imageCache = new Array ();
function loadThisImage (image) {
if (!downloadImages) return;
var msg = '';
msg += 'loadThisImage; image=' + image;
msg += '\nimagePathComponent(image) = ' + imagePathComponent;
var stripped=stripNamespace(image);
var forhash=myDecodeURI(stripped).split(' ').join('_');
var hash=md5_hex(forhash);
var pathcpt=hash.substring(0,1) + '/' + hash.substring(0,2) + '/';
msg +='\n\nbreakdown:\n stripped==stripNamespace(image)='+stripped;
msg +='\nforhash=myDecodeURI(stripped).split(" ").join("_")='+forhash;
msg +='\nhash=md5_hex(forhash)-' +hash;
msg +='\npathcpt='+pathcpt;
if (!isValidImageName(image)) return false;
if(popupDebug != null)
alert(msg);
msg='List of urls:\n';
var imageUrls=new Array();
for (var i=0; i<imageSources.length; ++i) {
var url;
if (imageSources[i].thumb)
url=imageThumbURL(image, imageSources[i].wiki, imageSources[i].width);
else
url=imageURL(image, imageSources[i].wiki);
for (var j=0; j<gImageCache.length; ++j) {
if (url == gImageCache[j]) return loadThisImageAtThisUrl(image, url);
}
imageUrls.push(url);
}
msg='imageUrls:\n';
for (var i=0; i<imageUrls.length; ++i) {
var url = imageUrls[i];
imageSources[i].active=false;
msg += '\n'+url;
imageArray[i]=new Image();
imageArray[i].src=url;
}
//myalert(msg);
if (popupDebug) alert (msg);
if (popupImageTimer != null) {
clearInterval(popupImageTimer);
counter=0;
}
gImage=image;
popupImageTimer=setInterval("checkImages()", 250);
return;
};
function loadThisImageAtThisUrl(image, url) {
//myalert('loading "best" image:\n'+url);
gImage=image;
imageArray = new Array();
imageArray[0] = new Image();
imageArray[0].src=url;
if (popupImageTimer != null) {
clearInterval(popupImageTimer);
counter=0;
}
popupImageTimer=setInterval("checkImages()", 250);
return;
}
function loadImages(article) {
if(! isImage(article) ) return;
if (popupDebug) alert('loadImages, article='+article);
return loadThisImage(article);
};
function setPopupHTML (str, elementId, popupId) {
if (typeof popupId === 'undefined') popupId = popupImageId;
var popupElement=
document.getElementById(elementId+popupId);
var timer;
if (typeof popupHTMLTimers[elementId] == 'undefined') {
timer=null;
}
else {
timer=popupHTMLTimers[elementId];
}
if (popupElement != null) {
if(timer) clearInterval(timer);
popupHTMLTimers[elementId]=null;
popupElement.innerHTML=str;
log('setPopupElement found the '+elementId+popupId+ ' element' +
'\nstr='+str+
'\npopupElement.innerHTML=' + popupElement.innerHTML);
return true;
} else {
log('setPopupElement did not find the '+elementId+popupId+ ' element' +
'\nstr='+str);
var loopFunction=function() { setPopupHTML(str,elementId,popupId);}
popupHTMLLoopFunctions[elementId] = loopFunction;
if (!timer) {
var doThis = 'popupHTMLLoopFunctions["'+elementId+'"]()';
popupHTMLTimers[elementId] = setInterval(doThis, 600);
}
}
};
function setImageStatus(str, id) {
return setPopupHTML(str, 'popupImageStatus', id);
};
function setPopupTrailer(str,id) {
return setPopupHTML(str, 'popupGubbins', id);}
function checkImages() {
if (checkImagesTimer!=null) {
clearInterval(checkImagesTimer);
checkImagesTimer=null;
if (loopcounter > 10); {loopcounter=0; return;}
loopcounter++;
} else counter++;
var status = ( counter % 2 ) ? ':' : '.' ;
setImageStatus(status);
if (counter > 100) {counter = 0; clearInterval(popupImageTimer);}
var popupImage=null;
popupImage=document.getElementById("popupImage"+popupImageId);
if (popupImage == null) {
// this doesn't seem to happen any more in practise for some reason
// still, I'll leave it in
checkImagesTimer=setInterval("checkImages()",333);
return;
}
// get the first image to successfully load
// and put it in the popupImage
for(var i = 0; i < imageArray.length; ++i) {
if(isImageOk(imageArray[i])) {
// stop all the gubbins, assign the image and return
clearInterval(popupImageTimer);
if(isImage(gImage)) {
popupImage.src=imageArray[i].src;
popupImage.style.display='inline';
imageSources[i].active=true;
// should we check to see if it's already there? maybe...
gImageCache.push(imageArray[i].src);
//myalert('gImageCache='+gImageCache.join('\n'));
setPopupImageLink(gImage, imageSources[i].wiki);
stopImagesDownloading();
}
setImageStatus('');
// reset evil nonconstant globals
delete imageArray; imageArray=new Array();
popupImageTimer=null;
counter=0;
loopcounter=0;
return popupImage.src;
}
}
};
function stopImagesDownloading() {
gImage=null;
if (imageArray == null) return null;
var i;
for (i=0; i<imageArray.length; ++i) {
//imageArray[i].src=''; // this is a REALLY BAD IDEA
delete imageArray[i];
//imageArray[i] = new Image();
}
imageArray = new Array ();
return i;
};
function toggleSize() {
var imgContainer=this;
if (!imgContainer) { alert('imgContainer is null :/'); return;}
img=imgContainer.firstChild;
if (!img) { alert('img is null :/'); return;}
var msg='';
for (var i=0; i<imgContainer.childNodes.length; ++i)
msg += '\nimgContainer.childNodes['+i+'].width=' +
imgContainer.childNodes[i].width;
if (!img.style.width || img.style.width=='')
img.style.width='100%';
else img.style.width=''; // popupImageSize+'px';
};
function setPopupImageLink (img, wiki) {
if( wiki === null || img === null ) return null;
var a=document.getElementById("popupImageLink"+popupImageId);
if (a === null) return null;
var linkURL = imageURL(img, wiki);
if (linkURL != null) {
if (popupImagesToggleSize) {
a.onclick=toggleSize;
a.title='Toggle image size';
} else {
a.href=linkURL;
a.title='Open full-size image';
}
}
return linkURL;
};
function setupTooltips() {
debugsimple('top of setupTooltips');
if (typeof window.opera != 'undefined')
dsimplePopups=true;
// debugsimple('couple of lines later, after opera hack');
var anchors=document.getElementsByTagName('A');
// alert(anchors.length + 'anchors');
var s='';
if (removeTitles==null) removeTitles=dremoveTitles;
for (var i=0; i<anchors.length; ++i)
{
var a=anchors[i];
var h=a.href;
var contribs=contributions.exec(h);
var email=emailuser.exec(h);
var exc=exceptions.exec(h);
var m=re.exec(h);
if (
(! isInToc(a)) &&
(contribs != null || (exc == null && m != null) )
) {
a.onmouseover=mouseOverWikiLink;
a.onmouseout= mouseOutWikiLink;
a.onclick= killPopup;
if (removeTitles) {
a.originalTitle=a.title;
a.title='';
}
}
}
};
//////////////
// THINGIES //
//////////////
// How the URLs for images in the popup come about
// loadPreviewImage
// |
// getWiki
// |<----------------see other schematic for details
// insertPreviewImage (insertPreviewImage = onComplete)
// |
// | insertPreviewImage gets a wikiText fragment from
// | the wikiText downloaded by getWiki
// |
// [wikiMarkupToAddressFragment]
// |
// | mouseOverWikiLink (gets an "address fragment",
// | | no processing needed)
// \->-loadThisImage---<----loadImages
// |
// [image(Thumb)URL]-->--hopefully valid image urls
var currentLink=null;
function mouseOverWikiLink() {
// FIXME: should not generate the HTML until the delay has elapsed,
// and then popup immediately. Can be a CPU hog otherwise.
/* // good idea? dunno
if ( typeof o3_showingsticky != "undefined" && o3_showingsticky != 0 ) {
return;
}
*/
var a=this;
if (a==currentLink) return;
else currentLink=a;
var html = popupHTML(a);
var article=articleFromAnchor(a);
if (popupImageTimer != null) {
clearInterval(popupImageTimer);
counter=0;
}
if (popupDelay==null) popupDelay=dpopupDelay;
if (popupFgColor==null) popupFgColor=dpopupFgColor;
if (popupBgColor==null) popupBgColor=dpopupBgColor;
if (downloadImages==null) downloadImages=ddownloadImages;
log('running overlib now');
var setmaxwidth = function () { over.style.maxWidth = '300px'; }
registerHook("createPopup", setmaxwidth, FAFTER);
overlib(html,
STICKY,
/* MOUSEOFF, */
WRAP,
CELLPAD, 5,
OFFSETX, 2,
OFFSETY, 2,
DELAY, popupDelay*1000,
FGCOLOR, popupFgColor,
BGCOLOR, popupBgColor);
debugsimple('just after overlib call');
if (simplePopups===null)
simplePopups = dsimplePopups;
debugsimple('after default assignment');
if(simplePopups) return;
debugsimple('simplePopups was false, so we continue...');
if (imagePopupsForImages===null)
imagePopupsForImages = dimagePopupsForImages;
var previewImage=true;
gImage=null;
if (
isImage(article) &&
( imagePopupsForImages || ! anchorContainsImage(a) )
)
{
loadImages(article);
}
else if (!isImage(article) && previewImage) {
redirCount=0;
loadPreviewImage(article);
}
};
function loadPreviewImage(article) {
/* var imgStatus;
imgStatus='';
for (var i=0; i<redirCount+2; ++i) imgStatus += '.';
setImageStatus(imgStatus); */
var ret=getWiki(article, insertPreviewImage);
return ret;
};
function loadPreviewImageFromRedir(redirPage, redirMatch) {
/* redirMatch is a regex match */
var target = redirMatch[1];
var trailingRubbish=redirMatch[2];
log ('found a first redirect to ' + target);
++redirCount;
var warnRedir='<br>Redirects to ';
warnRedir += redirLink(target);
if (trailingRubbish.length > 0) {
log ('found trailing rubbish: in redirect to\n'
+ target + '\n\n' + trailingRubbish);
warnRedir += ', '+formatBytes(trailingRubbish.length);
warnRedir += ' ' +
doNotRedirLink(redirPage, 'hidden', 'Show text hidden after #redirect[[...]]');
}
setPopupHTML(warnRedir, 'popupWarnRedir');
return loadPreviewImage(myEncodeURI(target));
};
function extractChunk(str, header, breakChar) {
if (str.indexOf(header) != 0) return null;
if (!breakChar) return str.substring(header.length);
var findChar=str.indexOf(breakChar);
if (findChar==-1) return str.substring(header.length);
return str.substring(header.length, findChar);
}
function urlToWikiPage (url) {
log ('urlToWikiPage\nurl='+url);
var urlFragment=null;
if (!urlFragment) urlFragment=extractChunk(url, titlebase, '&');
if (!urlFragment) urlFragment=extractChunk(url, wikibase, '?');
if (!urlFragment) return null;
return addressFragmentToWikiMarkup(urlFragment);
}
function insertPreviewImage(download) {
log('starting insertPreviewImage');
if (download.id != popupImageId) {
log('download.id='+download.id
+' does not match popupImageId='+popupImageId);
return;
}
var wikiText=download.data;
log ('considering '+wikiText.length+' bytes of data, starting\n'
+ wikiText.substring(0,50) );
var redirectRegex= /^[ \n]*[#]redirect[: \n]*\[\[([^\]]*)\]\]\s*(.*)/i ;
var redirMatch = redirectRegex.exec(wikiText);
if (redirMatch && redirCount==0) {
return loadPreviewImageFromRedir(urlToWikiPage(download.url), redirMatch);
} else redirCount=0;
log('not a redirect');
// setImageStatus(''); // this seems redundant
if (extraPageInfo===null) extraPageInfo=dextraPageInfo;
if (extraPageInfo) {
log ('getting extraPageInfo');
var pgInfo=getPageInfo(wikiText);
log ('got '+pgInfo);
setPopupTrailer('<br>' + pgInfo);
}
var imagePage=getValidImageFromWikiText(wikiText);
if(imagePage) {
log ('found imagePage='+imagePage);
// loadThisImage expects an "address fragment"
imagePage = wikiMarkupToAddressFragment(imagePage);
loadThisImage(imagePage);
}
else log('no image found');
if (popupPreviews===null) popupPreviews=dpopupPreviews;
if (popupPreviews) {popupPreview(download);}
log ('done insertPreviewImage');
// myalert(gMsg); gMsg='';
};
var localTest=false;
function popupPreview(download) {
// FIXME: horizonal rules should be skipped
// FIXME: get rid of html tagsx
if (localTest)
var data = download.substring(0,8000); // FOR TESTING
else
var data=download.data.substring(0,10000); // huge pages be gone
var datum=new Array();
datum.push(data);
// we strip in order:
//
// * html comments <!-- ... -->
// * contents of <div...> ... </div> and <gallery> ... </gallery>
// * templates {{ }}
// * wikitext tables
// * wikitext images
// * wikitext rules ----
// * lines starting with a :
// * html tables
// * a mop-up: delete all lines starting with <
// * all html tags
// * "chunks" of italic text (heuristics alert)
// * __TOC__, __NOTOC__
// hasta la vista, comments
data=data.replace(RegExp('<!--(\\n|[^-]|-[^-]|--[^>])*-->', 'g'), '');
// say goodbye, divs
data=data.replace(RegExp('< *div[^>]* *>(.|\\n)*< */ *div *>',
'gi'),
'');
// and galleries
data=data.replace(RegExp('< *gallery[^>]* *>(.|\\n)*< */ *gallery *>',
'gi'),
'');
// try to remove templates
data=data.replace(RegExp('[{][{]([{][{][^}]*[}][}]|[^{}])*[}][}]', 'g'), '');
datum.push(data);
// tables are bad, too
data=data.replace
(RegExp('[{]\\|([{][|]([^\\|]|\\|[^}])*[|][}]|[^\\|]|\\|[^}])*\\|[}]', 'g')
, '');
datum.push(data);
// images are a nono
// who says regexes aren't fun?
// this ain't so good, try it on [[User:dbenbenn]]
// i think we should match:
// [[image: ...... ]] where ....... is consists of repetitions of any of:
// 1. not [ or ]
// 2. [[ (not ])* ]]
// 3. [ (not ])* ]
var imagedetector
='[[][[]\\s*image\\s*:([^\\[\\]]|\\[\\[[^\\]]*\\]\\]|\\[[^\\]]*\\])*\\]\\]';
var crudeImageRegex = RegExp(imagedetector, 'gi');
// alert(data.match(crudeImageRegex).join('\n-\n'));
data=data.replace(crudeImageRegex, '');
// we simply *can't* be doing with horizontal rules right now
data=data.replace(RegExp('^-{4,}','mg'),'');
// no indented lines
data=data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), '\n');
// or html tables // this doesn't cope with embedded tables
// for example, [[Kingdom of Ireland]] (yucky source)
//data=data.replace(RegExp('<table[^>]*>([\\n\\s]|[^<]|<[^/]|</[^t]|'+
//'</t[^a]|</ta[^b]|'+
//'</tab[^l]|</tabl[^e]|</table[^>])*</table>','gi'),
//'');
// may this is good enough?
data=data.replace(RegExp('< *table[^>]* *>([^\\n]|\\n[^\\n])*< */ *table *>\\n\\n', 'gi'),
'');
// let's delete lines starting with <. it's worth a try.
data=data.replace(RegExp('(^|\\n) *<[^\\n]*', 'g'), '\n');
// or those pesky html tags
data=data.replace(RegExp('<[^>]*>','g'),'');
// chunks of italic text? you crazy, man?
// Fails on [[United Kingdom]]
// now works on [[Ireland]]
//var italicChunkRegex =
// new RegExp
// ("((^|\\n)\\s*:*\\s*''([^']|'''|'[^']){30,}(.|\\n[^\\n])*''[.!?\\s]*\\n)*"
// , 'g');
var italicChunkRegex=new RegExp
("((^|\\n)\\s*:*\\s*''[^']([^']|'''|'[^']){20}(.|\\n[^\\n])*''[.!?\\s]*\\n)*"
, 'g');
data=data.replace(italicChunkRegex, '');
// return data; //TESTING
// replace __TOC__, __NOTOC__ and whatever else there is
// this'll probably do
data=data.replace(RegExp('^__[A-Z_]*__ *$', 'gm'),'');
// dont't be givin' me no subsequent paragraphs, either, you hear me?
stuff=(RegExp('^\\s*([^\\n]|\\n[^\\n])*')).exec(data);
if (stuff)
data = stuff[0];
// superfluous sentences are RIGHT OUT.
// note: 1 set of parens here needed to make the slice work
data = data.split(RegExp('([!?.]+["'+"'"+']*\\s)','g'));
// leading space is bad, mmkay?
data[0]=data[0].replace(RegExp('^\\s*'), '');
var notSentenceEnds=RegExp('([^.][a-z][.][a-z]|etc|sic)$', 'i');
data = fixSentenceEnds(data, notSentenceEnds);
var maxPreviewSentences=3;
var maxPreviewCharacters=800;
var n=maxPreviewSentences;
var d;
do {d=firstSentences(data,n); --n; }
while ( d.length > maxPreviewCharacters && n > 0 );
data = d;
// myalert(datum.join('\n===\n'));
if (localTest)
return data; // FOR TESTING
var newhtml=wiki2html(data); // needs livepreview
//newhtml = '<table width="260"><tr><td>' + newhtml +
//'</td></tr></table>';
setPopupHTML('<hr>'+newhtml, 'popupPreview');
};
function fixSentenceEnds(strs, reg) {
// take an array of strings, strs
// join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg
for (var i=0; i<strs.length-2; ++i) {
if (reg.test(strs[i])) {
a=new Array ();
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 fixSentenceEnds(a,reg);
}
}
//alert('returning '+strs.join('\n\n'));
return strs;
}
function firstSentences(strs, howmany) {
var t=strs.slice(0, 2*howmany);
return t.join('');
}
var stopPopupTimer=null;
function fuzzyCursorOff(fuzz) {
if (!over) return null;
var left = parseInt(over.style.left);
var top = parseInt(over.style.top);
var right = left + (over.offsetWidth >= parseInt(o3_width) ? over.offsetWidth : parseInt(o3_width));
var bottom = top + (over.offsetHeight >= o3_aboveheight ? over.offsetHeight : o3_aboveheight);
if (o3_x < left-fuzz || o3_x > right+fuzz || o3_y < top-fuzz || o3_y > bottom + fuzz) return true;
return false;
}
// seems that fuzzyCursorOff should precede mouseOutWikiLink in the source
// or sometimes during page loads, errors are generated
function mouseOutWikiLink () {
// document.title += '!';
if (fuzzyCursorOff(5)) {
if (stopPopupTimer) {
clearInterval(stopPopupTimer);
stopPopupTimer=null;
}
killPopup();
return;
}
if (!stopPopupTimer)
stopPopupTimer=setInterval("mouseOutWikiLink()", 500);
};
function killPopup() {
// o3_showingsticky should be defined in overlib.js
//if ( typeof o3_showingsticky != "undefined" && o3_showingsticky == 0 ) {
cClick();
currentLink=null;
// abortCurrentDownload();
stopImagesDownloading();
//}
return true; // preserve default action (eg from onclick)
};
////////////////////////////////////////////////////////////////////
// Run things
////////////////////////////////////////////////////////////////////
if (window.addEventListener)
window.addEventListener("load",setupTooltips,false);
else if (window.attachEvent)
window.attachEvent("onload",setupTooltips);
else {
window._old_ABCD_onload = window.onload;
window.onload = function() {
window._old_ABCD_onload();
setupTooltips();
}
}
function debugsimple(pos) {
alert(pos+
'\n\n'+
'simplePopups='+
simplePopups+
'\nthis is '+
((simplePopups===null)? '':'**not** ') +
'null' +
'\n\ndsimplePopups='+dsimplePopups
);
}
debugsimple('first pass');
//simplePopups=true;
//debugsimple('just set the bugger to true');