//
// DOM innerHTML v1.00 (RC1) - Copyright (c) 2002 interactivetools.com, inc.
// A standards compliant DOM based replacement for the innerHTML property
//

var useProprietaryFeatures = true;

// optional: use proprietary browser features when available to speed things up.
// This will also make it work with older browsers that don't support standards
// but support properietary features (eg: innerHTML)

/* NOTES:

IE6: el.setAttribute('class',className, 0); // doesn't work, you have to use pseudoname "className" instead.

*/

/* ------------------------------------------------------------------------- *\
  Function    : getOuterHTML
  Description : return string of HTML within (and including) element.  Element
                can be passed as object reference or object ID.
  Usage       : var myHTML = getOuterHTML(element);
\* ------------------------------------------------------------------------- */

function getOuterHTML(obj) {
  if (typeof obj == 'string') { obj = document.getElementById(obj); }
  if (obj == null) { return alert('getOuterHTML: Invalid object name or reference: '+ obj); };

  if (useProprietaryFeatures) {
    if (obj.outerHTML != null) { return obj.outerHTML; }
  }

  var html = "";
  html += getNodeHTML(obj);
  html += getInnerHTML(obj);
  html += getNodeHTMLclosingTag(obj);

  return html;  
  
}

/* ------------------------------------------------------------------------- *\
  Function    : 
  Description : 
  
  Usage       : 
\* ------------------------------------------------------------------------- */

function getNodeHTML(node) { 
  if (typeof node == 'string') { node = document.getElementById(node); }
  var html = "";

  // display each child node
  if      (node.nodeType == 3) { // text node
    html += _htmlEncode(node.nodeValue);
  }
  if      (node.nodeType == 8) { // comment
    html += '<'+'!--' + _htmlEncode(node.nodeValue) + '--'+'>';
  }
  else if (node.nodeType == 1) { // element node
    html += "<" + node.nodeName.toLowerCase();

    // loop over element attributes
    if (node.attributes) { 
      for (var x=0; x<node.attributes.length; x++) {
        var thisAttr = node.attributes[x];
        //if (!thisAttr.specified) { continue; }
        var myAttrName  = String(thisAttr.nodeName).toLowerCase();
        var myAttrValue;
        var attrNode = node.attributes[myAttrName];

        if   (attrNode) { myAttrValue = node.attributes[myAttrName].nodeValue; } // IE mangles javascript onAction attribute values returned by getAttribute
        else            { myAttrValue = node.getAttribute(thisAttr.nodeName, 2); } 

        if (!myAttrValue) {
          if (myAttrName == 'src') { node.getAttribute(thisAttr.nodeName, 2); } // get original value, not generated absolute paths (IE6)
          if (myAttrName == 'href') { node.getAttribute(thisAttr.nodeName, 2);} // get original value, not generated absolute paths (IE6)
          if (myAttrName == 'class') { myAttrValue = node.className; } // IE6 doesn't read class value right.
          if (myAttrName == 'style') { myAttrValue = node.style.cssText; } // IE6 doesn't read style value right.
        }
        
        if (!myAttrValue) { continue; }
        
        html += ' '+ myAttrName +'="'+ _htmlEncode(myAttrValue) +'"';
      }
    }
    if (_isEmptyElement(node)) { html += " />"; }
    else                     { html += ">"; }
  }

  return html;
}

function getNodeHTMLclosingTag(node) { 
  if (node.nodeType == 1 && _isEmptyElement(node) == false) {
    return "</"+ node.nodeName.toLowerCase() +">";
  }
  else { return ""; }
}


/* ------------------------------------------------------------------------- *\
  Function    : getInnerHTML
  Description : return string of HTML within element.  Element can be passed
                as object reference or object ID.
  Usage       : var myHTML = getInnerHTML(element);
\* ------------------------------------------------------------------------- */

function getInnerHTML(obj) {
  var str = obj;
  if (typeof obj == 'string') { obj = document.getElementById(obj); }
  if (obj == null) { return alert('getInnerHTML: Invalid object name or reference: '+ str); };

//  if (useProprietaryFeatures) {
//    if (obj.innerHTML != null) { return obj.innerHTML; }
//  }

  var html = '';

  // loop over child nodes
  for (var n=0; n<obj.childNodes.length; n++) { 
    var thisNode = obj.childNodes[n];
    html += getNodeHTML(thisNode);
    if (thisNode.childNodes.length) { html += getInnerHTML(thisNode); }     // if child node has children of it's own, display those
    html += getNodeHTMLclosingTag(thisNode);
  }
  return html;
}

/* ------------------------------------------------------------------------- *\
  Function    : setInnerHTML
  Description : update the HTML contained within element.  Element can be passed
                as object reference or object ID.
  Usage       : setInnerHTML(element, newHTML);
\* ------------------------------------------------------------------------- */

function setInnerHTML(obj,html) {
  var str = obj;
  if (typeof obj == 'string') { obj = document.getElementById(obj); }
  if (obj == null) { return alert('setInnerHTML: Invalid object name or reference: '+ str); };


  if (useProprietaryFeatures) {
    if (obj.innerHTML != null) { obj.innerHTML = html; return; }
  }

  // replace old content with new content - we jump through some hoops here so
  // we can update the content by replacing one node and still keep the original
  // node so references previously returned by getElementById and like won't be broken
  
  var myDocFrag = _createDocumentFragmentFromHTML(html);        // create doc fragement from HTML string
  var tempObj = obj.cloneNode(true);                            // clone parent (and children)

  obj.parentNode.replaceChild(tempObj, obj);                    // replace old parent with clone temporarily
  while (obj.lastChild != null) { obj.removeChild(obj.lastChild); } // erase old parents children
  obj.appendChild(myDocFrag);                                   // add docfrag children to old parent
  tempObj.parentNode.replaceChild(obj, tempObj);                // put old parent (w/ new children) back

}
/* ------------------------------------------------------------------------- *\
  Function    : setOuterHTML
  Description : update the HTML contained within element.  Element can be passed
                as object reference or object ID.
  Usage       : setOuterHTML(element, newHTML);
\* ------------------------------------------------------------------------- */

function setOuterHTML(obj,html) {
  var str = obj;
  if (typeof obj == 'string') { obj = document.getElementById(obj); }
  if (obj == null) { return alert('setOuterHTML: Invalid object name or reference: '+ str); };

  if (useProprietaryFeatures) {
    if (obj.outerHTML != null) { obj.outerHTML = html; return; }
  }

  var myDocFrag = _createDocumentFragmentFromHTML(html);        // create doc fragement from HTML string
  obj.parentNode.replaceChild(myDocFrag, obj);                  // replace old parent with new content

}

/* ------------------------------------------------------------------------- *\
  Function    : appendInnerHTML
  Description : append HTML to end of element
  Usage       : appendHTML(element, newHTML);
\* ------------------------------------------------------------------------- */

function appendInnerHTML(obj,html) {

  if (typeof obj == 'string') { obj = document.getElementById(obj); }
  if (obj == null) { return alert('setInnerHTML: Invalid object name or reference'); };

  if (useProprietaryFeatures) {
    if (obj.innerHTML != null) { obj.innerHTML += html; return; }
  }

  obj.appendChild( _createDocumentFragmentFromHTML(html) );
}

/* ------------------------------------------------------------------------- *\
  Function    : _createDocumentFragmentFromHTML
  Description : create a DocumentFragment from an HTML string
\* ------------------------------------------------------------------------- */

function _createDocumentFragmentFromHTML(html) {  

  var myDocFrag = document.createDocumentFragment();
  var myframe;

  // create temp iframe and append it to document
  var frameName = '__tempframe__';
  myframe = document.createElement('IFRAME');
  myframe.setAttribute('name',frameName, 0); // required for moz1.1 window.frames
  myframe.setAttribute('id',frameName, 0);   // required for IE 6.0 window.frames
  myframe.style.position   = 'absolute'; // ie6 doesn't work with setAttribute 'style'
  myframe.style.visibility = 'hidden';
  myframe.style.top   = '0px';
  myframe.style.left  = '0px';
  document.body.appendChild(myframe);

  // write new html to iframe
  var myFrameDoc = _getIframeDocument(frameName);
  if (myFrameDoc == null) { return alert("Error accessing iframe document!"); }

  myFrameDoc.open();
  myFrameDoc.write("<body>" +html+ "</body>");
  myFrameDoc.close();

  // copy child nodes from iframe body to document fragment
  _copyChildNodes(myFrameDoc.body, myDocFrag);
  
  myframe.parentNode.removeChild(myframe);        // remove temp iframe
  return myDocFrag;                               // return document fragment
}

/* ------------------------------------------------------------------------- *\
  Function    : _copyChildNodes
  Description : copy child nodes from one node and append them to another
\* ------------------------------------------------------------------------- */

function _copyChildNodes(source, target) {  
  for (var n=0; n<source.childNodes.length; n++) { 
    var thisNode = source.childNodes[n];

    // clone node (and its children) and append it
    try { target.appendChild( thisNode.cloneNode(true) ); }

    // if that's not supported, do it manually. (IE6 doesn't support appending nodes from other documents)
    catch (exception) {
      var newNode;
      if (thisNode.nodeType == 1) { newNode = document.createElement(thisNode.nodeName); }
      if (thisNode.nodeType == 3) { newNode = document.createTextNode(thisNode.nodeValue); }
      if (thisNode.nodeType == 8) { newNode = document.createComment(thisNode.nodeValue); }
      
      if (thisNode.attributes) { // copy node attributes

        // set "src" first, to avoid IE6 bug where setting it resets height/width on images
        var mySrc = thisNode.getAttribute('src', 2);
        if (mySrc) {
          newNode.setAttribute('src', mySrc, 0);
          newNode.removeAttribute('height', 0);  // remove IE set value (let it be set below)
          newNode.removeAttribute('width', 0);   // remove IE set value (let it be set below)
        }

        for (var x=0; x<thisNode.attributes.length; x++) {
          var thisAttr = thisNode.attributes[x];
          if (!thisAttr.specified) { alert("debug note: thisAttr.specified isn't reliable, consider checking the attribute's value for truth instead"); continue; }

          var myAttrName = thisAttr.nodeName.toLowerCase();
          if (myAttrName == 'src') { continue; } // skip src, see above
          
          var myAttrValue = thisNode.getAttribute(thisAttr.nodeName, 2); // get original value, not generated absolute paths (IE6)
          newNode.setAttribute(myAttrName, myAttrValue, 0);
        }
      }
      target.appendChild(newNode);
      if (thisNode.hasChildNodes()) { _copyChildNodes(thisNode, newNode); }
    }
  }
}

/* ------------------------------------------------------------------------- *\
  Function    : _isEmptyElement
  Description : check whether a element is allowed to be empty or not
                (eg: does it need a closing tag).
\* ------------------------------------------------------------------------- */

function _isEmptyElement(node) {
  switch (node.nodeName.toLowerCase()) {
    case 'area':
    case 'base':
    case 'br':
    case 'col':
    case 'hr':
    case 'img':
    case 'input':
    case 'link':
    case 'meta':
    case 'param':
      return true;
    default:
      return false;
  }
}

/* ------------------------------------------------------------------------- *\
  Function    : _getIframeDocument
  Description : return document obj for specied iframe "id"
\* ------------------------------------------------------------------------- */

function _getIframeDocument(frameName) {
  var obj = document.getElementById(frameName);
  if (obj.name != obj.id) { return alert("getIframeDocument: frame name and ID must be the same"); }

  if (obj.contentDocument) {          // DOM2, moz1+, NS6
    return obj.contentDocument;
  } else if (obj.contentWindow) {  // moz1+, IE5.5+
    return obj.contentWindow.document;
  } else if (window.frames) {      // DOM0, moz1+, NS6, IE5+ (Mac/Win)
    return window.frames[frameName].document; // some browser go by name, some by ID, set both.
  }
}

/* ------------------------------------------------------------------------- *\
  Function    : _htmlEncode
  Description : encode special characters as html entities
\* ------------------------------------------------------------------------- */

function _htmlEncode(str) {
  if (!str || !str.length) { return str; }
  str = str.replace(/&/ig, "&amp;");
  str = str.replace(/</ig, "&lt;");
  str = str.replace(/>/ig, "&gt;");
  str = str.replace(/"/ig, "&quot;");
  return str; 
}

/* ------------------------------------------------------------------------- *\
  Function    : forceRedraw
  Description : Some browsers don't redraw elements properly when you move
                things around with DHTML.  This tricks them into redrawing
                the screen.
\* ------------------------------------------------------------------------- */

function forceRedraw() {

  // Mac IE 5.0
  if (navigator.userAgent.indexOf('Mac') > 0 && navigator.userAgent.indexOf('MSIE 5') > 0 ) {
    document.bgColor = document.bgColor;
  }
  
  // Netscape 6
  if (navigator.userAgent.indexOf('Netscape6') > 0) {
    document.body.style.visibility = "hidden";
    document.body.style.visibility = "visible";
  }

}