// Cross-Browser Rich Text Editor
// http://www.kevinroth.com/rte/demo.htm
// Written by Kevin Roth (kevin@NOSPAMkevinroth.com - remove NOSPAM)
// Visit the support forums at http://www.kevinroth.com/forums/index.php?c=2

var RTE = function rte()
{    	
    var self                = null;
    this.text               = null;
    this.textAlign          = null;
    this.font               = null;
	this.templateClass      = null;
    this.position           = null;
    this.dimensions         = null;
    this.element            = null;
    var iframeBody          = null;
    var iframeWindow        = null;
    var iframeDocument   	= null;
    this.currentPalette     = null;
    this.editor             = null;
    
    return {
        init: function(editor)
        {
            self = this;
            self.element = Dom.get("rte1");
            self.editor = editor;
            
			iframeDocument  = (isBrowserIE()) ? document.frames[self.element.id].document : self.element.contentDocument;
			iframeWindow    = self.element.contentWindow;
			iframeBody      = iframeWindow.document.body;
			
			if (!isBrowserIE()) {iframeDocument.designMode = "On";} // Enables text editing inside the BODY for FF. IE has its own defenition "<body CONTENTEDITABLE="true">"	
			self.element.allowTransparency = true; // Makes the background transparent
			Dom.setStyle(iframeBody, "background-color", "transparent"); // Also needed
			self.element.frameborder = 0;
			
			maxDimension = parent;
            
            return self;
        },  
        
        getIFrameBody: function()
        {
            var iframeBody;
            
    	    // Get iframeBody.
    	 	if (document.all) {
			    iframeBody = self.element.document.body;
		    } else {
			    iframeBody = self.element.contentWindow.document.body;
		    }
		    
		    return iframeBody;
        }, // getIFrameBody
        
        getIFrameWindow: function()
        {
            return self.element.contentWindow;
        }, // getIFrameBody
    	
    	// Returns properties for textElement
    	getProperties: function()
    	{
    	    iframeBody = self.getIFrameBody();
		
    		self.position = [Dom.getStyle(self.element, "top"), Dom.getStyle(self.element, "left")];
    		self.dimensions = [parseInt(Dom.getStyle(self.element, "width"), 10), parseInt(Dom.getStyle(self.element, "height"), 10)];
    		self.font = [Dom.getStyle(iframeBody, "font-family"), Dom.getStyle(iframeBody, "font-size")];
		    self.textAlign = Dom.getStyle(iframeBody, "text-align");
    		self.text = iframeBody.innerHTML;
    		
    		return [self.position, self.dimensions, self.text, self.font, self.textAlign];
    	},
        
    	// Sets the properties that were gotten from textElement
    	setProperties: function(args)
    	{
    		self.position = args[0];
    		self.dimensions = args[1];
    		self.text = args[2];
    		self.font = args[3]; 
    		self.textAlign = args[4];  
			self.templateClass = args[5]; 
    		
    		//Update element
    		Dom.setStyle(self.element, "top", self.position[0]);
    		Dom.setStyle(self.element, "left", self.position[1]);
    		Dom.setStyle(self.element, "width", self.dimensions[0]+"px");
    		Dom.setStyle([self.element,iframeBody], "height", self.dimensions[1]+"px");
    		    		
    	    iframeBody = self.getIFrameBody();
    		
    		self.enableDesignMode("rte1", self.text, false, self.templateClass);
    	},

        enableDesignMode : function(rte, html, readOnly, templateClass)
        {            
            self.element.allowTransparency = true; // Makes the background transparent
			self.element.frameborder = 0;
			
	        var frameHtml = "<html id=\"" + rte + "\">\n";
	        
	        frameHtml += "<head>\n";
	        frameHtml += "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../styles/templateList.css\" />";
	        
	        frameHtml += "<style>\n";
	        frameHtml += "* {margin: 0; padding: 0;}\n";
	        frameHtml += "HTML {\n";
	        frameHtml += "  overflow: hidden;";
	        frameHtml += "}\n";
	        frameHtml += "body {\n";
	        frameHtml += "  background-color: transparent;\n";
	        frameHtml += "  font-size: " + self.font[1] + ";\n";
	        frameHtml += "  font-family: " + self.font[0] + ";\n";
	        frameHtml += "	border: none;\n";
	        frameHtml += "	overflow: hidden;\n";
	        frameHtml += "	padding-left: 21px;\n";
	        frameHtml += "  overflow: hidden;\n";
	        frameHtml += "}\n";
	        frameHtml += "p {\n";
	        frameHtml += "  display: inline;\n";
	        frameHtml += "}\n";	    	        
	        frameHtml += "</style>\n";
	        
	        frameHtml += "</head>\n";
	        
	        frameHtml += "<body class=\"" + templateClass + "\" style=\"text-align: " + self.textAlign + ";\">\n";
	        frameHtml += html + "\n";
	        frameHtml += "</body>\n";
	        
	        frameHtml += "</html>";
        	
        	var ua = navigator.userAgent.toLowerCase();
        	isGecko = (ua.indexOf("gecko") != -1);
        	
	        if (document.all)
	        {
		        var oRTE = frames[rte].document;
		        oRTE.open();
		        oRTE.write(frameHtml);
		        oRTE.close();
		        if (!readOnly) oRTE.designMode = "On";
	        }
	        else
	        {
		        try
		        {
			        if (!readOnly) document.getElementById(rte).contentDocument.designMode = "on";
			        try
			        {
				        var oRTE = document.getElementById(rte).contentWindow.document;
				        oRTE.open();
				        oRTE.write(frameHtml);
				        oRTE.close();
				        if (isGecko && !readOnly) {
					        //attach a keyboard handler for gecko browsers to make keyboard shortcuts work
					        oRTE.addEventListener("keypress", self.kb_handler, true);
				        }
			        }
			        catch (e)
			        {
				        alert("Error preloading content.");
			        }
		        }
		        catch (e)
		        {
			        //gecko may take some time to enable design mode.
			        //Keep looping until able to set.
			        if (isGecko)
			        {
				        setTimeout("enableDesignMode('" + rte + "', '" + html + "', " + readOnly + ");", 10);
			        }
			        else
			        {
				        return false;
			        }
		        }
	        }
			
			iframeBody = self.getIFrameBody();
			
			// Sets the keyListeners (the difference between the browsers is the element the listener is attached to - iframeBody/iframeDocument)
			if (isBrowserIE())
			{
				YAHOO.util.Event.addListener(iframeBody , "keyup", self.updateIFrameHeight);
				YAHOO.util.Event.addListener(iframeBody , "keydown", self.captureKey);
			}
			else
			{
				YAHOO.util.Event.addListener(iframeDocument, "keyup", self.updateIFrameHeight);
				YAHOO.util.Event.addListener(iframeDocument, "keydown", self.captureKey);
			}
        }, // enableDesignMode
        
        editText: function(command, option)
        {
   			switch (command)
   			{
   			    // Uses the browser internal method "execCommand" - reference : http://msdn2.microsoft.com/en-us/library/ms533049.aspx
    	        // Although Justify is supported in "execCommand", using it in IE6 seems to create a system bug (browser freeze) so this specific implementation is manual
				case ("JustifyLeft"):
				case ("JustifyRight"):
				case ("JustifyCenter"):
				    var textAlign = command.replace("Justify", "");
				    iframeBody = self.getIFrameBody();
				    Dom.setStyle(iframeBody, "text-align", textAlign);
				    break;
				
			    // "backcolor" for IE and "hilitecolor" for Moz..
				case ("backcolor"):
				    if (!isBrowserIE()) { command = "hilitecolor"; }
				    self.rteCommand(self.element.id, command, option);
                    break;
                    
    			default:
    			    self.rteCommand(self.element.id, command, option);
    		}
    		
			selectInWin.hideCurrentInWin(); // Causes the select font inwin to disappear
			self.editor.hideColorPalette(); // Causes the color selection inwin to disappear
    		self.updateIFrameHeight(); // Needed when updating font family or size (the wrapping element's height must be update as well)
            
        }, // editText

        rteCommand: function(rte, command, option)
        {
	        //function to perform command
	        var oRTE;
	        
	        if (document.all)
	        {
		        oRTE = frames[rte];
	        }
	        else
	        {
		        oRTE = document.getElementById(rte).contentWindow;
	        }
        	
	        try
	        {
		        oRTE.focus();
	  	        oRTE.document.execCommand(command, false, option);
		        oRTE.focus();
	        }
	        catch (e)
	        {
		        //alert(e);
		        //setTimeout("rteCommand('" + rte + "', '" + command + "', '" + option + "');", 10);
	        }
        },   
    	
    	// Sets the variable to "backcolor" / "forcolor"
    	setCurrentPalette: function(palette)
    	{
    	    self.currentPalette = palette;
    	}, // setCurrentPalette
	
	    // Selects all the text in inside the edit element
	    selectAll: function(hypletTextElement)
	    {
            if (isBrowserIE())
            {
                iframeBody = self.getIFrameBody();
                
                var length = iframeBody.innerHTML.length;
                var textRange = iframeBody.createTextRange();
                textRange.collapse(true);//go to beginning of range
                textRange.moveEnd('character', length);
                textRange.moveStart('character', 0);
                textRange.select(); 
            }    
            else
            {
                iframeWindow = self.getIFrameWindow();
                    
                var innerText = clearHTMLTags(hypletTextElement.mainElement.innerHTML);
                innerText = innerText.replace("&lt;","<").replace("&gt;",">").replace(/&nbsp;/gim," ");
                
                // Meant to disregard a &nbsp; at the end of a innerText (that may come from a prior text deletion) and that apparently disables the select functionality
                var space = "&nbsp;";
                if (innerText!=space && innerText.lastIndexOf(space)==(innerText.length-space.length)) {
                    innerText=innerText.slice(0,innerText.length-space.length);
                }
                iframeWindow.find(innerText, false, false);
                iframeWindow.focus();
            }
        },
        
        focus: function()
        {
            iframeWindow = self.getIFrameWindow();
            iframeWindow.focus();
        }, // focus
		
		// Sets the color of the selected text
		// Fired within rte/palette.htm
		setColor: function(color, e)
		{
		    //if (e) {YAHOO.util.Event.stopEvent(e);} // I'm not sure what this is needed for - right now everything works fine in IE and Moz
			self.editText(self.currentPalette, color);
		}, // setColor
		
	    restoreDefaults: function()
	    {
	         self.editText("removeFormat"); 
	    }, // restoreDefaults
	
	    // Captures the ENTER and ESC keys and unEdits the text element
	    captureKey: function(e)
        {
            var evt = null;
        
            if (!e)
            {
                evt = event;
                evt.sender = evt.srcElement;
            }
            else
            {
                evt = e;
                evt.sender = evt.target;
            }
                
            if ((evt.keyCode == 13 && !evt.shiftKey) || evt.keyCode == 27)
            {
                self.editor.unEditElement();
            }
        }, // captureKey
        
        // Updates the height of the edit element Iframe so that it corisponds to the text inside it
        // The IFrane element is the one that needs to be set with the calculated height therefore it gets the height of the IFrame body
        updateIFrameHeight: function()
        {
    	    iframeBody = self.getIFrameBody();
    	    
    		Dom.setStyle(iframeBody, "height", "auto"); 
        	var height = iframeBody.offsetHeight;
        	
        	// diffHeight holds the difference between the old height and the new one
        	// If it is more than zero, which means the IFrame grew, then check if it makes the element overflow the HypletEditor.
        	// If it does - it changes the "top" property and pulls the element back up
        	var diffHeight = height - self.element.offsetHeight;
        	if (diffHeight > 0)
        	{
        	    var iframeRegion = YAHOO.util.Region.getRegion(self.element);
        	    if (!self.editor.region.contains(iframeRegion)){
        	       var newY = parseInt(Dom.getStyle(self.element, "top"), 10) - (diffHeight+4);
            	   Dom.setStyle(self.element, "top", newY+"px");
        	    }
        	}
        	Dom.setStyle(self.element, "height", height+"px");
        }, //updateIFrameHeight
        
        kb_handler: function(evt)
        {
	        var rte = evt.target.id;
        	
	        //contributed by Anti Veeranna (thanks Anti!)
	        if (evt.ctrlKey) {
		        var key = String.fromCharCode(evt.charCode).toLowerCase();
		        var cmd = '';
		        switch (key) {
			        case 'b': cmd = "bold"; break;
			        case 'i': cmd = "italic"; break;
			        case 'u': cmd = "underline"; break;
		        };

		        if (cmd) {
			        rteCommand(rte, cmd, null);
        			
			        // stop the event bubble
			        evt.preventDefault();
			        evt.stopPropagation();
		        }
 	        }
        } // kb_handler
    } // return
}();