/* Copyright (C) 1996-2009 MicroStrategy Incorporated, All rights reserved. Confidential. */

/**
 * Manages iframe updates.
 * @class
 */
var iframe = new function() { }
iframe.prototype = new Object();

/**
 * Stores whether the promptFunctions are included in the page.  Indicates that we shouldn't show the wait window when the prompts are loaded.
 * This field is set once, but then never referenced so my guess is that it isn't used anymore.
 * @type Boolean
 * @default false
 */
iframe.isPromptedReport = false;
/**
 * Indicates that the show wait page has been called at least once.  Not sure why, but it may be related to old style prompts.  It's value is set to true in 
 * {@link iframe.showWaitPage} and then checked in {@link reloadPreviousPage}.
 * @type Boolean
 * @default false
 */
var hasLoaded = false;

/**
 * Indicates when to hide the tree processing message in treev3.js.  Not sure where that is used.
 * @type Boolean
 * @default false
 */
iframe.isTreeProcessing = false;

/**
 * Indicates whether the user has hit the cancel button.  Not sure it works anymore.
 * @type Boolean
 * @default false
 */
iframe.isAborting = false;

/**
 * Holds the handle to a window.setTimeout for showing the wait page.
 * @type Integer
 */
iframe.windowTimer = null;

/**
 * Holds a reference the to modal curtain that is positioned behind the please wait dialog.
 * @type HTMLElement
 */
iframe.waitCurtain = null;

/**
 * Flag to indicate that the iframe is currently replacing components.
 * @type Boolean
 * @default false
 */
iframe.isProcessing = false;

/**
 * Stores the new cssText for the consolidated grid stylesheet.
 * @type String
 */
iframe.consolidatedStyles = {};

/**
 * indicate if it's during partial update.  
 */

iframe.onWaitState = false;
/**
 * Called from within the iframe to notify the parent window that the iframe is about to make a request.
 * @param {Boolean} isXHR [true] indicating the method is invoked within XHR context thus checkChildStatus call should be avoided
 */
iframe.notifyParent  = function(isXHR) {
    // Disable wait page during juil execShowPopup.
    if (self.supressWaitPage) return;
    
    // display curtain to prevent user interaction during load.
    iframe.showWaitCurtain();

    // customizable delay in showing wait page.
    var delay = 0,
    	showWait = true;
    
    if (window.microstrategy) {
        delay = parseInt(window.microstrategy.waitPageDelay);
        if (isNaN(delay) || delay < 0) delay = 0;
        showWait = window.microstrategy.showWaitPopup;
    }
    if (showWait) {
    	if (delay == 0) {
    		iframe.showWaitPage();
    	} else if (delay != -1) {
    		iframe.windowTimer = window.setTimeout("iframe.showWaitPage()", delay);
    	}
    }
    
    if (window.microstrategy) {
        window.microstrategy.showWaitPopup = true;
    }    
    
    if(!isXHR){
	    if (!window.isUnloading) {
	        window.setTimeout("iframe.checkChildStatus()", 3000);
	    }
    }
}

/**
 * Called when the user hits the 'Cancel' button on the Processing Request dialog in Report mode.
 */
iframe.stopWindow = function() {
    iframe.isAborting = true;
    if (window.event) window.event.cancelBubble = true;

    if(window.frameManager && window.frameManager.document) {
        window.frameManager.document.execCommand("Stop");
    }

    document.execCommand("Stop");
    if (microstrategy.updateManager) microstrategy.updateManager.acknowledgeRequest();
    iframe.hideWaitPage();
}

/**
 * Reloads previous browser page.  Unable to find any static reference to this function so it must be in the html page. 
 */
function reloadPreviousPage() {
    if (hasLoaded) {
        var oNewDoc = window.document.open("text/html");
        oNewDoc.close();
        window.history.go(-1);
    }
}

/**
 * Check the status of the iframe after 3 seconds to look for invalid iframe contents.  If found, the html is transferred to the parent window.
 */
iframe.checkChildStatus = function() {
    if (!iframe.isAborting) {
        try {
        	if(window.frameManager && window.frameManager.document && window.frameManager.document.readyState == "complete" && window.document.readyState == "complete") {
        		if(!window.frameManager.isIframe) {
        			var sMarkup = window.frameManager.document.documentElement.innerHTML;
        			var oNewDoc = window.document.open("text/html");
        			if (sMarkup.indexOf("<!DOCTYPE") == -1) {
        				oNewDoc.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \" >");
        			}
        			oNewDoc.write(sMarkup);
        			oNewDoc.close();
        		}
        		if (!iframe.isProcessing) {
        			window.setTimeout("if (typeof(iframe)!= 'undefined' && typeof(iframe.hideWaitPage) != 'undefined') iframe.hideWaitPage();", 1000);
        		}
        	}
        	else {
        		window.setTimeout("if (typeof(iframe)!= 'undefined') iframe.checkChildStatus()", 3000);
        	}
        }
        catch (err) {
            iframe.hideWaitPage();
        }
    } else {
        // Aborted - make sure the Iframe is ready to process following requests ...
        if(window.frameManager && window.frameManager.document && window.frameManager.document.readyState == "complete") {
            if(!window.frameManager.isIframe && !window.frameManager.document.body.onbeforeunload) {
                window.frameManager.document.body.onbeforeunload = new Function("window.parent.iframe.notifyParent();");
            }
        }
    }
}

/**
 * Creates, positions and displays the modal curtain whenever the iframe makes a request to the server.
 */
iframe.showWaitCurtain = function() {
    // Disable wait page during juil execShowPopup.
    if (self.supressWaitPage) return;
    iframe.onWaitState = true;
    var clientHeight = getClientHeight();
    var clientWidth = getClientWidth();
    var left = getDocumentScrollLeft();
    var top = getDocumentScrollTop();
    if (iframe.waitCurtain == null) {
        var div = document.createElement("div");
        div.className = "divWaitCurtain";
        div.appendChild(document.createTextNode(" "));
        div.onmousedown = new Function("if (typeof(window.event) != \"undefined\") {window.event.cancelBubble = true; } return false;");
        div.ondblclick = new Function("if (typeof(window.event) != \"undefined\") { window.event.cancelBubble = true; } return false;");
        iframe.waitCurtain = document.body.appendChild(div);
    }
    if (!bIsW3C) enablePulldowns(document.body, false);
    var wcs = iframe.waitCurtain.style;
    if (clientHeight > 0) wcs.height = clientHeight + "px";
    if (clientWidth > 0) wcs.width = clientWidth + "px";
    if (left > 0) wcs.left = left + "px";
    if (top > 0) wcs.top = top + "px";
    wcs.display = "block";
}

/**
 * Creates and shows wait page whenever the iframe makes a request to the web server.
 */
iframe.showWaitPage = function() {
    // Disable wait page during juil execShowPopup.
    if (self.supressWaitPage) return;

    //Don't display 'Wait' window when prompts are displayed.
    //currentPin will be set to at least 1 when prompts are loaded.
    //Therefore, if it's -1, then it means prompts haven't been loaded yet.
    iframe.isProcessing = false;

    if (currentPin == -1) {
    	hasLoaded = true;
    	var bone = microstrategy.bone("divWaitBox");
    	if (bone && bone.elem) {
    		bone.elem.style.left = ((getClientWidth() - getObjWidth(bone.elem)) / 2 + getDocumentScrollLeft()) + 'px';
    		bone.elem.style.top  = ((getClientHeight() - 100) / 2 + getDocumentScrollTop()) + 'px';
    		bone.elem.style.zIndex = 9999;

    		if (!bIsW3C) togglePulldowns(bone.elem, false);
    		
    		bone.elem.style.visibility = "visible";
    	}
    	iframe.isAborting = false;
    }
}

/**
 * Hides the wait dialog when the iframe request is complete and all components have been updated.
 * @param {Boolean} hideWaitCurtain [true] Indicates whether to hide the modal wait curtain.
 */
iframe.hideWaitPage = function(hideWaitCurtain) {
    window.clearTimeout(iframe.windowTimer);
    var el = document.getElementById('divWaitBox');
    if (el && el.style.visibility == 'visible') {
        var bone = microstrategy.bone("divWaitBox");
        bone.closeDialog();
    }
    
    /* //The feature is not turned on, so it is not necessary here. 
    var visibleWaitBoxes = document.getElementsByName("mstrWebsimplewait");
    for (var i = 0; i < visibleWaitBoxes.length; i++) {
        visibleWaitBoxes[i].style.visibility = 'hidden';
    }
    */
    
    if (typeof(hideWaitCurtain) == 'undefined') hideWaitCurtain = true;
    if (hideWaitCurtain) iframe.hideWaitCurtain();
}

/**
 * Hides the modal wait curtain.
 */
iframe.hideWaitCurtain = function() {
    if (iframe.waitCurtain) {
        iframe.waitCurtain.style.display = "none";
        if (!bIsW3C) enablePulldowns(document.body, true);
    }
    iframe.onWaitState = false;
}

/**
 * Clears the IFRAME html attribute on every second parent node of type DIV.  It has no limit so I would expect that it would travel up 
 * the entire DOM tree until it encounters the HTML tag.  We should consider refactoring this method.
 * @param {HTMLElement} iframeComponent The HTMLElement with which to begin the non-inclusive upward traversal.  
 */
iframe.clearIFrameParents = function(iframeComponent) {
     var current = iframeComponent,
     	 parent = null;
     
     while ((parent = current.parentNode) != null) {
        if (parent.tagName == "DIV" && parent.getAttribute("IFRAME") == 'true') {
            parent.setAttribute('IFRAME', 'false', 0);
        }
        current = parent;
     }
}

/**
 * Called from the iframe html page to begin the update procedure.
 * @param {Window} parentWindow The {@link Window} that contains the iframe.
 * @param {Window} iframeWindow The {@link Window} within the iframe. 
 */
iframe.replaceComponents = function(parentWindow, iframeWindow) {
  if (iframeWindow != parentWindow && !iframe.isAborting) {
	  this.consolidatedStyles = {};
      iframe.isProcessing = true;

      //visible select boxes will cause IE to flash during iFrame update, so hide them.
      if (!bIsW3C) iframe.togglePulldownChildren(parentWindow.document.body, false);

      var aIFrameDivs = iframeWindow.document.getElementsByTagName("div"),
	      aIFrameForms = iframeWindow.document.getElementsByTagName("form"),
	      aIFrameComments = iframeWindow.document.getElementsByTagName("comment"),
	      aScripts = null,
	      i, sHTML, parent, current,id;

      for (i = 0, len = aIFrameComments.length; i < len; i++) {
        if (aIFrameComments[i].getAttribute("IFRAME") == 'true') {
            // if the replacable component exsits on the page, clear the parents' iframe=true
            if(window.document.getElementById(aIFrameComments[i].id)) {
               iframe.clearIFrameParents(aIFrameComments[i]);
            } 
            ////TQMS#362173 - if the component, except for modal dialog, doesn't exist on page, set iframe to false and go check the parents
            else if (aIFrameComments[i].getAttribute("dialog") != 'true' && !aIFrameComments[i].getAttribute("css")) { 
                aIFrameComments[i].setAttribute('IFRAME', 'false', 0);
             }
         }
      }

      for (i = 0, len = aIFrameDivs.length; i < len; i++) {
        if (aIFrameDivs[i].getAttribute("IFRAME") == 'true') {
            // if the replacable component exsits on the page, clear the parents' iframe=true
            if(window.document.getElementById(aIFrameDivs[i].id)) {
               iframe.clearIFrameParents(aIFrameDivs[i]);
            } else {        // if the component doesn't exist on page, set iframe to false and go check the parents 
               aIFrameDivs[i].setAttribute('IFRAME', 'false', 0);
            }
         }
      }

      for (i = 0, len = aIFrameComments.length; i < len; i++) {
        if ((aIFrameComments[i].getAttribute("IFRAME") == 'true') && (aIFrameComments[i].getAttribute("ISEMPTY") != 'true')) {
          if (typeof aIFrameComments[i].text != 'undefined') {
        	  sHTML = aIFrameComments[i].text;
          } else {
        	  sHTML = aIFrameComments[i].innerHTML;
          }
          // Should begin with < and end with >
          var indexBegin = sHTML.indexOf("<");
          var indexEnd = sHTML.lastIndexOf(">");
          sHTML = sHTML.substr(indexBegin,indexEnd+1-indexBegin);

          sHTML = sHTML.substring(4, sHTML.length - 3);
          sHTML = sHTML.replace(/'/g, "\'");
          parentWindow.iframe.updateComponent(aIFrameComments[i].getAttribute("ID"), sHTML, aIFrameComments[i], true);
        }
      }

      for (i = 0, len = aIFrameDivs.length; i < len; i++) {
        if (aIFrameDivs[i].getAttribute("IFRAME") == 'true' && aIFrameDivs[i].getAttribute("ISEMPTY") != 'true') {
          if (aIFrameDivs[i].getAttribute("errBox") != 'true' || currentModalEditor.length == 0) {
            sHTML = iframe.getOuterHTML(aIFrameDivs[i]);
            sHTML = sHTML.replace(/'/g, "\'");
            id = aIFrameDivs[i].getAttribute("ID");
            parentWindow.iframe.updateComponent(id, sHTML);
          } else {
            sHTML = aIFrameDivs[i].innerHTML;
            if (sHTML.length > 0) {
              showMessage( {contents:sHTML, elements:microstrategy.OK_BUTTON, type:mstrMsgBoxImpl.MSG_ERROR});
            }
          }
        }
      }
      document.title =  window.frameManager.pageTitle;

      for (var styleId in this.consolidatedStyles) {
          updateStyleContainer(this.consolidatedStyles[styleId], styleId);      
      }

      //visible select boxes will cause IE to flash during iFrame update, so unhide the ones we previously hid.
      if (!bIsW3C) iframe.togglePulldownChildren(parentWindow.document.body, true);

      //Hide tree processing at the end...
      if (iframe.isTreeProcessing) {
          removeTreeWaitMessage();
      }
      
      //#367569, #372071, #367950, #370530 - dynamic JS loading in IE   
      microstrategy.loadDynamicJS();

      microstrategy.registerNewBones();
  }
}

/**
 * Toggles visibility of select elements.  Only called for IE because select elements cause flashing during the update process.
 * @param {HTMLElement} oElem The windows body element that is having it's components replaced.
 * @param {Boolean} bShow Whether to show or hide the select elements.
 */
iframe.togglePulldownChildren = function(oElem, bShow) {
    try {
        var pulldowns = oElem.getElementsByTagName('select');
        if (pulldowns.length) {
            if (bShow) {
                for (var i = 0, len = pulldowns.length; i < len; i++) {
                	var owner = pulldowns[i].getAttribute('hd');
                	if (owner == null || owner.length == 0) {
                		pulldowns[i].style.visibility = 'visible';
                	}
                }
            } else {
                for (var i = 0, len = pulldowns.length; i < len; i++) {
                	pulldowns[i].style.visibility = 'hidden';
                }
            }
        }
    }
    catch(localerr) {}
}

iframe.createPlaceHolder = function(sComponentID) {
	var oDivNode = document.createElement('div');
    oDivNode.id = sComponentID;
    document.body.appendChild(oDivNode);
}

/**
 * Extract the javascript tags from an html element, cache them in to scritArray for later evaluation
 * @param {HTMLElement} oDivNode  The html element that needs to have its script tags extracted
 * @param {Array} scriptArray The array hosting javascript tags.
 */
iframe.extractScript = function(oDivNode, scriptArray){
    var aScripts = oDivNode.getElementsByTagName("SCRIPT");   
    if ((aScripts) && (aScripts.length > 0)) {
        for (var j = 0; j < aScripts.length; j++) {
            if (aScripts[j].getAttribute("language") != "VBSCRIPT" && (aScripts[j].getAttribute("id") == "" || aScripts[j].getAttribute("id") == null)) {
                var script = trim(aScripts[j].innerHTML);
                if (script.indexOf("<!--") == 0) {
                    script = script.substring(4, script.length-3);
                }
                scriptArray.push(script);
            }
        }
    }
}

/**
 * Extract the image tags from an html element, cache them in to chartArray for resource loading
 * @param {HTMLElement} oDivNode  The html element that needs to have its image tags extracted
 * @param {Array} chartArray The array hosting image tags.
 */
iframe.extractImage = function(oDivNode, chartArray){
   if(!bIsW3C) {//TQMS 282298: double fetching graphs in IE   
	    var imgArray = oDivNode.getElementsByTagName("IMG");
	    if(imgArray && (imgArray.length > 0)){
	        for(var j = 0; j< imgArray.length; j++){       
	            if(imgArray[j].getAttribute("dsrc") != null) {
	                chartArray.push(imgArray[j]);
	            }
	        }
	    }
	    imgArray = oDivNode.getElementsByTagName("INPUT");
	    if(imgArray && (imgArray.length > 0)){
	        for(var j = 0; j< imgArray.length; j++){       
	            if(imgArray[j].getAttribute("dsrc") != null) {
	                chartArray.push(imgArray[j]);
	            }
	        }
	    }
	}
}

/**
 * Replaces the html for a single component.
 * @param {String} sComponentID The ID of the component to replace.
 * @param {String} sNewHTML The HTML fragment used to overwrite the component.
 */
iframe.updateComponent = function(sComponentID, sNewHTML, iframeNode, shouldCreatePlaceHolder) {
    var aScripts = null,
    	oParentDivs,
    	oParentDiv;

   if (iframeNode && iframeNode.getAttribute("slid")) {
        var slices = document.getElementsByName(sComponentID);
        if (slices && slices.length > 0) {
            for(var i = 0, len = slices.length; i < len; i++) {
                if (slices[i].getAttribute("slid") == iframeNode.getAttribute("slid")) {
                    oParentDiv = slices[i];
                    break;
                }
            }   
        }
    } 
    
    if (!oParentDiv) {
    
        oParentDivs = document.getElementById(sComponentID);

	    if (!oParentDivs && shouldCreatePlaceHolder) {
	        this.createPlaceHolder(sComponentID);
	        oParentDivs = document.getElementById(sComponentID);
	    }
        
        if (oParentDivs) {
	         if (oParentDivs.length > 1) {
	            for(i = 0, len = oParentDivs.length; i < len; i++) {
	                if (oParentDivs[i].tagName == "DIV") {
	                    oParentDiv = oParentDivs[i];
	                    break;
	                }
	            }
	        } else {
	            oParentDiv = oParentDivs;
	        }
        }
    }

    if (oParentDiv) {

        var sReplaceHTML = sNewHTML.replace(/\r\n/g, "");
        var oDivNode = iframe.createElementFromHTML(sReplaceHTML);

        var scriptArray = [];
        iframe.extractScript(oDivNode, scriptArray);
       
        var chartArray = [];
        iframe.extractImage(oDivNode, chartArray);

        if (oDivNode.getAttribute("message") == 'true') {
            showMessage({contents:sNewHTML, elements:microstrategy.OK_BUTTON, type:mstrMsgBoxImpl.MSG_WARNING});
        }
        if (oDivNode.getAttribute("css") == '1') {
            var styleId = oDivNode.getAttribute("styleid");
            if (!this.consolidatedStyles[styleId]) {
                this.consolidatedStyles[styleId] = "";
            }
        	this.consolidatedStyles[styleId]  = consolidateStyleSheets(oDivNode, this.consolidatedStyles[styleId], oDivNode.getAttribute("styleid"));
        } else {
        	var commentsIdx = sReplaceHTML.indexOf("<comment");
        	if (commentsIdx > -1) return;

        	if (oParentDiv.getAttribute(mstrHTMLAttributes.ATTR_MODAL) == 'true' || (oParentDiv.popupMask)) {
        		togglePulldowns(oParentDiv, true);
        	}
        	if (oDivNode.getAttribute("partialUpdate") && oParentDiv.childNodes.length > 1){//partial update
        		oParentDiv.innerHTML = oDivNode.innerHTML;
        	} else {//full update
        		if(bIsW3C && !bIsIE8) {
        			iframe.setOuterHTML(oParentDiv, oDivNode);
        		} else {

        			//Replaces one node in the DOM tree with another.
        			//replaceNode(oParentDiv, oDivNode);
        			if (oParentDiv && oDivNode) {
        				var p = oParentDiv.parentNode;
        				p.insertBefore(oDivNode, oParentDiv);
        				p.removeChild(oParentDiv);
        			}

        			if (chartArray.length > 0) {//TQMS 282298: double fetching graphs in IE   
        				for(var j = 0, cnt = chartArray.length; j < cnt; j++){
        					chartArray[j].src = chartArray[j].getAttribute("dsrc");
        				}
        			}
        		}
        	}

        	for(var j = 0, len = scriptArray.length; j < len; j++) {
        		eval(scriptArray[j].toString());  
        	}
        }
    }
}


/**
 * Creates an HTMLElement from an HTML fragment.  
 * @param {String} tagStr The HTML fragment for creating the new element.
 * @type HTMLElement
 * @returns The new HTML Element.
 */
iframe.createElementFromHTML = function(tagStr) {
    var tempDiv = document.createElement("div");
    tempDiv.innerHTML = tagStr;
    iframe.adjustNode(tempDiv);
    
    return tempDiv.firstChild;
}

/**
 * This method is used to overcome a Firefox bug where SCRIPT and STYLE elements are stripped from the new component HTML.  
 * We should verify that this is still an issue and that there is not a better way to do it (perhaps using HTML fragments objects).
 * @param {HTMLElement} tempDiv The HTML element that needs to be adjusted/corrected in Firefox. 
 */
iframe.adjustNode = function(tempDiv) {
    if (bIsW3C && tempDiv.childNodes.length > 1) {
        // Firefox 1.0 tends to pull out SCRIPT and STYLE tags
    	// out of the target tag under some circumstances. This is
    	// detected by counting the resulting number of children
    	// after setting the inner HTML
        iframe.adjustNodes(tempDiv);
        
        // To fix TQMS 314350: When the target html is content of a HTML Document, 
        // Some tags will go out of target tag in Firefox. We need to reinsert it into target tag
        if (microstrategy.pageName == 'document') {
            iframe.adjustNodesForHTMLDocument(tempDiv);
        }
    }
}


/**
 * Returns the outerHTML of an element.  Needed because W3C compliant browsers doesn't support outerHTML.  We should consider refactoring to use DOM Standard methods.
 * @param {HTMLElement} oTag The tag from which to get the outerHTML.
 * @type String
 * @returns The outerHTML of the supplied HTMLElement.
 */
iframe.getOuterHTML = function(oTag) {
	return (typeof oTag.outerHTML != "undefined") ? oTag.outerHTML : iframe.getManualOuterHTML(oTag);
}

/**
 * Private method used to simulate outerHTML in W3C compliant browsers.
 * @param {HTMLElement} oTag The tag from which to get the outerHTML.
 * @type String
 * @returns The outerHTML of the supplied HTMLElement.
 */
iframe.getManualOuterHTML = function(oTag) {
    var result = "<" + oTag.tagName;

    // get all attributes...
    var attrs = oTag.attributes;
    for (var i = 0, len = attrs.length; i < len; i++) {
        var att = attrs[i];
        if (att.specified && att.nodeName != '_moz-userdefined') {
            result += " " + att.nodeName + "=\"" + att.nodeValue + "\"";
        }
    }

    result += ">" + oTag.innerHTML + "</" + oTag.tagName + ">";
    return result;
}

/**
 * Reorders an HTMLElements childNodes so that style related elements (STYLE and LINK) are at the top and script element are at the bottom.  Needed to deal with 
 * a Firefox bug where SCRIPT and STYLE elements are stripped from the new component HTML.  We should verify that this is still an issue.
 * @param {HTMLElement} oTag The tag whose childNodes will be reordered.
 */
iframe.adjustNodes = function(oTag) {
    var children = oTag.childNodes;
    // Last child will always be main (target) tag
    var div = oTag.lastChild;
    var childrenLength = children.length;
    for (var i=0; i < childrenLength; i++) {
        var child = children[0];
        // Move style to the top, script to the bottom
        if (child.tagName.toLowerCase() == "script") {
            div.appendChild(child);
        } else if (child.tagName.toLowerCase() == "style") {
            div.insertBefore(child, div.firstChild);
        } else if (child.tagName.toLowerCase() == "link") {
            div.insertBefore(child, div.firstChild);
        }
    }
}

/** 
 * Reorders an HTMLElements childNodes such that all but the first nodes will be inserted into the first node.  Seems to be specific to MSTR HTML Documents.  Good
 * candidate for moving to another location.
 * @param {HTMLElement} oTag The tag whose childNodes will be reordered.
 */
iframe.adjustNodesForHTMLDocument = function(oTag) {
    var children = oTag.childNodes;
    // insert all other tags inside first tag
    var div = oTag.firstChild;
    var childrenLength = children.length;
    for (var i=1; i < childrenLength; i++) {
        var child = children[1];
        div.appendChild(child);
    }
}

/**
 * Sets the outerHTML of an element.  Needed because W3C compliant browsers doesn't support outerHTML.  We should consider refactoring to use DOM Standard methods.
 * @param {HTMLElement} oTag The target tag for the new HTML and attributes.
 * @param {HTMLElement} oNewTag The source tag for the new HTML and attributes.
 */
iframe.setOuterHTML = function(oTag, oNewTag) {
    // Remove all attributes on this tag...
    var attrs = oTag.attributes;
    for (var i= attrs.length - 1; i > -1; i--) {
        var att = attrs[i];
        if (att.specified) {
            oTag.removeAttribute(att.nodeName);
        }
    }

    // Set new attributes
    attrs = oNewTag.attributes;
    for (var i=0, len = attrs.length; i < len; i++) {
        var att = attrs[i];
        if (att.specified && att.nodeName != '_moz-userdefined') {
            oTag.setAttribute(att.nodeName,att.value);
        }
    }

    oTag.style.cssText = oNewTag.style.cssText;
    if (oTag.innerHTML.length == 0 && oNewTag.innerHTML.length == 0) return;

    oTag.innerHTML = oNewTag.innerHTML;
}

