/* Last published: 10 Feb 2012 12:31 */
/****************************************************************************************
DOMHelp.js
Utility functions to aid with the manipulation of the DOM.
****************************************************************************************/
/**
 * The following are classes for manipulating the CSS class of an HTML element.
 * adapted from 'Javascript: The Definite Guide (5th edition)' 
 * by David Flanagan, published by O'Reilly, 2006.
 * 978-0-596-10199-2.
 * Defines a global symbol CSSClass, which can then be used to contain utility functions
 * for working with the class attribute (className property) of HTML elements.
 * Example usage:
 * if(CSSClass.isMember(element, classname)) { return };
 */
var CSSClass = {};    // namespace object.
// isMember()
// Determine whether the specified element is a member of the specified
// class. This function is optimised for the common case in which the
// className property contains only a single classname. But it also
// handles the case in which it is a list of whitespace-separated classes.
// 'element' can be the element object itself or the id (string) of the element.
CSSClass.isMember = function(element, classname) {
    if(typeof element == "string") {
        element = document.getElementById(element);  // element id
    }
    var classes = element.className;  // Get the list of classes
    if(!classes) {
        return false;  // No classes defined
    }
    if(classes==classname) {
        return true;  // Exact match
    }
    // We didn't match exactly, so if there is no whitespace, then
    // this element is not a member of the class
    var whitespace = /\s+/;
    if(!whitespace.test(classes)) {
        return false;
    }
    // If we get here, the element is a member of more than one class and so
    // we've got to check them individually.
    var c = classes.split(whitespace);  // split with whitespace delimiter
    for(var i =0; i<c.length; i++) { // loop through classes
        if(c[i]==classname) {
            return true;  // and check for matches
        }
    }
        return false;  // None of the classes matched.
};
// addClass()
// add class 'classname' to the className of 'element' (if it is not already there).
// 'element' can be the element object itself or the id (string) of the element.
CSSClass.addClass = function(element, classname) {
    if(typeof element == "string") {
        element = document.getElementById(element);  // element id
    }
    if(CSSClass.isMember(element, classname)) {
        return;  // if already a member, do nothing
    }
    if(element.className) {
        classname = " " + classname;  // whitespace separator, if needed
    }
    element.className += classname;  // append the new class to the end
};
// removeClass()
// remove all occurrences (if any) of class 'classname' from the className of 'element'.
// 'element' can be the element object itself or the id (string) of the element.
CSSClass.removeClass = function(element, classname) {
    if(typeof element == "string") {
        element = document.getElementById(element);  // element id
    }
    // search the className for all occurrences of 'classname' and replace with "".
    // \s* matches any number of whitespace characters.
    // "g" makes the regular expression match any number of occurrences.
    element.className = element.className.replace(new RegExp("\\b" + classname + "\\b\\s*", "g"), "");
};
// hasClass()
// returns true if 'element' is a member of the class 'classname'; otherwise return false.
// (Note. this does the same thing as 'isMember' but not sure which is best!!!)
// 'element' can be the element object itself or the id (string) of the element.
CSSClass.hasClass = function(element, classname) {
    if(typeof element == "string") {
        element = document.getElementById(element);  // element id
    }
    
    // before doing a regexp search, optimise for a couple of common cases
    var classes = element.className;
    if(!classes) {
        return false;  // not a member of any classes
    }
    if(classes == classname) {
        return true;   // member of just this one class
    }
    
    // otherwise, use a regular expression to search for classname as a word by itself
    // \b in a regular expression requires a match at a word boundary
    return element.className.search("\\b" + classname + "\\b") != -1;
};

/*==============================================================================
                       DOMReady - window.onload alternative
                       ====================================
                       Copyright (c) 2007 Vyacheslav Smolin

Author:
-------
Vyacheslav Smolin (http://www.richarea.com, http://html2xhtml.richarea.com,
re@richarea.com)
About the script:
-----------------
The traditional approach to start working with DOM structure of a page is to
wait while page is loaded completely to be sure DOM is ready ;) This means that
window.onload event used for that will fire after all images and other content
is loaded.
If page contains a lot of such content then your functionality starting by
window.onload (eg menu) will be activated with a nonticable delay.
The smarter approach is not to wait when all the content your scripts do not
need will load, but use something like Mozilla's DOMContentLoaded event.
Browsers supported:
-------------
IE, Opera, Safari, Mozilla-based browsers (Firefox, Mozilla, etc).
For non-supported browsers window.onload is used.
Usage:
------
Please see example.html.
License:
--------
Free. Copyright information must stay intact.
Notes:
------
Dean Edwards's solution for IE has been used.
More info: http://dean.edwards.name/weblog/2005/09/busted/.
==============================================================================*/
var DOMReady = {
onDOMReadyHandler : function() {},
// returns true if listener is active, otherwise - false (that means that
// window.onload is used
listenDOMReady : function() {
var browser = navigator.userAgent;
var is_safari = /(safari|webkit)/i.test(browser);
var is_opera = /opera/i.test(browser);
var is_msie = /msie/i.test(browser);
var is_mozilla = /mozilla/i.test(browser) && !(/(compatible|webkit)/i.test(browser));
    if (is_opera || is_mozilla){
        this.attachEvent(document, "DOMContentLoaded", this.onDOMReadyHandler);
        return true;
    }
    if (is_msie) {
        document.write('<script id="dr_ie_script" defer="true" src="javascript:;"><\/script>');
        document.getElementById("dr_ie_script").onreadystatechange = function(){
            if (this.readyState == "complete") {
                DOMReady.onDOMReadyHandler();
            }
        };
        return true;
    }
    if (is_safari) {
        this.domReadyTimer = window.setInterval(function(){
            if (document.readyState == "loaded" ||
                document.readyState == "complete") {
                window.clearInterval(DOMReady.domReadyTimer);
                DOMReady.onDOMReadyHandler();
            }
        }, 10);
        return true;
    }

    // use onload event otherwise
    this.attachEvent(window, "load", DOMReady.onDOMReadyHandler);
    return false;
},
// timer (used with Safari)
domReadyTimer : null,
// set event handler
attachEvent : function(obj, event, handler) {
    if (obj.addEventListener) {
        obj.addEventListener(event, handler, false);
    } else {
        if (obj.attachEvent) {
            obj.attachEvent('on'+event, handler);
        }
    }
},

// remove event handler
detachEvent : function(obj, event, handler) {
    if (obj.removeEventListener) {
        obj.removeEventListener(event, handler, false);
    } else {
        if (obj.detachEvent) {
            obj.detachEvent('on'+event, handler);
        }
    }
}
};

/**
 * getElements(classname, tagname, root):
 *
 * adapted from 'Javascript: The Definite Guide (5th edition)' 
 * by David Flanagan, published by O'Reilly, 2006.    
 * 
 * Return an array of DOM elements that are members of the specified class,
 * have the specified tagname, and are descendants of the specified root.
 *
 * If no classname is specified, elements are returned regardless of class.
 * If no tagname is specified, elements are returned regardless of tagname.
 * If no root is specified, the document object is used. If the specified root
 * is a string, it is an element id, and the root element is looked up by using
 * getElementsById()
 */
function getElements(classname, tagname, root) {
    // If no root specified, use the entire document.
    // If a string was specified, look it up.
    if(!root) {
        root = document;
    } else if (typeof root == "string") {
        root = document.getElementById(root);
    }
    // if no tagname was specified, use all tags
    if(!tagname) {
        tagname = "*";
    }
    // Find all descendants of the specified root with the specified tagname
    var all = root.getElementsByTagName(tagname);
    // If no classname was specified, we return all tags
    if(!classname) {
        return all;
    }
    // Otherwise, we filter the element by classname
    var elements = []; // start with an empty array
    for(var i=0; i<all.length; i++) {
        var element = all[i];
        if(CSSClass.isMember(element, classname)) {  // isMember() is defined above
            elements.push(element);  // Add class members to our array
        }
    }
    // Note that we always return an array, even if it is empty
    return elements;
}
// addClass() TEMP (for PGSearch BETA)
// add class 'classname' to the className of 'element' (if it is not already there).
// 'element' can be the element object itself or the id (string) of the element.
addClass = function(element, classname) {
    if(typeof element == "string") {
        element = document.getElementById(element);  // element id
    }
    if(CSSClass.isMember(element, classname)) {
        return;  // if already a member, do nothing
    }
    if(element.className) {
        classname = " " + classname;  // whitespace separator, if needed
    }
    element.className += classname;  // append the new class to the end
};
