JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6.5
[ckeditor.git] / _source / core / dom / range.js
index c8312b7..1aeac00 100644 (file)
@@ -347,50 +347,38 @@ CKEDITOR.dom.range = function( document )
 \r
        // Creates the appropriate node evaluator for the dom walker used inside\r
        // check(Start|End)OfBlock.\r
-       function getCheckStartEndBlockEvalFunction( isStart )\r
+       function getCheckStartEndBlockEvalFunction()\r
        {\r
                var skipBogus = false,\r
+                       whitespaces = CKEDITOR.dom.walker.whitespaces(),\r
                        bookmarkEvaluator = CKEDITOR.dom.walker.bookmark( true ),\r
-                       nbspRegExp = /^[\t\r\n ]*(?: |\xa0)$/;\r
+                       isBogus = CKEDITOR.dom.walker.bogus();\r
 \r
                return function( node )\r
                {\r
-                       // First ignore bookmark nodes.\r
-                       if ( bookmarkEvaluator( node ) )\r
+                       // First skip empty nodes.\r
+                       if ( bookmarkEvaluator( node ) || whitespaces( node ) )\r
                                return true;\r
 \r
-                       if ( node.type == CKEDITOR.NODE_TEXT )\r
+                       // Skip the bogus node at the end of block.\r
+                       if ( isBogus( node ) &&\r
+                                !skipBogus )\r
                        {\r
-                               // Skip the block filler NBSP.\r
-                               if ( CKEDITOR.env.ie &&\r
-                                        nbspRegExp.test( node.getText() ) &&\r
-                                        !skipBogus &&\r
-                                        !( isStart && node.getNext() ) )\r
-                               {\r
-                                       skipBogus = true;\r
-                               }\r
-                               // If there's any visible text, then we're not at the start.\r
-                               else if ( node.hasAscendant( 'pre' ) || CKEDITOR.tools.trim( node.getText() ).length )\r
-                                       return false;\r
-                       }\r
-                       else if ( node.type == CKEDITOR.NODE_ELEMENT )\r
-                       {\r
-                               // If there are non-empty inline elements (e.g. <img />), then we're not\r
-                               // at the start.\r
-                               if ( !inlineChildReqElements[ node.getName() ] )\r
-                               {\r
-                                       // Skip the padding block br.\r
-                                       if ( !CKEDITOR.env.ie &&\r
-                                                node.is( 'br' ) &&\r
-                                                !skipBogus &&\r
-                                                !( isStart && node.getNext() ) )\r
-                                       {\r
-                                               skipBogus = true;\r
-                                       }\r
-                                       else\r
-                                               return false;\r
-                               }\r
+                               skipBogus = true;\r
+                               return true;\r
                        }\r
+\r
+                       // If there's any visible text, then we're not at the start.\r
+                       if ( node.type == CKEDITOR.NODE_TEXT &&\r
+                                        ( node.hasAscendant( 'pre' ) ||\r
+                                                CKEDITOR.tools.trim( node.getText() ).length ) )\r
+                               return false;\r
+\r
+                       // If there are non-empty inline elements (e.g. <img />), then we're not\r
+                       // at the start.\r
+                       if ( node.type == CKEDITOR.NODE_ELEMENT && !inlineChildReqElements[ node.getName() ] )\r
+                               return false;\r
+\r
                        return true;\r
                };\r
        }\r
@@ -401,21 +389,28 @@ CKEDITOR.dom.range = function( document )
        // text node and non-empty elements unless it's being bookmark text.\r
        function elementBoundaryEval( checkStart )\r
        {\r
+               var whitespaces = CKEDITOR.dom.walker.whitespaces(),\r
+                       bookmark = CKEDITOR.dom.walker.bookmark( 1 );\r
+\r
                return function( node )\r
                {\r
+                       // First skip empty nodes.\r
+                       if ( bookmark( node ) || whitespaces( node ) )\r
+                               return true;\r
+\r
                        // Tolerant bogus br when checking at the end of block.\r
                        // Reject any text node unless it's being bookmark\r
                        // OR it's spaces.\r
                        // Reject any element unless it's being invisible empty. (#3883)\r
                        return !checkStart && isBogus( node ) ||\r
-                                       ( node.type == CKEDITOR.NODE_TEXT ?\r
-                                          !CKEDITOR.tools.trim( node.getText() ) || !!node.getParent().data( 'cke-bookmark' )\r
-                                          : node.getName() in CKEDITOR.dtd.$removeEmpty );\r
+                                                node.type == CKEDITOR.NODE_ELEMENT &&\r
+                                                node.getName() in CKEDITOR.dtd.$removeEmpty;\r
                };\r
        }\r
 \r
        var whitespaceEval = new CKEDITOR.dom.walker.whitespaces(),\r
-               bookmarkEval = new CKEDITOR.dom.walker.bookmark();\r
+               bookmarkEval = new CKEDITOR.dom.walker.bookmark(),\r
+               nbspRegExp = /^[\t\r\n ]*(?:&nbsp;|\xa0)$/;\r
 \r
        function nonWhitespaceOrBookmarkEval( node )\r
        {\r
@@ -1834,13 +1829,13 @@ CKEDITOR.dom.range = function( document )
                        var startContainer = this.startContainer,\r
                                startOffset = this.startOffset;\r
 \r
-                       // If the starting node is a text node, and non-empty before the offset,\r
-                       // then we're surely not at the start of block.\r
-                       if ( startOffset && startContainer.type == CKEDITOR.NODE_TEXT )\r
+                       // [IE] Special handling for range start in text with a leading NBSP,\r
+                       // we it to be isolated, for bogus check.\r
+                       if ( CKEDITOR.env.ie && startOffset && startContainer.type == CKEDITOR.NODE_TEXT )\r
                        {\r
                                var textBefore = CKEDITOR.tools.ltrim( startContainer.substring( 0, startOffset ) );\r
-                               if ( textBefore.length )\r
-                                       return false;\r
+                               if ( nbspRegExp.test( textBefore ) )\r
+                                       this.trim( 0, 1 );\r
                        }\r
 \r
                        // We need to grab the block element holding the start boundary, so\r
@@ -1853,7 +1848,7 @@ CKEDITOR.dom.range = function( document )
                        walkerRange.setStartAt( path.block || path.blockLimit, CKEDITOR.POSITION_AFTER_START );\r
 \r
                        var walker = new CKEDITOR.dom.walker( walkerRange );\r
-                       walker.evaluator = getCheckStartEndBlockEvalFunction( true );\r
+                       walker.evaluator = getCheckStartEndBlockEvalFunction();\r
 \r
                        return walker.checkBackward();\r
                },\r
@@ -1863,13 +1858,13 @@ CKEDITOR.dom.range = function( document )
                        var endContainer = this.endContainer,\r
                                endOffset = this.endOffset;\r
 \r
-                       // If the ending node is a text node, and non-empty after the offset,\r
-                       // then we're surely not at the end of block.\r
-                       if ( endContainer.type == CKEDITOR.NODE_TEXT )\r
+                       // [IE] Special handling for range end in text with a following NBSP,\r
+                       // we it to be isolated, for bogus check.\r
+                       if ( CKEDITOR.env.ie && endContainer.type == CKEDITOR.NODE_TEXT )\r
                        {\r
                                var textAfter = CKEDITOR.tools.rtrim( endContainer.substring( endOffset ) );\r
-                               if ( textAfter.length )\r
-                                       return false;\r
+                               if ( nbspRegExp.test( textAfter ) )\r
+                                       this.trim( 1, 0 );\r
                        }\r
 \r
                        // We need to grab the block element holding the start boundary, so\r
@@ -1882,15 +1877,53 @@ CKEDITOR.dom.range = function( document )
                        walkerRange.setEndAt( path.block || path.blockLimit, CKEDITOR.POSITION_BEFORE_END );\r
 \r
                        var walker = new CKEDITOR.dom.walker( walkerRange );\r
-                       walker.evaluator = getCheckStartEndBlockEvalFunction( false );\r
+                       walker.evaluator = getCheckStartEndBlockEvalFunction();\r
 \r
                        return walker.checkForward();\r
                },\r
 \r
                /**\r
-                * Check if elements at which the range boundaries anchor are read-only,\r
-                * with respect to "contenteditable" attribute.\r
+                * Traverse with {@link CKEDITOR.dom.walker} to retrieve the previous element before the range start.\r
+                * @param {Function} evaluator Function used as the walker's evaluator.\r
+                * @param {Function} [guard] Function used as the walker's guard.\r
+                * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,\r
+                * default to the root editable if not defined.\r
+                *\r
+                * @return {CKEDITOR.dom.element|null} The returned node from the traversal.\r
+                */\r
+               getPreviousNode : function( evaluator, guard, boundary ) {\r
+\r
+                       var walkerRange = this.clone();\r
+                       walkerRange.collapse( 1 );\r
+                       walkerRange.setStartAt( boundary || this.document.getBody(), CKEDITOR.POSITION_AFTER_START );\r
+\r
+                       var walker = new CKEDITOR.dom.walker( walkerRange );\r
+                       walker.evaluator = evaluator;\r
+                       walker.guard = guard;\r
+                       return walker.previous();\r
+               },\r
+\r
+               /**\r
+                * Traverse with {@link CKEDITOR.dom.walker} to retrieve the next element before the range start.\r
+                * @param {Function} evaluator Function used as the walker's evaluator.\r
+                * @param {Function} [guard] Function used as the walker's guard.\r
+                * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,\r
+                * default to the root editable if not defined.\r
+                *\r
+                * @return {CKEDITOR.dom.element|null} The returned node from the traversal.\r
                 */\r
+               getNextNode: function( evaluator, guard, boundary )\r
+               {\r
+                       var walkerRange = this.clone();\r
+                       walkerRange.collapse();\r
+                       walkerRange.setEndAt( boundary || this.document.getBody(), CKEDITOR.POSITION_BEFORE_END );\r
+\r
+                       var walker = new CKEDITOR.dom.walker( walkerRange );\r
+                       walker.evaluator = evaluator;\r
+                       walker.guard = guard;\r
+                       return walker.next();\r
+               },\r
+\r
                checkReadOnly : ( function()\r
                {\r
                        function checkNodesEditable( node, anotherEnd )\r
@@ -1939,8 +1972,6 @@ CKEDITOR.dom.range = function( document )
                 */\r
                moveToElementEditablePosition : function( el, isMoveToEnd )\r
                {\r
-                       var nbspRegExp = /^[\t\r\n ]*(?:&nbsp;|\xa0)$/;\r
-\r
                        function nextDFS( node, childOnly )\r
                        {\r
                                var next;\r