[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/plugins/domiterator/ -> plugin.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  /**

   7   * @file DOM iterator, which iterates over list items, lines and paragraphs.

   8   */
   9  
  10  CKEDITOR.plugins.add( 'domiterator' );
  11  
  12  (function()
  13  {
  14      /**

  15       * @name CKEDITOR.dom.iterator

  16       */
  17  	function iterator( range )
  18      {
  19          if ( arguments.length < 1 )
  20              return;
  21  
  22          this.range = range;
  23          this.forceBrBreak = false;
  24  
  25          // Whether include <br>s into the enlarged range.(#3730).

  26          this.enlargeBr = true;
  27          this.enforceRealBlocks = false;
  28  
  29          this._ || ( this._ = {} );
  30      }
  31  
  32      var beginWhitespaceRegex = /^[\r\n\t ]+$/,
  33          isBookmark = CKEDITOR.dom.walker.bookmark();
  34  
  35      iterator.prototype = {
  36          getNextParagraph : function( blockTag )
  37          {
  38              // The block element to be returned.

  39              var block;
  40  
  41              // The range object used to identify the paragraph contents.

  42              var range;
  43  
  44              // Indicats that the current element in the loop is the last one.

  45              var isLast;
  46  
  47              // Instructs to cleanup remaining BRs.

  48              var removePreviousBr, removeLastBr;
  49  
  50              // This is the first iteration. Let's initialize it.

  51              if ( !this._.lastNode )
  52              {
  53                  range = this.range.clone();
  54  
  55                  // Shrink the range to exclude harmful "noises" (#4087, #4450, #5435).

  56                  range.shrink( CKEDITOR.NODE_ELEMENT, true );
  57  
  58                  range.enlarge( this.forceBrBreak || !this.enlargeBr ?
  59                                 CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS );
  60  
  61                  var walker = new CKEDITOR.dom.walker( range ),
  62                      ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true );
  63                  // Avoid anchor inside bookmark inner text.

  64                  walker.evaluator = ignoreBookmarkTextEvaluator;
  65                  this._.nextNode = walker.next();
  66                  // TODO: It's better to have walker.reset() used here.

  67                  walker = new CKEDITOR.dom.walker( range );
  68                  walker.evaluator = ignoreBookmarkTextEvaluator;
  69                  var lastNode = walker.previous();
  70                  this._.lastNode = lastNode.getNextSourceNode( true );
  71  
  72                  // We may have an empty text node at the end of block due to [3770].

  73                  // If that node is the lastNode, it would cause our logic to leak to the

  74                  // next block.(#3887)

  75                  if ( this._.lastNode &&
  76                          this._.lastNode.type == CKEDITOR.NODE_TEXT &&
  77                          !CKEDITOR.tools.trim( this._.lastNode.getText( ) ) &&
  78                          this._.lastNode.getParent().isBlockBoundary() )
  79                  {
  80                      var testRange = new CKEDITOR.dom.range( range.document );
  81                      testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END );
  82                      if ( testRange.checkEndOfBlock() )
  83                      {
  84                          var path = new CKEDITOR.dom.elementPath( testRange.endContainer );
  85                          var lastBlock = path.block || path.blockLimit;
  86                          this._.lastNode = lastBlock.getNextSourceNode( true );
  87                      }
  88                  }
  89  
  90                  // Probably the document end is reached, we need a marker node.

  91                  if ( !this._.lastNode )
  92                  {
  93                      this._.lastNode = this._.docEndMarker = range.document.createText( '' );
  94                      this._.lastNode.insertAfter( lastNode );
  95                  }
  96  
  97                  // Let's reuse this variable.

  98                  range = null;
  99              }
 100  
 101              var currentNode = this._.nextNode;
 102              lastNode = this._.lastNode;
 103  
 104              this._.nextNode = null;
 105              while ( currentNode )
 106              {
 107                  // closeRange indicates that a paragraph boundary has been found,

 108                  // so the range can be closed.

 109                  var closeRange = false;
 110  
 111                  // includeNode indicates that the current node is good to be part

 112                  // of the range. By default, any non-element node is ok for it.

 113                  var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ),
 114                      continueFromSibling = false;
 115  
 116                  // If it is an element node, let's check if it can be part of the

 117                  // range.

 118                  if ( !includeNode )
 119                  {
 120                      var nodeName = currentNode.getName();
 121  
 122                      if ( currentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) )
 123                      {
 124                          // <br> boundaries must be part of the range. It will

 125                          // happen only if ForceBrBreak.

 126                          if ( nodeName == 'br' )
 127                              includeNode = true;
 128                          else if ( !range && !currentNode.getChildCount() && nodeName != 'hr' )
 129                          {
 130                              // If we have found an empty block, and haven't started

 131                              // the range yet, it means we must return this block.

 132                              block = currentNode;
 133                              isLast = currentNode.equals( lastNode );
 134                              break;
 135                          }
 136  
 137                          // The range must finish right before the boundary,

 138                          // including possibly skipped empty spaces. (#1603)

 139                          if ( range )
 140                          {
 141                              range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
 142  
 143                              // The found boundary must be set as the next one at this

 144                              // point. (#1717)

 145                              if ( nodeName != 'br' )
 146                                  this._.nextNode = currentNode;
 147                          }
 148  
 149                          closeRange = true;
 150                      }
 151                      else
 152                      {
 153                          // If we have child nodes, let's check them.

 154                          if ( currentNode.getFirst() )
 155                          {
 156                              // If we don't have a range yet, let's start it.

 157                              if ( !range )
 158                              {
 159                                  range = new CKEDITOR.dom.range( this.range.document );
 160                                  range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
 161                              }
 162  
 163                              currentNode = currentNode.getFirst();
 164                              continue;
 165                          }
 166                          includeNode = true;
 167                      }
 168                  }
 169                  else if ( currentNode.type == CKEDITOR.NODE_TEXT )
 170                  {
 171                      // Ignore normal whitespaces (i.e. not including &nbsp; or

 172                      // other unicode whitespaces) before/after a block node.

 173                      if ( beginWhitespaceRegex.test( currentNode.getText() ) )
 174                          includeNode = false;
 175                  }
 176  
 177                  // The current node is good to be part of the range and we are

 178                  // starting a new range, initialize it first.

 179                  if ( includeNode && !range )
 180                  {
 181                      range = new CKEDITOR.dom.range( this.range.document );
 182                      range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
 183                  }
 184  
 185                  // The last node has been found.

 186                  isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) );
 187  
 188                  // If we are in an element boundary, let's check if it is time

 189                  // to close the range, otherwise we include the parent within it.

 190                  if ( range && !closeRange )
 191                  {
 192                      while ( !currentNode.getNext() && !isLast )
 193                      {
 194                          var parentNode = currentNode.getParent();
 195  
 196                          if ( parentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) )
 197                          {
 198                              closeRange = true;
 199                              isLast = isLast || ( parentNode.equals( lastNode) );
 200                              break;
 201                          }
 202  
 203                          currentNode = parentNode;
 204                          includeNode = true;
 205                          isLast = ( currentNode.equals( lastNode ) );
 206                          continueFromSibling = true;
 207                      }
 208                  }
 209  
 210                  // Now finally include the node.

 211                  if ( includeNode )
 212                      range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END );
 213  
 214                  currentNode = currentNode.getNextSourceNode( continueFromSibling, null, lastNode );
 215                  isLast = !currentNode;
 216  
 217                  // We have found a block boundary. Let's close the range and move out of the

 218                  // loop.

 219                  if ( isLast || ( closeRange && range ) )
 220                          break;
 221              }
 222  
 223              // Now, based on the processed range, look for (or create) the block to be returned.

 224              if ( !block )
 225              {
 226                  // If no range has been found, this is the end.

 227                  if ( !range )
 228                  {
 229                      this._.docEndMarker && this._.docEndMarker.remove();
 230                      this._.nextNode = null;
 231                      return null;
 232                  }
 233  
 234                  var startPath = new CKEDITOR.dom.elementPath( range.startContainer );
 235                  var startBlockLimit = startPath.blockLimit,
 236                      checkLimits = { div : 1, th : 1, td : 1 };
 237                  block = startPath.block;
 238  
 239                  if ( !block
 240                          && !this.enforceRealBlocks
 241                          && checkLimits[ startBlockLimit.getName() ]
 242                          && range.checkStartOfBlock()
 243                          && range.checkEndOfBlock() )
 244                      block = startBlockLimit;
 245                  else if ( !block || ( this.enforceRealBlocks && block.getName() == 'li' ) )
 246                  {
 247                      // Create the fixed block.

 248                      block = this.range.document.createElement( blockTag || 'p' );
 249  
 250                      // Move the contents of the temporary range to the fixed block.

 251                      range.extractContents().appendTo( block );
 252                      block.trim();
 253  
 254                      // Insert the fixed block into the DOM.

 255                      range.insertNode( block );
 256  
 257                      removePreviousBr = removeLastBr = true;
 258                  }
 259                  else if ( block.getName() != 'li' )
 260                  {
 261                      // If the range doesn't includes the entire contents of the

 262                      // block, we must split it, isolating the range in a dedicated

 263                      // block.

 264                      if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() )
 265                      {
 266                          // The resulting block will be a clone of the current one.

 267                          block = block.clone( false );
 268  
 269                          // Extract the range contents, moving it to the new block.

 270                          range.extractContents().appendTo( block );
 271                          block.trim();
 272  
 273                          // Split the block. At this point, the range will be in the

 274                          // right position for our intents.

 275                          var splitInfo = range.splitBlock();
 276  
 277                          removePreviousBr = !splitInfo.wasStartOfBlock;
 278                          removeLastBr = !splitInfo.wasEndOfBlock;
 279  
 280                          // Insert the new block into the DOM.

 281                          range.insertNode( block );
 282                      }
 283                  }
 284                  else if ( !isLast )
 285                  {
 286                      // LIs are returned as is, with all their children (due to the

 287                      // nested lists). But, the next node is the node right after

 288                      // the current range, which could be an <li> child (nested

 289                      // lists) or the next sibling <li>.

 290  
 291                      this._.nextNode = ( block.equals( lastNode ) ? null :
 292                          range.getBoundaryNodes().endNode.getNextSourceNode( true, null, lastNode ) );
 293                  }
 294              }
 295  
 296              if ( removePreviousBr )
 297              {
 298                  var previousSibling = block.getPrevious();
 299                  if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT )
 300                  {
 301                      if ( previousSibling.getName() == 'br' )
 302                          previousSibling.remove();
 303                      else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' )
 304                          previousSibling.getLast().remove();
 305                  }
 306              }
 307  
 308              if ( removeLastBr )
 309              {
 310                  // Ignore bookmark nodes.(#3783)

 311                  var bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true );
 312  
 313                  var lastChild = block.getLast();
 314                  if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' )
 315                  {
 316                      // Take care not to remove the block expanding <br> in non-IE browsers.

 317                      if ( CKEDITOR.env.ie
 318                           || lastChild.getPrevious( bookmarkGuard )
 319                           || lastChild.getNext( bookmarkGuard ) )
 320                          lastChild.remove();
 321                  }
 322              }
 323  
 324              // Get a reference for the next element. This is important because the

 325              // above block can be removed or changed, so we can rely on it for the

 326              // next interation.

 327              if ( !this._.nextNode )
 328              {
 329                  this._.nextNode = ( isLast || block.equals( lastNode ) ) ? null :
 330                      block.getNextSourceNode( true, null, lastNode );
 331              }
 332  
 333              return block;
 334          }
 335      };
 336  
 337      CKEDITOR.dom.range.prototype.createIterator = function()
 338      {
 339          return new iterator( this );
 340      };
 341  })();


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