[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/core/dom/ -> walker.js (source)

   1  /*

   2  Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.

   3  For licensing, see LICENSE.html or http://ckeditor.com/license

   4  */
   5  
   6  (function()
   7  {
   8      // This function is to be called under a "walker" instance scope.

   9  	function iterate( rtl, breakOnFalse )
  10      {
  11          // Return null if we have reached the end.

  12          if ( this._.end )
  13              return null;
  14  
  15          var node,
  16              range = this.range,
  17              guard,
  18              userGuard = this.guard,
  19              type = this.type,
  20              getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
  21  
  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();
  30  
  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 )
  41          {
  42              // Gets the node that stops the walker when going LTR.

  43              var limitLTR = range.endContainer,
  44                  blockerLTR = limitLTR.getChild( range.endOffset );
  45  
  46              this._.guardLTR = function( node, movingOut )
  47              {
  48                  return ( ( !movingOut || !limitLTR.equals( node ) )
  49                      && ( !blockerLTR || !node.equals( blockerLTR ) )
  50                      && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || node.getName() != 'body' ) );
  51              };
  52          }
  53  
  54          // Create the RTL guard function, if necessary.

  55          if ( rtl && !this._.guardRTL )
  56          {
  57              // Gets the node that stops the walker when going LTR.

  58              var limitRTL = range.startContainer,
  59                  blockerRTL = ( range.startOffset > 0 ) && limitRTL.getChild( range.startOffset - 1 );
  60  
  61              this._.guardRTL = function( node, movingOut )
  62              {
  63                  return ( ( !movingOut || !limitRTL.equals( node ) )
  64                      && ( !blockerRTL || !node.equals( blockerRTL ) )
  65                      && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || node.getName() != 'body' ) );
  66              };
  67          }
  68  
  69          // Define which guard function to use.

  70          var stopGuard = rtl ? this._.guardRTL : this._.guardLTR;
  71  
  72          // Make the user defined guard function participate in the process,

  73          // otherwise simply use the boundary guard.

  74          if ( userGuard )
  75          {
  76              guard = function( node, movingOut )
  77              {
  78                  if ( stopGuard( node, movingOut ) === false )
  79                      return false;
  80  
  81                  return userGuard( node, movingOut );
  82              };
  83          }
  84          else
  85              guard = stopGuard;
  86  
  87          if ( this.current )
  88              node = this.current[ getSourceNodeFn ]( false, type, guard );
  89          else
  90          {
  91              // Get the first node to be returned.

  92  
  93              if ( rtl )
  94              {
  95                  node = range.endContainer;
  96  
  97                  if ( range.endOffset > 0 )
  98                  {
  99                      node = node.getChild( range.endOffset - 1 );
 100                      if ( guard( node ) === false )
 101                          node = null;
 102                  }
 103                  else
 104                      node = ( guard ( node, true ) === false ) ?
 105                          null : node.getPreviousSourceNode( true, type, guard );
 106              }
 107              else
 108              {
 109                  node = range.startContainer;
 110                  node = node.getChild( range.startOffset );
 111  
 112                  if ( node )
 113                  {
 114                      if ( guard( node ) === false )
 115                          node = null;
 116                  }
 117                  else
 118                      node = ( guard ( range.startContainer, true ) === false ) ?
 119                          null : range.startContainer.getNextSourceNode( true, type, guard ) ;
 120              }
 121          }
 122  
 123          while ( node && !this._.end )
 124          {
 125              this.current = node;
 126  
 127              if ( !this.evaluator || this.evaluator( node ) !== false )
 128              {
 129                  if ( !breakOnFalse )
 130                      return node;
 131              }
 132              else if ( breakOnFalse && this.evaluator )
 133                  return false;
 134  
 135              node = node[ getSourceNodeFn ]( false, type, guard );
 136          }
 137  
 138          this.end();
 139          return this.current = null;
 140      }
 141  
 142  	function iterateToLast( rtl )
 143      {
 144          var node, last = null;
 145  
 146          while ( ( node = iterate.call( this, rtl ) ) )
 147              last = node;
 148  
 149          return last;
 150      }
 151  
 152      CKEDITOR.dom.walker = CKEDITOR.tools.createClass(
 153      {
 154          /**

 155           * Utility class to "walk" the DOM inside a range boundaries. If

 156           * necessary, partially included nodes (text nodes) are broken to

 157           * reflect the boundaries limits, so DOM and range changes may happen.

 158           * Outside changes to the range may break the walker.

 159           *

 160           * The walker may return nodes that are not totaly included into the

 161           * range boundaires. Let's take the following range representation,

 162           * where the square brackets indicate the boundaries:

 163           *

 164           * [<p>Some <b>sample] text</b>

 165           *

 166           * While walking forward into the above range, the following nodes are

 167           * returned: <p>, "Some ", <b> and "sample". Going

 168           * backwards instead we have: "sample" and "Some ". So note that the

 169           * walker always returns nodes when "entering" them, but not when

 170           * "leaving" them. The guard function is instead called both when

 171           * entering and leaving nodes.

 172           *

 173           * @constructor

 174           * @param {CKEDITOR.dom.range} range The range within which walk.

 175           */
 176          $ : function( range )
 177          {
 178              this.range = range;
 179  
 180              /**

 181               * A function executed for every matched node, to check whether

 182               * it's to be considered into the walk or not. If not provided, all

 183               * matched nodes are considered good.

 184               * If the function returns "false" the node is ignored.

 185               * @name CKEDITOR.dom.walker.prototype.evaluator

 186               * @property

 187               * @type Function

 188               */
 189              // this.evaluator = null;

 190  
 191              /**

 192               * A function executed for every node the walk pass by to check

 193               * whether the walk is to be finished. It's called when both

 194               * entering and exiting nodes, as well as for the matched nodes.

 195               * If this function returns "false", the walking ends and no more

 196               * nodes are evaluated.

 197               * @name CKEDITOR.dom.walker.prototype.guard

 198               * @property

 199               * @type Function

 200               */
 201              // this.guard = null;

 202  
 203              /** @private */

 204              this._ = {};
 205          },
 206  
 207  //        statics :

 208  //        {

 209  //            /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.

 210  //             * @param {CKEDITOR.dom.node} startNode The node from wich the walk

 211  //             *        will start.

 212  //             * @param {CKEDITOR.dom.node} [endNode] The last node to be considered

 213  //             *        in the walk. No more nodes are retrieved after touching or

 214  //             *        passing it. If not provided, the walker stops at the

 215  //             *        <body> closing boundary.

 216  //             * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the

 217  //             *        provided nodes.

 218  //             */

 219  //            createOnNodes : function( startNode, endNode, startInclusive, endInclusive )

 220  //            {

 221  //                var range = new CKEDITOR.dom.range();

 222  //                if ( startNode )

 223  //                    range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;

 224  //                else

 225  //                    range.setStartAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_AFTER_START ) ;

 226  //

 227  //                if ( endNode )

 228  //                    range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;

 229  //                else

 230  //                    range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;

 231  //

 232  //                return new CKEDITOR.dom.walker( range );

 233  //            }

 234  //        },

 235  //

 236          proto :
 237          {
 238              /**

 239               * Stop walking. No more nodes are retrieved if this function gets

 240               * called.

 241               */
 242              end : function()
 243              {
 244                  this._.end = 1;
 245              },
 246  
 247              /**

 248               * Retrieves the next node (at right).

 249               * @returns {CKEDITOR.dom.node} The next node or null if no more

 250               *        nodes are available.

 251               */
 252              next : function()
 253              {
 254                  return iterate.call( this );
 255              },
 256  
 257              /**

 258               * Retrieves the previous node (at left).

 259               * @returns {CKEDITOR.dom.node} The previous node or null if no more

 260               *        nodes are available.

 261               */
 262              previous : function()
 263              {
 264                  return iterate.call( this, true );
 265              },
 266  
 267              /**

 268               * Check all nodes at right, executing the evaluation fuction.

 269               * @returns {Boolean} "false" if the evaluator function returned

 270               *        "false" for any of the matched nodes. Otherwise "true".

 271               */
 272              checkForward : function()
 273              {
 274                  return iterate.call( this, false, true ) !== false;
 275              },
 276  
 277              /**

 278               * Check all nodes at left, executing the evaluation fuction.

 279               * @returns {Boolean} "false" if the evaluator function returned

 280               *        "false" for any of the matched nodes. Otherwise "true".

 281               */
 282              checkBackward : function()
 283              {
 284                  return iterate.call( this, true, true ) !== false;
 285              },
 286  
 287              /**

 288               * Executes a full walk forward (to the right), until no more nodes

 289               * are available, returning the last valid node.

 290               * @returns {CKEDITOR.dom.node} The last node at the right or null

 291               *        if no valid nodes are available.

 292               */
 293              lastForward : function()
 294              {
 295                  return iterateToLast.call( this );
 296              },
 297  
 298              /**

 299               * Executes a full walk backwards (to the left), until no more nodes

 300               * are available, returning the last valid node.

 301               * @returns {CKEDITOR.dom.node} The last node at the left or null

 302               *        if no valid nodes are available.

 303               */
 304              lastBackward : function()
 305              {
 306                  return iterateToLast.call( this, true );
 307              },
 308  
 309              reset : function()
 310              {
 311                  delete this.current;
 312                  this._ = {};
 313              }
 314  
 315          }
 316      });
 317  
 318      /*

 319       * Anything whose display computed style is block, list-item, table,

 320       * table-row-group, table-header-group, table-footer-group, table-row,

 321       * table-column-group, table-column, table-cell, table-caption, or whose node

 322       * name is hr, br (when enterMode is br only) is a block boundary.

 323       */
 324      var blockBoundaryDisplayMatch =
 325      {
 326          block : 1,
 327          'list-item' : 1,
 328          table : 1,
 329          'table-row-group' : 1,
 330          'table-header-group' : 1,
 331          'table-footer-group' : 1,
 332          'table-row' : 1,
 333          'table-column-group' : 1,
 334          'table-column' : 1,
 335          'table-cell' : 1,
 336          'table-caption' : 1
 337      },
 338      blockBoundaryNodeNameMatch = { hr : 1 };
 339  
 340      CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames )
 341      {
 342          var nodeNameMatches = CKEDITOR.tools.extend( {},
 343                                                      blockBoundaryNodeNameMatch, customNodeNames || {} );
 344  
 345          return blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] ||
 346              nodeNameMatches[ this.getName() ];
 347      };
 348  
 349      CKEDITOR.dom.walker.blockBoundary = function( customNodeNames )
 350      {
 351          return function( node , type )
 352          {
 353              return ! ( node.type == CKEDITOR.NODE_ELEMENT
 354                          && node.isBlockBoundary( customNodeNames ) );
 355          };
 356      };
 357  
 358      CKEDITOR.dom.walker.listItemBoundary = function()
 359      {
 360              return this.blockBoundary( { br : 1 } );
 361      };
 362  
 363      /**

 364       * Whether the to-be-evaluated node is a bookmark node OR bookmark node

 365       * inner contents.

 366       * @param {Boolean} contentOnly Whether only test againt the text content of

 367       * bookmark node instead of the element itself(default).

 368       * @param {Boolean} isReject Whether should return 'false' for the bookmark

 369       * node instead of 'true'(default).

 370       */
 371      CKEDITOR.dom.walker.bookmark = function( contentOnly, isReject )
 372      {
 373  		function isBookmarkNode( node )
 374          {
 375              return ( node && node.getName
 376                      && node.getName() == 'span'
 377                      && node.hasAttribute('_fck_bookmark') );
 378          }
 379  
 380          return function( node )
 381          {
 382              var isBookmark, parent;
 383              // Is bookmark inner text node?

 384              isBookmark = ( node && !node.getName && ( parent = node.getParent() )
 385                          && isBookmarkNode( parent ) );
 386              // Is bookmark node?

 387              isBookmark = contentOnly ? isBookmark : isBookmark || isBookmarkNode( node );
 388              return isReject ^ isBookmark;
 389          };
 390      };
 391  
 392      /**

 393       * Whether the node is a text node containing only whitespaces characters.

 394       * @param isReject

 395       */
 396      CKEDITOR.dom.walker.whitespaces = function( isReject )
 397      {
 398          return function( node )
 399          {
 400              var isWhitespace = node && ( node.type == CKEDITOR.NODE_TEXT )
 401                              && !CKEDITOR.tools.trim( node.getText() );
 402              return isReject ^ isWhitespace;
 403          };
 404      };
 405  
 406      /**

 407       * Whether the node is invisible in wysiwyg mode.

 408       * @param isReject

 409       */
 410      CKEDITOR.dom.walker.invisible = function( isReject )
 411      {
 412          var whitespace = CKEDITOR.dom.walker.whitespaces();
 413          return function( node )
 414          {
 415              // Nodes that take no spaces in wysiwyg:

 416              // 1. White-spaces but not including NBSP;

 417              // 2. Empty inline elements, e.g. <b></b> we're checking here

 418              // 'offsetHeight' instead of 'offsetWidth' for properly excluding

 419              // all sorts of empty paragraph, e.g. <br />.

 420              var isInvisible = whitespace( node ) || node.is && !node.$.offsetHeight;
 421              return isReject ^ isInvisible;
 422          };
 423      };
 424  
 425      var tailNbspRegex = /^[\t\r\n ]*(?:&nbsp;|\xa0)$/,
 426          isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),
 427          isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ),
 428          fillerEvaluator = function( element )
 429          {
 430              return isNotBookmark( element ) && isNotWhitespaces( element );
 431          };
 432  
 433      // Check if there's a filler node at the end of an element, and return it.

 434      CKEDITOR.dom.element.prototype.getBogus = function ()
 435      {
 436          var tail = this.getLast( fillerEvaluator );
 437          if ( tail && ( !CKEDITOR.env.ie ? tail.is && tail.is( 'br' )
 438                  : tail.getText && tailNbspRegex.test( tail.getText() ) ) )
 439          {
 440              return tail;
 441          }
 442          return false;
 443      };
 444  
 445  })();


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7