X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=_source%2Fcore%2Fdom%2Frange.js;h=0146f6a6d691f222153f1d44ccf8ea907c3520d1;hb=e371ddf8abcb89013e20e6d0dd746adec344d0e5;hp=127f7aaba39ce553c0961f31b471c82436c47d2f;hpb=e7789c1ad838194d45eeee6ac2eb6e55f5cf35a1;p=ckeditor.git
diff --git a/_source/core/dom/range.js b/_source/core/dom/range.js
index 127f7aa..0146f6a 100644
--- a/_source/core/dom/range.js
+++ b/_source/core/dom/range.js
@@ -397,6 +397,7 @@ CKEDITOR.dom.range = function( document )
var startNode, endNode;
var baseId;
var clone;
+ var collapsed = this.collapsed;
startNode = this.document.createElement( 'span' );
startNode.setAttribute( '_fck_bookmark', 1 );
@@ -413,7 +414,7 @@ CKEDITOR.dom.range = function( document )
}
// If collapsed, the endNode will not be created.
- if ( !this.collapsed )
+ if ( !collapsed )
{
endNode = startNode.clone();
endNode.setHtml( ' ' );
@@ -442,7 +443,8 @@ CKEDITOR.dom.range = function( document )
return {
startNode : serializable ? baseId + 'S' : startNode,
endNode : serializable ? baseId + 'E' : endNode,
- serializable : serializable
+ serializable : serializable,
+ collapsed : collapsed
};
},
@@ -465,6 +467,8 @@ CKEDITOR.dom.range = function( document )
var startOffset = this.startOffset,
endOffset = this.endOffset;
+ var collapsed = this.collapsed;
+
var child, previous;
// If there is no range then get out of here.
@@ -501,7 +505,7 @@ CKEDITOR.dom.range = function( document )
}
// Process the end only if not normalized.
- if ( !this.isCollapsed )
+ if ( !collapsed )
{
// Find out if the start is pointing to a text node that
// will be normalized.
@@ -532,10 +536,11 @@ CKEDITOR.dom.range = function( document )
return {
start : startContainer.getAddress( normalized ),
- end : this.isCollapsed ? null : endContainer.getAddress( normalized ),
+ end : collapsed ? null : endContainer.getAddress( normalized ),
startOffset : startOffset,
endOffset : endOffset,
normalized : normalized,
+ collapsed : collapsed,
is2 : true // It's a createBookmark2 bookmark.
};
},
@@ -697,7 +702,7 @@ CKEDITOR.dom.range = function( document )
},
/**
- * Move the range out of bookmark nodes if they're been the container.
+ * Move the range out of bookmark nodes if they'd been the container.
*/
optimizeBookmark: function()
{
@@ -1166,13 +1171,13 @@ CKEDITOR.dom.range = function( document )
var walker = new CKEDITOR.dom.walker( walkerRange ),
blockBoundary, // The node on which the enlarging should stop.
- tailBr, //
- defaultGuard = CKEDITOR.dom.walker.blockBoundary(
+ tailBr, // In case BR as block boundary.
+ notBlockBoundary = CKEDITOR.dom.walker.blockBoundary(
( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) ? { br : 1 } : null ),
// Record the encountered 'blockBoundary' for later use.
boundaryGuard = function( node )
{
- var retval = defaultGuard( node );
+ var retval = notBlockBoundary( node );
if ( !retval )
blockBoundary = node;
return retval;
@@ -1193,8 +1198,9 @@ CKEDITOR.dom.range = function( document )
// It's the body which stop the enlarging if no block boundary found.
blockBoundary = blockBoundary || body;
- // Start the range at different position by comparing
- // the document position of it with 'enlargeable' node.
+ // Start the range either after the end of found block (
...
[text)
+ // or at the start of block ([text...), by comparing the document position
+ // with 'enlargeable' node.
this.setStartAt(
blockBoundary,
!blockBoundary.is( 'br' ) &&
@@ -1220,8 +1226,8 @@ CKEDITOR.dom.range = function( document )
// It's the body which stop the enlarging if no block boundary found.
blockBoundary = blockBoundary || body;
- // Start the range at different position by comparing
- // the document position of it with 'enlargeable' node.
+ // Close the range either before the found block start (text]
...
) or at the block end (...text])
+ // by comparing the document position with 'enlargeable' node.
this.setEndAt(
blockBoundary,
( !enlargeable && this.checkEndOfBlock()
@@ -1237,10 +1243,17 @@ CKEDITOR.dom.range = function( document )
/**
* Descrease the range to make sure that boundaries
- * always anchor beside text nodes or innermost element.
+ * always anchor beside text nodes or innermost element.
* @param {Number} mode ( CKEDITOR.SHRINK_ELEMENT | CKEDITOR.SHRINK_TEXT ) The shrinking mode.
+ *
+ * - CKEDITOR.SHRINK_ELEMENT
+ * - Shrink the range boundaries to the edge of the innermost element.
+ * - CKEDITOR.SHRINK_TEXT
+ * - 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.
+ *
+ * @param {Boolean} selectContents Whether result range anchors at the inner OR outer boundary of the node.
*/
- shrink : function( mode )
+ shrink : function( mode, selectContents )
{
// Unable to shrink a collapsed range.
if ( !this.collapsed )
@@ -1315,14 +1328,14 @@ CKEDITOR.dom.range = function( document )
if ( moveStart )
{
var textStart = walker[ mode == CKEDITOR.SHRINK_ELEMENT ? 'lastForward' : 'next']();
- textStart && this.setStartBefore( textStart );
+ textStart && this.setStartAt( textStart, selectContents ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_START );
}
if ( moveEnd )
{
walker.reset();
var textEnd = walker[ mode == CKEDITOR.SHRINK_ELEMENT ? 'lastBackward' : 'previous']();
- textEnd && this.setEndAfter( textEnd );
+ textEnd && this.setEndAt( textEnd, selectContents ? CKEDITOR.POSITION_BEFORE_END : CKEDITOR.POSITION_AFTER_END );
}
return !!( moveStart || moveEnd );
@@ -1382,6 +1395,11 @@ CKEDITOR.dom.range = function( document )
// we will not need this check for our use of this class so we can
// ignore it for now.
+ // Fixing invalid range start inside dtd empty elements.
+ if( startNode.type == CKEDITOR.NODE_ELEMENT
+ && CKEDITOR.dtd.$empty[ startNode.getName() ] )
+ startNode = startNode.getParent(), startOffset = startNode.getIndex();
+
this.startContainer = startNode;
this.startOffset = startOffset;
@@ -1408,6 +1426,11 @@ CKEDITOR.dom.range = function( document )
// will not need this check for our use of this class so we can ignore
// it for now.
+ // Fixing invalid range end inside dtd empty elements.
+ if( endNode.type == CKEDITOR.NODE_ELEMENT
+ && CKEDITOR.dtd.$empty[ endNode.getName() ] )
+ endNode = endNode.getParent(), endOffset = endNode.getIndex() + 1;
+
this.endContainer = endNode;
this.endOffset = endOffset;
@@ -1614,26 +1637,36 @@ CKEDITOR.dom.range = function( document )
},
/**
- * Check whether current range is on the inner edge of the specified element.
- * @param {Number} checkType ( CKEDITOR.START | CKEDITOR.END ) The checking side.
+ * Check whether a range boundary is at the inner boundary of a given
+ * element.
* @param {CKEDITOR.dom.element} element The target element to check.
+ * @param {Number} checkType The boundary to check for both the range
+ * and the element. It can be CKEDITOR.START or CKEDITOR.END.
+ * @returns {Boolean} "true" if the range boundary is at the inner
+ * boundary of the element.
*/
checkBoundaryOfElement : function( element, checkType )
{
+ var checkStart = ( checkType == CKEDITOR.START );
+
+ // Create a copy of this range, so we can manipulate it for our checks.
var walkerRange = this.clone();
+
+ // Collapse the range at the proper size.
+ walkerRange.collapse( checkStart );
+
// Expand the range to element boundary.
- walkerRange[ checkType == CKEDITOR.START ?
- 'setStartAt' : 'setEndAt' ]
- ( element, checkType == CKEDITOR.START ?
- CKEDITOR.POSITION_AFTER_START
- : CKEDITOR.POSITION_BEFORE_END );
+ walkerRange[ checkStart ? 'setStartAt' : 'setEndAt' ]
+ ( element, checkStart ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_END );
- var walker = new CKEDITOR.dom.walker( walkerRange ),
- retval = false;
+ // Create the walker, which will check if we have anything useful
+ // in the range.
+ var walker = new CKEDITOR.dom.walker( walkerRange );
walker.evaluator = elementBoundaryEval;
- return walker[ checkType == CKEDITOR.START ?
- 'checkBackward' : 'checkForward' ]();
+
+ return walker[ checkStart ? 'checkBackward' : 'checkForward' ]();
},
+
// Calls to this function may produce changes to the DOM. The range may
// be updated to reflect such changes.
checkStartOfBlock : function()
@@ -1779,8 +1812,15 @@ CKEDITOR.dom.range = function( document )
*/
getEnclosedNode : function()
{
- var walkerRange = this.clone(),
- walker = new CKEDITOR.dom.walker( walkerRange ),
+ var walkerRange = this.clone();
+
+ // Optimize and analyze the range to avoid DOM destructive nature of walker. (#5780)
+ walkerRange.optimize();
+ if ( walkerRange.startContainer.type != CKEDITOR.NODE_ELEMENT
+ || walkerRange.endContainer.type != CKEDITOR.NODE_ELEMENT )
+ return null;
+
+ var walker = new CKEDITOR.dom.walker( walkerRange ),
isNotBookmarks = CKEDITOR.dom.walker.bookmark( true ),
isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),
evaluator = function( node )
@@ -1826,11 +1866,15 @@ CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS = 3;
/**
* Check boundary types.
- * @see CKEDITOR.dom.range::checkBoundaryOfElement
+ * @see CKEDITOR.dom.range.prototype.checkBoundaryOfElement
*/
CKEDITOR.START = 1;
CKEDITOR.END = 2;
CKEDITOR.STARTEND = 3;
+/**
+ * Shrink range types.
+ * @see CKEDITOR.dom.range.prototype.shrink
+ */
CKEDITOR.SHRINK_ELEMENT = 1;
CKEDITOR.SHRINK_TEXT = 2;