// JavaScript Document

/*
====================================================================================================================
#	Date			Developer	Brief Description of Change and Reason for Change
====================================================================================================================
1.	7-Mar-2007		pinhow		Add support for HTML (non-XHTML) text.
								Usage: Put HTML text between "<![CDATA[|HTML|" and "]]>" tags.
2.	8-Mar-2007		pinhow		Add handler for IE to handle "script" tag.
								Every "script" tag in IE will be moved out from its parent tag if any.
								This is to enable the script to be executed in IE.
3.	13-Mar-2007		pinhow		Fixed IE bug which gets error when IE proccess the "style" tag.
4.	21-Mar-2007		pinhow		For "<![CDATA[|HTML|" and "]]>", "|HTML|" will be removed after convert to XHTML.
								This is to prevent "script" tag being eliminated when it is put as 1st child in 
								innerHTML in IE.
5.	31-May-2007		pinhow		Added fade in and fade out effects for taconite-replace-children.
								Usage: Include SpryEffects.js
								<taconite-replace-children contextNodeID="target_div" parseInBrowser="true" fadeOut="true" fadeIn="true" clearLoadingID="my_loading">
								fadeOut = true : fade out the content before replacing the content.
								fadeIn = true : fade in the content after replacing the content.
								clearLoadingID = {ID} : Clear loading container after fade in. 
								Normally for ajaxRequest.setLoadingAutoRemove(false).
6.	04-Jun-2009		pinhow		Handle IE8: Set the input value at last, otherwise IE8 will reset the value to 
								"Submit Query" when it set the type to "Submit" after setting the value.
								
===================================================================================================================
*/

var taconite_parser_version=1.502;
var ajax_fadeOut_duration = 800; // #5
var ajax_fadeIn_duration = 800; // #5
var isIE=document.uniqueID;
String.prototype.trim = function() {
    //skip leading and trailing whitespace
    //and return everything in between
    var x=this;
    x=x.replace(/^\s*(.*)/, "$1");
    x=x.replace(/(.*?)\s*$/, "$1");
    return x;
};

function requiresContextNode(xmlTagName) {
    return !(xmlTagName == "taconite-execute-javascript" || xmlTagName == "taconite-redirect");
}


function XhtmlToDOMParser(){
    this.parseXhtml = function(xml){
        var xmlTagName=xml.tagName.toLowerCase();
        var contextNode=document.getElementById(xml.getAttribute("contextNodeID"));
        if(contextNode == null && requiresContextNode(xmlTagName)){
            return false;
        }
        switch (xmlTagName) {
            case "taconite-append-as-children":
                getReplaceChildren(contextNode,xml,false);
                break;
            case "taconite-delete":
                getDelete(contextNode,xml);
                break;
            case "taconite-append-as-first-child":
                getAppendAsFirstChild(contextNode,xml);
                break;                         
            case "taconite-insert-after":
                getInsertAfter(contextNode,xml);
                break;
            case "taconite-insert-before":
                getInsertBefore(contextNode,xml);
                break;                         
            case "taconite-replace-children":
				// #5 Check the fadeIn & fadeOut value.
				var fadeOut = xml.getAttribute("fadeOut");
				if( fadeOut != null ){
					if( fadeOut.toLowerCase() == "true" )
						fadeOut = true;
					else
						fadeOut = false;
				}
				else {
					fadeOut = false;
				}
				var fadeIn = xml.getAttribute("fadeIn");
				if( fadeIn != null ){
					if( fadeIn.toLowerCase() == "true" )
						fadeIn = true;
					else
						fadeIn = false;
				}
				else {
					fadeIn = false;
				}
				// end #5 Check the fadeIn & fadeOut value.
				
				// #5 Function to check & clear loading container
				var clearLoadingContainer = function(){
					var loadingContainer = document.getElementById(xml.getAttribute("clearLoadingID"));
					if( loadingContainer != null ){
			            while(loadingContainer.childNodes.length >0){
			                loadingContainer.removeChild(loadingContainer.childNodes[0]);
			            }      
			        }
				}
				// end #5 Function to check & clear loading container
				
				// #5 Function to clear opacity, so it won't looks weird in IE
				var clearOpacity = function(){
					if (window.ActiveXObject)
						contextNode.style.filter = "";
					else
						contextNode.style.opacity = "";
				}
				// end #5 Function to clear opacity, so it won't looks weird in IE
				
				// #5 Replace/Update content with fade in and fade out effects base on request.
				if( fadeOut ){
					var fade_stop = function() {
						 try {
						 	getReplaceChildren(contextNode,xml,true);
						 }
						 catch(exception){}
						 if( fadeIn ){ // If fadeIn & fadeOut, then fade out content, replace content, fade in content.
							var ajaxFade = new Spry.Effect.Fade(xml.getAttribute("contextNodeID"), {finish:clearOpacity, duration: ajax_fadeIn_duration, from: 0, to: 100, toggle:false});
							ajaxFade.start();
						}
						else{ // If fadeOut only, then fade out content, replace content, show the content.
							clearOpacity();
						}
						clearLoadingContainer();
					}
					var ajaxFade = new Spry.Effect.Fade(xml.getAttribute("contextNodeID"), {finish:fade_stop, duration: ajax_fadeOut_duration, from: 100, to: 0, toggle:false});
					ajaxFade.start();
				}
				else if( fadeIn ){ // If fadeIn only, then hide content, replace content, fade in content.
						var fade_stop = function() {
							try {
								getReplaceChildren(contextNode,xml,true);
							}
						 	catch(exception){}
							var ajaxFade = new Spry.Effect.Fade(xml.getAttribute("contextNodeID"), {finish:clearOpacity, duration: ajax_fadeIn_duration, from: 0, to: 100, toggle:false});
							ajaxFade.start();
							clearLoadingContainer();
						}
						var ajaxFade = new Spry.Effect.Fade(xml.getAttribute("contextNodeID"), {finish:fade_stop, duration: 0, from: 100, to: 0, toggle:false});
						ajaxFade.start();
				}
				else{ // If no fadeIn & no fadeOut, then just do nothing on fading.
					getReplaceChildren(contextNode,xml,true);
					clearLoadingContainer();
				}				
				// end #5 Replace/Update content with fade in and fade out effects base on request.                
                break;
            case "taconite-replace":
                getReplace(contextNode,xml);
                break;                         
            case "taconite-set-attributes":
                xml.removeAttribute("contextNodeID");
                xml.removeAttribute("parseInBrowser");
                handleAttributes(contextNode,xml);
                break;
            case "taconite-redirect":
                handleRedirect(xml);
                break;
            case "taconite-execute-javascript":
                executeJavascript(xml);
                break;
        }  
        return true;
    };
    
    function isInlineMode(node) {
        var attrType;
        if(!node.tagName.toLowerCase() == "input") {
            return false;
        }
        attrType=node.getAttribute("type");
        
        if(attrType=="radio" || attrType=="checkbox") {
            return true;
        }
        return false;
    }  
    this.getJavaScript= function() {
        return "var dummy_taconite_variable=0";
    }; 
    function handleNode(xmlNode){
        var nodeType = xmlNode.nodeType;               
        switch(nodeType) {
            case 1:  //ELEMENT_NODE
                return handleElement(xmlNode);
            case 3:  //TEXT_NODE
           // case 4:  //CDATA_SECTION_NODE
                var textNode = document.createTextNode(xmlNode.nodeValue);
                if(isIE) {
                    textNode.nodeValue = textNode.nodeValue.replace(/\n/g, '\r'); 
                }
                return textNode;
			case 4:  //CDATA_SECTION_NODE	// Edited by pinhow 7-Mar-2007
				if( xmlNode.data.substring(0, 6) == "|HTML|" ){	// HTML (NON-XHTML) TEXT			
					return handleHTMLNodes(xmlNode);					
				}
				else{  // SAME WITH CASE 3
					var textNode = document.createTextNode(xmlNode.nodeValue);
	                if(isIE) {
	                    textNode.nodeValue = textNode.nodeValue.replace(/\n/g, '\r'); 
	                }
	                return textNode;
				}
				
        }      
        return null;
    }
    function handleElement(xmlNode){
        var domElemNode=null;
        var xmlNodeTagName=xmlNode.tagName.toLowerCase();
        if(isIE){
            if(isInlineMode(xmlNode)) {
                return document.createElement("<INPUT " + handleAttributes(domElemNode,xmlNode,true) + ">");
            }
            if(xmlNodeTagName == "style"){
                //In internet explorer, we have to use styleSheets array.		
                var text,rulesArray,styleSheetPtr;
                var regExp = /\s+/g;
                text=xmlNode.text.replace(regExp, " ");
                rulesArray=text.split("}");
                
                domElemNode=document.createElement("style");
				
				// Added by pinhow 13-Mar-2007
				// If "style" tag not found, create one on document body
				if( document.styleSheets.length == 0 ){
					var document_style = document.createElement("style");
					window.document.body.appendChild(document_style);
				}
				
                var styleSheetPtr=document.styleSheets[document.styleSheets.length-1];
                for(var i=0;i<rulesArray.length;i++){
                    rulesArray[i]=rulesArray[i].trim();
                    var rulePart=rulesArray[i].split("{");
                    if(rulePart.length==2) {//Add only if the rule is valid
                    	rulePart[0] = rulePart[0].trim();
						rulePart[1] = rulePart[1].trim();
					    if( rulePart[1] == "" )	// Added by pinhow 13-Mar-2007 to prevent error when it is empty value
							rulePart[1] = " ";
						styleSheetPtr.addRule(rulePart[0],rulePart[1],-1);//Append at the end of stylesheet.
                    }
                }							
                return domElemNode;			
            }
            
        }
        if(domElemNode == null){
            if(useIEFormElementCreationStrategy(xmlNodeTagName)) {
                domElemNode = createFormElementsForIEStrategy(xmlNode);
            }
            else {
				if(isIE && xmlNodeTagName == "script"){  // Added by pinhow 8-Mar-2007
					// script tag will be handled separately for IE
					domElemNode = document.createElement("script_tag");
				}
				else{
					domElemNode = document.createElement(xmlNodeTagName);
				}
            }
            
            handleAttributes(domElemNode,xmlNode);
            //Fix for IE Script tag: Unexpected call to method or property access error
            //IE don't allow script tag to have child
            if(isIE && (!domElemNode.canHaveChildren || domElemNode.nodeName == "script_tag") ){
                if(xmlNode.childNodes.length > 0){
                    domElemNode.text=xmlNode.text;
                }
                
            }                              
            else{
                for(var z = 0; z < xmlNode.childNodes.length; z++) {
                    var domChildNode=handleNode(xmlNode.childNodes[z]);
                    if(domChildNode!=null) {
                        domElemNode.appendChild(domChildNode);
                    }
                }
            }
        }  
		       
        return domElemNode;
    }
	
	// Added by pinhow 7-Mar-2007
	function handleHTMLNodes(cdataNode){  // Parameter: CDATA node
		// Comment by pinhow 21-Mar-2007. "|HTML|" will be removed after convert to XHTML.
		//cdataNode.data = cdataNode.data.substring(6);
					
		// Convert HTML to XHTML using html2xhtml.js
		var convert_node = document.createElement("convert_node");
		convert_node.innerHTML = cdataNode.data;
		var returned_xhtml = get_xhtml(convert_node);
		returned_xhtml = returned_xhtml.replace(/&nbsp;/g, "&#160;");
		// Added by pinhow 21-Mar-2007. Remove "|HTML|" at the starting.
		returned_xhtml = returned_xhtml.substring(6);
		var xhtml_content = "<multiple_nodes>" + returned_xhtml + "</multiple_nodes>";
		
		// code for IE
		if (window.ActiveXObject)
		  {
		  var xmldoc=new ActiveXObject("Microsoft.XMLDOM");
		  xmldoc.async = false;
		  //xmldoc.resolveExternals = true; 
		  //xmldoc.validateOnParse = false;
		  xmldoc.loadXML(xhtml_content);
		  }
		// code for Mozilla, Firefox, Opera, etc.
		else
		  {
		  var parser=new DOMParser();
		  var xmldoc=parser.parseFromString(xhtml_content,"text/xml");
		  }
		
		var xml_node = xmldoc.documentElement;
		return xml_node;
	}
    
    function useIEFormElementCreationStrategy(xmlNodeTagName) {
        var useIEStrategy = false;
        
        if (isIE && ( xmlNodeTagName.toLowerCase() == "form" ||
              xmlNodeTagName.toLowerCase() == "input" ||
              xmlNodeTagName.toLowerCase() == "textarea" ||
              xmlNodeTagName.toLowerCase() == "select" ||
              xmlNodeTagName.toLowerCase() == "a" ||
              xmlNodeTagName.toLowerCase() == "applet" ||
              xmlNodeTagName.toLowerCase() == "button" ||
              xmlNodeTagName.toLowerCase() == "img" ||
              xmlNodeTagName.toLowerCase() == "link" ||
              xmlNodeTagName.toLowerCase() == "map" ||
              xmlNodeTagName.toLowerCase() == "object")) {
                      
            useIEStrategy = true;
        }
        
        return useIEStrategy;
    }
    
    function createFormElementsForIEStrategy(xmlNode) {
        var attr = null;
        var name = "";
        var value = "";
        for (var x = 0; x < xmlNode.attributes.length; x++) {
            attr = xmlNode.attributes[x];
            name = attr.name.trim();
            if (name == "name") {
                value = attr.value.trim();
            }
        }

        domElemNode = document.createElement("<" + xmlNode.tagName + " name='" + value + "' />"); // e.g. document.createElement("<input name='slot2'>");
        
        return domElemNode;
    }
    
    function handleAttributes(domNode, xmlNode) {
        var attr = null;
        var attrString = "";
        var name = "";
        var value = "";
        var returnAsText = false;
        if(arguments.length == 3) {
            returnAsText = true;
        }
		var has_value_of_value = false; // #6
		var value_of_value = ""; // #6
        
        for(var x = 0; x < xmlNode.attributes.length; x++) {
            attr = xmlNode.attributes[x];
            name = cleanAttributeName(attr.name.trim());
            value = attr.value.trim();
            if(!returnAsText){
                if(name == "style") {
                    /* IE workaround */
                    domNode.style.cssText = value;
                    /* Standards compliant */
                    domNode.setAttribute(name, value);
                }
                else if(name.trim().toLowerCase().substring(0, 2) == "on") {
                    /* IE workaround for event handlers */
                    //domNode.setAttribute(name,value);							
					// Added by pinhow 9-Mar-2007.			
					value = getValidEventString(value);
                    eval("domNode." + name.trim().toLowerCase() + "=function(){" + value + "}");
                }
                else if(name == "value") {
                    /* IE workaround for the value attribute -- makes form elements selectable/editable */
                    // #6 Commented. domNode.value = value;
					has_value_of_value = true; // #6
					value_of_value = value; // #6
                }
                else if(useIEFormElementCreationStrategy(xmlNode.tagName) && name == "name") {
                    //Do nothing, as the "name" attribute was handled in the createFormElementsForIEStrategy function
                    continue;
                }
                else {
                    /* Standards compliant */
                    domNode.setAttribute(name,value);
                }
                /* class attribute workaround for IE */
                if(name == "class") {
                    domNode.setAttribute("className",value);
                }
            }else{
               	if(name.trim().toLowerCase().substring(0, 2) == "on") {
					// Added by pinhow 21-Mar-2007.			
					value = getValidEventString(value);
				}
			    attrString = attrString + name + "=\"" + value + "\" " ;
            }
        }
		// #6
		if( has_value_of_value ){
			domNode.setAttribute("value",value_of_value);
		}
		// end #6
        return attrString;
    }
	// Added by pinhow 9-Mar-2007. Main objective is for handling in IE. 
	// If found value = "function anonym(){ my_function() }"
	// then change it becomes value = "my_function()" only.
	function getValidEventString(value){
		value = value.trim();
		if( value.toLowerCase().substring(0, 9) == "function " ){
			var openSymbol = value.indexOf("{");
			var closeSymbol = value.lastIndexOf("}");
			if( openSymbol != -1 && closeSymbol != -1 && openSymbol < closeSymbol ) {
				value = value.substring(openSymbol+1, closeSymbol);
			}
			value = getValidEventString(value);
		}
		return value;
	}
    function getAppendAsFirstChild(domNode,xml){
        var firstNode=null;
        if(domNode.childNodes.length > 0) {
            firstNode=domNode.childNodes[0];
        }
        
        for(var i=0;i<xml.childNodes.length;i++){
            domChildNode=handleNode(xml.childNodes[i]);
            if(domChildNode!=null){
                if(firstNode==null){
                    if(domChildNode.nodeName == "multiple_nodes"){ // Edited & added by pinhow 7-Mar-2007
						getReplaceChildren(domNode,domChildNode, false); 
					}
					else {
						if( isIE ){  // Added by pinhow 8-Mar-2007					
							if(domChildNode.nodeName.toLowerCase() == "script_tag" ){
								domNode.appendChild(getIEScriptNode(domChildNode));
							}
							else{
								var script_nodes = getIEScriptNodes(domChildNode);										
								domNode.appendChild(domChildNode);
								for(var k=0; k < script_nodes.length; k++){
									domNode.appendChild(script_nodes[k]);
								}
							}
						}
						else{
							domNode.appendChild(domChildNode);
						}
					}
                }
                else {
                    if(domChildNode.nodeName == "multiple_nodes"){ // Added by pinhow 7-Mar-2007
						getInsertBefore(firstNode,domChildNode);
					}
					else {
						if( isIE ){  // Added by pinhow 8-Mar-2007					
							if(domChildNode.nodeName.toLowerCase() == "script_tag" ){
								domNode.insertBefore(getIEScriptNode(domChildNode),firstNode);
							}
							else{
								var script_nodes = getIEScriptNodes(domChildNode);										
								domNode.insertBefore(domChildNode,firstNode);	
								for(var k=0; k < script_nodes.length; k++){
									domNode.insertBefore(script_nodes[k],firstNode);
								}
							}
						}
						else{
							domNode.insertBefore(domChildNode,firstNode);
						}
					}
                }
                
            }
        }              
    }
    
    function getInsertAfter(domNode,xml){
        var domChildNode=null;
        var nextSibling=domNode.nextSibling;
        for(var i=0;i<xml.childNodes.length;i++){
            domChildNode=handleNode(xml.childNodes[i]);
            if(domChildNode!=null){
                if(nextSibling!=null) {
                    if(domChildNode.nodeName == "multiple_nodes"){ // Added by pinhow 7-Mar-2007
						getInsertBefore(nextSibling,domChildNode);
					}
					else {
						if( isIE ){  // Added by pinhow 8-Mar-2007					
							if(domChildNode.nodeName.toLowerCase() == "script_tag" ){
								domNode.parentNode.insertBefore(getIEScriptNode(domChildNode),nextSibling);
							}
							else{
								var script_nodes = getIEScriptNodes(domChildNode);										
								domNode.parentNode.insertBefore(domChildNode,nextSibling);
								for(var k=0; k < script_nodes.length; k++){
									domNode.parentNode.insertBefore(script_nodes[k],nextSibling);
								}
							}
						}
						else{
							domNode.parentNode.insertBefore(domChildNode,nextSibling);
						}
					}
                }
                else {
                    if(domChildNode.nodeName == "multiple_nodes"){ // Added by pinhow 7-Mar-2007
						getReplaceChildren(domNode.parentNode,domChildNode, false);
					}
					else {
						if( isIE ){  // Added by pinhow 8-Mar-2007					
							if(domChildNode.nodeName.toLowerCase() == "script_tag" ){
								domNode.parentNode.appendChild(getIEScriptNode(domChildNode));
							}
							else{
								var script_nodes = getIEScriptNodes(domChildNode);									
								domNode.parentNode.appendChild(domChildNode);
								for(var k=0; k < script_nodes.length; k++){
									domNode.parentNode.appendChild(script_nodes[k]);
								}
							}						
						}
						else{
							domNode.parentNode.appendChild(domChildNode);
						}
					}
                }
            }
        }              
    }
    function getInsertBefore(domNode,xml){
        var domChildNode=null;
        for(var i=0;i<xml.childNodes.length;i++){
            domChildNode=handleNode(xml.childNodes[i]);
            if(domChildNode!=null) {
                if(domChildNode.nodeName == "multiple_nodes"){ // Added by pinhow 7-Mar-2007
					getInsertBefore(domNode,domChildNode);
				}
				else {
					if( isIE ){  // Added by pinhow 8-Mar-2007					
						if(domChildNode.nodeName.toLowerCase() == "script_tag" ){
							domNode.parentNode.insertBefore(getIEScriptNode(domChildNode),domNode);
						}
						else{						
							var script_nodes = getIEScriptNodes(domChildNode);							
							domNode.parentNode.insertBefore(domChildNode,domNode);
							for(var k=0; k < script_nodes.length; k++){
								domNode.parentNode.insertBefore(script_nodes[k],domNode);
							}	
						}
					}
					else{
						domNode.parentNode.insertBefore(domChildNode,domNode);
					}
				}
            }
        }              
    }      
    function getReplace(domNode,xml){
        getInsertAfter(domNode,xml);
        domNode.parentNode.removeChild(domNode);
    }
    function getDelete(domNode) {
        domNode.parentNode.removeChild(domNode);
    }
    function getReplaceChildren(domNode,xml,doRemoveChildren) {
        var domChildNode=null;
        if(doRemoveChildren){
            while(domNode.childNodes.length >0){
                domNode.removeChild(domNode.childNodes[0]);
            }      
        }
        for(var i=0;i<xml.childNodes.length;i++){
            domChildNode=handleNode(xml.childNodes[i]);
            if(domChildNode!=null) {
                if(domChildNode.nodeName == "multiple_nodes"){ // Added by pinhow 7-Mar-2007
					getReplaceChildren(domNode,domChildNode, false);
				}
				else{				
					if( isIE ){  // Added by pinhow 8-Mar-2007					
						if(domChildNode.nodeName.toLowerCase() == "script_tag" ){
							domNode.appendChild(getIEScriptNode(domChildNode));
						}
						else{
							var script_nodes = getIEScriptNodes(domChildNode);								
							domNode.appendChild(domChildNode);	
							for(var k=0; k < script_nodes.length; k++){
								domNode.appendChild(script_nodes[k]);
							}	
						}				
					}
					else{
						domNode.appendChild(domChildNode);
					}					
				}
            }
        }              
    }
	
	// For IE only. Get the "script_tag" tags, convert to "script" tags, return as an array.
	// Remove the "script_tag" tags since no longer be used.
	function getIEScriptNodes(domChildNode){ // Added by pinhow 8-Mar-2007
		var script_nodes = new Array();
		var k = 0;
		for(var j=0; j<domChildNode.childNodes.length; j++){
			if( domChildNode.childNodes[j].nodeName.toLowerCase() == "script_tag" ){
				script_nodes[k] = domChildNode.childNodes[j];
				script_nodes[k] = document.createElement("script");
				script_nodes[k].text=domChildNode.text;
				script_nodes[k].text = domChildNode.childNodes[j].text;
				domChildNode.removeChild(domChildNode.childNodes[j]);
			}
			else{
				var script_nodes2 = getIEScriptNodes(domChildNode.childNodes[j]);
				script_nodes = script_nodes.concat(script_nodes2);
			}
			k = script_nodes.length;
		}
		return script_nodes;
	}
	function getIEScriptNode(input_node){
		var script_node = document.createElement("script");
		handleAttributes(script_node, input_node);
		script_node.text=input_node.text;
		return script_node;
	}
    
    function handleRedirect(xmlNode) {
        var targetUrl = xmlNode.getAttribute("targetUrl");
        window.location.replace(targetUrl);
    }
    
    function executeJavascript(xmlNode) {
        var scripts = xmlNode.getElementsByTagName("script");
        for (var i = 0; i < scripts.length; i++) {
            var script = scripts[i];
            if (script.getAttribute("type") == "text/javascript") {
                var js = script.firstChild.nodeValue;
                eval(js);
            }
        }
    }

    function cleanAttributeName(name) {
        if(isIE == false) {
            return;
        }
        
        // IE workaround to change cellspacing to cellSpacing, etc
        var cleanName = name.toLowerCase();
        if(cleanName == "cellspacing") {
            cleanName = "cellSpacing";
        }
        else if(cleanName == "cellpadding") {
            cleanName = "cellPadding";
        }
        else if(cleanName == "colspan") {
            cleanName = "colSpan";
        }
        else if(cleanName == "tabindex") {
            cleanName = "tabIndex";
        }
        else if(cleanName == "readonly") {
            cleanName = "readOnly";
        }
        return cleanName;
    }
    
}
