glimmer-dsl-web 0.0.4 → 0.0.6

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.
@@ -1,36 +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
53
  # TODO contribute fix to opal to allow passing observer with & to off with selector not specified as nil
32
- @dom_element.off(@event, @js_listener)
33
- @element_proxy.listeners_for(@event).delete(self)
54
+ @dom_element.off(@event_name, @js_listener)
55
+ @element.listeners_for(@event_attribute).delete(self)
34
56
  end
35
57
  alias unobserve unregister
36
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
- 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,166 @@
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
+ Address = Struct.new(: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
86
+
87
+ def state_code=(value)
88
+ self.state = STATES[value]
89
+ end
90
+
91
+ def summary
92
+ values.map(&:to_s).reject(&:empty?).join(', ')
93
+ end
94
+ end
95
+
96
+ @address = Address.new(
97
+ street: '123 Main St',
98
+ street2: 'Apartment 3C, 2nd door to the right',
99
+ city: 'San Diego',
100
+ state: 'California',
101
+ zip_code: '91911'
102
+ )
103
+
104
+ include Glimmer
105
+
106
+ Document.ready? do
107
+ div {
108
+ form(style: 'display: grid; grid-auto-columns: 80px 200px;') { |address_form|
109
+ label('Street: ', for: 'street-field')
110
+ input(id: 'street-field') {
111
+ # Bidirectional Data-Binding with <=> ensures input.value and @address.street
112
+ # automatically stay in sync when either side changes
113
+ value <=> [@address, :street]
114
+ }
115
+
116
+ label('Street 2: ', for: 'street2-field')
117
+ textarea(id: 'street2-field') {
118
+ value <=> [@address, :street2]
119
+ }
120
+
121
+ label('City: ', for: 'city-field')
122
+ input(id: 'city-field') {
123
+ value <=> [@address, :city]
124
+ }
125
+
126
+ label('State: ', for: 'state-field')
127
+ select(id: 'state-field') {
128
+ Address::STATES.each do |state_code, state|
129
+ option(value: state_code) { state }
130
+ end
131
+
132
+ value <=> [@address, :state_code]
133
+ }
134
+
135
+ label('Zip Code: ', for: 'zip-code-field')
136
+ input(id: 'zip-code-field', type: 'number', min: '0', max: '99999') {
137
+ # Bidirectional Data-Binding with <=> ensures input.value and @address.zip_code
138
+ # automatically stay in sync when either side changes
139
+ # on_write option specifies :to_s method to invoke on value before writing to model attribute
140
+ # to ensure the numeric zip code value is stored as a String
141
+ value <=> [@address, :zip_code,
142
+ on_write: :to_s
143
+ ]
144
+ }
145
+
146
+ style {
147
+ <<~CSS
148
+ .#{address_form.element_id} * {
149
+ margin: 5px;
150
+ }
151
+ .#{address_form.element_id} input, .#{address_form.element_id} select {
152
+ grid-column: 2;
153
+ }
154
+ CSS
155
+ }
156
+ }
157
+
158
+ div(style: 'margin: 5px') {
159
+ # Unidirectional Data-Binding is done with <= to ensure @address.summary changes update div.inner_text
160
+ # as computed by changes to the address member attributes + state_code address custom attribute
161
+ inner_text <= [@address, :summary,
162
+ computed_by: @address.members + ['state_code']
163
+ ]
164
+ }
165
+ }.render
166
+ 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
@@ -48,7 +48,6 @@ if RUBY_ENGINE == 'opal'
48
48
  require 'opal-async'
49
49
  require 'async/ext'
50
50
  require 'to_collection'
51
- require 'pure-struct' # TODO double check if the latest Opal implemented everything below already
52
51
  require 'glimmer-dsl-web/vendor/jquery'
53
52
  require 'opal-jquery'
54
53
  require 'opal/jquery/local_storage'
@@ -76,12 +75,7 @@ if RUBY_ENGINE == 'opal'
76
75
  require 'glimmer-dsl-xml'
77
76
  require 'glimmer-dsl-css'
78
77
 
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
78
+ Glimmer::Config.loop_max_count = 150 # TODO consider disabling if preferred
85
79
 
86
80
  original_logger_level = Glimmer::Config.logger.level
87
81
  Glimmer::Config.logger = Glimmer::Config::OpalLogger.new(STDOUT)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-30 00:00:00.000000000 Z
11
+ date: 2024-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -86,26 +86,6 @@ dependencies:
86
86
  - - "<"
87
87
  - !ruby/object:Gem::Version
88
88
  version: 3.0.0
89
- - !ruby/object:Gem::Dependency
90
- name: pure-struct
91
- requirement: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: 1.0.2
96
- - - "<"
97
- - !ruby/object:Gem::Version
98
- version: 2.0.0
99
- type: :runtime
100
- prerelease: false
101
- version_requirements: !ruby/object:Gem::Requirement
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: 1.0.2
106
- - - "<"
107
- - !ruby/object:Gem::Version
108
- version: 2.0.0
109
89
  - !ruby/object:Gem::Dependency
110
90
  name: puts_debuggerer
111
91
  requirement: !ruby/object:Gem::Requirement
@@ -259,18 +239,26 @@ files:
259
239
  - lib/glimmer-dsl-web/ext/date.rb
260
240
  - lib/glimmer-dsl-web/ext/exception.rb
261
241
  - lib/glimmer-dsl-web/samples/hello/hello_button.rb
242
+ - lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb
243
+ - lib/glimmer-dsl-web/samples/hello/hello_form.rb
262
244
  - lib/glimmer-dsl-web/samples/hello/hello_world.rb
263
245
  - lib/glimmer-dsl-web/vendor/jquery.js
264
246
  - lib/glimmer/config/opal_logger.rb
265
247
  - lib/glimmer/data_binding/element_binding.rb
266
- - lib/glimmer/data_binding/observable_element.rb
248
+ - lib/glimmer/dsl/web/bind_expression.rb
249
+ - lib/glimmer/dsl/web/data_binding_expression.rb
267
250
  - lib/glimmer/dsl/web/dsl.rb
268
251
  - lib/glimmer/dsl/web/element_expression.rb
252
+ - lib/glimmer/dsl/web/general_element_expression.rb
269
253
  - lib/glimmer/dsl/web/listener_expression.rb
254
+ - lib/glimmer/dsl/web/p_expression.rb
270
255
  - lib/glimmer/dsl/web/property_expression.rb
256
+ - lib/glimmer/dsl/web/select_expression.rb
257
+ - lib/glimmer/dsl/web/shine_data_binding_expression.rb
271
258
  - lib/glimmer/util/proc_tracker.rb
272
259
  - lib/glimmer/web.rb
273
260
  - lib/glimmer/web/element_proxy.rb
261
+ - lib/glimmer/web/event_proxy.rb
274
262
  - lib/glimmer/web/listener_proxy.rb
275
263
  - lib/glimmer/web/property_owner.rb
276
264
  homepage: http://github.com/AndyObtiva/glimmer-dsl-web
@@ -1,14 +0,0 @@
1
- module Glimmer
2
- module DataBinding
3
- module ObservableElement
4
- def method_missing(method, *args, &block)
5
- method_name = method.to_s
6
- if method_name.start_with?('on_')
7
- handle_observation_request(method_name, block)
8
- else
9
- super
10
- end
11
- end
12
- end
13
- end
14
- end