﻿$namespace("web.w3.dom");

var __web_w3_dom = web.w3.dom;

__web_w3_dom.NodeType = Enum.createEx("ELEMENT_NODE",1, "ATTRIBUTE_NODE", 2, "TEXT_NODE",3, 
    "COMMENT_NODE", 8, "DOCUMENT_NODE", 9, "DOCUMENT_FRAGMENT_NODE", 11);

/***********************************************************************************************************
 * DTD:: TopElement  Availability "Registration//Organization//Type Label//Definition  Language""URL" 
 *
 * With Microsoft Internet Explorer 6 and later, you switch on standards-compliant mode by including the 
 * !DOCTYPE declaration at the top of your document, specifying a valid Label in the declaration, 
 * and in some cases, specifying the Definition and/or URL. The Label specifies the unique name of the 
 * Document Type Definition (DTD), and can be appended with the version number of the DTD. The Definition 
 * specifies the definition of the DTD that is specified in the Label. The URL specifies the location of the DTD.

 * When standards-compliant mode is switched on, Internet Explorer renders the document in compliance with 
 * the Cascading Style Sheets (CSS), Level 1 (CSS1)  standard. When standards-compliant mode is not switched on, 
 * rendering behavior is consistent with previous versions of Internet Explorer. 
 ***********************************************************************************************************/
__web_w3_dom.DocumentCompatType = Enum.create("BackCompat", "CSS1Compat");

__web_w3_dom.getNonTextNode = function(oNode)
{
    try{while(oNode && oNode.nodeType != __web_w3_dom.NodeType.ELEMENT_NODE) oNode = oNode.parentNode;}
    catch(e){oNode=null;}
    return oNode;
}

__web_w3_dom.scriptRoot = sys.env.getScriptRoot();

__web_w3_dom.getLayoutRoot = function() 
{
    return (document.compatMode == __web_w3_dom.DocumentCompatType.CSS1Compat) ? 
    document.documentElement : document.body;
}

__web_w3_dom.measureString = function(str, fontSize)
{
    if(!fontSize) fontSize = parseInt(document.body.currentStyle.fontSize);
    var temp = document.createElement("span");
    temp.style.visibility = "hidden";
    temp.style.height = "1px";
    temp.style.fontSize = "1px";
    temp.style.overflow = "hidden";
    temp.innerText = str;
    document.body.appendChild(temp);
    var width = temp.offsetWidth * parseInt(fontSize) / 2;
    document.body.removeChild(temp);
    return width;
}

// Determines if the element is focusable
__web_w3_dom.isFocusable = function(p_el)
{
	var focusList = "INPUT|BUTTON|TEXTAREA|FIELDSET|IFRAME|SELECT|"
	return (p_el.tagName && (!p_el.disabled) && (focusList.indexOf(p_el.tagName + "|")>-1 || (p_el.tagName=="A" && p_el.href)));
}

// Find the next focusable element (element that passes Web.UI.isFocusable)
// p_elScope - the "element" you wish to cycle within
// p_elStart - the element you want to start your scan from
// p_blnDirection - find next (true) or previous (false)
__web_w3_dom.findFocusableElement = function(p_elScope, p_elStart, p_blnDirection)
{
	function GetNextElement(p_el)
	{
		if (!p_el) return null;
		var elNext = p_blnDirection ? p_el.nextSibling : p_el.previousSibling;
		while (elNext && elNext.nodeType!=1)
		{
			elNext = p_blnDirection ? elNext.nextSibling : elNext.previousSibling;
		}
		if (!elNext)
			return GetNextElement(p_el.parentNode)
		else
			return elNext;
	}

	function invoke(p_elScope,p_elStart)
	{
		var elCurrent = p_elStart;
		if (elCurrent && p_elScope.contains(elCurrent))
  		{
			while (elCurrent!=null)
			{
				if (!__web_w3_dom.isFocusable(elCurrent))
				{
					if (p_blnDirection && elCurrent.firstChild)
						elCurrent = elCurrent.firstChild;
					else if (!p_blnDirection && elCurrent.lastChild)
						elCurrent = elCurrent.lastChild;
					else
						elCurrent = GetNextElement(elCurrent);				
		        }
				else
				{
					return elCurrent;
				}
			}
		}
		return null;
	}

	if (p_elStart)
		p_elStart = GetNextElement(p_elStart);
	else
		p_elStart = p_elScope;
	var elMatch = invoke(p_elScope,p_elStart)
	if (!elMatch && p_elStart && p_elStart!=p_elScope)
		return invoke(p_elScope,p_elScope); // cycle
	else
		return elMatch;
}

__web_w3_dom.Layout = new function()
{
    var p = ["padding", "margin", "border"];
    var v = ["Top", "Right", "Bottom", "Left"];
    var f = ["{0}{1}", "{0}{1}", "{0}{1}Width"];
    
    var dom = __web_w3_dom;
    
    function _Layout(el)
    {
        this.getElement = function() { return el; }
    }
    
    _Layout.prototype.getContentRect = function()
    {
        var temp = new web.drawing.Rect(this.left, this.top, this.width, this.height);
        
        if(document.compatMode == __web_w3_dom.DocumentCompatType.CSS1Compat)
        {
            temp.left += this.borderLeftWidth + this.paddingLeft;
            temp.top += this.borderTopWidth + this.paddingTop;
            temp.width -= (this.borderLeftWidth + this.paddingLeft + 
                this.paddingRight + this.borderRightWidth);
            temp.height -= (this.borderTopWidth + this.paddingTop + 
                this.paddingBottom + this.borderBottomWidth);
        }
        
        return temp.clone();
    }
    
    
    this.calc = function(el, root)
    {
        // calculate layout - measurement
        var d = this.getDimension(el);
          
        // calculate layout - location
        var l = this.getLocation(el, root);
        
        var layout = new _Layout(el);
        
        for(var p in d) layout[p] = d[p];
        for(var p in l) layout[p] = l[p];
        
        return layout;
    }
    
    this.getDimension = function(el)
    {
        var d = {};
        var property = null;
        for(var i = 0; i < p.length; i++) {
            for(var j = 0; j < v.length; j++) {
                property = String.format(f[i], p[i], v[j]);
                d[property] = parseInt(el.currentStyle[property]);
                if(isNaN(d[property])) d[property] = 0;
            }
        }
        d.width = el.offsetWidth;
        d.height = el.offsetHeight;
        return d;
    }
    
    this.getLocation = function(el, scope)
    {
        var layoutRoot = dom.getLayoutRoot();
        var l = {left:el.offsetLeft, top:el.offsetTop};
        el = el.offsetParent;
        while(el && (!scope || el != scope))
        {
            l.left += (el.offsetLeft - (document.body == el || layoutRoot == el ? 0 : Convert.toInt(el.scrollLeft)));
            l.top += (el.offsetTop - (document.body == el || layoutRoot == el ? 0 : Convert.toInt(el.scrollTop)));
            el = el.offsetParent;
        }
        return l;
    }
}

__web_w3_dom.CleanupHelper = function()
{
    var m_h=[];
    var m_d=[];
    var m_n=[];
    var m_this = this;
    
    this.initialize=function(p_elOwner)
    {
    }
	
	this.dispose = function(p_blnDispose)
    {
        detachEvents();
        disposeProperties(p_blnDispose);
        if(!p_blnDispose)
            detachNodes();
        m_h = [];
        m_d = [];
        m_n = [];
    }
    
    this.disposeGroup=function(group)
    {
        m_this.removeNodeGroup(group);
        m_this.detachEventGroup(group);
        m_this.disposePropertyGroup(group);
    }
    
    this.attachEvent=function(group,obj,evt,cb)
	{
	    var h =
	    {
	        group:group,obj:obj,evt:evt,cb:cb,
	        detach:function(){this.obj.detachEvent(evt,cb)},
	        equals:function(o,e,c){return this.obj==o&&this.evt==e&&this.cb==c}
	    };
        obj.attachEvent(evt,cb)
	    m_h.push(h);
	}
	
	this.initializeProperty=function(obj,group)
    {
        if(obj.initialize)
            obj.initialize();
        m_d.push({obj:obj,group:group});
    }
    
    this.registerNode=function(node,group)
    {
        m_n.push({node:node,group:group});
    }
    
    this.createNode=function(tag,properties,styles,parent,group)
	{
	    var el = document.createElement(tag);
	    for(var p in properties)
	        el[p] = properties[p];
	    for(var p in styles)
	        el.style[p] = styles[p];
	    if(parent)
	        parent.appendChild(el);
	    m_this.registerNode(el,group);
	    return el;
	}
    
    this.removeNodeGroup=function(group)
	{
	    for(var i=m_n.length-1;i>=0;i--)
	    {
	        if(m_n[i].group==group)
	        {
	            m_n[i].node.removeNode(true);
	            m_n.remove(m_n[i]);
	        }
	    }
	}
	
    
    this.detachEvent=function(obj,evt,cb)
	{
	    for(var i=m_h.length-1;i>=0;i--)
	    {
	        if(m_h[i].equals(obj,evt,cb))
	        {
	            m_h[i].detach();
	            m_h.remove(m_h[i]);
	        }
	    }
	}
	
	
	
	this.detachEventGroup=function(group)
	{
	    for(var i=m_h.length-1;i>=0;i--)
	    {
	        if(m_h[i].group==group)
	        {
	            m_h[i].detach();
	            m_h.remove(m_h[i]);
	        }
	    }
	}
	
	this.disposePropertyGroup=function(group)
	{
	    if(null==m_d) return;
	    for(var i=m_d.length-1;i>=0;i--)
	    {
	        if(m_d[i].group==group)
	        {
	            if(m_d[i].obj.dispose)
	                m_d[i].obj.dispose();
	            m_d.remove(m_d[i]);
	        }
	    }
	}
	
	function detachEvents()
	{
	    if(null==m_h) return;
	    for(var i=m_h.length-1;i>=0;i--)
	    {
	        m_h[i].detach();
	        m_h[i]=null;
	    }
	    m_h=[];
	}
	
	function disposeProperties()
	{
	    if(null==m_d) return;
	    for(var i=m_d.length-1;i>=0;i--)
	    {
	        if(m_d[i].obj.dispose)
	            m_d[i].obj.dispose();
	        m_d[i]=null;
	    }
	    m_d=[];
	}
	
	function detachNodes()
	{
	   	if(null==m_n) return;
	    for(var i=m_n.length-1;i>=0;i--)
	    {
	        m_n[i].node.removeNode(true);
	        m_n[i]=null;
	    }
	    m_n=[]; 
	}
}

