node.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. import CKEditorError from '../../utils/ckeditorerror.js';
  7. import EmitterMixin from '../../utils/emittermixin.js';
  8. import mix from '../../utils/mix.js';
  9. /**
  10. * Abstract tree view node class.
  11. *
  12. * @abstract
  13. * @memberOf engine.treeView
  14. */
  15. export default class Node {
  16. /**
  17. * Creates a tree view node.
  18. *
  19. * This is an abstract class, so this constructor should not be used directly.
  20. */
  21. constructor() {
  22. /**
  23. * Parent element. Null by default. Set by {@link engine.treeView.Element#insertChildren}.
  24. *
  25. * @readonly
  26. * @member {engine.treeView.Element|engine.treeView.DocumentFragment|null} engine.treeView.Node#parent
  27. */
  28. this.parent = null;
  29. /**
  30. * {@link engine.treeView.Document} reference.
  31. *
  32. * @protected
  33. * @member {engine.treeView.Document} engine.treeView.Node#_document
  34. */
  35. this._document = null;
  36. }
  37. /**
  38. * Returns index of the node in the parent element or null if the node has no parent.
  39. *
  40. * Throws error if the parent element does not contain this node.
  41. *
  42. * @returns {Number|null} Index of the node in the parent element or null if the node has not parent.
  43. */
  44. getIndex() {
  45. let pos;
  46. if ( !this.parent ) {
  47. return null;
  48. }
  49. // No parent or child doesn't exist in parent's children.
  50. if ( ( pos = this.parent.getChildIndex( this ) ) == -1 ) {
  51. /**
  52. * The node's parent does not contain this node. It means that the document tree is corrupted.
  53. *
  54. * @error treeview-node-not-found-in-parent
  55. */
  56. throw new CKEditorError( 'treeview-node-not-found-in-parent: The node\'s parent does not contain this node.' );
  57. }
  58. return pos;
  59. }
  60. /**
  61. * Returns nodes next sibling or `null` if it is the last child.
  62. *
  63. * @returns {engine.treeView.Node|null} Nodes next sibling or `null` if it is the last child.
  64. */
  65. getNextSibling() {
  66. const index = this.getIndex();
  67. return ( index !== null && this.parent.getChild( index + 1 ) ) || null;
  68. }
  69. /**
  70. * Returns nodes previous sibling or `null` if it is the first child.
  71. *
  72. * @returns {engine.treeView.Node|null} Nodes previous sibling or `null` if it is the first child.
  73. */
  74. getPreviousSibling() {
  75. const index = this.getIndex();
  76. return ( index !== null && this.parent.getChild( index - 1 ) ) || null;
  77. }
  78. /**
  79. * Gets {@link engine.treeView.Document} reference. If the node has {@link engine.treeView.Document}, assign by
  80. * {@link engine.treeView.Node#setDocument} it will be returned. Otherwise {@link engine.treeView.Document} of the parents node
  81. * will be returned. If node has no parent, `null` will be returned.
  82. *
  83. * @returns {engine.treeView.Document|null} Tree view of the node, tree view of the parent or null.
  84. */
  85. getDocument() {
  86. if ( this._document ) {
  87. return this._document;
  88. } else if ( this.parent ) {
  89. return this.parent.getDocument();
  90. } else {
  91. return null;
  92. }
  93. }
  94. /**
  95. * Returns ancestors array of this node.
  96. *
  97. * @param {Object} options Options object.
  98. * @param {Boolean} [options.includeNode=false] When set to `true` this node will be also included in parent's array.
  99. * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from node's parent to root element,
  100. * otherwise root element will be the first item in the array.
  101. * @returns {Array} Array with ancestors.
  102. */
  103. getAncestors( options = { includeNode: false, parentFirst: false } ) {
  104. const ancestors = [];
  105. let parent = options.includeNode ? this : this.parent;
  106. while ( parent !== null ) {
  107. ancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );
  108. parent = parent.parent;
  109. }
  110. return ancestors;
  111. }
  112. /**
  113. * Sets the {@link engine.treeView.Document} of the node. Note that not all of nodes need to have {@link engine.treeView.Document}
  114. * assigned, see {@link engine.treeView.Node#getDocument}.
  115. *
  116. * @param {engine.treeView.Document} document Document.
  117. */
  118. setDocument( document ) {
  119. this._document = document;
  120. }
  121. /**
  122. * Removes node from parent.
  123. */
  124. remove() {
  125. this.parent.removeChildren( this.getIndex() );
  126. }
  127. /**
  128. * @param {engine.treeView.ChangeType} type Type of the change.
  129. * @param {engine.treeView.Node} node Changed node.
  130. * @fires engine.treeView.Node#change
  131. */
  132. _fireChange( type, node ) {
  133. this.fire( 'change', type, node );
  134. if ( this.parent ) {
  135. this.parent._fireChange( type, node );
  136. }
  137. }
  138. /**
  139. * Clones this node.
  140. *
  141. * @method treeView.Node#clone
  142. * @returns {treeView.Node} Clone of this node.
  143. */
  144. /**
  145. * Checks if provided node is similar to this node.
  146. *
  147. * @method treeView.Node#isSimilar
  148. * @returns {Boolean} True if nodes are similar.
  149. */
  150. /**
  151. * Fired when a node changes.
  152. *
  153. * * In case of {@link engine.treeView.Text text nodes} it will be a change of the text data.
  154. * * In case of {@link engine.treeView.Element elements} it will be a change of child nodes or attributes.
  155. *
  156. * Change event is bubbling, it is fired on the ancestors chain.
  157. *
  158. * @event engine.treeView.Node#change
  159. * @param {engine.treeView.ChangeType} Type of the change.
  160. * @param {engine.treeView.Node} Changed node.
  161. */
  162. }
  163. mix( Node, EmitterMixin );