8
0

node.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. CKEDITOR.define( [ 'document/attribute', 'utils' ], function( Attribute, utils ) {
  7. /**
  8. * Abstract document tree node class.
  9. *
  10. * @class document.Node
  11. */
  12. class Node {
  13. /**
  14. * Creates tree node.
  15. *
  16. * This is an abstract class, it should not be created directly.
  17. *
  18. * Created node has no parent. Parent of the node is set when it is attached to the {@link document.Element}.
  19. *
  20. * @param {Array} attrs Array of attributes.
  21. * @constructor
  22. */
  23. constructor( attrs ) {
  24. /**
  25. * Parent element. Null by default.
  26. *
  27. * @property {document.Element|Null} parent
  28. */
  29. this.parent = null;
  30. /**
  31. * Array of attributes.
  32. *
  33. * Attributes of nodes attached to the document can be changed only be the {@link document.ChangeOpeation}.
  34. *
  35. * @property {Array} attr
  36. */
  37. this.attrs = attrs || [];
  38. }
  39. /**
  40. * Returns true if node contain attribute with the same key and value as given or the same key if the
  41. * given parameter is a string.
  42. *
  43. * @param {document.Attribute|String} attr Attribute or key to compare.
  44. * @returns {Boolean} True if node contains given attribute or attribute with given key.
  45. */
  46. hasAttr( attr ) {
  47. return this.getAttr( attr ) !== null;
  48. }
  49. /**
  50. * Returns attribute if node contain attribute with the same key and value as given or the same key if the
  51. * given parameter is a string.
  52. *
  53. * @param {document.Attribute|String|Null} attr Attribute or key to compare.
  54. * @returns {document.Attribute} Attribute if node contains given attribute or attribute with given key,
  55. * or null if attribute was not found.
  56. */
  57. getAttr( attr ) {
  58. var i, len;
  59. if ( attr instanceof Attribute ) {
  60. for ( i = 0, len = this.attrs.length; i < len; i++ ) {
  61. if ( this.attrs[ i ].isEqual( attr ) ) {
  62. return this.attrs[ i ];
  63. }
  64. }
  65. } else {
  66. for ( i = 0, len = this.attrs.length; i < len; i++ ) {
  67. if ( this.attrs[ i ].key == attr ) {
  68. return this.attrs[ i ];
  69. }
  70. }
  71. }
  72. return null;
  73. }
  74. /**
  75. * Position of the node in the parent element.
  76. *
  77. * @readonly
  78. * @property {Number} positionInParent
  79. */
  80. get positionInParent() {
  81. var pos;
  82. // No parent or child doesn't exist in parent's children.
  83. if ( !this.parent || ( pos = this.parent.getChildIndex( this ) ) == -1 ) {
  84. return null;
  85. }
  86. return pos;
  87. }
  88. /**
  89. * Dept of the node, which equals total number of its parents.
  90. *
  91. * @readonly
  92. * @property {Number} depth
  93. */
  94. get depth() {
  95. var depth = 0;
  96. var parent = this.parent;
  97. while ( parent ) {
  98. depth++;
  99. parent = parent.parent;
  100. }
  101. return depth;
  102. }
  103. /**
  104. * The top parent for the node. If node has no parent it is its own root.
  105. *
  106. * @readonly
  107. * @property {Number} depth
  108. */
  109. get root() {
  110. var root = this; // jscs:ignore safeContextKeyword
  111. while ( root.parent ) {
  112. root = root.parent;
  113. }
  114. return root;
  115. }
  116. /**
  117. * Nodes next sibling or null if it is the last child.
  118. *
  119. * @readonly
  120. * @property {document.Node|Null} nextSibling
  121. */
  122. get nextSibling() {
  123. var pos = this.positionInParent;
  124. return ( pos !== null && this.parent.getChild( pos + 1 ) ) || null;
  125. }
  126. /**
  127. * Nodes previous sibling or null if it is the last child.
  128. *
  129. * @readonly
  130. * @property {document.Node|Null} previousSibling
  131. */
  132. get previousSibling() {
  133. var pos = this.positionInParent;
  134. return ( pos !== null && this.parent.getChild( pos - 1 ) ) || null;
  135. }
  136. /**
  137. * Get path to the node. For example if the node is the second child of the first child of the root then the path
  138. * will be [ 1, 2 ]. This path can be used as a parameter of in {@link document.Position}.
  139. *
  140. * @returns {Array} Path, array of numbers.
  141. */
  142. getPath() {
  143. var path = [];
  144. var node = this; // jscs:ignore safeContextKeyword
  145. while ( node.parent ) {
  146. path.unshift( node.positionInParent );
  147. node = node.parent;
  148. }
  149. return path;
  150. }
  151. /**
  152. * Custom toJSON method to solve child-parent circular dependencies.
  153. *
  154. * @returns {Object} Clone of this object with the parent property replaced with its name.
  155. */
  156. toJSON() {
  157. var json = utils.clone( this );
  158. // Due to circular references we need to remove parent reference.
  159. json.parent = this.parent ? this.parent.name : null;
  160. return json;
  161. }
  162. }
  163. return Node;
  164. } );