},\r
\r
/**\r
- * Move the range out of bookmark nodes if they're been the container.\r
+ * Move the range out of bookmark nodes if they'd been the container.\r
*/\r
optimizeBookmark: function()\r
{\r
\r
var walker = new CKEDITOR.dom.walker( walkerRange ),\r
blockBoundary, // The node on which the enlarging should stop.\r
- tailBr, //\r
- defaultGuard = CKEDITOR.dom.walker.blockBoundary(\r
+ tailBr, // In case BR as block boundary.\r
+ notBlockBoundary = CKEDITOR.dom.walker.blockBoundary(\r
( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) ? { br : 1 } : null ),\r
// Record the encountered 'blockBoundary' for later use.\r
boundaryGuard = function( node )\r
{\r
- var retval = defaultGuard( node );\r
+ var retval = notBlockBoundary( node );\r
if ( !retval )\r
blockBoundary = node;\r
return retval;\r
// It's the body which stop the enlarging if no block boundary found.\r
blockBoundary = blockBoundary || body;\r
\r
- // Start the range at different position by comparing\r
- // the document position of it with 'enlargeable' node.\r
+ // Start the range either after the end of found block (<p>...</p>[text)\r
+ // or at the start of block (<p>[text...), by comparing the document position\r
+ // with 'enlargeable' node.\r
this.setStartAt(\r
blockBoundary,\r
!blockBoundary.is( 'br' ) &&\r
// It's the body which stop the enlarging if no block boundary found.\r
blockBoundary = blockBoundary || body;\r
\r
- // Start the range at different position by comparing\r
- // the document position of it with 'enlargeable' node.\r
+ // Close the range either before the found block start (text]<p>...</p>) or at the block end (...text]</p>)\r
+ // by comparing the document position with 'enlargeable' node.\r
this.setEndAt(\r
blockBoundary,\r
( !enlargeable && this.checkEndOfBlock()\r
\r
/**\r
* Descrease the range to make sure that boundaries\r
- * always anchor beside text nodes or innermost element.\r
+ * always anchor beside text nodes or innermost element.\r
* @param {Number} mode ( CKEDITOR.SHRINK_ELEMENT | CKEDITOR.SHRINK_TEXT ) The shrinking mode.\r
+ * <dl>\r
+ * <dt>CKEDITOR.SHRINK_ELEMENT</dt>\r
+ * <dd>Shrink the range boundaries to the edge of the innermost element.</dd>\r
+ * <dt>CKEDITOR.SHRINK_TEXT</dt>\r
+ * <dd>Shrink the range boudaries to anchor by the side of enclosed text node, range remains if there's no text nodes on boundaries at all.</dd>\r
+ * </dl>\r
+ * @param {Boolean} selectContents Whether result range anchors at the inner OR outer boundary of the node.\r
*/\r
shrink : function( mode, selectContents )\r
{\r
CKEDITOR.POSITION_AFTER_START\r
: CKEDITOR.POSITION_BEFORE_END );\r
\r
- var walker = new CKEDITOR.dom.walker( walkerRange ),\r
- retval = false;\r
+ var walker = new CKEDITOR.dom.walker( walkerRange );\r
walker.evaluator = elementBoundaryEval;\r
return walker[ checkType == CKEDITOR.START ?\r
'checkBackward' : 'checkForward' ]();\r
},\r
+\r
// Calls to this function may produce changes to the DOM. The range may\r
// be updated to reflect such changes.\r
checkStartOfBlock : function()\r
*/\r
getEnclosedNode : function()\r
{\r
- var walkerRange = this.clone(),\r
- walker = new CKEDITOR.dom.walker( walkerRange ),\r
+ var walkerRange = this.clone();\r
+\r
+ // Optimize and analyze the range to avoid DOM destructive nature of walker. (#5780)\r
+ walkerRange.optimize();\r
+ if ( walkerRange.startContainer.type != CKEDITOR.NODE_ELEMENT\r
+ || walkerRange.endContainer.type != CKEDITOR.NODE_ELEMENT )\r
+ return null;\r
+\r
+ var walker = new CKEDITOR.dom.walker( walkerRange ),\r
isNotBookmarks = CKEDITOR.dom.walker.bookmark( true ),\r
isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),\r
evaluator = function( node )\r
\r
/**\r
* Check boundary types.\r
- * @see CKEDITOR.dom.range::checkBoundaryOfElement\r
+ * @see CKEDITOR.dom.range.prototype.checkBoundaryOfElement\r
*/\r
CKEDITOR.START = 1;\r
CKEDITOR.END = 2;\r
CKEDITOR.STARTEND = 3;\r
\r
+/**\r
+ * Shrink range types.\r
+ * @see CKEDITOR.dom.range.prototype.shrink\r
+ */\r
CKEDITOR.SHRINK_ELEMENT = 1;\r
CKEDITOR.SHRINK_TEXT = 2;\r