Ticket #3367: 3367.patch

File 3367.patch, 14.2 KB (added by Frederico Caldeira Knabben, 13 years ago)
  • _source/core/dom/range.js

     
    14051405                        };
    14061406                },
    14071407
     1408                // Calls to this function may produce changes to the DOM. The range may
     1409                // be updated to reflect such changes.
    14081410                checkStartOfBlock : function()
    14091411                {
    14101412                        var startContainer = this.startContainer,
    1411                                 startOffset = this.startOffset,
    1412                                 startNode,
    1413                                 startInclusive;
     1413                                startOffset = this.startOffset;
    14141414
    1415                         if ( startOffset )
     1415                        // If the starting node is a text node, and non-empty before the offset,
     1416                        // then we're surely not at the start of block.
     1417                        if ( startOffset && startContainer.type == CKEDITOR.NODE_TEXT )
    14161418                        {
    1417                                 // If the starting node is a text node, and non-empty before the offset,
    1418                                 // then we're surely not at the start of block.
    1419                                 if ( startContainer.type == CKEDITOR.NODE_TEXT )
    1420                                 {
    1421                                         var textBefore = CKEDITOR.tools.ltrim( startContainer.substring( 0, startOffset ) );
    1422                                         if ( textBefore.length )
    1423                                                 return false;
    1424                                 }
    1425                                 else
    1426                                 {
    1427                                         startNode = startContainer.getChild( startOffset - 1 );
    1428                                         startInclusive = true;
    1429                                 }
     1419                                var textBefore = CKEDITOR.tools.ltrim( startContainer.substring( 0, startOffset ) );
     1420                                if ( textBefore.length )
     1421                                        return false;
    14301422                        }
    14311423                       
    1432                         if ( !startNode )
    1433                                 startNode = startContainer;
     1424                        // Antecipate the trim() call here, so the walker will not make
     1425                        // changes to the DOM, which would not get reflected into this
     1426                        // range otherwise.
     1427                        this.trim();
    14341428
    1435                         var path        = new CKEDITOR.dom.elementPath( startNode ),
    1436                                 walker  = new CKEDITOR.dom.walker( startNode, ( path.block || path.blockLimit ) );
    1437 
    1438                         if ( ( path.block && startNode.equals( path.block ) )
    1439                                 || ( !path.block && startNode.equals( path.blockLimit ) ) )
    1440                         {
    1441                                 return true;
    1442                         }
    1443 
    1444                         walker.startInclusive = startInclusive;
    1445                         walker.evaluator = getCheckStartEndBlockEvalFunction( true );
     1429                        // We need to grab the block element holding the start boundary, so
     1430                        // let's use an element path for it.
     1431                        var path = new CKEDITOR.dom.elementPath( this.startContainer );
    14461432                       
     1433                        // Creates a range starting at the block start until the range start.
     1434                        var walkerRange = this.clone();
     1435                        walkerRange.collapse( true );
     1436                        walkerRange.setStartAt( path.block || path.blockLimit, CKEDITOR.POSITION_AFTER_START );
     1437                       
     1438                        var walker = new CKEDITOR.dom.walker( walkerRange );
     1439                        walker.evaluator = getCheckStartEndBlockEvalFunction( true );
     1440
    14471441                        return walker.checkBackward();
    14481442                },
    14491443
    14501444                checkEndOfBlock : function()
    14511445                {
    14521446                        var endContainer = this.endContainer,
    1453                                 endOffset = this.endOffset,
    1454                                 startNode,
    1455                                 startInclusive;
     1447                                endOffset = this.endOffset;
    14561448
    14571449                        // If the ending node is a text node, and non-empty after the offset,
    14581450                        // then we're surely not at the end of block.
     
    14621454                                if ( textAfter.length )
    14631455                                        return false;
    14641456                        }
    1465                         else
    1466                         {
    1467                                 startNode = endContainer.getChild( endOffset );
    1468                                 startInclusive = !!startNode;
    1469                         }
    14701457
    1471                         if ( !startNode )
    1472                                 startNode = endContainer;
     1458                        // Antecipate the trim() call here, so the walker will not make
     1459                        // changes to the DOM, which would not get reflected into this
     1460                        // range otherwise.
     1461                        this.trim();
    14731462
    1474                         var path        = new CKEDITOR.dom.elementPath( startNode ),
    1475                                 walker  = new CKEDITOR.dom.walker( startNode, ( path.block || path.blockLimit ) );
    1476 
    1477                         if ( ( path.block && startNode.equals( path.block ) )
    1478                                 || ( !path.block && startNode.equals( path.blockLimit ) ) )
    1479                         {
    1480                                 return true;
    1481                         }
    1482 
    1483                         walker.startInclusive = startInclusive;
    1484                         walker.evaluator = getCheckStartEndBlockEvalFunction( false );
     1463                        // We need to grab the block element holding the start boundary, so
     1464                        // let's use an element path for it.
     1465                        var path = new CKEDITOR.dom.elementPath( this.endContainer );
    14851466                       
     1467                        // Creates a range starting at the block start until the range start.
     1468                        var walkerRange = this.clone();
     1469                        walkerRange.collapse( false );
     1470                        walkerRange.setEndAt( path.block || path.blockLimit, CKEDITOR.POSITION_BEFORE_END );
     1471                       
     1472                        var walker = new CKEDITOR.dom.walker( walkerRange );
     1473                        walker.evaluator = getCheckStartEndBlockEvalFunction( false );
     1474
    14861475                        return walker.checkForward();
    14871476                },
    14881477
  • _source/core/dom/walker.js

     
    88        // This function is to be called under a "walker" instance scope.
    99        function iterate( rtl, breakOnFalse )
    1010        {
     11                // Return null if we have reached the end.
    1112                if ( this._.end )
    1213                        return null;
    1314
    1415                var node,
     16                        range = this.range,
     17                        guard,
     18                        userGuard = this.guard,
    1519                        type = this.type,
    1620                        getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
    1721
    18                 var guard = this.guard,
    19                         endNode = this.endNode;
     22                // This is the first call. Initialize it.
     23                if ( !this._.start )
     24                {
     25                        this._.start = 1;
     26                       
     27                        // Trim text nodes and optmize the range boundaries. DOM changes
     28                        // may happen at this point.
     29                        range.trim();
    2030
    21                 if ( endNode )
     31                        // A collapsed range must return null at first call.
     32                        if ( range.collapsed )
     33                        {
     34                                this.end();
     35                                return null;
     36                        }
     37                }
     38
     39                // Create the LTR guard function, if necessary.
     40                if ( !rtl && !this._.guardLTR )
    2241                {
    23                         if ( guard )
     42                        // Gets the node that stops the walker when going LTR.
     43                        var blockerLTR = range.endContainer;
     44                        blockerLTR = blockerLTR.getChild( range.endOffset ) || blockerLTR.getNextSourceNode( true );
     45                       
     46                        this._.guardLTR = function( node )
    2447                        {
    25                                 var originalGuard;
    26                                 guard = function( node )
    27                                 {
    28                                         if ( node.equals( endNode ) )
    29                                                 return false;
     48                                return ( ( !blockerLTR || !node.equals( blockerLTR ) )
     49                                        && ( node.type != CKEDITOR.NODE_ELEMENT || node.name != 'body' ) );
     50                        }
     51                }
     52               
     53                // Create the RTL guard function, if necessary.
     54                if ( rtl && !this._.guardRTL )
     55                {
     56                        // Gets the node that stops the walker when going LTR.
     57                        var blockerRTL = range.startContainer;
     58                        blockerRTL = ( range.startOffset > 0 ) ? blockerRTL.getChild( range.startOffset - 1 ) : blockerRTL.getPreviousSourceNode( true );
     59                       
     60                        this._.guardRTL = function( node )
     61                        {
     62                                return ( ( !blockerRTL || !node.equals( blockerRTL ) )
     63                                        && ( node.type != CKEDITOR.NODE_ELEMENT || node.name != 'body' ) );
     64                        }
     65                }
     66               
     67                // Define which guard function to use.
     68                stopGuard = rtl ? this._.guardRTL : this._.guardLTR;
    3069
    31                                         return originalGuard( node );
    32                                 }
     70                // Make the user defined guard function participate in the process,
     71                // otherwise simply use the boundary guard.
     72                if ( userGuard )
     73                {
     74                        guard = function( node )
     75                        {
     76                                if ( stopGuard( node ) === false )
     77                                        return false;
     78
     79                                return userGuard( node );
    3380                        }
    34                         else
    35                                 guard = endNode;
    3681                }
     82                else
     83                        guard = stopGuard;
    3784
    3885                if ( this.current )
    3986                        node = this.current[ getSourceNodeFn ]( false, type, guard );
    40                 else if ( this.startInclusive )
     87                else
    4188                {
    42                         node = this.startNode;
    43                         if ( this.guard && this.guard( node ) === false )
    44                                 node = null;
     89                        // Get the first node to be returned.
     90
     91                        if ( rtl )
     92                        {
     93                                node = range.endContainer;
     94                                node = ( range.endOffset > 0 ) ? node.getChild( range.endOffset - 1 ) : node.getPreviousSourceNode( true, type, guard );
     95                        }
     96                        else
     97                        {
     98                                node = range.startContainer;
     99                                node = node.getChild( range.startOffset ) || node.getNextSourceNode( true, type, guard );
     100                        }
    45101                }
    46                 else
    47                         node = this.startNode[ getSourceNodeFn ]( true, type, guard );
    48102
    49103                while ( node && !this._.end )
    50104                {
    51105                        this.current = node;
    52106
    53                         if ( node == this.endNode && !this.endInclusive )
    54                                 break;
    55 
    56107                        if ( !this.evaluator || this.evaluator( node ) !== false )
    57108                                return node;
    58109                        else if ( breakOnFalse && this.evaluator )
     
    65116                return this.current = null;
    66117        }
    67118
    68         function iterateToLast( rtl )
    69         {
    70                 var node, last = null;
     119//      function iterateToLast( rtl )
     120//      {
     121//              var node, last = null;
    71122
    72                 while ( node = iterate.call( this, rtl ) )
    73                         last = node;
     123//              while ( node = iterate.call( this, rtl ) )
     124//                      last = node;
    74125
    75                 return last;
    76         }
     126//              return last;
     127//      }
    77128
    78129        CKEDITOR.dom.walker = CKEDITOR.tools.createClass(
    79130        {
    80131                /**
    81                  * Utility class to "walk" inside a DOM tree starting from a specific
    82                  * node. Each step in the walk can be preciselly controlled.
     132                 * Utility class to "walk" the DOM inside a range boundaries. If
     133                 * necessary, partially included nodes (text nodes) are broken to
     134                 * reflect the boundaries limits, so DOM and range changes may happen.
     135                 * Outside changes to the range may break the walker.
     136                 *
     137                 * The walker may return nodes that are not totaly included into the
     138                 * range boundaires. Let's take the following range representation,
     139                 * where the square brackets indicate the boundaries:
     140                 *
     141                 * [<p>Some <b>sample] text</b>
     142                 *
     143                 * While walking forward into the above range, the following nodes are
     144                 * returned: <p>, "Some ", <b> and "sample". Going
     145                 * backwards instead we have: "sample" and "Some ". So note that the
     146                 * walker always returns nodes when "entering" them, but not when
     147                 * "leaving" them. The guard function is instead called both when
     148                 * entering and leaving nodes.
     149                 *
    83150                 * @constructor
    84                  * @param {CKEDITOR.dom.node} startNode The node from wich the walk
    85                  *              will start.
    86                  * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
    87                  *              in the walk. No more nodes are retrieved after touching or
    88                  *              passing it.
     151                 * @param {CKEDITOR.dom.range} range The range within which walk.
    89152                 */
    90                 $ : function( startNode, endNode )
     153                $ : function( range )
    91154                {
    92                         /**
    93                          * The node from which start walking.
    94                          * @type {CKEDITOR.dom.node}
    95                          */
    96                         this.startNode = startNode;
     155                        this.range = range;
    97156
    98157                        /**
    99                          * The end boundary node of the walk.
    100                          * @type {CKEDITOR.dom.node}
    101                          */
    102                         this.endNode = endNode;
    103 
    104                         /**
    105                          * Indicates that the start node is to be included in the walk.
    106                          * @name CKEDITOR.pluginDefinition.prototype.startInclusive
    107                          * @property
    108                          * @type Boolean
    109                          * @default false
    110                          */
    111                         // this.startInclusive = false;
    112 
    113                         /**
    114                          * Indicates that the end node is to be included in the walk.
    115                          * @name CKEDITOR.pluginDefinition.prototype.endInclusive
    116                          * @property
    117                          * @type Boolean
    118                          * @default false
    119                          */
    120                         // this.endInclusive = false;
    121 
    122                         /**
    123158                         * A function executed for every matched node, to check whether
    124159                         * it's to be considered into the walk or not. If not provided, all
    125160                         * matched nodes are considered good.
     
    146181                        this._ = {};
    147182                },
    148183
     184//              statics :
     185//              {
     186//                      /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.
     187//                       * @param {CKEDITOR.dom.node} startNode The node from wich the walk
     188//                       *              will start.
     189//                       * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
     190//                       *              in the walk. No more nodes are retrieved after touching or
     191//                       *              passing it. If not provided, the walker stops at the
     192//                       *              <body> closing boundary.
     193//                       * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the
     194//                       *              provided nodes.
     195//                       */
     196//                      createOnNodes : function( startNode, endNode, startInclusive, endInclusive )
     197//                      {
     198//                              var range = new CKEDITOR.dom.range();
     199//                              range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
     200
     201//                              if ( endNode )
     202//                                      range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
     203//                              else
     204//                                      range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;
     205
     206//                              return new CKEDITOR.dom.walker( range );
     207//                      }
     208//              },
     209
    149210                proto :
    150211                {
    151212                        /**
     
    166227                        {
    167228                                return iterate.call( this );
    168229                        },
    169 
     230                       
    170231                        /**
    171232                         * Retrieves the previous node (at left).
    172233                         * @returns {CKEDITOR.dom.node} The previous node or null if no more
     
    178239                        },
    179240
    180241                        /**
    181                          * Executes a full walk forward (to the right), until no more nodes
    182                          * are available, returning the last valid node.
    183                          * @returns {CKEDITOR.dom.node} The last node at the right or null
    184                          *              if no valid nodes are available.
    185                          */
    186                         lastForward : function()
    187                         {
    188                                 return iterateToLast.call( this );
    189                         },
    190 
    191                         /**
    192                          * Executes a full walk backwards (to the left), until no more nodes
    193                          * are available, returning the last valid node.
    194                          * @returns {CKEDITOR.dom.node} The last node at the left or null
    195                          *              if no valid nodes are available.
    196                          */
    197                         lastBackward : function()
    198                         {
    199                                 return iterateToLast.call( this, true );
    200                         },
    201 
    202                         /**
    203242                         * Check all nodes at right, executing the evaluation fuction.
    204243                         * @returns {Boolean} "false" if the evaluator function returned
    205244                         *              "false" for any of the matched nodes. Otherwise "true".
     
    218257                        {
    219258                                return iterate.call( this, true, true ) !== false;
    220259                        }
     260
     261// The following features have been originally included in the implementation,
     262// but they are not used anywhere in the code, so they got commented out.
     263
     264//                      /**
     265//                       * Executes a full walk forward (to the right), until no more nodes
     266//                       * are available, returning the last valid node.
     267//                       * @returns {CKEDITOR.dom.node} The last node at the right or null
     268//                       *              if no valid nodes are available.
     269//                       */
     270//                      lastForward : function()
     271//                      {
     272//                              return iterateToLast.call( this );
     273//                      },
     274
     275//                      /**
     276//                       * Executes a full walk backwards (to the left), until no more nodes
     277//                       * are available, returning the last valid node.
     278//                       * @returns {CKEDITOR.dom.node} The last node at the left or null
     279//                       *              if no valid nodes are available.
     280//                       */
     281//                      lastBackward : function()
     282//                      {
     283//                              return iterateToLast.call( this, true );
     284//                      }
    221285                }
    222286        });
    223287})();
© 2003 – 2022, CKSource sp. z o.o. sp.k. All rights reserved. | Terms of use | Privacy policy