/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2005 SumTotal Systems, Inc. All rights reserved.
//
// The copyright to the computer software herein is proprietary and remains
// the property of SumTotal Systems, Inc. It may be used and/or copied only with
// the written consent of SumTotal Systems, Inc. or in accordance with the terms and
// conditions stipulated in the agreement/contract under which this software
// has been supplied.
//
// $Id: SYS_browser.js,v 1.30 2007/05/02 00:40:26 mstewart Exp $
// $Date: 2007/05/02 00:40:26 $
// $RCSfile: SYS_browser.js,v $
// $Revision: 1.30 $
//
// Abstract:
//
//    Browser class to identify browsers and operating system
//
// Revision History:
//
//    2002-02-25   Anand Arvind    Created file
//
/////////////////////////////////////////////////////////////////////////////

var BROWSER_UNKNOWN              = 0
var BROWSER_IE                   = 1
var BROWSER_MOZILLA              = 2
var BROWSER_NETSCAPE             = 3

/////////////////////////////////////////////////////////////////////////////
//
// Function Name : _ObjBrowser
//
// Parameters    :
//
// Return        :
//
// Synopsis      :
//
/////////////////////////////////////////////////////////////////////////////
function _ObjBrowser()
{

    this.$nBrowser        = BROWSER_UNKNOWN ;
    this.$nBrowserVersion = 100 ;
    this.$strUA           = String(navigator.userAgent);

    _ObjBrowser.prototype.Init = function()
    {

        var $nBrowserChar    = "";
        var $nBrowserStart   = 0 ;

        if ( this.$strUA.indexOf("MSIE") >= 0 )
        {

            this.$nBrowser        = BROWSER_IE ;
            this.$nBrowserVersion = "";

            $nBrowserStart   = this.$strUA.indexOf("MSIE")+5
            $nBrowserChar    = this.$strUA.charAt($nBrowserStart);

            while ( $nBrowserChar != ";" )
            {
                if ( ( $nBrowserChar >= '0' && $nBrowserChar <= '9' ) || $nBrowserChar == '.' )
                    this.$nBrowserVersion += $nBrowserChar ;
                $nBrowserStart++;
                $nBrowserChar     = this.$strUA.charAt($nBrowserStart);
            };

           this.$nBrowserVersion = parseInt( parseFloat( this.$nBrowserVersion ) * 100 ) ;

        }
        else if ( this.$strUA.indexOf("Mozilla") >= 0 )
        {
            this.$nBrowser        = BROWSER_MOZILLA ;
            this.$nBrowserVersion = parseInt ( (this.$strUA.substring( this.$strUA.indexOf("/") + 1,  this.$strUA.indexOf("/") + 5  )) * 100 );
        }

    };

    _ObjBrowser.prototype.IsNetscape = function()
    {
        if ( this.$nBrowser == BROWSER_MOZILLA )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsFirefox = function()
    {
        if ( this.$strUA.indexOf("Firefox") > -1 )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsIE = function()
    {
        if ( this.$nBrowser == BROWSER_IE )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsMozilla = function()
    {
        if ( this.$nBrowser == BROWSER_MOZILLA )
            return true ;
        return false ;
    }


    _ObjBrowser.prototype.Version = function()
    {
        return this.$nBrowserVersion ;
    }

    _ObjBrowser.IsOSWindows = function()
    {
        if ( this.$strUA.indexOf("win") >= 0 || this.$strUA.indexOf("Win") >= 0 )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsWin95 = function()
    {
        if ( this.$strUA.indexOf("Windows 95") >= 0 )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsWinNT = function()
    {
        if ( this.$strUA.indexOf("Windows NT") >= 0 || this.$strUA.indexOf("WinNT") >= 0 )
            return true ;
        return false ;
    }


    _ObjBrowser.prototype.IsWin2000 = function()
    {
        if ( this.$strUA.indexOf("Windows NT 5.0") >= 0 )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsWinXP = function()
    {
        if ( this.$strUA.indexOf("Windows NT 5.1") >= 0 )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.Supports = function(strValue)
    {

        if ( strValue == "try/catch" )
        {
            if ( this.$nBrowser == BROWSER_IE && this.$nBrowserVersion >= 500 )
                return true ;
        };

        if ( strValue == "highlights" )
        {
            //if ( this.$nBrowser == BROWSER_IE && this.$nBrowserVersion >= 500 )
            //if ( this.$nBrowserVersion >= 500 )
                return true ;
        };

        return false ;

    }

    _ObjBrowser.prototype.IsNS4 = function()
    {
        if ( this.IsNetscape() && this.Version() < 500 )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsNS6 = function()
    {
        if ( this.IsNetscape() && this.Version() >= 500 )
            return true ;
        return false ;
    }

    _ObjBrowser.prototype.IsIE4 = function()
    {
        if ( this.IsIE() && this.Version() < 500 )
            return true ;
        return false ;
    }

}



///
/// <summary>
///  TO DO
///   
///  
/// </summary>
/// <parameters>
///  <param name= "">TO DO </param>
/// </parameters>
/// <remarks>
///  TO DO
///  document.all returns a reference to the collection of elements contained 
///  by the object.
///  When document.all is supplied with a string that specifies the element
///  or collection to retrieve and if there is more than one element with the 
///  name or id property equal to the string, the method returns a collection 
///  of matching elements.
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// </remarks>
/// <returns>  
///  TO DO
///  
/// </returns>
///

document.CBAPI_all = SYS_Browser_all

function SYS_Browser_all (str)
{ 
        // document.all is not a W3C standard
        // Use getElementById/getElementsByName instead

        // Check if there is an element with the given ID 
        // If there is an element with the given ID return it
        // else return a collection of elements with the name attribute as the given string
        return ( (document.CBAPI_GetElementByID(str)) ? (document.CBAPI_GetElementByID(str)) : 
                                                     (document.CBAPI_GetElementsByName(str)) );
}

///
/// <summary>
///  The easiest way to access an element in the document irrespective its position 
///  is by document.all method. This being not a W3C standard needs to be 
///  avoided. 
///  This method takes an elementID as a parameter and returns the 
///  corresponding element.
/// </summary>
/// <parameters>
///  <param name= "elemID">String - The value of ID attribute of the required element</param>
/// </parameters>
/// <remarks>
///  If the ID value belongs to a collection, this method returns the first object 
///  in the collection.
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// </remarks>
/// <returns> Returns the element with the specified value of the ID attribute. 
///  Returns null if the element with the given ID is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///
document.CBAPI_GetElementByID = SYS_Browser_GetElementByID

function SYS_Browser_GetElementByID(elemID)
{
        return ( (document.getElementById) ? document.getElementById(elemID) : 
                           ((document.all) ? document.all(elemID) : null) );
}


///
/// <summary>
/// GetElementById is case-insensitive in IE - work around this by 
/// checking for the found object not having the same ID as the requested ID,
/// save and clear the ID for that object, and try again (repeat as needed)  when done,
/// restore the saved IDs
/// </summary>
/// <parameters>
///  <param name= "doc">the document object to search for the element on</param>
///  <param name= "id">String - The value of ID attribute of the required element</param>
/// </parameters>
/// <returns> Returns the element with the specified value of the ID attribute. 
///  Returns null if the element with the given ID is not found
/// </returns>
///
function SYS_Browser_CaseSensitiveGetElementById(doc,id)
{
    var idStack = [];
    var element = doc.getElementById(id);
    if (!element)
    {
        // if element is not found no need to continue
        return element;
    }

    while (element && element.id != id)
    {
        idStack.push({id:element.id,element:element});
        element.id='';
        element = doc.getElementById(id);
    }

    var stackLength = idStack.length;
    for (var stackIndex = 0; stackIndex<stackLength; stackIndex++)
    {
        idStack[stackIndex].element.id = idStack[stackIndex].id;
    }
    idStack = null;
    return element;
}


///
/// <summary>
///  The easiest way to access an element in the document irrespective its position 
///  is by document.all method. This being not a W3C standard needs to be 
///  avoided. 
///  This method takes an element name as a parameter and returns the 
///  corresponding element.
/// </summary>
/// <parameters>
///  <param name= "tagName">String - The name of the required element</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// </remarks>
/// <returns> Returns a collection of elements with the specified element name. 
///  Returns null if no element with the given name is found
///  or if the browser does not support any of the used methods.
/// </returns>
///
document.CBAPI_GetElementsByTag = SYS_Browser_GetElementsByTag

function SYS_Browser_GetElementsByTag(tagName)
{
        var elem = (document.getElementsByTagName) ? document.getElementsByTagName(tagName) : 
                           ((document.all) ? document.all(tagName) : null);
        return elem;
}

///
/// <summary>
///  The easiest way to access an element in the document irrespective its position 
///  is by document.all method. This being not a W3C standard needs to be 
///  avoided. 
///  This method takes the value of a NAME attribute as a parameter and returns the 
///  corresponding element.
/// </summary>
/// <parameters>
///  <param name= "elemName">String - The value of the NAME attribute of 
///   required element</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// </remarks>
/// <returns> Returns a collection of elements with the same NAME attribute. 
///  Returns null if the element with the given NAME attribute is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///
document.CBAPI_GetElementsByName = SYS_Browser_GetElementsByName

function SYS_Browser_GetElementsByName(elemName)
{
        var elem = (document.getElementsByName) ? document.getElementsByName(elemName) : 
                           ((document.all) ? document.all(elemName) : null);
        return elem;
}

///
/// <summary>
///  The easiest way to access an element in the document irrespective its position 
///  is by document.all method. This being not a W3C standard needs to be 
///  avoided. 
///  This method takes the value of a NAME attribute or element name as a parameter 
///  and returns the corresponding element.
/// </summary>
/// <parameters>
///  <param name= "param" >elemName: String - The value of the NAME 
///   attribute of required element, tagName: String - The name of the required 
///   element</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// </remarks>
/// <returns> Returns a collection of elements with the same NAME attribute or 
///  a collection of elements with the specified element name.
///  Returns null if no element with the given NAME attribute is found or 
///  if no element with the given name is found or if the browser does not 
///  support any of the used methods.
/// </returns>
///
function SYS_Browser_GetElements(param)
{
        var elem;
        elem = SYS_Browser_GetElementsByTag(param);
        
        if(!elem)
        {
                elem = SYS_Browser_GetElementsByName(param);
        }

        return elem;
}

///
/// <summary>
///  The event handling mechanism described in W3C DOM differs from the way
///  IE handles events. In order to wqualize these two different models and
///  dispay a consistent interface, this function is developed.
///  This function takes event as input and spits out the corresponding
///  object that fired the event based on the browser.
/// </summary>
/// <parameters>
///  <param name= "evt">object - the fired event</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> Returns the object that fired the event.
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_GetEventTarget(evt)
{
        var elem;
        evt = SYS_Browser_GetEventObject(evt);

        if (evt) 
        {
                elem = (evt.currentTarget) ? evt.currentTarget : ((evt.srcElement) ? evt.srcElement : null);
                return elem;
        }
        else
        {
                return null;
        }
}

///
/// <summary>
///  The event handling mechanism described in W3C DOM differs from the way
///  IE handles events. In order to wqualize these two different models and
///  dispay a consistent interface, this function is developed.
///  This function takes event as input and spits out the corresponding
///  object that fired the event based on the browser.
/// </summary>
/// <parameters>
///  <param name= "evt">object - the fired event</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> Returns the Unicode integer value of the typed
///  character that fired the event.
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_GetEventKeyCode(evt)
{
        var elem;
        var charCode;

        evt = SYS_Browser_GetEventObject(evt);

        if (evt) 
        {
            elem = SYS_Browser_GetEventTarget(evt);
                
            if (elem) 
            {
                charCode = (evt.charCode) ? evt.charCode : ((evt.which) ? evt.which : evt.keyCode);
                return charCode;
            }
            return null;
        }

        return null;

}

///
/// <summary>
///  The event handling mechanism described in W3C DOM differs from the way
///  IE handles events. In order to wqualize these two different models and
///  dispay a consistent interface, this function is developed.
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= "evt">object - the fired event</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_IsLeftClick(evt)
{
        evt = SYS_Browser_GetEventObject(evt);

        if (evt && typeof evt.button != "undefined" )
        {
            // In NN6+, the value of the button property when left mouse button 
            // is clicked is 0
            if (g_objBrowser.IsNetscape() && evt.button == 0)
            {
                return true;
            }
            // In IE4+, the value of the button property when left mouse button 
            // is clicked is 1
            else if (g_objBrowser.IsIE() && evt.button == 1)
            {
                return true;
            }
        }
        return false;
}

///
/// <summary>
///  The event handling mechanism described in W3C DOM differs from the way
///  IE handles events. In order to wqualize these two different models and
///  dispay a consistent interface, this function is developed.
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= "evt">object - the fired event</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_IsRightClick(evt)
{
    evt = SYS_Browser_GetEventObject(evt);

    // In IE4+ as well as NN6+, the value of the button property 
    // when right mouse button is clicked is 2
    if (evt && typeof evt.button != "undefined" && evt.button == 2)
    {
        return true;
    }

    return false;
}


///
/// <summary>
///  The event handling mechanism described in W3C DOM differs from the way
///  IE handles events. In order to equalize these two different models and
///  dispay a consistent interface, this function is developed.
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= "evt">object - the fired event. To be hard coded as 'event'.</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_GetEventObject(evt)
{
    return ((evt) ? evt : ((window.event) ? window.event : null));
}

///
/// <summary>
///  The event handling mechanism described in W3C DOM differs from the way
///  IE handles events. In order to equalize these two different models and
///  dispay a consistent interface, this function is developed.
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= "evt">object - the fired event. To be hard coded as 'event' by default.</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_StopEventPropagation(evt)
{
   evt = SYS_Browser_GetEventObject(evt);

   if (evt.preventDefault)
   {
       evt.preventDefault();
       evt.stopPropagation();
   }
   else if (typeof (evt.cancelBubble)  != "undefined")
   {
       evt.cancelBubble = true;
       evt.returnValue = false;
   }
}

///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_CreateXMLObject()
{
    var bFound = false;
    var objDoc = "";
    var Arr_ActiveX   = ["MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.5.0", "MSXML2.DOMDocument.4.0", "MSXML2.DOMDocument.3.0", "MSXML2.DOMDocument.2.6","MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XmlDom"];

    // IE specific initialization
    if ( typeof ActiveXObject != "undefined" )
    {
        // Iterate through array to determine the available ActiveX
        for (var i=0; i < Arr_ActiveX.length && !bFound; i++) 
        {
            try
            {
                // Try to create the object
                objDoc = new ActiveXObject(Arr_ActiveX[i]);
                bFound = true;
            }
            catch (objException) 
            { 
            } 
        }

        // Throw an error if no ActiveX found
        if (!bFound)
            throw "There is no MSXML ActiveX installed on your computer."
        else
        {
            objDoc.setProperty( "SelectionLanguage", "XPath" );
            objDoc.async = false;
            objDoc.resolveExternals = false; 
        }
        return objDoc;
    } // End of IE specific code
    else
        return (new DOMParser());
}

///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_LoadXML(objDoc, strXML)
{
    if ( g_objBrowser.IsIE() )
    {
        objDoc.loadXML( strXML );
        return objDoc;
    }
    else
    {
        objDoc = objDoc.parseFromString( strXML, "text/xml");
        return objDoc;
    }   
} 

///
/// <summary>
///  Mirrors what create node is on IE for Netscape.  Will create a node of either element or attribute type
///  depending on what node type is passed in
/// </summary>
/// <parameters>
///  <param name= objDoc>xml object</param>
///  <param name= nodetype>node type, in this case either attribute or element</param>
///  <param name= name>name of node</param>
///  <param name= namespaceURI>namespaceURI if one exists</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_CreateNode( objDoc, nodetype, name, namespaceURI )
{
    if ( g_objBrowser.IsIE() )
    {
        return (objDoc.createNode(nodetype, name, namespaceURI));
    }
    else
    {
        if (nodetype == 1)
        //node type is element
        {
            return ((namespaceURI == "") ? objDoc.createElement(name): objDoc.createElementNS(namespaceURI, name));
        }
        else if (nodetype == 2)
        //node type is attribute        
        {
            return ((namespaceURI == "") ? objDoc.createAttribute(name): objDoc.createAttributeNS(namespaceURI, name));
        }
    }
    return null;   
}

///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_SelectNodes( objDoc, query )
{
    if ( g_objBrowser.IsIE() )
    {
        return (objDoc.selectNodes( query ));  
    }
    else
    {
        var rgItemFields = new Array();
        var j = 0;
        if(objDoc)
        {
            var pXPE = new XPathEvaluator();
            var xPathResult = pXPE.evaluate( query, objDoc, null, 5, null );
    
            if (xPathResult )
            {

                var curfield = xPathResult.iterateNext();
                while (curfield)
                {
                    rgItemFields[j] = curfield;
                    j++;
                    curfield = xPathResult.iterateNext();
                }
            }
        }
        return rgItemFields;
    }   
}



///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Selects the first XmlNode that matches the XPath expression.
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_SelectSingleNode(objDoc, query)
{
    var xPathResult = new Array();
    xPathResult = SYS_Browser_SelectNodes(objDoc, query);
    return ( xPathResult[0] );
}


///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_XML_GetNodes( xPathResultArr, attrName )
{
    var rgItemFields = new Array();
    var j = 0;

    for ( j=0; j < xPathResultArr.length; j++ )
        rgItemFields[j] = xPathResultArr[j].getAttribute( attrName );
        
    return rgItemFields;
} // End of function

///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///  Returns null if the object is not found
///  or if the browser does not support any of the used methods.
/// </returns>
///

function SYS_Browser_GetXML( obj )
{
    var strXML = null;

    if ( !g_objBrowser.IsNetscape() )
    {
        strXML = obj.xml; 
    }   
    else
    {
        //create a new XMLSerializer
        var objXMLSerializer = new XMLSerializer();
        //get the XML string
        strXML = objXMLSerializer.serializeToString( obj );            
    }
        
    return strXML; 
} 

///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///
///  The following provides getter functions for 
///    .outerHTML
///  to allow to read those properties in NN6 in a IE4/5 compatible way. 
///  Note that while the scheme of traversing the document tree should point 
///  you in the right direction the code example might not satisfy your 
///  needs as there are subtle difficulties when trying to reproduce the 
///  html source from the document tree. See for yourself whether you like 
///  the result and improve it as needed to cover other exceptions than 
///  those handled (for the empty elements and the textarea element)
///  
/// </returns>
///
function SYS_Browser_OuterHTML_Init()
{
    if (typeof(HTMLElement) != "undefined")    
    {
        HTMLElement.prototype.__defineSetter__ ( "outerHTML",   
            function (html) {
                this.outerHTMLInput = html;
                var range = this.ownerDocument.createRange();
                range.setStartBefore(this);
                var docFrag = range.createContextualFragment(html);
                this.parentNode.replaceChild(docFrag, this);
            } );

        HTMLElement.prototype.__defineGetter__( "outerHTML", 
            function () {
                return _getOuterHTML (this);
            } );
    }
}

function _getOuterHTML (node) {
    var html = '';
    var emptyElements = { HR: true, BR: true, IMG: true, INPUT: true };
    var specialElements = { TEXTAREA: true };
  
    switch (node.nodeType) {
      case Node.ELEMENT_NODE:
        html += '<';
        html += node.nodeName;
        if (!specialElements[node.nodeName]) {
            for (var a = 0; a < node.attributes.length; a++)
                html += ' ' + node.attributes[a].nodeName.toUpperCase() +
                      '="' + node.attributes[a].nodeValue + '"';
            html += '>'; 
            if (!emptyElements[node.nodeName]) {
                html += node.innerHTML;
                html += '<\/' + node.nodeName + '>';
            }
        }
        else switch (node.nodeName) {
          case 'TEXTAREA':
            for (var a = 0; a < node.attributes.length; a++)
                if (node.attributes[a].nodeName.toLowerCase() != 'value')
                    html += ' ' + node.attributes[a].nodeName.toUpperCase() +
                           '="' + node.attributes[a].nodeValue + '"';
                else 
                    var content = node.attributes[a].nodeValue;
            html += '>'; 
            html += content;
            html += '<\/' + node.nodeName + '>';
          break; 
        }
      break;
      case Node.TEXT_NODE:
        html += node.nodeValue;
      break;
      case Node.COMMENT_NODE:
        html += '<!' + '--' + node.nodeValue + '--' + '>';
      break;
    }
    
    return html;
}

///
/// <summary>
///  TO DO
///  
/// </summary>
/// <parameters>
///  <param name= >TO DO</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///
///  The following provides getter functions for 
///    .innerText
///  To Do
///  To Do
/// </returns>
///
function SYS_Browser_InnerText_Init()
{
	if(typeof HTMLElement!="undefined")
	{
		HTMLElement.prototype.__defineGetter__( "innerText", 
			function () {
				var tmp = this.innerHTML.replace(/<br>/gi,"\n");
				return tmp.replace(/<[^>]+>/g,"");
			});

		HTMLElement.prototype.__defineSetter__ ( "innerText",   
		    function (txtStr) {
				var parsedText = document.createTextNode(txtStr);
				this.innerHTML = "";
				this.appendChild( parsedText );
			});
	}

}
function SYS_Browser_GetDialogArguments()
{
    var strDlgArg;

    if( g_objBrowser.IsNetscape() )
        strDlgArg = opener.g_DialogWin.args;
    else        
        strDlgArg = window.dialogArguments;

    return strDlgArg;

}

///
/// <summary>
///  In Netscape the disabled buttons dont get greyed out. We do that changing the class (style) to Inactive. While enabling it, need to give if the Button had Bold or Normal style.
///  
/// </summary>
/// <parameters>
///  <param name= "objBtn"> object - the html button object</param>
/// </parameters>
/// <remarks>
///  This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///
///  The following provides getter functions for 
///    .outerHTML
///  to allow to read those properties in NN6 in a IE4/5 compatible way. 
///  Note that while the scheme of traversing the document tree should point 
///  you in the right direction the code example might not satisfy your 
///  needs as there are subtle difficulties when trying to reproduce the 
///  html source from the document tree. See for yourself whether you like 
///  the result and improve it as needed to cover other exceptions than 
///  those handled (for the empty elements and the textarea element)
///  
/// </returns>
///
function SYS_Browser_ImageButton_Disable(objBtn)
{
    if (objBtn)
        objBtn.disabled = true ;

    if (g_objBrowser.IsNetscape()) 
    {
        var strBtnClassName = objBtn.getAttribute('class');
        
        if ( strBtnClassName == null 
          || strBtnClassName == "" 
          || strBtnClassName.indexOf('clsImageButton') < 0 ) return ; // Dont handle if not ImageButton;
        
        var strBtnDisableClassName = strBtnClassName.substring(0,strBtnClassName.indexOf('_') + 1) + 'Inactive' ;
        
        objBtn.setAttribute('class',strBtnDisableClassName);
    }
}

///
/// <summary>
///  In Netscape the disabled buttons dont get greyed out. We do that changing the class (style) to Inactive. While enabling it, need to give if the Button had Bold or Normal style.
///  
/// </summary>
/// <parameters>
///  <param name= "objBtn"> object - the html button object</param>
///  <param name= "bBtnIsBold"> boolean - Enable button to Bold.</param>
/// </parameters>
/// <remarks>
///   The second param is optional with default value as (true) or Normal (false). In sync to bAction param in objHtml.Button(). This function is a part of the object layer being developed to support
///         multiple browsers.
/// <returns> 
///  TO DO
///
///  The following provides getter functions for 
///    .outerHTML
///  to allow to read those properties in NN6 in a IE4/5 compatible way. 
///  Note that while the scheme of traversing the document tree should point 
///  you in the right direction the code example might not satisfy your 
///  needs as there are subtle difficulties when trying to reproduce the 
///  html source from the document tree. See for yourself whether you like 
///  the result and improve it as needed to cover other exceptions than 
///  those handled (for the empty elements and the textarea element)
///  
/// </returns>
///

function SYS_Browser_ImageButton_Enable(objBtn, bBtnIsBold )
{
    if (objBtn)
        objBtn.disabled = false ;

    if (g_objBrowser.IsNetscape())     
    {
        if (bBtnIsBold == null) bBtnIsBold = false ;
        
        var strBtnClassName = objBtn.getAttribute('class');
        
        if ( strBtnClassName == null 
          || strBtnClassName == "" 
          || strBtnClassName.indexOf('clsImageButton') < 0
          || strBtnClassName.indexOf('Inactive') < 0 ) return ; // Dont handle if not Inactive ImageButton;
        
        var strBtnEnableClassName = strBtnClassName.substring(0,strBtnClassName.indexOf('_') + 1) + 
                                    ( (bBtnIsBold) ? 'Bold' : 'Normal' ) ;
        
        objBtn.setAttribute('class', strBtnEnableClassName);
    }
}


///
/// <summary>
/// Return an XmlHttpRequest object for the 
/// target platform.
/// </summary>
/// <returns> 
/// XmlHttpRequest object
/// </returns>
///
function SYS_Browser_CreateXMLHttpRequest()
{
    var XmlHttpRequest = null;
    var usingActiveX   = false;
    
    // Always instantiate active x if not Netscape.
    // Use the ActiveX object if possible as IIS has 
    // a content-header length limitation that must
    // be increased manually (via script) if posting > 200K
    if (!g_objBrowser.IsNetscape()) 
    {
        try
        {
            XmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            usingActiveX = true;
        }
        catch (e) {} //suppress any error so we can try to create native object
    }
    
    // If we can't create the ActiveX object or if Netscape, we will use the native object
    if (!usingActiveX && (typeof(XMLHttpRequest) != "undefined"))
    {
        XmlHttpRequest = new XMLHttpRequest();
    }
    
    return XmlHttpRequest;
}

