glimmer-dsl-opal 0.0.3 → 0.0.8

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +1049 -35
  4. data/VERSION +1 -1
  5. data/lib/glimmer-dsl-opal.rb +5 -2
  6. data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
  7. data/lib/glimmer/data_binding/list_selection_binding.rb +51 -0
  8. data/lib/glimmer/data_binding/table_items_binding.rb +67 -0
  9. data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
  10. data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
  11. data/lib/glimmer/dsl/opal/column_properties_expression.rb +22 -0
  12. data/lib/glimmer/dsl/opal/dsl.rb +14 -0
  13. data/lib/glimmer/dsl/opal/list_expression.rb +17 -0
  14. data/lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb +42 -0
  15. data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
  16. data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
  17. data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
  18. data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
  19. data/lib/glimmer/dsl/opal/table_column_expression.rb +17 -0
  20. data/lib/glimmer/dsl/opal/table_expression.rb +17 -0
  21. data/lib/glimmer/dsl/opal/table_items_data_binding_expression.rb +29 -0
  22. data/lib/glimmer/opal/display_proxy.rb +23 -0
  23. data/lib/glimmer/opal/div_proxy.rb +11 -2
  24. data/lib/glimmer/opal/document_proxy.rb +141 -11
  25. data/lib/glimmer/opal/element_proxy.rb +38 -15
  26. data/lib/glimmer/opal/grid_layout_proxy.rb +3 -1
  27. data/lib/glimmer/opal/iframe_proxy.rb +23 -0
  28. data/lib/glimmer/opal/input_proxy.rb +8 -4
  29. data/lib/glimmer/opal/label_proxy.rb +1 -1
  30. data/lib/glimmer/opal/layout_data_proxy.rb +23 -2
  31. data/lib/glimmer/opal/list_proxy.rb +80 -0
  32. data/lib/glimmer/opal/modal.rb +94 -0
  33. data/lib/glimmer/opal/point.rb +5 -0
  34. data/lib/glimmer/opal/select_proxy.rb +1 -1
  35. data/lib/glimmer/opal/tab_folder.rb +53 -0
  36. data/lib/glimmer/opal/tab_item.rb +98 -0
  37. data/lib/glimmer/opal/table_column.rb +50 -0
  38. data/lib/glimmer/opal/table_item.rb +136 -0
  39. data/lib/glimmer/opal/table_proxy.rb +149 -0
  40. data/lib/samples/elaborate/contact_manager.rb +1 -2
  41. data/lib/samples/elaborate/login.rb +0 -1
  42. data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
  43. data/lib/samples/hello/hello_tab.rb +2 -2
  44. metadata +30 -14
  45. data/lib/glimmer/config.rb +0 -22
  46. data/lib/glimmer/dsl/engine.rb +0 -193
  47. data/lib/glimmer/dsl/expression.rb +0 -42
  48. data/lib/glimmer/dsl/expression_handler.rb +0 -48
  49. data/lib/glimmer/dsl/parent_expression.rb +0 -12
  50. data/lib/glimmer/dsl/static_expression.rb +0 -36
  51. data/lib/glimmer/dsl/top_level_expression.rb +0 -7
  52. data/lib/glimmer/error.rb +0 -6
  53. data/lib/glimmer/invalid_keyword_error.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8fcd24e24134d90f11791bfa99b68aa16726b3ac97a8d77bad5bdba4761c866
4
- data.tar.gz: 32f0a803b817689f9ea48e4fda7506fcc562eb606bb546cb1735c77a2ff60487
3
+ metadata.gz: 6a67315f8276add7f19a24f488c635567a39fe798e7e21e49ce23de2aeb6c0d2
4
+ data.tar.gz: e667498792a2522e9271a04ccd2051396c778e528dd77fbb593c6369eee971e2
5
5
  SHA512:
6
- metadata.gz: b9a3ada345381b967ff44feb61d2a5f52dfba6ce1297c6e3f5d21359276dbdcd3844fc4bc731475f34219f13281d89fe5a1bdb1e7adafd08093e286ec36e6ef8
7
- data.tar.gz: e120cdd6aad1afd34b95f59cc805b975dd2348e3b32de13c3ef20402c4c22c9fc0308a97a71846656db2928c038b70bc46014a532616afd8d43e752f5ce9f509
6
+ metadata.gz: 02db0846e7e3b430387e693aa4981c2f01636a01b5ed5ba32646cbdac15991604ccbd5efa4d8e8b837027c69861c28b8d1917f5bef792121de9be8b86584e064
7
+ data.tar.gz: 5d07f4b44c97c81bcf554b18d423e0007efe14bf8cdaa8529f0c295581518654a94989dcc1a0e921e8626a7ca3ca243f572a4d163f3e4bd450fe81684303dae2
@@ -1,5 +1,35 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.8
4
+
5
+ - Contact Manager sample support
6
+
7
+ ## 0.0.7
8
+
9
+ - Tic Tac Toe sample support
10
+ - Login sample support
11
+
12
+ ## 0.0.6
13
+
14
+ - Hello, Tab! sample support
15
+
16
+ ## 0.0.5
17
+
18
+ - Hello, Browser! sample support
19
+
20
+ ## 0.0.4
21
+
22
+ - Hello, List Single Selection! sample support
23
+ - Hello, List Multi Selection! sample support
24
+
25
+ ## 0.0.3
26
+
27
+ - Hello, Computed! sample support
28
+
29
+ ## 0.0.2
30
+
31
+ - Hello, Combo! sample support
32
+
3
33
  ## 0.0.1
4
34
 
5
35
  - Initial support for webifying Glimmer SWT apps
data/README.md CHANGED
@@ -1,16 +1,22 @@
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)
1
+ # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=65 /> Glimmer DSL for Opal 0.0.8 (Webify Desktop Apps)
3
2
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-opal.svg)](http://badge.fury.io/rb/glimmer-dsl-opal)
4
3
  [![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
4
 
6
- [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for Opal is a web GUI adaptor for desktop apps built with [Glimmer](https://github.com/AndyObtiva/glimmer) & [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt).
5
+ Glimmer DSL for Opal is a web GUI adaptor for webifying [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps (i.e. apps built with [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)).
7
6
 
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.
7
+ It enables running [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps on the web via [Rails](https://rubyonrails.org/) and [Opal](https://opalrb.com/) without changing a line of code. Apps may then be custom-styled for the web via standard CSS.
9
8
 
10
- NOTE: Alpha Version 0.0.3 only supports capabilities for:
11
- - Hello, World!
12
- - Hello, Combo!
13
- - Hello, Computed!
9
+ NOTE: Alpha Version 0.0.8 only supports bare-minimum capabilities for the following [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt) [samples](https://github.com/AndyObtiva/glimmer#samples):
10
+ - [Hello, World!](#hello-world)
11
+ - [Hello, Combo!](#hello-combo)
12
+ - [Hello, Computed!](#hello-computed)
13
+ - [Hello, List Single Selection!](#hello-list-single-selection)
14
+ - [Hello, List Multi Selection!](#hello-list-multi-selection)
15
+ - [Hello, Browser!](#hello-browser)
16
+ - [Hello, Tab!](#hello-tab)
17
+ - [Login](#login)
18
+ - [Tic Tac Toe](#tic-tac-toe)
19
+ - [Contact Manager](#contact-manager)
14
20
 
15
21
  Other Glimmer DSL gems:
16
22
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI)
@@ -27,6 +33,17 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
27
33
  - `button`
28
34
  - `text`
29
35
  - `composite`
36
+ - `list` & `list(:multi)`
37
+ - `tab_folder`
38
+ - `tab_item`
39
+ - `table`
40
+ - `table_column`
41
+ - `message_box`
42
+ - `on_widget_selected`
43
+ - `on_modify_text`
44
+ - `observe`
45
+ - `bind`
46
+ - `async_exec`
30
47
  - `grid_layout`
31
48
  - `layout_data`
32
49
 
@@ -37,37 +54,49 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
37
54
 
38
55
  ## Setup
39
56
 
40
- Please follow these instructions to make Glimmer desktop apps work in Opal inside Rails 5
57
+ (NOTE: if you run into issues, they are probably fixed in master or development/wip branch, you may check out instead)
58
+
59
+ Please install a Rails 5 gem (e.g. `gem install rails -v5.2.4.3` )
41
60
 
42
61
  Start a new Rails 5 app:
43
62
 
44
63
  ```
45
- rails new hello_world
64
+ rails new glimmer_app
46
65
  ```
47
66
 
48
- Follow instructions to setup opal with a rails application: config/initializers/assets.rb
67
+ Add the following to `Gemfile`:
49
68
 
50
- Add the following to `Gemfile` (NOTE: if you run into issues, they are probably fixed in master or development/wip branch, you may check out instead):
51
69
  ```
52
- gem 'opal-rails'
53
- gem 'opal-browser'
54
- gem 'glimmer-dsl-opal', '~> 0.0.3', require: false
70
+ gem 'opal-rails', '~> 1.1.2'
71
+ gem 'opal-async', '~> 1.1.0'
72
+ gem 'opal-browser', '~> 0.2.0'
73
+ gem 'glimmer-dsl-opal', '~> 0.0.8', require: false
55
74
  ```
56
75
 
57
- Edit `config/initializers/assets.rb` and add:
76
+ Follow (opal-rails)[https://github.com/opal/opal-rails] instructions, basically the configuration of: config/initializers/assets.rb
77
+
78
+ Edit `config/initializers/assets.rb` and add the following at the bottom:
58
79
  ```
59
80
  Opal.use_gem 'glimmer-dsl-opal'
60
81
  ```
61
82
 
62
- ## Examples
63
-
64
- ### Hello, World!
65
-
66
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
83
+ Add the following line to the top of an empty `app/assets/javascripts/application.rb` (replacing `application.js`)
67
84
 
68
85
  ```ruby
69
86
  require 'glimmer-dsl-opal' # brings opal and opal browser too
87
+ ```
88
+
89
+ Add more code to `app/assets/javascripts/application.rb` from one of the samples below or require a [Glimmer](https://github.com/AndyObtiva/glimmer) app/[custom-shell](https://github.com/AndyObtiva/glimmer#custom-shell-gem) gem.
70
90
 
91
+ ## Samples
92
+
93
+ ### Hello Samples
94
+
95
+ #### Hello, World!
96
+
97
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
98
+
99
+ ```ruby
71
100
  include Glimmer
72
101
 
73
102
  shell {
@@ -75,12 +104,12 @@ shell {
75
104
  label {
76
105
  text 'Hello, World!'
77
106
  }
78
- }
107
+ }.open
79
108
  ```
80
109
 
81
110
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
82
111
 
83
- ![Glimmer DSL for Opal Hello World](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-world.png)
112
+ ![Glimmer DSL for SWT Hello World](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-world.png)
84
113
 
85
114
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
86
115
 
@@ -95,13 +124,11 @@ You should see "Hello, World!"
95
124
 
96
125
  ![Glimmer DSL for Opal Hello World](images/glimmer-dsl-opal-hello-world.png)
97
126
 
98
- ### Hello, Combo!
127
+ #### Hello, Combo!
99
128
 
100
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
129
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
101
130
 
102
131
  ```ruby
103
- require 'glimmer-dsl-opal' # brings opal and opal browser too
104
-
105
132
  class Person
106
133
  attr_accessor :country, :country_options
107
134
 
@@ -139,7 +166,7 @@ HelloCombo.new.launch
139
166
  ```
140
167
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
141
168
 
142
- ![Glimmer DSL for Opal Hello Combo](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-combo.png)
169
+ ![Glimmer DSL for SWT Hello Combo](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-combo.png)
143
170
 
144
171
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
145
172
 
@@ -154,13 +181,11 @@ You should see "Hello, Combo!"
154
181
 
155
182
  ![Glimmer DSL for Opal Hello Combo](images/glimmer-dsl-opal-hello-combo.png)
156
183
 
157
- ### Hello, Computed!
184
+ #### Hello, Computed!
158
185
 
159
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
186
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
160
187
 
161
188
  ```ruby
162
- require 'glimmer-dsl-opal' # brings opal and opal browser too
163
-
164
189
  class HelloComputed
165
190
  class Contact
166
191
  attr_accessor :first_name, :last_name, :year_of_birth
@@ -183,8 +208,6 @@ class HelloComputed
183
208
  end
184
209
  end
185
210
 
186
- require_relative "hello_computed/contact"
187
-
188
211
  class HelloComputed
189
212
  include Glimmer
190
213
 
@@ -255,7 +278,7 @@ HelloComputed.new.launch
255
278
  ```
256
279
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
257
280
 
258
- ![Glimmer DSL for Opal Hello Computed](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-computed.png)
281
+ ![Glimmer DSL for SWT Hello Computed](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-computed.png)
259
282
 
260
283
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
261
284
 
@@ -270,6 +293,997 @@ You should see "Hello, Computed!"
270
293
 
271
294
  ![Glimmer DSL for Opal Hello Computed](images/glimmer-dsl-opal-hello-computed.png)
272
295
 
296
+ #### Hello, List Single Selection!
297
+
298
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
299
+
300
+ ```ruby
301
+ class Person
302
+ attr_accessor :country, :country_options
303
+
304
+ def initialize
305
+ self.country_options=["", "Canada", "US", "Mexico"]
306
+ self.country = "Canada"
307
+ end
308
+
309
+ def reset_country
310
+ self.country = "Canada"
311
+ end
312
+ end
313
+
314
+ class HelloListSingleSelection
315
+ include Glimmer
316
+ def launch
317
+ person = Person.new
318
+ shell {
319
+ composite {
320
+ list {
321
+ selection bind(person, :country)
322
+ }
323
+ button {
324
+ text "Reset"
325
+ on_widget_selected do
326
+ person.reset_country
327
+ end
328
+ }
329
+ }
330
+ }.open
331
+ end
332
+ end
333
+
334
+ HelloListSingleSelection.new.launch
335
+ ```
336
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
337
+
338
+ ![Glimmer DSL for SWT Hello List Single Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-single-selection.png)
339
+
340
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
341
+
342
+ Start the Rails server:
343
+ ```
344
+ rails s
345
+ ```
346
+
347
+ Visit `http://localhost:3000`
348
+
349
+ You should see "Hello, List Single Selection!"
350
+
351
+ ![Glimmer DSL for Opal Hello List Single Selection](images/glimmer-dsl-opal-hello-list-single-selection.png)
352
+
353
+ #### Hello, List Multi Selection!
354
+
355
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
356
+
357
+ ```ruby
358
+ class Person
359
+ attr_accessor :provinces, :provinces_options
360
+
361
+ def initialize
362
+ self.provinces_options=[
363
+ "",
364
+ "Quebec",
365
+ "Ontario",
366
+ "Manitoba",
367
+ "Saskatchewan",
368
+ "Alberta",
369
+ "British Columbia",
370
+ "Nova Skotia",
371
+ "Newfoundland"
372
+ ]
373
+ self.provinces = ["Quebec", "Manitoba", "Alberta"]
374
+ end
375
+
376
+ def reset_provinces
377
+ self.provinces = ["Quebec", "Manitoba", "Alberta"]
378
+ end
379
+ end
380
+
381
+ class HelloListMultiSelection
382
+ include Glimmer
383
+ def launch
384
+ person = Person.new
385
+ shell {
386
+ composite {
387
+ list(:multi) {
388
+ selection bind(person, :provinces)
389
+ }
390
+ button {
391
+ text "Reset"
392
+ on_widget_selected do
393
+ person.reset_provinces
394
+ end
395
+ }
396
+ }
397
+ }.open
398
+ end
399
+ end
400
+
401
+ HelloListMultiSelection.new.launch
402
+ ```
403
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
404
+
405
+ ![Glimmer DSL for SWT Hello List Multi Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-multi-selection.png)
406
+
407
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
408
+
409
+ Start the Rails server:
410
+ ```
411
+ rails s
412
+ ```
413
+
414
+ Visit `http://localhost:3000`
415
+
416
+ You should see "Hello, List Multi Selection!"
417
+
418
+ ![Glimmer DSL for Opal Hello List Multi Selection](images/glimmer-dsl-opal-hello-list-multi-selection.png)
419
+
420
+ #### Hello, Browser!
421
+
422
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
423
+
424
+ ```ruby
425
+ include Glimmer
426
+
427
+ shell {
428
+ minimum_size 1024, 860
429
+ browser {
430
+ url 'http://brightonresort.com/about'
431
+ }
432
+ }.open
433
+ ```
434
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
435
+
436
+ ![Glimmer DSL for SWT Hello Browser](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-browser.png)
437
+
438
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
439
+
440
+ Start the Rails server:
441
+ ```
442
+ rails s
443
+ ```
444
+
445
+ Visit `http://localhost:3000`
446
+
447
+ You should see "Hello, Browser!"
448
+
449
+ ![Glimmer DSL for Opal Hello Browser](images/glimmer-dsl-opal-hello-browser.png)
450
+
451
+ #### Hello, Tab!
452
+
453
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
454
+
455
+ ```ruby
456
+ class HelloTab
457
+ include Glimmer
458
+ def launch
459
+ shell {
460
+ text "Hello, Tab!"
461
+ tab_folder {
462
+ tab_item {
463
+ text "English"
464
+ label {
465
+ text "Hello, World!"
466
+ }
467
+ }
468
+ tab_item {
469
+ text "French"
470
+ label {
471
+ text "Bonjour, Univers!"
472
+ }
473
+ }
474
+ }
475
+ }.open
476
+ end
477
+ end
478
+
479
+ HelloTab.new.launch
480
+ ```
481
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
482
+
483
+ ![Glimmer DSL for SWT Hello Tab English](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-tab-english.png)
484
+ ![Glimmer DSL for SWT Hello Tab French](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-tab-french.png)
485
+
486
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
487
+
488
+ Start the Rails server:
489
+ ```
490
+ rails s
491
+ ```
492
+
493
+ Visit `http://localhost:3000`
494
+
495
+ You should see "Hello, Tab!"
496
+
497
+ ![Glimmer DSL for Opal Hello Tab English](images/glimmer-dsl-opal-hello-tab-english.png)
498
+ ![Glimmer DSL for Opal Hello Tab French](images/glimmer-dsl-opal-hello-tab-french.png)
499
+
500
+ ### Elaborate Samples
501
+
502
+ #### Login
503
+
504
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
505
+
506
+ ```ruby
507
+ require "observer"
508
+
509
+ #Presents login screen data
510
+ class LoginPresenter
511
+
512
+ attr_accessor :user_name
513
+ attr_accessor :password
514
+ attr_accessor :status
515
+
516
+ def initialize
517
+ @user_name = ""
518
+ @password = ""
519
+ @status = "Logged Out"
520
+ end
521
+
522
+ def status=(status)
523
+ @status = status
524
+
525
+ #TODO add feature to bind dependent properties to master property (2017-07-25 nested data binding)
526
+ notify_observers("logged_in")
527
+ notify_observers("logged_out")
528
+ end
529
+
530
+ def logged_in
531
+ self.status == "Logged In"
532
+ end
533
+
534
+ def logged_out
535
+ !self.logged_in
536
+ end
537
+
538
+ def login
539
+ self.status = "Logged In"
540
+ end
541
+
542
+ def logout
543
+ self.user_name = ""
544
+ self.password = ""
545
+ self.status = "Logged Out"
546
+ end
547
+
548
+ end
549
+
550
+ #Login screen
551
+ class Login
552
+ include Glimmer
553
+
554
+ def launch
555
+ presenter = LoginPresenter.new
556
+ @shell = shell {
557
+ text "Login"
558
+ composite {
559
+ grid_layout 2, false #two columns with differing widths
560
+
561
+ label { text "Username:" } # goes in column 1
562
+ text { # goes in column 2
563
+ text bind(presenter, :user_name)
564
+ enabled bind(presenter, :logged_out)
565
+ }
566
+
567
+ label { text "Password:" }
568
+ text(:password, :border) {
569
+ text bind(presenter, :password)
570
+ enabled bind(presenter, :logged_out)
571
+ }
572
+
573
+ label { text "Status:" }
574
+ label { text bind(presenter, :status) }
575
+
576
+ button {
577
+ text "Login"
578
+ enabled bind(presenter, :logged_out)
579
+ on_widget_selected { presenter.login }
580
+ }
581
+
582
+ button {
583
+ text "Logout"
584
+ enabled bind(presenter, :logged_in)
585
+ on_widget_selected { presenter.logout }
586
+ }
587
+ }
588
+ }
589
+ @shell.open
590
+ end
591
+ end
592
+
593
+ Login.new.launch
594
+ ```
595
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
596
+
597
+ ![Glimmer DSL for SWT Login](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login.png)
598
+ ![Glimmer DSL for SWT Login Filled In](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login-filled-in.png)
599
+ ![Glimmer DSL for SWT Login Logged In](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login-logged-in.png)
600
+
601
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
602
+
603
+ Start the Rails server:
604
+ ```
605
+ rails s
606
+ ```
607
+
608
+ Visit `http://localhost:3000`
609
+
610
+ You should see "Login" dialog
611
+
612
+ ![Glimmer DSL for Opal Login](images/glimmer-dsl-opal-login.png)
613
+ ![Glimmer DSL for Opal Login Filled In](images/glimmer-dsl-opal-login-filled-in.png)
614
+ ![Glimmer DSL for Opal Login Logged In](images/glimmer-dsl-opal-login-logged-in.png)
615
+
616
+ #### Tic Tac Toe
617
+
618
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
619
+
620
+ ```ruby
621
+ class TicTacToe
622
+ class Cell
623
+ EMPTY = ""
624
+ attr_accessor :sign, :empty
625
+
626
+ def initialize
627
+ reset
628
+ end
629
+
630
+ def mark(sign)
631
+ self.sign = sign
632
+ end
633
+
634
+ def reset
635
+ self.sign = EMPTY
636
+ end
637
+
638
+ def sign=(sign_symbol)
639
+ @sign = sign_symbol
640
+ self.empty = sign == EMPTY
641
+ end
642
+
643
+ def marked
644
+ !empty
645
+ end
646
+ end
647
+ end
648
+
649
+ class TicTacToe
650
+ class Board
651
+ DRAW = :draw
652
+ IN_PROGRESS = :in_progress
653
+ WIN = :win
654
+ attr :winning_sign
655
+ attr_accessor :game_status
656
+
657
+ def initialize
658
+ @sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
659
+ build_grid
660
+ @winning_sign = Cell::EMPTY
661
+ @game_status = IN_PROGRESS
662
+ end
663
+
664
+ #row and column numbers are 1-based
665
+ def mark(row, column)
666
+ self[row, column].mark(current_sign)
667
+ game_over? #updates winning sign
668
+ end
669
+
670
+ def current_sign
671
+ @current_sign = @sign_state_machine[@current_sign]
672
+ end
673
+
674
+ def [](row, column)
675
+ @grid[row-1][column-1]
676
+ end
677
+
678
+ def game_over?
679
+ win? or draw?
680
+ end
681
+
682
+ def win?
683
+ win = (row_win? or column_win? or diagonal_win?)
684
+ self.game_status=WIN if win
685
+ win
686
+ end
687
+
688
+ def reset
689
+ (1..3).each do |row|
690
+ (1..3).each do |column|
691
+ self[row, column].reset
692
+ end
693
+ end
694
+ @winning_sign = Cell::EMPTY
695
+ @current_sign = nil
696
+ self.game_status=IN_PROGRESS
697
+ end
698
+
699
+ private
700
+
701
+ def build_grid
702
+ @grid = []
703
+ 3.times do |row_index| #0-based
704
+ @grid << []
705
+ 3.times { @grid[row_index] << Cell.new }
706
+ end
707
+ end
708
+
709
+ def row_win?
710
+ (1..3).each do |row|
711
+ if row_has_same_sign(row)
712
+ @winning_sign = self[row, 1].sign
713
+ return true
714
+ end
715
+ end
716
+ false
717
+ end
718
+
719
+ def column_win?
720
+ (1..3).each do |column|
721
+ if column_has_same_sign(column)
722
+ @winning_sign = self[1, column].sign
723
+ return true
724
+ end
725
+ end
726
+ false
727
+ end
728
+
729
+ #needs refactoring if we ever decide to make the board size dynamic
730
+ def diagonal_win?
731
+ if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
732
+ @winning_sign = self[1, 1].sign
733
+ return true
734
+ end
735
+ if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
736
+ @winning_sign = self[3, 1].sign
737
+ return true
738
+ end
739
+ false
740
+ end
741
+
742
+ def draw?
743
+ @board_full = true
744
+ 3.times do |x|
745
+ 3.times do |y|
746
+ @board_full = false if self[x, y].empty
747
+ end
748
+ end
749
+ self.game_status = DRAW if @board_full
750
+ @board_full
751
+ end
752
+
753
+ def row_has_same_sign(number)
754
+ row_sign = self[number, 1].sign
755
+ [2, 3].each do |column|
756
+ return false unless row_sign == (self[number, column].sign)
757
+ end
758
+ true if self[number, 1].marked
759
+ end
760
+
761
+ def column_has_same_sign(number)
762
+ column_sign = self[1, number].sign
763
+ [2, 3].each do |row|
764
+ return false unless column_sign == (self[row, number].sign)
765
+ end
766
+ true if self[1, number].marked
767
+ end
768
+
769
+ end
770
+ end
771
+
772
+ class TicTacToe
773
+ include Glimmer
774
+
775
+ def initialize
776
+ @tic_tac_toe_board = Board.new
777
+ @shell = shell {
778
+ text "Tic-Tac-Toe"
779
+ composite {
780
+ grid_layout 3, true
781
+ (1..3).each { |row|
782
+ (1..3).each { |column|
783
+ button {
784
+ layout_data :fill, :fill, true, true
785
+ text bind(@tic_tac_toe_board[row, column], :sign)
786
+ enabled bind(@tic_tac_toe_board[row, column], :empty)
787
+ on_widget_selected {
788
+ @tic_tac_toe_board.mark(row, column)
789
+ }
790
+ }
791
+ }
792
+ }
793
+ }
794
+ }
795
+ observe(@tic_tac_toe_board, :game_status) { |game_status|
796
+ display_win_message if game_status == Board::WIN
797
+ display_draw_message if game_status == Board::DRAW
798
+ }
799
+ end
800
+
801
+ def display_win_message
802
+ display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
803
+ end
804
+
805
+ def display_draw_message
806
+ display_game_over_message("Draw!")
807
+ end
808
+
809
+ def display_game_over_message(message_text)
810
+ message_box(@shell) {
811
+ text 'Game Over'
812
+ message message_text
813
+ }.open
814
+ @tic_tac_toe_board.reset
815
+ end
816
+
817
+ def open
818
+ @shell.open
819
+ end
820
+ end
821
+
822
+ TicTacToe.new.open
823
+ ```
824
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
825
+
826
+ ![Glimmer DSL for SWT Tic Tac Toe](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe.png)
827
+ ![Glimmer DSL for SWT Tic Tac Toe In Progress](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe-in-progress.png)
828
+ ![Glimmer DSL for SWT Tic Tac Toe Game Over](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe-game-over.png)
829
+
830
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
831
+
832
+ Start the Rails server:
833
+ ```
834
+ rails s
835
+ ```
836
+
837
+ Visit `http://localhost:3000`
838
+
839
+ You should see "Tic Tac Toe"
840
+
841
+ ![Glimmer DSL for Opal Tic Tac Toe](images/glimmer-dsl-opal-tic-tac-toe.png)
842
+ ![Glimmer DSL for Opal Tic Tac Toe In Progress](images/glimmer-dsl-opal-tic-tac-toe-in-progress.png)
843
+ ![Glimmer DSL for Opal Tic Tac Toe Game Over](images/glimmer-dsl-opal-tic-tac-toe-game-over.png)
844
+
845
+ #### Contact Manager
846
+
847
+ Add the following Glimmer code to `app/assets/javascripts/application.rb`
848
+
849
+ ```ruby
850
+ class ContactManager
851
+ class Contact
852
+ attr_accessor :first_name, :last_name, :email
853
+
854
+ def initialize(attribute_map)
855
+ @first_name = attribute_map[:first_name]
856
+ @last_name = attribute_map[:last_name]
857
+ @email = attribute_map[:email]
858
+ end
859
+ end
860
+ end
861
+
862
+ class ContactManager
863
+ class ContactRepository
864
+ NAMES_FIRST = %w[
865
+ Liam
866
+ Noah
867
+ William
868
+ James
869
+ Oliver
870
+ Benjamin
871
+ Elijah
872
+ Lucas
873
+ Mason
874
+ Logan
875
+ Alexander
876
+ Ethan
877
+ Jacob
878
+ Michael
879
+ Daniel
880
+ Henry
881
+ Jackson
882
+ Sebastian
883
+ Aiden
884
+ Matthew
885
+ Samuel
886
+ David
887
+ Joseph
888
+ Carter
889
+ Owen
890
+ Wyatt
891
+ John
892
+ Jack
893
+ Luke
894
+ Jayden
895
+ Dylan
896
+ Grayson
897
+ Levi
898
+ Isaac
899
+ Gabriel
900
+ Julian
901
+ Mateo
902
+ Anthony
903
+ Jaxon
904
+ Lincoln
905
+ Joshua
906
+ Christopher
907
+ Andrew
908
+ Theodore
909
+ Caleb
910
+ Ryan
911
+ Asher
912
+ Nathan
913
+ Thomas
914
+ Leo
915
+ Isaiah
916
+ Charles
917
+ Josiah
918
+ Hudson
919
+ Christian
920
+ Hunter
921
+ Connor
922
+ Eli
923
+ Ezra
924
+ Aaron
925
+ Landon
926
+ Adrian
927
+ Jonathan
928
+ Nolan
929
+ Jeremiah
930
+ Easton
931
+ Elias
932
+ Colton
933
+ Cameron
934
+ Carson
935
+ Robert
936
+ Angel
937
+ Maverick
938
+ Nicholas
939
+ Dominic
940
+ Jaxson
941
+ Greyson
942
+ Adam
943
+ Ian
944
+ Austin
945
+ Santiago
946
+ Jordan
947
+ Cooper
948
+ Brayden
949
+ Roman
950
+ Evan
951
+ Ezekiel
952
+ Xaviar
953
+ Jose
954
+ Jace
955
+ Jameson
956
+ Leonardo
957
+ Axel
958
+ Everett
959
+ Kayden
960
+ Miles
961
+ Sawyer
962
+ Jason
963
+ Emma
964
+ Olivia
965
+ Ava
966
+ Isabella
967
+ Sophia
968
+ Charlotte
969
+ Mia
970
+ Amelia
971
+ Harper
972
+ Evelyn
973
+ Abigail
974
+ Emily
975
+ Elizabeth
976
+ Mila
977
+ Ella
978
+ Avery
979
+ Sofia
980
+ Camila
981
+ Aria
982
+ Scarlett
983
+ Victoria
984
+ Madison
985
+ Luna
986
+ Grace
987
+ Chloe
988
+ Penelope
989
+ Layla
990
+ Riley
991
+ Zoey
992
+ Nora
993
+ Lily
994
+ Eleanor
995
+ Hannah
996
+ Lillian
997
+ Addison
998
+ Aubrey
999
+ Ellie
1000
+ Stella
1001
+ Natalie
1002
+ Zoe
1003
+ Leah
1004
+ Hazel
1005
+ Violet
1006
+ Aurora
1007
+ Savannah
1008
+ Audrey
1009
+ Brooklyn
1010
+ Bella
1011
+ Claire
1012
+ Skylar
1013
+ Lucy
1014
+ Paisley
1015
+ Everly
1016
+ Anna
1017
+ Caroline
1018
+ Nova
1019
+ Genesis
1020
+ Emilia
1021
+ Kennedy
1022
+ Samantha
1023
+ Maya
1024
+ Willow
1025
+ Kinsley
1026
+ Naomi
1027
+ Aaliyah
1028
+ Elena
1029
+ Sarah
1030
+ Ariana
1031
+ Allison
1032
+ Gabriella
1033
+ Alice
1034
+ Madelyn
1035
+ Cora
1036
+ Ruby
1037
+ Eva
1038
+ Serenity
1039
+ Autumn
1040
+ Adeline
1041
+ Hailey
1042
+ Gianna
1043
+ Valentina
1044
+ Isla
1045
+ Eliana
1046
+ Quinn
1047
+ Nevaeh
1048
+ Ivy
1049
+ Sadie
1050
+ Piper
1051
+ Lydia
1052
+ Alexa
1053
+ Josephine
1054
+ Emery
1055
+ Julia
1056
+ Delilah
1057
+ Arianna
1058
+ Vivian
1059
+ Kaylee
1060
+ Sophie
1061
+ Brielle
1062
+ Madeline
1063
+ ]
1064
+ NAMES_LAST = %w[
1065
+ Smith
1066
+ Johnson
1067
+ Williams
1068
+ Brown
1069
+ Jones
1070
+ Miller
1071
+ Davis
1072
+ Wilson
1073
+ Anderson
1074
+ Taylor
1075
+ ]
1076
+ def initialize(contacts = nil)
1077
+ @contacts = contacts || 1000.times.map do |n|
1078
+ random_first_name_index = (rand*NAMES_FIRST.size).to_i
1079
+ random_last_name_index = (rand*NAMES_LAST.size).to_i
1080
+ first_name = NAMES_FIRST[random_first_name_index]
1081
+ last_name = NAMES_LAST[random_last_name_index]
1082
+ email = "#{first_name}@#{last_name}.com".downcase
1083
+ Contact.new(
1084
+ first_name: first_name,
1085
+ last_name: last_name,
1086
+ email: email
1087
+ )
1088
+ end
1089
+ end
1090
+
1091
+ def find(attribute_filter_map)
1092
+ @contacts.find_all do |contact|
1093
+ match = true
1094
+ attribute_filter_map.keys.each do |attribute_name|
1095
+ contact_value = contact.send(attribute_name).downcase
1096
+ filter_value = attribute_filter_map[attribute_name].downcase
1097
+ match = false unless contact_value.match(filter_value)
1098
+ end
1099
+ match
1100
+ end
1101
+ end
1102
+ end
1103
+ end
1104
+
1105
+ class ContactManager
1106
+ class ContactManagerPresenter
1107
+ attr_accessor :results
1108
+ @@contact_attributes = [:first_name, :last_name, :email]
1109
+ @@contact_attributes.each {|attribute_name| attr_accessor attribute_name}
1110
+
1111
+ def initialize(contact_repository = nil)
1112
+ @contact_repository = contact_repository || ContactRepository.new
1113
+ @results = []
1114
+ end
1115
+
1116
+ def list
1117
+ self.results = @contact_repository.find({})
1118
+ end
1119
+
1120
+ def find
1121
+ filter_map = {}
1122
+ @@contact_attributes.each do |attribute_name|
1123
+ filter_map[attribute_name] = self.send(attribute_name) if self.send(attribute_name)
1124
+ end
1125
+ self.results = @contact_repository.find(filter_map)
1126
+ @sort_attribute_name = nil
1127
+ @sort_direction_ascending = nil
1128
+ end
1129
+
1130
+ def toggle_sort(attribute_name)
1131
+ @sort_attribute_name = attribute_name
1132
+ @sort_direction_ascending = !@sort_direction_ascending
1133
+ sorted_results = self.results.sort_by {|contact| contact.send(attribute_name).downcase}
1134
+ sorted_results = sorted_results.reverse unless @sort_direction_ascending
1135
+ self.results = sorted_results
1136
+ end
1137
+ end
1138
+ end
1139
+
1140
+ class ContactManager
1141
+ include Glimmer
1142
+
1143
+ def initialize
1144
+ @contact_manager_presenter = ContactManagerPresenter.new
1145
+ @contact_manager_presenter.list
1146
+ end
1147
+
1148
+ def launch
1149
+ shell {
1150
+ text "Contact Manager"
1151
+ composite {
1152
+ composite {
1153
+ grid_layout 2, false
1154
+ label {text "First &Name: "}
1155
+ text {
1156
+ text bind(@contact_manager_presenter, :first_name)
1157
+ on_key_pressed {|key_event|
1158
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
1159
+ }
1160
+ }
1161
+ label {text "&Last Name: "}
1162
+ text {
1163
+ text bind(@contact_manager_presenter, :last_name)
1164
+ on_key_pressed {|key_event|
1165
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
1166
+ }
1167
+ }
1168
+ label {text "&Email: "}
1169
+ text {
1170
+ text bind(@contact_manager_presenter, :email)
1171
+ on_key_pressed {|key_event|
1172
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
1173
+ }
1174
+ }
1175
+ composite {
1176
+ grid_layout 2, false
1177
+ button {
1178
+ text "&Find"
1179
+ on_widget_selected {
1180
+ @contact_manager_presenter.find
1181
+ }
1182
+ }
1183
+ button {
1184
+ text "&List All"
1185
+ on_widget_selected {
1186
+ @contact_manager_presenter.list
1187
+ }
1188
+ }
1189
+ }
1190
+ }
1191
+
1192
+ table(:multi) { |table_proxy|
1193
+ layout_data {
1194
+ horizontal_alignment :fill
1195
+ vertical_alignment :fill
1196
+ grab_excess_horizontal_space true
1197
+ grab_excess_vertical_space true
1198
+ height_hint 200
1199
+ }
1200
+ table_column {
1201
+ text "First Name"
1202
+ width 80
1203
+ on_widget_selected {
1204
+ @contact_manager_presenter.toggle_sort(:first_name)
1205
+ }
1206
+ }
1207
+ table_column {
1208
+ text "Last Name"
1209
+ width 80
1210
+ on_widget_selected {
1211
+ @contact_manager_presenter.toggle_sort(:last_name)
1212
+ }
1213
+ }
1214
+ table_column {
1215
+ text "Email"
1216
+ width 200
1217
+ on_widget_selected {
1218
+ @contact_manager_presenter.toggle_sort(:email)
1219
+ }
1220
+ }
1221
+ items bind(@contact_manager_presenter, :results), column_properties(:first_name, :last_name, :email)
1222
+ on_mouse_down { |event|
1223
+ table_proxy.edit_table_item(event.table_item, event.column_index)
1224
+ }
1225
+ }
1226
+ }
1227
+ }.open
1228
+ end
1229
+ end
1230
+
1231
+ ContactManager.new.launch
1232
+
1233
+ ```
1234
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1235
+
1236
+ Glimmer DSL for SWT Contact Manager
1237
+
1238
+ ![Glimmer DSL for SWT Contact Manager](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager.png)
1239
+
1240
+ Glimmer DSL for SWT Contact Manager Find
1241
+
1242
+ ![Glimmer DSL for SWT Contact Manager Find](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-find.png)
1243
+
1244
+ Glimmer DSL for SWT Contact Manager Edit Started
1245
+
1246
+ ![Glimmer DSL for SWT Contact Manager Edit Started](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-edit-started.png)
1247
+
1248
+ Glimmer DSL for SWT Contact Manager Edit In Progress
1249
+
1250
+ ![Glimmer DSL for SWT Contact Manager Edit In Progress](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-edit-in-progress.png)
1251
+
1252
+ Glimmer DSL for SWT Contact Manager Edit Done
1253
+
1254
+ ![Glimmer DSL for SWT Contact Manager Edit Done](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-edit-done.png)
1255
+
1256
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
1257
+
1258
+ Start the Rails server:
1259
+ ```
1260
+ rails s
1261
+ ```
1262
+
1263
+ Visit `http://localhost:3000`
1264
+
1265
+ You should see "Tic Tac Toe"
1266
+
1267
+ Glimmer DSL for Opal Contact Manager
1268
+
1269
+ ![Glimmer DSL for Opal Contact Manager](images/glimmer-dsl-opal-contact-manager.png)
1270
+
1271
+ Glimmer DSL for Opal Contact Manager Find
1272
+
1273
+ ![Glimmer DSL for Opal Contact Manager Find](images/glimmer-dsl-opal-contact-manager-find.png)
1274
+
1275
+ Glimmer DSL for Opal Contact Manager Edit Started
1276
+
1277
+ ![Glimmer DSL for Opal Contact Manager Edit Started](images/glimmer-dsl-opal-contact-manager-edit-started.png)
1278
+
1279
+ Glimmer DSL for Opal Contact Manager Edit In Progress
1280
+
1281
+ ![Glimmer DSL for Opal Contact Manager Edit In Progress](images/glimmer-dsl-opal-contact-manager-edit-in-progress.png)
1282
+
1283
+ Glimmer DSL for Opal Contact Manager Edit Done
1284
+
1285
+ ![Glimmer DSL for Opal Contact Manager Edit Done](images/glimmer-dsl-opal-contact-manager-edit-done.png)
1286
+
273
1287
  ## Help
274
1288
 
275
1289
  ### Issues