[ Index ]
 

Code source de FCKeditor 2.4

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/editor/_source/classes/ -> fckw3crange.js (source)

   1  /*
   2   * FCKeditor - The text editor for Internet - http://www.fckeditor.net
   3   * Copyright (C) 2003-2007 Frederico Caldeira Knabben
   4   * 
   5   * == BEGIN LICENSE ==
   6   * 
   7   * Licensed under the terms of any of the following licenses at your
   8   * choice:
   9   * 
  10   *  - GNU General Public License Version 2 or later (the "GPL")
  11   *    http://www.gnu.org/licenses/gpl.html
  12   * 
  13   *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
  14   *    http://www.gnu.org/licenses/lgpl.html
  15   * 
  16   *  - Mozilla Public License Version 1.1 or later (the "MPL")
  17   *    http://www.mozilla.org/MPL/MPL-1.1.html
  18   * 
  19   * == END LICENSE ==
  20   * 
  21   * File Name: fckw3crange.js
  22   *     This class partially implements the W3C DOM Range for browser that don't
  23   *     support the standards (like IE):
  24   *     http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html
  25   * 
  26   * File Authors:
  27   *         Frederico Caldeira Knabben (www.fckeditor.net)
  28   */
  29  
  30  var FCKW3CRange = function( parentDocument )
  31  {
  32      this._Document = parentDocument ;
  33  
  34      this.startContainer    = null ;
  35      this.startOffset    = null ;
  36      this.endContainer    = null ;
  37      this.endOffset        = null ;
  38      this.collapsed        = true ;
  39  }
  40  
  41  FCKW3CRange.CreateRange = function( parentDocument )
  42  {
  43      // We could opt to use the Range implentation of the browsers. The problem
  44      // is that every browser have different bugs on their implementations,
  45      // mostly related to different interpretations of the W3C specifications.
  46      // So, for now, let's use our implementation and pray for browsers fixings
  47      // soon. Otherwise will go crazy on trying to find out workarounds.
  48      /*
  49      // Get the browser implementation of the range, if available.
  50      if ( parentDocument.createRange )
  51      {
  52          var range = parentDocument.createRange() ;
  53          if ( typeof( range.startContainer ) != 'undefined' )
  54              return range ;
  55      }
  56      */
  57      return new FCKW3CRange( parentDocument ) ;
  58  }
  59  
  60  FCKW3CRange.CreateFromRange = function( parentDocument, sourceRange )
  61  {
  62      var range = FCKW3CRange.CreateRange( parentDocument ) ;
  63      range.setStart( sourceRange.startContainer, sourceRange.startOffset ) ;
  64      range.setEnd( sourceRange.endContainer, sourceRange.endOffset ) ;
  65      return range ;
  66  }
  67  
  68  FCKW3CRange.prototype = 
  69  {
  70  
  71      _UpdateCollapsed : function()
  72      {
  73        this.collapsed = ( this.startContainer == this.endContainer && this.startOffset == this.endOffset ) ;
  74      },
  75  
  76      // W3C requires a check for the new position. If it is after the end
  77      // boundary, the range should be collapsed to the new start. It seams we
  78      // will not need this check for our use of this class so we can ignore it for now.
  79      setStart : function( refNode, offset )
  80      {
  81          this.startContainer    = refNode ;
  82          this.startOffset    = offset ;
  83          
  84          if ( !this.endContainer )
  85          {
  86              this.endContainer    = refNode ;
  87              this.endOffset        = offset ;
  88          }
  89  
  90          this._UpdateCollapsed() ;
  91      },
  92      
  93      // W3C requires a check for the new position. If it is before the start
  94      // boundary, the range should be collapsed to the new end. It seams we
  95      // will not need this check for our use of this class so we can ignore it for now.
  96      setEnd : function( refNode, offset )
  97      {
  98          this.endContainer    = refNode ;
  99          this.endOffset        = offset ;
 100          
 101          if ( !this.startContainer )
 102          {
 103              this.startContainer    = refNode ;
 104              this.startOffset    = offset ;
 105          }
 106  
 107          this._UpdateCollapsed() ;
 108      },
 109  
 110      setStartAfter : function( refNode )
 111      {
 112          this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
 113      },
 114  
 115      setStartBefore : function( refNode )
 116      {
 117          this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
 118      },
 119  
 120      setEndAfter : function( refNode )
 121      {
 122          this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
 123      },
 124  
 125      setEndBefore : function( refNode )
 126      {
 127          this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
 128      },
 129      
 130      collapse : function( toStart )
 131      {
 132          if ( toStart )
 133          {
 134              this.endContainer    = this.startContainer ;
 135              this.endOffset        = this.startOffset ;
 136          }
 137          else
 138          {
 139              this.startContainer    = this.endContainer ;
 140              this.startOffset    = this.endOffset ;
 141          }
 142          
 143          this.collapsed = true ;
 144      },
 145  
 146      selectNodeContents : function( refNode )
 147      {
 148          this.setStart( refNode, 0 ) ;
 149          this.setEnd( refNode, refNode.nodeType == 3 ? refNode.data.length : refNode.childNodes.length ) ;
 150      },
 151  
 152      insertNode : function( newNode )
 153      {
 154          var startContainer = this.startContainer ;
 155          var startOffset = this.startOffset ;
 156          
 157          // If we are in a text node.
 158          if ( startContainer.nodeType == 3 )
 159          {
 160              startContainer.splitText( startOffset ) ;
 161  
 162              // Check if it is necessary to update the end boundary.
 163              if ( startContainer == this.endContainer )
 164                  this.setEnd( startContainer.nextSibling, this.endOffset - this.startOffset ) ;
 165              
 166              // Insert the new node it after the text node.
 167              FCKDomTools.InsertAfterNode( startContainer, newNode ) ;
 168      
 169              return ;
 170          }
 171          else
 172          {
 173              // Simply insert the new node before the current start node.
 174              startContainer.insertBefore( newNode, startContainer.childNodes[ startOffset ] || null ) ;
 175  
 176              // Check if it is necessary to update the end boundary.
 177              if ( startContainer == this.endContainer )
 178              {
 179                  this.endOffset++ ;
 180                  this.collapsed = false ;
 181              }
 182          }
 183      },
 184  
 185      deleteContents : function()
 186      {
 187          if ( this.collapsed )
 188              return ;
 189          
 190          this._ExecContentsAction( 0 ) ;
 191      },
 192  
 193      extractContents : function()
 194      {
 195          var docFrag = new FCKDocumentFragment( this._Document ) ;
 196  
 197          if ( !this.collapsed )
 198              this._ExecContentsAction( 1, docFrag ) ;
 199  
 200          return docFrag ;
 201      },
 202  
 203      // The selection may be lost when clonning (due to the splitText() call).
 204      cloneContents : function()
 205      {
 206          var docFrag = new FCKDocumentFragment( this._Document ) ;
 207  
 208          if ( !this.collapsed )
 209              this._ExecContentsAction( 2, docFrag ) ;
 210  
 211          return docFrag ;
 212      },
 213  
 214      _ExecContentsAction : function( action, docFrag )
 215      {    
 216          var startNode    = this.startContainer ;
 217          var endNode        = this.endContainer ;
 218          
 219          var startOffset    = this.startOffset ;
 220          var endOffset    = this.endOffset ;
 221          
 222          var removeStartNode    = false ;
 223          var removeEndNode    = false ;
 224          
 225          // Check the start and end nodes and make the necessary removals or changes.
 226          
 227          // Start from the end, otherwise DOM mutations (splitText) made in the
 228          // start boundary may interfere on the results here.
 229  
 230          // For text containers, we must simply split the node and point to the
 231          // second part. The removal will be handled by the rest of the code .
 232          if ( endNode.nodeType == 3 )
 233              endNode = endNode.splitText( endOffset ) ;
 234          else
 235          {
 236              // If the end container has children and the offset is pointing
 237              // to a child, then we should start from it.
 238              if ( endNode.childNodes.length > 0 )
 239              {
 240                  // If the offset points after the last node.
 241                  if ( endOffset > endNode.childNodes.length - 1 )
 242                  {
 243                      // Let's create a temporary node and mark it for removal.
 244                      endNode = FCKDomTools.InsertAfterNode( endNode.lastChild, this._Document.createTextNode('') ) ;
 245                      removeEndNode = true ;
 246                  }
 247                  else
 248                      endNode = endNode.childNodes[ endOffset ] ;
 249              }
 250          }
 251  
 252          // For text containers, we must simply split the node. The removal will
 253          // be handled by the rest of the code .
 254          if ( startNode.nodeType == 3 )
 255          {
 256              startNode.splitText( startOffset ) ;
 257              
 258              // In cases the end node is the same as the start node, the above
 259              // splitting will also split the end, so me must move the end to
 260              // the second part of the split.
 261              if ( startNode == endNode )
 262                  endNode = startNode.nextSibling ;
 263          }
 264          else
 265          {
 266              // If the start container has children and the offset is pointing
 267              // to a child, then we should start from its previous sibling.
 268              if ( startNode.childNodes.length > 0 &&  startOffset <= startNode.childNodes.length - 1 )
 269              {
 270                  // If the offset points to the first node, we don't have a
 271                  // sibling, so let's use the first one, but mark it for removal.
 272                  if ( startOffset == 0 )
 273                  {
 274                      // Let's create a temporary node and mark it for removal.
 275                      startNode = startNode.insertBefore( this._Document.createTextNode(''), startNode.firstChild ) ;
 276                      removeStartNode = true ;
 277                  }
 278                  else
 279                      startNode = startNode.childNodes[ startOffset ].previousSibling ;
 280              }
 281          }
 282          
 283          // Get the parent nodes tree for the start and end boundaries.
 284          var startParents    = FCKDomTools.GetParents( startNode ) ;
 285          var endParents        = FCKDomTools.GetParents( endNode ) ;
 286          
 287          // Compare them, to find the top most siblings.
 288          var i, topStart, topEnd ;
 289          
 290          for ( i = 0 ; i < startParents.length ; i++ )
 291          {
 292              topStart    = startParents[i] ;
 293              topEnd        = endParents[i] ;
 294              
 295              // The compared nodes will match until we find the top most
 296              // siblings (different nodes that have the same parent).
 297              // "i" will hold the index in the parants array for the top 
 298              // most element.
 299              if ( topStart != topEnd )
 300                  break ;
 301          }
 302  
 303          var clone, levelStartNode, levelClone, currentNode, currentSibling ;
 304          
 305          if ( docFrag )
 306              clone = docFrag.RootNode ;
 307  
 308          // Remove all successive sibling nodes for every node in the
 309          // startParents tree.
 310          for ( var j = i ; j < startParents.length ; j++ )
 311          {
 312              levelStartNode = startParents[j] ;
 313              
 314              // For Extract and Clone, we must clone this level.
 315              if ( clone && levelStartNode != startNode )        // action = 0 = Delete
 316                  levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == startNode ) ) ;
 317              
 318              currentNode = levelStartNode.nextSibling ;
 319              
 320              while( currentNode )
 321              {
 322                  // Stop processing when the current node matches a node in the
 323                  // endParents tree or if it is the endNode.
 324                  if ( currentNode == endParents[j] || currentNode == endNode )
 325                      break ;
 326                  
 327                  // Cache the next sibling.
 328                  currentSibling = currentNode.nextSibling ;
 329  
 330                  // If clonning, just clone it.
 331                  if ( action == 2 )    // 2 = Clone
 332                      clone.appendChild( currentNode.cloneNode( true ) ) ;
 333                  else
 334                  {
 335                      // Both Delete and Extract will remove the node.
 336                      currentNode.parentNode.removeChild( currentNode ) ;
 337                      
 338                      // When Extracting, move the removed node to the docFrag.
 339                      if ( action == 1 )    // 1 = Extract
 340                          clone.appendChild( currentNode ) ;
 341                  }
 342                  
 343                  currentNode = currentSibling ;
 344              }
 345              
 346              if ( clone )
 347                  clone = levelClone ;
 348          }
 349          
 350          if ( docFrag )
 351              clone = docFrag.RootNode ;
 352  
 353          // Remove all previous sibling nodes for every node in the
 354          // endParents tree.
 355          for ( var k = i ; k < endParents.length ; k++ )
 356          {
 357              levelStartNode = endParents[k] ;
 358              
 359              // For Extract and Clone, we must clone this level.
 360              if ( action > 0 && levelStartNode != endNode )        // action = 0 = Delete
 361                  levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == endNode ) ) ;
 362  
 363              // The processing of siblings may have already been done by the parent.
 364              if ( !startParents[k] || levelStartNode.parentNode != startParents[k].parentNode )
 365              {
 366                  currentNode = levelStartNode.previousSibling ;
 367  
 368                  while( currentNode )
 369                  {
 370                      // Stop processing when the current node matches a node in the
 371                      // startParents tree or if it is the startNode.
 372                      if ( currentNode == startParents[k] || currentNode == startNode )
 373                          break ;
 374  
 375                      // Cache the next sibling.
 376                      currentSibling = currentNode.previousSibling ;
 377  
 378                      // If clonning, just clone it.
 379                      if ( action == 2 )    // 2 = Clone
 380                          clone.insertBefore( currentNode.cloneNode( true ), clone.firstChild ) ;
 381                      else
 382                      {
 383                          // Both Delete and Extract will remove the node.
 384                          currentNode.parentNode.removeChild( currentNode ) ;
 385                          
 386                          // When Extracting, mode the removed node to the docFrag.
 387                          if ( action == 1 )    // 1 = Extract
 388                              clone.insertBefore( currentNode, clone.firstChild ) ;
 389                      }
 390  
 391                      currentNode = currentSibling ;
 392                  }
 393              }
 394              
 395              if ( clone )
 396                  clone = levelClone ;
 397          }
 398          
 399          if ( action == 2 )        // 2 = Clone.
 400          {
 401              // No changes in the DOM should be done, so fix the split text (if any).
 402  
 403              var startTextNode = this.startContainer ;
 404              if ( startTextNode.nodeType == 3 )
 405              {
 406                  startTextNode.data += startTextNode.nextSibling.data ;
 407                  startTextNode.parentNode.removeChild( startTextNode.nextSibling ) ;
 408              }
 409  
 410              var endTextNode = this.endContainer ;
 411              if ( endTextNode.nodeType == 3 && endTextNode.nextSibling )
 412              {
 413                  endTextNode.data += endTextNode.nextSibling.data ;
 414                  endTextNode.parentNode.removeChild( endTextNode.nextSibling ) ;
 415              }
 416          }
 417          else
 418          {
 419              // Collapse the range.
 420      
 421              // If a node has been partially selected, collapse the range between
 422              // topStart and topEnd. Otherwise, simply collapse it to the start. (W3C specs).
 423              if ( topStart && topEnd && ( startNode.parentNode != topStart.parentNode || endNode.parentNode != topEnd.parentNode ) )
 424                  this.setStart( topEnd.parentNode, FCKDomTools.GetIndexOf( topEnd ) ) ;
 425              
 426              // Collapse it to the start.
 427              this.collapse( true ) ;
 428          }
 429  
 430          // Cleanup any marked node.
 431          if( removeStartNode )
 432              startNode.parentNode.removeChild( startNode ) ;
 433  
 434          if( removeEndNode && endNode.parentNode )
 435              endNode.parentNode.removeChild( endNode ) ;
 436      },
 437  
 438      cloneRange : function()
 439      {
 440          return FCKW3CRange.CreateFromRange( this._Document, this ) ;
 441      },
 442  
 443      toString : function()
 444      {
 445          var docFrag = this.cloneContents() ;
 446          
 447          var tmpDiv = this._Document.createElement( 'div' ) ;
 448          docFrag.AppendTo( tmpDiv ) ;
 449          
 450          return tmpDiv.textContent || tmpDiv.innerText ;
 451      }
 452  } ;


Généré le : Sun Feb 25 15:28:05 2007 par Balluche grâce à PHPXref 0.7