// widgEditor.js: HTML Editor
// Requires: DOM 3

// FIXME: I think the widgEditor should die and my html editor should be used instead (agustinf)


//*****************************************************************************
//    END CONFIGURATION
//****************************************************************************/

function registerWidgEditor (id,webpath) {
     DOM.addEventListener(window, 'load', function() { new widgEditor(id,false,false,webpath) });
}

function widgEditor(replacedTextareaID, extraToolbarElem, registerOnSubmit, webpath)
{
    // If widgInsertParagraphs = true, when content is submitted paragraphs will be
    // inserted around text without a parent element. Mozilla does not
    // automatically do this, so if this is set to false you will end up with some
    // plain text blocks. Uses a double <br /> as a pargraph marker.
    this.self = this;
    this.theTextarea = document.getElementById(replacedTextareaID);
    this.theContainer = document.createElement("div");
    this.theIframe = document.createElement("iframe");
    this.theInput = document.createElement("input");
    this.theInst = replacedTextareaID + "Inst";
    this.webpath = webpath;
    
    this.menus = [
        { name:  'Cut', action: this.menuCut, disabled: DOM.isGecko },
        { name:  'Copy', action: this.menuCopy, disabled: DOM.isGecko },
        { name:  'Paste', action: this.menuPaste, disabled: DOM.isGecko },
        { name:  '' },
        { name:  'Select all', action: this.menuSelectAll, disabled: false }
    ];
    
    this.initialized = false;
    this.locked = true;
    this.pasteCache = "";
    this.focused = false;
    
    // Location of stylesheet file for editor content
    this.widgStylesheet = this.webpath + "assets/css/htmlEditor/widgContent.css";
    this.widgInsertParagraphs = true;

    // Modify DOM objects for editor
    this.theContainer.id = this.theTextarea.id + "WidgContainer";
    this.theContainer.className = "widgContainer";
    
    this.iframeId = this.theTextarea.id  + "WidgIframe";
    this.theIframe.id = this.iframeId;
    this.theIframe.className = "widgIframe";
    this.theIframe.frameBorder = 0;
    
    this.theInput.type = "hidden";
    this.theInput.id = this.theTextarea.id;
    this.theInput.name = this.theTextarea.name;
    this.theInput.value = this.theTextarea.value;

    this.theToolbar = new widgToolbar(this, extraToolbarElem);
    
    this.theTextarea.id += "WidgTextarea";
    this.theTextarea.name += "WidgTextarea";
    
    this.theContainer.appendChild(this.theToolbar.theList);
    this.theContainer.appendChild(this.theIframe);
    this.theContainer.appendChild(this.theInput);

    this.theInput.widgEditorObject = this;
    
    this.theTextarea.parentNode.replaceChild(this.theContainer, this.theTextarea);

    // Fill editor with old textarea content
    this.writeDocument(this.theInput.value);

    // Make editor editable
    this.initEdit();
    var me = this;
    // Add submit listener to parent form
    if (registerOnSubmit) {
        var oldOnsubmit = null;
        var theForm = this.theContainer.parentNode;
        var haveForm = true;
        
        while (haveForm == true && theForm.nodeName.toLowerCase() != "form") {
            if (theForm.parentNode) {
                theForm = theForm.parentNode;
            } else {
                theForm = document.forms[0]
                haveForm = false;
            }
        }
        
        addOnSubmitEvent(theForm, function() { me.updateInput() });
    }
    if (!DOM.isGecko) {
        var popupmenu = new PopupMenu(this.theIframe, this.menus, true, this);
        popupmenu.registerElement(this.theIframe);
        if (DOM.isIE) {
            popupmenu.onbeforeopen = function()
            {
                me.selectionBeforeContextMenu = me.theIframe.contentWindow.document.selection.createRange();
            }
        }
        DOM.addObjEventListener(this, this.theIframe.contentWindow.document, 'keydown', this.handleKeyEvent);
    }
    return true;
}

widgEditor.prototype.get = function()
{
    this.updateInput();
    return this.theInput.value;
}

widgEditor.prototype.updateInput = function()
{
    if (DOM.isGecko) { // Convert spans to semantics in Mozilla
        this.convertSPANs(true);
    }
    this.paragraphise();
    this.cleanSource();
    this.theTextarea.value = this.theInput.value;
}

widgEditor.prototype.fixSelection = function()
{
    this.theIframe.contentWindow.focus();
    if (DOM.isIE) {
        this.selectionBeforeContextMenu.select();
    }
}

widgEditor.prototype.menuCut = function()
{
    this.fixSelection()
    this.theIframe.contentWindow.document.execCommand('cut', false, null);
}

widgEditor.prototype.menuCopy = function()
{
    this.fixSelection()
    this.theIframe.contentWindow.document.execCommand('copy', false, null);
}

widgEditor.prototype.menuPaste = function()
{
    this.fixSelection()
    this.theIframe.contentWindow.document.execCommand('paste', false, null);
}

widgEditor.prototype.menuSelectAll = function()
{
    this.fixSelection()
    this.theIframe.contentWindow.document.execCommand('selectall', false, null);
}

widgEditor.prototype.handleKeyEvent = function(event)
{
    if (event.keyCode == 9) {
        if (DOM.isGecko) {
            DOM.focusNextElement(this.theIframe, event.shiftKey);
            DOM.preventDefault(event);
            DOM.stopPropagation(event);
        }
    } else if (event.ctrlKey) {
        try {
            var chr = String.fromCharCode(event.keyCode).toLowerCase();
            if (chr == 'b') {
                this.theIframe.contentWindow.document.execCommand('bold', false, null);
                DOM.preventDefault(event);
                DOM.stopPropagation(event);
            } else if (chr == 'i') {
                this.theIframe.contentWindow.document.execCommand('italic', false, null);
                DOM.preventDefault(event);
                DOM.stopPropagation(event);
            } else if (chr == 'k') {
                this.theToolbar.widgToolbarAction('link');
                DOM.preventDefault(event);
                DOM.stopPropagation(event);
            }
        } catch (e) {
            Log(e);
        }
    }
}

// Clean pasted content
widgEditor.prototype.cleanPaste = function()
{
        this.cleanSource();
        
        var matchedHead = "";
        var matchedTail = "";
        var newContent = this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
        var newContentStart = 0;
        var newContentFinish = 0;
        var newSnippet = "";
        var tempNode = document.createElement("div");
        var i;
        
        // Find start of both strings that matches
        for (newContentStart = 0; newContent.charAt(newContentStart) == this.pasteCache.charAt(newContentStart); newContentStart++)
        {
            matchedHead += this.pasteCache.charAt(newContentStart);
        }
        
        // If newContentStart is inside a HTML tag, move to opening brace of tag
        for (i = newContentStart; i >= 0; i--)
        {
            if (this.pasteCache.charAt(i) == "<") {
                newContentStart = i;
                matchedHead = this.pasteCache.substring(0, newContentStart);
                
                break;
            } else if(this.pasteCache.charAt(i) == ">") {
                break;
            }
        }

        newContent = this.reverseString(newContent);
        this.pasteCache = this.reverseString(this.pasteCache);

        // Find end of both strings that matches
        for (newContentFinish = 0; newContent.charAt(newContentFinish) == this.pasteCache.charAt(newContentFinish); newContentFinish++) {
            matchedTail += this.pasteCache.charAt(newContentFinish);
        }

        // If newContentFinish is inside a HTML tag, move to closing brace of tag
        for (i = newContentFinish; i >= 0; i--) {
            if (this.pasteCache.charAt(i) == ">") {
                newContentFinish = i;
                matchedTail = this.pasteCache.substring(0, newContentFinish);
                
                break;
            } else if(this.pasteCache.charAt(i) == "<") {
                break;
            }
        }

        matchedTail = this.reverseString(matchedTail);

        // If there's no difference in pasted content
        if (newContentStart == newContent.length - newContentFinish) {
            return false;
        }

        newContent = this.reverseString(newContent);
        newSnippet = newContent.substring(newContentStart, newContent.length - newContentFinish);
        newSnippet = this.validTags(newSnippet);

        // Replace opening bold tags with strong
        newSnippet = newSnippet.replace(/<b(\s+|>)/g, "<strong$1");
        // Replace closing bold tags with closing strong
        newSnippet = newSnippet.replace(/<\/b(\s+|>)/g, "</strong$1");    
        // Replace italic tags with em
        newSnippet = newSnippet.replace(/<i(\s+|>)/g, "<em$1");
        // Replace closing italic tags with closing em
        newSnippet = newSnippet.replace(/<\/i(\s+|>)/g, "</em$1");
        // Strip out unaccepted attributes
        newSnippet = newSnippet.replace(/<[^>]*>/g,
            function(match)
            {
                match = match.replace(/ ([^=]+)="[^"]*"/g,
                    function(match2, attributeName)
                    {
                        if (attributeName == "alt" || attributeName == "href" || attributeName == "src" || attributeName == "title") {
                            return match2;
                        }
                        return "";
                    }
                );
                return match;
            }
        );

        tempNode.innerHTML = newSnippet;

        this.acceptableChildren(tempNode);
        
        this.theInput.value = matchedHead + tempNode.innerHTML + matchedTail;

        // Final cleanout for MS Word cruft
        this.theInput.value = this.theInput.value.replace(/<\?xml[^>]*>/g, "");
        this.theInput.value = this.theInput.value.replace(/<[^ >]+:[^>]*>/g, "");
        this.theInput.value = this.theInput.value.replace(/<\/[^ >]+:[^>]*>/g, "");

        this.refreshDisplay();
        

//    return true;
}

// Clean the HTML code of the content area
widgEditor.prototype.cleanSource = function()
{
    var theHTML = "";
    
    theHTML = this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;

    theHTML = this.validTags(theHTML);
    
    // Remove leading and trailing whitespace
    theHTML = theHTML.replace(/^\s+/, "");
    theHTML = theHTML.replace(/\s+$/, "");
    
    // Remove style attribute inside any tag
    theHTML = theHTML.replace(/ style="[^"]*"/g, "");

    // Replace improper BRs
    theHTML = theHTML.replace(/<br>/g, "<br />");

    // Remove BRs right before the end of blocks
    theHTML = theHTML.replace(/<br \/>\s*<\/(li|p)/g, "</$1");

    //replace headings
    theHTML = theHTML.replace(/<h1([^>]*)>/g, "<div><strong>");
    theHTML = theHTML.replace(/<h2([^>]*)>/g, "<div><strong>");
    theHTML = theHTML.replace(/<h3([^>]*)>/g, "<div><strong>");
    theHTML = theHTML.replace(/<h4([^>]*)>/g, "<div><strong>");
    theHTML = theHTML.replace(/<h5([^>]*)>/g, "<div><strong>");
    theHTML = theHTML.replace(/<h6([^>]*)>/g, "<div><strong>");
    theHTML = theHTML.replace(/<\/h1([^>]*)>/g, "</strong></div>");
    theHTML = theHTML.replace(/<\/h2([^>]*)>/g, "</strong></div>");
    theHTML = theHTML.replace(/<\/h3([^>]*)>/g, "</strong></div>");
    theHTML = theHTML.replace(/<\/h4([^>]*)>/g, "</strong></div>");
    theHTML = theHTML.replace(/<\/h5([^>]*)>/g, "</strong></div>");
    theHTML = theHTML.replace(/<\/h6([^>]*)>/g, "</strong></div>");

    theHTML = theHTML.replace(/<p([^>]*)>/g, "<div>");
    theHTML = theHTML.replace(/<\/p([^>]*)>/g, "</div>");

    theHTML = theHTML.replace(/<o([^>]*)>/g, "");
    theHTML = theHTML.replace(/<\/o([^>]*)>/g, "");

    //change ordered lists for unordered lists
    theHTML = theHTML.replace(/<ol([^>]*)>/g, "<ul>");
    theHTML = theHTML.replace(/<\/ol([^>]*)>/g, "</ul>");

    // Remove empty tags
    theHTML = theHTML.replace(/(<[^\/]>|<[^\/][^>]*[^\/]>)\s*<\/[^>]*>/g, "");
    
    //fab
    theHTML = theHTML.replace(/-&gt;/g,"->");

    this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML = theHTML;
    
    if(!(theHTML == '<div>&nbsp;</div>' ||  theHTML == '<DIV>&nbsp;</DIV>'))
    this.theInput.value = theHTML;
    
    return true;
}

// Check for enter key
widgEditor.prototype.detectEnter = function(e)
{
    var keyPressed = null;
    var theEvent = null;
    
    if (e) {
        theEvent = e;
    } else {
        theEvent = event;
    }
    if (theEvent.keyCode == 13) {
        var self = this;
        self.paragraphise();
        return false;
    }

    return true;
}

// Check for pasted content
widgEditor.prototype.detectPaste = function(e)
{
    var keyPressed = null;
    var theEvent = null;
    
    if (e) {
        theEvent = e;
    } else {
        theEvent = event;
    }
    
    if (theEvent.ctrlKey && theEvent.keyCode == 86) {
        var self = this;
        this.pasteCache = this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
        // Because Mozilla can't access the clipboard directly, must rely on timeout to check pasted differences in main content
        setTimeout(function(){self.cleanPaste(); return true;}, 100);
    }

    return true;
}

widgEditor.prototype.convertSPANs = function(theSwitch)
{
    if (theSwitch) {
        /* Replace styled spans with their semantic equivalent */
        var theSPANs = this.theIframe.contentWindow.document.getElementsByTagName("span");
    
        while(theSPANs.length > 0) {
            var theChildren = new Array();
            var theReplacementElement = null;
            var theParentElement = null;
            
            for (var j = 0; j < theSPANs[0].childNodes.length; j++)
            {
                theChildren.push(theSPANs[0].childNodes[j].cloneNode(true));
            }
            
            /* Detect type of span style */
            switch (theSPANs[0].getAttribute("style"))
            {
                case "font-weight: bold;":
                    theReplacementElement = this.theIframe.contentWindow.document.createElement("strong");
                    theParentElement = theReplacementElement;
                    
                    break;
                
                case "font-style: italic;":
                    theReplacementElement = this.theIframe.contentWindow.document.createElement("em");
                    theParentElement = theReplacementElement;
                    
                    break;
                    
                case "font-weight: bold; font-style: italic;":
                    theParentElement = this.theIframe.contentWindow.document.createElement("em");
                    theReplacementElement = this.theIframe.contentWindow.document.createElement("strong");
                    theReplacementElement.appendChild(theParentElement);
                    
                    break;
                    
                case "font-style: italic; font-weight: bold;":
                    theParentElement = this.theIframe.contentWindow.document.createElement("strong");
                    theReplacementElement = this.theIframe.contentWindow.document.createElement("em");
                    theReplacementElement.appendChild(theParentElement);
                    
                    break;
                    
                default:
                    this.replaceNodeWithChildren(theSPANs[0]);
                
                    break;
            }
            
            if (theReplacementElement != null) {
                for (var j = 0; j < theChildren.length; j++) {
                    theParentElement.appendChild(theChildren[j]);
                }
                theSPANs[0].parentNode.replaceChild(theReplacementElement, theSPANs[0]);
            }
            
            theSPANs = this.theIframe.contentWindow.document.getElementsByTagName("span");
        }
    } else {
        /* Replace em and strong tags with styled spans */
        var theEMs = this.theIframe.contentWindow.document.getElementsByTagName("em");
        
        while(theEMs.length > 0)
        {
            var theChildren = new Array();
            var theSpan = this.theIframe.contentWindow.document.createElement("span");
            
            theSpan.setAttribute("style", "font-style: italic;");
            
            for (var j = 0; j < theEMs[0].childNodes.length; j++)
            {
                theChildren.push(theEMs[0].childNodes[j].cloneNode(true));
            }
            
            for (var j = 0; j < theChildren.length; j++)
            {
                theSpan.appendChild(theChildren[j]);
            }

            theEMs[0].parentNode.replaceChild(theSpan, theEMs[0]);
            theEMs = this.theIframe.contentWindow.document.getElementsByTagName("em");
        }
        
        var theSTRONGs = this.theIframe.contentWindow.document.getElementsByTagName("strong");
        
        while(theSTRONGs.length > 0)
        {
            var theChildren = new Array();
            var theSpan = this.theIframe.contentWindow.document.createElement("span");
            
            theSpan.setAttribute("style", "font-weight: bold;");
            
            for (var j = 0; j < theSTRONGs[0].childNodes.length; j++)
            {
                theChildren.push(theSTRONGs[0].childNodes[j].cloneNode(true));
            }
            
            for (var j = 0; j < theChildren.length; j++)
            {
                theSpan.appendChild(theChildren[j]);
            }

            theSTRONGs[0].parentNode.replaceChild(theSpan, theSTRONGs[0]);
            theSTRONGs = this.theIframe.contentWindow.document.getElementsByTagName("strong");
        }
    }
    
    return true;
}

widgEditor.prototype.isBroken = function()
{
    try {
        this.theIframe.contentWindow.document.execCommand("decreasefontsize", false, false);
        this.theIframe.contentWindow.document.execCommand("increasefontsize", false, false);
        return false;
    } catch (e) {
        return true;
    }
}

// Turn on document editing
widgEditor.prototype.initEdit = function()
{
    var self = this;
    var error = false;
    
    try {
        this.theIframe.contentWindow.document.designMode = "on";
    } catch (e) {
        error = true;
    }
    
    if (!DOM.isIE) {
        this.convertSPANs(false);
    }
    
    if (!this.initialized) {
        this.theContainer.style.visibility = "visible";
        this.theTextarea.style.visibility = "visible";
        
        // Mozilla event capturing
        if (typeof document.addEventListener == "function") {
            function fixMozillaFocusBug() {
                var selection = self.theIframe.contentWindow.getSelection();
                if (selection.focusNode) {
                    return;
                }
                var range = self.theIframe.contentWindow.document.createRange();
                range.selectNodeContents(self.theIframe.contentWindow.document.body.firstChild);
                range.collapse(true);
                selection.addRange(range);
            }
            this.theIframe.contentWindow.document.addEventListener("focus", function(){ if (!self.focused && self.isBroken()) { self.initEdit(); self.focused = true } fixMozillaFocusBug() }, false);
            this.theIframe.contentWindow.document.addEventListener("blur", function(){ self.focused = false; }, false);
            this.theIframe.contentWindow.document.addEventListener("mouseup", function(){widgToolbarCheckState(self);}, false);
            this.theIframe.contentWindow.document.addEventListener("keyup", function(e){widgToolbarCheckState(self);self.detectEnter(e);}, false);
            this.theIframe.contentWindow.document.addEventListener("keydown", function(e){self.detectPaste(e); }, false);
        } else { // IE event capturing
            this.theIframe.contentWindow.document.attachEvent("onmouseup", function(){widgToolbarCheckState(self); return true;});
            this.theIframe.contentWindow.document.attachEvent("onkeyup", function(e){widgToolbarCheckState(self);self.detectEnter(e); return true;});
            this.theIframe.contentWindow.document.attachEvent("onkeydown", function(e){self.detectPaste(e); return true;}, false);
        }
        
        this.locked = false;
        if ((typeof mainTabs) != 'undefined') {
            if ((typeof mainTabs.resizeTabSection) != 'undefined') {
                mainTabs.resizeTabSection();
            }
        }
        //resizeParentIFrameIfNeeded(150);
        this.initialized = true;
    }
    return true;
}

// Add elements to a paragraph and inserts the paragraph before a given element in the body
widgEditor.prototype.insertNewParagraph = function(elementArray, succeedingElement)
{
    var theBody = this.theIframe.contentWindow.document.getElementsByTagName("body")[0];
    var theParagraph = this.theIframe.contentWindow.document.createElement("div");
    
    for (var i = 0; i < elementArray.length; i++) {
        theParagraph.appendChild(elementArray[i]);
    }
    
    if (typeof(succeedingElement) != "undefined") {
        theBody.insertBefore(theParagraph, succeedingElement);
    } else {
        theBody.appendChild(theParagraph);
    }
    
    return true;
}

// Format the HTML with paragraphs. Any parentless text is enclosed in a paragraph, double breaks are paragraph markers
widgEditor.prototype.paragraphise = function()
{
    if (this.widgInsertParagraphs) {
        var theBody = this.theIframe.contentWindow.document.getElementsByTagName("body")[0];
        // Remove all text nodes containing just whitespace
        for (var i = 0; i < theBody.childNodes.length; i++) {
            if (theBody.childNodes[i].nodeName.toLowerCase() == "#text" &&
                theBody.childNodes[i].data.search(/^\s*$/) != -1) {
                theBody.removeChild(theBody.childNodes[i]);
                --i;
            }
        }
        
        var removedElements = new Array();
        
        for (var i = 0; i < theBody.childNodes.length; i++) {
            if (this.isInlineName(theBody.childNodes[i].nodeName)) {
                removedElements.push(theBody.childNodes[i].cloneNode(true));
                theBody.removeChild(theBody.childNodes[i]);
                --i;
            } else if (theBody.childNodes[i].nodeName.toLowerCase() == "br") {
                if (i + 1 < theBody.childNodes.length) {
                    // If the current break tag is followed by another break tag
                    if (theBody.childNodes[i + 1].nodeName.toLowerCase() == "br") {
                        // Remove consecutive break tags
                        while (i < theBody.childNodes.length && theBody.childNodes[i].nodeName.toLowerCase() == "br") {
                            theBody.removeChild(theBody.childNodes[i]);
                        }
                        if (removedElements.length > 0) {
                            this.insertNewParagraph(removedElements, theBody.childNodes[i]);
                            removedElements = new Array();
                        }
                    } else if (!this.isInlineName(theBody.childNodes[i + 1].nodeName)) { // If the break tag appears before a block element
                        theBody.removeChild(theBody.childNodes[i]);
                    } else if (removedElements.length > 0) {
                        removedElements.push(theBody.childNodes[i].cloneNode(true));
                        theBody.removeChild(theBody.childNodes[i]);
                    } else {
                        theBody.removeChild(theBody.childNodes[i]);
                    }
                    --i;
                } else {
                    theBody.removeChild(theBody.childNodes[i]);
                }
            } else if (removedElements.length > 0) {
                this.insertNewParagraph(removedElements, theBody.childNodes[i]);
                removedElements = new Array();
            }
        }
        if (removedElements.length > 0) {
            this.insertNewParagraph(removedElements);
        }
    }
    
    return true;
}

// Update hidden input to reflect editor contents, for submission
widgEditor.prototype.refreshDisplay = function()
{

    this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML    = this.theInput.value;
    return true;
}

// Write initial content to editor
widgEditor.prototype.writeDocument = function(documentContent)
{
    // HTML template into which the HTML Editor content is inserted
    var documentTemplate = "\
        <html>\
            <head>\
                <style type=\"text/css\">@import url(\"INSERT:STYLESHEET:END\");</style>\
            </head>\
            <body id=\"iframeBody\">\INSERT:CONTENT:END\</body>\
        </html>\
    ";
    
    // Insert dynamic variables/content into document
    documentTemplate = documentTemplate.replace(/INSERT:STYLESHEET:END/, this.widgStylesheet);
    if(documentContent != '')
    {
        documentTemplate = documentTemplate.replace(/INSERT:CONTENT:END/, documentContent);
    }
    else
    {
        documentTemplate = documentTemplate.replace(/INSERT:CONTENT:END/, '<div>&nbsp;</div>');
    }
    
    this.theIframe.contentWindow.document.open();
    this.theIframe.contentWindow.document.write(documentTemplate);
    this.theIframe.contentWindow.document.close();
    
    return true;
}

widgEditor.prototype.acceptableChildren = function(theNode)
{
    var theChildren = theNode.childNodes, temp;
    
    for (var i = 0; i < theChildren.length; i++) {
        if (!this.isAcceptedElementName(theChildren[i].nodeName)) {
            if (!this.isInlineName(theChildren[i].nodeName)) {
                if (theNode.nodeName.toLowerCase() == "div") {
                    temp = this.replaceNodeWithChildren(theNode);
                    // This was because of mantis#0000801: JobBoard - WidgEditor pasting error
                    // I However, I really didn't understand the source of the problem very well. I just ensured that if there was no node returned, the function would stop calling itself
                    if (typeof temp == 'object') {
                        this.acceptableChildren(temp);
                    }
                    return true;
                }
                this.changeNodeType(theChildren[i], "div");
            } else {
                this.replaceNodeWithChildren(theChildren[i]);
            }
            i = -1;
        }
    }
    
    for (var i = 0; i < theChildren.length; i++)
    {
        this.acceptableChildren(theChildren[i]);
    }
    
    return true;
}

// Change the type of a node, e.g. h3 to p
widgEditor.prototype.changeNodeType = function(theNode, nodeType)
{
    var theChildren = new Array();
    var theNewNode = document.createElement(nodeType);
    var theParent = theNode.parentNode;
    
    if (theParent != null) {
        for (var i = 0; i < theNode.childNodes.length; i++) {
            theChildren.push(theNode.childNodes[i].cloneNode(true));
        }
        for (var i = 0; i < theChildren.length; i++) {
            theNewNode.appendChild(theChildren[i]);
        }
        theParent.replaceChild(theNewNode, theNode);
    }
    
    return true;
}

// Replace a node with its children -- delete the item and move its children up one level in the hierarchy
widgEditor.prototype.replaceNodeWithChildren = function(theNode)
{
    var theChildren = new Array();
    var theParent = theNode.parentNode;
    
    if (theParent != null) {
        for (var i = 0; i < theNode.childNodes.length; i++) {
            theChildren.push(theNode.childNodes[i].cloneNode(true));
        }
        for (var i = 0; i < theChildren.length; i++) {
            theParent.insertBefore(theChildren[i], theNode);
        }
        theParent.removeChild(theNode);
        return theParent;
    }
    
    return true;
}

// Check if a string is the nodeName of an accepted element
widgEditor.prototype.isAcceptedElementName = function(elementName)
{
    var elementList = new Array("#text", "a", "em", "br", "li", "ol", "div", "strong");
    var theName = elementName.toLowerCase();
    for (var i = 0; i < elementList.length; i++) {
        if (theName == elementList[i]) {
            return true;
        }
    }
    return false;
}

// Check if a string is the nodeName of an inline element
widgEditor.prototype.isInlineName = function(elementName)
{
    var inlineList = new Array("#text", "a", "em", "font", "span", "strong", "u", "img");
    var theName = elementName.toLowerCase();
    for (var i = 0; i < inlineList.length; i++) {
        if (theName == inlineList[i]) {
            return true;
        }
    }
    return false;
}

// Reverse a string
widgEditor.prototype.reverseString = function(str)
{
    var theString = "";
    for (var i = str.length - 1; i >= 0; i--) {
        theString += str.charAt(i);
    }
    return theString;
}

// Make tags valid by converting uppercase element and attribute names to lowercase and quoting attributes
widgEditor.prototype.validTags = function(theString)
{
    // Replace uppercase element names with lowercase
    theString = theString.replace(/<[^> ]*/g, function(match){return match.toLowerCase();});
    
    // Replace uppercase attribute names with lowercase
    theString = theString.replace(/<[^>]*>/g, function(match)
        {
            match = match.replace(/ [^=]+=/g, function(match2){return match2.toLowerCase();});

            return match;
        });
            
    // Put quotes around unquoted attributes
    theString = theString.replace(/<[^>]*>/g, function(match)
        {
            match = match.replace(/( [^=]+=)([^"][^ >]*)/g, "$1\"$2\"");
            
            return match;
        });
        
    return theString;
}

// Toolbar items
function widgToolbar(theEditor,extraToolbarElem)
{
    var self = this;
    
    // Items to appear in toolbar.
    this.widgToolbarItems = new Array();
    self.widgToolbarItems.push("bold");
    self.widgToolbarItems.push("italic");
    self.widgToolbarItems.push("hyperlink");
    self.widgToolbarItems.push("unorderedlist");
    self.widgToolbarItems.push("htmlsource");
    
    // Initializating extra toolbar elements
    if (extraToolbarElem) {
        var theElements = extraToolbarElem.split('|');
        for (var i = 0; i < theElements.length; i++) {
            if(theElements[i] == "jobTitle")
            self.widgToolbarItems.push("jobTitle");
            if(theElements[i] == "candFirstName")
            self.widgToolbarItems.push("candFirstName");
            if(theElements[i] == "userFirstName")
            self.widgToolbarItems.push("userFirstName");
            if(theElements[i] == "resumeSource")
            self.widgToolbarItems.push("resumeSource");
            if(theElements[i] == "candLastName")
            self.widgToolbarItems.push("candLastName");
            if(theElements[i] == "userLastName")
            self.widgToolbarItems.push("userLastName");
        }
    }
    
    this.widgEditorObject = theEditor;
    
    // Create toolbar ul element
    this.theList = document.createElement("ul");
    this.theList.id = this.widgEditorObject.theInput.id + "WidgToolbar";
    this.theList.className = "widgToolbar";
    this.theList.widgToolbarObject = this;

    // Create toolbar items
    for (var i = 0; i < self.widgToolbarItems.length; i++) {
        switch (self.widgToolbarItems[i])
        {
            case "bold":
                this.addButton(this.theList.id + "ButtonBold", "widgButtonBold", "Bold", "bold");
                
                break;
                
            case "italic":
                this.addButton(this.theList.id + "ButtonItalic", "widgButtonItalic", "Italic", "italic");
                
                break;
                
            case "hyperlink":
                this.addButton(this.theList.id + "ButtonLink", "widgButtonLink", "Hyperlink", "link");
                
                break;
                
            case "unorderedlist":
                this.addButton(this.theList.id + "ButtonUnordered", "widgButtonUnordered", "Unordered List", "insertunorderedlist");
                
                break;
                
            case "htmlsource":
                this.addButton(this.theList.id + "ButtonHTML", "widgButtonHTML", "HTML Source", "html");
                
                break;
                
            case "jobTitle":
                this.addButton(this.theList.id + "ButtonJobTitle", "widgButtonJobTitle", "Job Title", "jobTitle");
                
                break;
                
            case "candFirstName":
                this.addButton(this.theList.id + "ButtonCandFirstName", "widgButtonCandFirstName", "Candidate First Name", "candFirstName");
                
                break;
                
            case "userFirstName":
                this.addButton(this.theList.id + "ButtonUserFirstName", "widgButtonUserFirstName", "User First Name", "userFirstName");
                
                break;
                
            case "resumeSource":
                this.addButton(this.theList.id + "ButtonResumeSource", "widgButtonResumeSource", "Resume Source", "resumeSource");
                
                break;
            
            case "candLastName":
                this.addButton(this.theList.id + "ButtonCandLastName", "widgButtonCandLastName", "Candidate Last Name", "candLastName");
                
                break;
                
            case "userLastName":
                this.addButton(this.theList.id + "ButtonUserLastName", "widgButtonUserLastName", "User Last Name", "userLastName");
                
                break;
        }
    }

    return true;
}

// Add button to toolbar
widgToolbar.prototype.addButton = function(theID, theClass, theLabel, theAction)
{
    var menuItem = document.createElement("li");
    var theLink = document.createElement("a");
    var theSpan = document.createElement("span");
    var theText = document.createTextNode(theLabel);
    
    menuItem.id = theID;
    menuItem.className = "widgEditButton";

    theLink.href = "#";
    theLink.title = theLabel;
    theLink.className = theClass;

    DOM.addEventListener(theLink, 'click',
        function(obj, action)
        {
            return function(event)
            {
                obj.widgToolbarAction(action);
                DOM.preventDefault(event);
            }
        }(this, theAction)
    );
    theLink.onmouseover = function() { window.status = "" };

    theSpan.appendChild(theText);
    theLink.appendChild(theSpan);
    menuItem.appendChild(theLink);
    this.theList.appendChild(menuItem);

    return true;
}

// Change the status of the selected toolbar item
widgToolbar.prototype.setState = function(theState, theStatus)
{
    if (theState != "SelectBlock") {
        var theButton = DOM.get(this.theList.id + "Button" + theState);
        if (theButton != null) {
            if (theStatus == "on") {
                DOM.addClass(theButton, "on");
            } else {
                DOM.removeClass(theButton, "on");
            }
        }
    } else {
        var theSelect = DOM.get(this.theList.id + "SelectBlock");
        if (theSelect != null) {
            theSelect.value = "";
            theSelect.value = theStatus;
        }
    }
    return true;
}


widgToolbar.prototype.widgToolbarAction =  function(action)
{
    // Action taken when toolbar item activated
    switch (action) {
        // NOTE: We need to make a function to build these buttons, I'm not doing it yet because I think we will strip down
        
        case "html":
            alert('Your HTML code is:\n\n"' + this.widgEditorObject.get() + '"') ; return false;
            
            break;

        case "html":
            alert('Your HTML code is:\n\n' + this.widgEditorObject.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML); return false;
            
            break;
                
            
        case "link":
            if (DOM.hasClass(DOM.get(this.theList.id + "ButtonLink"), "on")) {
                this.widgEditorObject.theIframe.contentWindow.document.execCommand("Unlink", false, null);
                this.widgEditorObject.theToolbar.setState("Link", "off");
            } else {
                if (this.widgEditorObject.theIframe.contentWindow.document.selection) {
                    theSelection = this.widgEditorObject.theIframe.contentWindow.document.selection.createRange().text;
                    if (theSelection == "") {
                        alert("Please select the text you wish to hyperlink.");
                        break;
                    }
                } else {
                    theSelection = this.widgEditorObject.theIframe.contentWindow.getSelection();
                    if (theSelection == "") {
                        alert("Please select the text you wish to hyperlink.");
                        break;
                    }
                }
                var theURL = prompt("Enter the URL for this.widgEditorObject link:", "http://");
                if (theURL != null) {            
                    this.widgEditorObject.theIframe.contentWindow.document.execCommand("CreateLink", false, theURL);
                    this.widgEditorObject.theToolbar.setState("Link", "on");
                }
            }
            break;
            

        default:
            var doc = document.getElementById(this.widgEditorObject.iframeId).contentWindow.document;
            doc.execCommand(action, false, null);
            var theAction = action.replace(/^./, function(match){return match.toUpperCase();});
            
            // Turn off ordered toolbar item if unordered toolbar item was activated    
            if (action == "insertunorderedlist")
            {
                theAction = "Unordered";
                this.widgEditorObject.theToolbar.setState("Ordered", "off");
            }
            if (DOM.isIE) {
                // If toolbar item was turned on
                if (doc.queryCommandState(action, false, null))
                {
                    this.widgEditorObject.theToolbar.setState(theAction, "on");
                }
                else
                {
                    this.widgEditorObject.theToolbar.setState(theAction, "off");
                }
            }
            
    }
    
    this.widgEditorObject.theIframe.contentWindow.focus();
        
    return false;
}

// Check the nesting of the current cursor position/selection
function widgToolbarCheckState(theWidgEditor, resubmit)
{
    if (!resubmit) {
        // Allow browser to update selection before using the selection
        setTimeout(function(){widgToolbarCheckState(theWidgEditor, true); return true;}, 500);
    }
    
    var theSelection = null;
    var theRange = null;
    var theParentNode = null;
    var theLevel = 0;
    var style;
    var boldSet = false;
    var italicsSet = false;
    
    // Turn off all the buttons
    var menuListItems = theWidgEditor.theToolbar.theList.childNodes;
    for (var i = 0; i < menuListItems.length; i++) {
        DOM.removeClass(menuListItems[i], "on");
    }
    // IE selections
    if (theWidgEditor.theIframe.contentWindow.document.selection) {
        theSelection = theWidgEditor.theIframe.contentWindow.document.selection;
        theRange = theSelection.createRange();
        try {
            theParentNode = theRange.parentElement();
        } catch (e) {
            return false;
        }
    } else { // Mozilla selections
        try {
            theSelection = theWidgEditor.theIframe.contentWindow.getSelection();
        } catch (e) {
            return false;
        }
        try {
            theRange = theSelection.getRangeAt(0);
        } catch (e) {
            return false;
        }
        theParentNode = theRange.commonAncestorContainer;
    }
    
    while (theParentNode.nodeType == 3) {
        theParentNode = theParentNode.parentNode;
    }
    
    while (theParentNode.nodeName.toLowerCase() != "body") {
        switch (theParentNode.nodeName.toLowerCase()) {
            case "a":
                theWidgEditor.theToolbar.setState("Link", "on");
                break;
                
            case "em":
                theWidgEditor.theToolbar.setState("Italic", "on");
                break;
                
            case "li":
                break;
                
            case "ol":
                theWidgEditor.theToolbar.setState("Ordered", "on");
                theWidgEditor.theToolbar.setState("Unordered", "off");
                break;
                
            case "span":
            case "div":
                if (theParentNode.getAttribute("style")) {
                    style = theParentNode.getAttribute("style");
                    if (!boldSet) {
                        if (/font-weight: bold/.test(style)) {
                            theWidgEditor.theToolbar.setState("Bold", "on");
                            boldSet = true;
                        }
                        if (/font-weight: normal/.test(style)) {
                            theWidgEditor.theToolbar.setState("Bold", "off");
                            boldSet = true;
                        }
                    }
                    if (!italicsSet) {
                        if (/font-style: italic/.test(style)) {
                            theWidgEditor.theToolbar.setState("Italic", "on");
                            italicsSet = true;
                        }
                    }
                }
                break;
            
            case "strong":
                theWidgEditor.theToolbar.setState("Bold", "on");
                break;
            
            case "ul":
                theWidgEditor.theToolbar.setState("Unordered", "on");
                theWidgEditor.theToolbar.setState("Ordered", "off");
                break;
            
            default:
                theWidgEditor.theToolbar.setState("SelectBlock", "<" + theParentNode.nodeName.toLowerCase() + ">");
                break;
        }
        
        theParentNode = theParentNode.parentNode;
        theLevel++;
    }
    return true;
}



