Ticket #3304: 3304_7.patch

File 3304_7.patch, 30.6 KB (added by Garry Yao, 11 years ago)
  • _source/plugins/domiterator/plugin.js

     
    314314                        // above block can be removed or changed, so we can rely on it for the
    315315                        // next interation.
    316316                        if ( !this._.nextNode )
     317                        {
    317318                                this._.nextNode = ( isLast || block.equals( lastNode ) ) ? null :
    318319                                        getNextSourceNode( block, lastNode, true );
     320                        }
    319321
    320322                        return block;
    321323                }
  • _source/plugins/find/dialogs/find.js

     
    55
    66(function()
    77{
    8         // Element tag names which prevent characters counting.
    9         var characterBoundaryElementsEnum =
     8        function guardDomWalkerNonEmptyTextNode( node )
    109        {
    11                 address :1, blockquote :1, dl :1, h1 :1, h2 :1, h3 :1,
    12                 h4 :1, h5 :1, h6 :1, p :1, pre :1, li :1, dt :1, de :1, div :1, td:1, th:1
    13         };
     10                return ( node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 )
     11        }
    1412
    15         var guardDomWalkerNonEmptyTextNode = function( evt )
     13        /**
     14         * Elements which break characters been considered as sequence.
     15        */
     16        function checkCharactersBoundary ( node )
    1617        {
    17                 if ( evt.data.to && evt.data.to.type == CKEDITOR.NODE_TEXT
    18                         && evt.data.to.$.length > 0 )
    19                         this.stop();
    20                 CKEDITOR.dom.domWalker.blockBoundary( { br : 1 } ).call( this, evt );
    21         };
    22 
     18                var dtd = CKEDITOR.dtd;
     19                return node.isBlockBoundary(
     20                        CKEDITOR.tools.extend( {}, dtd.$empty, dtd.$nonEditable ) );
     21        }
    2322
    2423        /**
    2524         * Get the cursor object which represent both current character and it's dom
     
    3029                var obj = {
    3130                        textNode : this.textNode,
    3231                        offset : this.offset,
    33                         character : this.textNode ? this.textNode.getText().charAt( this.offset ) : null,
     32                        character : this.textNode ?
     33                                this.textNode.getText().charAt( this.offset ) : null,
    3434                        hitMatchBoundary : this._.matchBoundary
    3535                };
    3636                return obj;
     
    7575                 * Iterator which walk through document char by char.
    7676                 * @param {Object} start
    7777                 * @param {Number} offset
     78                 * @param {Boolean} isStrict
    7879                 */
    79                 var characterWalker = function( start, offset )
     80                var characterWalker = function( range , matchWord )
    8081                {
    81                         var isCursor = typeof( start.textNode ) !== 'undefined';
    82                         this.textNode = isCursor ? start.textNode : start;
    83                         this.offset = isCursor ? start.offset : offset;
     82                        var walker =
     83                                new CKEDITOR.dom.walker( range );
     84                        walker[ matchWord ? 'guard' : 'evaluator' ] =
     85                                guardDomWalkerNonEmptyTextNode;
     86                        walker.breakOnFalse = true;
     87
    8488                        this._ = {
    85                                 walker : new CKEDITOR.dom.domWalker( this.textNode ),
     89                                matchWord : matchWord,
     90                                walker : walker,
    8691                                matchBoundary : false
    8792                        };
    8893                };
     
    9095                characterWalker.prototype = {
    9196                        next : function()
    9297                        {
     98                                return this.move();     
     99                        },
     100                       
     101                        back : function()
     102                        {
     103                                return this.move( true );
     104                        },
     105                       
     106                        move : function( rtl )
     107                        {
     108                                var currentTextNode = this.textNode;
    93109                                // Already at the end of document, no more character available.
    94                                 if( !this.textNode )
     110                                if(  currentTextNode === null )
    95111                                        return cursorStep.call( this );
    96112
    97113                                this._.matchBoundary = false;
     
    96112
    97113                                this._.matchBoundary = false;
    98114
    99                                 // If there are more characters in the text node, get it and
    100                                 // raise an event.
    101                                 if( this.textNode.type == CKEDITOR.NODE_TEXT
    102                                         && this.offset < this.textNode.getLength() - 1 )
     115                                // There are more characters in the text node, step forward.
     116                                if( currentTextNode
     117                                    && rtl
     118                                        && this.offset > 0 )
    103119                                {
    104                                         this.offset++;
     120                                        this.offset--;
    105121                                        return cursorStep.call( this );
    106122                                }
    107 
    108                                 // If we are at the end of the text node, use dom walker to get
    109                                 // the next text node.
    110                                 var data = null;
    111                                 while ( !data || ( data.node && data.node.type !=
    112                                         CKEDITOR.NODE_TEXT ) )
     123                                else if( currentTextNode
     124                                        && this.offset < currentTextNode.getLength() - 1 )
    113125                                {
    114                                         data = this._.walker.forward(
    115                                                 guardDomWalkerNonEmptyTextNode );
    116 
    117                                         // Block boundary? BR? Document boundary?
    118                                         if ( !data.node
    119                                                 || ( data.node.type !== CKEDITOR.NODE_TEXT
    120                                                         && data.node.getName() in
    121                                                         characterBoundaryElementsEnum ) )
    122                                                 this._.matchBoundary = true;
    123                                 }
    124                                 this.textNode = data.node;
    125                                 this.offset = 0;
    126                                 return cursorStep.call( this );
    127                         },
    128 
    129                         back : function()
    130                         {
    131                                 this._.matchBoundary = false;
    132 
    133                                 // More characters -> decrement offset and return.
    134                                 if ( this.textNode.type == CKEDITOR.NODE_TEXT && this.offset > 0 )
    135                                 {
    136                                         this.offset--;
     126                                        this.offset++;
    137127                                        return cursorStep.call( this );
    138128                                }
    139 
    140                                 // Start of text node -> use dom walker to get the previous text node.
    141                                 var data = null;
    142                                 while ( !data
    143                                 || ( data.node && data.node.type != CKEDITOR.NODE_TEXT ) )
     129                                else
    144130                                {
    145                                         data = this._.walker.reverse( guardDomWalkerNonEmptyTextNode );
     131                                        currentTextNode = null;
     132                                        // At the end of the text node, walking foward for the next.
     133                                        while ( !currentTextNode )
     134                                        {
     135                                                currentTextNode =
     136                                                        this._.walker[ rtl ? 'previous' : 'next' ].call( this._.walker );
    146137
    147                                         // Block boundary? BR? Document boundary?
    148                                         if ( !data.node || ( data.node.type !== CKEDITOR.NODE_TEXT &&
    149                                         data.node.getName() in characterBoundaryElementsEnum ) )
    150                                                 this._.matchBoundary = true;
     138                                                // Stop searching if we're need full word match.
     139                                                if ( this._.matchWord && !currentTextNode )
     140                                                        break;
     141                                                // Marking as match boundaries.
     142                                                if( currentTextNode === false
     143                                                   && checkCharactersBoundary( this._.walker.current ) )
     144                                                        this._.matchBoundary = true;
     145       
     146                                                // Already reach document end.
     147                                                if ( this._.walker._.end )
     148                                                        break;
     149                                        }
     150                                        // Found a fresh text node.
     151                                        this.textNode = currentTextNode;
     152                                        if ( currentTextNode )
     153                                                this.offset = rtl ? currentTextNode.getLength() - 1 : 0;
     154                                        else
     155                                                this.offset = 0;
    151156                                }
    152                                 this.textNode = data.node;
    153                                 this.offset = data.node.length - 1;
     157
    154158                                return cursorStep.call( this );
    155159                        }
     160
    156161                };
    157162
    158163                /**
     
    218223                                // node.
    219224                                if ( endNode.getLength() < 1 )
    220225                                {
    221                                         while ( ( endNode = endNode.getPreviousSourceNode() ) && !( endNode.type == CKEDITOR.NODE_TEXT && endNode.getLength() > 0 ) )
     226                                        while ( ( endNode = endNode.getPreviousSourceNode() )
     227                                                   && !( endNode.type == CKEDITOR.NODE_TEXT
     228                                                                        && endNode.getLength() > 0 ) )
    222229                                        { /*jsl:pass*/ }
    223230
    224231                                        endIndex = endNode.getLength();
     
    224231                                        endIndex = endNode.getLength();
    225232                                }
    226233
    227                                 var cursor = new characterWalker( startNode, startIndex );
    228                                 this._.cursors = [ cursor ];
    229                                 if ( !( cursor.textNode.equals( endNode ) && cursor.offset == endIndex - 1 ) )
     234                                // Rebuild the character range.
     235                                var cursor,
     236                                                walker = new characterWalker(
     237                                                                getRangeAfterCursor(
     238                                                                                                        ( { textNode: startNode, offset : startIndex } ),
     239                                                                                                        true ) );
     240                                this._.cursors = [];
     241                                do
    230242                                {
    231                                         do
    232                                         {
    233                                                 cursor = new characterWalker( cursor );
    234                                                 cursor.next();
    235                                                 this._.cursors.push( cursor );
    236                                         }
    237                                         while ( !( cursor.textNode.equals( endNode ) && cursor.offset == endIndex - 1 ) );
     243                                        cursor = walker.next();
     244                                        this._.cursors.push( cursor );
    238245                                }
    239 
     246                                while ( !( cursor.textNode.equals( endNode )
     247                                                         && cursor.offset == endIndex - 1 ) );
    240248                                this._.rangeLength = this._.cursors.length;
    241249                        },
    242250
     
    338346                                return cursors[ cursors.length - 1 ].character;
    339347                        },
    340348
    341                         getNextRange : function( maxLength )
     349                        getNextCharacterRange : function( maxLength )
    342350                        {
    343                                 var cursors = this._.cursors;
    344                                 if ( cursors.length < 1 )
     351                                var lastCursor,
     352                                                cursors = this._.cursors;
     353                                if ( !( lastCursor = cursors[ cursors.length - 1 ] ) )
    345354                                        return null;
    346 
    347                                 var next = new characterWalker( cursors[ cursors.length - 1 ] );
    348                                 return new characterRange( next, maxLength );
     355                                return new characterRange(
     356                                                                                new characterWalker(
     357                                                                                        getRangeAfterCursor( lastCursor ) ),
     358                                                                                maxLength );
    349359                        },
    350 
     360                       
    351361                        getCursors : function()
    352362                        {
    353363                                return this._.cursors;
     
    354364                        }
    355365                };
    356366
     367               
     368                // The remaining document range after the character cursor.
     369                function getRangeAfterCursor( cursor , inclusive )
     370                {
     371                        var range = new CKEDITOR.dom.range();
     372                        range.setStart( cursor.textNode,
     373                                                   ( inclusive ? cursor.offset : cursor.offset + 1 ) );
     374                        range.setEndAt( editor.document.getBody(),
     375                                                        CKEDITOR.POSITION_BEFORE_END );
     376                        return range;
     377                }
     378
     379                // The document range before the character cursor.
     380                function getRangeBeforeCursor( cursor )
     381                {
     382                        var range = new CKEDITOR.dom.range();
     383                        range.setStartAt( editor.document.getBody(),
     384                                                        CKEDITOR.POSITION_AFTER_START );
     385                        range.setEnd( cursor.textNode, cursor.offset );
     386                        return range;
     387                }
     388               
    357389                var KMP_NOMATCH = 0,
    358390                        KMP_ADVANCED = 1,
    359391                        KMP_MATCHED = 2;
     
    430462                };
    431463
    432464                var finder = {
    433                         startCursor : null,
    434                         range : null,
     465                        searchRange : null,
     466                        matchRange : null,
    435467                        find : function( pattern, matchCase, matchWord, matchCyclic )
    436468                        {
    437                                 if( !this.range )
    438                                         this.range = new characterRange( new characterWalker( this.startCursor ), pattern.length );
     469                                if( !this.matchRange )
     470                                        this.matchRange =
     471                                                new characterRange(
     472                                                        new characterWalker( this.searchRange ),
     473                                                        pattern.length );
    439474                                else
    440475                                {
    441                                         this.range.removeHighlight();
    442                                         this.range = this.range.getNextRange( pattern.length );
     476                                        this.matchRange.removeHighlight();
     477                                        this.matchRange = this.matchRange.getNextCharacterRange( pattern.length );
    443478                                }
    444479
    445480                                var matcher = new kmpMatcher( pattern, !matchCase ),
     
    448483
    449484                                while ( character !== null )
    450485                                {
    451                                         this.range.moveNext();
    452                                         while ( ( character = this.range.getEndCharacter() ) )
     486                                        this.matchRange.moveNext();
     487                                        while ( ( character = this.matchRange.getEndCharacter() ) )
    453488                                        {
    454489                                                matchState = matcher.feedCharacter( character );
    455490                                                if ( matchState == KMP_MATCHED )
     
    454489                                                matchState = matcher.feedCharacter( character );
    455490                                                if ( matchState == KMP_MATCHED )
    456491                                                        break;
    457                                                 if ( this.range.moveNext().hitMatchBoundary )
     492                                                if ( this.matchRange.moveNext().hitMatchBoundary )
    458493                                                        matcher.reset();
    459494                                        }
    460495
     
    462497                                        {
    463498                                                if ( matchWord )
    464499                                                {
    465                                                         var cursors = this.range.getCursors(),
     500                                                        var cursors = this.matchRange.getCursors(),
    466501                                                                tail = cursors[ cursors.length - 1 ],
    467                                                                 head = cursors[ 0 ],
    468                                                                 headWalker = new characterWalker( head ),
    469                                                                 tailWalker = new characterWalker( tail );
    470 
     502                                                                head = cursors[ 0 ];
     503                                                                headWalker =
     504                                                                        new characterWalker(
     505                                                                                getRangeBeforeCursor( head ),
     506                                                                        true ),
     507                                                                tailWalker =
     508                                                                        new characterWalker(
     509                                                                                getRangeAfterCursor( tail ),
     510                                                                        true );
    471511                                                        if ( ! ( isWordSeparator(
    472512                                                                                headWalker.back().character )
    473513                                                                                && isWordSeparator(
     
    475515                                                                continue;
    476516                                                }
    477517
    478                                                 this.range.setMatched();
     518                                                this.matchRange.setMatched();
    479519                                                return true;
    480520                                        }
    481521                                }
     
    480520                                        }
    481521                                }
    482522
    483                                 this.range.clearMatched();
    484 
    485                                 // clear current session and restart from beginning
     523                                this.matchRange.clearMatched();
     524                                this.matchRange.removeHighlight();
     525                                // Clear current session and restart with the default search
     526                                // range.
    486527                                if ( matchCyclic )
    487528                                {
    488                                         this.startCursor = getDefaultStartCursor();
    489                                         this.range = null;
     529                                        this.searchRange = getSearchRange( true );
     530                                        this.matchRange = null;
    490531                                }
    491532
    492533                                return false;
     
    530571                }
    531572
    532573                /**
    533                  * Get cursor that indicate search begin with, receive from user
     574                 * The range in which find/replace happened, receive from user
    534575                 * selection prior.
    535576                 */
    536                 function getStartCursor()
     577                function getSearchRange( isDefault )
    537578                {
    538                         var sel = editor.getSelection();
    539                         if ( sel )
     579                        var searchRange,
     580                                sel = editor.getSelection(),
     581                                body = editor.document.getBody();
     582                        if ( sel && !isDefault )
    540583                        {
    541                                 var lastRange = sel.getRanges()[ sel.getRanges().length - 1 ];
    542                                 return {
    543                                         textNode : lastRange.getBoundaryNodes().endNode,
    544                                         offset : lastRange.endContainer.type ===
    545                                                 CKEDITOR.NODE_ELEMENT ?
    546                                                 0       : lastRange.endOffset
    547                                 };
     584                                searchRange = sel.getRanges()[ 0 ].clone();
     585                                searchRange.collapse( true );
    548586                        }
    549587                        else
    550                                 return getDefaultStartCursor();
     588                        {
     589                                searchRange = new CKEDITOR.dom.range();
     590                                searchRange.setStartAt( body, CKEDITOR.POSITION_AFTER_START );
     591                        }
     592                        searchRange.setEndAt( body, CKEDITOR.POSITION_BEFORE_END );
     593                        return searchRange;
    551594                }
    552595
    553596                return {
     
    785828                        onShow : function()
    786829                        {
    787830                                // Establish initial searching start position.
    788                                 finder.startCursor = getStartCursor.call( this );
     831                                finder.searchRange = getSearchRange();
    789832
    790833                                if ( startupPage == 'replace' )
    791834                                        this.getContentElement( 'replace', 'txtFindReplace' ).focus();
     
    794837                        },
    795838                        onHide : function()
    796839                        {
    797                                 if ( finder.range && finder.range.isMatched() )
     840                                if ( finder.matchRange && finder.matchRange.isMatched() )
    798841                                {
    799                                         finder.range.removeHighlight();
     842                                        finder.matchRange.removeHighlight();
    800843                                        editor.focus();
    801844                                        editor.getSelection().selectRanges(
    802                                                 [ finder.range.toDomRange() ] );
     845                                                [ finder.matchRange.toDomRange() ] );
    803846                                }
    804847
    805848                                // Clear current session before dialog close
    806                                 delete finder.range;
     849                                delete finder.matchRange;
    807850                        }
    808851                };
    809852        };
  • _source/tests/core/dom/range.html

     
    2121
    2222        var doc = new CKEDITOR.dom.document( document );
    2323
     24        var getRange = function( startId, endId )
     25        {
     26                var range = new CKEDITOR.dom.range( CKEDITOR.document );
     27                range.moveToBookmark( { startNode : startId, endNode : endId, serializable : true } );
     28                return range;
     29        };
     30
    2431        return tests = {
    2532                test__constructor : function()
    2633                {
     
    930937                        assert.isFalse( range.collapsed, 'range.collapsed' );
    931938                },
    932939
     940                test_enlarge_list1 : function()
     941                {
     942                        var range = getRange( 'S1', null );
     943                        range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
     944
     945                        assert.areSame( document.getElementById( '_EnlargeP7' ), range.startContainer.$, 'range.startContainer' );
     946                        assert.areSame( 0, range.startOffset, 'range.startOffset' );
     947                        assert.areSame( document.getElementById( '_EnlargeP7' ), range.endContainer.$, 'range.endContainer' );
     948                        assert.areSame( 3, range.endOffset, 'range.endOffset' );
     949                        assert.isFalse( range.collapsed, 'range.collapsed' );
     950                },
     951
     952                test_enlarge_list2 : function()
     953                {
     954                        var range = getRange( 'S2', 'E2' );
     955                        range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
     956
     957                        assert.areSame( document.getElementById( '_EnlargeP8' ), range.startContainer.$, 'range.startContainer' );
     958                        assert.areSame( 0, range.startOffset, 'range.startOffset' );
     959                        assert.areSame( document.getElementById( '_EnlargeP8' ), range.endContainer.$, 'range.endContainer' );
     960                        assert.areSame( 4, range.endOffset, 'range.endOffset' );
     961                        assert.isFalse( range.collapsed, 'range.collapsed' );
     962                },
     963
     964                test_enlarge_list3 : function()
     965                {
     966                        var range = getRange( 'S3', null );
     967                        range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
     968
     969                        assert.areSame( document.getElementById( '_EnlargeP9' ), range.startContainer.$, 'range.startContainer' );
     970                        assert.areSame( 2, range.startOffset, 'range.startOffset' );
     971                        assert.areSame( document.getElementById( '_EnlargeP9' ), range.endContainer.$, 'range.endContainer' );
     972                        assert.areSame( 3, range.endOffset, 'range.endOffset' );
     973                        assert.isFalse( range.collapsed, 'range.collapsed' );
     974                },
     975
     976                test_enlarge_list4 : function()
     977                {
     978                        var range = getRange( 'S4', null );
     979                        range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
     980
     981                        assert.areSame( document.getElementById( '_EnlargeP10' ), range.startContainer.$, 'range.startContainer' );
     982                        assert.areSame( 3, range.startOffset, 'range.startOffset' );
     983                        assert.areSame( document.getElementById( '_EnlargeP10' ), range.endContainer.$, 'range.endContainer' );
     984                        assert.areSame( 5, range.endOffset, 'range.endOffset' );
     985                        assert.isFalse( range.collapsed, 'range.collapsed' );
     986                },
     987
     988                test_enlarge_list5 : function()
     989                {
     990                        var range = getRange( 'S1', null );
     991                        var bookmark = range.createBookmark();
     992                        range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
     993
     994                        assert.areSame( document.getElementById( '_EnlargeP7' ), range.startContainer.$, 'range.startContainer' );
     995                        assert.areSame( 0, range.startOffset, 'range.startOffset' );
     996                        assert.areSame( document.getElementById( '_EnlargeP7' ), range.endContainer.$, 'range.endContainer' );
     997                        assert.areSame( 4, range.endOffset, 'range.endOffset' );
     998                        assert.isFalse( range.collapsed, 'range.collapsed' );
     999                        range.moveToBookmark( bookmark );
     1000                },
     1001
    9331002                test_deleteContents_W3C_1 : function()
    9341003                {
    9351004                        // W3C DOM Range Specs - Section 2.6 - Example 1
     
    18231892                        assert.isFalse( range.checkEndOfBlock() );
    18241893                },
    18251894
     1895                test_checkEndOfBlock9 : function()
     1896                {
     1897                        var range = getRange( 'S5', null );
     1898                        assert.isFalse( range.checkEndOfBlock() );
     1899                },
     1900
     1901                test_checkEndOfBlock10 : function()
     1902                {
     1903                        var range = getRange( 'S6', null );
     1904                        assert.isTrue( range.checkEndOfBlock() );
     1905                },
     1906
     1907                test_checkEndOfBlock11 : function()
     1908                {
     1909                        var range = getRange( 'S7', null );
     1910                        assert.areSame( range.checkEndOfBlock(), !CKEDITOR.env.ie, 'range.checkBlock()' );
     1911                },
     1912
     1913                test_checkEndOfBlock12 : function()
     1914                {
     1915                        var range = getRange( 'S8', null );
     1916                        assert.isFalse( range.checkEndOfBlock() );
     1917                },
     1918
     1919                test_checkEndOfBlock13 : function()
     1920                {
     1921                        var range = getRange( 'S9', null );
     1922                        assert.isFalse( range.checkEndOfBlock() );
     1923                },
     1924
    18261925                /////////////
    18271926
    18281927                setUp : function()
     
    19702069                <p id="_EnlargeP4">Test <i id="_EnlargeI4"> Enlarge</i></p>
    19712070                <p id="_EnlargeP5">Test <i id="_EnlargeI5">Enlarge</i></p>
    19722071                <p id="_EnlargeP6">Test <i id="_EnlargeI6"><b></b>Enlarge</i></p>
     2072                <p id="_EnlargeP7">Test <span id="S1"></span>List<br/ >Item Enlarge</p>
     2073                <p id="_EnlargeP8">Test <span id="S2"></span>List<span id="E2"></span> <br /><br />Item Enlarge</p>
     2074                <p id="_EnlargeP9">Test List <br /><span id="S3"></span><br />Item Enlarge</p>
     2075                <p id="_EnlargeP10">Test List <br /><br />Item<span id="S4"></span> Enlarge</p>
     2076                <p>Test Check<span id="S5"></span><br />End</p>
     2077                <p>Test Check<br />End<span id="S6"></span></p>
     2078                <p>Test Check End<span id="S7"></span><br /></p>
     2079                <p>Test Check End<span id="S8"></span><br /><br /></p>
     2080                <p>Test Check<span id="S9"></span> End</p>
    19732081        </div>
    19742082        <script type="text/javascript">
    19752083        //<![CDATA[
  • _source/core/dom/range.js

     
    263263        // check(Start|End)OfBlock.
    264264        function getCheckStartEndBlockEvalFunction( isStart )
    265265        {
     266                var hadBr = false;
    266267                return function( node )
    267268                {
    268                         var hadBr = false;
    269 
    270269                        if ( node.type == CKEDITOR.NODE_TEXT )
    271270                        {
    272271                                // If there's any visible text, then we're not at the start.
     
    279278                                // at the start.
    280279                                if ( !inlineChildReqElements[ node.getName() ] )
    281280                                {
    282                                         // If we're working at the end-of-block, forgive the first <br />.
    283                                         if ( !isStart && node.getName() == 'br' && !hadBr )
     281                                        // If we're working at the end-of-block, forgive the first <br /> in non-IE
     282                                        // browsers.
     283                                        if ( !isStart && !CKEDITOR.env.ie && node.getName() == 'br' && !hadBr )
    284284                                                hadBr = true;
    285285                                        else
    286286                                                return false;
     
    10871087
    10881088                                case CKEDITOR.ENLARGE_BLOCK_CONTENTS:
    10891089                                case CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:
    1090                                         // DFS backward to get the block/list item boundary at or before the start.
    10911090
    1092                                         // Get the boundaries nodes.
    1093                                         var startNode = this.getTouchedStartNode(),
    1094                                                 endNode = this.getTouchedEndNode();
    1095 
    1096                                         if ( startNode.type == CKEDITOR.NODE_ELEMENT && startNode.isBlockBoundary() )
    1097                                         {
    1098                                                 this.setStartAt( startNode,
    1099                                                         CKEDITOR.dtd.$empty[ startNode.getName() ] ?
    1100                                                                 CKEDITOR.POSITION_AFTER_END :
    1101                                                                 CKEDITOR.POSITION_AFTER_START );
    1102                                         }
    1103                                         else
    1104                                         {
    1105                                                 // Get the function used to check the enlaarging limits.
    1106                                                 var guardFunction = ( unit == CKEDITOR.ENLARGE_BLOCK_CONTENTS ?
    1107                                                                 CKEDITOR.dom.domWalker.blockBoundary() :
    1108                                                                 CKEDITOR.dom.domWalker.listItemBoundary() );
    1109 
    1110                                                 // Create the DOM walker, which will traverse the DOM.
    1111                                                 var walker = new CKEDITOR.dom.domWalker( startNode );
    1112 
    1113                                                 // Go walk in reverse sense.
    1114                                                 var data = walker.reverse( guardFunction );
    1115 
    1116                                                 var boundaryEvent = data.events.shift();
     1091                                        // Enlarging the start boundary.
     1092                                        var walkerRange = new CKEDITOR.dom.range( this.document );
     1093                                        walkerRange.setStartAt(
     1094                                                this.document.getBody(), CKEDITOR.POSITION_AFTER_START );
     1095                                        walkerRange.setEnd( this.startContainer, this.startOffset );
     1096                                        var walker = new CKEDITOR.dom.walker( walkerRange ),
     1097                                               
     1098                                                guard = CKEDITOR.dom.walker.blockBoundary(
     1099                                                                ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) ? { br : 1 } : null ),
     1100                                                tailBr,
     1101                                                listGuard = function( node )
     1102                                                {
     1103                                                        var result = guard( node );
     1104                                                        if ( !result && node.is && node.is( 'br' ) )
     1105                                                                tailBr = node;
     1106                                                        return result;
     1107                                                },
     1108                                                enlargeable;
     1109                                        walker.guard = guard;
     1110                                               
     1111                                        if ( ( enlargeable = walker.lastBackward() ) )
     1112                                                this.setStartAt(
     1113                                                        enlargeable, CKEDITOR.POSITION_BEFORE_START );
    11171114
    1118                                                 this.setStartBefore( boundaryEvent.from );
    1119                                         }
    1120 
    1121                                         if ( endNode.type == CKEDITOR.NODE_ELEMENT && endNode.isBlockBoundary() )
    1122                                         {
    1123                                                 this.setEndAt( endNode,
    1124                                                         CKEDITOR.dtd.$empty[ endNode.getName() ] ?
    1125                                                                 CKEDITOR.POSITION_BEFORE_START :
    1126                                                                 CKEDITOR.POSITION_BEFORE_END );
    1127                                         }
    1128                                         else
    1129                                         {
    1130                                                 // DFS forward to get the block/list item boundary at or before the end.
    1131                                                 walker.setNode( endNode );
    1132                                                 data = walker.forward( guardFunction );
    1133                                                 boundaryEvent = data.events.shift();
    1134 
    1135                                                 this.setEndAfter( boundaryEvent.from );
    1136                                         }
     1115                                        // Enlarging the end boundary.
     1116                                        walkerRange = this.clone();
     1117                                        walkerRange.collapse();
     1118                                        walkerRange.setEndAt(
     1119                                                this.document.getBody(), CKEDITOR.POSITION_BEFORE_END );
     1120                                        walker = new CKEDITOR.dom.walker( walkerRange );
     1121                                        walker.guard = ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) ?
     1122                                                 listGuard : guard;
     1123                                        if ( ( enlargeable = walker.lastForward() ) )
     1124                                                        this.setEndAfter( enlargeable );
     1125                                        // We must include the <br> at the end of range if there's
     1126                                        // one and we're expanding list item contents
     1127                                        if ( tailBr )
     1128                                                this.setEndAfter( tailBr );
    11371129                        }
    11381130                },
    11391131
     
    15181510                        if ( this.collapsed || container.type != CKEDITOR.NODE_ELEMENT )
    15191511                                return container ;
    15201512
    1521                         return container.getChild[ this.endOffset - 1 ] || container ;
     1513                        return container.getChild( this.endOffset - 1 ) || container ;
    15221514                }
    15231515        };
    15241516})();
  • _source/core/dom/walker.js

     
    66(function()
    77{
    88        // This function is to be called under a "walker" instance scope.
    9         function iterate( rtl, breakOnFalse )
     9        function iterate( rtl, forceBreakOnFalse )
    1010        {
    1111                // Return null if we have reached the end.
    1212                if ( this._.end )
     
    1717                        guard,
    1818                        userGuard = this.guard,
    1919                        type = this.type,
     20                        breakOnFalse = forceBreakOnFalse || this._.breakOnFalse;
    2021                        getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
    2122
    2223                // This is the first call. Initialize it.
     
    134135                return this.current = null;
    135136        }
    136137
    137 //      function iterateToLast( rtl )
    138 //      {
    139 //              var node, last = null;
     138        function iterateToLast( rtl )
     139        {
     140                var node, last = null;
    140141
    141 //              while ( node = iterate.call( this, rtl ) )
    142 //                      last = node;
     142                while ( node = iterate.call( this, rtl ) )
     143                        last = node;
    143144
    144 //              return last;
    145 //      }
     145                return last;
     146        }
    146147
    147148        CKEDITOR.dom.walker = CKEDITOR.tools.createClass(
    148149        {
     
    177178                         * it's to be considered into the walk or not. If not provided, all
    178179                         * matched nodes are considered good.
    179180                         * If the function returns "false" the node is ignored.
    180                          * @name CKEDITOR.pluginDefinition.prototype.evaluator
     181                         * @name CKEDITOR.dom.walker.prototype.evaluator
    181182                         * @property
    182183                         * @type Function
    183184                         */
     
    189190                         * entering and exiting nodes, as well as for the matched nodes.
    190191                         * If this function returns "false", the walking ends and no more
    191192                         * nodes are evaluated.
    192                          * @name CKEDITOR.pluginDefinition.prototype.guard
     193                         * @name CKEDITOR.dom.walker.prototype.guard
    193194                         * @property
    194195                         * @type Function
    195196                         */
     
    194195                         * @type Function
    195196                         */
    196197                        // this.guard = null;
    197 
     198                       
     199                        /**
     200                         * Whether the iteration return 'false' when the specified
     201                         * {@link CKEDITOR.dom.walker.prototype.evaluator} failed.
     202                         *@name CKEDITOR.dom.walker.prototype.breakOnFalse
     203                         *@property
     204                         *@type Boolean
     205                         */
     206                        // this.breakOnFalse = false;
     207                       
    198208                        /** @private */
    199209                        this._ = {};
    200210                },
    201 
     211//
    202212//              statics :
    203213//              {
    204214//                      /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.
     
    214224//                      createOnNodes : function( startNode, endNode, startInclusive, endInclusive )
    215225//                      {
    216226//                              var range = new CKEDITOR.dom.range();
    217 //                              range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
    218 
     227//                              if ( startNode )
     228//                                      range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
     229//                              else
     230//                                      range.setStartAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_AFTER_START ) ;
     231//
    219232//                              if ( endNode )
    220233//                                      range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
    221234//                              else
     
    220233//                                      range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
    221234//                              else
    222235//                                      range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;
    223 
     236//
    224237//                              return new CKEDITOR.dom.walker( range );
    225238//                      }
    226239//              },
    227 
     240//
    228241                proto :
    229242                {
    230243                        /**
     
    263276                         */
    264277                        checkForward : function()
    265278                        {
    266                                 return iterate.call( this, false, true ) !== false;
     279                                var last;
     280                                while ( ( last = iterate.call( this, false, true ) ) )
     281                                {}
     282                                return  last !== false;
    267283                        },
    268284
    269285                        /**
     
    273289                         */
    274290                        checkBackward : function()
    275291                        {
    276                                 return iterate.call( this, true, true ) !== false;
    277                         }
     292                                var last;
     293                                while ( ( last = iterate.call( this, true, true ) ) )
     294                                {}
     295                                return  last !== false;
     296                        },
    278297
    279 // The following features have been originally included in the implementation,
    280 // but they are not used anywhere in the code, so they got commented out.
     298                        /**
     299                         * Executes a full walk forward (to the right), until no more nodes
     300                         * are available, returning the last valid node.
     301                         * @returns {CKEDITOR.dom.node} The last node at the right or null
     302                         *              if no valid nodes are available.
     303                         */
     304                        lastForward : function()
     305                        {
     306                                return iterateToLast.call( this );
     307                        },
    281308
    282 //                      /**
    283 //                       * Executes a full walk forward (to the right), until no more nodes
    284 //                       * are available, returning the last valid node.
    285 //                       * @returns {CKEDITOR.dom.node} The last node at the right or null
    286 //                       *              if no valid nodes are available.
    287 //                       */
    288 //                      lastForward : function()
    289 //                      {
    290 //                              return iterateToLast.call( this );
    291 //                      },
     309                        /**
     310                         * Executes a full walk backwards (to the left), until no more nodes
     311                         * are available, returning the last valid node.
     312                         * @returns {CKEDITOR.dom.node} The last node at the left or null
     313                         *              if no valid nodes are available.
     314                         */
     315                        lastBackward : function()
     316                        {
     317                                return iterateToLast.call( this, true );
     318                        }
    292319
    293 //                      /**
    294 //                       * Executes a full walk backwards (to the left), until no more nodes
    295 //                       * are available, returning the last valid node.
    296 //                       * @returns {CKEDITOR.dom.node} The last node at the left or null
    297 //                       *              if no valid nodes are available.
    298 //                       */
    299 //                      lastBackward : function()
    300 //                      {
    301 //                              return iterateToLast.call( this, true );
    302 //                      }
    303320                }
    304321        });
     322
     323        /*
     324         * Anything whose display computed style is block, list-item, table,
     325         * table-row-group, table-header-group, table-footer-group, table-row,
     326         * table-column-group, table-column, table-cell, table-caption, or whose node
     327         * name is hr, br (when enterMode is br only) is a block boundary.
     328         */
     329        var blockBoundaryDisplayMatch =
     330        {
     331                block : 1,
     332                'list-item' : 1,
     333                table : 1,
     334                'table-row-group' : 1,
     335                'table-header-group' : 1,
     336                'table-footer-group' : 1,
     337                'table-row' : 1,
     338                'table-column-group' : 1,
     339                'table-column' : 1,
     340                'table-cell' : 1,
     341                'table-caption' : 1
     342        },
     343        blockBoundaryNodeNameMatch = { hr : 1 };
     344
     345        CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames )
     346        {
     347                var nodeNameMatches = CKEDITOR.tools.extend(
     348                        blockBoundaryNodeNameMatch, customNodeNames || {} );
     349
     350                return blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] ||
     351                        nodeNameMatches[ this.getName() ];
     352        };
     353
     354        CKEDITOR.dom.walker.blockBoundary = function( customNodeNames )
     355        {
     356                return function( node , type )
     357                {
     358                        return ! ( node.type == CKEDITOR.NODE_ELEMENT
     359                                                && node.isBlockBoundary( customNodeNames ) );
     360                };
     361        };
     362       
     363        CKEDITOR.dom.walker.listItemBoundary = function()
     364        {
     365                        return this.blockBoundary( { br : 1 } );
     366        };
     367
    305368})();
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy