Module: Glimmer::Web::Component
- Includes:
- DataBinding::ObservableModel
- Included in:
- AddressForm, AddressPage, ButtonCounter, ComponentStyleContainer, ContactForm, ContactTable, HelloFormMvp, HelloObserver, HelloObserverDataBinding, HelloParagraph, HelloStyle, NewTodoForm, StyledButton, StyledButtonRangeInput, TodoFilters, TodoInput, TodoList, TodoListItem, TodoMvc, TodoMvcFooter
- Defined in:
- lib/glimmer/web/component.rb
Defined Under Namespace
Modules: ClassMethods, GlimmerSupersedable
Constant Summary
collapse
- ADD_COMPONENT_KEYWORDS_UPON_INHERITANCE =
proc do
class << self
def inherited(subclass)
Glimmer::Web::Component.add_component_keyword_to_classes_map_for(subclass)
subclass.class_eval(&Glimmer::Web::Component::ADD_COMPONENT_KEYWORDS_UPON_INHERITANCE)
end
end
end
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
-
#add_observer(observer, attribute_name) ⇒ Object
-
#attribute_setter(attribute_name) ⇒ Object
-
#bind_content(*binding_args, &content_block) ⇒ Object
-
#can_add_observer?(attribute_name) ⇒ Boolean
-
#can_handle_observation_request?(observation_request) ⇒ Boolean
-
#content(*args, &block) ⇒ Object
Returns content block if used as an attribute reader (no args) Otherwise, if a block is passed, it adds it as content to this Glimmer web component.
-
#data_bind(property, model_binding) ⇒ Object
-
#get_attribute(attribute_name) ⇒ Object
-
#handle_observation_request(observation_request, block) ⇒ Object
-
#has_attribute?(attribute_name, *args) ⇒ Boolean
-
#has_instance_method?(method_name) ⇒ Boolean
This method ensures it has an instance method not coming from Glimmer DSL.
-
#initialize(parent, args, options, &content) ⇒ Object
-
#local_respond_to? ⇒ Object
-
#method_missing(method_name, *args, &block) ⇒ Object
-
#observer_registrations ⇒ Object
This stores observe keyword registrations of model/attribute observers.
-
#post_add_content ⇒ Object
-
#post_initialize_child(child) ⇒ Object
Subclasses may override to perform post initialization work on an added child.
-
#remove ⇒ Object
-
#render(parent: nil, custom_parent_dom_element: nil, brand_new: false) ⇒ Object
-
#respond_to_missing?(method_name, include_private = false) ⇒ Boolean
-
#set_attribute(attribute_name, *args) ⇒ Object
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args, &block) ⇒ Object
407
408
409
410
411
412
413
414
415
|
# File 'lib/glimmer/web/component.rb', line 407
def method_missing(method_name, *args, &block)
if can_handle_observation_request?(method_name)
handle_observation_request(method_name, block)
elsif markup_root.respond_to?(method_name, true)
markup_root.send(method_name, *args, &block)
else
super(method_name, *args, &block)
end
end
|
Instance Attribute Details
#args ⇒ Object
252
253
254
|
# File 'lib/glimmer/web/component.rb', line 252
def args
@args
end
|
#component_style ⇒ Object
252
253
254
|
# File 'lib/glimmer/web/component.rb', line 252
def component_style
@component_style
end
|
#markup_root ⇒ Object
252
253
254
|
# File 'lib/glimmer/web/component.rb', line 252
def markup_root
@markup_root
end
|
#options ⇒ Object
252
253
254
|
# File 'lib/glimmer/web/component.rb', line 252
def options
@options
end
|
#parent ⇒ Object
Also known as:
parent_proxy
252
253
254
|
# File 'lib/glimmer/web/component.rb', line 252
def parent
@parent
end
|
#style_block ⇒ Object
252
253
254
|
# File 'lib/glimmer/web/component.rb', line 252
def style_block
@style_block
end
|
Class Method Details
.add_component(component) ⇒ Object
188
189
190
191
|
# File 'lib/glimmer/web/component.rb', line 188
def add_component(component)
component_class_to_components_map[component.class] ||= {}
component_class_to_components_map[component.class][component.object_id] = component
end
|
.add_component_keyword_to_classes_map_for(component_class) ⇒ Object
.add_component_style(component) ⇒ Object
.any_component?(component_class) ⇒ Boolean
213
214
215
|
# File 'lib/glimmer/web/component.rb', line 213
def any_component?(component_class)
component_class_to_components_map.has_key?(component_class)
end
|
.any_component_style?(component_class) ⇒ Boolean
217
218
219
|
# File 'lib/glimmer/web/component.rb', line 217
def any_component_style?(component_class)
component_styles.has_key?(component_class)
end
|
.body_components ⇒ Object
229
230
231
|
# File 'lib/glimmer/web/component.rb', line 229
def body_components
components.reject {|component| component.is_a?(ComponentStyleContainer)}
end
|
.component_class_to_components_map ⇒ Object
242
243
244
|
# File 'lib/glimmer/web/component.rb', line 242
def component_class_to_components_map
@component_class_to_components_map ||= {}
end
|
.component_count(component_class) ⇒ Object
221
222
223
|
# File 'lib/glimmer/web/component.rb', line 221
def component_count(component_class)
component_class_to_components_map[component_class].size
end
|
.component_keyword_to_classes_map ⇒ Object
176
177
178
|
# File 'lib/glimmer/web/component.rb', line 176
def component_keyword_to_classes_map
@component_keyword_to_classes_map ||= reset_component_keyword_to_classes_map
end
|
.component_styles ⇒ Object
246
247
248
|
# File 'lib/glimmer/web/component.rb', line 246
def component_styles
@component_styles ||= {}
end
|
.components ⇒ Object
225
226
227
|
# File 'lib/glimmer/web/component.rb', line 225
def components
component_class_to_components_map.values.map(&:values).flatten
end
|
.for(underscored_component_name) ⇒ Object
154
155
156
157
158
159
160
161
162
|
# File 'lib/glimmer/web/component.rb', line 154
def for(underscored_component_name)
component_classes = Glimmer::Web::Component.component_keyword_to_classes_map[underscored_component_name]
if component_classes.nil? || component_classes.empty?
Glimmer::Config.logger.debug {"#{underscored_component_name} has no Glimmer web component class!" }
nil
else
component_class = component_classes.first
end
end
|
.head_components ⇒ Object
233
234
235
|
# File 'lib/glimmer/web/component.rb', line 233
def head_components
components.select {|component| component.is_a?(ComponentStyleContainer)}
end
|
.included(klass) ⇒ Object
.interpretation_stack ⇒ Object
184
185
186
|
# File 'lib/glimmer/web/component.rb', line 184
def interpretation_stack
@interpretation_stack ||= []
end
|
.keywords_for_class(component_class) ⇒ Object
171
172
173
174
|
# File 'lib/glimmer/web/component.rb', line 171
def keywords_for_class(component_class)
namespaces = component_class.to_s.split(/::/).map(&:underscore).reverse
namespaces.size.times.map { |n| namespaces[0..n].reverse.join('__') }
end
|
.remove_all_components ⇒ Object
237
238
239
240
|
# File 'lib/glimmer/web/component.rb', line 237
def remove_all_components
body_components.each(&:remove)
end
|
.remove_component(component) ⇒ Object
193
194
195
196
|
# File 'lib/glimmer/web/component.rb', line 193
def remove_component(component)
component_class_to_components_map[component.class].delete(component.object_id)
component_class_to_components_map.delete(component.class) if component_class_to_components_map[component.class].empty?
end
|
.remove_component_style(component) ⇒ Object
.reset_component_keyword_to_classes_map ⇒ Object
180
181
182
|
# File 'lib/glimmer/web/component.rb', line 180
def reset_component_keyword_to_classes_map
@component_keyword_to_classes_map = {}
end
|
Instance Method Details
#add_observer(observer, attribute_name) ⇒ Object
334
335
336
337
338
339
340
|
# File 'lib/glimmer/web/component.rb', line 334
def add_observer(observer, attribute_name)
if has_instance_method?(attribute_name)
super(observer, attribute_name)
else
@markup_root.add_observer(observer, attribute_name)
end
end
|
#attribute_setter(attribute_name) ⇒ Object
371
372
373
|
# File 'lib/glimmer/web/component.rb', line 371
def attribute_setter(attribute_name)
"#{attribute_name}="
end
|
#bind_content(*binding_args, &content_block) ⇒ Object
388
389
390
|
# File 'lib/glimmer/web/component.rb', line 388
def bind_content(*binding_args, &content_block)
@markup_root&.bind_content(*binding_args, &content_block)
end
|
#can_add_observer?(attribute_name) ⇒ Boolean
330
331
332
|
# File 'lib/glimmer/web/component.rb', line 330
def can_add_observer?(attribute_name)
has_instance_method?(attribute_name) || has_instance_method?("#{attribute_name}?") || @markup_root.can_add_observer?(attribute_name)
end
|
#can_handle_observation_request?(observation_request) ⇒ Boolean
310
311
312
313
314
315
316
317
318
|
# File 'lib/glimmer/web/component.rb', line 310
def can_handle_observation_request?(observation_request)
observation_request = observation_request.to_s
result = false
if observation_request.start_with?('on_updated_')
property = observation_request.sub(/^on_updated_/, '')
result = can_add_observer?(property)
end
result || markup_root&.can_handle_observation_request?(observation_request)
end
|
#content(*args, &block) ⇒ Object
Returns content block if used as an attribute reader (no args) Otherwise, if a block is passed, it adds it as content to this Glimmer web component
394
395
396
397
398
399
400
401
402
403
404
405
|
# File 'lib/glimmer/web/component.rb', line 394
def content(*args, &block)
if args.empty?
if block_given?
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Web::ComponentExpression.new, self.class.keyword, &block)
else
@content
end
else
super
end
end
|
#data_bind(property, model_binding) ⇒ Object
384
385
386
|
# File 'lib/glimmer/web/component.rb', line 384
def data_bind(property, model_binding)
@markup_root&.data_bind(property, model_binding)
end
|
#get_attribute(attribute_name) ⇒ Object
363
364
365
366
367
368
369
|
# File 'lib/glimmer/web/component.rb', line 363
def get_attribute(attribute_name)
if has_instance_method?(attribute_name)
send(attribute_name)
else
@markup_root.get_attribute(attribute_name)
end
end
|
#handle_observation_request(observation_request, block) ⇒ Object
320
321
322
323
324
325
326
327
328
|
# File 'lib/glimmer/web/component.rb', line 320
def handle_observation_request(observation_request, block)
observation_request = observation_request.to_s
if observation_request.start_with?('on_updated_')
property = observation_request.sub(/^on_updated_/, '') add_observer(DataBinding::Observer.proc(&block), property) if can_add_observer?(property)
else
markup_root.handle_observation_request(observation_request, block)
end
end
|
#has_attribute?(attribute_name, *args) ⇒ Boolean
342
343
344
345
|
# File 'lib/glimmer/web/component.rb', line 342
def has_attribute?(attribute_name, *args)
has_instance_method?(attribute_setter(attribute_name)) ||
@markup_root.has_attribute?(attribute_name, *args)
end
|
#has_instance_method?(method_name) ⇒ Boolean
This method ensures it has an instance method not coming from Glimmer DSL
356
357
358
359
360
361
|
# File 'lib/glimmer/web/component.rb', line 356
def has_instance_method?(method_name)
respond_to?(method_name) and
!markup_root&.respond_to?(method_name) and
!method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
!method(method_name)&.source_location&.first&.include?('glimmer/web/element_proxy.rb')
end
|
#initialize(parent, args, options, &content) ⇒ Object
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
# File 'lib/glimmer/web/component.rb', line 255
def initialize(parent, args, options, &content)
Glimmer::Web::Component.add_component(self)
Component.interpretation_stack.push(self)
@parent = parent
options = args.delete_at(-1) if args.is_a?(Array) && args.last.is_a?(Hash)
if args.is_a?(Hash)
options = args
args = []
end
options ||= {}
@args = args
options ||= {}
@options = self.class.options.merge(options)
@content = Util::ProcTracker.new(content) if content
execute_hooks('before_render')
markup_block = self.class.instance_variable_get("@markup_block")
raise Glimmer::Error, 'Invalid Glimmer web component for having no markup! Please define markup block!' if markup_block.nil?
@markup_root = instance_exec(&markup_block)
add_style_block
@markup_root.options[:parent] = options[:parent] if !options[:parent].nil?
@parent ||= @markup_root.parent
raise Glimmer::Error, 'Invalid Glimmer web component for having an empty markup! Please fill markup block!' if @markup_root.nil?
if options[:render] != false
execute_hooks('after_render')
else
on_render_listener = proc { execute_hooks('after_render') }
@markup_root.handle_observation_request('on_render', on_render_listener)
end
observer_registration_cleanup_listener = proc do
observer_registrations.compact.each(&:deregister)
observer_registrations.clear
end
@markup_root.handle_observation_request('on_remove', observer_registration_cleanup_listener)
post_add_content if content.nil?
end
|
#local_respond_to? ⇒ Object
417
|
# File 'lib/glimmer/web/component.rb', line 417
alias local_respond_to? respond_to_missing?
|
#observer_registrations ⇒ Object
This stores observe keyword registrations of model/attribute observers
306
307
308
|
# File 'lib/glimmer/web/component.rb', line 306
def observer_registrations
@observer_registrations ||= []
end
|
#post_add_content ⇒ Object
#post_initialize_child(child) ⇒ Object
Subclasses may override to perform post initialization work on an added child
297
298
299
|
# File 'lib/glimmer/web/component.rb', line 297
def post_initialize_child(child)
end
|
#remove ⇒ Object
380
381
382
|
# File 'lib/glimmer/web/component.rb', line 380
def remove
@markup_root&.remove
end
|
#render(parent: nil, custom_parent_dom_element: nil, brand_new: false) ⇒ Object
375
376
377
378
|
# File 'lib/glimmer/web/component.rb', line 375
def render(parent: nil, custom_parent_dom_element: nil, brand_new: false)
@markup_root&.render(parent: parent, custom_parent_dom_element: custom_parent_dom_element, brand_new: brand_new)
end
|
#respond_to_missing?(method_name, include_private = false) ⇒ Boolean
418
419
420
421
422
|
# File 'lib/glimmer/web/component.rb', line 418
def respond_to_missing?(method_name, include_private = false)
super(method_name, include_private) or
can_handle_observation_request?(method_name) or
markup_root.respond_to?(method_name, include_private)
end
|
#set_attribute(attribute_name, *args) ⇒ Object
347
348
349
350
351
352
353
|
# File 'lib/glimmer/web/component.rb', line 347
def set_attribute(attribute_name, *args)
if has_instance_method?(attribute_setter(attribute_name))
send(attribute_setter(attribute_name), *args)
else
@markup_root.set_attribute(attribute_name, *args)
end
end
|