Module: Ruwi::Template::BuildVdom
- Defined in:
- lib/ruwi/runtime/template/build_vdom.rb
Class Method Summary collapse
- .build(elements) ⇒ String
-
.build_component(element, tag_name, filtered_attributes = nil) ⇒ String
Build component element.
-
.build_element(element, tag_name, filtered_attributes = nil) ⇒ String
Build regular HTML element.
-
.build_fragment(element, tag_name) ⇒ String
Build fragment or div element with data-template attribute.
- .embed_script?(doc) ⇒ Boolean
-
.get_embed_script(script) ⇒ String
get value from embed script ex) Count: :count -> Count: component.state.
-
.has_data_template_attribute?(element) ⇒ Boolean
Check if element has data-template attribute.
- .is_component?(tag_name) ⇒ Boolean
-
.parse_attributes(attributes) ⇒ String
Parse attributes array.
-
.parse_text_node(element) ⇒ String
parse text node ex) “test” -> “test” ex) “test :count” -> “test #:count” ex) “test + 1” -> “test #+ 1” ex) “test :count test” -> “test #:count test” ex) “test :count test :count test” -> “test #:count test #:count test”.
Class Method Details
.build(elements) ⇒ String
10 11 12 13 14 15 16 17 18 19 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 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 10 def build(elements) vdom = [] i = 0 elements_length = elements[:length].to_i while i < elements_length element = elements[i] # text node if element[:nodeType] == JS.global[:Node][:TEXT_NODE] text_result = parse_text_node(element) vdom << text_result if text_result i += 1 next end tag_name = element[:tagName].to_s.downcase # fragment node (including div elements with data-template attribute) if element[:nodeType] == JS.global[:Node][:ELEMENT_NODE] && (tag_name == 'template' || (tag_name == 'div' && has_data_template_attribute?(element))) # Check for conditional attributes on template if Ruwi::Template::BuildConditionalGroup.has_conditional_attribute?(element) # Process conditional group (r-if, r-elsif, r-else) conditional_group, next_index = Ruwi::Template::BuildConditionalGroup.build_conditional_group(elements, i) vdom << conditional_group i = next_index else vdom << build_fragment(element, tag_name) i += 1 end next end # element node (including components) if element[:nodeType] == JS.global[:Node][:ELEMENT_NODE] # Check for conditional attributes on all elements (including components) if Ruwi::Template::BuildConditionalGroup.has_conditional_attribute?(element) # Process conditional group (r-if, r-elsif, r-else) conditional_group, next_index = Ruwi::Template::BuildConditionalGroup.build_conditional_group(elements, i) vdom << conditional_group i = next_index # Check for r-for attribute on all elements (including components) elsif Ruwi::Template::BuildForGroup.has_for_attribute?(element) # Process r-for loop - the result is a map expression that returns an array for_loop = Ruwi::Template::BuildForGroup.build_for_loop(element) if for_loop && !for_loop.empty? # Wrap the map result with splat operator to expand the array vdom << "*#{for_loop}" end i += 1 else # Handle components and regular elements if is_component?(tag_name) vdom << build_component(element, tag_name) else vdom << build_element(element, tag_name) end i += 1 end next end i += 1 end vdom.compact.join(',') end |
.build_component(element, tag_name, filtered_attributes = nil) ⇒ String
Build component element
198 199 200 201 202 203 204 205 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 198 def build_component(element, tag_name, filtered_attributes = nil) attributes_str = parse_attributes(filtered_attributes || element[:attributes].to_a) children = build(element[:childNodes]) # Convert kebab-case to PascalCase for component name component_name = tag_name.split('-').map(&:capitalize).join "Ruwi::Vdom.h(#{component_name}, {#{attributes_str}}, [#{children}])" end |
.build_element(element, tag_name, filtered_attributes = nil) ⇒ String
Build regular HTML element
212 213 214 215 216 217 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 212 def build_element(element, tag_name, filtered_attributes = nil) attributes_str = parse_attributes(filtered_attributes || element[:attributes].to_a) children = build(element[:childNodes]) "Ruwi::Vdom.h('#{tag_name}', {#{attributes_str}}, [#{children}])" end |
.build_fragment(element, tag_name) ⇒ String
Build fragment or div element with data-template attribute
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 182 def build_fragment(element, tag_name) # div elements with data-template don't have content property, use childNodes directly if tag_name == 'template' && element[:content] content_nodes = element[:content][:childNodes] else content_nodes = element[:childNodes] end children = build(content_nodes) "Ruwi::Vdom.h_fragment([#{children}])" end |
.embed_script?(doc) ⇒ Boolean
151 152 153 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 151 def (doc) doc.match?(/\{.+\}/) end |
.get_embed_script(script) ⇒ String
get value from embed script ex) Count: :count -> Count: component.state
159 160 161 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 159 def (script) script.gsub(/\{(.+)\}/) { ::Regexp.last_match(1) } end |
.has_data_template_attribute?(element) ⇒ Boolean
Check if element has data-template attribute
166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 166 def has_data_template_attribute?(element) return false unless element[:attributes] length = element[:attributes][:length].to_i length.times do |i| attribute = element[:attributes][i] key = attribute[:name].to_s return true if key == 'data-template' end false end |
.is_component?(tag_name) ⇒ Boolean
141 142 143 144 145 146 147 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 141 def is_component?(tag_name) # Component tags start with letter but exclude standard HTML elements return false unless tag_name.match?(/^[a-z]/) # Use the standard HTML elements list from Parser module !Ruwi::Template::Parser::STANDARD_HTML_ELEMENTS.include?(tag_name) end |
.parse_attributes(attributes) ⇒ String
Parse attributes array
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 117 def parse_attributes(attributes) attributes_str = [] attributes.each do |attribute| key = attribute[:name].to_s value = attribute[:value].to_s if (value) # Special handling for 'on' attribute to preserve hash structure if key == 'on' attributes_str << ":#{key} => #{value}" else attributes_str << ":#{key} => #{(value)}" end next end attributes_str << ":#{key} => '#{value}'" end attributes_str.join(', ') end |
.parse_text_node(element) ⇒ String
parse text node ex) “test” -> “test” ex) “test :count” -> “test #:count” ex) “test + 1” -> “test #+ 1” ex) “test :count test” -> “test #:count test” ex) “test :count test :count test” -> “test #:count test #:count test”
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/ruwi/runtime/template/build_vdom.rb', line 86 def parse_text_node(element) value = element[:nodeValue].to_s.chomp.strip return nil if value.empty? # Split the text by embedded script pattern and process each part # Regular expression explanation: # ( : Start capture group (this ensures the pattern itself is included in the result) # \{ : Match an opening curly brace (escaped because { is special in regex) # [^}]+ : Match one or more characters that are not a closing curly brace # \} : Match a closing curly brace (escaped because } is special in regex) # ) : End capture group # Example: # Input: "hello {state[:count]} world" # Output: ["hello ", "{state[:count]}", " world"] parts = value.split(/(\{[^}]+\})/) processed_parts = parts.map do |part| if (part) "\#{#{(part)}}" else part end end # Join all parts and wrap in double quotes %("#{processed_parts.join}") end |