User:HudgynS/common.js
Jump to navigation
Jump to search
Note: This is a user's personal page attached to their profile! This is not an actual article, may not be related to JoJo or Araki, and is not associated with the wiki. As such, it may not adhere to the policies. |
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
/* <pre> */
/* popup on link:hover */
/* it's like mw:Extension:Popups if HTML worked */
/* originally maintained by user:fngplg for Fandom */
/* adapted to MediaWiki by HudgynS */
/* classes: main: npage-preview, wide image: npage-preview-vertical, */
/* image only: npage-preview-file, image not found: npage-preview-noimage */
/* img: <img>, text: <div> */
(function wrapper ($) {
var parser = new DOMParser();
var urlVars = new URLSearchParams(location.search);
var Settings = window.pPreview || {},
mwc = mw.config.get(['wgScriptPath', 'wgSassParams', 'wgArticlePath']);
Settings.debug = urlVars.get('debug') || urlVars.get('debug1') || (Settings.debug !== undefined ? Settings.debug : false);
// killswitch
Settings.dontrun = urlVars.get('nolp');
if (Settings.dontrun) return;
// default values
var Defaults = {
dock: '#mw-content-text, #article-comments',
defimage: 'https://jojowiki.com/extensions/InterviewManager/resources/Loading-Koichi.png',
noimage : 'https://static.jojowiki.com/images/7/71/latest/20230228042347/JJBESymbol.png',
};// defaults
var pp = {};
pp.sync = []; // synchronization element
var ncache = []; // {href, data}
var loc = {lefts: 5, tops: 5}; // left: x, top: y, lefts: left-shift, clientx
var currentEl = {}; // {href, ?data}
var windowData = {};
// var api = new mw.Api();
var apiUri;
// exports
Settings.wrapper = wrapper;
Settings.context = this;
Settings.f = {init: init, main: main, createuri: createUri, getpreview: ngetPreview,
showpreview: nshowPreview, hidepreview: nhidePreview, cache: ncache,
ignoreimage: nignoreImage, ignorepage: nignorePage, ignorelink: nignoreLink,
cacheof: ncacheOf, chkimagesrc: chkImageSrc, preprocess: preprocess,
elvalidate: elValidate, processtext: processText, resettimer: resetTimer,
callapi: callApi, splitnamespace: splitNamespace};
mw.loader.using(['mediawiki.util', 'mediawiki.Uri'], init);
function log () {
var a = [].slice.call(arguments);
a.unshift('pp');
if (Settings.debug) console.log.apply(this, a);
}// log
pp.start = function (e) {
// allows (true) processing for element e
if (e) {
if (pp.sync.indexOf(e) > -1) {
return false;
}
}
Settings.process = true;
pp.sync.push(e || Settings.process);
return true;
};// start
pp.stop = function (e) {
hlpaHover();
var epos = pp.sync.indexOf(e);
if (epos !== -1) {
// remove e from sync array
pp.sync.splice(epos, 1);
} else {
// remove something; stack presumed
pp.sync.splice(0, 1);
}
if (pp.sync.length === 0) {
Settings.process = false;
}
};// stop
pp.cachedupl = function () {
// check cache for href duplication
var el = null;
outer:
for (var i = 0, len = ncache.length; i < len; i++) {
for (var k = i + 1; k < len; k++) {
if (ncache[i].href === ncache[k].href) {
el = {v: ncache[i].href, i: i, k: k};
break outer;
}
}// k inner loop
}// i outer loop
if (el) {
console.log('pp.cachedupl found', el.v, el.i, el.k);
}
};// cachedupl
function init () {
if (window.pPreview && window.pPreview.version) {
log('init dbl run protection triggered');
return;
}
Settings.version = '1.70';
log('init vrsn:', Settings.version);
apiUri = new mw.Uri({path: mwc.wgScriptPath + '/api.php'});
// use api.v1/article/details
Settings.apid = Settings.apid !== undefined ? Settings.apid : false;
// show preview delay, ms
Settings.delay = Settings.delay !== undefined ? Settings.delay : 200;
// suppress hover events for x ms
Settings.ttl = Settings.ttl !== undefined ? Settings.ttl : 100;
// Settings.throttling = timeout until x
Settings.throttle = Settings.throttle !== undefined ? Settings.throttle : 100;
Settings.throttling = false;
Settings.process = false;// processing data
Settings.tlen = Settings.tlen !== undefined ? Settings.tlen : 800; // max text length
// do not remove portable infobox on preprocess stage
Settings.pibox = Settings.pibox !== undefined ? Settings.pibox : false;
// do not remove infobox siblings
Settings.piboxkeepprev = Settings.piboxkeepprev !== undefined ? Settings.piboxkeepprev : false;
// cache size
Settings.csize = Settings.csize !== undefined ? Settings.csize : 100;
Settings.defimage = Settings.defimage !== undefined ? Settings.defimage : Defaults.defimage; // default image path
// no image found. class: npage-preview-noimage
Settings.noimage = Settings.noimage !== undefined ? Settings.noimage : Defaults.noimage;
// request to perform scaling
Settings.scale = Settings.scale !== undefined ? Settings.scale : {r: '?', t: '/scale-to-width-down/350?'};
// container (#WikiaMainContent, #mw-content-text etc)
Settings.dock = !!Settings.dock ? Settings.dock : Defaults.dock;
// parse whole page. debug purposes mainly
Settings.wholepage = urlVars.get('wholepage') || (Settings.wholepage !== undefined ? Settings.wholepage : false);
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 || [];
// parents to ignore
Settings.RegExp.iparents = Settings.RegExp.iparents || ['[id^=flytabs] .tabs'];
// classes to ignore
Settings.RegExp.iclasses = Settings.RegExp.iclasses || [];
// content to process. non-exclusive inclusion
Settings.RegExp.onlyinclude = Settings.RegExp.onlyinclude || [];
// content to remove (css-style targets)
Settings.RegExp.noinclude = Settings.RegExp.noinclude || [];
// Settings.RegExp.hash = Settings.RegExp.hash || new RegExp('#.*');
Settings.RegExp.wiki = Settings.RegExp.wiki || new RegExp('^.*?\/wiki\/', 'i');
// delete tags
Settings.RegExp.dtag = Settings.RegExp.dtag || new RegExp(/<\/*([^\/biusl]|s[^p]|lin|b[^r>\s]+|[iu][^>\s]+).*?>/, 'gm');
// preprocess data (remove scripts)
Settings.RegExp.prep = Settings.RegExp.prep || [];
// set len restriction for apid.abstract
if (Settings.apid) {
Settings.tlen = (Settings.tlen > 500) ? 500 : Settings.tlen;
}
// ensure #mw-content-text is processed
Settings.fixContentHook = Settings.fixContentHook !== undefined ? Settings.fixContentHook : true;
Settings.emptytext = Settings.emptytext !== undefined ? Settings.emptytext : /^([\n\s]|<[^>]+?>|<!--.*?-->|\.\.\.)*?$/;
window.pPreview = Settings;
var thisPage = (createUri(location) || {}).truepath;
// should i ignore this page
if (!thisPage || nignorePage(thisPage)) {
mw.hook('wikipage.content').remove(main);
log('ignore', thisPage);
return;
}
// run once
// dump sass params
var sasses = '';
$.each(mwc.wgSassParams, function(k, v) {
sasses = sasses + '--sass-' + k + ':' + v + ';\n';
});// each sassparam
if (sasses.length) {
sasses = ':root {\n' + sasses + '}';
mw.util.addCSS(sasses);
}
log('sasses', {sasses: sasses});
log('rmain');
if (Settings.debug) {
Settings.cache = ncache;
}
Settings.RegExp.ilinks.push(thisPage); // ignore this page
Settings.RegExp.ilinks.push(new RegExp(apiUri.path)); // ignore unknown
var r;
if (Settings.RegExp.prep instanceof RegExp) {
r = Settings.RegExp.prep;
Settings.RegExp.prep = [r];
}// if regexp.prep is regexp
if (!(Settings.RegExp.prep instanceof Array)) {
Settings.RegExp.prep = [];
}// if regexp.prep is not array
Settings.RegExp.prep.push(/<script>[\s\S]*?<\/script>/igm);
Settings.RegExp.prep.push(/<ref>[\s\S]*?<\/ref>/igm);
Settings.defimage = chkImageSrc(Settings.defimage) ? Settings.defimage : Defaults.defimage;
Settings.noimage = chkImageSrc(Settings.noimage) ? Settings.noimage : Defaults.noimage;
Settings.f.pp = pp;
// ajaxrc support
window.ajaxCallAgain = window.ajaxCallAgain || [];
window.ajaxCallAgain.push(main);
mw.hook('wikipage.content').add(main);
mw.hook('ppreview.ready').fire(Settings);
// load localization, if no local (wiki\user-specific) noimage defined
if (Settings.noimage === Defaults.noimage) {
log('i18n load');
mw.hook('dev.i18n').add(function (i18n) {
i18n.loadMessages('LinkPreview').done(function (i18n) {
log('i18n loaded', i18n);
i18n.useContentLang();
var img = i18n.msg('no-image').plain();
Settings.noimage = chkImageSrc(img) ? img : Settings.noimage;
log('i18n noimage', Settings.noimage, img);
});
});
}
// main();
} // init
function main ($cont) {
// main
log('main', $cont);
if (Settings.fixContentHook && $cont && $cont.length) {
Settings.fixContentHook = false;
if ($cont.selector !== '#mw-content-text') {
log('main fixcontent', $cont);
main($('#mw-content-text'));
}
}
var $content, arr = [];
// gather dock sites to one array
Settings.dock.split(',').forEach(function (v) {
var $c = {};
if ($cont) {
// if $cont belongs to dock container
$c = ($cont.is(v) || $cont.parents(v).length) ? $cont : {};
} else {
// get whole dock. if main() called w\o params
$c = $(v);
}// if $cont. instead of $cont ? .is || .len ? : :
$.merge(arr, $c);
});// each dock
$content = $(arr);
log('main.c:', $content);
$content.find('a').each(function() {
var $el = $(this);
if (elValidate($el)) { // internal link
// $el.hover(aHover, resetTimer);
$el.off('mouseover.pp blur.pp mouseout.pp');
$el.on('mouseover.pp', aHover);
} // if internal link
}); // each a
} // main
function getImage(url) {
return new Promise(function (resolve, reject) {
var image = new Image();
image.onerror = function (data) { reject(); };
image.src = url;
image.decode().then(function(data) {
resolve(url);
})
.catch(function (e) { reject(); });
});
}
function userAvatar(userid) {
return new Promise(function (resolve, reject) { // yes there is no other way to handle this in ES5
var avatar = '';
getImage('https://static.jojowiki.com/images/avatars/jojowiki_'+userid+'_l.png')
.then(function (data) {
resolve(data);
})
.catch(function (e) {
getImage('https://static.jojowiki.com/images/avatars/jojowiki_'+userid+'_l.jpg')
.then(function (data) {
resolve(data);
})
.catch(function (e) {
getImage('https://static.jojowiki.com/images/avatars/jojowiki_'+userid+'_l.gif')
.then(function (data) {
resolve(data);
})
.catch(function (e) {
getImage('https://static.jojowiki.com/images/avatars/jojowiki_'+userid+'_l.jpeg')
.then(function (data) {
resolve(data);
})
.catch(function (e) {
resolve('https://static.jojowiki.com/images/avatars/default_l.gif');
});
});
});
});
});
}
function splitNamespace(pagename) {
// returns array containing namespace and pagename without namespace
var divider = pagename.search(/:[^_\s]/);
if (divider) {
var namespace = pagename.substring(0, divider);
var namespaceless = pagename.substring(divider+1);
return new Array(namespace, namespaceless);
}
return new Array('', pagename);
} // splitNamespace
function callApi(nuri, withD) {
// calls the site API and returns array containing text and image
return new Promise(function (resolve, reject) {
var text = '';
var img = '';
var orient = 'horizontal';
var extend;
var splitName = splitNamespace(nuri.apititle);
var apipage = new mw.Uri({path: mwc.wgScriptPath + '/api.php'});
var datafunc;
if (!splitName) reject();
switch (splitName[0]) {
case 'Category': // include additional text option listing members
apipage.extend({
action: 'query', titles: nuri.apititle, prop: 'extracts|pageimages', format: 'json', formatversion: 2,
redirects: false, exchars: 1200, piprop: 'thumbnail', list: 'categorymembers', cmtitle: nuri.apititle,
cmlimit: 50, pithumbsize: 200, pilicense: 'any', smaxage: 600, maxage: 600, uselang: 'content'
});
datafunc = function (item, text, img, orient) {
if (item.categorymembers && (!text || Settings.emptytext.test(text))) {
text = '<b>' + splitName[1].replace(/_/g,' ') + ':</b> ';
$.each(item.categorymembers, function(index, value) {
text = text + value.title;
if (index < item.categorymembers.length-1) {
text = text + ', ';
}
});
}
resolve(new Array(text, img, orient));
};
break;
case 'File': // get higher-quality file in case there's no text
apipage.extend({
action: 'query', titles: nuri.apititle, prop: 'extracts|pageimages', format: 'json',
formatversion: 2, redirects: false, exchars: 1200, piprop: 'thumbnail',
pithumbsize: 300, pilicense: 'any', smaxage: 600, maxage: 600, uselang: 'content'
});
datafunc = function (item, text, img, orient) {
resolve(new Array(text, img, orient));
};
break;
case 'User':
case 'UserWiki':
case 'User profile':
username = nuri.apititle.substring(nuri.apititle.search(':')+1);
if (username.search('/') > -1) username = username.substring(0, username.search('/'));
apipage.extend({
action: 'query', titles: nuri.apititle, prop: 'extracts', format: 'json',
formatversion: 2, redirects: false, exchars: 1200, list: 'users', ususers: username,
usprop: 'gender|registration|editcount', smaxage: 600, maxage: 600, uselang: 'content'
});
datafunc = function (item, text, img, orient) {
if (item.users && item.users[0]) {
if (!text || Settings.emptytext.test(text)
|| text.substring(0,26) === '<p>This is your user page.') {
text = '<b>' + item.users[0].name + '</b>';
if (item.users[0].gender) {
switch (item.users[0].gender) {
case 'male':
text = text + ' (♂)';
break;
case 'female':
text = text + ' (♀)';
break;
} // ideally pronouns would be a field
}
if (item.users[0].registration) {
var registered = new Date(item.users[0].registration);
text = text + '<br><b>Registered:</b> ' + registered.toLocaleString();
}
if (item.users[0].editcount) {
text = text + '<br><b>Edits:</b> ' + item.users[0].editcount.toLocaleString();
}
}
if ((!img || img === '') && item.users[0].userid) {
userAvatar(item.users[0].userid).then(function (data) {
resolve(new Array(text, data, orient));
});
}
else resolve(new Array(text, img, orient));
}
else resolve(new Array(text, img, orient));
};
break;
case 'Blog':
apipage.extend({
action: 'query', titles: nuri.apititle, prop: 'extracts|pageimages', format: 'json',
formatversion: 2, redirects: false, exchars: 1200, piprop: 'thumbnail',
pithumbsize: 250, pilicense: 'any', smaxage: 600, maxage: 600, uselang: 'content'
});
datafunc = function (item, text, img, orient) {
if (text) {
var vote = text.match(/<div id="Answer".*?<\/div>/);
if (vote[0]) { text = text.substring(text.search(vote[0])+vote[0].length); }
}
resolve(new Array(text, img, orient));
};
break;
case 'Interview':
case 'Help':
case 'JoJo_Wiki':
case '':
if (withD) {
apipage.extend({
action: 'query', titles: nuri.apititle, prop: 'extracts|pageimages', format: 'json',
formatversion: 2, redirects: false, exchars: 1200, explaintext: true,
exsectionformat: 'plain', piprop: 'thumbnail', pithumbsize: 250,
pilicense: 'any', smaxage: 600, maxage: 600, uselang: 'content'
});
}
else {
apipage.extend({
action: 'query', titles: nuri.apititle, prop: 'extracts|pageimages', format: 'json',
formatversion: 2, redirects: false, exchars: 1200, piprop: 'thumbnail',
pithumbsize: 250, pilicense: 'any', smaxage: 600, maxage: 600, uselang: 'content'
});
}
datafunc = function (item, text, img, orient) {
resolve(new Array(text, img, orient));
};
break;
default:
reject();
break;
}
$.getJSON(apipage).done(function(data) {
var item = data.query;
if (item.pages && item.pages[0]) {
if (item.pages[0].thumbnail) {
img = item.pages[0].thumbnail.source;
if (item.pages[0].thumbnail.width > item.pages[0].thumbnail.height) {
orient = 'vertical';
}
}
if (item.pages[0].extract && !Settings.emptytext.test(item.pages[0].extract)) {
text = item.pages[0].extract;
if (text.search('<div class="introSwitch">') > -1 || Settings.wholepage) {
apipage = new mw.Uri({path: mwc.wgScriptPath + '/api.php'});
apipage.extend({
action: 'parse', page: nuri.apititle, prop: 'text', format: 'json',
formatversion: 2, redirects: false, smaxage: 600, maxage: 600, uselang: 'content'
});
$.getJSON(apipage).done(function(data) {
var item2 = data.parse;
if (item2.text) {
text = item2.text;
}
text = processText(text, nuri);
datafunc(item, text, img, orient);
})
.fail(function(data) {
text = processText(text, nuri);
datafunc(item, text, img, orient);
});// apid.fail
}
else {
text = processText(text, nuri);
datafunc(item, text, img, orient);
}
}
else {
datafunc(item, text, img, orient);
}
}
else {
datafunc(item, text, img, orient);
}
})// apid.done
.fail(function(data) {
log('gp apid.fail', nuri, data);
Settings.RegExp.ilinks.push(nuri.truepath); // and ignore it
pp.stop(nuri.truepath);
reject();
});// apid.fail
});
} // callApi
function resetTimer (ev) {
// resets timer until preview ends
if (ev.data.el) {
if (ev.data.el.timer) clearTimeout(ev.data.el.timer);
ev.data.el.timer = setTimeout(function() {nhidePreview(ev.data.el)}, Settings.ttl);
}
} // resetTimer
function processText (text, nuri) {
// various text cleaning operations
if (text && text.length > 0) {
// preprocess (cleanup)
text = preprocess(text);
var newimg;
// cut everything past the table of contents or first header
var header = text.search(/(<div id="toc"|<h[1-4]>)/);
if (header > -1) {
text = text.substring(0, header);
}
var switcherTabber = text.match(/<div class="switcherTabber".*?">/); // TabberSwitch functionality
if (switcherTabber) {
var rawtext = text.replace(/class="([^"]*?)noexcerpt([^"]*?)"/g,'class="$1noexcerpt oo-ui-element-hidden$2"'); // hide all noexcerpt sections
text = rawtext.substring(rawtext.search('\n<div class="introSwitch">')+1); // cut the beginning templates (hopefully!)
var ns = splitNamespace(nuri.apititle);
if (ns[1]) {
ns[1] = ns[1].replace(/_/g,' '); // convert url to proper name
ns[1] = ns[1].substring(ns[1].search('/')+1, ns[1].length);
}
var imagetabs = rawtext.match(/tabcontents--(.|\n)+?class="introSwitch/);
if (imagetabs[0]) {
imagetabs = imagetabs[0].match(/tabcontents--(.|\n)+?(class="tabcontents|class="introSwitch)/g);
if (imagetabs.length == 1) {
imagetabs = imagetabs[0].match(/src=".+?\.(jpg|jpeg|png|gif)"/g);
}
else {
imagetabs = $.grep(imagetabs, function (value, index) {
imagetabs[index] = imagetabs[index].match(/src=".+?\.(jpg|jpeg|png|gif)"/);
if (imagetabs[index] === null) return false;
else {
imagetabs[index] = imagetabs[index][0];
return true;
}
});
}
}
// cut all but the first image of each tab
var switcherTabs = switcherTabber[0].match(/data-url[1-4]=".*?"/g); // find our possible names
var switcherNames = switcherTabber[0].match(/data-name[1-4]=".*?"/g); // find our possible backup names
$.each(switcherTabs, function (index, value) {
var matchName = value.substring(11, value.length-1); // get the value of the attribute
if (matchName === '') matchName = switcherNames[index].substring(12, switcherNames[index].length-1);
if (matchName === ns[1] && index < imagetabs.length) {
var tabimage = imagetabs[index]; // find image
if (tabimage) {
newimg = tabimage.substring(5, tabimage.length-1); // return image
}
if (index == 0) {
text = text.replace(/<div class="introSwitch">((.|\n)*?)<\/div>/g,'<span>$1</span>');
text = text.replace(/<div class="introSwitch2" style="display:none;">((.|\n)*?)<\/div>/g,'');
}
else {
text = text.replace(/<div class="introSwitch">(.|\n)*?<\/div>/g,'');
text = text.replace(/<div class="introSwitch2" style="display:none;">((.|\n)*?)<\/div>/g,'<span>$1</span>');
}
return false; // we change the div to a span so it won't be cut down in the coming purge
}
else {
if (index == switcherTabs.length-1) { // if this is the last data-url
text = text.replace(/<div class="introSwitch">((.|\n)*?)<\/div>/g,'<span>$1</span>');
text = text.replace(/<div class="introSwitch2" style="display:none;">((.|\n)*?)<\/div>/g,'');
} // same as above
}
});
}
else {
// actually cut everything past the table of contents or first header
header = text.search(/(<\/p>\n\n)/);
if (header > -1) {
text = text.substring(0, header+4);
}
}
// text clean up
// cut everything until the first paragraph
var para = text.search(/(<span|<p>|<b>|<i>|<u>|\n[^<\n])/);
if (para > -1) {
text = text.substring(para);
}
text = text.replace(/<a href="#.*?">\[.+?\]<\/a>/g, ''); // remove references
text = text.replace(Settings.RegExp.dtag, ''); // and misc. tags
text = text.replace(/[\n]+?/g, ' '); // we can now toss out natural line breaks (unless we put them there as br tags!)
if (text.length > 0 && text.substring(0,4) != '<!--') {
if (newimg) {
return new Array(text, newimg);
}
else return text;
}
}
return "";
}// processText
function elValidate ($el) {
// returns false if element should be ignored
var ahref = $el.attr('href'),
bstop = false;
// log('elValidate. el.h:', ahref);
if (!ahref) return false;
ahref = createUri(ahref);
// log('elValidate.uri:', ahref);
if (!ahref || (ahref.hostname !== apiUri.host) || nignoreLink(ahref.truepath)) {
return false;
}
// chk classes
if ($.isArray(Settings.RegExp.iclasses)) {
Settings.RegExp.iclasses.forEach(function(v) {
if ($el.hasClass(v)) {
log('elValidate classes', v, ahref.truepath);
// Settings.RegExp.ilinks.push(ahref.truepath);
bstop = true;
}
});
}
// log('elValidate classes', bstop);
if (bstop) return false;
// chk parents
if ($.isArray(Settings.RegExp.iparents)) {
Settings.RegExp.iparents.forEach(function(v) {
if ($el.parents(v).length) {
log('elValidate parents', v, ahref.truepath);
// Settings.RegExp.ilinks.push(ahref.truepath);
bstop = true;
}
});
}
// log('elValidate parents', bstop);
if (bstop) return false;
return true;
}// elValidate
function chkImageSrc (src) {
// is src belongs to wiki
if (!src) return false;
var url;
try {
url = new mw.Uri(src);
return (/(\.jojowiki\.com)$/.test(url.host));
}
catch (e) {
return false;
}
return false;
}// chkimagesrc
function preprocess (text) {
// prep must be non-empty array (script removing at least, added in the init)
if (!(Settings.RegExp.prep instanceof Array) || Settings.RegExp.prep.length < 1) return '';
var s = text,
$s = $('<div>').html(s);
// remove noinclude items
if (Settings.RegExp.noinclude && (Settings.RegExp.noinclude instanceof Array)) {
Settings.RegExp.noinclude.forEach(function(v){$s.find(v).remove();});
}// if RegExp.noinclude
s = $s.html();
// process exclusive items
// must be done before trash tag processing. because of reasons
if (Settings.RegExp.onlyinclude && (Settings.RegExp.onlyinclude instanceof Array)) {
/* exclusive
Settings.RegExp.onlyinclude.forEach(function (v) {
var $v = $s.find(v);
if ($v.length) $s = $v;// call it exclusive
});
s = $s.html();
*/
/* non-exclusive set */
s = Settings.RegExp.onlyinclude.map(function(v) {
var $v = $s.find(v);
if ($v.length) {
$s.find(v).remove();
return $v.map(function() {return this.outerHTML}).toArray().join();
} else {
return false;
}
})
.filter(Boolean).join() || s;
}// if RegExp.onlyinclude
Settings.RegExp.prep.forEach(function (v) {
s = s.replace(v, '');
});
return s;
}// preprocess
function createUri (href, base) {
var h;
try {
h = new mw.Uri(href.toString());
h.pathname = h.path;
h.hostname = h.host;
} catch (e) {
h = undefined;
log('createUrl.e', e);
}
if (h) {
try {
h.truepath = decodeURIComponent(h.pathname.replace(Settings.RegExp.wiki, ''));
h.interwiki = h.path.split('/wiki/')[0];
h.islocal = mwc.wgArticlePath.split('/wiki/')[0] === h.interwiki;
}
catch (e) {
h = undefined;
log('createuri decode.e', e, h, String(h));
}
}
return h;
} // createUri
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
} // escapeRegExp
function hlpaHover () {
// aHover helper
if (Settings.throttling) {
clearTimeout(Settings.throttling);
Settings.throttling = false;
}
}// hlpaHover
function aHover (ev) {
// a hover handler
ev.stopPropagation();
log('ahover ', Settings.throttling, currentEl.href);
// suppress some events
if (Settings.throttling || Settings.process) {
return false;
}
var hel = createUri($(ev.currentTarget).attr('href')) || {};
// if link already in process
var preview = $('.npage-preview');
if (currentEl.source !== ev.currentTarget) {
currentEl.source = ev.currentTarget;
}
if (hel && hel.truepath && currentEl.href == hel.truepath) {
if (preview.timer) clearTimeout(preview.timer);
return false;
}
nhidePreview(preview);
currentEl.href = hel.truepath;
currentEl.islocal = hel.islocal;
currentEl.interwiki = hel.interwiki;
currentEl.source = ev.currentTarget;
// if link determined be ignored
if (nignoreLink(currentEl.href)) {
return true;
} // if ignore link
// set coords
loc.left = ev.pageX;
loc.top = ev.pageY;
loc.clientX = ev.clientX;
loc.clientY = ev.clientY;
log('ahover ev:', ev, 'cel:', currentEl);
setTimeout(ngetPreview.bind(this, ev), Settings.delay);
return false;
} // ahover
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 (uri, div, img, force, withD) {
// preview helper
// load img and add to div
var im;
im = $('img', div);
if (!Settings.apid && !withD) {
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
}// if !apid
windowData = {href: uri.truepath, data: div, uri: uri};
ncache.push(windowData);
if (Settings.debug) window.pPreview.pdiv = d.data;
$('.npage-preview').content = windowData.data;
pp.stop(windowData.href);
} // hlpPreview
function ngetPreview (ev, forcepath, withD) {
var nuri = createUri($(currentEl.source).attr('href')) || {};
nuri.truepath = forcepath || nuri.truepath;
nuri.apititle = nuri.truepath.replace(/^\/+/g, '') || '';
if (!nuri || !nuri.truepath || nuri.apititle.length <= 0 || nuri.apititle === 'index.php'
|| nuri.apititle.substring(nuri.apititle.length-3) === '.js'
|| nuri.apititle.substring(nuri.apititle.length-4) === '.css') {
log('gp no href', ev, forcepath);
return;
}
if (!pp.start(nuri.truepath)) {
// this href already started to process
log('gp suppressed dbl processing for', nuri);
return;
}
// save bandwidth
log('gp uri: ', nuri, ' curel.href: ', currentEl.href, nuri.truepath === currentEl.href, 'd:', withD);
// withd means fallback request, that should not be cancelled early
if (!forcepath && !withD && (nuri.truepath != currentEl.href)) {
pp.stop(nuri.truepath);
return;
}
var div = $('<div>', {class: 'mw-body npage-preview'})
.append($('<div>', {class: 'npage-text npage-temp'}).text("Loading preview..."));
var ndata = ncacheOf(nuri.truepath);
log('gp x:', loc.left, 'y:', loc.top);
if (ndata) {
div.html(ndata.data.html()); // get content from cache
div.addClass(ndata.data.attr('class'));
} // if data
else div.timer = null;
div.source = currentEl.source;
$(div).off('mouseover.pp blur.pp mouseout.pp');
$(div).on('mouseover.pp', function() {
if (div.timer) clearTimeout(div.timer);
});
$(div).on('blur.pp mouseout.pp', {el: div}, resetTimer);
$(currentEl.source).off('blur.pp mouseout.pp');
$(currentEl.source).on('blur.pp mouseout.pp', {el: div}, resetTimer);
if (ndata) {
log('gp show preview', ndata);
nshowPreview(div, nuri, forcepath ? true : false);
pp.stop(nuri.truepath);
return false;
} // if data
// Prepare the waiting window
windowData = {href: nuri.truepath, data: div, uri: nuri};
nshowPreview(windowData.data, windowData.uri, forcepath ? true : false);
// get data
var apicall,
img,
iwrap = $('<img>', {src: Settings.defimage}),
twrap = $('<div>', {class: 'npage-text'}),
awrap = $('<a>', {href: ''});
callApi(nuri, withD).then(function(data) {
log('gp apip', apicall);
if (!data) {
log('gp apid.error', nuri, apicall);
Settings.RegExp.ilinks.push(nuri.truepath); // and ignore it
pp.stop(nuri.truepath);
return this;
}
if (data.length < 1) {
log('gp apid.noitem', nuri, apicall);
Settings.RegExp.ilinks.push(nuri.truepath); // and ignore it
pp.stop(nuri.truepath);
return this;
}
if (data[1] && !nignoreImage(0)) {
img = data[1];
}
if (data[0]) {
text = data[0];
if (text.length == 2) {
img = text[1];
text = text[0];
}
if (text && !Settings.emptytext.test(text)) {
text = text.replace(/\n/g,'<br>');
$(twrap).html(text);
div.append(twrap);
}
else div.addClass('npage-preview-file');
}
else div.addClass('npage-preview-file'); // add file class (show at 200px) if there is no text
if (!img && !text) {
pp.stop(nuri.truepath);
if (Settings.apid || withD) {
Settings.RegExp.ilinks.push(nuri.truepath); // and ignore it
return this;
} else {
// last try; via api.v1
return ngetPreview(ev, null, true);
}
}
awrap.html(iwrap);
awrap.attr('href',nuri.truepath);
div.prepend(awrap);
div.querySelector(".npage-temp").innerHTML = "";
if (data[2] === 'vertical') div.addClass('npage-preview-vertical');
if (img) {
hlpPreview(nuri, div, img, forcepath ? true : false);
} else { // if img
hlpPreview(nuri, div, false, forcepath ? true : false);
}// no img
// pp.stop();
return false;
})
.catch(function() {
return false;
});
return;
} // getpreview
function nshowPreview (data, target, force) {
log('sp', data, target, force);
currentEl.href = ''; // this makes sure it can pop back up on the same link!
if (!($(data.source).is(":hover"))) { nhidePreview(data); return false; } // in case the cursor already left
log('sp data:', data);
// nhidePreview();
$('.npage-preview').remove(); // remove artefacts
$('body').append($(data));
$(data.source).off('mouseover.pp');
$(data.source).on('mouseover.pp', function() {
if (data.timer) clearTimeout(data.timer);
});
// prehide data
$(data).css({left: -10000, top: -10000});
$(data).show(200, function() { // ;// fadeIn('fast');
// reposition works well with pre-set fixed data bounds
if ((loc.clientY + $(data).height()) > $(window).height()) {
loc.top -= ($(data).height() + loc.tops);
} else {
loc.top += loc.tops;
}// if top>window
if ((loc.clientX + $(data).width()) > $(window).width()) {
loc.left -= ($(data).width() + loc.lefts);
} else {
loc.left += loc.lefts;
}// if left>window
// move preview to target location
log('sp loc', loc);
loc.left = loc.left > 0 ? loc.left : 0;
loc.top = loc.top > 0 ? loc.top : 0;
$(data).css({
left: force ? $('body').scrollLeft() : loc.left,
top: force ? $('body').scrollTop() : loc.top});
mw.hook('ppreview.show').fire(data);
});// data.show.done
} // showpreview
function nhidePreview (data) {
clearTimeout(data.timer);
$(data.source).off('mouseover.pp mouseout.pp');
$(data.source).on('mouseover.pp', aHover);
//$(data).remove();
// clear throttling
$(data).css('visibility', 'hidden');
hlpaHover();
} // 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 < 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;
} // nignorelink
function ncacheOf (href) {
// returns cached obj or null
if (ncache.length > Settings.csize) ncache = []; // clear cache
for (var i = 0, len = ncache.length; i < len; i++) {
if (ncache[i].href === href) {
log('cache found:', href, 'data:', ncache[i].data);
// window.ppcdata = ncache[i];
return ncache[i];
}
}
return null;
} // ncacheof
})(jQuery);