glimmer-dsl-web 0.6.0 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +795 -11
- data/VERSION +1 -1
- data/glimmer-dsl-web.gemspec +6 -4
- data/lib/glimmer/dsl/web/component_expression.rb +21 -3
- data/lib/glimmer/dsl/web/component_slot_content_expression.rb +11 -5
- data/lib/glimmer/web/component.rb +27 -10
- data/lib/glimmer/web/element_proxy.rb +14 -10
- data/lib/glimmer-dsl-web/samples/hello/hello_component.rb +141 -177
- data/lib/glimmer-dsl-web/samples/hello/hello_component_listeners.rb +351 -0
- data/lib/glimmer-dsl-web/samples/hello/hello_component_listeners_default_slot.rb +349 -0
- data/lib/glimmer-dsl-web/samples/hello/hello_component_slots.rb +28 -68
- data/lib/glimmer-dsl-web/samples/hello/hello_content_data_binding.rb +3 -2
- data/lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb +28 -71
- data/lib/glimmer-dsl-web/samples/hello/hello_style.rb +3 -3
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/new_todo_form.rb +1 -1
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_input.rb +1 -1
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list.rb +3 -3
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list_item.rb +1 -3
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc.rb +2 -2
- metadata +6 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.2
|
data/glimmer-dsl-web.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: glimmer-dsl-web 0.6.
|
5
|
+
# stub: glimmer-dsl-web 0.6.2 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "glimmer-dsl-web".freeze
|
9
|
-
s.version = "0.6.
|
9
|
+
s.version = "0.6.2"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Andy Maleh".freeze]
|
14
|
-
s.date = "2024-
|
14
|
+
s.date = "2024-09-30"
|
15
15
|
s.description = "Glimmer DSL for Web (Ruby in the Browser Web Frontend Framework) enables building Web Frontends using Ruby in the Browser, as per Matz's recommendation in his RubyConf 2022 keynote speech to replace JavaScript with Ruby. It aims at providing the simplest, most intuitive, most straight-forward, and most productive frontend framework in existence. The framework follows the Ruby way (with DSLs and TIMTOWTDI) and the Rails way (Convention over Configuration) in building Isomorphic Ruby on Rails Applications. It provides a Ruby HTML DSL, which uniquely enables writing both structure code and logic code in one language. It supports both Unidirectional (One-Way) Data-Binding (using <=) and Bidirectional (Two-Way) Data-Binding (using <=>). Dynamic rendering (and re-rendering) of HTML content is also supported via Content Data-Binding. Modular design is supported with Glimmer Web Components, Component Slots, and Component Custom Event Listeners. And, a Ruby CSS DSL is supported with the included Glimmer DSL for CSS. Many samples are demonstrated in the Rails sample app (there is a very minimal Standalone [No Rails] sample app too). You can finally live in pure Rubyland on the Web in both the frontend and backend with Glimmer DSL for Web! This gem relies on Opal Ruby.".freeze
|
16
16
|
s.email = "andy.am@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
@@ -33,6 +33,8 @@ Gem::Specification.new do |s|
|
|
33
33
|
"lib/glimmer-dsl-web/ext/kernel.rb",
|
34
34
|
"lib/glimmer-dsl-web/samples/hello/hello_button.rb",
|
35
35
|
"lib/glimmer-dsl-web/samples/hello/hello_component.rb",
|
36
|
+
"lib/glimmer-dsl-web/samples/hello/hello_component_listeners.rb",
|
37
|
+
"lib/glimmer-dsl-web/samples/hello/hello_component_listeners_default_slot.rb",
|
36
38
|
"lib/glimmer-dsl-web/samples/hello/hello_component_slots.rb",
|
37
39
|
"lib/glimmer-dsl-web/samples/hello/hello_content_data_binding.rb",
|
38
40
|
"lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb",
|
@@ -102,7 +104,7 @@ Gem::Specification.new do |s|
|
|
102
104
|
|
103
105
|
s.add_runtime_dependency(%q<glimmer>.freeze, ["~> 2.8.0"])
|
104
106
|
s.add_runtime_dependency(%q<glimmer-dsl-xml>.freeze, ["~> 1.4.0"])
|
105
|
-
s.add_runtime_dependency(%q<glimmer-dsl-css>.freeze, ["~> 1.5.
|
107
|
+
s.add_runtime_dependency(%q<glimmer-dsl-css>.freeze, ["~> 1.5.2"])
|
106
108
|
s.add_runtime_dependency(%q<opal>.freeze, ["= 1.8.2"])
|
107
109
|
s.add_runtime_dependency(%q<opal-rails>.freeze, ["= 2.0.3"])
|
108
110
|
s.add_runtime_dependency(%q<opal-async>.freeze, ["~> 1.4.1"])
|
@@ -12,16 +12,34 @@ module Glimmer
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def interpret(parent, keyword, *args, &block)
|
15
|
-
|
16
|
-
|
15
|
+
component_class = Glimmer::Web::Component.for(keyword)
|
16
|
+
component_class.new(parent, args, {}, &block)
|
17
17
|
end
|
18
18
|
|
19
19
|
def add_content(parent, keyword, *args, &block)
|
20
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
21
|
+
slot = options[:slot] || options['slot']
|
22
|
+
slot = slot.to_s unless slot.nil?
|
20
23
|
# TODO consider avoiding source_location since it does not work in Opal
|
21
24
|
if block.source_location && (block.source_location == parent.content&.__getobj__&.source_location)
|
22
25
|
parent.content.call(parent) unless parent.content.called?
|
23
26
|
else
|
24
|
-
|
27
|
+
if slot
|
28
|
+
if slot == 'markup_root_slot'
|
29
|
+
super(parent, keyword, *args, &block)
|
30
|
+
else
|
31
|
+
slot_element = parent.slot_elements[slot]
|
32
|
+
slot_element&.content(&block)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
if parent.default_slot
|
36
|
+
slot = parent.default_slot
|
37
|
+
slot_element = parent.slot_elements[slot]
|
38
|
+
slot_element&.content(&block)
|
39
|
+
else
|
40
|
+
super(parent, keyword, *args, &block)
|
41
|
+
end
|
42
|
+
end
|
25
43
|
end
|
26
44
|
parent.post_add_content
|
27
45
|
end
|
@@ -28,19 +28,25 @@ module Glimmer
|
|
28
28
|
module Web
|
29
29
|
class ComponentSlotContentExpression < Expression
|
30
30
|
def can_interpret?(parent, keyword, *args, &block)
|
31
|
+
component = parent.is_a?(Glimmer::Web::Component) ? parent : parent&.ancestor_component
|
31
32
|
slot = keyword.to_s
|
32
33
|
block_given? &&
|
33
|
-
|
34
|
+
!component.nil? &&
|
34
35
|
(
|
35
|
-
|
36
|
-
|
36
|
+
component.slot_elements.keys.include?(slot) ||
|
37
|
+
component.slot_elements.keys.include?(slot.to_sym)
|
37
38
|
)
|
38
39
|
end
|
39
40
|
|
40
41
|
def interpret(parent, keyword, *args, &block)
|
41
42
|
slot = keyword.to_s
|
42
|
-
|
43
|
-
|
43
|
+
component = parent.is_a?(Glimmer::Web::Component) ? parent : parent.ancestor_component
|
44
|
+
if slot == 'markup_root_slot'
|
45
|
+
component.content(slot: slot.to_sym, &block)
|
46
|
+
else
|
47
|
+
slot_element = component.slot_elements[slot] || component.slot_elements[slot.to_sym]
|
48
|
+
slot_element.content(&block)
|
49
|
+
end
|
44
50
|
end
|
45
51
|
end
|
46
52
|
end
|
@@ -89,17 +89,26 @@ module Glimmer
|
|
89
89
|
@after_render = block
|
90
90
|
end
|
91
91
|
|
92
|
-
def event(
|
92
|
+
def event(event_name)
|
93
93
|
@events ||= []
|
94
|
-
|
95
|
-
@events <<
|
94
|
+
event_name = event_name.to_sym
|
95
|
+
@events << event_name unless @events.include?(event_name)
|
96
96
|
end
|
97
97
|
|
98
|
-
def events(*
|
99
|
-
|
98
|
+
def events(*event_names)
|
99
|
+
@events ||= []
|
100
|
+
if event_names.empty?
|
100
101
|
@events
|
101
102
|
else
|
102
|
-
|
103
|
+
event_names.each { |event| event(event) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def default_slot(slot_name = nil)
|
108
|
+
if slot_name.nil?
|
109
|
+
@default_slot
|
110
|
+
else
|
111
|
+
@default_slot = slot_name.to_s.to_sym
|
103
112
|
end
|
104
113
|
end
|
105
114
|
|
@@ -269,7 +278,7 @@ module Glimmer
|
|
269
278
|
end
|
270
279
|
# <- end of class methods
|
271
280
|
|
272
|
-
attr_reader :markup_root, :parent, :args, :options, :style_block, :component_style, :slot_elements, :events
|
281
|
+
attr_reader :markup_root, :parent, :args, :options, :style_block, :component_style, :slot_elements, :events, :default_slot
|
273
282
|
alias parent_proxy parent
|
274
283
|
|
275
284
|
def initialize(parent, args, options, &content)
|
@@ -286,7 +295,8 @@ module Glimmer
|
|
286
295
|
@args = args
|
287
296
|
options ||= {}
|
288
297
|
@options = self.class.options.merge(options)
|
289
|
-
@events = self.class.instance_variable_get("@events")
|
298
|
+
@events = self.class.instance_variable_get("@events") || []
|
299
|
+
@default_slot = self.class.instance_variable_get("@default_slot")
|
290
300
|
@content = Util::ProcTracker.new(content) if content
|
291
301
|
# @style_blocks = {} # TODO enable when doing bulk head rendering in the future
|
292
302
|
execute_hooks('before_render')
|
@@ -473,8 +483,15 @@ module Glimmer
|
|
473
483
|
@content
|
474
484
|
end
|
475
485
|
else
|
476
|
-
|
477
|
-
|
486
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
487
|
+
slot = options[:slot] || options['slot']
|
488
|
+
slot = slot.to_sym unless slot.nil?
|
489
|
+
if slot
|
490
|
+
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Web::ComponentExpression.new, self.class.keyword, slot: slot, &block)
|
491
|
+
else
|
492
|
+
# delegate to GUI DSL ContentExpression
|
493
|
+
super
|
494
|
+
end
|
478
495
|
end
|
479
496
|
end
|
480
497
|
|
@@ -604,16 +604,20 @@ module Glimmer
|
|
604
604
|
|
605
605
|
def handle_observation_request(keyword, original_event_listener)
|
606
606
|
if rendered?
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
607
|
+
if keyword.start_with?('on_') && !['on_render', 'on_remove'].include?(keyword.to_s)
|
608
|
+
(ancestor_component || component)&.handle_observation_request(keyword, original_event_listener)
|
609
|
+
else
|
610
|
+
listener = ListenerProxy.new(
|
611
|
+
element: self,
|
612
|
+
selector: selector,
|
613
|
+
dom_element: dom_element,
|
614
|
+
event_attribute: keyword,
|
615
|
+
original_event_listener: original_event_listener,
|
616
|
+
)
|
617
|
+
listener.register
|
618
|
+
listeners_for(keyword) << listener
|
619
|
+
listener
|
620
|
+
end
|
617
621
|
else
|
618
622
|
enqueue_post_render_method_call('handle_observation_request', keyword, original_event_listener)
|
619
623
|
end
|
@@ -21,198 +21,162 @@
|
|
21
21
|
|
22
22
|
require 'glimmer-dsl-web'
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
"LA"=>"Louisiana",
|
47
|
-
"MA"=>"Massachusetts",
|
48
|
-
"MD"=>"Maryland",
|
49
|
-
"ME"=>"Maine",
|
50
|
-
"MI"=>"Michigan",
|
51
|
-
"MN"=>"Minnesota",
|
52
|
-
"MO"=>"Missouri",
|
53
|
-
"MS"=>"Mississippi",
|
54
|
-
"MT"=>"Montana",
|
55
|
-
"NC"=>"North Carolina",
|
56
|
-
"ND"=>"North Dakota",
|
57
|
-
"NE"=>"Nebraska",
|
58
|
-
"NH"=>"New Hampshire",
|
59
|
-
"NJ"=>"New Jersey",
|
60
|
-
"NM"=>"New Mexico",
|
61
|
-
"NV"=>"Nevada",
|
62
|
-
"NY"=>"New York",
|
63
|
-
"OH"=>"Ohio",
|
64
|
-
"OK"=>"Oklahoma",
|
65
|
-
"OR"=>"Oregon",
|
66
|
-
"PA"=>"Pennsylvania",
|
67
|
-
"PR"=>"Puerto Rico",
|
68
|
-
"RI"=>"Rhode Island",
|
69
|
-
"SC"=>"South Carolina",
|
70
|
-
"SD"=>"South Dakota",
|
71
|
-
"TN"=>"Tennessee",
|
72
|
-
"TX"=>"Texas",
|
73
|
-
"UT"=>"Utah",
|
74
|
-
"VA"=>"Virginia",
|
75
|
-
"VI"=>"Virgin Islands",
|
76
|
-
"VT"=>"Vermont",
|
77
|
-
"WA"=>"Washington",
|
78
|
-
"WI"=>"Wisconsin",
|
79
|
-
"WV"=>"West Virginia",
|
80
|
-
"WY"=>"Wyoming"
|
81
|
-
}
|
82
|
-
|
83
|
-
def state_code
|
84
|
-
STATES.invert[state]
|
85
|
-
end
|
24
|
+
unless Object.const_defined?(:Address)
|
25
|
+
Address = Struct.new(:full_name, :street, :street2, :city, :state, :zip_code, :billing_and_shipping, keyword_init: true) do
|
26
|
+
STATES = {
|
27
|
+
"AK"=>"Alaska", "AL"=>"Alabama", "AR"=>"Arkansas", "AS"=>"American Samoa", "AZ"=>"Arizona",
|
28
|
+
"CA"=>"California", "CO"=>"Colorado", "CT"=>"Connecticut", "DC"=>"District of Columbia", "DE"=>"Delaware",
|
29
|
+
"FL"=>"Florida", "GA"=>"Georgia", "GU"=>"Guam", "HI"=>"Hawaii", "IA"=>"Iowa", "ID"=>"Idaho", "IL"=>"Illinois",
|
30
|
+
"IN"=>"Indiana", "KS"=>"Kansas", "KY"=>"Kentucky", "LA"=>"Louisiana", "MA"=>"Massachusetts", "MD"=>"Maryland",
|
31
|
+
"ME"=>"Maine", "MI"=>"Michigan", "MN"=>"Minnesota", "MO"=>"Missouri", "MS"=>"Mississippi", "MT"=>"Montana",
|
32
|
+
"NC"=>"North Carolina", "ND"=>"North Dakota", "NE"=>"Nebraska", "NH"=>"New Hampshire", "NJ"=>"New Jersey",
|
33
|
+
"NM"=>"New Mexico", "NV"=>"Nevada", "NY"=>"New York", "OH"=>"Ohio", "OK"=>"Oklahoma", "OR"=>"Oregon",
|
34
|
+
"PA"=>"Pennsylvania", "PR"=>"Puerto Rico", "RI"=>"Rhode Island", "SC"=>"South Carolina", "SD"=>"South Dakota",
|
35
|
+
"TN"=>"Tennessee", "TX"=>"Texas", "UT"=>"Utah", "VA"=>"Virginia", "VI"=>"Virgin Islands", "VT"=>"Vermont",
|
36
|
+
"WA"=>"Washington", "WI"=>"Wisconsin", "WV"=>"West Virginia", "WY"=>"Wyoming"
|
37
|
+
}
|
38
|
+
|
39
|
+
def state_code
|
40
|
+
STATES.invert[state]
|
41
|
+
end
|
42
|
+
|
43
|
+
def state_code=(value)
|
44
|
+
self.state = STATES[value]
|
45
|
+
end
|
86
46
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
47
|
+
def summary
|
48
|
+
string_attributes = to_h.except(:billing_and_shipping)
|
49
|
+
summary = string_attributes.values.map(&:to_s).reject(&:empty?).join(', ')
|
50
|
+
summary += " (Billing & Shipping)" if billing_and_shipping
|
51
|
+
summary
|
52
|
+
end
|
93
53
|
end
|
94
54
|
end
|
95
55
|
|
96
|
-
|
97
|
-
#
|
98
|
-
# Including Glimmer::Web::Component makes this class a View component and automatically
|
99
|
-
# generates a new Glimmer HTML DSL keyword that matches the lowercase underscored version
|
100
|
-
# of the name of the class. AddressForm generates address_form keyword, which can be used
|
101
|
-
# elsewhere in Glimmer HTML DSL code as done inside AddressPage below.
|
102
|
-
class AddressForm
|
103
|
-
include Glimmer::Web::Component
|
104
|
-
|
105
|
-
option :address
|
106
|
-
|
107
|
-
# Optionally, you can execute code before rendering markup.
|
108
|
-
# This is useful for pre-setup of variables (e.g. Models) that you would use in the markup.
|
56
|
+
unless Object.const_defined?(:AddressForm)
|
57
|
+
# AddressForm Glimmer Web Component (View component)
|
109
58
|
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
|
113
|
-
#
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
59
|
+
# Including Glimmer::Web::Component makes this class a View component and automatically
|
60
|
+
# generates a new Glimmer HTML DSL keyword that matches the lowercase underscored version
|
61
|
+
# of the name of the class. AddressForm generates address_form keyword, which can be used
|
62
|
+
# elsewhere in Glimmer HTML DSL code as done inside AddressPage below.
|
63
|
+
class AddressForm
|
64
|
+
include Glimmer::Web::Component
|
65
|
+
|
66
|
+
option :address
|
67
|
+
|
68
|
+
# Optionally, you can execute code before rendering markup.
|
69
|
+
# This is useful for pre-setup of variables (e.g. Models) that you would use in the markup.
|
70
|
+
#
|
71
|
+
# before_render do
|
72
|
+
# end
|
73
|
+
|
74
|
+
# Optionally, you can execute code after rendering markup.
|
75
|
+
# This is useful for post-setup of extra Model listeners that would interact with the
|
76
|
+
# markup elements and expect them to be rendered already.
|
77
|
+
#
|
78
|
+
# after_render do
|
79
|
+
# end
|
80
|
+
|
81
|
+
# markup block provides the content of the
|
82
|
+
markup {
|
83
|
+
div {
|
84
|
+
div(style: 'display: grid; grid-auto-columns: 80px 260px;') { |address_div|
|
85
|
+
label('Full Name: ', for: 'full-name-field')
|
86
|
+
input(id: 'full-name-field') {
|
87
|
+
value <=> [address, :full_name]
|
88
|
+
}
|
89
|
+
|
90
|
+
label('Street: ', for: 'street-field')
|
91
|
+
input(id: 'street-field') {
|
92
|
+
value <=> [address, :street]
|
93
|
+
}
|
94
|
+
|
95
|
+
label('Street 2: ', for: 'street2-field')
|
96
|
+
textarea(id: 'street2-field') {
|
97
|
+
value <=> [address, :street2]
|
98
|
+
}
|
99
|
+
|
100
|
+
label('City: ', for: 'city-field')
|
101
|
+
input(id: 'city-field') {
|
102
|
+
value <=> [address, :city]
|
103
|
+
}
|
104
|
+
|
105
|
+
label('State: ', for: 'state-field')
|
106
|
+
select(id: 'state-field') {
|
107
|
+
Address::STATES.each do |state_code, state|
|
108
|
+
option(value: state_code) { state }
|
109
|
+
end
|
119
110
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
111
|
+
value <=> [address, :state_code]
|
112
|
+
}
|
113
|
+
|
114
|
+
label('Zip Code: ', for: 'zip-code-field')
|
115
|
+
input(id: 'zip-code-field', type: 'number', min: '0', max: '99999') {
|
116
|
+
value <=> [address, :zip_code,
|
117
|
+
on_write: :to_s,
|
118
|
+
]
|
119
|
+
}
|
120
|
+
|
121
|
+
style {
|
122
|
+
r("#{address_div.selector} *") {
|
123
|
+
margin '5px'
|
124
|
+
}
|
125
|
+
r("#{address_div.selector} input, #{address_div.selector} select") {
|
126
|
+
grid_column '2'
|
127
|
+
}
|
128
|
+
}
|
137
129
|
}
|
138
130
|
|
139
|
-
|
140
|
-
|
141
|
-
|
131
|
+
div(style: 'margin: 5px') {
|
132
|
+
inner_text <= [address, :summary,
|
133
|
+
computed_by: address.members + ['state_code'],
|
134
|
+
]
|
142
135
|
}
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
option(value: state_code) { state }
|
148
|
-
end
|
136
|
+
}
|
137
|
+
}
|
138
|
+
end
|
139
|
+
end
|
149
140
|
|
150
|
-
|
151
|
-
|
141
|
+
unless Object.const_defined?(:AddressPage)
|
142
|
+
# AddressPage Glimmer Web Component (View component)
|
143
|
+
#
|
144
|
+
# This View component represents the main page being rendered,
|
145
|
+
# as done by its `render` class method below
|
146
|
+
class AddressPage
|
147
|
+
include Glimmer::Web::Component
|
148
|
+
|
149
|
+
before_render do
|
150
|
+
@shipping_address = Address.new(
|
151
|
+
full_name: 'Johnny Doe',
|
152
|
+
street: '3922 Park Ave',
|
153
|
+
street2: 'PO BOX 8382',
|
154
|
+
city: 'San Diego',
|
155
|
+
state: 'California',
|
156
|
+
zip_code: '91913',
|
157
|
+
)
|
158
|
+
@billing_address = Address.new(
|
159
|
+
full_name: 'John C Doe',
|
160
|
+
street: '123 Main St',
|
161
|
+
street2: 'Apartment 3C',
|
162
|
+
city: 'San Diego',
|
163
|
+
state: 'California',
|
164
|
+
zip_code: '91911',
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
markup {
|
169
|
+
div {
|
170
|
+
h1('Shipping Address')
|
152
171
|
|
153
|
-
|
154
|
-
input(id: 'zip-code-field', type: 'number', min: '0', max: '99999') {
|
155
|
-
value <=> [address, :zip_code,
|
156
|
-
on_write: :to_s,
|
157
|
-
]
|
158
|
-
}
|
172
|
+
address_form(address: @shipping_address)
|
159
173
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
}
|
164
|
-
r("#{address_div.selector} input, #{address_div.selector} select") {
|
165
|
-
grid_column '2'
|
166
|
-
}
|
167
|
-
}
|
168
|
-
}
|
169
|
-
|
170
|
-
div(style: 'margin: 5px') {
|
171
|
-
inner_text <= [address, :summary,
|
172
|
-
computed_by: address.members + ['state_code'],
|
173
|
-
]
|
174
|
+
h1('Billing Address')
|
175
|
+
|
176
|
+
address_form(address: @billing_address)
|
174
177
|
}
|
175
178
|
}
|
176
|
-
}
|
177
|
-
end
|
178
|
-
|
179
|
-
# AddressPage Glimmer Web Component (View component)
|
180
|
-
#
|
181
|
-
# This View component represents the main page being rendered,
|
182
|
-
# as done by its `render` class method below
|
183
|
-
class AddressPage
|
184
|
-
include Glimmer::Web::Component
|
185
|
-
|
186
|
-
before_render do
|
187
|
-
@shipping_address = Address.new(
|
188
|
-
full_name: 'Johnny Doe',
|
189
|
-
street: '3922 Park Ave',
|
190
|
-
street2: 'PO BOX 8382',
|
191
|
-
city: 'San Diego',
|
192
|
-
state: 'California',
|
193
|
-
zip_code: '91913',
|
194
|
-
)
|
195
|
-
@billing_address = Address.new(
|
196
|
-
full_name: 'John C Doe',
|
197
|
-
street: '123 Main St',
|
198
|
-
street2: 'Apartment 3C',
|
199
|
-
city: 'San Diego',
|
200
|
-
state: 'California',
|
201
|
-
zip_code: '91911',
|
202
|
-
)
|
203
179
|
end
|
204
|
-
|
205
|
-
markup {
|
206
|
-
div {
|
207
|
-
h1('Shipping Address')
|
208
|
-
|
209
|
-
address_form(address: @shipping_address)
|
210
|
-
|
211
|
-
h1('Billing Address')
|
212
|
-
|
213
|
-
address_form(address: @billing_address)
|
214
|
-
}
|
215
|
-
}
|
216
180
|
end
|
217
181
|
|
218
182
|
Document.ready? do
|