glimmer-dsl-opal 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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