Ticket #2871: 2871.patch

File 2871.patch, 21.1 KB (added by Martin Kou, 12 years ago)
  • _source/core/config.js

     
    146146         * @example
    147147         * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea';
    148148         */
    149         plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,pagebreak,removeformat,smiley,sourcearea,specialchar,tab,toolbar,wysiwygarea',
     149        plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,pagebreak,removeformat,smiley,sourcearea,specialchar,domiterator,tab,toolbar,wysiwygarea',
    150150
    151151        /**
    152152         * The theme to be used to build the UI.
  • _source/core/dom/element.js

     
    538538                },
    539539
    540540                /**
    541                  * Gets the first child node of this element.
    542                  * @returns {CKEDITOR.dom.node} The first child node or null if not
    543                  *              available.
    544                  * @example
    545                  * var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b></div>' );
    546                  * var first = <b>element.getFirst()</b>;
    547                  * alert( first.getName() );  // "b"
    548                  */
    549                 getFirst : function()
    550                 {
    551                         var $ = this.$.firstChild;
    552                         return $ ? new CKEDITOR.dom.node( $ ) : null;
    553                 },
    554 
    555                 getLast : function()
    556                 {
    557                         var $ = this.$.lastChild;
    558                         return $ ? new CKEDITOR.dom.node( $ ) : null;
    559                 },
    560 
    561                 /**
    562541                 * Gets the node that follows this element in its parent's child list.
    563542                 * @returns {CKEDITOR.dom.node} The next node or null if not
    564543                 *              available.
  • _source/core/dom/node.js

     
    215215                },
    216216
    217217                /**
     218                 * Gets the first child node of this node.
     219                 * @returns {CKEDITOR.dom.node} The first child node or null if not
     220                 *              available.
     221                 * @example
     222                 * var element = CKEDITOR.dom.element.createFromHtml( '&lt;div&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/div&gt;' );
     223                 * var first = <b>element.getFirst()</b>;
     224                 * alert( first.getName() );  // "b"
     225                 */
     226                getFirst : function()
     227                {
     228                        var $ = this.$.firstChild;
     229                        return $ ? new CKEDITOR.dom.node( $ ) : null;
     230                },
     231
     232                getLast : function()
     233                {
     234                        var $ = this.$.lastChild;
     235                        return $ ? new CKEDITOR.dom.node( $ ) : null;
     236                },
     237
     238                /**
    218239                 * Gets the node following this node (next sibling).
    219240                 * @returns {CKEDITOR.dom.node} The next node.
    220241                 */
     
    422443                {
    423444                        this.insertBefore( nodeToReplace );
    424445                        nodeToReplace.remove();
     446                },
     447
     448                trim : function()
     449                {
     450                        this.ltrim();
     451                        this.rtrim();
     452                },
     453
     454                ltrim : function()
     455                {
     456                        var child;
     457                        while ( ( child = this.getFirst() ) )
     458                        {
     459                                if ( child.type == CKEDITOR.NODE_TEXT )
     460                                {
     461                                        var trimmed = CKEDITOR.tools.ltrim( child.getText() ),
     462                                                originalLength = child.getLength();
     463
     464                                        if ( trimmed.length == 0 )
     465                                        {
     466                                                child.remove();
     467                                                continue;
     468                                        }
     469                                        else if ( trimmed.length < originalLength )
     470                                        {
     471                                                child.split( originalLength - trimmed.length );
     472
     473                                                // IE BUG: child.remove() may raise JavaScript errors here. (#81)
     474                                                this.$.removeChild( this.$.firstChild );
     475                                        }
     476                                }
     477                                break;
     478                        }
     479                },
     480
     481                rtrim : function()
     482                {
     483                        var child;
     484                        while ( ( child = this.getLast() ) )
     485                        {
     486                                if ( child.type == CKEDITOR.NODE_TEXT )
     487                                {
     488                                        var trimmed = child.getText().rtrim(),
     489                                                originalLength = child.getLength();
     490
     491                                        if ( trimmed.length == 0 )
     492                                        {
     493                                                child.remove();
     494                                                continue;
     495                                        }
     496                                        else if ( trimmed.length < originalLength )
     497                                        {
     498                                                child.split( trimmed.length );
     499
     500                                                // IE BUG: child.getNext().remove() may raise JavaScript errors here.
     501                                                // (#81)
     502                                                this.$.lastChild.parentNode.removeChild( this.$.lastChild );
     503                                        }
     504                                }
     505                                break;
     506                        }
     507
     508                        if ( !CKEDITOR.env.ie && !CKEDITOR.env.opera )
     509                        {
     510                                child = this.$.lastChild;
     511
     512                                if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' )
     513                                {
     514                                        // Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324).
     515                                        child.parentNode.removeChild( child ) ;
     516                                }
     517                        }
    425518                }
    426519        }
    427520);
  • _source/core/dom/range.js

     
    259259
    260260        var inlineChildReqElements = { abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 };
    261261
    262         var getBoundaryNodes = function()
    263         {
    264                 var startNode = this.startContainer,
    265                         endNode = this.endContainer,
    266                         startOffset = this.startOffset,
    267                         endOffset = this.endOffset,
    268                         childCount;
    269 
    270                 if ( startNode.type == CKEDITOR.NODE_ELEMENT )
    271                 {
    272                         childCount = startNode.getChildCount();
    273                         if ( childCount > startOffset )
    274                                 startNode = startNode.getChild( startOffset );
    275                         else if ( childCount < 1 )
    276                                 startNode = startNode.getPreviousSourceNode();
    277                         else            // startOffset > childCount but childCount is not 0
    278                         {
    279                                 // Try to take the node just after the current position.
    280                                 startNode = startNode.$;
    281                                 while ( startNode.lastChild )
    282                                         startNode = startNode.lastChild;
    283                                 startNode = new CKEDITOR.dom.node( startNode );
    284 
    285                                 // Normally we should take the next node in DFS order. But it
    286                                 // is also possible that we've already reached the end of
    287                                 // document.
    288                                 startNode = startNode.getNextSourceNode() || startNode;
    289                         }
    290                 }
    291                 if ( endNode.type == CKEDITOR.NODE_ELEMENT )
    292                 {
    293                         childCount = endNode.getChildCount();
    294                         if ( childCount > endOffset )
    295                                 endNode = endNode.getChild( endOffset ).getPreviousSourceNode();
    296                         else if ( childCount < 1 )
    297                                 endNode = endNode.getPreviousSourceNode();
    298                         else            // endOffset > childCount but childCount is not 0
    299                         {
    300                                 // Try to take the node just before the current position.
    301                                 endNode = endNode.$;
    302                                 while ( endNode.lastChild )
    303                                         endNode = endNode.lastChild;
    304                                 endNode = new CKEDITOR.dom.node( endNode );
    305                         }
    306                 }
    307 
    308                 return { startNode : startNode, endNode : endNode };
    309         };
    310 
    311262        // Check every node between the block boundary and the startNode or endNode.
    312263        var getCheckStartEndBlockFunction = function( isStart )
    313264        {
     
    478429                                this.collapse( true );
    479430                },
    480431
     432                getBoundaryNodes : function()
     433                {
     434                        var startNode = this.startContainer,
     435                                endNode = this.endContainer,
     436                                startOffset = this.startOffset,
     437                                endOffset = this.endOffset,
     438                                childCount;
     439
     440                        if ( startNode.type == CKEDITOR.NODE_ELEMENT )
     441                        {
     442                                childCount = startNode.getChildCount();
     443                                if ( childCount > startOffset )
     444                                        startNode = startNode.getChild( startOffset );
     445                                else if ( childCount < 1 )
     446                                        startNode = startNode.getPreviousSourceNode();
     447                                else            // startOffset > childCount but childCount is not 0
     448                                {
     449                                        // Try to take the node just after the current position.
     450                                        startNode = startNode.$;
     451                                        while ( startNode.lastChild )
     452                                                startNode = startNode.lastChild;
     453                                        startNode = new CKEDITOR.dom.node( startNode );
     454
     455                                        // Normally we should take the next node in DFS order. But it
     456                                        // is also possible that we've already reached the end of
     457                                        // document.
     458                                        startNode = startNode.getNextSourceNode() || startNode;
     459                                }
     460                        }
     461                        if ( endNode.type == CKEDITOR.NODE_ELEMENT )
     462                        {
     463                                childCount = endNode.getChildCount();
     464                                if ( childCount > endOffset )
     465                                        endNode = endNode.getChild( endOffset ).getPreviousSourceNode();
     466                                else if ( childCount < 1 )
     467                                        endNode = endNode.getPreviousSourceNode();
     468                                else            // endOffset > childCount but childCount is not 0
     469                                {
     470                                        // Try to take the node just before the current position.
     471                                        endNode = endNode.$;
     472                                        while ( endNode.lastChild )
     473                                                endNode = endNode.lastChild;
     474                                        endNode = new CKEDITOR.dom.node( endNode );
     475                                }
     476                        }
     477
     478                        return { startNode : startNode, endNode : endNode };
     479                },
     480
    481481                getCommonAncestor : function( includeSelf )
    482482                {
    483483                        var start = this.startContainer;
     
    969969                                case CKEDITOR.ENLARGE_BLOCK_CONTENTS:
    970970                                case CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:
    971971                                        // DFS backward to get the block/list item boundary at or before the start.
    972                                         var boundaryNodes = getBoundaryNodes.apply( this ),
     972                                        var boundaryNodes = this.getBoundaryNodes(),
    973973                                                startNode = boundaryNodes.startNode,
    974974                                                endNode = boundaryNodes.endNode,
    975975                                                guardFunction = ( unit == CKEDITOR.ENLARGE_BLOCK_CONTENTS ?
     
    11551155                        updateCollapsed( this );
    11561156                },
    11571157
    1158                 // TODO: The fixed block isn't trimmed, does not work for <pre>.
    11591158                // TODO: Does not add bogus <br> to empty fixed blocks.
    11601159                fixBlock : function( isStart, blockTag )
    11611160                {
     
    11641163                        this.collapse( isStart );
    11651164                        this.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
    11661165                        this.extractContents().appendTo( fixedBlock );
     1166                        fixedBlock.trim();
    11671167                        this.insertNode( fixedBlock );
    11681168                        this.moveToBookmark( bookmark );
    11691169                        return fixedBlock;
     
    12601260                                        return false;
    12611261                        }
    12621262
    1263                         var startNode = getBoundaryNodes.apply( this ).startNode,
     1263                        var startNode = this.getBoundaryNodes().startNode,
    12641264                                walker = new CKEDITOR.dom.domWalker( startNode );
    12651265
    12661266                        // DFS backwards until the block boundary, with the checker function.
     
    12841284                                        return false;
    12851285                        }
    12861286
    1287                         var endNode = getBoundaryNodes.apply( this ).endNode,
     1287                        var endNode = this.getBoundaryNodes().endNode,
    12881288                                walker = new CKEDITOR.dom.domWalker( endNode );
    12891289
    12901290                        // DFS forward until the block boundary, with the checker function.
  • _source/plugins/domiterator/plugin.js

     
     1/*
     2Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
     3For licensing, see LICENSE.html or http://ckeditor.com/license
     4*/
     5
     6/**
     7 * @file DOM iterator, which iterates over list items, lines and paragraphs.
     8 */
     9
     10CKEDITOR.plugins.add( 'domiterator' );
     11
     12(function()
     13{
     14        // Functions ported over from v2.
     15        function getTouchedStartNode( range )
     16        {
     17                var container = range.startContainer;
     18
     19                if ( range.collapsed || container.type != CKEDITOR.NODE_ELEMENT )
     20                        return container;
     21
     22                return container.getChildCount() > range.startOffset ? container.getChild( range.startOffset ) : container;
     23        }
     24
     25        function getTouchedEndNode( range )
     26        {
     27                var container = range.endContainer;
     28
     29                if ( range.collapsed || container.type != CKEDITOR.NODE_ELEMENT )
     30                        return container;
     31
     32                return container.getChildCount() > range.endOffset ? container.getChild( range.endOffset ) : container;
     33        }
     34       
     35        function getNextSourceNode( currentNode, startFromSibling, nodeType, stopSearchNode )
     36        {
     37                if ( !currentNode )
     38                        return null;
     39
     40                var node;
     41
     42                if ( !startFromSibling && currentNode.getFirst() )
     43                        node = currentNode.getFirst();
     44                else
     45                {
     46                        if ( stopSearchNode && currentNode.equals( stopSearchNode ) )
     47                                return null;
     48
     49                        node = currentNode.getNext();
     50
     51                        if ( !node && ( !stopSearchNode || !stopSearchNode.equals( currentNode.parentNode ) ) )
     52                                return getNextSourceNode( currentNode.getParent(), true, nodeType, stopSearchNode );
     53                }
     54
     55                if ( nodeType && node && node.type != nodeType )
     56                        return getNextSourceNode( node, false, nodeType, stopSearchNode );
     57
     58                return node;
     59        }
     60
     61        var iterator = function( range )
     62        {
     63                if ( arguments.length < 1 )
     64                        return;
     65
     66                this.range = range;
     67                this.forceBrBreak = false;
     68                this.enforceRealBlocks = false;
     69
     70                this._ || ( this._ = {} );
     71        },
     72                beginWhitespaceRegex = /^[\r\n\t ]+$/;
     73
     74
     75        iterator.prototype = {
     76                getNextParagraph : function( blockTag )
     77                {
     78                        // The block element to be returned.
     79                        var block;
     80
     81                        // The range object used to identify the paragraph contents.
     82                        var range;
     83
     84                        // Indicats that the current element in the loop is the last one.
     85                        var isLast;
     86
     87                        // Instructs to cleanup remaining BRs.
     88                        var removePreviousBr, removeLastBr;
     89
     90                        // Things we consider should be separated into blocks.
     91                        var displayMatches = { block : 1, 'list-item' : 1, table : 1, 'table-row-group' : 1, 'table-header-group' : 1,
     92                                'table-footer-group' : 1, 'table-row' : 1, 'table-column-group' : 1, 'table-column' : 1, 'table-cell' : 1,
     93                                'table-caption' : 1 };
     94
     95                        // This is the first iteration. Let's initialize it.
     96                        if ( !this._.lastNode )
     97                        {
     98                                range = this.range.clone();
     99                                range.enlarge( this.forceBrBreak ? CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS );
     100
     101                                this._.nextNode = getTouchedStartNode( range );
     102                                this._.lastNode = getTouchedEndNode( range );
     103
     104                                // Let's reuse this variable.
     105                                range = null;
     106                        }
     107
     108                        var currentNode = this._.nextNode,
     109                                lastNode = this._.lastNode;
     110
     111                        this._.nextNode = null;
     112
     113                        while ( currentNode )
     114                        {
     115                                // closeRange indicates that a paragraph boundary has been found,
     116                                // so the range can be closed.
     117                                var closeRange = false;
     118
     119                                // includeNode indicates that the current node is good to be part
     120                                // of the range. By default, any non-element node is ok for it.
     121                                var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ),
     122                                        continueFromSibling = false;
     123
     124                                // If it is an element node, let's check if it can be part of the
     125                                // range.
     126                                if ( !includeNode )
     127                                {
     128                                        var nodeName = currentNode.getName(),
     129                                                nodeDisplay = currentNode.getComputedStyle( 'display' );
     130
     131                                        if ( displayMatches[ nodeDisplay ] || ( this.forceBrBreak && nodeName == 'br' ) )
     132                                        {
     133                                                // <br> boundaries must be part of the range. It will
     134                                                // happen only if ForceBrBreak.
     135                                                if ( nodeName == 'br' )
     136                                                        includeNode = true;
     137                                                else if ( !range && currentNode.getChildCount() == 0 && nodeName != 'hr' )
     138                                                {
     139                                                        // If we have found an empty block, and haven't started
     140                                                        // the range yet, it means we must return this block.
     141                                                        block = currentNode;
     142                                                        isLast = currentNode.equals( lastNode );
     143                                                        break;
     144                                                }
     145
     146                                                // The range must finish right before the boundary,
     147                                                // including possibly skipped empty spaces. (#1603)
     148                                                if ( range )
     149                                                {
     150                                                        range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
     151
     152                                                        // The found boundary must be set as the next one at this
     153                                                        // point. (#1717)
     154                                                        if ( nodeName != 'br' )
     155                                                                this._.nextNode = getNextSourceNode( currentNode, true, null, lastNode ) || currentNode;
     156                                                }
     157
     158                                                closeRange = true;
     159                                        }
     160                                        else
     161                                        {
     162                                                // If we have child nodes, let's check them.
     163                                                if ( currentNode.getFirst() )
     164                                                {
     165                                                        // If we don't have a range yet, let's start it.
     166                                                        if ( !range )
     167                                                        {
     168                                                                range = new CKEDITOR.dom.range( this.range.document );
     169                                                                range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
     170                                                        }
     171
     172                                                        currentNode = currentNode.getFirst();
     173                                                        continue;
     174                                                }
     175                                                includeNode = true;
     176                                        }
     177                                }
     178                                else if ( currentNode.type == CKEDITOR.NODE_TEXT )
     179                                {
     180                                        // Ignore normal whitespaces (i.e. not including &nbsp; or
     181                                        // other unicode whitespaces) before/after a block node.
     182                                        if ( beginWhitespaceRegex.test( currentNode.getText() ) )
     183                                                includeNode = false;
     184                                }
     185
     186                                // The current node is good to be part of the range and we are
     187                                // starting a new range, initialize it first.
     188                                if ( includeNode && !range )
     189                                {
     190                                        range = new CKEDITOR.dom.range( this.range.document );
     191                                        range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
     192                                }
     193
     194                                // The last node has been found.
     195                                isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) );
     196
     197                                // If we are in an element boundary, let's check if it is time
     198                                // to close the range, otherwise we include the parent within it.
     199                                if ( range && !closeRange )
     200                                {
     201                                        while ( !currentNode.getNext() && !isLast )
     202                                        {
     203                                                var parentNode = currentNode.getParent();
     204
     205                                                if ( displayMatches[ parentNode.getComputedStyle( 'display' ) ] || ( this.forceBrBreak && parentNode.getName() == 'br' ) )
     206                                                {
     207                                                        closeRange = true;
     208                                                        isLast = isLast || ( parentNode.equals( lastNode) );
     209                                                        break;
     210                                                }
     211
     212                                                currentNode = parentNode;
     213                                                includeNode = true;
     214                                                isLast = ( currentNode.equals( lastNode ) );
     215                                                continueFromSibling = true;
     216                                        }
     217                                }
     218
     219                                // Now finally include the node.
     220                                if ( includeNode )
     221                                        range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END );
     222
     223                                // We have found a block boundary. Let's close the range and move out of the
     224                                // loop.
     225                                if ( ( closeRange || isLast ) && range )
     226                                {
     227                                        var boundaryNodes = range.getBoundaryNodes(),
     228                                                startPath = new CKEDITOR.dom.elementPath( range.startContainer ),
     229                                                endPath = new CKEDITOR.dom.elementPath( range.endContainer );
     230                                        if ( boundaryNodes.startNode.equals( boundaryNodes.endNode )
     231                                                        && boundaryNodes.startNode.getParent().equals( startPath.blockLimit )
     232                                                        && boundaryNodes.startNode.type == CKEDITOR.NODE_ELEMENT && boundaryNodes.startNode.getAttribute( '_fck_bookmark' ) )
     233                                                range = null;
     234                                        else
     235                                                break;
     236                                }
     237
     238                                if ( isLast )
     239                                        break;
     240
     241                                currentNode = getNextSourceNode( currentNode, continueFromSibling, null, lastNode );
     242                        }
     243
     244                        // Now, based on the processed range, look for (or create) the block to be returned.
     245                        if ( !block )
     246                        {
     247                                // If no range has been found, this is the end.
     248                                if ( !range )
     249                                {
     250                                        this._.nextNode = null;
     251                                        return null;
     252                                }
     253
     254                                var startPath = new CKEDITOR.dom.elementPath( range.startContainer ),
     255                                        startBlockLimit = startPath.blockLimit,
     256                                        checkLimits = { div : 1, th : 1, td : 1 };
     257                                block = startPath.block;
     258
     259                                if ( !block
     260                                                && !this.enforceRealBlocks
     261                                                && checkLimits[ startBlockLimit.getName() ]
     262                                                && range.checkStartOfBlock()
     263                                                && range.checkEndOfBlock() )
     264                                        block = startBlockLimit;
     265                                else if ( !block || ( this.enforceRealBlocks && block.getName() == 'li' ) )
     266                                {
     267                                        // Create the fixed block.
     268                                        block = this.range.document.createElement( blockTag || 'p' );
     269
     270                                        // Move the contents of the temporary range to the fixed block.
     271                                        range.extractContents().appendTo( block );
     272                                        block.trim();
     273
     274                                        // Insert the fixed block into the DOM.
     275                                        range.insertNode( block );
     276
     277                                        removePreviousBr = removeLastBr = true;
     278                                }
     279                                else if ( block.getName() != 'li' )
     280                                {
     281                                        // If the range doesn't includes the entire contents of the
     282                                        // block, we must split it, isolating the range in a dedicated
     283                                        // block.
     284                                        if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() )
     285                                        {
     286                                                // The resulting block will be a clone of the current one.
     287                                                block = block.clone( false );
     288
     289                                                // Extract the range contents, moving it to the new block.
     290                                                range.extractContents().appendTo( block );
     291                                                block.trim();
     292
     293                                                // Split the block. At this point, the range will be in the
     294                                                // right position for our intents.
     295                                                var splitInfo = range.splitBlock();
     296
     297                                                removePreviousBr = !splitInfo.wasStartOfBlock;
     298                                                removeLastBr = !splitInfo.wasEndOfBlock;
     299
     300                                                // Insert the new block into the DOM.
     301                                                range.insertNode( block );
     302                                        }
     303                                }
     304                                else if ( !isLast )
     305                                {
     306                                        // LIs are returned as is, with all their children (due to the
     307                                        // nested lists). But, the next node is the node right after
     308                                        // the current range, which could be an <li> child (nested
     309                                        // lists) or the next sibling <li>.
     310
     311                                        this._.nextNode = ( block.equals( lastNode ) ? null :
     312                                                        getNextSourceNode( range.getBoundaryNodes().endNode, true, null, lastNode ) );
     313                                }
     314                        }
     315
     316                        if ( removePreviousBr )
     317                        {
     318                                var previousSibling = block.getPrevious();
     319                                if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT )
     320                                {
     321                                        if ( previousSibling.getName() == 'br' )
     322                                                previousSibling.remove();
     323                                        else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' )
     324                                                previousSibling.getLast().remove();
     325                                }
     326                        }
     327
     328                        if ( removeLastBr )
     329                        {
     330                                var lastChild = block.getLast();
     331                                if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' )
     332                                        lastChild.remove();
     333                        }
     334
     335                        // Get a reference for the next element. This is important because the
     336                        // above block can be removed or changed, so we can rely on it for the
     337                        // next interation.
     338                        if ( !this._.nextNode )
     339                                this._.nextNode = ( isLast || block.equals( lastNode ) ) ? null : getNextSourceNode( block, true, null, lastNode );
     340
     341                        return block;
     342                }
     343        };
     344
     345        CKEDITOR.dom.range.prototype.createIterator = function()
     346        {
     347                return new iterator( this );
     348        };
     349})();
© 2003 – 2020 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy