glimmer-dsl-web 0.6.1 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -249,6 +249,10 @@ module Glimmer
249
249
  element_binding.unregister_all_observables
250
250
  end
251
251
  data_bindings.clear
252
+ content_binding_observer_registrations.each do |observer_registration|
253
+ observer_registration.unregister
254
+ end
255
+ content_binding_observer_registrations.clear
252
256
  end
253
257
 
254
258
  # Subclasses can override with their own selector
@@ -604,16 +608,20 @@ module Glimmer
604
608
 
605
609
  def handle_observation_request(keyword, original_event_listener)
606
610
  if rendered?
607
- listener = ListenerProxy.new(
608
- element: self,
609
- selector: selector,
610
- dom_element: dom_element,
611
- event_attribute: keyword,
612
- original_event_listener: original_event_listener,
613
- )
614
- listener.register
615
- listeners_for(keyword) << listener
616
- listener
611
+ if keyword.start_with?('on_') && !['on_render', 'on_remove'].include?(keyword.to_s)
612
+ (ancestor_component || component)&.handle_observation_request(keyword, original_event_listener)
613
+ else
614
+ listener = ListenerProxy.new(
615
+ element: self,
616
+ selector: selector,
617
+ dom_element: dom_element,
618
+ event_attribute: keyword,
619
+ original_event_listener: original_event_listener,
620
+ )
621
+ listener.register
622
+ listeners_for(keyword) << listener
623
+ listener
624
+ end
617
625
  else
618
626
  enqueue_post_render_method_call('handle_observation_request', keyword, original_event_listener)
619
627
  end
@@ -691,10 +699,14 @@ module Glimmer
691
699
  end
692
700
  model_binding_observer = Glimmer::DataBinding::ModelBinding.new(*binding_args)
693
701
  content_binding_observer = Glimmer::DataBinding::Observer.proc(&content_binding_work)
694
- content_binding_observer.observe(model_binding_observer)
702
+ content_binding_observer_registrations << content_binding_observer.observe(model_binding_observer)
695
703
  content_binding_work.call # TODO inspect if we need to pass args here (from observed attributes) [but it's simpler not to pass anything at first]
696
704
  end
697
705
 
706
+ def content_binding_observer_registrations
707
+ @content_binding_observer_registrations ||= []
708
+ end
709
+
698
710
  def respond_to_missing?(method_name, include_private = false)
699
711
  # TODO consider doing more correct checking of availability of properties/methods using native ticks
700
712
  property_name = property_name_for(method_name)
@@ -21,198 +21,162 @@
21
21
 
22
22
  require 'glimmer-dsl-web'
23
23
 
24
- Address = Struct.new(:full_name, :street, :street2, :city, :state, :zip_code, keyword_init: true) do
25
- STATES = {
26
- "AK"=>"Alaska",
27
- "AL"=>"Alabama",
28
- "AR"=>"Arkansas",
29
- "AS"=>"American Samoa",
30
- "AZ"=>"Arizona",
31
- "CA"=>"California",
32
- "CO"=>"Colorado",
33
- "CT"=>"Connecticut",
34
- "DC"=>"District of Columbia",
35
- "DE"=>"Delaware",
36
- "FL"=>"Florida",
37
- "GA"=>"Georgia",
38
- "GU"=>"Guam",
39
- "HI"=>"Hawaii",
40
- "IA"=>"Iowa",
41
- "ID"=>"Idaho",
42
- "IL"=>"Illinois",
43
- "IN"=>"Indiana",
44
- "KS"=>"Kansas",
45
- "KY"=>"Kentucky",
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
- def state_code=(value)
88
- self.state = STATES[value]
89
- end
90
-
91
- def summary
92
- to_h.values.map(&:to_s).reject(&:empty?).join(', ')
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
- # AddressForm Glimmer Web Component (View component)
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
- # before_render do
111
- # end
112
-
113
- # Optionally, you can execute code after rendering markup.
114
- # This is useful for post-setup of extra Model listeners that would interact with the
115
- # markup elements and expect them to be rendered already.
116
- #
117
- # after_render do
118
- # end
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
- # markup block provides the content of the
121
- markup {
122
- div {
123
- div(style: 'display: grid; grid-auto-columns: 80px 260px;') { |address_div|
124
- label('Full Name: ', for: 'full-name-field')
125
- input(id: 'full-name-field') {
126
- value <=> [address, :full_name]
127
- }
128
-
129
- label('Street: ', for: 'street-field')
130
- input(id: 'street-field') {
131
- value <=> [address, :street]
132
- }
133
-
134
- label('Street 2: ', for: 'street2-field')
135
- textarea(id: 'street2-field') {
136
- value <=> [address, :street2]
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
- label('City: ', for: 'city-field')
140
- input(id: 'city-field') {
141
- value <=> [address, :city]
131
+ div(style: 'margin: 5px') {
132
+ inner_text <= [address, :summary,
133
+ computed_by: address.members + ['state_code'],
134
+ ]
142
135
  }
143
-
144
- label('State: ', for: 'state-field')
145
- select(id: 'state-field') {
146
- Address::STATES.each do |state_code, state|
147
- option(value: state_code) { state }
148
- end
136
+ }
137
+ }
138
+ end
139
+ end
149
140
 
150
- value <=> [address, :state_code]
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
- label('Zip Code: ', for: 'zip-code-field')
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
- style {
161
- r("#{address_div.selector} *") {
162
- margin '5px'
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
@@ -22,63 +22,18 @@
22
22
  require 'glimmer-dsl-web'
23
23
 
24
24
  unless Object.const_defined?(:Address)
25
- Address = Struct.new(:full_name, :street, :street2, :city, :state, :zip_code, keyword_init: true) do
25
+ Address = Struct.new(:full_name, :street, :street2, :city, :state, :zip_code, :billing_and_shipping, keyword_init: true) do
26
26
  STATES = {
27
- "AK"=>"Alaska",
28
- "AL"=>"Alabama",
29
- "AR"=>"Arkansas",
30
- "AS"=>"American Samoa",
31
- "AZ"=>"Arizona",
32
- "CA"=>"California",
33
- "CO"=>"Colorado",
34
- "CT"=>"Connecticut",
35
- "DC"=>"District of Columbia",
36
- "DE"=>"Delaware",
37
- "FL"=>"Florida",
38
- "GA"=>"Georgia",
39
- "GU"=>"Guam",
40
- "HI"=>"Hawaii",
41
- "IA"=>"Iowa",
42
- "ID"=>"Idaho",
43
- "IL"=>"Illinois",
44
- "IN"=>"Indiana",
45
- "KS"=>"Kansas",
46
- "KY"=>"Kentucky",
47
- "LA"=>"Louisiana",
48
- "MA"=>"Massachusetts",
49
- "MD"=>"Maryland",
50
- "ME"=>"Maine",
51
- "MI"=>"Michigan",
52
- "MN"=>"Minnesota",
53
- "MO"=>"Missouri",
54
- "MS"=>"Mississippi",
55
- "MT"=>"Montana",
56
- "NC"=>"North Carolina",
57
- "ND"=>"North Dakota",
58
- "NE"=>"Nebraska",
59
- "NH"=>"New Hampshire",
60
- "NJ"=>"New Jersey",
61
- "NM"=>"New Mexico",
62
- "NV"=>"Nevada",
63
- "NY"=>"New York",
64
- "OH"=>"Ohio",
65
- "OK"=>"Oklahoma",
66
- "OR"=>"Oregon",
67
- "PA"=>"Pennsylvania",
68
- "PR"=>"Puerto Rico",
69
- "RI"=>"Rhode Island",
70
- "SC"=>"South Carolina",
71
- "SD"=>"South Dakota",
72
- "TN"=>"Tennessee",
73
- "TX"=>"Texas",
74
- "UT"=>"Utah",
75
- "VA"=>"Virginia",
76
- "VI"=>"Virgin Islands",
77
- "VT"=>"Vermont",
78
- "WA"=>"Washington",
79
- "WI"=>"Wisconsin",
80
- "WV"=>"West Virginia",
81
- "WY"=>"Wyoming"
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"
82
37
  }
83
38
 
84
39
  def state_code
@@ -90,7 +45,10 @@ unless Object.const_defined?(:Address)
90
45
  end
91
46
 
92
47
  def summary
93
- to_h.values.map(&:to_s).reject(&:empty?).join(', ')
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
94
52
  end
95
53
  end
96
54
  end
@@ -306,6 +264,8 @@ unless Object.const_defined?(:HelloComponentListeners)
306
264
  #
307
265
  # This View component represents the main page being rendered,
308
266
  # as done by its `render` class method below
267
+ #
268
+ # Note: check out HelloComponentListenersDefaultSlot for a simpler version that leverages the default slot feature
309
269
  class HelloComponentListeners
310
270
  class Presenter
311
271
  attr_accessor :status_message
@@ -386,5 +346,6 @@ end
386
346
 
387
347
  Document.ready? do
388
348
  # renders a top-level (root) HelloComponentListeners component
349
+ # Note: check out hello_component_listeners_default_slot.rb for a simpler version that leverages the default slot feature
389
350
  HelloComponentListeners.render
390
351
  end