
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * Nontoxic JS Library
 *
 * @package    indiemerch
 * @subpackage indiemerchandising.com
 * @author     Nontoxic Group <thegroup@nontoxicgroup.com>
 * @copyright  2005-2008 Indie Merchandising, LLC. ALL RIGHTS RESERVED
 * @version    SVN: $Id: nontoxic.js 5059 2008-05-12 16:13:45Z zero $
 */

/***************************** NONTOXIC LIBRARY *******************************/
// {{{ Nontoxic

// {{{ constructor
/**
 * Nontoxic lib constructor
 */
function Nontoxic()
{
}

// }}}
// {{{ getDOMElement()

/**
 * Get an element by its ID
 *
 * @param  string elementID
 * @return HTML_Element
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.getDOMElement = function(elementID)
{
    if(document.getElementById){
        return document.getElementById(elementID);
    } else if (document.all) {
        return document.all.namedItem(elementID);
    } else {
        return null;
    }
}

// }}}
// {{{ DOMElementHide()

/**
 * Hide an element
 *
 * @param HTML_Element e
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.DOMElementHide = function(o)
{
    if (document.getElementById || document.all) {
        o.style.display = 'none';
        o.style.visibility = 'hidden';
        o.style.hidden = 'none';
    } else if (document.layers) {
        o.visibility = 'hidden';
    }
}

// }}}
// {{{ DOMElementShow()

/**
 * Show an element
 *
 * @param HTML_Element e
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.DOMElementShow = function(o)
{
    o.style.visibility = 'visible';
    o.style.display = 'block';
    o.visibility = 'visible';
}

// }}}
// {{{ addEvent()

/**
 * Add an event listener to an element
 *
 * Written by Scott Andrew
 * found in "Enhancing Structural Markup with JavaScript" by Simon Willison
 * http://www.sitepoint.com/article/structural-markup-javascript
 *
 * @param  HTML_Element obj    the element
 * @param  string       evType the event type('click', 'blur', etc)
 * @param  function     fn     the function to attatch
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.addEvent = function(obj, evType, fn)
{
    if (obj.addEventListener){
        obj.addEventListener(evType, fn, true);
        return true;
    } else if (obj.attachEvent){
        var r = obj.attachEvent("on"+evType, fn);
        return r;
    } else {
        return false;
    }
}

// }}}
// {{{ getEventTarget()

/**
 * Get the target node from an event
 *
 * Written by Peter-Paul Koch
 * http://www.quirksmode.org/js/events_properties.html
 *
 * @param  Event        e the event object
 * @return HTML_Element the target element
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.getEventTarget = function(e) {

    var targ;

    if (!e) {
        var e = window.event;
    }

    if (e.target) {
        targ = e.target;
    } else if (e.srcElement) {
        targ = e.srcElement;
    }

    // defeat Safari bug
    if (targ.nodeType == 3) {
        targ = targ.parentNode;
    }

    return targ;
}

// }}}
// {{{ findPosX()

/**
 * Find the X position of an element
 *
 * Written by Peter-Paul Koch
 * http://www.quirksmode.org/js/findpos.html
 *
 * @param  HTML_Element obj the element
 * @return int          the X position
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.findPosX = function(obj)
{
    var curleft = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curleft += obj.offsetLeft
            obj = obj.offsetParent;
        }
    } else if (obj.x) {
        curleft += obj.x;
    }
    return curleft;
}

// }}}
// {{{ findPosY()

/**
 * Find the Y position of an element
 *
 * Written by Peter-Paul Koch
 * http://www.quirksmode.org/js/findpos.html
 *
 * @param  HTML_Element obj the element
 * @return int          the Y position
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.findPosY = function(obj)
{
    var curtop = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curtop += obj.offsetTop
            obj = obj.offsetParent;
        }
    } else if (obj.y) {
        curtop += obj.y;
    }
    return curtop;
}

// }}}
// {{{ classMatch()

/**
 * Match the class name on an element
 *
 * @param  HTML_Element el    the element
 * @param  string       cName the class name for which to search
 * @return bool         whether it matched
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.classMatch = function(el, cName)
{
    var r = new RegExp("\\b" + cName + "\\b", "i");
    if (r.exec(el.className)) {
        return true;
    } else {
        return false;
    }
}

// }}}

// }}}

/**************************** EVENT TAGGING CLASS *****************************/

// {{{ EventTagger

// {{{ constructor

/**
 * EventTagger constructor
 */
Nontoxic.EventTagger = function ()
{
    this.registered = new Array();
    this.count = 0;
}

// Create and throw away an object so that the prototype exists
new Nontoxic.EventTagger();

// }}}
// {{{ register()

/**
 * Register an event
 *
 * @param string   tName  the tag name
 * @param function fMatch the function to determine whether this particular
 *                        one should be tagged (takes a HTML_Element with the
 *                        tag name specified, and returns true if it should be
 *                        tagged, false otherwise)
 * @param function fAdd   the function to tag the element (takes a HTML_Element
 *                        with the tag name specified)
 *
 * @access public
 * @since  0.1
 */
Nontoxic.EventTagger.prototype.register = function (tName, fMatch, fAdd)
{
    var evReg = new Array();
    evReg['match'] = fMatch;
    evReg['add']   = fAdd;

    if (typeof(this.registered[tName]) == 'undefined') {
        this.registered[tName] = new Array();
    }

    this.registered[tName][this.registered[tName].length] = evReg;
}

// }}}
// {{{ registerObject()

/**
 * Register an object to an event
 *
 * @param string tName  the tag name
 * @param object tObj   the object in question
 * @param string fMatch the name of the matching function
 * @param string fAdd   the name of the adding function
 *
 * @access public
 * @since  0.1
 */
Nontoxic.EventTagger.prototype.registerObject = function (tName, tObj, fMatch, fAdd)
{
    var globalName = '_NTEvTg_' + this.count;

    eval(globalName + ' = tObj;');

    var doMatch = new Function('el', 'return ' + globalName + '.' + fMatch + "(el, '" + globalName + "');");
    var doAdd   = new Function('el', globalName + '.' + fAdd + "(el, '" + globalName + "');");

    this.register(tName, doMatch, doAdd);
    this.count++;
}


// }}}
// {{{ tagSimpleType()

/**
 * Tag a simple event, also checking for type
 *
 * @param string   tName  the element's tag name
 * @param string   elType the element's type
 * @param string   cName  the class name to search for
 * @param string   evType the event type
 * @param function fnc    the function to apply
 *
 * @access public
 * @since  0.1
 */
Nontoxic.EventTagger.prototype.tagSimpleType = function (tName, elType, cName, evType, fnc)
{
    var match = function (el)
    {
        if (el.type == elType && Nontoxic.classMatch(el, cName)) {
            return true;
        } else {
            return false;
        }
    }

    var add = function (el)
    {
        Nontoxic.addEvent(el, evType, fnc);
    }

    this.register(tName, match, add);
}

// }}}
// {{{ tagSimple()

/**
 * Tag a simple event
 *
 * @param string   tName  the element's tag name
 * @param string   cName  the class name to search for
 * @param string   evType the event type
 * @param function fnc    the function to apply
 *
 * @access public
 * @since  0.1
 */
Nontoxic.EventTagger.prototype.tagSimple = function (tName, cName, evType, fnc)
{
    var match = function (el)
    {
        return Nontoxic.classMatch(el, cName);
    }

    var add = function (el)
    {
        Nontoxic.addEvent(el, evType, fnc);
    }

    this.register(tName, match, add);
}

// }}}
// {{{ addAll

/**
 * Add all registered events
 *
 * @access public
 * @since  0.1
 */
Nontoxic.EventTagger.prototype.addAll = function ()
{
    for (var tName in this.registered) {
        var eList = document.getElementsByTagName(tName);
        for (var i=0; i < eList.length; i++) {
            for (var j=0; j < this.registered[tName].length; j++) {
                if (this.registered[tName][j]['match'](eList[i])) {
                    this.registered[tName][j]['add'](eList[i]);
                }
            }
        }
    }
}

// }}}

// }}}

/***************************** ROLLOVER SUBCLASS ******************************/

// {{{ Rollover

// {{{ constructor

/**
 * Rollover lib constructor
 */
Nontoxic.Rollover = function ()
{
}

// }}}
// {{{ tagMatchImage()

/**
 * Tagging: match (image)
 *
 * @param HTML_Element el the element
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.Rollover.tagMatchImage = function (el)
{
    return Nontoxic.classMatch(el, 'rollover');
}

// }}}
// {{{ tagMatchInput()

/**
 * Tagging: match (input type="image")
 *
 * @param HTML_Element el the element
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.Rollover.tagMatchInput = function (el)
{
    if (el.type == "image" && Nontoxic.classMatch(el, 'rollover')) {
        return true;
    } else {
        return false;
    }
}

// }}}
// {{{ tagAdd()

/**
 * Tagging: add
 *
 * @param HTML_Element el the element
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.Rollover.tagAdd = function (el)
{
    Nontoxic.addEvent(el, 'mouseover', Nontoxic.Rollover.switchOn);
    Nontoxic.addEvent(el, 'mouseout', Nontoxic.Rollover.switchOff);
}

// }}}
// {{{ switchOn()

/**
 * Switch on
 *
 * @param Event e the event
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.Rollover.switchOn = function(e)
{
    var target = Nontoxic.getEventTarget(e);
    if (!target) {
        return;
    }
    var srcFile = target.src;
    if (/_off.[a-z]{3}$/.exec(srcFile)) {
        target.src = srcFile.replace('_off.', '_on.');
    }
}

// }}}
// {{{ switchOff()

/**
 * Switch off
 *
 * @param Event e the event
 *
 * @access public
 * @since  0.1
 * @static
 */
Nontoxic.Rollover.switchOff = function(e)
{
    var target = Nontoxic.getEventTarget(e);
    if (!target) {
        return;
    }
    var srcFile = target.src;
    if (/_on.[a-z]{3}$/.exec(srcFile)) {
        target.src = srcFile.replace('_on.', '_off.');
    }
}

// }}}

// }}}

/************************** DELAYED MOUSEOVER CLASS ***************************/

// {{{ DelayMouseover

// {{{ constructor

/**
 * DelayMouseover constructor
 */
Nontoxic.DelayMouseover = function()
{
    this.registered = new Array();
    this.count = 0;
}

// Create and throw away an object so that the prototype exists
new Nontoxic.DelayMouseover();

// }}}
// {{{ register()

/**
 * Register an element, function, and timeout
 *
 * @param function     oFnc the function to call at the end of the timeout to
 *                          open the mouseover
 * @param function     cFnc the function to call when the open function's been
 *                          called and we mouse out again
 * @param HTML_Element el  the element over which we're hovering
 * @param int          tmd the time delay, in milliseconds
 *
 * @access public
 * @since  0.1
 */
Nontoxic.DelayMouseover.prototype.register = function(oFnc, cFnc, el, tmd)
{
    el._dlMsOv_id = this.count;
    this.count++;

    var group = new Array();
    group['openFnc']  = oFnc;
    group['closeFnc'] = cFnc;
    group['element']  = el;
    group['delay']    = tmd;
    this.registered[el._dlMsOv_id] = group;
}

// }}}
// {{{ addEvents()

/**
 * Add its mousing over and out
 *
 * @param HTML_element el the element
 *
 * @access public
 * @since  0.1
 */
Nontoxic.DelayMouseover.prototype.addEvents = function(el, myname)
{
    var mOver = new Function('e', myname + '.mouseover(e);');
    var mOut  = new Function('e', myname + '.mouseout(e);');
    Nontoxic.addEvent(el, 'mouseover', mOver);
    Nontoxic.addEvent(el, 'mouseout', mOut);
}

// }}}
// {{{ mouseover()

/**
 * The mouseover event
 *
 * @param Event e the event
 *
 * @access public
 * @since  0.1
 */
Nontoxic.DelayMouseover.prototype.mouseover = function(e)
{
    var target = Nontoxic.getEventTarget(e);
    if (!target) {
        return;
    }

    if (typeof(this.registered[target._dlMsOv_id]) == 'undefined') {
        return;
    }

    this.registered[target._dlMsOv_id]['over'] = 'yes';

    // global scope, so they'll be recognized later
    objname = '_dlMsOv_obj_' + target._dlMsOv_id;
    tgtname = '_dlMsOv_tgt_' + target._dlMsOv_id;
    eval(objname + ' = this;');
    eval(tgtname + ' = target;');

    window.setTimeout(objname + '.open(' + tgtname + ')', this.registered[target._dlMsOv_id]['delay']);
}

// }}}
// {{{ mouseout()

/**
 * The mouseout event
 *
 * @param Event e the event
 *
 * @access public
 * @since  0.1
 */
Nontoxic.DelayMouseover.prototype.mouseout = function(e)
{
    var target = Nontoxic.getEventTarget(e);
    if (!target) {
        return;
    }

    if (typeof(this.registered[target._dlMsOv_id]) == 'undefined') {
        return;
    }

    this.registered[target._dlMsOv_id]['over'] = 'no';

    this.close(target);
}

// }}}
// {{{ open()

/**
 * Run the open function if the user is still moused over the element
 *
 * @param HTML_Element el the element
 *
 * @access public
 * @since  0.1
 */
Nontoxic.DelayMouseover.prototype.open = function(el)
{
    if (typeof(this.registered[el._dlMsOv_id]['over']) == 'undefined') {
        return;
    }

    if (this.registered[el._dlMsOv_id]['over'] != 'yes') {
        return;
    }

    this.registered[el._dlMsOv_id]['state'] = 'open';
    this.registered[el._dlMsOv_id]['openFnc'](el);
}

// }}}
// {{{ close()

/**
 * Run the close function if the mouseover is open
 *
 * @param HTML_Element el the element
 *
 * @access public
 * @since  0.1
 */
Nontoxic.DelayMouseover.prototype.close = function(el)
{
    if (typeof(this.registered[el._dlMsOv_id]['state']) == 'undefined') {
        this.registered[el._dlMsOv_id]['state'] = 'closed';
    }

    if (this.registered[el._dlMsOv_id]['state'] == 'open') {
        this.registered[el._dlMsOv_id]['state'] = 'closed';
        this.registered[el._dlMsOv_id]['closeFnc'](el);
    }
}

// }}}
// {{{ toString()

Nontoxic.DelayMouseover.prototype.toString = function()
{
    return 'Delayed Items count: ' + this.count;
}

// }}}

// }}}

/********************************* OLD STUFF **********************************/

// {{{ Old Stuff

/**
 * Roll over an image from a list of images
 *
 * @param string iName
 * @param string type
 */
function rollIt(iName,type){
    if (document.images) {
        if (type=="on") {
            document.images[iName].src = imagesOn[iName].src;
            return true;
        } else if (type=="off") {
            document.images[iName].src = imagesOff[iName].src;
            return true;
        }
    }
    return false;
}

/**
 * Get an element by its ID
 *
 * @param  string elementID
 * @return HTML_Element
 */
function getDOMElement (elementID) {
    if(document.getElementById){
        return document.getElementById(elementID);
    } else if (document.all) {
        return document.all.namedItem(elementID);
    } else {
        return null;
    }
}

/**
 * Hide an element
 *
 * @param HTML_Element o
 */
function DOMElementHide (o) {
    if (document.getElementById || document.all) {
        o.style.display = 'none';
        o.style.visibility = 'hidden';
        o.style.hidden = 'none';
    } else if (document.layers) {
        o.visibility = 'hidden';
    }
}

/**
 * Show an element
 *
 * @param string o
 */
function DOMElementShow (o) {
    getDOMElement(o).style.visibility = 'visible';
    getDOMElement(o).style.display = 'block';
    getDOMElement(o).visibility = 'visible';
}

/**
 * Switch the source of an image by its ID
 *
 * @param string imgID
 * @param string newSrc
 */
function switchSrc(imgID, newSrc) {
    image  = getDOMElement(imgID);
    if (image == null) {
        return;
    }
    image.src = newSrc;
}

/**
 * Add an event listener to an element
 *
 * Written by Scott Andrew
 * found in "Enhancing Structural Markup with JavaScript" by Simon Willison
 * http://www.sitepoint.com/article/structural-markup-javascript
 */
function addEvent(obj, evType, fn){
    if (obj.addEventListener){
        obj.addEventListener(evType, fn, true);
        return true;
    } else if (obj.attachEvent){
        var r = obj.attachEvent("on"+evType, fn);
        return r;
    } else {
        return false;
    }
}

/**
 * Get the target node from an event
 *
 * Written by Peter-Paul Koch
 * http://www.quirksmode.org/js/events_properties.html
 */
function getEventTarget(e) {

    var targ;

    if (!e) {
        var e = window.event;
    }

    if (e.target) {
        targ = e.target;
    } else if (e.srcElement) {
        targ = e.srcElement;
    }

    // defeat Safari bug
    if (targ.nodeType == 3) {
        targ = targ.parentNode;
    }

    return targ;
}

/**
 * Find the X position of an element
 *
 * Written by Peter-Paul Koch
 * http://www.quirksmode.org/js/findpos.html
 */
function findPosX(obj)
{
    var curleft = 0;
    if (obj.offsetParent)
    {
        while (obj.offsetParent)
        {
            curleft += obj.offsetLeft
            obj = obj.offsetParent;
        }
    }
    else if (obj.x)
        curleft += obj.x;
    return curleft;
}

/**
 * Find the Y position of an element
 *
 * Written by Peter-Paul Koch
 * http://www.quirksmode.org/js/findpos.html
 */
function findPosY(obj)
{
    var curtop = 0;
    if (obj.offsetParent)
    {
        while (obj.offsetParent)
        {
            curtop += obj.offsetTop
            obj = obj.offsetParent;
        }
    }
    else if (obj.y)
        curtop += obj.y;
    return curtop;
}

/**
 * Apply a function to each element with a particular class name
 *
 * @param string   tName the element's tag name
 * @param string   cName the class name to search for
 * @param function fnc   the function to perform
 */
function opByClass(tName, cName, fnc) {
    var eList = document.getElementsByTagName(tName);
    var r = new RegExp("\\b" + cName + "\\b", "i");
    for (var i=0; i < eList.length; i++) {
        if (r.exec(eList[i].className)) {
            fnc(eList[i]);
        }
    }
}

/**
 * Tag a simple event
 *
 * @param string   tName  the element's tag name
 * @param string   cName  the class name to search for
 * @param string   evType the event type
 * @param function fnc    the function to apply
 */
function tagEventSimple(tName, cName, evType, fnc) {
    opByClass(tName, cName, function (target) {
            addEvent(target, evType, fnc);
        });
}



//
// Image rollovers
//

/**
 * Tag images and image inputs with the 'rollover' keyword with the
 * mouseOverImage and mouseOutImage functions
 */
function tagRollovers() {
    var imageList = document.getElementsByTagName('img');
    for (var i = 0; i < imageList.length; i++) {
        if (/\brollover\b/.exec(imageList[i].className)) {
            addEvent(imageList[i], 'mouseover', mouseOverImage);
            addEvent(imageList[i], 'mouseout', mouseOutImage);
        }
    }
    var inputList = document.getElementsByTagName('input');
    for (var i = 0; i < inputList.length; i++) {
        if (inputList[i].type == 'image' && /\brollover\b/.exec(inputList[i].className)) {
            addEvent(inputList[i], 'mouseover', mouseOverImage);
            addEvent(inputList[i], 'mouseout', mouseOutImage);
        }
    }
}

/**
 * Change the _off extention to _on in the src of the image
 *
 * @param Event e
 */
function mouseOverImage(e) {
    var target = getEventTarget(e);
    if (!target) {
        return;
    }
    var srcFile = target.src;
    if (/_off.[a-z]{3}$/.exec(srcFile)) {
        target.src = srcFile.replace('_off', '_on');
    }
}

/**
 * Change the _on extention to _off the src of the image
 *
 * @param Event e
 */
function mouseOutImage(e) {
    var target = getEventTarget(e);
    if (!target) {
        return;
    }
    var srcFile = target.src;
    if (/_on.[a-z]{3}$/.exec(srcFile)) {
        target.src = srcFile.replace('_on', '_off');
    }
}

// }}}

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * c-hanging-comment-ender-p: nil
 * End:
 */

