nicetitle.js

/* This version of nicetitles was originally a mix between the
   versions found at http://neo.dzygn.com/archive/2003/12/nicer-titles
   and http://kryogenix.org/code/browser/nicetitle/. I've updated the
   helper functions using some ideas from http://www.quirksmode.org,
   rewritten or cleaned up most of the code and added some new
   features.

   Do not forget to add a version of the addEvent function somewhere.


   Boris Yakobowski, October 2007
   http://www.yakobowski.org/nicetitles.html

   v1.0: initial release, April 2007
   v1.1: corrected a viewport bug under Safari, October 2007
*/

var XHTMLNS = "http://www.w3.org/1999/xhtml";

function NiceTitles() {
    if (!document.createElement || !document.getElementsByTagName) return;
    // add namespace methods to HTML DOM; this makes the script work in both
    // HTML and XML contexts.
    if(!document.createElementNS) {
        document.createElementNS = function(ns,elt) {
            return document.createElement(elt);
        }
    }

    var delay = 350;

    initA();
    initImg();


/* Internal variables */

    var current_float;
    var last_node = null;
    var do_delay = true;


/* Initialization of the floating elements */

    /* a tags with titles are displayed as nicetitles */
    function initA () {
        /* We do not use documents.links so as to see a tags with
           empty href */
        var links = document.getElementsByTagName("a");

        for (var i=0; i<links.length; i++) {
            var lnk = links[i];
            if (lnk.title) {
                lnk.setAttribute('nicetitle', lnk.title);
                lnk.removeAttribute('title');
                attach_handlers(lnk);
            }
        }
    }

    /* img tags with class thumb are displayed as thumbnails */
    function initImg() {
        var imgs = document.getElementsByTagName("img");

        for (var i=0; i<imgs.length; i++) {
            var img = imgs[i];
            if (img.className.match('thumb')) {
                attach_handlers(img);
            }
        }
    }


/* Handlers */

    function attach_handlers(n) {
        addEvent(n, "mouseover", showFloat);
        addEvent(n, "focus",     showFloat);
        addEvent(n, "mouseout",  hideFloat);
        addEvent(n, "blur",      hideFloat);
        addEvent(n, "mousemove", repositionFloat);
    }


    function showFloat (e) {
        if (current_float) hideFloat(current_float);

        var d = document.createElementNS(XHTMLNS,"div");

        if (this.nodeType == 1 && this.tagName == "IMG" &&
              this.className.match('thumb'))
            createThumbnail(d, this);
        else
            createNiceTitle(d, this);

        /* We will display the floating element hidden, so that
           we can compute its size and see if it fits within the window */
        d.style.visibility = 'hidden';
        /* We prevent the nicetitle from appearing at the bottom of
           a document, which might temporarily create scroll bars */
        d.style.top = '0px';
        document.body.appendChild(d);
        current_float = d;

        positionFloat(e, this);

        if (do_delay)
            /* Displays the float with some delay */
            setTimeout(function() {
                    d.style.visibility = 'visible';
                    do_delay=false;},
                delay);
        else
            d.style.visibility = 'visible';

    }

    function repositionFloat(e){
        positionFloat(e, this);
    }

    function hideFloat(e) {
        if (current_float) {
            document.body.removeChild(current_float);
            current_float = null;

            /* If no float is displayed for 300ms, we require
               the following one to be displayed with a delay */
            setTimeout(function() {
                    if (!current_float) do_delay=true;},
                300);
        }
    }


/* Contents of the floating elements */

    function createThumbnail (d, img) {
        if (last_node != img) do_delay = true;
        last_node = img;

        d.className = "floating-thumb";
        d.appendChild(img.cloneNode(false));

        d.offset = {x : -25, y : 30};
    }

    function createNiceTitle (d, n) {
        /* The focus can have been captured by a subnode (sup, em...)
           of the 'a' node. We first retrieve the 'a' node itself */
        lnk = getParent(n, "A");

        if (last_node != lnk) do_delay = true;
        last_node = lnk;

        d.className = "nicetitle";

        var p1 = document.createElementNS(XHTMLNS, "p");
        p1.className = "titletext";
        p1.appendChild(document.createTextNode(lnk.getAttribute("nicetitle")));
        d.appendChild(p1);

        /* If the link points to an url, we display it */
        if (lnk.href) {
            var p2 = document.createElementNS(XHTMLNS,"p");
            p2.className = "destination";
            p2.appendChild(document.createTextNode(lnk.href));
            d.appendChild(p2);
        } else if (lnk.name) {
        /* Otherwise, we display the name of the lnk, if it exists */
            var p2 = document.createElementNS(XHTMLNS,"p");
            p2.className = "name";
            p2.appendChild(document.createTextNode('#' + lnk.name));
            d.appendChild(p2);
        }

        d.offset = {x : -15, y : 35};
    }


/* Position of the floating elements */

    function positionFloat(e, n){
        if (!current_float) return;
        var e = window.event ? window.event : e;
        var viewport = getViewport();

        /* Left top coordinates of the float, before any correction */
        var float_lt;
        if(e.type == "focus")
            float_lt = getNodePosition(n);
        else /* The event should be mouse-related */
            float_lt = {x : viewport.x + e.clientX,
                        y : viewport.y + e.clientY};

        var float_l = float_lt.x + current_float.offset.x;
        var float_t = float_lt.y + current_float.offset.y;

        /* Dimensions of the float */
        var float_w = current_float.offsetWidth;
        var float_h = current_float.offsetHeight;

        /* Right down coordinates of the float, before corrections */
        var float_r = float_l + float_w;
        var float_d = float_t + float_h;

        /* Coordinates of the right down corner of the window */
        var window_r = viewport.width +  viewport.x;
        var window_d = viewport.height + viewport.y;

        /* Correct the position if we overflow */
        if(float_r + 10 >= window_r)
            float_l = window_r - float_w - 10;
        if(float_d + 10 >= window_d)
            float_t = window_d - float_h - 10;

        /* If the mouse is under the float, we shift it upwards */
        if (e.type != "focus" &&
                float_t-5 <= float_lt.y &&
                float_lt.y <= float_t + float_h+5)
            float_t = float_lt.y - float_h - 20;

        current_float.style.left = float_l + "px";
        current_float.style.top =  float_t + "px";
    }
}
addEvent(window, 'load', NiceTitles);


function getParent(el, pTagName) {
    if (el == null) return null;
    else if (el.nodeType == 1 && el.tagName == pTagName)
        return el;
    else
        return getParent(el.parentNode, pTagName);
}

/* See http://www.quirksmode.org/viewport/intro.html and
   http://www.quirksmode.org/viewport/compatibility.html */
function getViewport(){
    var width = height = 0;
    var x  = y = 0;

    if (self.innerHeight) { // all except Explorer
	width = self.innerWidth;
	height = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
        // Explorer 6 Strict Mode
        width = document.documentElement.clientWidth;
        height = document.documentElement.clientHeight;
    }
    else if (document.body) { // other Explorers
	width = document.body.clientWidth;
	height = document.body.clientHeight;
    }

    if (self.pageYOffset) { // all except Explorer
	x = self.pageXOffset;
	y = self.pageYOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {
	// Explorer 6 Strict
	x = document.documentElement.scrollLeft;
	y = document.documentElement.scrollTop;
    } else if (document.body) { // all other Explorers
	x = document.body.scrollLeft;
	y = document.body.scrollTop;
    }

    return {width : width, height : height, x : x, y : y };
}


/* See http://www.quirksmode.org/js/findpos.html for some explanations */
function getNodePosition(obj){
    var x = y = 0;

    do {
        if(obj.offsetLeft){x += obj.offsetLeft}
        if(obj.offsetTop ){y += obj.offsetTop}
    } while((obj = obj.offsetParent));

    return {x : x, y : y};
}

Generated by GNU enscript 1.6.4.