glimmer-dsl-web 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.5
@@ -2,17 +2,17 @@
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.0.3 ruby lib
5
+ # stub: glimmer-dsl-web 0.0.5 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-web".freeze
9
- s.version = "0.0.3".freeze
9
+ s.version = "0.0.5".freeze
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 = "2023-12-28"
15
- s.description = "Glimmer DSL for Web (Ruby in the Browser Web GUI Library) - Enables frontend GUI development with Ruby by adopting a DSL that follows web-like HTML syntax, enabling the transfer of HTML/CSS/JS skills to Ruby frontend development. This library relies on Opal Ruby.".freeze
14
+ s.date = "2023-12-30"
15
+ s.description = "Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library) - Enables frontend GUI development with Ruby by adopting a DSL that follows web-like HTML syntax, enabling the transfer of HTML/CSS/JS skills to Ruby frontend development. This library relies on Opal Ruby.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
18
18
  "CHANGELOG.md",
@@ -31,24 +31,27 @@ Gem::Specification.new do |s|
31
31
  "lib/glimmer-dsl-web/ext/date.rb",
32
32
  "lib/glimmer-dsl-web/ext/exception.rb",
33
33
  "lib/glimmer-dsl-web/samples/hello/hello_button.rb",
34
+ "lib/glimmer-dsl-web/samples/hello/hello_form.rb",
34
35
  "lib/glimmer-dsl-web/samples/hello/hello_world.rb",
35
36
  "lib/glimmer-dsl-web/vendor/jquery.js",
36
37
  "lib/glimmer/config/opal_logger.rb",
37
38
  "lib/glimmer/data_binding/element_binding.rb",
38
- "lib/glimmer/data_binding/observable_element.rb",
39
39
  "lib/glimmer/dsl/web/dsl.rb",
40
40
  "lib/glimmer/dsl/web/element_expression.rb",
41
41
  "lib/glimmer/dsl/web/listener_expression.rb",
42
+ "lib/glimmer/dsl/web/p_expression.rb",
43
+ "lib/glimmer/dsl/web/property_expression.rb",
42
44
  "lib/glimmer/util/proc_tracker.rb",
43
45
  "lib/glimmer/web.rb",
44
46
  "lib/glimmer/web/element_proxy.rb",
47
+ "lib/glimmer/web/event_proxy.rb",
45
48
  "lib/glimmer/web/listener_proxy.rb",
46
49
  "lib/glimmer/web/property_owner.rb"
47
50
  ]
48
51
  s.homepage = "http://github.com/AndyObtiva/glimmer-dsl-web".freeze
49
52
  s.licenses = ["MIT".freeze]
50
53
  s.rubygems_version = "3.5.3".freeze
51
- s.summary = "Glimmer DSL for Web".freeze
54
+ s.summary = "Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library)".freeze
52
55
 
53
56
  s.specification_version = 4
54
57
 
@@ -2,6 +2,8 @@ require 'glimmer/dsl/engine'
2
2
  # Dir[File.expand_path('../*_expression.rb', __FILE__)].each {|f| require f}
3
3
  require 'glimmer/dsl/web/element_expression'
4
4
  require 'glimmer/dsl/web/listener_expression'
5
+ require 'glimmer/dsl/web/property_expression'
6
+ require 'glimmer/dsl/web/p_expression'
5
7
 
6
8
  module Glimmer
7
9
  module DSL
@@ -10,7 +12,7 @@ module Glimmer
10
12
  # %w[
11
13
  # listener
12
14
  # data_binding
13
- # attribute
15
+ # property
14
16
  # shine_data_binding
15
17
  # element
16
18
  # ]
@@ -18,6 +20,7 @@ module Glimmer
18
20
  Web,
19
21
  %w[
20
22
  listener
23
+ property
21
24
  element
22
25
  ]
23
26
  )
@@ -11,7 +11,7 @@ module Glimmer
11
11
  def can_interpret?(parent, keyword, *args, &block)
12
12
  # TODO automatically pass parent option as element if not passed instead of rejecting elements without a paraent nor root
13
13
  # TODO raise a proper error if root is an element that is not found (maybe do this in model)
14
- !keyword.to_s.start_with?('on_')
14
+ !keyword.to_s.start_with?('on')
15
15
  end
16
16
 
17
17
  def interpret(parent, keyword, *args, &block)
@@ -0,0 +1,31 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/dsl/parent_expression'
3
+
4
+ require 'glimmer/web/element_proxy'
5
+
6
+ module Glimmer
7
+ module DSL
8
+ module Web
9
+ class PExpression < StaticExpression
10
+ include ParentExpression
11
+
12
+ def interpret(parent, keyword, *args, &block)
13
+ Glimmer::Web::ElementProxy.for(keyword, parent, args, block)
14
+ end
15
+
16
+ def add_content(parent, keyword, *args, &block)
17
+ if parent.rendered? || parent.skip_content_on_render_blocks?
18
+ return_value = super(parent, keyword, *args, &block)
19
+ if return_value.is_a?(String) && parent.dom_element.text.to_s.empty?
20
+ parent.add_text_content(return_value)
21
+ end
22
+ parent.post_add_content
23
+ return_value
24
+ else
25
+ parent.add_content_on_render(&block)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ require 'glimmer/dsl/expression'
2
+
3
+ require 'glimmer/web/element_proxy'
4
+
5
+ module Glimmer
6
+ module DSL
7
+ module Web
8
+ class PropertyExpression < Expression
9
+ def can_interpret?(parent, keyword, *args, &block)
10
+ parent.is_a?(Glimmer::Web::ElementProxy) and
11
+ (!args.empty?) and
12
+ parent.respond_to?("#{keyword}=") and
13
+ block.nil?
14
+ end
15
+
16
+ def interpret(parent, keyword, *args, &block)
17
+ parent.send("#{keyword}=", *args)
18
+ args
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -74,7 +74,7 @@ module Glimmer
74
74
 
75
75
  GLIMMER_ATTRIBUTES = [:parent]
76
76
 
77
- attr_reader :keyword, :parent, :args, :options, :children, :enabled, :foreground, :background, :focus, :removed?, :rendered
77
+ attr_reader :keyword, :parent, :args, :options, :children, :enabled, :foreground, :background, :removed?, :rendered
78
78
  alias rendered? rendered
79
79
 
80
80
  def initialize(keyword, parent, args, block)
@@ -95,7 +95,7 @@ module Glimmer
95
95
 
96
96
  # Executes for the parent of a child that just got removed
97
97
  def post_remove_child(child)
98
- @children&.delete(child)
98
+ @children.delete(child)
99
99
  end
100
100
 
101
101
  # Executes at the closing of a parent widget curly braces after all children/properties have been added/set
@@ -108,26 +108,19 @@ module Glimmer
108
108
  end
109
109
 
110
110
  def remove
111
+ @children.dup.each do |child|
112
+ child.remove
113
+ end
111
114
  remove_all_listeners
112
115
  dom_element.remove
113
116
  parent&.post_remove_child(self)
114
- # children.each(:remove) # TODO enable this safely
115
117
  @removed = true
116
- listeners_for('widget_removed').each {|listener| listener.call(Event.new(widget: self))}
118
+ # listeners_for('widget_removed').each {|listener| listener.call(Event.new(widget: self))}
117
119
  end
118
120
 
119
121
  def remove_all_listeners
120
- effective_observation_request_to_event_mapping.keys.each do |keyword|
121
- effective_observation_request_to_event_mapping[keyword].to_collection.each do |mapping|
122
- observation_requests[keyword].to_a.each do |event_listener|
123
- event = mapping[:event]
124
- event_handler = mapping[:event_handler]
125
- event_element_css_selector = mapping[:event_element_css_selector]
126
- the_listener_dom_element = event_element_css_selector ? Element[event_element_css_selector] : listener_dom_element
127
- the_listener_dom_element.off(event, event_listener)
128
- # TODO improve to precisely remove the listeners that were added, no more no less. (or use the event_listener_proxies method instead or in collaboration)
129
- end
130
- end
122
+ listeners.each do |event, event_listeners|
123
+ event_listeners.dup.each(&:unregister)
131
124
  end
132
125
  end
133
126
 
@@ -183,16 +176,6 @@ module Glimmer
183
176
  dom_element.css('background-color', background.to_css) unless background.nil?
184
177
  end
185
178
 
186
- def focus=(value)
187
- @focus = value
188
- dom_element.focus # TODO consider if a delay or async_exec is needed here
189
- end
190
-
191
- def set_focus
192
- self.focus = true
193
- end
194
- alias setFocus set_focus
195
-
196
179
  def parent_selector
197
180
  @parent&.selector
198
181
  end
@@ -233,7 +216,7 @@ module Glimmer
233
216
  end
234
217
  end
235
218
  end
236
- alias redraw render
219
+ alias rerender render
237
220
 
238
221
  def attach(the_parent_dom_element)
239
222
  the_parent_dom_element.append(@dom)
@@ -267,7 +250,6 @@ module Glimmer
267
250
  # TODO consider passing parent element instead and having table item include a table cell widget only for opal
268
251
  @dom = nil
269
252
  @dom = dom # TODO unify how to build dom for most widgets based on element, id, and name (class)
270
- # @dom = @parent.get_layout.dom(@dom) if @parent.respond_to?(:layout) && @parent.get_layout
271
253
  @dom
272
254
  end
273
255
 
@@ -275,17 +257,6 @@ module Glimmer
275
257
  # TODO auto-convert known glimmer attributes like parent to data attributes like data-parent
276
258
  @dom ||= html {
277
259
  send(keyword, html_options) {
278
- # TODO consider supporting the idea of dynamic CSS building on close of shell that adds only as much CSS as needed for widgets that were mentioned
279
- # style(class: 'common-style') {
280
- # style_dom_css
281
- # }
282
- # [LayoutProxy, WidgetProxy].map(&:descendants).reduce(:+).each do |style_class|
283
- # if style_class.constants.include?('STYLE')
284
- # style(class: "#{style_class.name.split(':').last.underscore.gsub('_', '-').sub(/-proxy$/, '')}-style") {
285
- # style_class::STYLE
286
- # }
287
- # end
288
- # end
289
260
  args.first if args.first.is_a?(String)
290
261
  }
291
262
  }.to_s
@@ -762,7 +733,7 @@ module Glimmer
762
733
  def can_handle_observation_request?(keyword)
763
734
  # TODO sort this out for Opal
764
735
  keyword = keyword.to_s
765
- keyword.start_with?('on_')
736
+ keyword.start_with?('on')
766
737
  # if keyword.start_with?('on_swt_')
767
738
  # constant_name = keyword.sub(/^on_swt_/, '')
768
739
  # SWTProxy.has_constant?(constant_name)
@@ -784,14 +755,15 @@ module Glimmer
784
755
 
785
756
  def handle_javascript_observation_request(keyword, original_event_listener)
786
757
  listener = ListenerProxy.new(
787
- element_proxy: self,
758
+ element: self,
788
759
  selector: selector,
789
760
  dom_element: dom_element,
790
- event: keyword.sub(/^on_/, ''),
761
+ event_attribute: keyword,
791
762
  listener: original_event_listener,
792
763
  original_event_listener: original_event_listener
793
764
  )
794
765
  listener.register
766
+ listeners_for(keyword) << listener
795
767
  listener
796
768
  # return unless effective_observation_request_to_event_mapping.keys.include?(keyword)
797
769
  # event = nil
@@ -845,22 +817,33 @@ module Glimmer
845
817
  end
846
818
 
847
819
  def respond_to_missing?(method_name, include_private = false)
820
+ # TODO consider doing more correct checking of availability of properties/methods using native `` ticks
821
+ property_name = property_name_for(method_name)
848
822
  super(method_name, include_private) ||
849
- (dom_element && dom_element.length > 0 && Native.call(dom_element, '0').respond_to?(method_name, include_private)) ||
823
+ (dom_element && dom_element.length > 0 && Native.call(dom_element, '0').respond_to?(method_name.to_s.camelcase, include_private)) ||
850
824
  dom_element.respond_to?(method_name, include_private) ||
825
+ (!dom_element.prop(property_name).nil? && !dom_element.prop(property_name).is_a?(Proc)) ||
851
826
  method_name.to_s.start_with?('on_')
852
827
  end
853
828
 
854
829
  def method_missing(method_name, *args, &block)
830
+ # TODO consider doing more correct checking of availability of properties/methods using native `` ticks
831
+ property_name = property_name_for(method_name)
855
832
  if method_name.to_s.start_with?('on_')
856
833
  handle_observation_request(method_name, block)
857
834
  elsif dom_element.respond_to?(method_name)
858
835
  dom_element.send(method_name, *args, &block)
836
+ elsif !dom_element.prop(property_name).nil? && !dom_element.prop(property_name).is_a?(Proc)
837
+ if method_name.end_with?('=')
838
+ dom_element.prop(property_name, *args)
839
+ else
840
+ dom_element.prop(property_name)
841
+ end
859
842
  elsif dom_element && dom_element.length > 0
860
843
  begin
861
844
  js_args = block.nil? ? args : (args + [block])
862
845
  Native.call(dom_element, '0').method_missing(method_name.to_s.camelcase, *js_args)
863
- rescue Exception
846
+ rescue Exception => e
864
847
  super(method_name, *args, &block)
865
848
  end
866
849
  else
@@ -868,6 +851,10 @@ module Glimmer
868
851
  end
869
852
  end
870
853
 
854
+ def property_name_for(method_name)
855
+ method_name.end_with?('=') ? method_name.to_s[0...-1].camelcase : method_name.to_s.camelcase
856
+ end
857
+
871
858
  def swt_widget
872
859
  # only added for compatibility/adaptibility with Glimmer DSL for SWT
873
860
  self
@@ -0,0 +1,59 @@
1
+ # Copyright (c) 2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ module Glimmer
23
+ module Web
24
+ class EventProxy
25
+ attr_reader :js_event, :listener
26
+
27
+ def initialize(js_event:, listener:)
28
+ @js_event = js_event
29
+ @listener = listener
30
+ end
31
+
32
+ def element = listener.element
33
+ def event_name = listener.event_name
34
+ def event_attribute = listener.event_attribute
35
+
36
+ def original_event
37
+ Native(`#{js_event.to_n}.originalEvent`)
38
+ end
39
+
40
+ def respond_to_missing?(method_name, include_private = false)
41
+ property_name = method_name.to_s.camelcase
42
+ super(method_name, include_private) ||
43
+ js_event.respond_to?(method_name, include_private) ||
44
+ `#{property_name} in #{original_event.to_n}`
45
+ end
46
+
47
+ def method_missing(method_name, *args, &block)
48
+ property_name = method_name.to_s.camelcase
49
+ if js_event.respond_to?(method_name, true)
50
+ js_event.send(method_name, *args, &block)
51
+ elsif `#{property_name} in #{original_event.to_n}`
52
+ original_event[property_name]
53
+ else
54
+ super(method_name, *args, &block)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,34 +1,58 @@
1
+ # Copyright (c) 2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/web/event_proxy'
23
+
1
24
  module Glimmer
2
25
  module Web
3
26
  class ListenerProxy
4
- attr_reader :element_proxy, :event, :dom_element, :selector, :listener, :original_event_listener
27
+ attr_reader :element, :event_attribute, :event_name, :dom_element, :selector, :listener, :js_listener, :original_event_listener
5
28
 
6
- def initialize(element_proxy:, event:, dom_element:, selector:, listener:)
7
- @element_proxy = element_proxy
8
- @event = event
29
+ def initialize(element:, event_attribute:, dom_element:, selector:, listener:)
30
+ @element = element
31
+ @event_attribute = event_attribute
32
+ @event_name = event_attribute.sub(/^on/, '')
9
33
  @dom_element = dom_element
10
34
  @selector = selector
11
35
  @listener = listener
12
- @js_listener = lambda do |event|
13
- event.prevent
14
- event.prevent_default
15
- event.stop_propagation
16
- event.stop_immediate_propagation
36
+ @js_listener = lambda do |js_event|
17
37
  # TODO wrap event with a Ruby Event object before passing to listener
18
- listener.call(event)
19
- false
38
+ event = EventProxy.new(js_event: js_event, listener: self)
39
+ result = listener.call(event)
40
+ result = true if result.nil?
41
+ result
20
42
  end
21
43
  @original_event_listener = original_event_listener
22
44
  end
23
45
 
24
46
  def register
25
- @dom_element.on(@event, &@js_listener)
47
+ @dom_element.on(@event_name, &@js_listener)
26
48
  end
27
49
  alias observe register
28
50
  alias reregister register
29
51
 
30
52
  def unregister
31
- @dom_element.off(@event, &@js_listener)
53
+ # TODO contribute fix to opal to allow passing observer with & to off with selector not specified as nil
54
+ @dom_element.off(@event_name, @js_listener)
55
+ @element.listeners_for(@event_attribute).delete(self)
32
56
  end
33
57
  alias unobserve unregister
34
58
  alias deregister unregister
@@ -25,75 +25,10 @@ include Glimmer
25
25
 
26
26
  Document.ready? do
27
27
  div {
28
- h1('Contact Form')
29
- form {
30
- div(class: 'field-row') {
31
- label('Name: ', for: 'name-field')
32
- @name_input = input(id: 'name-field', class: 'field', type: 'text', required: true)
33
- }
34
- div(class: 'field-row') {
35
- label('Email: ', for: 'email-field')
36
- @email_input = input(id: 'email-field', class: 'field', type: 'email', required: true)
37
- }
38
- @add_button = button('Add Contact', class: 'submit-button') {
39
- on_click do
40
- if ([@name_input, @email_input].all? {|input| input.check_validity })
41
- @table.content {
42
- tr {
43
- td { @name_input.value }
44
- td { @email_input.value }
45
- }
46
- }
47
- @email_input.value = @name_input.value = ''
48
- else
49
- error_messages = []
50
- error_messages << "Name is not valid! Make sure it is filled." if !@name_input.check_validity
51
- error_messages << "Email is not valid! Make sure it is filled and has a valid format." if !@email_input.check_validity
52
- $$.alert(error_messages.join("\n"))
53
- end
54
- end
55
- }
56
- }
57
- h1('Contacts Table')
58
- @table = table {
59
- tr {
60
- th('Name')
61
- th('Email')
62
- }
63
- tr {
64
- td('John Doe')
65
- td('johndoe@example.com')
66
- }
67
- tr {
68
- td('Jane Doe')
69
- td('janedoe@example.com')
70
- }
71
- }
72
-
73
- # CSS Styles
74
- style {
75
- <<~CSS
76
- .field-row {
77
- margin: 10px 5px;
78
- }
79
- .field {
80
- margin-left: 5px;
81
- }
82
- .submit-button {
83
- display: block;
84
- margin: 10px 5px;
85
- }
86
- table {
87
- border:1px solid grey;
88
- border-spacing: 0;
89
- }
90
- table tr td, table tr th {
91
- padding: 5px;
92
- }
93
- table tr:nth-child(even) {
94
- background: #ccc;
95
- }
96
- CSS
28
+ button('Greet') {
29
+ onclick do
30
+ $$.alert('Hello, Button!')
31
+ end
97
32
  }
98
33
  }.render
99
34
  end
@@ -0,0 +1,102 @@
1
+ # Copyright (c) 2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-web'
23
+
24
+ include Glimmer
25
+
26
+ Document.ready? do
27
+ div {
28
+ h1('Contact Form')
29
+
30
+ form {
31
+ div {
32
+ label('Name: ', for: 'name-field')
33
+ @name_input = input(type: 'text', id: 'name-field', required: true, autofocus: true)
34
+ }
35
+
36
+ div {
37
+ label('Email: ', for: 'email-field')
38
+ @email_input = input(type: 'email', id: 'email-field', required: true)
39
+ }
40
+
41
+ div {
42
+ input(type: 'submit', value: 'Add Contact') {
43
+ onclick do |event|
44
+ if ([@name_input, @email_input].all? {|input| input.check_validity })
45
+ event.prevent_default
46
+ # re-open table content and add row
47
+ @table.content {
48
+ tr {
49
+ td { @name_input.value }
50
+ td { @email_input.value }
51
+ }
52
+ }
53
+ @email_input.value = @name_input.value = ''
54
+ @name_input.focus
55
+ end
56
+ end
57
+ }
58
+ }
59
+ }
60
+
61
+ h1('Contacts Table')
62
+
63
+ @table = table {
64
+ tr {
65
+ th('Name')
66
+ th('Email')
67
+ }
68
+
69
+ tr {
70
+ td('John Doe')
71
+ td('johndoe@example.com')
72
+ }
73
+
74
+ tr {
75
+ td('Jane Doe')
76
+ td('janedoe@example.com')
77
+ }
78
+ }
79
+
80
+ # CSS Styles
81
+ style {
82
+ <<~CSS
83
+ input {
84
+ margin: 5px;
85
+ }
86
+ input[type=submit] {
87
+ margin: 5px 0;
88
+ }
89
+ table {
90
+ border:1px solid grey;
91
+ border-spacing: 0;
92
+ }
93
+ table tr td, table tr th {
94
+ padding: 5px;
95
+ }
96
+ table tr:nth-child(even) {
97
+ background: #ccc;
98
+ }
99
+ CSS
100
+ }
101
+ }.render
102
+ end
@@ -76,12 +76,7 @@ if RUBY_ENGINE == 'opal'
76
76
  require 'glimmer-dsl-xml'
77
77
  require 'glimmer-dsl-css'
78
78
 
79
- # TODO double check if alias native calls below have been added to jQuery-Opal (remove if so)
80
- Element.alias_native :replace_with, :replaceWith
81
- Element.alias_native :select
82
- # Element.alias_native :dialog
83
-
84
- Glimmer::Config.loop_max_count = 150 # TODO disable
79
+ Glimmer::Config.loop_max_count = 150 # TODO consider disabling if preferred
85
80
 
86
81
  original_logger_level = Glimmer::Config.logger.level
87
82
  Glimmer::Config.logger = Glimmer::Config::OpalLogger.new(STDOUT)