« get me outta code hell

Element.js « primitives « ui - tui-lib - Pure Node.js library for making visual command-line programs (ala vim, ncdu)
about summary refs log tree commit diff
path: root/ui/primitives/Element.js
blob: a5dbea65956535b55b8cf4f9847e90b694cccab0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import EventEmitter from 'node:events'

import exception from 'tui-lib/util/exception'

export default class Element extends EventEmitter {
  // The basic class containing methods for working with an element hierarchy.
  // Generally speaking, you usually want to extend DisplayElement instead of
  // this class.

  constructor() {
    super()

    this.children = []
    this.parent = null
  }

  eachDescendant(fn) {
    // Run a function on this element, all of its children, all of their
    // children, etc.
    fn(this)
    for (const child of this.children) {
      child.eachDescendant(fn)
    }
  }

  addChild(child, afterIndex = this.children.length, {fixLayout = true} = {}) {
    // TODO Don't let a direct ancestor of this be added as a child. Don't
    // let itself be one of its childs either!

    if (child === this) {
      throw exception(
        'EINVALIDHIERARCHY', 'An element cannot be a child of itself')
    }

    child.parent = this

    if (afterIndex === this.children.length) {
      this.children.push(child)
    } else {
      this.children.splice(afterIndex, 0, child)
    }

    if (fixLayout) {
      child.fixLayout()
    }
  }

  removeChild(child, {fixLayout = true} = {}) {
    // Removes the given child element from the children list of this
    // element. It won't be rendered in the future. If the given element
    // isn't a direct child of this element, nothing will happen.

    if (child.parent !== this) {
      return
    }

    child.parent = null
    this.children.splice(this.children.indexOf(child), 1)

    if (fixLayout) {
      this.fixLayout()
    }
  }

  get root() {
    let el = this
    while (el.parent) {
      el = el.parent
    }
    return el
  }

  get directAncestors() {
    const ancestors = []
    let el = this
    while (el.parent) {
      el = el.parent
      ancestors.push(el)
    }
    return ancestors
  }
}