[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/core/dom/ -> node.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   * @fileOverview Defines the {@link CKEDITOR.dom.node} class, which is the base

   8   *        class for classes that represent DOM nodes.

   9   */
  10  
  11  /**

  12   * Base class for classes representing DOM nodes. This constructor may return

  13   * and instance of classes that inherits this class, like

  14   * {@link CKEDITOR.dom.element} or {@link CKEDITOR.dom.text}.

  15   * @augments CKEDITOR.dom.domObject

  16   * @param {Object} domNode A native DOM node.

  17   * @constructor

  18   * @see CKEDITOR.dom.element

  19   * @see CKEDITOR.dom.text

  20   * @example

  21   */
  22  CKEDITOR.dom.node = function( domNode )
  23  {
  24      if ( domNode )
  25      {
  26          switch ( domNode.nodeType )
  27          {
  28              // Safari don't consider document as element node type. (#3389)

  29              case CKEDITOR.NODE_DOCUMENT :
  30                  return new CKEDITOR.dom.document( domNode );
  31  
  32              case CKEDITOR.NODE_ELEMENT :
  33                  return new CKEDITOR.dom.element( domNode );
  34  
  35              case CKEDITOR.NODE_TEXT :
  36                  return new CKEDITOR.dom.text( domNode );
  37          }
  38  
  39          // Call the base constructor.

  40          CKEDITOR.dom.domObject.call( this, domNode );
  41      }
  42  
  43      return this;
  44  };
  45  
  46  CKEDITOR.dom.node.prototype = new CKEDITOR.dom.domObject();
  47  
  48  /**

  49   * Element node type.

  50   * @constant

  51   * @example

  52   */
  53  CKEDITOR.NODE_ELEMENT = 1;
  54  
  55  /**

  56   * Document node type.

  57   * @constant

  58   * @example

  59   */
  60  CKEDITOR.NODE_DOCUMENT = 9;
  61  
  62  /**

  63   * Text node type.

  64   * @constant

  65   * @example

  66   */
  67  CKEDITOR.NODE_TEXT = 3;
  68  
  69  /**

  70   * Comment node type.

  71   * @constant

  72   * @example

  73   */
  74  CKEDITOR.NODE_COMMENT = 8;
  75  
  76  CKEDITOR.NODE_DOCUMENT_FRAGMENT = 11;
  77  
  78  CKEDITOR.POSITION_IDENTICAL = 0;
  79  CKEDITOR.POSITION_DISCONNECTED = 1;
  80  CKEDITOR.POSITION_FOLLOWING = 2;
  81  CKEDITOR.POSITION_PRECEDING = 4;
  82  CKEDITOR.POSITION_IS_CONTAINED = 8;
  83  CKEDITOR.POSITION_CONTAINS = 16;
  84  
  85  CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype,
  86      /** @lends CKEDITOR.dom.node.prototype */

  87      {
  88          /**

  89           * Makes this node child of another element.

  90           * @param {CKEDITOR.dom.element} element The target element to which append

  91           *        this node.

  92           * @returns {CKEDITOR.dom.element} The target element.

  93           * @example

  94           * var p = new CKEDITOR.dom.element( 'p' );

  95           * var strong = new CKEDITOR.dom.element( 'strong' );

  96           * strong.appendTo( p );

  97           *

  98           * // result: "<p><strong></strong></p>"

  99           */
 100          appendTo : function( element, toStart )
 101          {
 102              element.append( this, toStart );
 103              return element;
 104          },
 105  
 106          clone : function( includeChildren, cloneId )
 107          {
 108              var $clone = this.$.cloneNode( includeChildren );
 109  
 110              if ( !cloneId )
 111              {
 112                  var removeIds = function( node )
 113                  {
 114                      if ( node.nodeType != CKEDITOR.NODE_ELEMENT )
 115                          return;
 116  
 117                      node.removeAttribute( 'id', false ) ;
 118                      node.removeAttribute( '_cke_expando', false ) ;
 119  
 120                      var childs = node.childNodes;
 121                      for ( var i=0 ; i < childs.length ; i++ )
 122                          removeIds( childs[ i ] );
 123                  };
 124  
 125                  // The "id" attribute should never be cloned to avoid duplication.

 126                  removeIds( $clone );
 127              }
 128  
 129              return new CKEDITOR.dom.node( $clone );
 130          },
 131  
 132          hasPrevious : function()
 133          {
 134              return !!this.$.previousSibling;
 135          },
 136  
 137          hasNext : function()
 138          {
 139              return !!this.$.nextSibling;
 140          },
 141  
 142          /**

 143           * Inserts this element after a node.

 144           * @param {CKEDITOR.dom.node} node The that will preceed this element.

 145           * @returns {CKEDITOR.dom.node} The node preceeding this one after

 146           *        insertion.

 147           * @example

 148           * var em = new CKEDITOR.dom.element( 'em' );

 149           * var strong = new CKEDITOR.dom.element( 'strong' );

 150           * strong.insertAfter( em );

 151           *

 152           * // result: "&lt;em&gt;&lt;/em&gt;&lt;strong&gt;&lt;/strong&gt;"

 153           */
 154          insertAfter : function( node )
 155          {
 156              node.$.parentNode.insertBefore( this.$, node.$.nextSibling );
 157              return node;
 158          },
 159  
 160          /**

 161           * Inserts this element before a node.

 162           * @param {CKEDITOR.dom.node} node The that will be after this element.

 163           * @returns {CKEDITOR.dom.node} The node being inserted.

 164           * @example

 165           * var em = new CKEDITOR.dom.element( 'em' );

 166           * var strong = new CKEDITOR.dom.element( 'strong' );

 167           * strong.insertBefore( em );

 168           *

 169           * // result: "&lt;strong&gt;&lt;/strong&gt;&lt;em&gt;&lt;/em&gt;"

 170           */
 171          insertBefore : function( node )
 172          {
 173              node.$.parentNode.insertBefore( this.$, node.$ );
 174              return node;
 175          },
 176  
 177          insertBeforeMe : function( node )
 178          {
 179              this.$.parentNode.insertBefore( node.$, this.$ );
 180              return node;
 181          },
 182  
 183          /**

 184           * Retrieves a uniquely identifiable tree address for this node.

 185           * The tree address returns is an array of integers, with each integer

 186           * indicating a child index of a DOM node, starting from

 187           * document.documentElement.

 188           *

 189           * For example, assuming <body> is the second child from <html> (<head>

 190           * being the first), and we'd like to address the third child under the

 191           * fourth child of body, the tree address returned would be:

 192           * [1, 3, 2]

 193           *

 194           * The tree address cannot be used for finding back the DOM tree node once

 195           * the DOM tree structure has been modified.

 196           */
 197          getAddress : function( normalized )
 198          {
 199              var address = [];
 200              var $documentElement = this.getDocument().$.documentElement;
 201              var node = this.$;
 202  
 203              while ( node && node != $documentElement )
 204              {
 205                  var parentNode = node.parentNode;
 206                  var currentIndex = -1;
 207  
 208                  if ( parentNode )
 209                  {
 210                      for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
 211                      {
 212                          var candidate = parentNode.childNodes[i];
 213  
 214                          if ( normalized &&
 215                                  candidate.nodeType == 3 &&
 216                                  candidate.previousSibling &&
 217                                  candidate.previousSibling.nodeType == 3 )
 218                          {
 219                              continue;
 220                          }
 221  
 222                          currentIndex++;
 223  
 224                          if ( candidate == node )
 225                              break;
 226                      }
 227  
 228                      address.unshift( currentIndex );
 229                  }
 230  
 231                  node = parentNode;
 232              }
 233  
 234              return address;
 235          },
 236  
 237          /**

 238           * Gets the document containing this element.

 239           * @returns {CKEDITOR.dom.document} The document.

 240           * @example

 241           * var element = CKEDITOR.document.getById( 'example' );

 242           * alert( <b>element.getDocument().equals( CKEDITOR.document )</b> );  // "true"

 243           */
 244          getDocument : function()
 245          {
 246              var document = new CKEDITOR.dom.document( this.$.ownerDocument || this.$.parentNode.ownerDocument );
 247  
 248              return (
 249              this.getDocument = function()
 250                  {
 251                      return document;
 252                  })();
 253          },
 254  
 255          getIndex : function()
 256          {
 257              var $ = this.$;
 258  
 259              var currentNode = $.parentNode && $.parentNode.firstChild;
 260              var currentIndex = -1;
 261  
 262              while ( currentNode )
 263              {
 264                  currentIndex++;
 265  
 266                  if ( currentNode == $ )
 267                      return currentIndex;
 268  
 269                  currentNode = currentNode.nextSibling;
 270              }
 271  
 272              return -1;
 273          },
 274  
 275          getNextSourceNode : function( startFromSibling, nodeType, guard )
 276          {
 277              // If "guard" is a node, transform it in a function.

 278              if ( guard && !guard.call )
 279              {
 280                  var guardNode = guard;
 281                  guard = function( node )
 282                  {
 283                      return !node.equals( guardNode );
 284                  };
 285              }
 286  
 287              var node = ( !startFromSibling && this.getFirst && this.getFirst() ),
 288                  parent;
 289  
 290              // Guarding when we're skipping the current element( no children or 'startFromSibling' ).

 291              // send the 'moving out' signal even we don't actually dive into.

 292              if ( !node )
 293              {
 294                  if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
 295                      return null;
 296                  node = this.getNext();
 297              }
 298  
 299              while ( !node && ( parent = ( parent || this ).getParent() ) )
 300              {
 301                  // The guard check sends the "true" paramenter to indicate that

 302                  // we are moving "out" of the element.

 303                  if ( guard && guard( parent, true ) === false )
 304                      return null;
 305  
 306                  node = parent.getNext();
 307              }
 308  
 309              if ( !node )
 310                  return null;
 311  
 312              if ( guard && guard( node ) === false )
 313                  return null;
 314  
 315              if ( nodeType && nodeType != node.type )
 316                  return node.getNextSourceNode( false, nodeType, guard );
 317  
 318              return node;
 319          },
 320  
 321          getPreviousSourceNode : function( startFromSibling, nodeType, guard )
 322          {
 323              if ( guard && !guard.call )
 324              {
 325                  var guardNode = guard;
 326                  guard = function( node )
 327                  {
 328                      return !node.equals( guardNode );
 329                  };
 330              }
 331  
 332              var node = ( !startFromSibling && this.getLast && this.getLast() ),
 333                  parent;
 334  
 335              // Guarding when we're skipping the current element( no children or 'startFromSibling' ).

 336              // send the 'moving out' signal even we don't actually dive into.

 337              if ( !node )
 338              {
 339                  if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
 340                      return null;
 341                  node = this.getPrevious();
 342              }
 343  
 344              while ( !node && ( parent = ( parent || this ).getParent() ) )
 345              {
 346                  // The guard check sends the "true" paramenter to indicate that

 347                  // we are moving "out" of the element.

 348                  if ( guard && guard( parent, true ) === false )
 349                      return null;
 350  
 351                  node = parent.getPrevious();
 352              }
 353  
 354              if ( !node )
 355                  return null;
 356  
 357              if ( guard && guard( node ) === false )
 358                  return null;
 359  
 360              if ( nodeType && node.type != nodeType )
 361                  return node.getPreviousSourceNode( false, nodeType, guard );
 362  
 363              return node;
 364          },
 365  
 366          getPrevious : function( evaluator )
 367          {
 368              var previous = this.$, retval;
 369              do
 370              {
 371                  previous = previous.previousSibling;
 372                  retval = previous && new CKEDITOR.dom.node( previous );
 373              }
 374              while ( retval && evaluator && !evaluator( retval ) )
 375              return retval;
 376          },
 377  
 378          /**

 379           * Gets the node that follows this element in its parent's child list.

 380           * @param {Function} evaluator Filtering the result node.

 381           * @returns {CKEDITOR.dom.node} The next node or null if not available.

 382           * @example

 383           * var element = CKEDITOR.dom.element.createFromHtml( '&lt;div&gt;&lt;b&gt;Example&lt;/b&gt; &lt;i&gt;next&lt;/i&gt;&lt;/div&gt;' );

 384           * var first = <b>element.getFirst().getNext()</b>;

 385           * alert( first.getName() );  // "i"

 386           */
 387          getNext : function( evaluator )
 388          {
 389              var next = this.$, retval;
 390              do
 391              {
 392                  next = next.nextSibling;
 393                  retval = next && new CKEDITOR.dom.node( next );
 394              }
 395              while ( retval && evaluator && !evaluator( retval ) )
 396              return retval;
 397          },
 398  
 399          /**

 400           * Gets the parent element for this node.

 401           * @returns {CKEDITOR.dom.element} The parent element.

 402           * @example

 403           * var node = editor.document.getBody().getFirst();

 404           * var parent = node.<b>getParent()</b>;

 405           * alert( node.getName() );  // "body"

 406           */
 407          getParent : function()
 408          {
 409              var parent = this.$.parentNode;
 410              return ( parent && parent.nodeType == 1 ) ? new CKEDITOR.dom.node( parent ) : null;
 411          },
 412  
 413          getParents : function( closerFirst )
 414          {
 415              var node = this;
 416              var parents = [];
 417  
 418              do
 419              {
 420                  parents[  closerFirst ? 'push' : 'unshift' ]( node );
 421              }
 422              while ( ( node = node.getParent() ) )
 423  
 424              return parents;
 425          },
 426  
 427          getCommonAncestor : function( node )
 428          {
 429              if ( node.equals( this ) )
 430                  return this;
 431  
 432              if ( node.contains && node.contains( this ) )
 433                  return node;
 434  
 435              var start = this.contains ? this : this.getParent();
 436  
 437              do
 438              {
 439                  if ( start.contains( node ) )
 440                      return start;
 441              }
 442              while ( ( start = start.getParent() ) );
 443  
 444              return null;
 445          },
 446  
 447          getPosition : function( otherNode )
 448          {
 449              var $ = this.$;
 450              var $other = otherNode.$;
 451  
 452              if ( $.compareDocumentPosition )
 453                  return $.compareDocumentPosition( $other );
 454  
 455              // IE and Safari have no support for compareDocumentPosition.

 456  
 457              if ( $ == $other )
 458                  return CKEDITOR.POSITION_IDENTICAL;
 459  
 460              // Only element nodes support contains and sourceIndex.

 461              if ( this.type == CKEDITOR.NODE_ELEMENT && otherNode.type == CKEDITOR.NODE_ELEMENT )
 462              {
 463                  if ( $.contains )
 464                  {
 465                      if ( $.contains( $other ) )
 466                          return CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING;
 467  
 468                      if ( $other.contains( $ ) )
 469                          return CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
 470                  }
 471  
 472                  if ( 'sourceIndex' in $ )
 473                  {
 474                      return ( $.sourceIndex < 0 || $other.sourceIndex < 0 ) ? CKEDITOR.POSITION_DISCONNECTED :
 475                          ( $.sourceIndex < $other.sourceIndex ) ? CKEDITOR.POSITION_PRECEDING :
 476                          CKEDITOR.POSITION_FOLLOWING;
 477                  }
 478              }
 479  
 480              // For nodes that don't support compareDocumentPosition, contains

 481              // or sourceIndex, their "address" is compared.

 482  
 483              var addressOfThis = this.getAddress(),
 484                  addressOfOther = otherNode.getAddress(),
 485                  minLevel = Math.min( addressOfThis.length, addressOfOther.length );
 486  
 487                  // Determinate preceed/follow relationship.

 488                  for ( var i = 0 ; i <= minLevel - 1 ; i++ )
 489                   {
 490                      if ( addressOfThis[ i ] != addressOfOther[ i ] )
 491                      {
 492                          if ( i < minLevel )
 493                          {
 494                              return addressOfThis[ i ] < addressOfOther[ i ] ?
 495                                      CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
 496                          }
 497                          break;
 498                      }
 499                   }
 500  
 501                  // Determinate contains/contained relationship.

 502                  return ( addressOfThis.length < addressOfOther.length ) ?
 503                              CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING :
 504                              CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
 505          },
 506  
 507          /**

 508           * Gets the closes ancestor node of a specified node name.

 509           * @param {String} name Node name of ancestor node.

 510           * @param {Boolean} includeSelf (Optional) Whether to include the current

 511           * node in the calculation or not.

 512           * @returns {CKEDITOR.dom.node} Ancestor node.

 513           */
 514          getAscendant : function( name, includeSelf )
 515          {
 516              var $ = this.$;
 517  
 518              if ( !includeSelf )
 519                  $ = $.parentNode;
 520  
 521              while ( $ )
 522              {
 523                  if ( $.nodeName && $.nodeName.toLowerCase() == name )
 524                      return new CKEDITOR.dom.node( $ );
 525  
 526                  $ = $.parentNode;
 527              }
 528              return null;
 529          },
 530  
 531          hasAscendant : function( name, includeSelf )
 532          {
 533              var $ = this.$;
 534  
 535              if ( !includeSelf )
 536                  $ = $.parentNode;
 537  
 538              while ( $ )
 539              {
 540                  if ( $.nodeName && $.nodeName.toLowerCase() == name )
 541                      return true;
 542  
 543                  $ = $.parentNode;
 544              }
 545              return false;
 546          },
 547  
 548          move : function( target, toStart )
 549          {
 550              target.append( this.remove(), toStart );
 551          },
 552  
 553          /**

 554           * Removes this node from the document DOM.

 555           * @param {Boolean} [preserveChildren] Indicates that the children

 556           *        elements must remain in the document, removing only the outer

 557           *        tags.

 558           * @example

 559           * var element = CKEDITOR.dom.element.getById( 'MyElement' );

 560           * <b>element.remove()</b>;

 561           */
 562          remove : function( preserveChildren )
 563          {
 564              var $ = this.$;
 565              var parent = $.parentNode;
 566  
 567              if ( parent )
 568              {
 569                  if ( preserveChildren )
 570                  {
 571                      // Move all children before the node.

 572                      for ( var child ; ( child = $.firstChild ) ; )
 573                      {
 574                          parent.insertBefore( $.removeChild( child ), $ );
 575                      }
 576                  }
 577  
 578                  parent.removeChild( $ );
 579              }
 580  
 581              return this;
 582          },
 583  
 584          replace : function( nodeToReplace )
 585          {
 586              this.insertBefore( nodeToReplace );
 587              nodeToReplace.remove();
 588          },
 589  
 590          trim : function()
 591          {
 592              this.ltrim();
 593              this.rtrim();
 594          },
 595  
 596          ltrim : function()
 597          {
 598              var child;
 599              while ( this.getFirst && ( child = this.getFirst() ) )
 600              {
 601                  if ( child.type == CKEDITOR.NODE_TEXT )
 602                  {
 603                      var trimmed = CKEDITOR.tools.ltrim( child.getText() ),
 604                          originalLength = child.getLength();
 605  
 606                      if ( !trimmed )
 607                      {
 608                          child.remove();
 609                          continue;
 610                      }
 611                      else if ( trimmed.length < originalLength )
 612                      {
 613                          child.split( originalLength - trimmed.length );
 614  
 615                          // IE BUG: child.remove() may raise JavaScript errors here. (#81)

 616                          this.$.removeChild( this.$.firstChild );
 617                      }
 618                  }
 619                  break;
 620              }
 621          },
 622  
 623          rtrim : function()
 624          {
 625              var child;
 626              while ( this.getLast && ( child = this.getLast() ) )
 627              {
 628                  if ( child.type == CKEDITOR.NODE_TEXT )
 629                  {
 630                      var trimmed = CKEDITOR.tools.rtrim( child.getText() ),
 631                          originalLength = child.getLength();
 632  
 633                      if ( !trimmed )
 634                      {
 635                          child.remove();
 636                          continue;
 637                      }
 638                      else if ( trimmed.length < originalLength )
 639                      {
 640                          child.split( trimmed.length );
 641  
 642                          // IE BUG: child.getNext().remove() may raise JavaScript errors here.

 643                          // (#81)

 644                          this.$.lastChild.parentNode.removeChild( this.$.lastChild );
 645                      }
 646                  }
 647                  break;
 648              }
 649  
 650              if ( !CKEDITOR.env.ie && !CKEDITOR.env.opera )
 651              {
 652                  child = this.$.lastChild;
 653  
 654                  if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' )
 655                  {
 656                      // Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324).

 657                      child.parentNode.removeChild( child ) ;
 658                  }
 659              }
 660          },
 661  
 662          isReadOnly : function()
 663          {
 664              var current = this;
 665              while( current )
 666              {
 667                  if ( current.type == CKEDITOR.NODE_ELEMENT )
 668                  {
 669                      if ( current.is( 'body' ) || current.getCustomData( '_cke_notReadOnly' ) )
 670                          break;
 671  
 672                      if ( current.getAttribute( 'contentEditable' ) == 'false' )
 673                          return current;
 674                      else if ( current.getAttribute( 'contentEditable' ) == 'true' )
 675                          break;
 676                  }
 677                  current = current.getParent();
 678              }
 679  
 680              return false;
 681          }
 682      }
 683  );


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