X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fdomiterator%2Fplugin.js;h=f68f7c09d3533b72bba37a4f69a5364872a160c4;hb=2f22c0c38f17e75be5541089076885442aaa2377;hp=a7a8e4d4ad3f170e4425ba0add66b522b67e1495;hpb=ea7e3453c7b0f023b050aca6d9f83ab372860d91;p=ckeditor.git diff --git a/_source/plugins/domiterator/plugin.js b/_source/plugins/domiterator/plugin.js index a7a8e4d..f68f7c0 100644 --- a/_source/plugins/domiterator/plugin.js +++ b/_source/plugins/domiterator/plugin.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, 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 */ @@ -11,23 +11,38 @@ CKEDITOR.plugins.add( 'domiterator' ); (function() { - - var iterator = function( range ) + /** + * @name CKEDITOR.dom.iterator + */ + function iterator( range ) { if ( arguments.length < 1 ) return; this.range = range; - this.forceBrBreak = false; + this.forceBrBreak = 0; // Whether include
s into the enlarged range.(#3730). - this.enlargeBr = true; - this.enforceRealBlocks = false; + this.enlargeBr = 1; + this.enforceRealBlocks = 0; this._ || ( this._ = {} ); - }, - beginWhitespaceRegex = /^[\r\n\t ]+$/; + } + + var beginWhitespaceRegex = /^[\r\n\t ]+$/, + // Ignore bookmark nodes.(#3783) + bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ), + whitespacesGuard = CKEDITOR.dom.walker.whitespaces( true ), + skipGuard = function( node ) { return bookmarkGuard( node ) && whitespacesGuard( node ); }; + // Get a reference for the next element, bookmark nodes are skipped. + function getNextSourceNode( node, startFromSibling, lastNode ) + { + var next = node.getNextSourceNode( startFromSibling, null, lastNode ); + while ( !bookmarkGuard( next ) ) + next = next.getNextSourceNode( startFromSibling, null, lastNode ); + return next; + } iterator.prototype = { getNextParagraph : function( blockTag ) @@ -41,54 +56,69 @@ CKEDITOR.plugins.add( 'domiterator' ); // Indicats that the current element in the loop is the last one. var isLast; + // Indicate at least one of the range boundaries is inside a preformat block. + var touchPre; + // Instructs to cleanup remaining BRs. var removePreviousBr, removeLastBr; // This is the first iteration. Let's initialize it. - if ( !this._.lastNode ) + if ( !this._.started ) { range = this.range.clone(); - range.enlarge( this.forceBrBreak || !this.enlargeBr ? + + // Shrink the range to exclude harmful "noises" (#4087, #4450, #5435). + range.shrink( CKEDITOR.NODE_ELEMENT, true ); + + touchPre = range.endContainer.hasAscendant( 'pre', true ) + || range.startContainer.hasAscendant( 'pre', true ); + + range.enlarge( this.forceBrBreak && !touchPre || !this.enlargeBr ? CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS ); - var walker = new CKEDITOR.dom.walker( range ), - ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true ); - // Avoid anchor inside bookmark inner text. - walker.evaluator = ignoreBookmarkTextEvaluator; - this._.nextNode = walker.next(); - // TODO: It's better to have walker.reset() used here. - walker = new CKEDITOR.dom.walker( range ); - walker.evaluator = ignoreBookmarkTextEvaluator; - var lastNode = walker.previous(); - this._.lastNode = lastNode.getNextSourceNode( true ); - - // We may have an empty text node at the end of block due to [3770]. - // If that node is the lastNode, it would cause our logic to leak to the - // next block.(#3887) - if ( this._.lastNode && - this._.lastNode.type == CKEDITOR.NODE_TEXT && - !CKEDITOR.tools.trim( this._.lastNode.getText( ) ) && - this._.lastNode.getParent().isBlockBoundary() ) + if ( !range.collapsed ) { - var testRange = new CKEDITOR.dom.range( range.document ); - testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END ); - if ( testRange.checkEndOfBlock() ) + var walker = new CKEDITOR.dom.walker( range.clone() ), + ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true ); + // Avoid anchor inside bookmark inner text. + walker.evaluator = ignoreBookmarkTextEvaluator; + this._.nextNode = walker.next(); + // TODO: It's better to have walker.reset() used here. + walker = new CKEDITOR.dom.walker( range.clone() ); + walker.evaluator = ignoreBookmarkTextEvaluator; + var lastNode = walker.previous(); + this._.lastNode = lastNode.getNextSourceNode( true ); + + // We may have an empty text node at the end of block due to [3770]. + // If that node is the lastNode, it would cause our logic to leak to the + // next block.(#3887) + if ( this._.lastNode && + this._.lastNode.type == CKEDITOR.NODE_TEXT && + !CKEDITOR.tools.trim( this._.lastNode.getText() ) && + this._.lastNode.getParent().isBlockBoundary() ) { - var path = new CKEDITOR.dom.elementPath( testRange.endContainer ); - var lastBlock = path.block || path.blockLimit; - this._.lastNode = lastBlock.getNextSourceNode( true ); + var testRange = new CKEDITOR.dom.range( range.document ); + testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END ); + if ( testRange.checkEndOfBlock() ) + { + var path = new CKEDITOR.dom.elementPath( testRange.endContainer ); + var lastBlock = path.block || path.blockLimit; + this._.lastNode = lastBlock.getNextSourceNode( true ); + } } - } - // Probably the document end is reached, we need a marker node. - if ( !this._.lastNode ) - { - this._.lastNode = this._.docEndMarker = range.document.createText( '' ); - this._.lastNode.insertAfter( lastNode ); + // Probably the document end is reached, we need a marker node. + if ( !this._.lastNode ) + { + this._.lastNode = this._.docEndMarker = range.document.createText( '' ); + this._.lastNode.insertAfter( lastNode ); + } + + // Let's reuse this variable. + range = null; } - // Let's reuse this variable. - range = null; + this._.started = 1; } var currentNode = this._.nextNode; @@ -99,12 +129,13 @@ CKEDITOR.plugins.add( 'domiterator' ); { // closeRange indicates that a paragraph boundary has been found, // so the range can be closed. - var closeRange = false; + var closeRange = 0, + parentPre = currentNode.hasAscendant( 'pre' ); // includeNode indicates that the current node is good to be part // of the range. By default, any non-element node is ok for it. var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ), - continueFromSibling = false; + continueFromSibling = 0; // If it is an element node, let's check if it can be part of the // range. @@ -112,12 +143,13 @@ CKEDITOR.plugins.add( 'domiterator' ); { var nodeName = currentNode.getName(); - if ( currentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) ) + if ( currentNode.isBlockBoundary( this.forceBrBreak && + !parentPre && { br : 1 } ) ) { //
boundaries must be part of the range. It will // happen only if ForceBrBreak. if ( nodeName == 'br' ) - includeNode = true; + includeNode = 1; else if ( !range && !currentNode.getChildCount() && nodeName != 'hr' ) { // If we have found an empty block, and haven't started @@ -139,7 +171,7 @@ CKEDITOR.plugins.add( 'domiterator' ); this._.nextNode = currentNode; } - closeRange = true; + closeRange = 1; } else { @@ -156,7 +188,7 @@ CKEDITOR.plugins.add( 'domiterator' ); currentNode = currentNode.getFirst(); continue; } - includeNode = true; + includeNode = 1; } } else if ( currentNode.type == CKEDITOR.NODE_TEXT ) @@ -164,7 +196,7 @@ CKEDITOR.plugins.add( 'domiterator' ); // Ignore normal whitespaces (i.e. not including   or // other unicode whitespaces) before/after a block node. if ( beginWhitespaceRegex.test( currentNode.getText() ) ) - includeNode = false; + includeNode = 0; } // The current node is good to be part of the range and we are @@ -182,21 +214,25 @@ CKEDITOR.plugins.add( 'domiterator' ); // to close the range, otherwise we include the parent within it. if ( range && !closeRange ) { - while ( !currentNode.getNext() && !isLast ) + while ( !currentNode.getNext( skipGuard ) && !isLast ) { var parentNode = currentNode.getParent(); - if ( parentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) ) + if ( parentNode.isBlockBoundary( this.forceBrBreak + && !parentPre && { br : 1 } ) ) { - closeRange = true; + closeRange = 1; + includeNode = 0; isLast = isLast || ( parentNode.equals( lastNode) ); + // Make sure range includes bookmarks at the end of the block. (#7359) + range.setEndAt( parentNode, CKEDITOR.POSITION_BEFORE_END ); break; } currentNode = parentNode; - includeNode = true; + includeNode = 1; isLast = ( currentNode.equals( lastNode ) ); - continueFromSibling = true; + continueFromSibling = 1; } } @@ -204,33 +240,13 @@ CKEDITOR.plugins.add( 'domiterator' ); if ( includeNode ) range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END ); - currentNode = currentNode.getNextSourceNode( continueFromSibling, null, lastNode ); + currentNode = getNextSourceNode ( currentNode, continueFromSibling, lastNode ); isLast = !currentNode; // We have found a block boundary. Let's close the range and move out of the // loop. - if ( ( closeRange || isLast ) && range ) - { - var boundaryNodes = range.getBoundaryNodes(), - startPath = new CKEDITOR.dom.elementPath( range.startContainer ), - endPath = new CKEDITOR.dom.elementPath( range.endContainer ); - - // Drop the range if it only contains bookmark nodes.(#4087) - if ( boundaryNodes.startNode.equals( boundaryNodes.endNode ) - && boundaryNodes.startNode.getParent().equals( startPath.blockLimit ) - && boundaryNodes.startNode.type == CKEDITOR.NODE_ELEMENT - && boundaryNodes.startNode.getAttribute( '_fck_bookmark' ) ) - { - range = null; - this._.nextNode = null; - } - else + if ( isLast || ( closeRange && range ) ) break; - } - - if ( isLast ) - break; - } // Now, based on the processed range, look for (or create) the block to be returned. @@ -244,7 +260,7 @@ CKEDITOR.plugins.add( 'domiterator' ); return null; } - startPath = new CKEDITOR.dom.elementPath( range.startContainer ); + var startPath = new CKEDITOR.dom.elementPath( range.startContainer ); var startBlockLimit = startPath.blockLimit, checkLimits = { div : 1, th : 1, td : 1 }; block = startPath.block; @@ -260,14 +276,14 @@ CKEDITOR.plugins.add( 'domiterator' ); // Create the fixed block. block = this.range.document.createElement( blockTag || 'p' ); - // Move the contents of the temporary range to the fixed block. - range.extractContents().appendTo( block ); - block.trim(); + // Move the contents of the temporary range to the fixed block. + range.extractContents().appendTo( block ); + block.trim(); - // Insert the fixed block into the DOM. - range.insertNode( block ); + // Insert the fixed block into the DOM. + range.insertNode( block ); - removePreviousBr = removeLastBr = true; + removePreviousBr = removeLastBr = true; } else if ( block.getName() != 'li' ) { @@ -301,8 +317,7 @@ CKEDITOR.plugins.add( 'domiterator' ); // the current range, which could be an
  • child (nested // lists) or the next sibling
  • . - this._.nextNode = ( block.equals( lastNode ) ? null : - range.getBoundaryNodes().endNode.getNextSourceNode( true, null, lastNode ) ); + this._.nextNode = ( block.equals( lastNode ) ? null : getNextSourceNode( range.getBoundaryNodes().endNode, 1, lastNode ) ); } } @@ -320,9 +335,6 @@ CKEDITOR.plugins.add( 'domiterator' ); if ( removeLastBr ) { - // Ignore bookmark nodes.(#3783) - var bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ); - var lastChild = block.getLast(); if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' ) { @@ -339,8 +351,8 @@ CKEDITOR.plugins.add( 'domiterator' ); // next interation. if ( !this._.nextNode ) { - this._.nextNode = ( isLast || block.equals( lastNode ) ) ? null : - block.getNextSourceNode( true, null, lastNode ); + this._.nextNode = ( isLast || block.equals( lastNode ) || !lastNode ) ? null : + getNextSourceNode( block, 1, lastNode ); } return block;