Tree.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Tree.js
  3. *
  4. * @author realor
  5. */
  6. class Tree {
  7. constructor(element) {
  8. this.rootsElem = document.createElement('ul')
  9. element.appendChild(this.rootsElem)
  10. this.rootsElem.className = 'tree'
  11. this.roots = []
  12. }
  13. addNode(object, action, className) {
  14. const treeNode = new TreeNode(this, null, object, action, className)
  15. this.roots.push(treeNode)
  16. this.rootsElem.appendChild(treeNode.itemElem)
  17. return treeNode
  18. }
  19. getNodeLabel(value) {
  20. return value
  21. }
  22. clear() {
  23. this.rootsElem.innerHTML = ''
  24. this.roots = []
  25. }
  26. }
  27. class TreeNode {
  28. constructor(tree, parentTreeNode, value, action, className) {
  29. this.tree = tree
  30. this.parent = parentTreeNode
  31. this._value = value
  32. this.children = []
  33. this.itemElem = document.createElement('li')
  34. this.linkElem = document.createElement('a')
  35. this.linkElem.href = '#'
  36. this.itemElem.appendChild(this.linkElem)
  37. this.updateLabel()
  38. if (action) {
  39. this.linkElem.addEventListener('click', action)
  40. }
  41. this.childrenElem = null
  42. this.buttonElem = null
  43. if (className) this.itemElem.className = className
  44. }
  45. addNode(value, action, className) {
  46. if (this.childrenElem === null) {
  47. this.itemElem.innerHTML = ''
  48. this.itemElem.classList.add('collapsed')
  49. this.buttonElem = document.createElement('button')
  50. this.buttonElem.addEventListener('click', () => this.toggle())
  51. this.itemElem.appendChild(this.buttonElem)
  52. this.itemElem.appendChild(this.linkElem)
  53. this.childrenElem = document.createElement('ul')
  54. this.itemElem.appendChild(this.childrenElem)
  55. } else {
  56. this.buttonElem.style.display = ''
  57. }
  58. const treeNode = new TreeNode(this.tree, this, value, action, className)
  59. this.childrenElem.appendChild(treeNode.itemElem)
  60. this.children.push(treeNode)
  61. return treeNode
  62. }
  63. remove() {
  64. if (this.parent) {
  65. let index = this.parent.children.indexOf(this)
  66. if (index > -1) {
  67. this.parent.children.splice(index, 1)
  68. this.parent.childrenElem.removeChild(this.itemElem)
  69. if (this.parent.children.length === 0) {
  70. this.parent.buttonElem.style.display = 'none'
  71. }
  72. }
  73. } // remove from tree.roots
  74. else {
  75. let index = this.tree.roots.indexOf(this)
  76. if (index > -1) {
  77. this.tree.roots.splice(index, 1)
  78. this.tree.rootsElem.removeChild(this.itemElem)
  79. }
  80. }
  81. }
  82. set value(value) {
  83. this._value = value
  84. this.updateLabel()
  85. }
  86. get value() {
  87. return this._value
  88. }
  89. addClass(className) {
  90. this.linkElem.classList.add(className)
  91. }
  92. removeClass(className) {
  93. this.linkElem.classList.remove(className)
  94. }
  95. updateLabel() {
  96. this.linkElem.innerHTML = this.tree.getNodeLabel(this._value)
  97. }
  98. isExpanded() {
  99. return this.itemElem.classList.contains('expanded')
  100. }
  101. isCollapsed() {
  102. return this.itemElem.classList.contains('collapsed')
  103. }
  104. toggle() {
  105. if (this.isExpanded()) {
  106. this.collapse()
  107. } else {
  108. this.expand()
  109. }
  110. }
  111. expand(levels = 1) {
  112. if (levels > 0) {
  113. this.itemElem.classList.remove('collapsed')
  114. this.itemElem.classList.add('expanded')
  115. levels--
  116. if (levels > 0) {
  117. for (let i = 0; i < this.children.length; i++) {
  118. this.children[i].expand(levels)
  119. }
  120. }
  121. }
  122. }
  123. collapse(levels = 1) {
  124. if (levels > 0) {
  125. this.itemElem.classList.remove('expanded')
  126. this.itemElem.classList.add('collapsed')
  127. levels--
  128. if (levels > 0) {
  129. for (let i = 0; i < this.children.length; i++) {
  130. this.children[i].collapse(levels)
  131. }
  132. }
  133. }
  134. }
  135. expandAncestors(makeVisible = false) {
  136. let curr = this.parent
  137. while (curr) {
  138. curr.expand()
  139. curr = curr.parent
  140. }
  141. if (makeVisible) {
  142. this.linkElem.scrollIntoView({ block: 'center', inline: 'nearest' })
  143. }
  144. }
  145. clear() {
  146. if (this.childrenElem) {
  147. this.childrenElem.innerHTML = ''
  148. this.buttonElem.style.display = 'none'
  149. }
  150. this.children = []
  151. }
  152. }
  153. export { Tree }