MediaWiki:Tooltips.js

/** * http://dev.wikia.com/wiki/MediaWiki:Tooltips.js */

var tooltips = tooltips || { debug: false,

api: false, types: [], classes: ['basic-tooltip', 'advanced-tooltip'], advancedCounter: 1,

events: [], timeouts: [],

offsetX: 20, offsetY: 20, waitForImages: false,

init: function { if ($(document.body).hasClass('mw-special-InfoboxBuilder')) return; if (location.search.search('ttdebug=true') != -1 || (typeof tooltips_debug != 'undefined' && tooltips_debug)) tooltips.debug = true; var href = $('link[rel="canonical"]').attr('href') if (typeof href == 'undefined' || !href) { console.log('Tooltips: script couldn\'t find required link[rel="canonical"]  tag'); tooltips.disabled = true; return false; }   href = href.split('/wiki/'); tooltips.api = href[0] + '/api.php?format=json&action=parse&disablepp=true&prop=text&title=' + href[1]; if (mw.util.getParamValue('uselang')) tooltips.api += '&uselang=' + mw.util.getParamValue('uselang'); tooltips.api += '&text=';

tooltips.types['basic-tooltip'] = {}; tooltips.types['advanced-tooltip'] = {};

if (!tooltips.config) { console.log('Tooltips: missing config'); tooltips.disabled = true; return false; }

var content = $('#WikiaMainContent') if (!content.length) content = $('#mw-content-text')

if ($('#tooltip-wrapper').length == 0) $(' ').appendTo(content); if ($('#tooltip-storage').length == 0) $(' ').append(' Lorem ipsum dolor sit amet ').appendTo(content);

$('#tooltip-wrapper') .css({       'margin': '0px',        'position': 'fixed',        'height': 'auto',        'min-height': '0'      }) .hide

$('#tooltip-storage') .css({       'height': '0px',        'min-height': '0',        'visibility': 'hidden',        'overflow': 'hidden',        'position': 'static'      })

$('#tooltip-basic-tooltip').data('type', 'basic-tooltip');

tooltips.applyTooltips(document)

mw.hook('wikipage.content').add(function(elem) {     tooltips.applyTooltips($(elem));    });

if (typeof tooltips.events == 'string') tooltips.events = [tooltips.events] for (var x = 0; x < tooltips.events.length; x++) { $(window).on(tooltips.events[x], function(ev, elem) {       tooltips.applyTooltips(elem || this)      }) }

if (tooltips.debug) { $('#tooltip-wrapper').css({       'background-color': 'rgba(255,0,0,0.2)'      }) $('#tooltip-storage').css({       'background-color': 'rgba(0,255,0,0.2)',        'height': '500px',        'overflow-y': 'scroll',        'visibility': 'visible'      }) } },  config: function { if (typeof tooltips_list != 'undefined') { $(tooltips_list).each(function(i, v) {       tooltips.addType(v)      }); }   if (typeof tooltips_config == 'object') { tooltips.offsetX = tooltips_config.offsetX || tooltips.offsetX; tooltips.offsetY = tooltips_config.offsetY || tooltips.offsetY; tooltips.waitForImages = (tooltips_config.waitForImages || tooltips.waitForImages) && true; tooltips.events = tooltips_config.events || tooltips.events; }

return true }, applyTooltips: function(elem) { $(elem).find('.' + tooltips.classes.join(', .')).each(function {     $this = $(this)      if ($this.hasClass('tooltips-init-complete')) return;

$this.find('*').removeAttr('title'); $this.mouseover(tooltips.handlers.mouseOver); $this.mouseout(tooltips.handlers.mouseOut); $this.mousemove(tooltips.handlers.mouseMove);

$this.data('tooltip-contents', $(this).attr('title')); $this.removeAttr('title');

tooltips.advancedTooltip($this);

$(this).addClass('tooltips-init-complete'); }); },  advancedTooltip: function(elem) {    elem = $(elem)    if (!elem.hasClass('advanced-tooltip')) return;    var tips = elem.find('.tooltip-contents')    if (!tips.length) return;    var tip = $(' ').attr('id', 'tooltip-advanced-tooltip-' + tooltips.advancedCounter).appendTo('#tooltip-storage').data('type', 'advanced-tooltip').append($(tips[0]).contents).each(tooltips.calcSize);    tips.remove;    elem.data('tooltip-id-advanced-tooltip', tooltips.advancedCounter);    tooltips.advancedCounter++;  },  addType: function(tt) {    if (typeof tooltips.types[tt.classname] == 'undefined') {      var obj = {}

if (typeof tt.parse == 'string' || typeof tt.parse == 'function') var parse = tt.parse; else var parse = false; if (typeof tt.text == 'string' || typeof tt.text == 'function') var text = tt.text; else var text = false;

if (parse) { obj.text = parse; obj.parse = true; } else if (text) { obj.text = text; obj.parse = false; } else return;

if (typeof obj.text == 'string') obj.parameters = tooltips.getParameters(obj.text); else obj.parameters = [];

if (typeof tt.delay == 'string' || typeof tt.delay == 'number') obj.delay = parseInt(tt.delay); else obj.delay = false; if (typeof tt.onParsed == 'function') obj.onParsed = tt.onParsed; if (typeof tt.onShow == 'function') obj.onShow = tt.onShow; if (typeof tt.onHide == 'function') obj.onHide = tt.onHide;

tooltips.types[tt.classname] = obj; if (tooltips.classes.indexOf(tt.classname) == -1) tooltips.classes.push(tt.classname) } else { if (typeof tt.delay == 'string' || typeof tt.delay == 'number') tooltips.types[tt.classname].delay = parseInt(tt.delay); if (typeof tt.onParsed == 'function') tooltips.types[tt.classname].onParsed = tt.onParsed; if (typeof tt.onShow == 'function') tooltips.types[tt.classname].onShow = tt.onShow; if (typeof tt.onHide == 'function') tooltips.types[tt.classname].onHide = tt.onHide; } },  getParameters: function(text) { var list = [] var matches = text.match(/<#\s*[a-z0-9_\-]+?\s*#>/gi) if (matches) { for (var x = 0; x < matches.length; x++) { list.push(/<#\s*([a-z0-9_\-]+?)\s*#>/i.exec(matches[x])[1]) }   }    return list }, getAPI: function(text) { return tooltips.api + encodeURIComponent(text) }, getText: function(type, elem) { if (typeof tooltips.types[type].text == 'function') { var text = tooltips.types[type].text($(elem)[0]) } else { var text = tooltips.types[type].text for (var x = 0; x < tooltips.types[type].parameters.length; x++) { var param = tooltips.types[type].parameters[x] var value = $(elem).data(param) if (typeof value == 'undefined') value = '' var rx = new RegExp('<#\\s*' + param.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + '\\s*#>', 'g') text = text.replace(rx, value) }   }    return text }, getTooltip: function(type, elem) { elem = $(elem) if (elem.data('tooltip-id-' + type)) return $('#tooltip-' + type + '-' + elem.data('tooltip-id-' + type))

var text = tooltips.getText(type, elem) var id = tooltips.hash(text) elem.data('tooltip-id-' + type, id)

var tip = $('#tooltip-' + type + '-' + elem.data('tooltip-id-' + type)) if (tip.length) return tip;

tip = $(' ').attr('id', 'tooltip-' + type + '-' + id).appendTo('#tooltip-storage').data('type', type).addClass('tt-' + type)

tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]) tooltips.sameWidth

if (!tooltips.types[type].parse) { tip.html(text).each(tooltips.calcSize) tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]) tooltips.sameWidth } else { tip.addClass('tooltip-loading') var api = tooltips.getAPI(text) if (tooltips.debug) tip.html('' + api + ' ') tip.attr('title', api) $.ajax({       url: api,        dataType: 'json',        context: tip,        success: function(data, textStatus, jqXHR) {          $(this).html(data['parse']['text']['*']).each(tooltips.calcSize)          tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1])          tooltips.sameWidth          var images = $(this).find('img')          images.fadeTo(0, 0).one('load', function { if (tooltips.waitForImages) { $(this).fadeTo(0, 1); $(this).addClass('image-loaded') tip = $(this).closest('.main-tooltip') if (tip.find('img').length == tip.find('img.image-loaded').length) { tip.removeClass('tooltip-loading').each(tooltips.calcSize) tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]) tooltips.sameWidth }           } else $(this).fadeTo(100, 1); })         if (tooltips.waitForImages) {            if (images.length == 0) {              $(this).removeClass('tooltip-loading').each(tooltips.calcSize)            }          } else {            $(this).removeClass('tooltip-loading').each(tooltips.calcSize)          }          var type = $(this).data('type') || false          if (type && typeof tooltips.types[type].onParsed == 'function') {            tooltips.types[type].onParsed.call(this);            tip.each(tooltips.calcSize)          }          if ($(this).find('a.new').length > 0) $(this).addClass('has-redlinks')          tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1])          tooltips.sameWidth        }      }); }   return tip }, getBasicTooltip: function(elem) { return $("#tooltip-basic-tooltip").html($(elem).data('tooltip-contents').replace(/\\n/g, ' ')).each(tooltips.calcSize); }, getAdvancedTooltip: function(elem) { return $("#tooltip-advanced-tooltip-" + $(elem).data('tooltip-id-advanced-tooltip')); }, getTooltips: function(elem) { elem = $(elem) var classes = elem.attr('class').split(' ') var tips = [] for (var i = 0; i < classes.length; i++) { var tip = false; if (classes[i] == 'advanced-tooltip') tip = tooltips.getAdvancedTooltip(elem); else if (classes[i] == 'basic-tooltip') tip = tooltips.getBasicTooltip(elem); else if (typeof tooltips.types[classes[i]] != 'undefined') tip = tooltips.getTooltip(classes[i], elem); if (tip) tips.push(tip[0]); }   return $(tips) }, setOwnWidth: function { $this = $(this) if (typeof $this.data('width') != 'undefined') $this.css('width', $this.data('width') + 'px') else $this.css('width', '') }, calcSize: function { $this = $(this) $this.css('position', 'absolute') var temp = $this.css('width') $this.css('width', '') $this.data('width', $this.width); $this.data('height', $this.height); $this.data('outerwidth', $this.outerWidth(true)); $this.data('outerheight', $this.outerHeight(true)); $this.css('width', $this.data('width') + 'px') $this.css('position', '') $this.css('width', temp) }, sameWidth: function { if ($("#tooltip-wrapper").find('.main-tooltip').length == 1) { $("#tooltip-wrapper").find('.main-tooltip').each(tooltips.setOwnWidth) } else { var width = 0; $("#tooltip-wrapper").find('.main-tooltip').each(function {       width = Math.max(width, $(this).data('width') || 0);      }); $("#tooltip-wrapper").find('.main-tooltip').each(function {       $(this).css('width', width + 'px');      }); } },  wrapperPosition: function(mouseX, mouseY) { var tipH = parseInt($("#tooltip-wrapper").css('padding-top')) + parseInt($("#tooltip-wrapper").css('padding-bottom')); var tipW = 0;

$("#tooltip-wrapper").find('.main-tooltip').each(function {     if (typeof $(this).data('outerheight') != 'undefined') tipH += $(this).data('outerheight');    }); $("#tooltip-wrapper").find('.main-tooltip').each(function {     if (typeof $(this).data('outerwidth') != 'undefined') tipW = Math.max(tipW, $(this).data('outerwidth') + parseInt($("#tooltip-wrapper").css('padding-left')) + parseInt($("#tooltip-wrapper").css('padding-right')));    });

var coordX = tooltips.offsetX + mouseX; var coordY = tooltips.offsetY + mouseY;

var toRight = $(window).width - coordX;

if ($("#tooltip-wrapper").css('position') == 'fixed') { coordX = coordX - $(window).scrollLeft; coordY = coordY - $(window).scrollTop; coordY = Math.min(coordY, $(window).height - tipH - $('#WikiaBarWrapper').height); } else { coordY = Math.min(coordY, $(window).height - tipH - $('#WikiaBarWrapper').height + $(window).scrollTop); }   if (toRight >= tipW) $("#tooltip-wrapper").css({      left: coordX + 'px',      top: coordY + 'px'    }); else $("#tooltip-wrapper").css({     left: coordX - tipW - tooltips.offsetX * 2 + 'px',      top: coordY + 'px'    }); }, handlers: { mouseOver: function(e) { tooltips.lastKnownMousePos = [e.pageX, e.pageY] tooltips.wrapperPosition(e.pageX, e.pageY)

var tips = tooltips.getTooltips(this) $("#tooltip-wrapper").prepend(tips).show; tooltips.sameWidth

var handle = this tips.each(function {       var $this = $(this);        var type = $(this).data('type') || false;

$this.show; if (type && typeof tooltips.types[type] != 'undefined' && tooltips.types[type].delay) { $this.hide tooltips.timeouts[$(this).attr('id')] = setTimeout(function {           $this.show;            if (type && typeof tooltips.types[type].onShow == 'function') tooltips.types[type].onShow.call($this[0], handle);          }, tooltips.types[type].delay) } else if (type && typeof tooltips.types[type].onShow == 'function') tooltips.types[type].onShow.call(this, handle); });   },    mouseOut: function(e) {      tooltips.lastKnownMousePos = [e.pageX, e.pageY]      tooltips.wrapperPosition(e.pageX, e.pageY)

var handle = this $("#tooltip-wrapper").hide $("#tooltip-wrapper").find('.main-tooltip').appendTo('#tooltip-storage').each(function {       var type = $(this).data('type') || false;        if (type && typeof tooltips.types[type].onHide == 'function') tooltips.types[type].onHide.call(this, handle);        $(this).show        clearTimeout(tooltips.timeouts[$(this).attr('id')])        delete tooltips.timeouts[$(this).attr('id')]      }); },   mouseMove: function(e) { tooltips.lastKnownMousePos = [e.pageX, e.pageY] tooltips.wrapperPosition(e.pageX, e.pageY) }, },  hash: function(text) { /* Source: http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/ */ var hash = 0, i, char; if (text.length == 0) return hash; for (i = 0, l = text.length; i < l; i++) { char = text.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; // Convert to 32bit integer }   return hash; }, }

mw.loader.using('mediawiki.util').then(function { tooltips.init; });