JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6.3
[ckeditor.git] / _source / core / dom / range.js
index 477197e..30a78c4 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.html or http://ckeditor.com/license\r
 */\r
 \r
@@ -380,16 +380,23 @@ CKEDITOR.dom.range = function( document )
                };\r
        }\r
 \r
+\r
+       var isBogus = CKEDITOR.dom.walker.bogus();\r
        // Evaluator for CKEDITOR.dom.element::checkBoundaryOfElement, reject any\r
        // text node and non-empty elements unless it's being bookmark text.\r
-       function elementBoundaryEval( node )\r
+       function elementBoundaryEval( checkStart )\r
        {\r
-               // Reject any text node unless it's being bookmark\r
-               // OR it's spaces. (#3883)\r
-               return node.type != CKEDITOR.NODE_TEXT\r
-                           && node.getName() in CKEDITOR.dtd.$removeEmpty\r
-                           || !CKEDITOR.tools.trim( node.getText() )\r
-                           || !!node.getParent().data( 'cke-bookmark' );\r
+               return function( node )\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
+               };\r
        }\r
 \r
        var whitespaceEval = new CKEDITOR.dom.walker.whitespaces(),\r
@@ -1014,7 +1021,12 @@ CKEDITOR.dom.range = function( document )
                                                        // whitespaces at the end.\r
                                                        isWhiteSpace = false;\r
 \r
-                                                       if ( sibling.type == CKEDITOR.NODE_TEXT )\r
+                                                       if ( sibling.type == CKEDITOR.NODE_COMMENT )\r
+                                                       {\r
+                                                               sibling = sibling.getPrevious();\r
+                                                               continue;\r
+                                                       }\r
+                                                       else if ( sibling.type == CKEDITOR.NODE_TEXT )\r
                                                        {\r
                                                                siblingText = sibling.getText();\r
 \r
@@ -1044,7 +1056,7 @@ CKEDITOR.dom.range = function( document )
                                                                                        sibling = null;\r
                                                                                else\r
                                                                                {\r
-                                                                                       var allChildren = sibling.$.all || sibling.$.getElementsByTagName( '*' );\r
+                                                                                       var allChildren = sibling.$.getElementsByTagName( '*' );\r
                                                                                        for ( var i = 0, child ; child = allChildren[ i++ ] ; )\r
                                                                                        {\r
                                                                                                if ( !CKEDITOR.dtd.$removeEmpty[ child.nodeName.toLowerCase() ] )\r
@@ -1183,7 +1195,7 @@ CKEDITOR.dom.range = function( document )
 \r
                                                                isWhiteSpace = /^[\s\ufeff]/.test( siblingText );\r
                                                        }\r
-                                                       else\r
+                                                       else if ( sibling.type == CKEDITOR.NODE_ELEMENT )\r
                                                        {\r
                                                                // If this is a visible element.\r
                                                                // We need to check for the bookmark attribute because IE insists on\r
@@ -1204,7 +1216,7 @@ CKEDITOR.dom.range = function( document )
                                                                                        sibling = null;\r
                                                                                else\r
                                                                                {\r
-                                                                                       allChildren = sibling.$.all || sibling.$.getElementsByTagName( '*' );\r
+                                                                                       allChildren = sibling.$.getElementsByTagName( '*' );\r
                                                                                        for ( i = 0 ; child = allChildren[ i++ ] ; )\r
                                                                                        {\r
                                                                                                if ( !CKEDITOR.dtd.$removeEmpty[ child.nodeName.toLowerCase() ] )\r
@@ -1222,6 +1234,8 @@ CKEDITOR.dom.range = function( document )
                                                                                sibling = null;\r
                                                                }\r
                                                        }\r
+                                                       else\r
+                                                               isWhiteSpace = 1;\r
 \r
                                                        if ( isWhiteSpace )\r
                                                        {\r
@@ -1320,6 +1334,22 @@ CKEDITOR.dom.range = function( document )
                                                                CKEDITOR.POSITION_AFTER_START :\r
                                                                CKEDITOR.POSITION_AFTER_END );\r
 \r
+                                       // Avoid enlarging the range further when end boundary spans right after the BR. (#7490)\r
+                                       if ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS )\r
+                                       {\r
+                                               var theRange = this.clone();\r
+                                               walker = new CKEDITOR.dom.walker( theRange );\r
+\r
+                                               var whitespaces = CKEDITOR.dom.walker.whitespaces(),\r
+                                                       bookmark = CKEDITOR.dom.walker.bookmark();\r
+\r
+                                               walker.evaluator = function( node ) { return !whitespaces( node ) && !bookmark( node ); };\r
+                                               var previous = walker.previous();\r
+                                               if ( previous && previous.type == CKEDITOR.NODE_ELEMENT && previous.is( 'br' ) )\r
+                                                       return;\r
+                                       }\r
+\r
+\r
                                        // Enlarging the end boundary.\r
                                        walkerRange = this.clone();\r
                                        walkerRange.collapse();\r
@@ -1777,7 +1807,7 @@ CKEDITOR.dom.range = function( document )
                        // Create the walker, which will check if we have anything useful\r
                        // in the range.\r
                        var walker = new CKEDITOR.dom.walker( walkerRange );\r
-                       walker.evaluator = elementBoundaryEval;\r
+                       walker.evaluator = elementBoundaryEval( checkStart );\r
 \r
                        return walker[ checkStart ? 'checkBackward' : 'checkForward' ]();\r
                },\r
@@ -1904,47 +1934,53 @@ CKEDITOR.dom.range = function( document )
                 */\r
                moveToElementEditablePosition : function( el, isMoveToEnd )\r
                {\r
-                       var isEditable;\r
-\r
-                       // Empty elements are rejected.\r
-                       if ( CKEDITOR.dtd.$empty[ el.getName() ] )\r
-                               return false;\r
-\r
-                       while ( el && el.type == CKEDITOR.NODE_ELEMENT )\r
+                       function nextDFS( node, childOnly )\r
                        {\r
-                               isEditable = el.isEditable();\r
+                               var next;\r
 \r
-                               // If an editable element is found, move inside it.\r
-                               if ( isEditable )\r
-                                       this.moveToPosition( el, isMoveToEnd ?\r
-                                                                CKEDITOR.POSITION_BEFORE_END :\r
-                                                                CKEDITOR.POSITION_AFTER_START );\r
-                               // Stop immediately if we've found a non editable inline element (e.g <img>).\r
-                               else if ( CKEDITOR.dtd.$inline[ el.getName() ] )\r
+                               if ( node.type == CKEDITOR.NODE_ELEMENT\r
+                                               && node.isEditable( false )\r
+                                               && !CKEDITOR.dtd.$nonEditable[ node.getName() ] )\r
                                {\r
-                                       this.moveToPosition( el, isMoveToEnd ?\r
-                                                                CKEDITOR.POSITION_AFTER_END :\r
-                                                                CKEDITOR.POSITION_BEFORE_START );\r
-                                       return true;\r
+                                       next = node[ isMoveToEnd ? 'getLast' : 'getFirst' ]( nonWhitespaceOrBookmarkEval );\r
                                }\r
 \r
-                               // Non-editable non-inline elements are to be bypassed, getting the next one.\r
-                               if ( CKEDITOR.dtd.$empty[ el.getName() ] )\r
-                                       el = el[ isMoveToEnd ? 'getPrevious' : 'getNext' ]( nonWhitespaceOrBookmarkEval );\r
-                               else\r
-                                       el = el[ isMoveToEnd ? 'getLast' : 'getFirst' ]( nonWhitespaceOrBookmarkEval );\r
+                               if ( !childOnly && !next )\r
+                                       next = node[ isMoveToEnd ? 'getPrevious' : 'getNext' ]( nonWhitespaceOrBookmarkEval );\r
 \r
+                               return next;\r
+                       }\r
+\r
+                       var found = 0;\r
+\r
+                       while ( el )\r
+                       {\r
                                // Stop immediately if we've found a text node.\r
-                               if ( el && el.type == CKEDITOR.NODE_TEXT )\r
+                               if ( el.type == CKEDITOR.NODE_TEXT )\r
                                {\r
                                        this.moveToPosition( el, isMoveToEnd ?\r
                                                                 CKEDITOR.POSITION_AFTER_END :\r
                                                                 CKEDITOR.POSITION_BEFORE_START );\r
-                                       return true;\r
+                                       found = 1;\r
+                                       break;\r
+                               }\r
+\r
+                               // If an editable element is found, move inside it, but not stop the searching.\r
+                               if ( el.type == CKEDITOR.NODE_ELEMENT )\r
+                               {\r
+                                       if ( el.isEditable() )\r
+                                       {\r
+                                               this.moveToPosition( el, isMoveToEnd ?\r
+                                                                                                CKEDITOR.POSITION_BEFORE_END :\r
+                                                                                                CKEDITOR.POSITION_AFTER_START );\r
+                                               found = 1;\r
+                                       }\r
                                }\r
+\r
+                               el = nextDFS( el, found );\r
                        }\r
 \r
-                       return isEditable;\r
+                       return !!found;\r
                },\r
 \r
                /**\r