Class: Vident::Stimulus::Outlet

Inherits:
Base
  • Object
show all
Defined in:
lib/vident/stimulus/outlet.rb

Overview

‘data-<parent-ctrl>-<child-ctrl>-outlet` fragment.

Constant Summary collapse

SELECTOR_CHARS =

Characters that only make sense in a CSS selector, never in a Stimulus controller path/identifier.

/[.#\[>,*+:]/

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

to_data_hash

Methods included from Combinable

#deconstruct, #deconstruct_keys, #with

Class Method Details

.auto_selector(outlet_identifier, component_id:) ⇒ Object



67
68
69
70
# File 'lib/vident/stimulus/outlet.rb', line 67

def self.auto_selector(outlet_identifier, component_id:)
  prefix = component_id ? "##{css_escape_ident(component_id)} " : ""
  "#{prefix}[data-controller~=#{outlet_identifier}]"
end

.css_escape_ident(id) ⇒ Object

CSS-escapes anything outside the bare identifier alphabet (‘A-Za-z0-9_-`) using the `HH ` hex form (with trailing space delimiter). Bare `<char>` works for many punctuation cases but not for whitespace, parens, or non-ASCII — the hex form is always valid per CSS Syntax §4.3.7.



77
78
79
# File 'lib/vident/stimulus/outlet.rb', line 77

def self.css_escape_ident(id)
  id.to_s.gsub(/[^A-Za-z0-9_-]/) { |c| "\\#{c.ord.to_s(16)} " }
end

.parse(*args, implied:, component_id: nil) ⇒ Object



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
# File 'lib/vident/stimulus/outlet.rb', line 21

def self.parse(*args, implied:, component_id: nil)
  case args
  in [Outlet => o]
    o
  in [Symbol => sym]
    name = sym.to_s.dasherize
    new(controller: implied, name: name, selector: auto_selector(name, component_id: component_id))
  in [String => str] if SELECTOR_CHARS.match?(str)
    raise ::Vident::ParseError, raw_string_selector_message(str)
  in [String => str]
    name = Naming.stimulize_path(str)
    new(controller: implied, name: name, selector: auto_selector(name, component_id: component_id))
  in [Symbol => sym, Selector => sel]
    new(controller: implied, name: sym.to_s.dasherize, selector: sel.css)
  in [String => str, Selector => sel]
    new(controller: implied, name: Naming.stimulize_path(str), selector: sel.css)
  in [String => parent_path, Symbol => child_sym]
    child_name = child_sym.to_s.dasherize
    new(
      controller: Controller.parse(parent_path, implied: implied),
      name: child_name,
      selector: auto_selector(child_name, component_id: component_id)
    )
  in [String => parent_path, Symbol => child_sym, Selector => sel]
    new(
      controller: Controller.parse(parent_path, implied: implied),
      name: child_sym.to_s.dasherize,
      selector: sel.css
    )
  in [obj] if obj.respond_to?(:stimulus_identifier)
    ident = obj.stimulus_identifier
    new(controller: implied, name: ident, selector: auto_selector(ident, component_id: component_id))
  in [Selector => sel]
    raise ::Vident::ParseError,
      "Outlet.parse: a Selector must be paired with a child controller name. " \
      "Use `(:name, Vident::Selector(#{sel.css.inspect}))` or " \
      "`(\"some/parent\", :name, Vident::Selector(...))` for the cross-controller form."
  in [_, String => sel]
    raise ::Vident::ParseError, raw_string_selector_message(sel)
  in [_, _, String => sel]
    raise ::Vident::ParseError, raw_string_selector_message(sel)
  else
    raise ::Vident::ParseError, "Outlet.parse: invalid arguments #{args.inspect}"
  end
end

.raw_string_selector_message(value) ⇒ Object



81
82
83
84
85
86
# File 'lib/vident/stimulus/outlet.rb', line 81

def self.raw_string_selector_message(value)
  "Outlet.parse: a bare String is a controller path, never a CSS selector. " \
    "Wrap verbatim selectors in `Vident::Selector(...)` (got #{value.inspect}). " \
    "For auto-selectors based on a child controller identifier, pass a Symbol or " \
    "an unwrapped String — Vident builds `[data-controller~=…]` for you."
end

Instance Method Details

#data_attribute_keyObject



90
# File 'lib/vident/stimulus/outlet.rb', line 90

def data_attribute_key = :"#{controller.name}-#{name}-outlet"

#to_data_pairObject



92
# File 'lib/vident/stimulus/outlet.rb', line 92

def to_data_pair = [data_attribute_key, selector]

#to_hObject Also known as: to_hash



94
# File 'lib/vident/stimulus/outlet.rb', line 94

def to_h = {data_attribute_key => selector}

#to_sObject



88
# File 'lib/vident/stimulus/outlet.rb', line 88

def to_s = selector