Module: Weft::Context::Traversal

Included in:
Weft::Component, Page
Defined in:
lib/weft/context/traversal.rb

Overview

Render-tree navigation for components and pages: reach an ancestor — or self — in the Arbre tree by type or tag, to read its identity (class, weft_dom_id, route, page path). This is the "child affects ancestor" affordance: a nested component discovers what it needs to target instead of being hand-fed its parent's identity.

Mixed into Weft::Component and Weft::Page (not Context itself — the tree's root has no ancestors to walk). Lives here beside Interception as the other render-context mechanism the two share.

Call inside build. (There is no instance, and no render tree to walk, inside a verb block.) Lean on the ancestor's identity and params — fixed at construction — rather than state its own build may not have set yet, since it is mid-build above you.

Instance Method Summary collapse

Instance Method Details

#closest(matcher, include_self: true, &refine) ⇒ Object

The nearest node matching matcher, self included, walking up the tree — impedance-matched to the DOM's Element.closest(): include-self, nearest-first, nil if none.

closest(Weft::Page)                     # nearest enclosing page
closest(OrdersPanel)                    # nearest panel of that type
closest(Paginatable)                    # nearest node playing that role
closest(:div)                           # nearest <div> (self included)
closest(Weft::Component) { |c| c.params.key?(:order_id) }  # refined

matcher is a Class/Module (matched is_a?, subclass- and include-inclusive) or a Symbol (matched against tag_name). An optional block refines: a candidate must match the positional AND the block. Returns the matching Arbre node — a component for a class match, a plain element for a tag — or nil.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/weft/context/traversal.rb', line 37

def closest(matcher, include_self: true, &refine)
  unless matcher.is_a?(Module) || matcher.is_a?(Symbol)
    raise ArgumentError,
          "closest matcher must be a Class, Module, or Symbol tag name (got #{matcher.class})"
  end

  node = include_self ? self : parent
  while node
    return node if traversal_match?(node, matcher, refine)

    node = node.parent
  end
  nil
end

#closest!(matcher, include_self: true) ⇒ Object

closest that raises Weft::AncestorNotFound instead of returning nil — for a component that requires the ancestor (pair with dependent!).



58
59
60
61
62
# File 'lib/weft/context/traversal.rb', line 58

def closest!(matcher, include_self: true, &)
  closest(matcher, include_self: include_self, &) ||
    raise(Weft::AncestorNotFound,
          "no #{matcher.inspect} #{include_self ? 'at or above' : 'above'} #{self.class}")
end

#enclosing(matcher) ⇒ Object

closest strictly above self (self excluded) — the expressive read for "reach my enclosing X". Does not take include_self; use closest for that.



54
# File 'lib/weft/context/traversal.rb', line 54

def enclosing(matcher, &) = closest(matcher, include_self: false, &)

#enclosing!(matcher) ⇒ Object

enclosing that raises instead of returning nil.



65
# File 'lib/weft/context/traversal.rb', line 65

def enclosing!(matcher, &) = closest!(matcher, include_self: false, &)