/*\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
// This function is to be called under a "walker" instance scope.\r
function iterate( rtl, breakOnFalse )\r
{\r
+ var range = this.range;\r
+\r
// Return null if we have reached the end.\r
if ( this._.end )\r
return null;\r
\r
- var node,\r
- range = this.range,\r
- guard,\r
- userGuard = this.guard,\r
- type = this.type,\r
- getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );\r
-\r
// This is the first call. Initialize it.\r
if ( !this._.start )\r
{\r
this._.start = 1;\r
\r
- // Trim text nodes and optmize the range boundaries. DOM changes\r
- // may happen at this point.\r
- range.trim();\r
-\r
// A collapsed range must return null at first call.\r
if ( range.collapsed )\r
{\r
this.end();\r
return null;\r
}\r
+\r
+ // Move outside of text node edges.\r
+ range.optimize();\r
}\r
\r
+ var node,\r
+ startCt = range.startContainer,\r
+ endCt = range.endContainer,\r
+ startOffset = range.startOffset,\r
+ endOffset = range.endOffset,\r
+ guard,\r
+ userGuard = this.guard,\r
+ type = this.type,\r
+ getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );\r
+\r
// Create the LTR guard function, if necessary.\r
if ( !rtl && !this._.guardLTR )\r
{\r
- // Gets the node that stops the walker when going LTR.\r
- var limitLTR = range.endContainer,\r
- blockerLTR = limitLTR.getChild( range.endOffset );\r
+ // The node that stops walker from moving up.\r
+ var limitLTR = endCt.type == CKEDITOR.NODE_ELEMENT ?\r
+ endCt :\r
+ endCt.getParent();\r
+\r
+ // The node that stops the walker from going to next.\r
+ var blockerLTR = endCt.type == CKEDITOR.NODE_ELEMENT ?\r
+ endCt.getChild( endOffset ) :\r
+ endCt.getNext();\r
\r
this._.guardLTR = function( node, movingOut )\r
{\r
// Create the RTL guard function, if necessary.\r
if ( rtl && !this._.guardRTL )\r
{\r
- // Gets the node that stops the walker when going LTR.\r
- var limitRTL = range.startContainer,\r
- blockerRTL = ( range.startOffset > 0 ) && limitRTL.getChild( range.startOffset - 1 );\r
+ // The node that stops walker from moving up.\r
+ var limitRTL = startCt.type == CKEDITOR.NODE_ELEMENT ?\r
+ startCt :\r
+ startCt.getParent();\r
+\r
+ // The node that stops the walker from going to next.\r
+ var blockerRTL = startCt.type == CKEDITOR.NODE_ELEMENT ?\r
+ startOffset ?\r
+ startCt.getChild( startOffset - 1 ) : null :\r
+ startCt.getPrevious();\r
\r
this._.guardRTL = function( node, movingOut )\r
{\r
else\r
{\r
// Get the first node to be returned.\r
-\r
if ( rtl )\r
{\r
- node = range.endContainer;\r
+ node = endCt;\r
\r
- if ( range.endOffset > 0 )\r
+ if ( node.type == CKEDITOR.NODE_ELEMENT )\r
{\r
- node = node.getChild( range.endOffset - 1 );\r
- if ( guard( node ) === false )\r
- node = null;\r
+ if ( endOffset > 0 )\r
+ node = node.getChild( endOffset - 1 );\r
+ else\r
+ node = ( guard ( node, true ) === false ) ?\r
+ null : node.getPreviousSourceNode( true, type, guard );\r
}\r
- else\r
- node = ( guard ( node, true ) === false ) ?\r
- null : node.getPreviousSourceNode( true, type, guard );\r
}\r
else\r
{\r
- node = range.startContainer;\r
- node = node.getChild( range.startOffset );\r
+ node = startCt;\r
\r
- if ( node )\r
+ if ( node.type == CKEDITOR.NODE_ELEMENT )\r
{\r
- if ( guard( node ) === false )\r
- node = null;\r
+ if ( ! ( node = node.getChild( startOffset ) ) )\r
+ node = ( guard ( startCt, true ) === false ) ?\r
+ null : startCt.getNextSourceNode( true, type, guard ) ;\r
}\r
- else\r
- node = ( guard ( range.startContainer, true ) === false ) ?\r
- null : range.startContainer.getNextSourceNode( true, type, guard ) ;\r
}\r
+\r
+ if ( node && guard( node ) === false )\r
+ node = null;\r
}\r
\r
while ( node && !this._.end )\r
\r
CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames )\r
{\r
- var nodeNameMatches = CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$block, customNodeNames || {} );\r
+ var nodeNameMatches = customNodeNames ?\r
+ CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$block, customNodeNames || {} ) :\r
+ CKEDITOR.dtd.$block;\r
\r
// Don't consider floated formatting as block boundary, fall back to dtd check in that case. (#6297)\r
return this.getComputedStyle( 'float' ) == 'none' && blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ]\r
};\r
};\r
\r
+ CKEDITOR.dom.walker.bogus = function( isReject )\r
+ {\r
+ function nonEmpty( node )\r
+ {\r
+ return !isWhitespaces( node ) && !isBookmark( node );\r
+ }\r
+\r
+ return function( node )\r
+ {\r
+ var isBogus = !CKEDITOR.env.ie ? node.is && node.is( 'br' ) :\r
+ node.getText && tailNbspRegex.test( node.getText() );\r
+\r
+ if ( isBogus )\r
+ {\r
+ var parent = node.getParent(), next = node.getNext( nonEmpty );\r
+ isBogus = parent.isBlockBoundary() &&\r
+ ( !next ||\r
+ next.type == CKEDITOR.NODE_ELEMENT &&\r
+ next.isBlockBoundary() );\r
+ }\r
+\r
+ return !! ( isReject ^ isBogus );\r
+ };\r
+ };\r
+\r
var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/,\r
isWhitespaces = CKEDITOR.dom.walker.whitespaces(),\r
isBookmark = CKEDITOR.dom.walker.bookmark(),\r