// $Header: /local/cvs_repository/caf/modules/content/web_static/js/util.js,v 1.5 2009/10/06 09:00:54 mark Exp $

//----------------------------------------------------------------------
// tab dialog implementation

function selectTab (tabgroup, tabno) {
    try {
        for (var i=1; true; i++) {
            var tabs = getElementsByClass('li', tabgroup+'tab'+i);
            var pane = document.getElementById(tabgroup+'pane'+i);
            if (tabs.length == 0 && !pane)
                break;
            var fn;
            if (i == tabno) {
                fn = addCssClass;
            } else {
                fn = removeCssClass;
            }
            var j;
            for (j=0; j<tabs.length; j++) {
                fn(tabs[j], 'selected');
            }
            fn(pane, 'selected');
        }
    } catch (err) {
        /* ignore, to make sure we always return false */
    }
    return false; /* for use in onclicks */
}


function toggleBox (toggle, boxid) {
    try {
        var box = document.getElementById(boxid);
        if (box) {
            if (hasClass(box, 'toggleboxshown')) {
                _changeCssClass(box, 'toggleboxshown', 'toggleboxhidden');
                _changeCssClass(toggle, 'toggleon', 'toggleoff')
            } else {
                _changeCssClass(box, 'toggleboxhidden', 'toggleboxshown');
                _changeCssClass(toggle, 'toggleoff', 'toggleon')
            }
        }
    } catch (err) {
        /* ignore, to make sure we always return false */
    }
    return false;
}


function removeCssClass (el, classname) {
    var classes = el.className.split(' ');

    for (var i=0; i < classes.length; i++) {
        if (classes[i] == classname) {
            classes.splice(i,1);
            break;
        }
    }

    el.className = classes.toString().replace(/,/g, ' ');
}


function addCssClass (el, classname) {
    var classes = el.className.split(' ');

    for (var i=0; i < classes.length; i++) {
        if (classes[i] == classname) {
            return;
        }
    }

    el.className = el.className + ' ' + classname;
}


function _changeCssClass (el, classname, newclassname) {
    /* we used to just call removeCssClass and then addCssClass,
     * but that changes the order of the classes, which affects
     * the semantics
     */
    var classes = el.className.split(' ');

    for (var i=0; i < classes.length; i++) {
        if (classes[i] == classname) {
            classes[i] = newclassname;
            break;
        }
    }

    el.className = classes.toString().replace(/,/g, ' ');
}

//----------------------------------------------------------------------
// programmatically include a CSS file

function includeCSS (cssurl, opts) {
    /* IE6 gives an 'operation aborted' error if you attempt to modify the
     * DOM from a script that isn't a direct child of the BODY (which they
     * won't be in HTML Strict, because its DTD doesn't allow script tags
     * outside the HEAD. So, we implement this as an onload event handler.
     *
     * http://weblogs.asp.net/infinitiesloop/archive/2006/11/02/Dealing-with-IE-_2600_quot_3B00_Operation-Aborted_2600_quot_3B002E00_-Or_2C00_-how-to-Crash-IE.aspx
     */
    function _doit () {
        var link = document.createElement('link');
        link.setAttribute('rel', 'stylesheet');
        link.setAttribute('type', 'text/css');
        link.setAttribute('href', cssurl);
        for (var opt in opts) {
            link.setAttribute(opt, opts[opt]);
        }
        var parent = document.getElementsByTagName('head')[0];
        parent.appendChild(link);
    }
    addLoadEvent(_doit);
}


// Load a javascript source file
// handler is invoked when the file has been loaded

function loadJS (jsurl, handler) {
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', jsurl);
    if (handler) {
        // for IE
        var callcount = 0;
        script.onreadystatechange = function () {
            if (this.readyState == undefined)
                return;
            if (this.readyState == 'complete' || this.readyState == 'loaded') {
                callcount++;
                if (callcount > 1)
                    return;
                handler();
            }
        };

        // for every other browser
        script.onload = handler;
    }
    var parent = document.getElementsByTagName('head')[0];
    parent.appendChild(script);
}



// Add an event handler to an HTML element. Any existing handler will
// be invoked first.

function addEventHandler (element, handlername, handler) {
    var oldhandler = element[handlername];
    if (typeof oldhandler != 'function') {
        element[handlername] = handler;
    } else {
        element[handlername] = function() {
                                   oldhandler();
                                   handler();
                               };
    }
}


function addUnloadEvent (func) {
    addEventHandler(window, 'onunload', func);
}

function addLoadEvent (func) {
    addEventHandler(window, 'onload', func);
}

function addSubmitEvent (form, func) {
    addEventHandler(form, 'onsubmit', func);
}



//----------------------------------------------------------------------
// Find all elements of type 'type' that are have CSS class 'cls'

function getElementsByClass (type, cls) {
    var els = document.getElementsByTagName(type);
    var list = new Array();
    for (var i = 0; i < els.length; i++) {
        if (hasClass(els[i], cls)) {
            list.push(els.item(i));
        }
    }
    return list;
}


//----------------------------------------------------------------------

function scrollToAnchor (anchor) {
    window.location.hash = anchor;
}


//----------------------------------------------------------------------
// ### we should replace this with a safer JSON decoder

function JSON_decode (jsonstring) {
    return eval('('+jsonstring+')');
}


//----------------------------------------------------------------------
// JavaScript has no native way to escape HTML

function escapeHTML (str) {
    var div = document.createElement('div');
    var text = document.createTextNode(str);
    div.appendChild(text);
    return div.innerHTML;
};


//----------------------------------------------------------------------
// convert a string to a boolean
// could add this to the String.prototype?

function parseBoolean (str) {
    return (str == 'True' || str == 'true' || str == 'Yes' || str == 'yes');
}



//----------------------------------------------------------------------
// invoke browser print dialogue

function printPage () {
    if (window.print) {
        window.print();
    } else {
        alert("We couldn't print this page automatically for you. Please use your browser's print icon or menu option.");
    }
}


//----------------------------------------------------------------------
// cookie functions, from http://www.quirksmode.org/js/cookies.html

function createCookie(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 readCookie(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 eraseCookie(name) {
    createCookie(name,"",-1);
}


//----------------------------------------------------------------------

function urlAddParams (url, params) {
    for (var p in params) {
        if (!params[p])
            continue;
        var pattern = new RegExp("([?&]"+p+"=)[^&]*");
        if (url.match(pattern)) {
            // this will go wrong if params.p has character sequences that
            // mean something to replace(), e.g. $n
            url = url.replace(pattern, '$1'+escape(params[p]));
        } else {
            if (url.indexOf('?') == -1) {
                url += '?';
            } else {
                url += '&';
            }
            url += p + '=' + escape(params[p]);
        }
    }
    return url;
}


//----------------------------------------------------------------------
// Open a URL in a new window

function openInNewWindow (url) {
    var newWindow = window.open(url, '_blank');
    newWindow.focus();
    return false;  // for use in onclick handlers on <a> tags
}


//----------------------------------------------------------------------
// nicked from drupal, for autocomplete

function absolutePosition(el) {
  var sLeft = 0, sTop = 0;
  var isDiv = /^div$/i.test(el.tagName);
  if (isDiv && el.scrollLeft) {
    sLeft = el.scrollLeft;
  }
  if (isDiv && el.scrollTop) {
    sTop = el.scrollTop;
  }
  var r = { x: el.offsetLeft - sLeft, y: el.offsetTop - sTop };
  if (el.offsetParent) {
    var tmp = absolutePosition(el.offsetParent);
    r.x += tmp.x;
    r.y += tmp.y;
  }
  return r;
};


/**
 * Make IE's XMLHTTP object accessible through XMLHttpRequest()
 */
if (typeof XMLHttpRequest == 'undefined') {
  XMLHttpRequest = function () {
    var msxmls = ['MSXML3', 'MSXML2', 'Microsoft']
    for (var i=0; i < msxmls.length; i++) {
      try {
        return new ActiveXObject(msxmls[i]+'.XMLHTTP')
      }
      catch (e) { }
    }
    throw new Error("No XML component installed!");
  }
}

/**
 * Creates an HTTP GET request and sends the response to the callback function.
 *
 * Note that dynamic arguments in the URI should be escaped with encodeURIComponent().
 */
function HTTPGet(uri, callbackFunction, callbackParameter) {
  var xmlHttp = new XMLHttpRequest();
  var bAsync = true;
  if (!callbackFunction) {
    bAsync = false;
  }

  xmlHttp.open('GET', uri, bAsync);
  xmlHttp.send(null);

  if (bAsync) {
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4) {
        callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter);
      }
    }
    return xmlHttp;
  }
  else {
    return xmlHttp.responseText;
  }
}

/**
 * Creates an HTTP POST request and sends the response to the callback function
 *
 * Note: passing null or undefined for 'object' makes the request fail in Opera 8.
 *       Pass an empty string instead.
 */
function HTTPPost(uri, callbackFunction, callbackParameter, object) {
  var xmlHttp = new XMLHttpRequest();
  var bAsync = true;
  if (!callbackFunction) {
    bAsync = false;
  }
  xmlHttp.open('POST', uri, bAsync);

  var toSend = '';
  if (typeof object == 'object') {
    xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    for (var i in object) {
      toSend += (toSend ? '&' : '') + i + '=' + encodeURIComponent(object[i]);
    }
  }
  else {
    toSend = object;
  }
  xmlHttp.send(toSend);

  if (bAsync) {
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4) {
        callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter);
      }
    }
    return xmlHttp;
  }
  else {
    return xmlHttp.responseText;
  }
}


/**
 * Removes an element from the page
 */
function removeNode(node) {
  if (typeof node == 'string') {
    node = $(node);
  }
  if (node && node.parentNode) {
    return node.parentNode.removeChild(node);
  }
  else {
    return false;
  }
}


/**
 * Removes a class name from an element
 */
function removeClass(node, className) {
  if (!hasClass(node, className)) {
    return false;
  }
  // Replaces words surrounded with whitespace or at a string border with a space. Prevents multiple class names from being glued together.
  node.className = eregReplace('(^|\\s+)'+ className +'($|\\s+)', ' ', node.className);
  return true;
}


/**
 * Emulate PHP's ereg_replace function in javascript
 */
function eregReplace(search, replace, subject) {
  return subject.replace(new RegExp(search,'g'), replace);
}


/**
 * Returns true if an element has a specified class name
 */
function hasClass(node, className) {
  if (node.className == className) {
    return true;
  }
  var reg = new RegExp('(^| )'+ className +'($| )')
  if (reg.test(node.className)) {
    return true;
  }
  return false;
}


/**
 * Adds a class name to an element
 */
function addClass(node, className) {
  if (hasClass(node, className)) {
    return false;
  }
  node.className += ' '+ className;
  return true;
}

/* confirm message before going to a URL */
function confirm_url(message,url) {
        var ok = confirm(message);
        if(ok) {
                document.location = url;
        }
}
