X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fcore%2Fdom%2Frange.js;h=c8312b749b3008e1b304afd3e45c587104c06880;hb=refs%2Ftags%2Fv3.6.4;hp=67759c80ad1e1ea2232f2d632d4edcdeb8a3ef8c;hpb=e73319a12b56100b29ef456fd74114fe5519e01c;p=ckeditor.git diff --git a/_source/core/dom/range.js b/_source/core/dom/range.js index 67759c8..c8312b7 100644 --- a/_source/core/dom/range.js +++ b/_source/core/dom/range.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -349,7 +349,10 @@ CKEDITOR.dom.range = function( document ) // check(Start|End)OfBlock. function getCheckStartEndBlockEvalFunction( isStart ) { - var hadBr = false, bookmarkEvaluator = CKEDITOR.dom.walker.bookmark( true ); + var skipBogus = false, + bookmarkEvaluator = CKEDITOR.dom.walker.bookmark( true ), + nbspRegExp = /^[\t\r\n ]*(?: |\xa0)$/; + return function( node ) { // First ignore bookmark nodes. @@ -358,8 +361,16 @@ CKEDITOR.dom.range = function( document ) if ( node.type == CKEDITOR.NODE_TEXT ) { + // Skip the block filler NBSP. + if ( CKEDITOR.env.ie && + nbspRegExp.test( node.getText() ) && + !skipBogus && + !( isStart && node.getNext() ) ) + { + skipBogus = true; + } // If there's any visible text, then we're not at the start. - if ( node.hasAscendant( 'pre' ) || CKEDITOR.tools.trim( node.getText() ).length ) + else if ( node.hasAscendant( 'pre' ) || CKEDITOR.tools.trim( node.getText() ).length ) return false; } else if ( node.type == CKEDITOR.NODE_ELEMENT ) @@ -368,10 +379,14 @@ CKEDITOR.dom.range = function( document ) // at the start. if ( !inlineChildReqElements[ node.getName() ] ) { - // If we're working at the end-of-block, forgive the first
in non-IE - // browsers. - if ( !isStart && !CKEDITOR.env.ie && node.getName() == 'br' && !hadBr ) - hadBr = true; + // Skip the padding block br. + if ( !CKEDITOR.env.ie && + node.is( 'br' ) && + !skipBogus && + !( isStart && node.getNext() ) ) + { + skipBogus = true; + } else return false; } @@ -380,16 +395,23 @@ CKEDITOR.dom.range = function( document ) }; } + + var isBogus = CKEDITOR.dom.walker.bogus(); // Evaluator for CKEDITOR.dom.element::checkBoundaryOfElement, reject any // text node and non-empty elements unless it's being bookmark text. - function elementBoundaryEval( node ) + function elementBoundaryEval( checkStart ) { - // Reject any text node unless it's being bookmark - // OR it's spaces. (#3883) - return node.type != CKEDITOR.NODE_TEXT - && node.getName() in CKEDITOR.dtd.$removeEmpty - || !CKEDITOR.tools.trim( node.getText() ) - || !!node.getParent().data( 'cke-bookmark' ); + return function( node ) + { + // Tolerant bogus br when checking at the end of block. + // Reject any text node unless it's being bookmark + // OR it's spaces. + // Reject any element unless it's being invisible empty. (#3883) + return !checkStart && isBogus( node ) || + ( node.type == CKEDITOR.NODE_TEXT ? + !CKEDITOR.tools.trim( node.getText() ) || !!node.getParent().data( 'cke-bookmark' ) + : node.getName() in CKEDITOR.dtd.$removeEmpty ); + }; } var whitespaceEval = new CKEDITOR.dom.walker.whitespaces(), @@ -506,7 +528,7 @@ CKEDITOR.dom.range = function( document ) if ( serializable ) { baseId = 'cke_bm_' + CKEDITOR.tools.getNextNumber(); - startNode.setAttribute( 'id', baseId + 'S' ); + startNode.setAttribute( 'id', baseId + ( collapsed ? 'C' : 'S' ) ); } // If collapsed, the endNode will not be created. @@ -537,7 +559,7 @@ CKEDITOR.dom.range = function( document ) this.moveToPosition( startNode, CKEDITOR.POSITION_AFTER_END ); return { - startNode : serializable ? baseId + 'S' : startNode, + startNode : serializable ? baseId + ( collapsed ? 'C' : 'S' ) : startNode, endNode : serializable ? baseId + 'E' : endNode, serializable : serializable, collapsed : collapsed @@ -1014,7 +1036,12 @@ CKEDITOR.dom.range = function( document ) // whitespaces at the end. isWhiteSpace = false; - if ( sibling.type == CKEDITOR.NODE_TEXT ) + if ( sibling.type == CKEDITOR.NODE_COMMENT ) + { + sibling = sibling.getPrevious(); + continue; + } + else if ( sibling.type == CKEDITOR.NODE_TEXT ) { siblingText = sibling.getText(); @@ -1044,7 +1071,7 @@ CKEDITOR.dom.range = function( document ) sibling = null; else { - var allChildren = sibling.$.all || sibling.$.getElementsByTagName( '*' ); + var allChildren = sibling.$.getElementsByTagName( '*' ); for ( var i = 0, child ; child = allChildren[ i++ ] ; ) { if ( !CKEDITOR.dtd.$removeEmpty[ child.nodeName.toLowerCase() ] ) @@ -1183,7 +1210,7 @@ CKEDITOR.dom.range = function( document ) isWhiteSpace = /^[\s\ufeff]/.test( siblingText ); } - else + else if ( sibling.type == CKEDITOR.NODE_ELEMENT ) { // If this is a visible element. // We need to check for the bookmark attribute because IE insists on @@ -1204,7 +1231,7 @@ CKEDITOR.dom.range = function( document ) sibling = null; else { - allChildren = sibling.$.all || sibling.$.getElementsByTagName( '*' ); + allChildren = sibling.$.getElementsByTagName( '*' ); for ( i = 0 ; child = allChildren[ i++ ] ; ) { if ( !CKEDITOR.dtd.$removeEmpty[ child.nodeName.toLowerCase() ] ) @@ -1222,6 +1249,8 @@ CKEDITOR.dom.range = function( document ) sibling = null; } } + else + isWhiteSpace = 1; if ( isWhiteSpace ) { @@ -1793,7 +1822,7 @@ CKEDITOR.dom.range = function( document ) // Create the walker, which will check if we have anything useful // in the range. var walker = new CKEDITOR.dom.walker( walkerRange ); - walker.evaluator = elementBoundaryEval; + walker.evaluator = elementBoundaryEval( checkStart ); return walker[ checkStart ? 'checkBackward' : 'checkForward' ](); }, @@ -1814,11 +1843,6 @@ CKEDITOR.dom.range = function( document ) return false; } - // Antecipate the trim() call here, so the walker will not make - // changes to the DOM, which would not get reflected into this - // range otherwise. - this.trim(); - // We need to grab the block element holding the start boundary, so // let's use an element path for it. var path = new CKEDITOR.dom.elementPath( this.startContainer ); @@ -1848,11 +1872,6 @@ CKEDITOR.dom.range = function( document ) return false; } - // Antecipate the trim() call here, so the walker will not make - // changes to the DOM, which would not get reflected into this - // range otherwise. - this.trim(); - // We need to grab the block element holding the start boundary, so // let's use an element path for it. var path = new CKEDITOR.dom.elementPath( this.endContainer ); @@ -1920,16 +1939,14 @@ CKEDITOR.dom.range = function( document ) */ moveToElementEditablePosition : function( el, isMoveToEnd ) { + var nbspRegExp = /^[\t\r\n ]*(?: |\xa0)$/; + function nextDFS( node, childOnly ) { var next; - if ( node.type == CKEDITOR.NODE_ELEMENT - && node.isEditable( false ) - && !CKEDITOR.dtd.$nonEditable[ node.getName() ] ) - { + if ( node.type == CKEDITOR.NODE_ELEMENT && node.isEditable( false ) ) next = node[ isMoveToEnd ? 'getLast' : 'getFirst' ]( nonWhitespaceOrBookmarkEval ); - } if ( !childOnly && !next ) next = node[ isMoveToEnd ? 'getPrevious' : 'getNext' ]( nonWhitespaceOrBookmarkEval ); @@ -1937,6 +1954,15 @@ CKEDITOR.dom.range = function( document ) return next; } + // Handle non-editable element e.g. HR. + if ( el.type == CKEDITOR.NODE_ELEMENT && !el.isEditable( false ) ) + { + this.moveToPosition( el, isMoveToEnd ? + CKEDITOR.POSITION_AFTER_END : + CKEDITOR.POSITION_BEFORE_START ); + return true; + } + var found = 0; while ( el ) @@ -1944,7 +1970,11 @@ CKEDITOR.dom.range = function( document ) // Stop immediately if we've found a text node. if ( el.type == CKEDITOR.NODE_TEXT ) { - this.moveToPosition( el, isMoveToEnd ? + // Put cursor before block filler. + if ( isMoveToEnd && this.checkEndOfBlock() && nbspRegExp.test( el.getText() ) ) + this.moveToPosition( el, CKEDITOR.POSITION_BEFORE_START ); + else + this.moveToPosition( el, isMoveToEnd ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ); found = 1; @@ -1961,6 +1991,9 @@ CKEDITOR.dom.range = function( document ) CKEDITOR.POSITION_AFTER_START ); found = 1; } + // Put cursor before padding block br. + else if ( isMoveToEnd && el.is( 'br' ) && this.checkEndOfBlock() ) + this.moveToPosition( el, CKEDITOR.POSITION_BEFORE_START ); } el = nextDFS( el, found );