glimmer-dsl-opal 0.0.4 → 0.0.9
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 +4 -4
- data/CHANGELOG.md +35 -0
- data/README.md +983 -34
- data/VERSION +1 -1
- data/lib/glimmer-dsl-opal.rb +5 -2
- data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
- data/lib/glimmer/data_binding/table_items_binding.rb +70 -0
- data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/column_properties_expression.rb +22 -0
- data/lib/glimmer/dsl/opal/dsl.rb +11 -0
- data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
- data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
- data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/table_column_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/table_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/table_items_data_binding_expression.rb +29 -0
- data/lib/glimmer/opal/display_proxy.rb +23 -0
- data/lib/glimmer/opal/div_proxy.rb +11 -2
- data/lib/glimmer/opal/document_proxy.rb +124 -4
- data/lib/glimmer/opal/element_proxy.rb +45 -14
- data/lib/glimmer/opal/grid_layout_proxy.rb +3 -1
- data/lib/glimmer/opal/iframe_proxy.rb +23 -0
- data/lib/glimmer/opal/input_proxy.rb +8 -4
- data/lib/glimmer/opal/label_proxy.rb +1 -1
- data/lib/glimmer/opal/layout_data_proxy.rb +23 -2
- data/lib/glimmer/opal/list_proxy.rb +2 -2
- data/lib/glimmer/opal/modal.rb +94 -0
- data/lib/glimmer/opal/point.rb +5 -0
- data/lib/glimmer/opal/select_proxy.rb +1 -1
- data/lib/glimmer/opal/tab_folder.rb +53 -0
- data/lib/glimmer/opal/tab_item.rb +98 -0
- data/lib/glimmer/opal/table_column.rb +50 -0
- data/lib/glimmer/opal/table_item.rb +136 -0
- data/lib/glimmer/opal/table_proxy.rb +149 -0
- data/lib/samples/elaborate/contact_manager.rb +1 -2
- data/lib/samples/elaborate/login.rb +0 -1
- data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
- data/lib/samples/hello/hello_tab.rb +2 -2
- metadata +28 -16
- data/lib/glimmer/config.rb +0 -22
- data/lib/glimmer/dsl/engine.rb +0 -193
- data/lib/glimmer/dsl/expression.rb +0 -42
- data/lib/glimmer/dsl/expression_handler.rb +0 -48
- data/lib/glimmer/dsl/parent_expression.rb +0 -12
- data/lib/glimmer/dsl/static_expression.rb +0 -36
- data/lib/glimmer/dsl/top_level_expression.rb +0 -7
- data/lib/glimmer/error.rb +0 -6
- data/lib/glimmer/invalid_keyword_error.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b56026edb0b7ab096e2b972afcc99f2914db153e52fa52616859b44e86d0ad8c
|
4
|
+
data.tar.gz: aa94ad9ded4e7cac3ec706db46a012861e9c1e3a0d0026cdcc7833f43733eba0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66e958ca4e486e0a33908fb21d72322c375da35774a86e0514898a50b214bff0ecd7e7f4f5ce930983394cf49d9386ddce45f9ddcc0eb5e0074c455e8ebb87c9
|
7
|
+
data.tar.gz: 9e57c5f9a2bb433f182e7f7ce392f19985796cd56f8f40bed01bfed2e7385a25b4bf3fb7b06c541dae0b77cda2a981ac71d2a094d21f0beede0f8867b3fd1333
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,40 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.0.9
|
4
|
+
|
5
|
+
- Upgraded to glimmer gem v0.9.3
|
6
|
+
- Fixed issue with missing Glimmer::Opal::ElementProxy#id=(value) method breaking Contact Manager sample Find feature
|
7
|
+
|
8
|
+
## 0.0.8
|
9
|
+
|
10
|
+
- Contact Manager sample support
|
11
|
+
|
12
|
+
## 0.0.7
|
13
|
+
|
14
|
+
- Tic Tac Toe sample support
|
15
|
+
- Login sample support
|
16
|
+
|
17
|
+
## 0.0.6
|
18
|
+
|
19
|
+
- Hello, Tab! sample support
|
20
|
+
|
21
|
+
## 0.0.5
|
22
|
+
|
23
|
+
- Hello, Browser! sample support
|
24
|
+
|
25
|
+
## 0.0.4
|
26
|
+
|
27
|
+
- Hello, List Single Selection! sample support
|
28
|
+
- Hello, List Multi Selection! sample support
|
29
|
+
|
30
|
+
## 0.0.3
|
31
|
+
|
32
|
+
- Hello, Computed! sample support
|
33
|
+
|
34
|
+
## 0.0.2
|
35
|
+
|
36
|
+
- Hello, Combo! sample support
|
37
|
+
|
3
38
|
## 0.0.1
|
4
39
|
|
5
40
|
- Initial support for webifying Glimmer SWT apps
|
data/README.md
CHANGED
@@ -1,18 +1,20 @@
|
|
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.4 (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.9 (Webify Desktop Apps)
|
3
2
|
[](http://badge.fury.io/rb/glimmer-dsl-opal)
|
4
3
|
[](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
5
4
|
|
6
|
-
|
7
|
-
|
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.
|
5
|
+
Glimmer DSL for Opal is an experimental web GUI adaptor for [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps (i.e. apps built with [Glimmer](https://github.com/AndyObtiva/glimmer) [DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)). It webifies them via [Rails](https://rubyonrails.org/) and [Opal](https://opalrb.com/), allowing Ruby desktop apps to run on the web without changing a line of code. Apps may then be custom-styled for the web via standard CSS.
|
9
6
|
|
10
|
-
NOTE: Alpha Version 0.0.
|
7
|
+
NOTE: Alpha Version 0.0.9 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):
|
11
8
|
- [Hello, World!](#hello-world)
|
12
9
|
- [Hello, Combo!](#hello-combo)
|
13
10
|
- [Hello, Computed!](#hello-computed)
|
14
11
|
- [Hello, List Single Selection!](#hello-list-single-selection)
|
15
12
|
- [Hello, List Multi Selection!](#hello-list-multi-selection)
|
13
|
+
- [Hello, Browser!](#hello-browser)
|
14
|
+
- [Hello, Tab!](#hello-tab)
|
15
|
+
- [Login](#login)
|
16
|
+
- [Tic Tac Toe](#tic-tac-toe)
|
17
|
+
- [Contact Manager](#contact-manager)
|
16
18
|
|
17
19
|
Other Glimmer DSL gems:
|
18
20
|
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI)
|
@@ -30,6 +32,16 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
|
|
30
32
|
- `text`
|
31
33
|
- `composite`
|
32
34
|
- `list` & `list(:multi)`
|
35
|
+
- `tab_folder`
|
36
|
+
- `tab_item`
|
37
|
+
- `table`
|
38
|
+
- `table_column`
|
39
|
+
- `message_box`
|
40
|
+
- `on_widget_selected`
|
41
|
+
- `on_modify_text`
|
42
|
+
- `observe`
|
43
|
+
- `bind`
|
44
|
+
- `async_exec`
|
33
45
|
- `grid_layout`
|
34
46
|
- `layout_data`
|
35
47
|
|
@@ -40,37 +52,55 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
|
|
40
52
|
|
41
53
|
## Setup
|
42
54
|
|
43
|
-
|
55
|
+
(NOTE: if you run into issues, they are probably fixed in master or development/wip branch, you may check out instead)
|
56
|
+
|
57
|
+
Please install a Rails 5 gem (e.g. `gem install rails -v5.2.4.3` )
|
44
58
|
|
45
59
|
Start a new Rails 5 app:
|
46
60
|
|
47
61
|
```
|
48
|
-
rails new
|
62
|
+
rails new glimmer_app
|
49
63
|
```
|
50
64
|
|
51
|
-
|
65
|
+
Add the following to `Gemfile`:
|
52
66
|
|
53
|
-
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):
|
54
67
|
```
|
55
|
-
gem 'opal-rails'
|
56
|
-
gem 'opal-
|
57
|
-
gem '
|
68
|
+
gem 'opal-rails', '~> 1.1.2'
|
69
|
+
gem 'opal-async', '~> 1.1.0'
|
70
|
+
gem 'opal-browser', '~> 0.2.0'
|
71
|
+
gem 'glimmer-dsl-opal', '~> 0.0.9', require: false
|
58
72
|
```
|
59
73
|
|
60
|
-
|
74
|
+
Follow (opal-rails)[https://github.com/opal/opal-rails] instructions, basically the configuration of: config/initializers/assets.rb
|
75
|
+
|
76
|
+
Edit `config/initializers/assets.rb` and add the following at the bottom:
|
61
77
|
```
|
62
78
|
Opal.use_gem 'glimmer-dsl-opal'
|
63
79
|
```
|
64
80
|
|
65
|
-
|
81
|
+
Add the following line to the top of an empty `app/assets/javascripts/application.rb` (replacing `application.js`)
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
require 'glimmer-dsl-opal' # brings opal and opal browser too
|
85
|
+
```
|
86
|
+
|
87
|
+
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.
|
88
|
+
|
89
|
+
## Samples
|
90
|
+
|
91
|
+
### Hello Samples
|
66
92
|
|
67
|
-
|
93
|
+
#### Hello, World!
|
68
94
|
|
69
|
-
Add the following
|
95
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
70
96
|
|
71
97
|
```ruby
|
72
|
-
require '
|
98
|
+
require 'samples/hello/hello_world'
|
99
|
+
```
|
100
|
+
|
101
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
73
102
|
|
103
|
+
```ruby
|
74
104
|
include Glimmer
|
75
105
|
|
76
106
|
shell {
|
@@ -78,12 +108,12 @@ shell {
|
|
78
108
|
label {
|
79
109
|
text 'Hello, World!'
|
80
110
|
}
|
81
|
-
}
|
111
|
+
}.open
|
82
112
|
```
|
83
113
|
|
84
114
|
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
85
115
|
|
86
|
-

|
87
117
|
|
88
118
|
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
89
119
|
|
@@ -98,13 +128,17 @@ You should see "Hello, World!"
|
|
98
128
|
|
99
129
|

|
100
130
|
|
101
|
-
|
131
|
+
#### Hello, Combo!
|
102
132
|
|
103
|
-
Add the following
|
133
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
104
134
|
|
105
135
|
```ruby
|
106
|
-
require '
|
136
|
+
require 'samples/hello/hello_combo'
|
137
|
+
```
|
138
|
+
|
139
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
107
140
|
|
141
|
+
```ruby
|
108
142
|
class Person
|
109
143
|
attr_accessor :country, :country_options
|
110
144
|
|
@@ -142,7 +176,7 @@ HelloCombo.new.launch
|
|
142
176
|
```
|
143
177
|
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
144
178
|
|
145
|
-

|
146
180
|
|
147
181
|
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
148
182
|
|
@@ -157,13 +191,18 @@ You should see "Hello, Combo!"
|
|
157
191
|
|
158
192
|

|
159
193
|
|
160
|
-
|
194
|
+
#### Hello, Computed!
|
195
|
+
|
196
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
161
197
|
|
162
|
-
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
163
198
|
|
164
199
|
```ruby
|
165
|
-
require '
|
200
|
+
require 'samples/hello/hello_computed'
|
201
|
+
```
|
202
|
+
|
203
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
166
204
|
|
205
|
+
```ruby
|
167
206
|
class HelloComputed
|
168
207
|
class Contact
|
169
208
|
attr_accessor :first_name, :last_name, :year_of_birth
|
@@ -256,7 +295,7 @@ HelloComputed.new.launch
|
|
256
295
|
```
|
257
296
|
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
258
297
|
|
259
|
-

|
260
299
|
|
261
300
|
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
262
301
|
|
@@ -271,9 +310,16 @@ You should see "Hello, Computed!"
|
|
271
310
|
|
272
311
|

|
273
312
|
|
274
|
-
|
313
|
+
#### Hello, List Single Selection!
|
314
|
+
|
315
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
275
316
|
|
276
|
-
|
317
|
+
|
318
|
+
```ruby
|
319
|
+
require 'samples/hello/hello_list_single_selection'
|
320
|
+
```
|
321
|
+
|
322
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
277
323
|
|
278
324
|
```ruby
|
279
325
|
class Person
|
@@ -313,7 +359,7 @@ HelloListSingleSelection.new.launch
|
|
313
359
|
```
|
314
360
|
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
315
361
|
|
316
|
-

|
317
363
|
|
318
364
|
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
319
365
|
|
@@ -328,9 +374,15 @@ You should see "Hello, List Single Selection!"
|
|
328
374
|
|
329
375
|

|
330
376
|
|
331
|
-
|
377
|
+
#### Hello, List Multi Selection!
|
332
378
|
|
333
|
-
Add the following
|
379
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
require 'samples/hello/hello_list_multi_selection'
|
383
|
+
```
|
384
|
+
|
385
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
334
386
|
|
335
387
|
```ruby
|
336
388
|
class Person
|
@@ -380,7 +432,7 @@ HelloListMultiSelection.new.launch
|
|
380
432
|
```
|
381
433
|
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
382
434
|
|
383
|
-

|
384
436
|
|
385
437
|
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
386
438
|
|
@@ -395,6 +447,903 @@ You should see "Hello, List Multi Selection!"
|
|
395
447
|
|
396
448
|

|
397
449
|
|
450
|
+
#### Hello, Browser!
|
451
|
+
|
452
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
453
|
+
|
454
|
+
```ruby
|
455
|
+
require 'samples/hello/hello_browser'
|
456
|
+
```
|
457
|
+
|
458
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
459
|
+
|
460
|
+
```ruby
|
461
|
+
include Glimmer
|
462
|
+
|
463
|
+
shell {
|
464
|
+
minimum_size 1024, 860
|
465
|
+
browser {
|
466
|
+
url 'http://brightonresort.com/about'
|
467
|
+
}
|
468
|
+
}.open
|
469
|
+
```
|
470
|
+
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
471
|
+
|
472
|
+

|
473
|
+
|
474
|
+
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
475
|
+
|
476
|
+
Start the Rails server:
|
477
|
+
```
|
478
|
+
rails s
|
479
|
+
```
|
480
|
+
|
481
|
+
Visit `http://localhost:3000`
|
482
|
+
|
483
|
+
You should see "Hello, Browser!"
|
484
|
+
|
485
|
+

|
486
|
+
|
487
|
+
#### Hello, Tab!
|
488
|
+
|
489
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
490
|
+
|
491
|
+
```ruby
|
492
|
+
require 'samples/hello/hello_tab'
|
493
|
+
```
|
494
|
+
|
495
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
496
|
+
|
497
|
+
```ruby
|
498
|
+
class HelloTab
|
499
|
+
include Glimmer
|
500
|
+
def launch
|
501
|
+
shell {
|
502
|
+
text "Hello, Tab!"
|
503
|
+
tab_folder {
|
504
|
+
tab_item {
|
505
|
+
text "English"
|
506
|
+
label {
|
507
|
+
text "Hello, World!"
|
508
|
+
}
|
509
|
+
}
|
510
|
+
tab_item {
|
511
|
+
text "French"
|
512
|
+
label {
|
513
|
+
text "Bonjour, Univers!"
|
514
|
+
}
|
515
|
+
}
|
516
|
+
}
|
517
|
+
}.open
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
HelloTab.new.launch
|
522
|
+
```
|
523
|
+
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
524
|
+
|
525
|
+

|
526
|
+

|
527
|
+
|
528
|
+
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
529
|
+
|
530
|
+
Start the Rails server:
|
531
|
+
```
|
532
|
+
rails s
|
533
|
+
```
|
534
|
+
|
535
|
+
Visit `http://localhost:3000`
|
536
|
+
|
537
|
+
You should see "Hello, Tab!"
|
538
|
+
|
539
|
+

|
540
|
+

|
541
|
+
|
542
|
+
### Elaborate Samples
|
543
|
+
|
544
|
+
#### Login
|
545
|
+
|
546
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
547
|
+
|
548
|
+
```ruby
|
549
|
+
require 'samples/elaborate/login'
|
550
|
+
```
|
551
|
+
|
552
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
553
|
+
|
554
|
+
```ruby
|
555
|
+
require "observer"
|
556
|
+
|
557
|
+
#Presents login screen data
|
558
|
+
class LoginPresenter
|
559
|
+
|
560
|
+
attr_accessor :user_name
|
561
|
+
attr_accessor :password
|
562
|
+
attr_accessor :status
|
563
|
+
|
564
|
+
def initialize
|
565
|
+
@user_name = ""
|
566
|
+
@password = ""
|
567
|
+
@status = "Logged Out"
|
568
|
+
end
|
569
|
+
|
570
|
+
def status=(status)
|
571
|
+
@status = status
|
572
|
+
|
573
|
+
#TODO add feature to bind dependent properties to master property (2017-07-25 nested data binding)
|
574
|
+
notify_observers("logged_in")
|
575
|
+
notify_observers("logged_out")
|
576
|
+
end
|
577
|
+
|
578
|
+
def logged_in
|
579
|
+
self.status == "Logged In"
|
580
|
+
end
|
581
|
+
|
582
|
+
def logged_out
|
583
|
+
!self.logged_in
|
584
|
+
end
|
585
|
+
|
586
|
+
def login
|
587
|
+
self.status = "Logged In"
|
588
|
+
end
|
589
|
+
|
590
|
+
def logout
|
591
|
+
self.user_name = ""
|
592
|
+
self.password = ""
|
593
|
+
self.status = "Logged Out"
|
594
|
+
end
|
595
|
+
|
596
|
+
end
|
597
|
+
|
598
|
+
#Login screen
|
599
|
+
class Login
|
600
|
+
include Glimmer
|
601
|
+
|
602
|
+
def launch
|
603
|
+
presenter = LoginPresenter.new
|
604
|
+
@shell = shell {
|
605
|
+
text "Login"
|
606
|
+
composite {
|
607
|
+
grid_layout 2, false #two columns with differing widths
|
608
|
+
|
609
|
+
label { text "Username:" } # goes in column 1
|
610
|
+
text { # goes in column 2
|
611
|
+
text bind(presenter, :user_name)
|
612
|
+
enabled bind(presenter, :logged_out)
|
613
|
+
}
|
614
|
+
|
615
|
+
label { text "Password:" }
|
616
|
+
text(:password, :border) {
|
617
|
+
text bind(presenter, :password)
|
618
|
+
enabled bind(presenter, :logged_out)
|
619
|
+
}
|
620
|
+
|
621
|
+
label { text "Status:" }
|
622
|
+
label { text bind(presenter, :status) }
|
623
|
+
|
624
|
+
button {
|
625
|
+
text "Login"
|
626
|
+
enabled bind(presenter, :logged_out)
|
627
|
+
on_widget_selected { presenter.login }
|
628
|
+
}
|
629
|
+
|
630
|
+
button {
|
631
|
+
text "Logout"
|
632
|
+
enabled bind(presenter, :logged_in)
|
633
|
+
on_widget_selected { presenter.logout }
|
634
|
+
}
|
635
|
+
}
|
636
|
+
}
|
637
|
+
@shell.open
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
Login.new.launch
|
642
|
+
```
|
643
|
+
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
644
|
+
|
645
|
+

|
646
|
+

|
647
|
+

|
648
|
+
|
649
|
+
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
650
|
+
|
651
|
+
Start the Rails server:
|
652
|
+
```
|
653
|
+
rails s
|
654
|
+
```
|
655
|
+
|
656
|
+
Visit `http://localhost:3000`
|
657
|
+
|
658
|
+
You should see "Login" dialog
|
659
|
+
|
660
|
+

|
661
|
+

|
662
|
+

|
663
|
+
|
664
|
+
#### Tic Tac Toe
|
665
|
+
|
666
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
667
|
+
|
668
|
+
```ruby
|
669
|
+
require 'samples/elaborate/tic_tac_toe'
|
670
|
+
```
|
671
|
+
|
672
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
673
|
+
|
674
|
+
```ruby
|
675
|
+
class TicTacToe
|
676
|
+
class Cell
|
677
|
+
EMPTY = ""
|
678
|
+
attr_accessor :sign, :empty
|
679
|
+
|
680
|
+
def initialize
|
681
|
+
reset
|
682
|
+
end
|
683
|
+
|
684
|
+
def mark(sign)
|
685
|
+
self.sign = sign
|
686
|
+
end
|
687
|
+
|
688
|
+
def reset
|
689
|
+
self.sign = EMPTY
|
690
|
+
end
|
691
|
+
|
692
|
+
def sign=(sign_symbol)
|
693
|
+
@sign = sign_symbol
|
694
|
+
self.empty = sign == EMPTY
|
695
|
+
end
|
696
|
+
|
697
|
+
def marked
|
698
|
+
!empty
|
699
|
+
end
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
class TicTacToe
|
704
|
+
class Board
|
705
|
+
DRAW = :draw
|
706
|
+
IN_PROGRESS = :in_progress
|
707
|
+
WIN = :win
|
708
|
+
attr :winning_sign
|
709
|
+
attr_accessor :game_status
|
710
|
+
|
711
|
+
def initialize
|
712
|
+
@sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
|
713
|
+
build_grid
|
714
|
+
@winning_sign = Cell::EMPTY
|
715
|
+
@game_status = IN_PROGRESS
|
716
|
+
end
|
717
|
+
|
718
|
+
#row and column numbers are 1-based
|
719
|
+
def mark(row, column)
|
720
|
+
self[row, column].mark(current_sign)
|
721
|
+
game_over? #updates winning sign
|
722
|
+
end
|
723
|
+
|
724
|
+
def current_sign
|
725
|
+
@current_sign = @sign_state_machine[@current_sign]
|
726
|
+
end
|
727
|
+
|
728
|
+
def [](row, column)
|
729
|
+
@grid[row-1][column-1]
|
730
|
+
end
|
731
|
+
|
732
|
+
def game_over?
|
733
|
+
win? or draw?
|
734
|
+
end
|
735
|
+
|
736
|
+
def win?
|
737
|
+
win = (row_win? or column_win? or diagonal_win?)
|
738
|
+
self.game_status=WIN if win
|
739
|
+
win
|
740
|
+
end
|
741
|
+
|
742
|
+
def reset
|
743
|
+
(1..3).each do |row|
|
744
|
+
(1..3).each do |column|
|
745
|
+
self[row, column].reset
|
746
|
+
end
|
747
|
+
end
|
748
|
+
@winning_sign = Cell::EMPTY
|
749
|
+
@current_sign = nil
|
750
|
+
self.game_status=IN_PROGRESS
|
751
|
+
end
|
752
|
+
|
753
|
+
private
|
754
|
+
|
755
|
+
def build_grid
|
756
|
+
@grid = []
|
757
|
+
3.times do |row_index| #0-based
|
758
|
+
@grid << []
|
759
|
+
3.times { @grid[row_index] << Cell.new }
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
def row_win?
|
764
|
+
(1..3).each do |row|
|
765
|
+
if row_has_same_sign(row)
|
766
|
+
@winning_sign = self[row, 1].sign
|
767
|
+
return true
|
768
|
+
end
|
769
|
+
end
|
770
|
+
false
|
771
|
+
end
|
772
|
+
|
773
|
+
def column_win?
|
774
|
+
(1..3).each do |column|
|
775
|
+
if column_has_same_sign(column)
|
776
|
+
@winning_sign = self[1, column].sign
|
777
|
+
return true
|
778
|
+
end
|
779
|
+
end
|
780
|
+
false
|
781
|
+
end
|
782
|
+
|
783
|
+
#needs refactoring if we ever decide to make the board size dynamic
|
784
|
+
def diagonal_win?
|
785
|
+
if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
|
786
|
+
@winning_sign = self[1, 1].sign
|
787
|
+
return true
|
788
|
+
end
|
789
|
+
if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
|
790
|
+
@winning_sign = self[3, 1].sign
|
791
|
+
return true
|
792
|
+
end
|
793
|
+
false
|
794
|
+
end
|
795
|
+
|
796
|
+
def draw?
|
797
|
+
@board_full = true
|
798
|
+
3.times do |x|
|
799
|
+
3.times do |y|
|
800
|
+
@board_full = false if self[x, y].empty
|
801
|
+
end
|
802
|
+
end
|
803
|
+
self.game_status = DRAW if @board_full
|
804
|
+
@board_full
|
805
|
+
end
|
806
|
+
|
807
|
+
def row_has_same_sign(number)
|
808
|
+
row_sign = self[number, 1].sign
|
809
|
+
[2, 3].each do |column|
|
810
|
+
return false unless row_sign == (self[number, column].sign)
|
811
|
+
end
|
812
|
+
true if self[number, 1].marked
|
813
|
+
end
|
814
|
+
|
815
|
+
def column_has_same_sign(number)
|
816
|
+
column_sign = self[1, number].sign
|
817
|
+
[2, 3].each do |row|
|
818
|
+
return false unless column_sign == (self[row, number].sign)
|
819
|
+
end
|
820
|
+
true if self[1, number].marked
|
821
|
+
end
|
822
|
+
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
class TicTacToe
|
827
|
+
include Glimmer
|
828
|
+
|
829
|
+
def initialize
|
830
|
+
@tic_tac_toe_board = Board.new
|
831
|
+
@shell = shell {
|
832
|
+
text "Tic-Tac-Toe"
|
833
|
+
composite {
|
834
|
+
grid_layout 3, true
|
835
|
+
(1..3).each { |row|
|
836
|
+
(1..3).each { |column|
|
837
|
+
button {
|
838
|
+
layout_data :fill, :fill, true, true
|
839
|
+
text bind(@tic_tac_toe_board[row, column], :sign)
|
840
|
+
enabled bind(@tic_tac_toe_board[row, column], :empty)
|
841
|
+
on_widget_selected {
|
842
|
+
@tic_tac_toe_board.mark(row, column)
|
843
|
+
}
|
844
|
+
}
|
845
|
+
}
|
846
|
+
}
|
847
|
+
}
|
848
|
+
}
|
849
|
+
observe(@tic_tac_toe_board, :game_status) { |game_status|
|
850
|
+
display_win_message if game_status == Board::WIN
|
851
|
+
display_draw_message if game_status == Board::DRAW
|
852
|
+
}
|
853
|
+
end
|
854
|
+
|
855
|
+
def display_win_message
|
856
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
857
|
+
end
|
858
|
+
|
859
|
+
def display_draw_message
|
860
|
+
display_game_over_message("Draw!")
|
861
|
+
end
|
862
|
+
|
863
|
+
def display_game_over_message(message_text)
|
864
|
+
message_box(@shell) {
|
865
|
+
text 'Game Over'
|
866
|
+
message message_text
|
867
|
+
}.open
|
868
|
+
@tic_tac_toe_board.reset
|
869
|
+
end
|
870
|
+
|
871
|
+
def open
|
872
|
+
@shell.open
|
873
|
+
end
|
874
|
+
end
|
875
|
+
|
876
|
+
TicTacToe.new.open
|
877
|
+
```
|
878
|
+
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
879
|
+
|
880
|
+

|
881
|
+

|
882
|
+

|
883
|
+
|
884
|
+
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
885
|
+
|
886
|
+
Start the Rails server:
|
887
|
+
```
|
888
|
+
rails s
|
889
|
+
```
|
890
|
+
|
891
|
+
Visit `http://localhost:3000`
|
892
|
+
|
893
|
+
You should see "Tic Tac Toe"
|
894
|
+
|
895
|
+

|
896
|
+

|
897
|
+

|
898
|
+
|
899
|
+
#### Contact Manager
|
900
|
+
|
901
|
+
Add the following require statement to `app/assets/javascripts/application.rb`
|
902
|
+
|
903
|
+
```ruby
|
904
|
+
require 'samples/elaborate/contact_manager'
|
905
|
+
```
|
906
|
+
|
907
|
+
Or add the Glimmer code directly if you prefer to play around with it:
|
908
|
+
|
909
|
+
```ruby
|
910
|
+
class ContactManager
|
911
|
+
class Contact
|
912
|
+
attr_accessor :first_name, :last_name, :email
|
913
|
+
|
914
|
+
def initialize(attribute_map)
|
915
|
+
@first_name = attribute_map[:first_name]
|
916
|
+
@last_name = attribute_map[:last_name]
|
917
|
+
@email = attribute_map[:email]
|
918
|
+
end
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
922
|
+
class ContactManager
|
923
|
+
class ContactRepository
|
924
|
+
NAMES_FIRST = %w[
|
925
|
+
Liam
|
926
|
+
Noah
|
927
|
+
William
|
928
|
+
James
|
929
|
+
Oliver
|
930
|
+
Benjamin
|
931
|
+
Elijah
|
932
|
+
Lucas
|
933
|
+
Mason
|
934
|
+
Logan
|
935
|
+
Alexander
|
936
|
+
Ethan
|
937
|
+
Jacob
|
938
|
+
Michael
|
939
|
+
Daniel
|
940
|
+
Henry
|
941
|
+
Jackson
|
942
|
+
Sebastian
|
943
|
+
Aiden
|
944
|
+
Matthew
|
945
|
+
Samuel
|
946
|
+
David
|
947
|
+
Joseph
|
948
|
+
Carter
|
949
|
+
Owen
|
950
|
+
Wyatt
|
951
|
+
John
|
952
|
+
Jack
|
953
|
+
Luke
|
954
|
+
Jayden
|
955
|
+
Dylan
|
956
|
+
Grayson
|
957
|
+
Levi
|
958
|
+
Isaac
|
959
|
+
Gabriel
|
960
|
+
Julian
|
961
|
+
Mateo
|
962
|
+
Anthony
|
963
|
+
Jaxon
|
964
|
+
Lincoln
|
965
|
+
Joshua
|
966
|
+
Christopher
|
967
|
+
Andrew
|
968
|
+
Theodore
|
969
|
+
Caleb
|
970
|
+
Ryan
|
971
|
+
Asher
|
972
|
+
Nathan
|
973
|
+
Thomas
|
974
|
+
Leo
|
975
|
+
Isaiah
|
976
|
+
Charles
|
977
|
+
Josiah
|
978
|
+
Hudson
|
979
|
+
Christian
|
980
|
+
Hunter
|
981
|
+
Connor
|
982
|
+
Eli
|
983
|
+
Ezra
|
984
|
+
Aaron
|
985
|
+
Landon
|
986
|
+
Adrian
|
987
|
+
Jonathan
|
988
|
+
Nolan
|
989
|
+
Jeremiah
|
990
|
+
Easton
|
991
|
+
Elias
|
992
|
+
Colton
|
993
|
+
Cameron
|
994
|
+
Carson
|
995
|
+
Robert
|
996
|
+
Angel
|
997
|
+
Maverick
|
998
|
+
Nicholas
|
999
|
+
Dominic
|
1000
|
+
Jaxson
|
1001
|
+
Greyson
|
1002
|
+
Adam
|
1003
|
+
Ian
|
1004
|
+
Austin
|
1005
|
+
Santiago
|
1006
|
+
Jordan
|
1007
|
+
Cooper
|
1008
|
+
Brayden
|
1009
|
+
Roman
|
1010
|
+
Evan
|
1011
|
+
Ezekiel
|
1012
|
+
Xaviar
|
1013
|
+
Jose
|
1014
|
+
Jace
|
1015
|
+
Jameson
|
1016
|
+
Leonardo
|
1017
|
+
Axel
|
1018
|
+
Everett
|
1019
|
+
Kayden
|
1020
|
+
Miles
|
1021
|
+
Sawyer
|
1022
|
+
Jason
|
1023
|
+
Emma
|
1024
|
+
Olivia
|
1025
|
+
Ava
|
1026
|
+
Isabella
|
1027
|
+
Sophia
|
1028
|
+
Charlotte
|
1029
|
+
Mia
|
1030
|
+
Amelia
|
1031
|
+
Harper
|
1032
|
+
Evelyn
|
1033
|
+
Abigail
|
1034
|
+
Emily
|
1035
|
+
Elizabeth
|
1036
|
+
Mila
|
1037
|
+
Ella
|
1038
|
+
Avery
|
1039
|
+
Sofia
|
1040
|
+
Camila
|
1041
|
+
Aria
|
1042
|
+
Scarlett
|
1043
|
+
Victoria
|
1044
|
+
Madison
|
1045
|
+
Luna
|
1046
|
+
Grace
|
1047
|
+
Chloe
|
1048
|
+
Penelope
|
1049
|
+
Layla
|
1050
|
+
Riley
|
1051
|
+
Zoey
|
1052
|
+
Nora
|
1053
|
+
Lily
|
1054
|
+
Eleanor
|
1055
|
+
Hannah
|
1056
|
+
Lillian
|
1057
|
+
Addison
|
1058
|
+
Aubrey
|
1059
|
+
Ellie
|
1060
|
+
Stella
|
1061
|
+
Natalie
|
1062
|
+
Zoe
|
1063
|
+
Leah
|
1064
|
+
Hazel
|
1065
|
+
Violet
|
1066
|
+
Aurora
|
1067
|
+
Savannah
|
1068
|
+
Audrey
|
1069
|
+
Brooklyn
|
1070
|
+
Bella
|
1071
|
+
Claire
|
1072
|
+
Skylar
|
1073
|
+
Lucy
|
1074
|
+
Paisley
|
1075
|
+
Everly
|
1076
|
+
Anna
|
1077
|
+
Caroline
|
1078
|
+
Nova
|
1079
|
+
Genesis
|
1080
|
+
Emilia
|
1081
|
+
Kennedy
|
1082
|
+
Samantha
|
1083
|
+
Maya
|
1084
|
+
Willow
|
1085
|
+
Kinsley
|
1086
|
+
Naomi
|
1087
|
+
Aaliyah
|
1088
|
+
Elena
|
1089
|
+
Sarah
|
1090
|
+
Ariana
|
1091
|
+
Allison
|
1092
|
+
Gabriella
|
1093
|
+
Alice
|
1094
|
+
Madelyn
|
1095
|
+
Cora
|
1096
|
+
Ruby
|
1097
|
+
Eva
|
1098
|
+
Serenity
|
1099
|
+
Autumn
|
1100
|
+
Adeline
|
1101
|
+
Hailey
|
1102
|
+
Gianna
|
1103
|
+
Valentina
|
1104
|
+
Isla
|
1105
|
+
Eliana
|
1106
|
+
Quinn
|
1107
|
+
Nevaeh
|
1108
|
+
Ivy
|
1109
|
+
Sadie
|
1110
|
+
Piper
|
1111
|
+
Lydia
|
1112
|
+
Alexa
|
1113
|
+
Josephine
|
1114
|
+
Emery
|
1115
|
+
Julia
|
1116
|
+
Delilah
|
1117
|
+
Arianna
|
1118
|
+
Vivian
|
1119
|
+
Kaylee
|
1120
|
+
Sophie
|
1121
|
+
Brielle
|
1122
|
+
Madeline
|
1123
|
+
]
|
1124
|
+
NAMES_LAST = %w[
|
1125
|
+
Smith
|
1126
|
+
Johnson
|
1127
|
+
Williams
|
1128
|
+
Brown
|
1129
|
+
Jones
|
1130
|
+
Miller
|
1131
|
+
Davis
|
1132
|
+
Wilson
|
1133
|
+
Anderson
|
1134
|
+
Taylor
|
1135
|
+
]
|
1136
|
+
def initialize(contacts = nil)
|
1137
|
+
@contacts = contacts || 1000.times.map do |n|
|
1138
|
+
random_first_name_index = (rand*NAMES_FIRST.size).to_i
|
1139
|
+
random_last_name_index = (rand*NAMES_LAST.size).to_i
|
1140
|
+
first_name = NAMES_FIRST[random_first_name_index]
|
1141
|
+
last_name = NAMES_LAST[random_last_name_index]
|
1142
|
+
email = "#{first_name}@#{last_name}.com".downcase
|
1143
|
+
Contact.new(
|
1144
|
+
first_name: first_name,
|
1145
|
+
last_name: last_name,
|
1146
|
+
email: email
|
1147
|
+
)
|
1148
|
+
end
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
def find(attribute_filter_map)
|
1152
|
+
@contacts.find_all do |contact|
|
1153
|
+
match = true
|
1154
|
+
attribute_filter_map.keys.each do |attribute_name|
|
1155
|
+
contact_value = contact.send(attribute_name).downcase
|
1156
|
+
filter_value = attribute_filter_map[attribute_name].downcase
|
1157
|
+
match = false unless contact_value.match(filter_value)
|
1158
|
+
end
|
1159
|
+
match
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
end
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
class ContactManager
|
1166
|
+
class ContactManagerPresenter
|
1167
|
+
attr_accessor :results
|
1168
|
+
@@contact_attributes = [:first_name, :last_name, :email]
|
1169
|
+
@@contact_attributes.each {|attribute_name| attr_accessor attribute_name}
|
1170
|
+
|
1171
|
+
def initialize(contact_repository = nil)
|
1172
|
+
@contact_repository = contact_repository || ContactRepository.new
|
1173
|
+
@results = []
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
def list
|
1177
|
+
self.results = @contact_repository.find({})
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
def find
|
1181
|
+
filter_map = {}
|
1182
|
+
@@contact_attributes.each do |attribute_name|
|
1183
|
+
filter_map[attribute_name] = self.send(attribute_name) if self.send(attribute_name)
|
1184
|
+
end
|
1185
|
+
self.results = @contact_repository.find(filter_map)
|
1186
|
+
@sort_attribute_name = nil
|
1187
|
+
@sort_direction_ascending = nil
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
def toggle_sort(attribute_name)
|
1191
|
+
@sort_attribute_name = attribute_name
|
1192
|
+
@sort_direction_ascending = !@sort_direction_ascending
|
1193
|
+
sorted_results = self.results.sort_by {|contact| contact.send(attribute_name).downcase}
|
1194
|
+
sorted_results = sorted_results.reverse unless @sort_direction_ascending
|
1195
|
+
self.results = sorted_results
|
1196
|
+
end
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
class ContactManager
|
1201
|
+
include Glimmer
|
1202
|
+
|
1203
|
+
def initialize
|
1204
|
+
@contact_manager_presenter = ContactManagerPresenter.new
|
1205
|
+
@contact_manager_presenter.list
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
def launch
|
1209
|
+
shell {
|
1210
|
+
text "Contact Manager"
|
1211
|
+
composite {
|
1212
|
+
composite {
|
1213
|
+
grid_layout 2, false
|
1214
|
+
label {text "First &Name: "}
|
1215
|
+
text {
|
1216
|
+
text bind(@contact_manager_presenter, :first_name)
|
1217
|
+
on_key_pressed {|key_event|
|
1218
|
+
@contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
|
1219
|
+
}
|
1220
|
+
}
|
1221
|
+
label {text "&Last Name: "}
|
1222
|
+
text {
|
1223
|
+
text bind(@contact_manager_presenter, :last_name)
|
1224
|
+
on_key_pressed {|key_event|
|
1225
|
+
@contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
|
1226
|
+
}
|
1227
|
+
}
|
1228
|
+
label {text "&Email: "}
|
1229
|
+
text {
|
1230
|
+
text bind(@contact_manager_presenter, :email)
|
1231
|
+
on_key_pressed {|key_event|
|
1232
|
+
@contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
|
1233
|
+
}
|
1234
|
+
}
|
1235
|
+
composite {
|
1236
|
+
grid_layout 2, false
|
1237
|
+
button {
|
1238
|
+
text "&Find"
|
1239
|
+
on_widget_selected {
|
1240
|
+
@contact_manager_presenter.find
|
1241
|
+
}
|
1242
|
+
}
|
1243
|
+
button {
|
1244
|
+
text "&List All"
|
1245
|
+
on_widget_selected {
|
1246
|
+
@contact_manager_presenter.list
|
1247
|
+
}
|
1248
|
+
}
|
1249
|
+
}
|
1250
|
+
}
|
1251
|
+
|
1252
|
+
table(:multi) { |table_proxy|
|
1253
|
+
layout_data {
|
1254
|
+
horizontal_alignment :fill
|
1255
|
+
vertical_alignment :fill
|
1256
|
+
grab_excess_horizontal_space true
|
1257
|
+
grab_excess_vertical_space true
|
1258
|
+
height_hint 200
|
1259
|
+
}
|
1260
|
+
table_column {
|
1261
|
+
text "First Name"
|
1262
|
+
width 80
|
1263
|
+
on_widget_selected {
|
1264
|
+
@contact_manager_presenter.toggle_sort(:first_name)
|
1265
|
+
}
|
1266
|
+
}
|
1267
|
+
table_column {
|
1268
|
+
text "Last Name"
|
1269
|
+
width 80
|
1270
|
+
on_widget_selected {
|
1271
|
+
@contact_manager_presenter.toggle_sort(:last_name)
|
1272
|
+
}
|
1273
|
+
}
|
1274
|
+
table_column {
|
1275
|
+
text "Email"
|
1276
|
+
width 200
|
1277
|
+
on_widget_selected {
|
1278
|
+
@contact_manager_presenter.toggle_sort(:email)
|
1279
|
+
}
|
1280
|
+
}
|
1281
|
+
items bind(@contact_manager_presenter, :results), column_properties(:first_name, :last_name, :email)
|
1282
|
+
on_mouse_down { |event|
|
1283
|
+
table_proxy.edit_table_item(event.table_item, event.column_index)
|
1284
|
+
}
|
1285
|
+
}
|
1286
|
+
}
|
1287
|
+
}.open
|
1288
|
+
end
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
ContactManager.new.launch
|
1292
|
+
|
1293
|
+
```
|
1294
|
+
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
1295
|
+
|
1296
|
+
Glimmer DSL for SWT Contact Manager
|
1297
|
+
|
1298
|
+

|
1299
|
+
|
1300
|
+
Glimmer DSL for SWT Contact Manager Find
|
1301
|
+
|
1302
|
+

|
1303
|
+
|
1304
|
+
Glimmer DSL for SWT Contact Manager Edit Started
|
1305
|
+
|
1306
|
+

|
1307
|
+
|
1308
|
+
Glimmer DSL for SWT Contact Manager Edit In Progress
|
1309
|
+
|
1310
|
+

|
1311
|
+
|
1312
|
+
Glimmer DSL for SWT Contact Manager Edit Done
|
1313
|
+
|
1314
|
+

|
1315
|
+
|
1316
|
+
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
1317
|
+
|
1318
|
+
Start the Rails server:
|
1319
|
+
```
|
1320
|
+
rails s
|
1321
|
+
```
|
1322
|
+
|
1323
|
+
Visit `http://localhost:3000`
|
1324
|
+
|
1325
|
+
You should see "Tic Tac Toe"
|
1326
|
+
|
1327
|
+
Glimmer DSL for Opal Contact Manager
|
1328
|
+
|
1329
|
+

|
1330
|
+
|
1331
|
+
Glimmer DSL for Opal Contact Manager Find
|
1332
|
+
|
1333
|
+

|
1334
|
+
|
1335
|
+
Glimmer DSL for Opal Contact Manager Edit Started
|
1336
|
+
|
1337
|
+

|
1338
|
+
|
1339
|
+
Glimmer DSL for Opal Contact Manager Edit In Progress
|
1340
|
+
|
1341
|
+

|
1342
|
+
|
1343
|
+
Glimmer DSL for Opal Contact Manager Edit Done
|
1344
|
+
|
1345
|
+

|
1346
|
+
|
398
1347
|
## Help
|
399
1348
|
|
400
1349
|
### Issues
|