glimmer-dsl-opal 0.0.3 → 0.0.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8fcd24e24134d90f11791bfa99b68aa16726b3ac97a8d77bad5bdba4761c866
4
- data.tar.gz: 32f0a803b817689f9ea48e4fda7506fcc562eb606bb546cb1735c77a2ff60487
3
+ metadata.gz: 4abedea4353104a18359a2131eee38b7cff23498f246e35ddec92380798c5555
4
+ data.tar.gz: cbba1e1d0b89ebd01c9ddba94cfbeeee5359f93b985e192d826829369794c85e
5
5
  SHA512:
6
- metadata.gz: b9a3ada345381b967ff44feb61d2a5f52dfba6ce1297c6e3f5d21359276dbdcd3844fc4bc731475f34219f13281d89fe5a1bdb1e7adafd08093e286ec36e6ef8
7
- data.tar.gz: e120cdd6aad1afd34b95f59cc805b975dd2348e3b32de13c3ef20402c4c22c9fc0308a97a71846656db2928c038b70bc46014a532616afd8d43e752f5ce9f509
6
+ metadata.gz: 8223f782d4e4daeefa03081e95b54fc4ab0e9782825a4fd4c17d041d73284c7bf1c78a3141defa526b648e5d6ab41b63ffafea610584d235f7f6b29adb21d3ca
7
+ data.tar.gz: d8f62269cc84ae305f3e6cbd74d371272008d7ed1f6d2d8bb44b3fb95cc96247c7628fb95f788a19e2e30d67aedf017dfc19e82b8467af349d000013caa05219
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=65 /> Glimmer DSL for Opal 0.0.3 (Web GUI for Desktop Apps)
2
+ # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=65 /> Glimmer DSL for Opal 0.0.4 (Web GUI for Desktop Apps)
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-opal.svg)](http://badge.fury.io/rb/glimmer-dsl-opal)
4
4
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
5
 
@@ -7,10 +7,12 @@
7
7
 
8
8
  It enables running [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps on the web via [Rails](https://rubyonrails.org/) 5 and [Opal](https://opalrb.com/) 1.
9
9
 
10
- NOTE: Alpha Version 0.0.3 only supports capabilities for:
11
- - Hello, World!
12
- - Hello, Combo!
13
- - Hello, Computed!
10
+ NOTE: Alpha Version 0.0.4 only supports capabilities below (detailed under [Examples](#examples)):
11
+ - [Hello, World!](#hello-world)
12
+ - [Hello, Combo!](#hello-combo)
13
+ - [Hello, Computed!](#hello-computed)
14
+ - [Hello, List Single Selection!](#hello-list-single-selection)
15
+ - [Hello, List Multi Selection!](#hello-list-multi-selection)
14
16
 
15
17
  Other Glimmer DSL gems:
16
18
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI)
@@ -27,6 +29,7 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
27
29
  - `button`
28
30
  - `text`
29
31
  - `composite`
32
+ - `list` & `list(:multi)`
30
33
  - `grid_layout`
31
34
  - `layout_data`
32
35
 
@@ -51,7 +54,7 @@ Add the following to `Gemfile` (NOTE: if you run into issues, they are probably
51
54
  ```
52
55
  gem 'opal-rails'
53
56
  gem 'opal-browser'
54
- gem 'glimmer-dsl-opal', '~> 0.0.3', require: false
57
+ gem 'glimmer-dsl-opal', '~> 0.0.4', require: false
55
58
  ```
56
59
 
57
60
  Edit `config/initializers/assets.rb` and add:
@@ -183,8 +186,6 @@ class HelloComputed
183
186
  end
184
187
  end
185
188
 
186
- require_relative "hello_computed/contact"
187
-
188
189
  class HelloComputed
189
190
  include Glimmer
190
191
 
@@ -270,6 +271,130 @@ You should see "Hello, Computed!"
270
271
 
271
272
  ![Glimmer DSL for Opal Hello Computed](images/glimmer-dsl-opal-hello-computed.png)
272
273
 
274
+ ### Hello, List Single Selection!
275
+
276
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
277
+
278
+ ```ruby
279
+ class Person
280
+ attr_accessor :country, :country_options
281
+
282
+ def initialize
283
+ self.country_options=["", "Canada", "US", "Mexico"]
284
+ self.country = "Canada"
285
+ end
286
+
287
+ def reset_country
288
+ self.country = "Canada"
289
+ end
290
+ end
291
+
292
+ class HelloListSingleSelection
293
+ include Glimmer
294
+ def launch
295
+ person = Person.new
296
+ shell {
297
+ composite {
298
+ list {
299
+ selection bind(person, :country)
300
+ }
301
+ button {
302
+ text "Reset"
303
+ on_widget_selected do
304
+ person.reset_country
305
+ end
306
+ }
307
+ }
308
+ }.open
309
+ end
310
+ end
311
+
312
+ HelloListSingleSelection.new.launch
313
+ ```
314
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
315
+
316
+ ![Glimmer DSL for Opal Hello List Single Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-single-selection.png)
317
+
318
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
319
+
320
+ Start the Rails server:
321
+ ```
322
+ rails s
323
+ ```
324
+
325
+ Visit `http://localhost:3000`
326
+
327
+ You should see "Hello, List Single Selection!"
328
+
329
+ ![Glimmer DSL for Opal Hello List Single Selection](images/glimmer-dsl-opal-hello-list-single-selection.png)
330
+
331
+ ### Hello, List Multi Selection!
332
+
333
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
334
+
335
+ ```ruby
336
+ class Person
337
+ attr_accessor :provinces, :provinces_options
338
+
339
+ def initialize
340
+ self.provinces_options=[
341
+ "",
342
+ "Quebec",
343
+ "Ontario",
344
+ "Manitoba",
345
+ "Saskatchewan",
346
+ "Alberta",
347
+ "British Columbia",
348
+ "Nova Skotia",
349
+ "Newfoundland"
350
+ ]
351
+ self.provinces = ["Quebec", "Manitoba", "Alberta"]
352
+ end
353
+
354
+ def reset_provinces
355
+ self.provinces = ["Quebec", "Manitoba", "Alberta"]
356
+ end
357
+ end
358
+
359
+ class HelloListMultiSelection
360
+ include Glimmer
361
+ def launch
362
+ person = Person.new
363
+ shell {
364
+ composite {
365
+ list(:multi) {
366
+ selection bind(person, :provinces)
367
+ }
368
+ button {
369
+ text "Reset"
370
+ on_widget_selected do
371
+ person.reset_provinces
372
+ end
373
+ }
374
+ }
375
+ }.open
376
+ end
377
+ end
378
+
379
+ HelloListMultiSelection.new.launch
380
+ ```
381
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
382
+
383
+ ![Glimmer DSL for Opal Hello List Multi Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-multi-selection.png)
384
+
385
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
386
+
387
+ Start the Rails server:
388
+ ```
389
+ rails s
390
+ ```
391
+
392
+ Visit `http://localhost:3000`
393
+
394
+ You should see "Hello, List Multi Selection!"
395
+
396
+ ![Glimmer DSL for Opal Hello List Multi Selection](images/glimmer-dsl-opal-hello-list-multi-selection.png)
397
+
273
398
  ## Help
274
399
 
275
400
  ### Issues
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
@@ -0,0 +1,51 @@
1
+ require 'glimmer/data_binding/observable'
2
+ require 'glimmer/data_binding/observer'
3
+
4
+ module Glimmer
5
+ module DataBinding
6
+ # SWT List element selection binding
7
+ class ListSelectionBinding
8
+ include Glimmer
9
+ include Observable
10
+ include Observer
11
+
12
+ attr_reader :element_proxy
13
+
14
+ PROPERTY_TYPE_UPDATERS = {
15
+ :string => lambda { |element_proxy, value| element_proxy.select(element_proxy.index_of(value.to_s)) },
16
+ :array => lambda { |element_proxy, value| element_proxy.selection=(value || []) }
17
+ }
18
+
19
+ PROPERTY_EVALUATORS = {
20
+ :string => lambda do |selection_array|
21
+ return nil if selection_array.empty?
22
+ selection_array[0]
23
+ end,
24
+ :array => lambda do |selection_array|
25
+ selection_array
26
+ end
27
+ }
28
+
29
+ # Initialize with list element and property_type
30
+ # property_type :string represents default list single selection
31
+ # property_type :array represents list multi selection
32
+ def initialize(element_proxy, property_type)
33
+ property_type = :string if property_type.nil? or property_type == :undefined
34
+ @element_proxy = element_proxy
35
+ @property_type = property_type
36
+ @element_proxy.on_widget_disposed do |dispose_event|
37
+ unregister_all_observables
38
+ end
39
+ end
40
+
41
+ def call(value)
42
+ PROPERTY_TYPE_UPDATERS[@property_type].call(@element_proxy, value) unless evaluate_property == value
43
+ end
44
+
45
+ def evaluate_property
46
+ selection_array = @element_proxy.selection.to_a #TODO refactor send('selection') into proper method invocation
47
+ PROPERTY_EVALUATORS[@property_type].call(selection_array)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -15,7 +15,9 @@ require 'glimmer/dsl/opal/combo_selection_data_binding_expression'
15
15
  require 'glimmer/dsl/opal/widget_listener_expression'
16
16
  require 'glimmer/dsl/opal/grid_layout_expression'
17
17
  require 'glimmer/dsl/opal/text_expression'
18
+ require 'glimmer/dsl/opal/list_expression'
18
19
  require 'glimmer/dsl/opal/layout_data_expression'
20
+ require 'glimmer/dsl/opal/list_selection_data_binding_expression'
19
21
 
20
22
  module Glimmer
21
23
  module DSL
@@ -25,6 +27,7 @@ module Glimmer
25
27
  %w[
26
28
  widget_listener
27
29
  combo_selection_data_binding
30
+ list_selection_data_binding
28
31
  data_binding
29
32
  text
30
33
  property
@@ -0,0 +1,17 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/dsl/parent_expression'
3
+ require 'glimmer/opal/list_proxy'
4
+
5
+ module Glimmer
6
+ module DSL
7
+ module Opal
8
+ class ListExpression < StaticExpression
9
+ include ParentExpression
10
+
11
+ def interpret(parent, keyword, *args, &block)
12
+ Glimmer::Opal::ListProxy.new(parent, args)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ require 'glimmer/dsl/expression'
2
+ require 'glimmer/data_binding/model_binding'
3
+ require 'glimmer/data_binding/element_binding'
4
+ require 'glimmer/data_binding/list_selection_binding'
5
+ require 'glimmer/opal/list_proxy'
6
+
7
+ module Glimmer
8
+ module DSL
9
+ module Opal
10
+ class ListSelectionDataBindingExpression < Expression
11
+ def can_interpret?(parent, keyword, *args, &block)
12
+ keyword == 'selection' and
13
+ block.nil? and
14
+ parent.is_a?(Glimmer::Opal::ListProxy) and
15
+ args.size == 1 and
16
+ args[0].is_a?(DataBinding::ModelBinding) and
17
+ args[0].evaluate_options_property.is_a?(Array)
18
+ end
19
+
20
+ def interpret(parent, keyword, *args, &block)
21
+ model_binding = args[0]
22
+ element_binding = DataBinding::ElementBinding.new(parent, 'items')
23
+ element_binding.call(model_binding.evaluate_options_property)
24
+ model = model_binding.base_model
25
+ #TODO make this options observer dependent and all similar observers in widget specific data binding interpretrs
26
+ element_binding.observe(model, model_binding.options_property_name)
27
+
28
+ property_type = :string
29
+ property_type = :array if parent.has_style?(:multi)
30
+ list_selection_binding = DataBinding::ListSelectionBinding.new(parent, property_type)
31
+ list_selection_binding.call(model_binding.evaluate_property)
32
+ #TODO check if nested data binding works for list widget and other widgets that need custom data binding
33
+ list_selection_binding.observe(model, model_binding.property_name_expression)
34
+
35
+ parent.on_widget_selected do
36
+ model_binding.call(list_selection_binding.evaluate_property)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -28,16 +28,26 @@ module Glimmer
28
28
  # TODO make grid-layout support grab excess space false
29
29
  @head_dom ||= DOM {
30
30
  head {
31
- # <<~CSS
32
- # <style>
33
- # div.grid-layout {
34
- # display: grid;
35
- # grid-template-columns: auto;
36
- # grid-row-gap: 10px;
37
- # justify-content: start;
38
- # }
39
- # </style>
40
- # CSS
31
+ <<~CSS
32
+ <style>
33
+ ul {
34
+ list-style: none;
35
+ padding: 0;
36
+ }
37
+ li {
38
+ cursor: default;
39
+ padding-left: 10px;
40
+ padding-right: 10px;
41
+ }
42
+ li.selected-list-item {
43
+ background: rgb(80, 116, 211);
44
+ color: white;
45
+ }
46
+ li.empty-list-item {
47
+ color: transparent;
48
+ }
49
+ </style>
50
+ CSS
41
51
  }
42
52
  }
43
53
  end
@@ -70,18 +70,28 @@ module Glimmer
70
70
  redraw
71
71
  end
72
72
 
73
+ # TODO rename to avoid conflict with SWT Style verbiage
74
+
73
75
  def style=(css)
74
76
  @style = css
75
77
  redraw
76
78
  end
77
79
 
80
+ def has_style?(symbol)
81
+ @args.include?(symbol) # not a very solid implementation. Bring SWT constants eventually
82
+ end
83
+
78
84
  def handle_observation_request(keyword, &event_listener)
79
85
  return unless observation_request_to_event_mapping.keys.include?(keyword)
80
- event = observation_request_to_event_mapping[keyword][:event]
81
- event_handler = observation_request_to_event_mapping[keyword][:event_handler]
82
- potential_event_listener = event_handler&.call(event_listener)
83
- event_listener = event_handler&.call(event_listener) || event_listener
84
- delegate = $document.on(event, selector, &event_listener)
86
+ event = nil
87
+ delegate = nil
88
+ [observation_request_to_event_mapping[keyword]].flatten.each do |mapping|
89
+ event = mapping[:event]
90
+ event_handler = mapping[:event_handler]
91
+ potential_event_listener = event_handler&.call(event_listener)
92
+ event_listener = event_handler&.call(event_listener) || event_listener
93
+ delegate = $document.on(event, selector, &event_listener)
94
+ end
85
95
  EventListenerProxy.new(element_proxy: self, event: event, selector: selector, delegate: delegate)
86
96
  end
87
97
 
@@ -0,0 +1,80 @@
1
+ require 'glimmer/opal/element_proxy'
2
+
3
+ module Glimmer
4
+ module Opal
5
+ class ListProxy < ElementProxy
6
+ ITEM_EMPTY = '_____'
7
+ attr_reader :items, :selection
8
+
9
+ def initialize(parent, args)
10
+ super(parent, args)
11
+ @selection = []
12
+ end
13
+
14
+ def items=(items)
15
+ @items = items.map {|item| item.strip == '' ? ITEM_EMPTY : item}
16
+ redraw
17
+ end
18
+
19
+ def index_of(item)
20
+ @items.index(item)
21
+ end
22
+
23
+ # used for multi-selection taking an array
24
+ def selection=(selection)
25
+ @selection = selection
26
+ redraw
27
+ end
28
+
29
+ # used for single selection taking an index
30
+ def select(index, meta = false)
31
+ selected_item = @items[index]
32
+ if @selection.include?(selected_item)
33
+ @selection.delete(selected_item) if meta
34
+ else
35
+ @selection = [] if !meta || (!has_style?(:multi) && @selection.to_a.size >= 1)
36
+ @selection << selected_item
37
+ end
38
+ self.selection = @selection
39
+ end
40
+
41
+ def observation_request_to_event_mapping
42
+ {
43
+ 'on_widget_selected' => {
44
+ event: 'click',
45
+ event_handler: -> (event_listener) {
46
+ -> (event) {
47
+ selected_item = event.target.text
48
+ select(index_of(selected_item), event.meta?)
49
+ event_listener.call(event)
50
+ }
51
+ }
52
+ }
53
+ }
54
+ end
55
+
56
+ def name
57
+ 'ul'
58
+ end
59
+
60
+ def dom
61
+ list_items = @items
62
+ list_id = id
63
+ list_style = style
64
+ list_selection = selection
65
+ @dom ||= DOM {
66
+ ul(id: list_id, style: list_style) {
67
+ list_items.to_a.each_with_index do |item, index|
68
+ li_class = ''
69
+ li_class += ' selected-list-item' if list_selection.include?(item)
70
+ li_class += ' empty-list-item' if item == ITEM_EMPTY
71
+ li(class: li_class) {
72
+ item
73
+ }
74
+ end
75
+ }
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-opal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-17 00:00:00.000000000 Z
11
+ date: 2020-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -170,6 +170,7 @@ files:
170
170
  - lib/glimmer-dsl-opal.rb
171
171
  - lib/glimmer/config.rb
172
172
  - lib/glimmer/data_binding/element_binding.rb
173
+ - lib/glimmer/data_binding/list_selection_binding.rb
173
174
  - lib/glimmer/data_binding/observable_element.rb
174
175
  - lib/glimmer/dsl/engine.rb
175
176
  - lib/glimmer/dsl/expression.rb
@@ -184,6 +185,8 @@ files:
184
185
  - lib/glimmer/dsl/opal/grid_layout_expression.rb
185
186
  - lib/glimmer/dsl/opal/label_expression.rb
186
187
  - lib/glimmer/dsl/opal/layout_data_expression.rb
188
+ - lib/glimmer/dsl/opal/list_expression.rb
189
+ - lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb
187
190
  - lib/glimmer/dsl/opal/property_expression.rb
188
191
  - lib/glimmer/dsl/opal/shell_expression.rb
189
192
  - lib/glimmer/dsl/opal/text_expression.rb
@@ -201,6 +204,7 @@ files:
201
204
  - lib/glimmer/opal/input_proxy.rb
202
205
  - lib/glimmer/opal/label_proxy.rb
203
206
  - lib/glimmer/opal/layout_data_proxy.rb
207
+ - lib/glimmer/opal/list_proxy.rb
204
208
  - lib/glimmer/opal/property_owner.rb
205
209
  - lib/glimmer/opal/select_proxy.rb
206
210
  - lib/samples/elaborate/contact_manager.rb