MediaWiki:Lord of the tooltips.js

From Lotro-Wiki.com
Jump to navigation Jump to search

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.
/*
   ITEMTOOLTIPS

   This is an awesome script from http://www.wowpedia.org/User:Pcj with enhancements by me (EoD)

   A rough idea how it works (stuff in brackets should be removed later on):
   -Add mouseover behaviour to all ajaxttlink classes
   -Add 2 divs (with the ids #tfbx, #ttfbx) at the end of the page which are actually hidden
   -On mouse over, check if the link has already been loaded
    -true: put the cached content into #tfbx
    -false: load the page into #tfbx but only the part inside of <div class="tooltip-content">...</div>
   -when loading has finished cache the content
   -if mouse is still on the link: display the (now) cached content, but move it to the mouse-pointer so it can be displayed
   -if mouse is moved off the link: do nothing

Some tags you might want to know:
   <span class="ajaxttlink">This one uses the title of the parent tag and creates a popup out of it</span>
   <span class="disablett">If used *inside* an ajaxttlink, it will disable the popup</span>

   <span class="tttemplatelink">This creates a popup, with this text and</span><span style="display:none;">with this popup text</span>
     This might change a bit in the future

   If autoItemTooltipsOn is enabled:
     <a href="http://www.example.com/index.php/Item:XXX">An A-tag with a href containing the value "index.php/Item:" will automatically add an ajaxttlink inside</a>

*/

article = "";

// See [[Help:Tooltips]]
// default setting to turn tooltips on
var lordTooltipsOn = true;
var autoItemTooltipsOn = true;
var autoTooltipsOn = true;
var offsetY = 10;
var offsetX = offsetY;

// This checks if the script is included on another page outside of lotro-wiki.com
var external = window.location.hostname == "lotro-wiki.com" ? false : true;
/*
 * The url where mediawiki's index.php is located.
 * If unsure, set the following variable to ""
 *
 * Examples:
 *    If your wiki is on the domain www.example.com and your script isn't:
 *        If http://www.example.com/index.php:         extURL = "http://www.example.com";
 *        If http://www.example.com/wiki/index.php:    extURL = "http://www.example.com/wiki";
 *    If your wiki AND the script is on 'www.example.org':
 *        If http://www.example.org/index.php:         extURL = "";
 *        If http://www.example.org/wiki/index.php:    extURL = "/wiki";
 */
var extURL = external ? "https://lotro-wiki.com" : "";

/*
 * Allow users to specify an external db to change links to.
 * Expects a path where the wiki pagename can be appended.
 *
 * Examples:
 *    If you use plain mediawiki paths:       extDB = "/index.php?title="
 *    If you use wikipedia-like paths:        extDB = "/index.php/"
 *
 */
var extDB = extURL + (external ? "/wiki/" : "/wiki/");


var $tfb; //this is the actual displayed frame, it contains the content between two "tooltip-content" tags.
var $ttfb; //called "template tfb" used for quicktemplates, it automatically adds the "tooltip-content" tags so they can be displayed
var $htt; //called "hidden tooltip"
var activeHoverLink = null;
//We disable caching on external fetching (caching feature still missing)
var tipCache = external ? null : new Object();



/*
 * Error messages
 */

var INTERNAL_ERROR = '<div class="tooltip-content tooltip-error"><b>Error</b><br /><i>"DATA"</i><br />This target either has no tooltip<br />or was not intended to have one.</div>'
var INTERNAL_LOADING = '<div class="tooltip-error" style="position:fixed; top: CLIENT_Ypx; left: CLIENT_Xpx; visibility: visible;">Loading...</div>';
var EXTERNAL_LOADING = '<div class="tooltip-error" style="position:fixed; top: CLIENT_Ypx; left: CLIENT_Xpx; visibility: visible;">Loading from ' + extURL + '...</div>';

// hides the tooltip
function hideTip() {
    $tfb.html("").removeClass("tooltip-ready").addClass("hidden").css("visibility", "hidden");
    activeHoverLink = null;
}

// displays the tooltip

function displayTip(e) {
    $htt.not(":empty").removeClass("hidden").addClass("tooltip-ready");
    moveTip(e);
    $htt.not(":empty").css("visibility", "visible");
    moveTip(e);
}

// moves the tooltip

function moveTip(e) {
    $ct = $htt.not(":empty");
    var newTop = e.clientY + ((e.clientY > ($(window).height() / 2)) ? -($ct.innerHeight()) : offsetY);
    var newLeft = e.clientX + ((e.clientX > ($(window).width() / 2)) ? -($ct.innerWidth() + offsetX) : offsetX);
    if (newTop < 0) {
        newTop = 0;
    }
    else if (newTop + $ct.innerHeight() + offsetY > $(window).height()) {
        newTop = $(window).height() - ($ct.innerHeight() + offsetY);
        //we want to prioritizes the top of the popup being in the window, instead of the bottom
        if (newTop < 0) {
            newTop = 0;
        }
    }
    $ct.css({
        "position": "fixed",
        "top": newTop + "px",
        "left": newLeft + "px"
    });
}

// AJAX tooltips

function showTip(e) {
    var $t = $(this);
    activeHoverLink = $t;
    $p = $t.parent();
    if ($p.hasClass("selflink") == false) {
        $t.removeAttr("title");
        $p.removeAttr("title");
        //First decode all encoded characters and then re-encode everything. This allows mixed en/decoded links.
        var url = extURL + "/index.php?title=" + encodeURIComponent(decodeURIComponent($t.data("tt").replace(/ /g, "_")));
        //There is no caching for external sites implemented (yet)!
        if (external) {
            $tfb.html(EXTERNAL_LOADING);

            fullurl = url + '&action=view&printable=yes';
            //We have registered an event handler for the loading event
            //so we just change the src to trigger that event
            $tfb.attr('src', fullurl);
            //Remove caching after 10s of loading.
        } else if (tipCache[url] != null) {
            $tfb.html(tipCache[url]);
            console.log('Lord of the tooltips.js: Found cached entry: ' + tipCache[url]);
            displayTip(e);
        } else {
            $tfb.html(INTERNAL_LOADING.replace("CLIENT_X", e.clientX).replace("CLIENT_Y", e.clientY));
            //We put the "Loading..." into the cache, to avoid multiple fetchings
            tipCache[url] = $tfb.html();

            fullurl = url + '&action=render div.tooltip-content';
            $tfb.load(fullurl, function(responseText, textStatus, XMLHttpRequest) {
                if (textStatus == "timeout") {
                    //Fetching has timed out, so we remove the cached "Loading..." entry (hence enable another try)
                    clearCache(url);
                } else if ($tfb.html() == "" || textStatus != "success") {
                    //we want to use the same position value as the parent tooltip div (fixes the problem of a very long black box)
                    tipCache[url] = INTERNAL_ERROR.replace("DATA", decodeURIComponent($t.data("tt")));
                } else {
                    $tfb.find(".tooltip-content").css("display", "");
                    tipCache[url] = $tfb.html();
                }
                if ($t == activeHoverLink) {
                    $tfb.html(tipCache[url]);
                    displayTip(e);
                }
            });
        }
    }
}

//This function removes a cached "Loading" entry.

function clearCache(url) {
    if (tipCache[url] != null) {
        //Cache is not empty, let's see if we are still loading.
        if (tipCache[url].indexOf("Loading") != -1) {
            tipCache[url] = null;
        }
    }
}

function itfb_request() {
    if ($tfb.attr("src") != null) {
        //alert('Requesting the tooltip-content from "'+$tfb.attr("src")+'"');
        //$tfb[0].contentWindow.postMessage('give me the tooltip-content!', $tfb.attr("src"));
        console.log('Lord of the tooltips.js: Requesting "'+$tfb.attr("src")+'" to loose weight');
        $tfb[0].contentWindow.postMessage('loose weight!', $tfb.attr("src"));
    }
}

function itfb_receiver(e) {
    //alert("Receiver: " + e.origin);
    if (e.origin != extURL) {
        return;
    }

    console.log("Lord of the tooltips.js: Received e.data: " + (e.data === null ? "null" : e.data) );
    if (e.data.substring(0, 8) == "height: ") {
        //alert("resizing to: "+e.data.replace(/height: (.*)/, "$1"));
        $tfb.height(e.data.replace(/height: (.*)/, "$1") + "px");
    } else {
        //This is not used (yet)!
        $tfb.html(e.data);
        tipCache[$tfb.attr("src").replace(/&action=view&printable=yes/, "")] = $tfb.html();
    }
    displayTip(e);
}

// quick tooltips

function hideTemplateTip() {
    $ttfb.html("").removeClass("tooltip-ready").addClass("hidden");
}

function showTemplateTip(e) {
    $ttfb.html('<div class="tooltip-content">' + $(this).next().html() + '</div>');
    displayTip(e);
}

function bindTT() {
    $t = $(this);
    $p = $t.parent();
    if ($p.hasClass("selflink") == false) {
        $t.data("tt", encodeURIComponent(decodeURIComponent($p.attr("title").replace("/wiki/", "").replace(" (page does not exist)", "").replace(/ /g, "_") )) ).hover(showTip, hideTip).mousemove(moveTip);
        fullextURL = extDB + $t.data("tt");
        $p.attr("href", fullextURL);
    }
}

function addTT() {
    $t = $(this);
    $p = $t.parent();
    $gp = $p.parent();
    if ($gp[0].tagName.toLowerCase() == "span" && $gp[0].outerHTML.includes("span typeof=\"mw:File\"")) {
        // prevent unwanted tooltips
        if(this.className != "mw-file-description" && !this.href.includes("wiki/LOTRO_Point") && !this.href.includes("wiki/Commendation")) { 
             $(this).wrapInner('<span class="ajaxttlink"></span>');
             $(this).attr("title", $(this).attr("href").replace(/.*\/(Item:.*)/, "$1"));
        }
    }
}

function addTTItem() {
    $(this).wrapInner('<span class="ajaxttlink"></span>');
    $(this).attr("title", $(this).attr("href").replace(/.*\/(Item:.*)/, "$1"));
}

// check to see if it is active then do it

function ttMouseOver() {
    if (lordTooltipsOn) {
        //we are using tfbx instead of tfb to avoid collisions with Eleazaros itemtooltip
        //if we have external popups we use an iframe inside of tfbx
        if (external) {
            $(article).append('<iframe id="tfbx" scrolling=no frameborder=0 class="htt"></iframe><div id="templatetfbx" class="htt"></div>');
            $("#tfbx").load(itfb_request); //We register an event for "iframe loading has finished"
            window.addEventListener('message', itfb_receiver, false);
        } else {
            $(article).append('<div id="tfbx" class="htt"></div><div id="templatetfbx" class="htt"></div>');
        }

        $tfb = $("#tfbx");
        $ttfb = $("#templatetfbx");
        $htt = $("#tfbx,#templatetfbx");


        //execute addTT on those links which link to "Item:" and (have not any descendent object or have not any descendent with an ajaxttlink class)
        if (autoTooltipsOn) $(article + " a[href*='wiki/']:not(:has(span.ajaxttlink))").each(addTT);
        if (autoItemTooltipsOn) $(article + " a[href*='wiki/Item:']:not(:has(span.ajaxttlink))").each(addTTItem);
        $(article + " span.ajaxttlink:not(:has(span.disablett))").each(bindTT);
        $(article + " span.tttemplatelink").hover(showTemplateTip, hideTemplateTip).mousemove(moveTip);
    }
}

$(function() {
    article = "#bodyContent";
    ttMouseOver();
});

/* END OF ITEMTOOLTIPS */