Class: Hokusai::NodeMounter

Inherits:
Object
  • Object
show all
Defined in:
ui/src/hokusai/node_mounter.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node, klass, secondary_stack = [], previous_target = nil) ⇒ NodeMounter

Returns a new instance of NodeMounter.

[View source]

10
11
12
13
14
15
16
17
18
# File 'ui/src/hokusai/node_mounter.rb', line 10

def initialize(node, klass, secondary_stack = [], previous_target = nil)
  @root = klass.new(node: node)
  @secondary_stack = secondary_stack
  @primary_stack = []

  node.ast.children.each_with_index do |child, index|
    primary_stack << Mounting::MountEntry.new(index, child, root, root, previous_target || root)
  end
end

Instance Attribute Details

#primary_stackObject

Returns the value of attribute primary_stack.


7
8
9
# File 'ui/src/hokusai/node_mounter.rb', line 7

def primary_stack
  @primary_stack
end

#rootObject (readonly)

Returns the value of attribute root.


8
9
10
# File 'ui/src/hokusai/node_mounter.rb', line 8

def root
  @root
end

#secondary_stackObject

Returns the value of attribute secondary_stack.


7
8
9
# File 'ui/src/hokusai/node_mounter.rb', line 7

def secondary_stack
  @secondary_stack
end

Instance Method Details

#mount(context: nil) ⇒ Object

[View source]

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'ui/src/hokusai/node_mounter.rb', line 20

def mount(context: nil)
  while entry = primary_stack.shift
    next if entry.virtual?

    if entry.loop?
      entries, secondary_entries = Mounting::LoopEntry.new(entry).register

      self.primary_stack = entries + primary_stack
      self.secondary_stack = secondary_entries + secondary_stack

      next
    end

    if entry.ast.has_if_condition?
      next unless entry.target.public_send(entry.ast.if.method)
    end

    if entry.slot?
      while siblings = secondary_stack.shift
        next if siblings.empty?

        continue = false

        while sibling_entry = siblings.pop
          # if we encounter a nested slot, we will
          # add the current siblings to the end of the next
          # non-empty slot sibling group
          # and continue processing slots
          if sibling_entry.slot?
            continue = true

            secondary_stack.each_with_index do |previous_siblings, i|
              next if previous_siblings.empty?

              secondary_stack[i] = siblings +  previous_siblings
              siblings.clear

              break
            end
          else
            primary_stack.unshift sibling_entry.with_block(entry.block)
          end
        end

        next if continue
        break
      end

      next
    end

    entry.mount(context: context) do |child_block|
      # create a subentry to register event handling and prop passing
      Mounting::UpdateEntry.new(child_block, entry.block, entry.target).register(context: context || entry.ctx)

      # Populate the secondary stack with the portal children
      # this stack will be used to populate any slots in the primary_stack
      items = []

      entry.ast.children.each_with_index do |child, child_index|
        child.has_if_condition?
        items << Mounting::MountEntry.new(child_index, child, child_block, entry.parent, entry.target, context: entry.ctx)
      end

      secondary_stack.unshift items

      # populate the primary stack with the newly compiled
      # ast from child_block
      primary_items = []

      child_block.node.ast.children.each_with_index do |child, child_index|
        primary_items << Mounting::MountEntry.new(child_index, child, child_block, child_block, context: entry.ctx)
      end

      self.primary_stack = primary_items + primary_stack
    end
  end

  root.public_send(:on_mounted) if root.respond_to?(:on_mounted)
  root
end