Class: Dommy::CustomElementRegistry
- Inherits:
-
Object
- Object
- Dommy::CustomElementRegistry
- Includes:
- Bridge::Methods
- Defined in:
- lib/dommy/custom_elements.rb
Overview
‘window.customElements` — registry mapping custom element tag names to Ruby classes that extend `HTMLElement`. Lifecycle callbacks (`connected_callback` / `disconnected_callback` / `attribute_changed_callback` / `adopted_callback`) are invoked by the document’s mutation pipeline when registered elements are added, removed, or have observed attributes mutated.
Names must contain a hyphen per the HTML spec (e.g., ‘my-button`).
Constant Summary collapse
- PCEN =
html.spec.whatwg.org/#valid-custom-element-name PCENChar — the characters allowed after the first (ASCII-lower) char: a superset of [-._0-9a-z] plus wide Unicode ranges. A valid name is ‘[a-z] PCENChar* - PCENChar*` (i.e. lower-alpha start + at least one “-”).
"\\-._0-9a-z\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u037D" \ "\\u037F-\\u1FFF\\u200C-\\u200D\\u203F-\\u2040\\u2070-\\u218F" \ "\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\u{10000}-\\u{EFFFF}"
- NAME_RE =
Regexp.new("\\A[a-z][#{PCEN}]*-[#{PCEN}]*\\z")
- RESERVED_NAMES =
Hyphenated names that the HTML spec reserves (SVG / MathML elements), so they are NOT valid custom element names even though they match NAME_RE.
%w[ annotation-xml color-profile font-face font-face-src font-face-uri font-face-format font-face-name missing-glyph ].to_set.freeze
Instance Method Summary collapse
- #__js_call__(method, args) ⇒ Object
- #__js_get__(_key) ⇒ Object
- #define(name, klass, _options = nil) ⇒ Object
- #get(name) ⇒ Object
- #get_name(klass) ⇒ Object
-
#initialize(window) ⇒ CustomElementRegistry
constructor
A new instance of CustomElementRegistry.
-
#upgrade(root) ⇒ Object
Walk ‘root`’s subtree and re-wrap any nodes whose tag is now registered; fires ‘connectedCallback` for each upgraded node that’s currently attached to a document tree.
-
#when_defined(name) ⇒ Object
Returns a Dommy::PromiseValue that resolves with the registered constructor when ‘name` is defined (immediately if already so).
Methods included from Bridge::Methods
Constructor Details
#initialize(window) ⇒ CustomElementRegistry
Returns a new instance of CustomElementRegistry.
29 30 31 32 33 34 35 |
# File 'lib/dommy/custom_elements.rb', line 29 def initialize(window) @window = window # name → klass @definitions = {} # name → Array<{ resolve, reject }> @pending_promises = {} end |
Instance Method Details
#__js_call__(method, args) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/dommy/custom_elements.rb', line 105 def __js_call__(method, args) case method when "define" define(args[0], args[1], args[2]) when "get" get(args[0]) when "whenDefined" when_defined(args[0]) when "upgrade" upgrade(args[0]) end end |
#__js_get__(_key) ⇒ Object
99 100 101 |
# File 'lib/dommy/custom_elements.rb', line 99 def __js_get__(_key) nil end |
#define(name, klass, _options = nil) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/dommy/custom_elements.rb', line 37 def define(name, klass, = nil) key = name.to_s unless key.match?(NAME_RE) raise DOMException::SyntaxError, "#{name.inspect} is not a valid custom element name" end if RESERVED_NAMES.include?(key) raise DOMException::SyntaxError, "#{name.inspect} is a reserved element name" end raise DOMException::NotSupportedError, "#{key} already defined" if @definitions.key?(key) @definitions[key] = klass # Resolve any pending whenDefined() promises and re-wrap # already-existing nodes (upgrade). resolve_pending(key, klass) upgrade_existing(key) nil end |
#get(name) ⇒ Object
56 57 58 |
# File 'lib/dommy/custom_elements.rb', line 56 def get(name) @definitions[name.to_s] end |
#get_name(klass) ⇒ Object
60 61 62 63 |
# File 'lib/dommy/custom_elements.rb', line 60 def get_name(klass) @definitions.each { |k, v| return k if v == klass } nil end |
#upgrade(root) ⇒ Object
Walk ‘root`’s subtree and re-wrap any nodes whose tag is now registered; fires ‘connectedCallback` for each upgraded node that’s currently attached to a document tree.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/dommy/custom_elements.rb', line 83 def upgrade(root) return nil unless root.respond_to?(:__dommy_backend_node__) walk_descendants(root.__dommy_backend_node__) do |nk| next unless nk.element? next unless @definitions.key?(nk.name) # Force re-wrap by clearing the document's cached wrapper. @window.document.__internal_reset_wrapper__(nk) wrapped = @window.document.wrap_node(nk) @window.document.__internal_notify_connected__(wrapped) if wrapped end nil end |
#when_defined(name) ⇒ Object
Returns a Dommy::PromiseValue that resolves with the registered constructor when ‘name` is defined (immediately if already so).
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/dommy/custom_elements.rb', line 67 def when_defined(name) key = name.to_s promise = PromiseValue.new(@window) if (klass = @definitions[key]) promise.fulfill(klass) else @pending_promises[key] ||= [] @pending_promises[key] << promise end promise end |