/*
 * $Id: faba5.editor-1.0.js 2695 2011-09-02 13:22:37Z markus.tripp@fabasoft.com $
 * 
 * Copyright © Fabasoft R&D GmbH, A-4020 Linz, 1995-2011.
 * 
 * All rights reserved. All hardware and software names used are registered trade names and/or registered trademarks of  
 * the respective manufacturers.
 * 
 * The user of this computer program acknowledges that the above copyright notice, which constitutes the Universal 
 * Copyright Convention, will be attached at the position in the function of the computer program which the author has 
 * deemed to sufficiently express the reservation of copyright. It is prohibited for customers, users and/or third  
 * parties to remove, modify or move this copyright notice.
 * 
 * This computer program is protected by copyright law and international treaties. Unauthorized reproduction or 
 * redistribution of this program, or any portion of it, may result in severe civil and criminal penalties.
 * 
 * The use of this software requires a valid license agreement for this software. This license agreement specifies 
 * especially permitted use through the licensing model. A license agreement must already exist prior to installing the 
 * software as the installation process of this software does not include the conclusion of a license agreement.
 */

(function() {
    $.widget('faba5.editor', {
        _init : function() {
            var self = this;
            var editorElement = this.element;
            
            editorElement.attr('contentEditable','true');
            
            if (!$.browser.msie) {
                this._executeCommand('styleWithCSS', false, 'false');
            }
            
            editorElement.mousedown(this._updateEditor);
            editorElement.keypress(this._updateEditor);
            editorElement.keydown(this._updateEditor);
            editorElement.blur(this._updateEditor);
            
            editorElement.blur(function() {
                self.saveSelection();
            });

            var pasteWrapEvent = 'paste';
            if ($.browser.msie) {
                pasteWrapEvent = 'beforepaste';
            }

            editorElement.bind(pasteWrapEvent, function(){
                editorElement.editor('wrapSelection');
            });
            
            // Disable table editing in FF
            try{document.execCommand('enableInlineTableEditing',false,false);} catch (ex){}
            // Disable image resizing in FF
            try{this._executeCommand('enableObjectResizing', false, false);} catch (ex){}
            
            editorElement.find('img').attr('contentEditable','false').attr('unselectable','on');
        },
        
        value : function() {
            var html = this.element.html();
            html = this._clean(html);
            
            return html;
        },
        
        _clean : function(content) {
            var cleaned = $('<div/>').append(content).appendTo('body');
            
            cleaned.find('strong').each(function() {
                 var element = $('<b/>').append($(this).html());
                $(this).replaceWith(element);
            });
            
            cleaned.find('span').each(function() {
                if ($(this).css('font-weight') == '700') {
                    var element = $('<b/>').append($(this).html());
                    $(this).replaceWith(element);   
                }

                if ($(this).css('font-style') == 'italic'){
                    var element = $('<i/>').append($(this).html());
                    $(this).replaceWith(element);   
                }

                if ($(this).css('text-decoration') == 'underline'){
                    var element = $('<u/>').append($(this).html());
                    $(this).replaceWith(element);   
                }
            });
            
            cleaned.find('em').each(function() {
                var element = $('<i/>').append($(this).html());
                $(this).replaceWith(element);
            });
            
            cleaned.find('p').each(function() {
                if ($(this).attr('align') == 'center'){
                    var element = $('<p/>').css('text-align', 'center').append($(this).html());
                    $(this).replaceWith(element);   
                }

                if ($(this).attr('align') == 'left'){
                    var element = $('<p/>').css('text-align', 'left').append($(this).html());
                    $(this).replaceWith(element);   
                }

                if ($(this).attr('align') == 'right'){
                    var element = $('<p/>').css('text-align', 'right').append($(this).html());
                    $(this).replaceWith(element);   
                }

                if ($(this).css('margin-left') == '40px'){
                    var element = $('<blockquote/>').append($(this).html());
                    $(this).replaceWith(element);   
                }
            });
            
            cleaned.find('h1 , h2 , h3').each(function() {
              if ($(this).attr('align') == 'center') {
                    $(this).removeAttr('align');
                    $(this).css('text-align', 'center');
              }
              if ($(this).attr('align') == 'left') {
                  $(this).removeAttr('align');
                  $(this).css('text-align', 'left');
            }
              if ($(this).attr('align') == 'right') {
                  $(this).removeAttr('align');
                  $(this).css('text-align', 'right');
              }
            });
            
            cleaned.find('p:empty, div:empty, span:empty').remove();
            
            cleaned.find('blockquote').each(function() {
                 $(this).removeAttr('style');
                 $(this).removeAttr('class');
                 $(this).removeAttr('dir');   
            });   

            cleaned.find('img').removeAttr('contentEditable').removeAttr('unselectable');
            
            var result = cleaned.html();
            cleaned.remove();
            
            return result.trim();
        },

        overwrite : function(node){
            this._overwriteWithNode(node);
        },
        
        selection : function() {
            return this._getSelection();
        },
        
        selectionRange : function() {
            return this._getSelectionRange();
        },

        wrapSelection : function() {
            var originalRange = this._getSelectionRange();
            var content;
            if (originalRange.extractContents) {
                var marker = document.createElement('div');
                marker.setAttribute('class','paste-marker');
                content = originalRange.extractContents();
                if(!content || content.length < 1) {
                    content = ' ';
                }
                marker.appendChild(content);
                originalRange.insertNode(marker);
                originalRange.selectNodeContents(marker);
            } else {
                content = originalRange.htmlText;
                if (!content || content.length < 1) {
                    content = '&nbsp;';
                }
                originalRange.pasteHTML('<div class="paste-marker">' + content + '</div>');
                originalRange.select();
                var range = document.body.createTextRange();
                range.moveToElementText( $('div.paste-marker').get(0));
                range.select();
            }
            
        },

        removeFormat : function(element) {
            var parent;
            if (element) {
                parent = element;
            } else {
                this._executeCommand('removeformat');
                parent = $(this._getSelectionAncestorContainer());
            }
            
            var linebreakElements = ['li','br','p','div','ul','ol','table','tr','td','th','a','img','u','i','b','h1','h2','h3'];
            var html = parent.html();
            if (!html || html == null) {
                html = '';
            }
            
            html = html.replace(/<!(?:--[\s\S]*?--\s*)?>\s*/g,'');
            html = this._stripHTML(html,linebreakElements);
            parent.html(html);
            parent.find('*').each(function(index, elem){
                for(var i=0;i< this.attributes.length;i++) {
                    var attrName = elem.attributes.item(i).name;
                    var tagName = this.tagName.toLowerCase();
                    
                    switch (tagName) {
                        case 'img':
                            if(attrName === 'src') {
                                break;
                            }
                        case 'a':
                            if (attrName === 'href' || attrName === 'target') {
                                break;
                            }
                        default:
                            $(elem).removeAttr(attrName);
                    }
                }
            });
        },
        
        formatblock : function(blockElement) {
            if ($.browser.msie) {
                this._executeCommand('formatblock', false, '<' + blockElement + '>');
            } else {
                this._executeCommand('formatblock', false, blockElement);
            }
        },

        isBoldPossible : function() {
            this._queryCommandEnabled('bold');
        },
        bold : function() {
            this._executeCommand('bold');
        },
        isItalicPossible : function() {
            this._queryCommandEnabled('italic');
        },
        italic : function() {
            this._executeCommand('italic');
        },
        isUnderlinePossible : function() {
            this._queryCommandEnabled('underline');
        },
        underline : function() {
            this._executeCommand('underline');
        },
        isSubscriptPossible : function() {
            this._queryCommandEnabled('subscript');
        },
        subscript : function() {
            this._executeCommand('subscript');
        },
        isSuperscriptPossible : function() {
            this._queryCommandEnabled('superscript');
        },
        superscript : function() {
            this._executeCommand('superscript');
        },
        isStrikethroughPossible : function() {
            this._queryCommandEnabled('strikethrough');
        },
        strikethrough : function() {
            this._executeCommand('strikethrough');
        },

        isCenterPossible : function() {
            this._queryCommandEnabled('justifycenter');
        },
        center : function() {
            this._executeCommand('justifycenter');
        },
        isFullPossible : function() {
            this._queryCommandEnabled('justifyfull');
        },
        full : function() {
            this._executeCommand('justifyfull');
        },
        isLeftPossible : function() {
            this._queryCommandEnabled('justifyleft');
        },
        left : function() {
            this._executeCommand('justifyleft');
        },
        isRightPossible : function() {
            this._queryCommandEnabled('justifyright');
        },
        right : function() {
            this._executeCommand('justifyRight');
        },

        isInsertHorizontalRulePossible : function() {
            this._queryCommandEnabled('inserthorizontalrule');
        },
        insertHorizontalRule : function() {
            this._executeCommand('inserthorizontalrule');
        },
        isInsertParagraphPossible : function() {
            this._queryCommandEnabled('insertparagraph');
        },
        insertParagraph : function() {
            this._executeCommand('insertparagraph');
        },
        istOrderedPossible : function() {
            this._queryCommandEnabled('insertorderedlist');
        },
        ordered : function() {
            this._executeCommand('insertorderedlist');
        },
        isUnorderedPossible : function() {
            this._queryCommandEnabled('insertunorderedlist');
        },
        unordered : function() {
            this._executeCommand('insertunorderedlist');
        },

        isRedoPossible : function() {
            this._queryCommandEnabled('redo');
        },
        redo : function() {
            this._executeCommand('redo');
        },
        isUndoPossible : function() {
            this._queryCommandEnabled('undo');
        },
        undo : function() {
            this._executeCommand('undo');
        },
        isUnlinkPossible : function() {
            this._queryCommandEnabled('unlink');
        },
        unlink : function() {
            this._executeCommand('justifyRight');
        },

        isIndentPossible : function() {
            this._queryCommandEnabled('indent');
        },
        indent : function() {
            this._executeCommand('indent');
        },
        isOutdentPossible : function() {
            this._queryCommandEnabled('outdent');
        },
        outdent : function() {
            this._executeCommand('outdent');
        },

        isCopyPossible : function() {
            this._queryCommandEnabled('copy');
        },
        copy : function() {
            this._executeCommand('copy');
        },
        isCutPossible : function() {
            this._queryCommandEnabled('cut');
        },
        cut : function() {
            this._executeCommand('cut');
        },
        isRemovePossible : function() {
            this._queryCommandEnabled('delete');
        },
        remove : function() {
            this._executeCommand('delete');
        },
        isPastePossible : function() {
            this._queryCommandEnabled('paste');
        },
        paste : function() {
            this._executeCommand('paste');
        },

        _queryCommandEnabled : function(command) {
            return this._getOwnerDocument().queryCommandEnabled(command);
        },

        _executeCommand : function(command, showDefaultUI, value) {
            this._getOwnerDocument().execCommand(command, showDefaultUI, value);
            this._triggerStateChange();
        },

        _getOwnerWindow : function() {
            return window;
        },
        _getOwnerDocument : function() {
            return this.element.get(0).ownerDocument;
        },

        _triggerStateChange : function() {

        },

        _getContaining : function(filter){
            if (window.getSelection) {
                return this._w3_getContaining(filter);
            } else {
                return this._ie_getContaining(filter);
            }
        },
        
        _overwriteWithNode : function(node){
            if (window.getSelection) {
                this._w3_overwriteWithNode(node);
            } else {
                this._ie_overwriteWithNode(node);
            }
        },
        
        _createElementFilter : function(tagName) {
            return function(elem){
                return elem.tagName==tagName;
            };
        },

        _getAncestor : function(elem, filter) {
            while (elem.tagName!='BODY') {
                if (filter(elem)) return elem;
                elem = elem.parentNode;
            }
            return null;
        },

        _includes : function(elem1, elem2) {
            if (elem2==elem1) return true;
            while (elem2.parentNode && elem2.parentNode) {
                if (elem2==elem1) return true;
                elem2 = elem2.parentNode;
            }
            return false;
        },

        _ie_getContaining : function(filter) {
            var editWindow = this._getOwnerWindow();
            var selection = editWindow.document.selection;
            var range;
            var elem;
            if (selection.type=='Control') {
                // control selection
                range = selection.createRange();
                if (range.length==1) {
                    elem = range.item(0);
                } else {
                    // multiple control selection
                    return null;
                }
            } else {
                range = selection.createRange();
                elem = range.parentElement();
            }
            return getAncestor(elem, filter);
        },

        _ie_overwriteWithNode:function(node) {
            var editWindow = this._getOwnerWindow();
            var rng = editWindow.document.selection.createRange();
            var marker = this._writeMarkerNode(editWindow, rng);
            marker.appendChild(node);
            marker.removeNode(); // removes node but not children
        },

        _writeMarkerNode:function(editWindow, rng) {
            var id = editWindow.document.uniqueID;
            var html = '<span id="' + id + '"></span>';
            rng.pasteHTML(html);
            var node = editWindow.document.getElementById(id);
            return node;
        },

        _w3_overwriteWithNode:function(node) {
            var editWindow = this._getOwnerWindow();
            var sel = editWindow.getSelection();
            var rng = sel.getRangeAt(0);
            
            if (sel.anchorNode.nodeName.toLowerCase() == 'a') {
                $(sel.anchorNode).remove();
            }
            
            rng.deleteContents();
            rng.insertNode(node);
            rng.setStartAfter(node);
            editWindow.getSelection().removeAllRanges();
            editWindow.getSelection().addRange(rng);
            
            if (this.element.focusMozilla) {
                this.element.focusMozilla();
            }
        },

        _w3_getContaining:function(filter) {
            var editWindow = this._getOwnerWindow();
            var range = editWindow.getSelection().getRangeAt(0);
            var container = range.commonAncestorContainer;
            return this._getAncestor(container, filter);
        },

        _getSelectionRange: function() {
            var win = this._getOwnerWindow();
            var range;
            if (win.getSelection) {
                try {
                    range = win.getSelection().getRangeAt(0);
                } catch (e) {
                    range = document.createRange();
                }
                
                if($.browser.opera) {
                    var s = range.startContainer;
                    if(s.nodeType === Node.TEXT_NODE) {
                        range.setStartBefore(s.parentNode);
                    }
                }
            } else {
                range = win.document.selection.createRange();
                range.select(); //Restore selection, if IE lost focus.
            }

            return range;
        },

        getRawSelection : function() {
            if (window.getSelection) {
                return window.getSelection();
            }
            
            return document.getSelection();
        },

        _getSelection: function() {
            var val = '';
            if (window.getSelection) {
                val = this._getSelectionRange().toString();
            } else if (document.selection) {
                val = this._getSelectionRange().text;
            }
            return val;
        },
        
        _getSelectionAncestorContainer : function() {
            if (this._getSelectionRange().commonAncestorContainer) {
                return this._getSelectionRange().commonAncestorContainer;
            } else if (this._getSelectionRange().parentElement) {
                return this._getSelectionRange().parentElement();
            } else {
                alert('Ancestor container not supported');
                return null;
            }
        },
        
        _stripHTML : function(html, ex) {
            if(!html || !html.length) return html;
            var exclude = ex;
            function f(a, b, c){
                if(typeof exclude != 'undefined'){
                    for(var i = 0; i < exclude.length; i++){
                        if(b == exclude[i] || b == '/' + exclude[i]) return a;
                    }
                }
                return '';
            }
            return html.replace(/<[/]?([^> ]+)[^>]*>/g, f);
        },

        _updateEditor : function() {
            var marker = $('div.paste-marker', this.element);
            
            if (marker.length > 0) {
                marker.trigger('beforeRemovePasteMarker');
                marker.replaceWith(marker.html());
                marker.trigger('afterRemovePasteMarker');
            }
        },
        
        saveSelection : function(node) {
            var range = this._getSelectionRange();
            if (node) {
                range = document.createRange();
                range.selectNode(node);
            } 
            
            if (range.cloneRange) {
                this._savedRange = range.cloneRange();
            } else if (range.duplicate) {
                this._savedRange = range.duplicate();
            }
        },
        
        restoreSelection : function() {
            if (this._savedRange) {
                this.element.focus();
                var win = this._getOwnerWindow();
                if (win.getSelection) {
                    win.getSelection().removeAllRanges();
                    win.getSelection().addRange(this._savedRange);
                    this.element.focus();
                } else {
                    this._savedRange.select();
                }
            }
        }
    });

    $.extend($.faba5.editor, {
        getter: 'selection',
        version: '1.8.1',
        author: 'Fabasoft',
        eventPrefix: 'editor',
        defaults: { }
    });

})();

