8
0

node.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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. * @param {document.Element|Null} parent Node parent.
  19. * @param {Array} attrs Array of attributes.
  20. */
  21. constructor( parent, attrs ) {
  22. /**
  23. * Parent element.
  24. *
  25. * @readonly
  26. * @property {document.Element} parent
  27. */
  28. this.parent = parent;
  29. /**
  30. * Array of attributes.
  31. *
  32. * @property {Array} attr
  33. */
  34. this.attrs = attrs || [];
  35. }
  36. hasAttr( attr ) {
  37. return this.getAttr( attr ) !== null;
  38. }
  39. getAttr( attr ) {
  40. var i, len;
  41. if ( attr instanceof Attribute ) {
  42. for ( i = 0, len = this.attrs.length; i < len; i++ ) {
  43. if ( this.attrs[ i ].isEqual( attr ) ) {
  44. return this.attrs[ i ];
  45. }
  46. }
  47. } else {
  48. for ( i = 0, len = this.attrs.length; i < len; i++ ) {
  49. if ( this.attrs[ i ].key == attr ) {
  50. return this.attrs[ i ];
  51. }
  52. }
  53. }
  54. return null;
  55. }
  56. /**
  57. * Position of the node in the parent element.
  58. *
  59. * @readonly
  60. * @property {Number} positionInParent
  61. */
  62. get positionInParent() {
  63. var pos;
  64. // No parent or child doesn't exist in parent's children.
  65. if ( !this.parent || ( pos = this.parent.children.indexOf( this ) ) == -1 ) {
  66. return null;
  67. }
  68. return pos;
  69. }
  70. /**
  71. * Dept of the node, which equals total number of its parents.
  72. *
  73. * @readonly
  74. * @property {Number} depth
  75. */
  76. get depth() {
  77. var depth = 0;
  78. var parent = this.parent;
  79. while ( parent ) {
  80. depth++;
  81. parent = parent.parent;
  82. }
  83. return depth;
  84. }
  85. /**
  86. * Nodes next sibling or null if it is the last child.
  87. *
  88. * @readonly
  89. * @property {document.Node|Null} nextSibling
  90. */
  91. get nextSibling() {
  92. var pos = this.positionInParent;
  93. return ( pos !== null && this.parent.children[ pos + 1 ] ) || null;
  94. }
  95. /**
  96. * Nodes previous sibling or null if it is the last child.
  97. *
  98. * @readonly
  99. * @property {document.Node|Null} previousSibling
  100. */
  101. get previousSibling() {
  102. var pos = this.positionInParent;
  103. return ( pos !== null && this.parent.children[ pos - 1 ] ) || null;
  104. }
  105. getPath() {
  106. var path = [];
  107. var node = this; // jscs:ignore safeContextKeyword
  108. while ( node.parent ) {
  109. path.unshift( node.positionInParent );
  110. node = node.parent;
  111. }
  112. return path;
  113. }
  114. toJSON() {
  115. var json = utils.clone( this );
  116. // Due to circular references we need to remove parent reference.
  117. json.parent = this.parent ? this.parent.name : null;
  118. return json;
  119. }
  120. }
  121. return Node;
  122. } );