// ---------------------------------------------------------------------
// $Id: dom.js,v 1.1.1.1 2007/12/05 23:29:11 chris Exp $
// ---------------------------------------------------------------------
// Convenience DOM enhancements.
// ---------------------------------------------------------------------

/*@cc_on @*/     // Who doesn't love IE?

// ---------------------------------------------------------------------
// The de-facto shortcut for getElementById() from the Prototype library.
// http://prototype.conio.net/

if (! window.$) window.$ = function (element) {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
};

// ---------------------------------------------------------------------
// "Ultimate" getElementsByClassName function by Robert Nyman.
// http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/

function dnGetElementsByClassName(className, tag, elm){
    var testClass = new RegExp("(^|\s)" + className + "(\s|$)");
    var tag = tag || "*";
    var elm = elm || document;
    var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
    var returnElements = [];
    var current;
    var length = elements.length;
    for(var i=0; i<length; i++){
        current = elements[i];
        if(testClass.test(current.className)){
            returnElements.push(current);
        }
    }
    return returnElements;
};

// ---------------------------------------------------------------------
// addEvent and removeEvent functions from the Quirksmode contest
// http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html

function dnAddEvent(obj, type, fn) {
    if (type == "dndomload") dnDomloadAddEvent(obj, fn);
    else if (obj.addEventListener) obj.addEventListener(type, fn, false);
    else if (obj.attachEvent) {
        obj["e"+type+fn] = fn;
        obj[type+fn] = function() { obj["e"+type+fn](window.event); };
        obj.attachEvent("on"+type, obj[type+fn]);
    }
};

function dnRemoveEvent(obj, type, fn) {
    if (obj.removeEventListener) obj.removeEventListener(type, fn, false);
    else if (obj.detachEvent) {
        obj.detachEvent("on"+type, obj[type+fn]);
        obj[type+fn] = null;
        obj["e"+type+fn] = null;
    }
};

// ---------------------------------------------------------------------
// window.onload waits for page resources to finish loading before firing.
// Adapted from the solution by Dean Edwards/Matthias Miller/John Resig,
// this allows you to schedule callbacks when the DOM is finished loading,
// which is likely before window.onload fires.
// http://dean.edwards.name/weblog/2006/06/again/#comment5338
// http://dean.edwards.name/weblog/2006/06/again/#comment56361
//
// Usage is simple and integrated. Simply call
// dnAddEvent(window, "dndomload", function) to attach functions to the
// DOM loading event.

function dnEnableDomload () {
    // Can only be called once.
    if (dnOnDomload.enabled) return;
    dnOnDomload.enabled = true;
    
    /* for Mozilla/Opera9 */
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", dnOnDomload, false);
    }

    /* for Internet Explorer */
    /*@if (@_win32)
        document.write("<script id=__ie_onload defer src=//:><\/script>");
        var script = document.getElementById("__ie_onload");
        script.onreadystatechange = function() {
            if (this.readyState == "complete") {
                dnOnDomload(); // call the onload handler
            }
        };
    /*@end @*/

    /* for Safari */
    if (/WebKit/i.test(navigator.userAgent)) { // sniff
        dnOnDomload.timer = setInterval(function() {
            if (/loaded|complete/.test(document.readyState)) {
                dnOnDomload(); // call the onload handler
            }
        }, 10);
    }

    /* for other browsers */
    dnAddEvent(window, "load", dnOnDomload);
};

function dnDomloadAddEvent (obj, fn) {
    dnEnableDomload();
    
    if (!dnOnDomload.objects) dnOnDomload.objects = [];
    dnOnDomload.objects[dnOnDomload.objects.length] = obj;
    
    if (!dnOnDomload.callbacks) dnOnDomload.callbacks = [];
    dnOnDomload.callbacks[dnOnDomload.callbacks.length] = fn;    
};

function dnOnDomload () {
    // quit if this function has already been called
    if (dnOnDomload.done) return;

    // flag this function so we don't do the same thing twice
    dnOnDomload.done = true;

    // kill the timer
    if (dnOnDomload.timer) clearInterval(dnOnDomload.timer);

    for (var i=0; i < dnOnDomload.callbacks.length; i++) {
        var obj = dnOnDomload.objects[i];
        obj["dnOnDomload" + i] = dnOnDomload.callbacks[i];
        obj["dnOnDomload" + i]();
        obj["dnOnDomload" + i] = null;
    };
};

// ---------------------------------------------------------------------
// Tired of typing this over and over?

function dnStopPropagation (e) {
    if (!e) var e = window.event;
    e.cancelBubble = true;
    if (e.stopPropagation)
        e.stopPropagation();
};

// ---------------------------------------------------------------------
// Firefox does not have an element.contains() method, and Safari has
// an incorrect implementation.

function dnContains (parent, child) {
    if (child == null)
        return false;
    if (child == parent)
        return true;
    else
        return dnContains(parent, child.parentNode);
};

// ---------------------------------------------------------------------
// Finds the absolute position of an element on the page.

function dnFindPos(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        curleft = obj.offsetLeft;
        curtop = obj.offsetTop;
        while (obj = obj.offsetParent) {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        }
    }
    return [curleft,curtop];
};

// ---------------------------------------------------------------------

function dnConcatNodeLists () {
    var result = [];
    for (var i = 0; i < arguments.length; i++) {
        for (var j = 0; j < arguments[i].length; j++) {
            result[result.length] = arguments[i].item(j);
        }
    }
    return result;
};

// ---------------------------------------------------------------------
// Add a bunch of CSS code to the document.
// From http://yuiblog.com/blog/2007/06/07/style/

function dnAddCss (cssCode) {
    var styleElement = document.createElement("style");
    styleElement.type = "text/css";
    
    if (styleElement.styleSheet) {
        styleElement.styleSheet.cssText = cssCode;
    } else {
        styleElement.appendChild(document.createTextNode(cssCode));
    }
    
    document.getElementsByTagName("head")[0].appendChild(styleElement);
};

// ---------------------------------------------------------------------
// Get the computed style property of an element.
// From http://www.quirksmode.org/dom/getstyles.html

function dnGetStyle (elem, prop) {
    var x = $(elem);
    if (x.currentStyle)
        var y = x.currentStyle[prop];
	else if (window.getComputedStyle)
        var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(prop);
    return y;
};

// ---------------------------------------------------------------------
// Standard cookie routines.
// From http://www.quirksmode.org/js/cookies.html

function dnCreateCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
};

function dnReadCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
};

function dnDeleteCookie(name) {
	createCookie(name,"",-1);
};

// ---------------------------------------------------------------------
// dnXhr() performs an asynchronous HTTP request.

function dnXhr (url, params, callback, method, headers) {
    // Let's create a new XMLHttpRequest object.
    var xhr = null;
    if (window.XMLHttpRequest) {
        try { xhr = new XMLHttpRequest(); }
        catch (e) { xhr = null; }
    }
    else if (window.ActiveXObject) {
       	try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }
       	catch (e) {
            try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
            catch (e) { xhr = null; }
    	}
    }
    if (!xhr) return null;
    
    // Save the XHR object for the callback and for potential abort() calls.
    if (!dnXhr.pending) dnXhr.pending = [];
    var xhrId = dnXhr.pending.length;
    dnXhr.pending.push({"url": url, "xhr": xhr});

    // Default to POST. Make sure params is defined.
    if (!method) method = "post";
    if (!params) params = { };

    // Prevent IE from caching responses to POSTs by making sure there is
    // at least always one parameter.
    if (/^post$/i.test(method)) params.__dnXhrIECacheBust__ = 1;
    
    // Convert the parameters into a query string.
    var q = dnXhr._createQueryString(params);
    
    // Add the query string to url if we're doing GET.
    if (q != "" && /^get$/i.test(method)) url += "?" + q;
    
    // Set up the callback.
    xhr = null;  // Keep this from getting in the closure: avoids IE's bad GC.
    dnXhr.pending[xhrId].xhr.onreadystatechange = function () {
        var xhr = window.dnXhr.pending[xhrId].xhr;
        
        // Get the status, and catch any errors FF throws.
        var status = -1;
        try { status = xhr.status; } catch (e) { };
        
        if (xhr.readyState == 4) {
            window.dnXhr.pending[xhrId] = null;
            if (status == 200) {
                if (callback) callback(xhr);
            } else {
                try {
                    if (console && console.error)
                        console.error("XMLHttpRequest error: "+ xhr.statusText);
                }
                catch (e) { }
            }
        }
    };
    xhr = dnXhr.pending[xhrId].xhr;  // Restore the xhr variable.
    
    // Kick off the request.
    xhr.open(method, url, true);
    if (headers) for (var h in headers) { xhr.setRequestHeader(h, headers[h]); }
    if (/^post$/i.test(method)) {        
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.send(q);
    }
    else xhr.send(null);
    return xhr;
};

dnXhr.abortAll = function () {
    if (!window.dnXhr.pending) return;
    for (var i = window.dnXhr.pending.length - 1; i >= 0; i--) {
        var o = window.dnXhr.pending[i];
        if (!o) continue;
        if (o.xhr) o.xhr.abort();
    }
};

dnXhr.abortForUrl = function (url) {
    if (!window.dnXhr.pending) return;
    for (var i = window.dnXhr.pending.length - 1; i >= 0; i--) {
        var o = window.dnXhr.pending[i];
        if (!o) continue;
        if (o.url != url) continue;
        o.xhr.abort();
    };
};

dnXhr._createQueryString = function (params) {
    var keys = [];
    for (var key in params) { keys.push(key); }
    keys.sort();
    
    var q = "";
    for (var i = 0; i < keys.length; i++) {
        var name = keys[i];
        q += encodeURIComponent(name) + "=" + encodeURIComponent(params[name]);
        q += "&";
    };
    
    return q.replace(/&$/, "");
};

// ---------------------------------------------------------------------
// Safari and Opera have problems with the img.complete property. To work
// around this, call dnImageCompleteWatch() on an img element before
// assigning it a (new) src. Then call dnImageComplete to test if the image
// has finished loading.

function dnImageCompleteWatch (img) {
    if (img.complete != null) return img;
    img.dnImageComplete = false;
    img.onload = function (e) { img.dnImageComplete = true; };
    return img;
};

function dnImageComplete (img) {
    if (img.complete != null) return img.complete;
    if (img.dnImageComplete != null) return img.dnImageComplete;
    return false;
};

// ---------------------------------------------------------------------
