MediaWiki:LinkPreview/code.js

/* */ /* smth like mw:Extension:Popups */ /* popup on link:hover */ /* maintainer: user:fngplg */ /* classes: main: npage-preview, image not found: npage-preview-noimage */ /* img:, text: */ (function ($){   var Settings = window.pPreview || {};    Settings.debug = Settings.debug !== undefined ? Settings.debug : false;    //show preview delay, ms    Settings.delay = Settings.delay !== undefined ? Settings.delay : 100;    Settings.tlen = Settings.tlen !== undefined ? Settings.tlen : 1000; //max text length    //cache size    Settings.csize = Settings.csize !== undefined ? Settings.csize : 100;    Settings.defimage = Settings.defimage !== undefined ? Settings.defimage : 'https://vignette2.wikia.nocookie.net/borderlands/images/0/05/Ajax.gif/revision/latest/scale-to-width-down/350?cb=20170626182120&path-prefix=ru'; //default image path    //no image found. class: npage-preview-noimage    Settings.noimage = Settings.noimage !== undefined ? Settings.noimage : 'https://vignette4.wikia.nocookie.net/borderlands/images/f/f5/%D0%97%D0%B0%D0%B3%D0%BB%D1%83%D1%88%D0%BA%D0%B0.png/revision/latest/scale-to-width-down/200?cb=20160122074659&path-prefix=ru'; //request to perform scaling Settings.scale = Settings.scale !== undefined ? Settings.scale : {r: '?', t: '/scale-to-width-down/350?'}; Settings.RegExp = Settings.RegExp || {}; //regexps //images 2 ignore Settings.RegExp.iimages = Settings.RegExp.iimages || []; //pages 2 ignore Settings.RegExp.ipages = Settings.RegExp.ipages || []; //links 2 ignore Settings.RegExp.ilinks = Settings.RegExp.ilinks || []; //Settings.RegExp.hash = Settings.RegExp.hash || new RegExp('#.*'); Settings.RegExp.wiki = Settings.RegExp.wiki || new RegExp('\/wiki\/', 'i'); Settings.RegExp.dtag = Settings.RegExp.dtag || new RegExp('<.*>','gm'); //preprocess data (remove scripts) Settings.RegExp.prep = Settings.RegExp.prep || new RegExp(' .*? ','igm'); //var iimages = Settings.RegExp.iimages; //images 2 ignore var ncache = []; //{href, data} var loc = {}; //x, y   var currentEl = {}; //{href, ?data} //var api = new mw.Api; var apiUri = new mw.Uri({path: '/api.php'}); var thisPage = createUri(location).truepath; mw.hook('wikipage.content').add(hlpHook); function hlpHook { //hook helper mw.loader.using(['mediawiki.util', 'mediawiki.api.parse'], init); }//hlphook function init { //should i ignore this page if (nignorePage(thisPage)) { mw.hook('wikipage.content').remove(hlpHook); if (Settings.debug) console.log('pp. ignore ', thisPage); return; }       //run once if (window.pPreview && window.pPreview.version) return; Settings.version = '1.0b'; window.pPreview = Settings; if (Settings.debug) { console.log('pp rmain'); Settings.cache = ncache; }       Settings.RegExp.ilinks.push(thisPage); // ignore this page //ajaxrc support window.ajaxCallAgain = window.ajaxCallAgain || []; window.ajaxCallAgain.push(main); main; } //init function main { $('#WikiaMainContent').find('a').each(function{           var el = $(this);            var ahref = el.attr('href');            if (Settings.debug) console.log('pp. main. el.h: ', ahref);           if (!ahref) return;            ahref = createUri(ahref);            if (Settings.debug) console.log('pp. main.uri: ', ahref);            if (ahref && !nignoreLink(ahref.truepath) && ahref.hostname === apiUri.host) { //internal link               el.hover(aHover, nhidePreview);                if (Settings.debug) {                    //ncache.push(el);                }            } // if internal link        }); //each a        /* $('body').off('mousemove.npreview'); $('body').on('mousemove.npreview', function(ev){           //loc.left = ev.pageX + 5;            //loc.top = ev.pageY + 5;            //nhidePreview;        }); */   } //main function createUri (href, base) { var h;       if (URL) { //if not ie actually h = new URL(href, base || apiUri.clone.extend({path:''}).toString); } else { try { h = new mw.Uri(href); h.pathname = h.path; h.hostname = h.host; } catch (e) { h = undefined; if (Settings.debug) console.log('pp.createUrl.e: ', e); }       } //if url if (h) { h.truepath = decodeURIComponent(h.pathname.replace(Settings.RegExp.wiki, '')); }       return h;    } //createUri function escapeRegExp(str) { return str.replace(/([.*+?^=!:${}|\[\]\/\\])/g, "\\$1"); } //escapeRegExp function aHover (ev) { //a hover handler ev.stopPropagation; currentEl.href = getHref(ev.currentTarget); //set coords loc = {left: ev.pageX + 5, top: ev.pageY +5}; if (Settings.debug) { console.log('pp.ahover ev:', ev); }       setTimeout(ngetPreview.bind(this, ev), Settings.delay); } //ahover function getHref(el) { //returns href //todo: deprecate it -> createUri var $el = $(el); var nhref = createUri($el.attr('href')); //if (Settings.debug) console.log('pp.gethref href: ', nhref); nhref = nhref.truepath; return nhref; } //gethref function getObj (data, key) { //traverse through object tree var ret = [], r;       for (var k in data) { if (data[k] instanceof Object) { if (k === key) { ret.push(data[k]); }               r=getObj(data[k], key); if (r) ret=ret.concat(r); } //if obj } //for k in data return ret; } //getObj function getVal (data, key) { //travers through object tree var ret = [], r;       for (var k in data) { if (data[k] instanceof Object) { r=getVal(data[k], key); if (r) { ret=ret.concat(r); }           } else { if (k === key) { ret.push(data[k]); }           } //if obj } //for k in data return ret; } //getVal function hlpPreview (href, div, img) { //preview helper //load img and add to div var im, d;       im = $('img', div); if (img) { //let vignette do scale im.attr('src', Settings.scale ? img.replace(Settings.scale.r, Settings.scale.t) : img); } else { im.attr('src', Settings.noimage); im.addClass('npage-preview-noimage'); } //if img d = {href: href, data: div}; ncache.push(d); if (Settings.debug) window.pPreview.pdiv = d.data; nshowPreview(d.data, d.href); } //hlpPreview function ngetPreview (ev) { var nhref = getHref(ev.currentTarget); //save bandwith //if (Settings.debug) console.log('pp.gp href: ', nhref, ' curel.href: ', currentEl.href, nhref==currentEl.href); if (nhref != currentEl.href) return; var ndata = ncacheOf(nhref); if (Settings.debug) console.log('pp.gp x:'+loc.left+' y:'+loc.top); if (ndata) { if (Settings.debug) console.log('pp.gp show preview', ndata); nshowPreview(ndata.data, nhref); return false; } //if data //get data var apipage = apiUri.clone.extend({action: 'parse', page: nhref, section: 0, prop: 'images|text', format: 'xml', disablepp: , redirects: }); if (Settings.debug) console.log('pp.gp apip: ', apipage); $.get(apipage).done(function(data){           var img = $(data).find('images img').toArray.map(function(value, index){ if (nignoreImage($(value).text)) { return false; } else { return $(value).text; }           }).filter(Boolean)[0];            //img = $(img);            var text = $(data).find('text').text;            if (!img && !text) {return false;}            //preprocess (cleanup)            text = text.replace(Settings.RegExp.prep, );            text = $(' ', {class: 'tmpdivclass', style: 'visibility:hidden;display:none;'}).html(text);            text.find('aside').prevAll.remove;            text.find('aside').remove;            //convert 2 text            text = text.text;            //text clean up            text = text ? text.replace(Settings.RegExp.dtag, ) : '';            text = text.trim.substr(0, Settings.tlen);            if (Settings.debug) {                window.pptext = text;                window.ppdata = data;                console.log('pp.gp img: '+img+' text: '+text);            }            var div = $(' ', {class: 'npage-preview'}); var d = {}, twrap, iwrap; if (text.length > 0) { twrap = $(' ', {text: text}); //wrap.text(text); div.append(twrap); } //if text iwrap = $(' ', {src: Settings.defimage}); div.prepend(iwrap); if (img) { //action=query&titles=file:.jpg&iiprop=url&prop=imageinfo&format=xml var im = 'file:' + img.trim; var apiimage = apiUri.clone.extend({action: 'query', redirects: '',                           titles: im, iiprop: 'url', prop: 'imageinfo', format: 'json'}); if (Settings.debug) { console.log('pp.gp img apii: ', apiimage.toString); }               $.getJSON(apiimage.toString).done(function(data) {                    //var d1 = $(data).find('page');                    //var im = $(' ').html(d1);                    if (Settings.debug) {                        console.log('pp.gp img apii done: ', data);                    }                    var im, d1;                    d1 = data.query;                    if (d1.redirects) {                        var imRed = getVal(getObj(d1, 'redirects'), 'to');                        if (Settings.debug) console.log('pp.gp img redir to ', imRed);                        if (imRed.length > 0) {                            imRed = imRed[0];                        } else {                            //no url found                            iwrap.attr('src', Settings.noimage);                            if (Settings.debug) console.log('pp.gp img redir.to not found in ', d1); return; }                       var apiim = apiimage.clone.extend({titles: imRed}); //resolve redirect if (Settings.debug) { console.log('pp.gp resolv redir: ', apiim.toString); }                       $.getJSON(apiim.toString, function(data) {                            var im = getVal(getObj(data, 'pages'), 'url');                            if (im.length > 0) {                                im = im[0];                            } else {                                //no url found. again                                im = false;                            }                            hlpPreview(nhref, div, im);                        }); //getjson. resolve redirect } else { im = getVal(getObj(d1, 'imageinfo'), 'url'); if (im.length > 0) { im = im[0]; } else { im = false; }                       hlpPreview(nhref, div, im); } //if redirects }).fail(function(data){ if (Settings.debug) { console.log('pp.gp img api fail', data); }               });            } else { //no img                hlpPreview(nhref, div, false);            }//if img        });//get page data return false; } //getpreview function nshowPreview (data, target) { //if (Settings.debug) console.log('pp.sp data: '+$(data).html); if (currentEl.href !== target) return false; //other hover processing yet if (Settings.debug) window.ppdiv1 = data; $('body').append($(data)); $(data).css({left: loc.left, top: loc.top}); $(data).show;//fadeIn('fast'); } //showpreview function nhidePreview (data) { currentEl.href = ''; $('.npage-preview').remove; } //hidepreview function nignoreImage (name) { //true if image should be ignore //name = name.replace(/(file):/im, ''); //name = name.charAt(0).toUpperCase + name.slice(1); for (var i=0, len=Settings.RegExp.iimages.length; i<len; i++) { if (Settings.RegExp.iimages[i] instanceof RegExp) { if (Settings.RegExp.iimages[i].test(name)) return true; } else { if (name === Settings.RegExp.iimages[i]) return true; } //if regexp }       return false; } //nignoreimage function nignorePage (name) { //true if page should be ignore var a = Settings.RegExp.ipages; for (var i=0, len=a.length; i<len; i++) { if (a[i] instanceof RegExp) { if (a[i].test(name)) return true; } else { if (name === a[i]) return true; } //if regexp }       return false; } //nignorepage function nignoreLink (name) { //true if link should be ignore var a = Settings.RegExp.ilinks; for (var i=0, len=a.length; i Settings.csize) ncache = []; //clear cache for (var i=0, len=ncache.length; i<len; i++) { if (ncache[i].href === href) { if (Settings.debug) console.log('pp.cache found: ' + href + ' data: ', ncache[i].data); //window.ppcdata = ncache[i]; return ncache[i]; }       }        return null; } //ncacheof })(jQuery);