Class: Mayu::VDOM::VNode
- Inherits:
-
T::Struct
- Object
- T::Struct
- Mayu::VDOM::VNode
- Extended by:
- T::Sig
- Includes:
- Interfaces::VNode
- Defined in:
- lib/mayu/vdom/vnode.rb
Constant Summary collapse
- Children =
T.type_alias { T::Array[VNode] }
- Id =
T.type_alias { IdGenerator::Type }
- Writable =
T.type_alias do T.any(Async::HTTP::Body::Writable, Brotli::Writer, StringIO) end
Class Method Summary collapse
Instance Method Summary collapse
- #action(type, payload) ⇒ Object
- #assert_not_removed! ⇒ Object
- #dom? ⇒ Boolean
- #dom_id ⇒ Object
- #enqueue_update! ⇒ Object
- #eql?(other) ⇒ Boolean
- #fetch(url, method: :GET, headers: {}, body: nil) ⇒ Object
- #format_attr(attr, value) ⇒ Object
- #format_prop(prop, value) ⇒ Object
- #format_props(&block) ⇒ Object
- #id_tree ⇒ Object
- #init_component ⇒ Object
- #inspect ⇒ Object
- #key ⇒ Object
- #marshal_dump ⇒ Object
- #marshal_load(a) ⇒ Object
- #navigate(path) ⇒ Object
- #props ⇒ Object
- #remove! ⇒ Object
- #removed? ⇒ Boolean
- #same?(descriptor) ⇒ Boolean
- #to_html ⇒ Object
- #traverse {|_self| ... } ⇒ Object
- #type ⇒ Object
- #write_html(io, **opts) ⇒ Object
Methods included from Interfaces::VNode
Class Method Details
.build(vtree, dom_parent_id, descriptor, task: Async::Task.current) ⇒ Object
28 29 30 31 32 33 34 35 |
# File 'lib/mayu/vdom/vnode.rb', line 28 def self.build( vtree, dom_parent_id, descriptor, task: Async::Task.current ) new(id: vtree.next_id!, vtree:, dom_parent_id:, descriptor:, task:) end |
Instance Method Details
#action(type, payload) ⇒ Object
126 127 128 |
# File 'lib/mayu/vdom/vnode.rb', line 126 def action(type, payload) @vtree.action(type, payload) end |
#assert_not_removed! ⇒ Object
65 66 67 68 |
# File 'lib/mayu/vdom/vnode.rb', line 65 def assert_not_removed! return true unless removed? raise "VNode is marked as removed and should not be used!" end |
#dom? ⇒ Boolean
57 |
# File 'lib/mayu/vdom/vnode.rb', line 57 def dom? = type.is_a?(Symbol) |
#dom_id ⇒ Object
55 |
# File 'lib/mayu/vdom/vnode.rb', line 55 def dom_id = (wrapper ? children.first&.dom_id || "root" : id) |
#enqueue_update! ⇒ Object
131 132 133 |
# File 'lib/mayu/vdom/vnode.rb', line 131 def enqueue_update! @vtree.enqueue_update!(self) end |
#eql?(other) ⇒ Boolean
141 142 143 |
# File 'lib/mayu/vdom/vnode.rb', line 141 def eql?(other) self.class === other && other.id == id end |
#fetch(url, method: :GET, headers: {}, body: nil) ⇒ Object
108 109 110 |
# File 'lib/mayu/vdom/vnode.rb', line 108 def fetch(url, method: :GET, headers: {}, body: nil) @vtree.session.fetch(url, method:, headers:, body:) end |
#format_attr(attr, value) ⇒ Object
246 247 248 249 250 251 252 |
# File 'lib/mayu/vdom/vnode.rb', line 246 def format_attr(attr, value) format( %{ %<attr>s="%<value>s"}, attr: attr.to_s, value: CGI.escape_html(value.to_s) ) end |
#format_prop(prop, value) ⇒ Object
255 256 257 258 259 260 261 262 263 |
# File 'lib/mayu/vdom/vnode.rb', line 255 def format_prop(prop, value) value = prop.to_s if value == true prop = :value if prop == :initial_value attr = prop.to_s.sub(/^on_/, "on").tr("_", "-") format_attr(attr, value) end |
#format_props(&block) ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/mayu/vdom/vnode.rb', line 221 def format_props(&block) props.each do |prop, value| next unless value next if prop == :children next if prop == :slot next if value == "" if value.is_a?(Hash) if prop == :style yield format_attr(prop, CSSAttributes.new(**value).to_s) else Utils .flatten_props(value, [prop.to_s]) .each { yield format_prop(_1, _2) } end next end yield format_prop(prop, value) end end |
#id_tree ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/mayu/vdom/vnode.rb', line 146 def id_tree children = Array(self.children).flatten.compact return children.first&.id_tree if component if children.empty? { id:, type: type.to_s } else { id:, ch: children.map(&:id_tree), type: type.to_s } end end |
#init_component ⇒ Object
116 117 118 |
# File 'lib/mayu/vdom/vnode.rb', line 116 def init_component @wrapper ||= Component.wrap(self, type, props) end |
#inspect ⇒ Object
159 160 161 |
# File 'lib/mayu/vdom/vnode.rb', line 159 def inspect "<#VNode:#{id} type=#{descriptor.type} key=#{descriptor.key}>" end |
#key ⇒ Object
52 |
# File 'lib/mayu/vdom/vnode.rb', line 52 def key = descriptor.key |
#marshal_dump ⇒ Object
71 72 73 74 |
# File 'lib/mayu/vdom/vnode.rb', line 71 def marshal_dump assert_not_removed! [@id, @dom_parent_id, @wrapper, @children, @descriptor] end |
#marshal_load(a) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/mayu/vdom/vnode.rb', line 77 def marshal_load(a) @id, @dom_parent_id, @wrapper, @children, @descriptor = a @removed = false if @wrapper @wrapper.instance_variable_set(:@vnode, self) instance = descriptor.component_class.new(@wrapper) @wrapper.instance_variable_set(:@instance, instance) instance.instance_variable_set(:@wrapper, @wrapper) @wrapper.instance_variable_set( :@helpers, Component::Helpers.new(@wrapper) ) end end |
#navigate(path) ⇒ Object
121 122 123 |
# File 'lib/mayu/vdom/vnode.rb', line 121 def navigate(path) @vtree.navigate(path) end |
#props ⇒ Object
50 |
# File 'lib/mayu/vdom/vnode.rb', line 50 def props = descriptor.props |
#remove! ⇒ Object
62 |
# File 'lib/mayu/vdom/vnode.rb', line 62 def remove! = @removed = true |
#removed? ⇒ Boolean
60 |
# File 'lib/mayu/vdom/vnode.rb', line 60 def removed? = @removed |
#same?(descriptor) ⇒ Boolean
136 137 138 |
# File 'lib/mayu/vdom/vnode.rb', line 136 def same?(descriptor) self.descriptor.eql?(descriptor) end |
#to_html ⇒ Object
164 165 166 |
# File 'lib/mayu/vdom/vnode.rb', line 164 def to_html T.must(StringIO.new.tap { write_html(_1) }.tap(&:rewind).read) end |
#traverse {|_self| ... } ⇒ Object
94 95 96 97 98 |
# File 'lib/mayu/vdom/vnode.rb', line 94 def traverse(&block) yield self children.each { |child| child.traverse(&block) } end |
#type ⇒ Object
48 |
# File 'lib/mayu/vdom/vnode.rb', line 48 def type = descriptor.type |
#write_html(io, **opts) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/mayu/vdom/vnode.rb', line 174 def write_html(io, **opts) type = descriptor.type case type when Mayu::VDOM::Interfaces::Descriptor::TEXT text = descriptor.text if text.empty? # A zero-width-space will generate a text node in the DOM. io.write("​") else io.write(CGI.escape_html(descriptor.text)) end return when Mayu::VDOM::Interfaces::Descriptor::COMMENT io.write("<!--mayu-id=#{@id}-->") return when :__mayu_links io.write(opts[:links].to_s) return when :__mayu_scripts io.write(opts[:scripts].to_s) return end cleaned_children = children if descriptor.component? cleaned_children.each { _1.write_html(io, **opts) } return end io.write("<#{type}") io.write(%< data-mayu-id="#{@id.to_s}">) format_props { |formatted_prop| io.write(formatted_prop) } io.write(">") return if type.is_a?(Symbol) && Mayu::HTML.void_tag?(type) cleaned_children.each { _1.write_html(io, **opts) } io.write("</#{type}>") end |