glimmer-dsl-opal 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/README.md +1003 -58
  4. data/VERSION +1 -1
  5. data/lib/glimmer-dsl-opal.rb +26 -8
  6. data/lib/glimmer/data_binding/element_binding.rb +1 -1
  7. data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
  8. data/lib/glimmer/data_binding/list_selection_binding.rb +1 -1
  9. data/lib/glimmer/data_binding/table_items_binding.rb +70 -0
  10. data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
  11. data/lib/glimmer/dsl/opal/column_properties_expression.rb +22 -0
  12. data/lib/glimmer/dsl/opal/combo_selection_data_binding_expression.rb +2 -2
  13. data/lib/glimmer/dsl/opal/dsl.rb +10 -12
  14. data/lib/glimmer/dsl/opal/layout_data_expression.rb +2 -2
  15. data/lib/glimmer/dsl/opal/{text_expression.rb → layout_expression.rb} +5 -5
  16. data/lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb +2 -3
  17. data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
  18. data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
  19. data/lib/glimmer/dsl/opal/shell_expression.rb +2 -2
  20. data/lib/glimmer/dsl/opal/{composite_expression.rb → table_column_expression.rb} +3 -3
  21. data/lib/glimmer/dsl/opal/{list_expression.rb → table_expression.rb} +3 -3
  22. data/lib/glimmer/dsl/opal/table_items_data_binding_expression.rb +29 -0
  23. data/lib/glimmer/dsl/opal/widget_expression.rb +23 -0
  24. data/lib/glimmer/opal/display_proxy.rb +23 -0
  25. data/lib/glimmer/opal/element_proxy.rb +48 -13
  26. data/lib/glimmer/swt/browser_proxy.rb +27 -0
  27. data/lib/glimmer/swt/button_proxy.rb +40 -0
  28. data/lib/glimmer/{opal/select_proxy.rb → swt/combo_proxy.rb} +15 -11
  29. data/lib/glimmer/swt/composite_proxy.rb +31 -0
  30. data/lib/glimmer/{opal → swt}/event_listener_proxy.rb +1 -1
  31. data/lib/glimmer/{opal → swt}/grid_layout_proxy.rb +7 -18
  32. data/lib/glimmer/swt/label_proxy.rb +30 -0
  33. data/lib/glimmer/swt/layout_data_proxy.rb +52 -0
  34. data/lib/glimmer/swt/layout_proxy.rb +60 -0
  35. data/lib/glimmer/{opal → swt}/list_proxy.rb +18 -15
  36. data/lib/glimmer/swt/message_box_proxy.rb +146 -0
  37. data/lib/glimmer/{opal → swt}/point.rb +1 -1
  38. data/lib/glimmer/{opal → swt}/property_owner.rb +1 -1
  39. data/lib/glimmer/swt/shell_proxy.rb +235 -0
  40. data/lib/glimmer/swt/tab_folder_proxy.rb +52 -0
  41. data/lib/glimmer/swt/tab_item_proxy.rb +101 -0
  42. data/lib/glimmer/swt/table_column_proxy.rb +56 -0
  43. data/lib/glimmer/swt/table_item_proxy.rb +147 -0
  44. data/lib/glimmer/swt/table_proxy.rb +177 -0
  45. data/lib/glimmer/swt/text_proxy.rb +46 -0
  46. data/lib/glimmer/swt/widget_proxy.rb +389 -0
  47. data/lib/jquery.js +2 -0
  48. data/lib/samples/elaborate/contact_manager.rb +2 -3
  49. data/lib/samples/elaborate/login.rb +0 -1
  50. data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
  51. data/lib/samples/hello/hello_computed.rb +19 -19
  52. data/lib/samples/hello/hello_tab.rb +2 -2
  53. metadata +92 -59
  54. data/lib/glimmer/config.rb +0 -22
  55. data/lib/glimmer/dsl/engine.rb +0 -193
  56. data/lib/glimmer/dsl/expression.rb +0 -42
  57. data/lib/glimmer/dsl/expression_handler.rb +0 -48
  58. data/lib/glimmer/dsl/opal/browser_expression.rb +0 -17
  59. data/lib/glimmer/dsl/opal/button_expression.rb +0 -18
  60. data/lib/glimmer/dsl/opal/combo_expression.rb +0 -17
  61. data/lib/glimmer/dsl/opal/grid_layout_expression.rb +0 -17
  62. data/lib/glimmer/dsl/opal/label_expression.rb +0 -17
  63. data/lib/glimmer/dsl/parent_expression.rb +0 -12
  64. data/lib/glimmer/dsl/static_expression.rb +0 -36
  65. data/lib/glimmer/dsl/top_level_expression.rb +0 -7
  66. data/lib/glimmer/error.rb +0 -6
  67. data/lib/glimmer/invalid_keyword_error.rb +0 -6
  68. data/lib/glimmer/opal/div_proxy.rb +0 -20
  69. data/lib/glimmer/opal/document_proxy.rb +0 -90
  70. data/lib/glimmer/opal/iframe_proxy.rb +0 -23
  71. data/lib/glimmer/opal/input_proxy.rb +0 -41
  72. data/lib/glimmer/opal/label_proxy.rb +0 -25
  73. data/lib/glimmer/opal/layout_data_proxy.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62c893d845b584b5b303dd5070b67b5042656159dbc1e4124fcc20fdaa469a8e
4
- data.tar.gz: 192f1904a065a6add1e2cffba0a3514dc8b178746b0f6b350e7973d88a9ac86d
3
+ metadata.gz: b86a4ab59fb47c8fd2e21c3f88d790942b19461e159b613edab602c250c0d9e7
4
+ data.tar.gz: 121b3220b1bdb4848ce065564f108bc03f0d8145a2e35d07936ed69f66d52e8a
5
5
  SHA512:
6
- metadata.gz: 895dda95906afa3738c34c927cc85600bcfb13a04f4e71ddc261221eeb6c0043f2b10f95561e9b03895a3ec7aa2b4c1a90c3c54667aacbc30b307fabdb569654
7
- data.tar.gz: da8bf5fa194f983e53190d45246dfecb6add28fd20bec9ea1e2cf413716ad44f256d41674882f59823b32d1576964bdf387b96ef683fdf90196469137757a18d
6
+ metadata.gz: e5a6fd8bb27c826ffbfa8baf5a0ab006f5756125eae25cea4fd08911c65736899520c8bbe1fafa6e1e9941ad1902dc90a62630170a2c0afec9f0420e4ec3911c
7
+ data.tar.gz: dfb9b7195d02486125efff51d9abb1c3c14ba62e9450f597d1508418155962eef0e00a7e2149f501de0f5fdf589fc4c71038392b743c42a43b9c83e914264462
@@ -1,5 +1,46 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.1.0
4
+
5
+ - Code redesign to better match the glimmer-dsl-swt APIs
6
+ - opal-jquery refactoring
7
+ - opal-rspec test coverage
8
+
9
+ ## 0.0.9
10
+
11
+ - Upgraded to glimmer gem v0.9.3
12
+ - Fixed issue with missing Glimmer::Opal::ElementProxy#id=(value) method breaking Contact Manager sample Find feature
13
+
14
+ ## 0.0.8
15
+
16
+ - Contact Manager sample support
17
+
18
+ ## 0.0.7
19
+
20
+ - Tic Tac Toe sample support
21
+ - Login sample support
22
+
23
+ ## 0.0.6
24
+
25
+ - Hello, Tab! sample support
26
+
27
+ ## 0.0.5
28
+
29
+ - Hello, Browser! sample support
30
+
31
+ ## 0.0.4
32
+
33
+ - Hello, List Single Selection! sample support
34
+ - Hello, List Multi Selection! sample support
35
+
36
+ ## 0.0.3
37
+
38
+ - Hello, Computed! sample support
39
+
40
+ ## 0.0.2
41
+
42
+ - Hello, Combo! sample support
43
+
3
44
  ## 0.0.1
4
45
 
5
46
  - Initial support for webifying Glimmer SWT apps
data/README.md CHANGED
@@ -1,21 +1,30 @@
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.5 (Web GUI for Desktop Apps)
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Opal 0.0.9 (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](https://github.com/AndyObtiva/glimmer) DSL for [Opal](https://opalrb.com/) is an experimental proof-of-concept web GUI adaptor for [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps (i.e. apps built with [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.
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
+ Glimmer DSL for Opal successfully reuses the entire [Glimmer](https://github.com/AndyObtiva/glimmer) core DSL engine in [Opal](https://opalrb.com/) Ruby, and as such inherits the full range of powerful Glimmer DSL [data-binding](https://github.com/AndyObtiva/glimmer#data-binding) capabilities, such as:
8
+ - `bind(model, property)` basic data-binding
9
+ - `bind(model, property, computed_by: procs)` computed data-binding
10
+ - `bind(model, property, on_read:, on_write:)` data-binding converters
11
+ - `bind(model, property), column_properties(columns)` `table` data-binding
12
+ - Automatically inferred `property_options` for `list` and `combo` data-binding
13
+ - `observe(model, property)` free-form observing
9
14
 
10
- NOTE: Alpha Version 0.0.5 only supports capabilities below (detailed under [Examples](#examples)):
15
+ NOTE: Alpha Version 0.1.0 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
16
  - [Hello, World!](#hello-world)
12
17
  - [Hello, Combo!](#hello-combo)
13
18
  - [Hello, Computed!](#hello-computed)
14
19
  - [Hello, List Single Selection!](#hello-list-single-selection)
15
20
  - [Hello, List Multi Selection!](#hello-list-multi-selection)
16
21
  - [Hello, Browser!](#hello-browser)
22
+ - [Hello, Tab!](#hello-tab)
23
+ - [Login](#login)
24
+ - [Tic Tac Toe](#tic-tac-toe)
25
+ - [Contact Manager](#contact-manager)
17
26
 
18
- Other Glimmer DSL gems:
27
+ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
19
28
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI)
20
29
  - [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
21
30
  - [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS (Cascading Style Sheets)
@@ -31,7 +40,16 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
31
40
  - `text`
32
41
  - `composite`
33
42
  - `list` & `list(:multi)`
34
- - `browser`
43
+ - `tab_folder`
44
+ - `tab_item`
45
+ - `table`
46
+ - `table_column`
47
+ - `message_box`
48
+ - `on_widget_selected`
49
+ - `on_modify_text`
50
+ - `observe`
51
+ - `bind`
52
+ - `async_exec`
35
53
  - `grid_layout`
36
54
  - `layout_data`
37
55
 
@@ -39,40 +57,69 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
39
57
 
40
58
  - Rails 5: [https://github.com/rails/rails/tree/5-2-stable](https://github.com/rails/rails/tree/5-2-stable)
41
59
  - Opal 1: [https://github.com/opal/opal-rails](https://github.com/opal/opal-rails)
60
+ - jQuery 3: [https://code.jquery.com/](https://code.jquery.com/) (jQuery 3.5.1 is included in the glimmer-dsl-opal rubygem)
42
61
 
43
62
  ## Setup
44
63
 
45
- Please follow these instructions to make Glimmer desktop apps work in Opal inside Rails 5
64
+ (NOTE: if you run into issues, keep in mind this is a very early experimental and incomplete alpha. Also, there is a slight chance issues you encounter are fixed in master or some other branch that you could check out instead)
65
+
66
+ Please install a Rails 5 gem (e.g. `gem install rails -v5.2.4.3` )
46
67
 
47
68
  Start a new Rails 5 app:
48
69
 
49
70
  ```
50
- rails new hello_world
71
+ rails new glimmer_app
51
72
  ```
52
73
 
53
- Follow instructions to setup opal with a rails application: config/initializers/assets.rb
74
+ Add the following to `Gemfile`:
54
75
 
55
- 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):
56
76
  ```
57
- gem 'opal-rails'
58
- gem 'opal-browser'
59
- gem 'glimmer-dsl-opal', '~> 0.0.5', require: false
77
+ gem 'opal-rails', '~> 1.1.2'
78
+ gem 'opal-async', '~> 1.1.0'
79
+ gem 'opal-jquery', '~> 0.4.4'
80
+ gem 'glimmer-dsl-opal', '~> 0.1.0', require: false
81
+ gem 'glimmer-dsl-xml', '~> 0.1.0', require: false
82
+
60
83
  ```
61
84
 
62
- Edit `config/initializers/assets.rb` and add:
85
+ Follow (opal-rails)[https://github.com/opal/opal-rails] instructions, basically the configuration of: config/initializers/assets.rb
86
+
87
+ Edit `config/initializers/assets.rb` and add the following at the bottom:
63
88
  ```
64
89
  Opal.use_gem 'glimmer-dsl-opal'
65
90
  ```
66
91
 
67
- ## Examples
92
+ Add the following line to the top of an empty `app/assets/javascripts/application.rb` (replacing `application.js`)
68
93
 
69
- ### Hello, World!
94
+ ```ruby
95
+ require 'glimmer-dsl-opal' # brings opal and opal browser too
96
+ ```
97
+
98
+ Add more code to `app/assets/javascripts/application.rb` inside `Document.ready? do; end` block 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.
99
+
100
+ ## Samples
70
101
 
71
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
102
+ Make sure to add any `require` statements or code below inside:
72
103
 
73
104
  ```ruby
74
- require 'glimmer-dsl-opal' # brings opal and opal browser too
105
+ Document.ready? do
106
+ # Code goes here.
107
+ end
108
+ ```
109
+
110
+ ### Hello Samples
111
+
112
+ #### Hello, World!
113
+
114
+ Add the following require statement to `app/assets/javascripts/application.rb`
115
+
116
+ ```ruby
117
+ require 'samples/hello/hello_world'
118
+ ```
119
+
120
+ Or add the Glimmer code directly if you prefer to play around with it:
75
121
 
122
+ ```ruby
76
123
  include Glimmer
77
124
 
78
125
  shell {
@@ -80,12 +127,12 @@ shell {
80
127
  label {
81
128
  text 'Hello, World!'
82
129
  }
83
- }
130
+ }.open
84
131
  ```
85
132
 
86
133
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
87
134
 
88
- ![Glimmer DSL for Opal Hello World](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-world.png)
135
+ ![Glimmer DSL for SWT Hello World](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-world.png)
89
136
 
90
137
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
91
138
 
@@ -100,13 +147,17 @@ You should see "Hello, World!"
100
147
 
101
148
  ![Glimmer DSL for Opal Hello World](images/glimmer-dsl-opal-hello-world.png)
102
149
 
103
- ### Hello, Combo!
150
+ #### Hello, Combo!
104
151
 
105
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
152
+ Add the following require statement to `app/assets/javascripts/application.rb`
106
153
 
107
154
  ```ruby
108
- require 'glimmer-dsl-opal' # brings opal and opal browser too
155
+ require 'samples/hello/hello_combo'
156
+ ```
157
+
158
+ Or add the Glimmer code directly if you prefer to play around with it:
109
159
 
160
+ ```ruby
110
161
  class Person
111
162
  attr_accessor :country, :country_options
112
163
 
@@ -144,7 +195,7 @@ HelloCombo.new.launch
144
195
  ```
145
196
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
146
197
 
147
- ![Glimmer DSL for Opal Hello Combo](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-combo.png)
198
+ ![Glimmer DSL for SWT Hello Combo](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-combo.png)
148
199
 
149
200
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
150
201
 
@@ -159,13 +210,18 @@ You should see "Hello, Combo!"
159
210
 
160
211
  ![Glimmer DSL for Opal Hello Combo](images/glimmer-dsl-opal-hello-combo.png)
161
212
 
162
- ### Hello, Computed!
213
+ #### Hello, Computed!
214
+
215
+ Add the following require statement to `app/assets/javascripts/application.rb`
163
216
 
164
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
165
217
 
166
218
  ```ruby
167
- require 'glimmer-dsl-opal' # brings opal and opal browser too
219
+ require 'samples/hello/hello_computed'
220
+ ```
221
+
222
+ Or add the Glimmer code directly if you prefer to play around with it:
168
223
 
224
+ ```ruby
169
225
  class HelloComputed
170
226
  class Contact
171
227
  attr_accessor :first_name, :last_name, :year_of_birth
@@ -193,15 +249,15 @@ class HelloComputed
193
249
 
194
250
  def initialize
195
251
  @contact = Contact.new(
196
- first_name: "Barry",
197
- last_name: "McKibbin",
252
+ first_name: 'Barry',
253
+ last_name: 'McKibbin',
198
254
  year_of_birth: 1985
199
255
  )
200
256
  end
201
257
 
202
258
  def launch
203
259
  shell {
204
- text "Hello Computed"
260
+ text 'Hello, Computed!'
205
261
  composite {
206
262
  grid_layout {
207
263
  num_columns 2
@@ -209,44 +265,44 @@ class HelloComputed
209
265
  horizontal_spacing 20
210
266
  vertical_spacing 10
211
267
  }
212
- label {text "First &Name: "}
268
+ label {text 'First &Name: '}
213
269
  text {
214
270
  text bind(@contact, :first_name)
215
271
  layout_data {
216
- horizontalAlignment :fill
217
- grabExcessHorizontalSpace true
272
+ horizontal_alignment :fill
273
+ grab_excess_horizontal_space true
218
274
  }
219
275
  }
220
- label {text "&Last Name: "}
276
+ label {text '&Last Name: '}
221
277
  text {
222
278
  text bind(@contact, :last_name)
223
279
  layout_data {
224
- horizontalAlignment :fill
225
- grabExcessHorizontalSpace true
280
+ horizontal_alignment :fill
281
+ grab_excess_horizontal_space true
226
282
  }
227
283
  }
228
- label {text "&Year of Birth: "}
284
+ label {text '&Year of Birth: '}
229
285
  text {
230
286
  text bind(@contact, :year_of_birth)
231
287
  layout_data {
232
- horizontalAlignment :fill
233
- grabExcessHorizontalSpace true
288
+ horizontal_alignment :fill
289
+ grab_excess_horizontal_space true
234
290
  }
235
291
  }
236
- label {text "Name: "}
292
+ label {text 'Name: '}
237
293
  label {
238
294
  text bind(@contact, :name, computed_by: [:first_name, :last_name])
239
295
  layout_data {
240
- horizontalAlignment :fill
241
- grabExcessHorizontalSpace true
296
+ horizontal_alignment :fill
297
+ grab_excess_horizontal_space true
242
298
  }
243
299
  }
244
- label {text "Age: "}
300
+ label {text 'Age: '}
245
301
  label {
246
302
  text bind(@contact, :age, on_write: :to_i, computed_by: [:year_of_birth])
247
303
  layout_data {
248
- horizontalAlignment :fill
249
- grabExcessHorizontalSpace true
304
+ horizontal_alignment :fill
305
+ grab_excess_horizontal_space true
250
306
  }
251
307
  }
252
308
  }
@@ -258,7 +314,7 @@ HelloComputed.new.launch
258
314
  ```
259
315
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
260
316
 
261
- ![Glimmer DSL for Opal Hello Computed](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-computed.png)
317
+ ![Glimmer DSL for SWT Hello Computed](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-computed.png)
262
318
 
263
319
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
264
320
 
@@ -273,9 +329,16 @@ You should see "Hello, Computed!"
273
329
 
274
330
  ![Glimmer DSL for Opal Hello Computed](images/glimmer-dsl-opal-hello-computed.png)
275
331
 
276
- ### Hello, List Single Selection!
332
+ #### Hello, List Single Selection!
333
+
334
+ Add the following require statement to `app/assets/javascripts/application.rb`
277
335
 
278
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
336
+
337
+ ```ruby
338
+ require 'samples/hello/hello_list_single_selection'
339
+ ```
340
+
341
+ Or add the Glimmer code directly if you prefer to play around with it:
279
342
 
280
343
  ```ruby
281
344
  class Person
@@ -315,7 +378,7 @@ HelloListSingleSelection.new.launch
315
378
  ```
316
379
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
317
380
 
318
- ![Glimmer DSL for Opal Hello List Single Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-single-selection.png)
381
+ ![Glimmer DSL for SWT Hello List Single Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-single-selection.png)
319
382
 
320
383
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
321
384
 
@@ -330,9 +393,15 @@ You should see "Hello, List Single Selection!"
330
393
 
331
394
  ![Glimmer DSL for Opal Hello List Single Selection](images/glimmer-dsl-opal-hello-list-single-selection.png)
332
395
 
333
- ### Hello, List Multi Selection!
396
+ #### Hello, List Multi Selection!
397
+
398
+ Add the following require statement to `app/assets/javascripts/application.rb`
334
399
 
335
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
400
+ ```ruby
401
+ require 'samples/hello/hello_list_multi_selection'
402
+ ```
403
+
404
+ Or add the Glimmer code directly if you prefer to play around with it:
336
405
 
337
406
  ```ruby
338
407
  class Person
@@ -382,7 +451,7 @@ HelloListMultiSelection.new.launch
382
451
  ```
383
452
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
384
453
 
385
- ![Glimmer DSL for Opal Hello List Multi Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-multi-selection.png)
454
+ ![Glimmer DSL for SWT Hello List Multi Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-multi-selection.png)
386
455
 
387
456
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
388
457
 
@@ -397,9 +466,15 @@ You should see "Hello, List Multi Selection!"
397
466
 
398
467
  ![Glimmer DSL for Opal Hello List Multi Selection](images/glimmer-dsl-opal-hello-list-multi-selection.png)
399
468
 
400
- ### Hello, Browser!
469
+ #### Hello, Browser!
470
+
471
+ Add the following require statement to `app/assets/javascripts/application.rb`
472
+
473
+ ```ruby
474
+ require 'samples/hello/hello_browser'
475
+ ```
401
476
 
402
- Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
477
+ Or add the Glimmer code directly if you prefer to play around with it:
403
478
 
404
479
  ```ruby
405
480
  include Glimmer
@@ -413,7 +488,7 @@ shell {
413
488
  ```
414
489
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
415
490
 
416
- ![Glimmer DSL for Opal Hello Browser](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-browser.png)
491
+ ![Glimmer DSL for SWT Hello Browser](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-browser.png)
417
492
 
418
493
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
419
494
 
@@ -428,6 +503,870 @@ You should see "Hello, Browser!"
428
503
 
429
504
  ![Glimmer DSL for Opal Hello Browser](images/glimmer-dsl-opal-hello-browser.png)
430
505
 
506
+ #### Hello, Tab!
507
+
508
+ Add the following require statement to `app/assets/javascripts/application.rb`
509
+
510
+ ```ruby
511
+ require 'samples/hello/hello_tab'
512
+ ```
513
+
514
+ Or add the Glimmer code directly if you prefer to play around with it:
515
+
516
+ ```ruby
517
+ class HelloTab
518
+ include Glimmer
519
+ def launch
520
+ shell {
521
+ text "Hello, Tab!"
522
+ tab_folder {
523
+ tab_item {
524
+ text "English"
525
+ label {
526
+ text "Hello, World!"
527
+ }
528
+ }
529
+ tab_item {
530
+ text "French"
531
+ label {
532
+ text "Bonjour, Univers!"
533
+ }
534
+ }
535
+ }
536
+ }.open
537
+ end
538
+ end
539
+
540
+ HelloTab.new.launch
541
+ ```
542
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
543
+
544
+ ![Glimmer DSL for SWT Hello Tab English](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-tab-english.png)
545
+ ![Glimmer DSL for SWT Hello Tab French](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-tab-french.png)
546
+
547
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
548
+
549
+ Start the Rails server:
550
+ ```
551
+ rails s
552
+ ```
553
+
554
+ Visit `http://localhost:3000`
555
+
556
+ You should see "Hello, Tab!"
557
+
558
+ ![Glimmer DSL for Opal Hello Tab English](images/glimmer-dsl-opal-hello-tab-english.png)
559
+ ![Glimmer DSL for Opal Hello Tab French](images/glimmer-dsl-opal-hello-tab-french.png)
560
+
561
+ ### Elaborate Samples
562
+
563
+ #### Login
564
+
565
+ Add the following require statement to `app/assets/javascripts/application.rb`
566
+
567
+ ```ruby
568
+ require 'samples/elaborate/login'
569
+ ```
570
+
571
+ Or add the Glimmer code directly if you prefer to play around with it:
572
+
573
+ ```ruby
574
+ require "observer"
575
+
576
+ #Presents login screen data
577
+ class LoginPresenter
578
+
579
+ attr_accessor :user_name
580
+ attr_accessor :password
581
+ attr_accessor :status
582
+
583
+ def initialize
584
+ @user_name = ""
585
+ @password = ""
586
+ @status = "Logged Out"
587
+ end
588
+
589
+ def status=(status)
590
+ @status = status
591
+
592
+ #TODO add feature to bind dependent properties to master property (2017-07-25 nested data binding)
593
+ notify_observers("logged_in")
594
+ notify_observers("logged_out")
595
+ end
596
+
597
+ def logged_in
598
+ self.status == "Logged In"
599
+ end
600
+
601
+ def logged_out
602
+ !self.logged_in
603
+ end
604
+
605
+ def login
606
+ self.status = "Logged In"
607
+ end
608
+
609
+ def logout
610
+ self.user_name = ""
611
+ self.password = ""
612
+ self.status = "Logged Out"
613
+ end
614
+
615
+ end
616
+
617
+ #Login screen
618
+ class Login
619
+ include Glimmer
620
+
621
+ def launch
622
+ presenter = LoginPresenter.new
623
+ @shell = shell {
624
+ text "Login"
625
+ composite {
626
+ grid_layout 2, false #two columns with differing widths
627
+
628
+ label { text "Username:" } # goes in column 1
629
+ text { # goes in column 2
630
+ text bind(presenter, :user_name)
631
+ enabled bind(presenter, :logged_out)
632
+ }
633
+
634
+ label { text "Password:" }
635
+ text(:password, :border) {
636
+ text bind(presenter, :password)
637
+ enabled bind(presenter, :logged_out)
638
+ }
639
+
640
+ label { text "Status:" }
641
+ label { text bind(presenter, :status) }
642
+
643
+ button {
644
+ text "Login"
645
+ enabled bind(presenter, :logged_out)
646
+ on_widget_selected { presenter.login }
647
+ }
648
+
649
+ button {
650
+ text "Logout"
651
+ enabled bind(presenter, :logged_in)
652
+ on_widget_selected { presenter.logout }
653
+ }
654
+ }
655
+ }
656
+ @shell.open
657
+ end
658
+ end
659
+
660
+ Login.new.launch
661
+ ```
662
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
663
+
664
+ ![Glimmer DSL for SWT Login](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login.png)
665
+ ![Glimmer DSL for SWT Login Filled In](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login-filled-in.png)
666
+ ![Glimmer DSL for SWT Login Logged In](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login-logged-in.png)
667
+
668
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
669
+
670
+ Start the Rails server:
671
+ ```
672
+ rails s
673
+ ```
674
+
675
+ Visit `http://localhost:3000`
676
+
677
+ You should see "Login" dialog
678
+
679
+ ![Glimmer DSL for Opal Login](images/glimmer-dsl-opal-login.png)
680
+ ![Glimmer DSL for Opal Login Filled In](images/glimmer-dsl-opal-login-filled-in.png)
681
+ ![Glimmer DSL for Opal Login Logged In](images/glimmer-dsl-opal-login-logged-in.png)
682
+
683
+ #### Tic Tac Toe
684
+
685
+ Add the following require statement to `app/assets/javascripts/application.rb`
686
+
687
+ ```ruby
688
+ require 'samples/elaborate/tic_tac_toe'
689
+ ```
690
+
691
+ Or add the Glimmer code directly if you prefer to play around with it:
692
+
693
+ ```ruby
694
+ class TicTacToe
695
+ class Cell
696
+ EMPTY = ""
697
+ attr_accessor :sign, :empty
698
+
699
+ def initialize
700
+ reset
701
+ end
702
+
703
+ def mark(sign)
704
+ self.sign = sign
705
+ end
706
+
707
+ def reset
708
+ self.sign = EMPTY
709
+ end
710
+
711
+ def sign=(sign_symbol)
712
+ @sign = sign_symbol
713
+ self.empty = sign == EMPTY
714
+ end
715
+
716
+ def marked
717
+ !empty
718
+ end
719
+ end
720
+ end
721
+
722
+ class TicTacToe
723
+ class Board
724
+ DRAW = :draw
725
+ IN_PROGRESS = :in_progress
726
+ WIN = :win
727
+ attr :winning_sign
728
+ attr_accessor :game_status
729
+
730
+ def initialize
731
+ @sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
732
+ build_grid
733
+ @winning_sign = Cell::EMPTY
734
+ @game_status = IN_PROGRESS
735
+ end
736
+
737
+ #row and column numbers are 1-based
738
+ def mark(row, column)
739
+ self[row, column].mark(current_sign)
740
+ game_over? #updates winning sign
741
+ end
742
+
743
+ def current_sign
744
+ @current_sign = @sign_state_machine[@current_sign]
745
+ end
746
+
747
+ def [](row, column)
748
+ @grid[row-1][column-1]
749
+ end
750
+
751
+ def game_over?
752
+ win? or draw?
753
+ end
754
+
755
+ def win?
756
+ win = (row_win? or column_win? or diagonal_win?)
757
+ self.game_status=WIN if win
758
+ win
759
+ end
760
+
761
+ def reset
762
+ (1..3).each do |row|
763
+ (1..3).each do |column|
764
+ self[row, column].reset
765
+ end
766
+ end
767
+ @winning_sign = Cell::EMPTY
768
+ @current_sign = nil
769
+ self.game_status=IN_PROGRESS
770
+ end
771
+
772
+ private
773
+
774
+ def build_grid
775
+ @grid = []
776
+ 3.times do |row_index| #0-based
777
+ @grid << []
778
+ 3.times { @grid[row_index] << Cell.new }
779
+ end
780
+ end
781
+
782
+ def row_win?
783
+ (1..3).each do |row|
784
+ if row_has_same_sign(row)
785
+ @winning_sign = self[row, 1].sign
786
+ return true
787
+ end
788
+ end
789
+ false
790
+ end
791
+
792
+ def column_win?
793
+ (1..3).each do |column|
794
+ if column_has_same_sign(column)
795
+ @winning_sign = self[1, column].sign
796
+ return true
797
+ end
798
+ end
799
+ false
800
+ end
801
+
802
+ #needs refactoring if we ever decide to make the board size dynamic
803
+ def diagonal_win?
804
+ if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
805
+ @winning_sign = self[1, 1].sign
806
+ return true
807
+ end
808
+ if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
809
+ @winning_sign = self[3, 1].sign
810
+ return true
811
+ end
812
+ false
813
+ end
814
+
815
+ def draw?
816
+ @board_full = true
817
+ 3.times do |x|
818
+ 3.times do |y|
819
+ @board_full = false if self[x, y].empty
820
+ end
821
+ end
822
+ self.game_status = DRAW if @board_full
823
+ @board_full
824
+ end
825
+
826
+ def row_has_same_sign(number)
827
+ row_sign = self[number, 1].sign
828
+ [2, 3].each do |column|
829
+ return false unless row_sign == (self[number, column].sign)
830
+ end
831
+ true if self[number, 1].marked
832
+ end
833
+
834
+ def column_has_same_sign(number)
835
+ column_sign = self[1, number].sign
836
+ [2, 3].each do |row|
837
+ return false unless column_sign == (self[row, number].sign)
838
+ end
839
+ true if self[1, number].marked
840
+ end
841
+
842
+ end
843
+ end
844
+
845
+ class TicTacToe
846
+ include Glimmer
847
+
848
+ def initialize
849
+ @tic_tac_toe_board = Board.new
850
+ @shell = shell {
851
+ text "Tic-Tac-Toe"
852
+ composite {
853
+ grid_layout 3, true
854
+ (1..3).each { |row|
855
+ (1..3).each { |column|
856
+ button {
857
+ layout_data :fill, :fill, true, true
858
+ text bind(@tic_tac_toe_board[row, column], :sign)
859
+ enabled bind(@tic_tac_toe_board[row, column], :empty)
860
+ on_widget_selected {
861
+ @tic_tac_toe_board.mark(row, column)
862
+ }
863
+ }
864
+ }
865
+ }
866
+ }
867
+ }
868
+ observe(@tic_tac_toe_board, :game_status) { |game_status|
869
+ display_win_message if game_status == Board::WIN
870
+ display_draw_message if game_status == Board::DRAW
871
+ }
872
+ end
873
+
874
+ def display_win_message
875
+ display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
876
+ end
877
+
878
+ def display_draw_message
879
+ display_game_over_message("Draw!")
880
+ end
881
+
882
+ def display_game_over_message(message_text)
883
+ message_box(@shell) {
884
+ text 'Game Over'
885
+ message message_text
886
+ }.open
887
+ @tic_tac_toe_board.reset
888
+ end
889
+
890
+ def open
891
+ @shell.open
892
+ end
893
+ end
894
+
895
+ TicTacToe.new.open
896
+ ```
897
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
898
+
899
+ ![Glimmer DSL for SWT Tic Tac Toe](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe.png)
900
+ ![Glimmer DSL for SWT Tic Tac Toe In Progress](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe-in-progress.png)
901
+ ![Glimmer DSL for SWT Tic Tac Toe Game Over](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe-game-over.png)
902
+
903
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
904
+
905
+ Start the Rails server:
906
+ ```
907
+ rails s
908
+ ```
909
+
910
+ Visit `http://localhost:3000`
911
+
912
+ You should see "Tic Tac Toe"
913
+
914
+ ![Glimmer DSL for Opal Tic Tac Toe](images/glimmer-dsl-opal-tic-tac-toe.png)
915
+ ![Glimmer DSL for Opal Tic Tac Toe In Progress](images/glimmer-dsl-opal-tic-tac-toe-in-progress.png)
916
+ ![Glimmer DSL for Opal Tic Tac Toe Game Over](images/glimmer-dsl-opal-tic-tac-toe-game-over.png)
917
+
918
+ #### Contact Manager
919
+
920
+ Add the following require statement to `app/assets/javascripts/application.rb`
921
+
922
+ ```ruby
923
+ require 'samples/elaborate/contact_manager'
924
+ ```
925
+
926
+ Or add the Glimmer code directly if you prefer to play around with it:
927
+
928
+ ```ruby
929
+ class ContactManager
930
+ class Contact
931
+ attr_accessor :first_name, :last_name, :email
932
+
933
+ def initialize(attribute_map)
934
+ @first_name = attribute_map[:first_name]
935
+ @last_name = attribute_map[:last_name]
936
+ @email = attribute_map[:email]
937
+ end
938
+ end
939
+ end
940
+
941
+ class ContactManager
942
+ class ContactRepository
943
+ NAMES_FIRST = %w[
944
+ Liam
945
+ Noah
946
+ William
947
+ James
948
+ Oliver
949
+ Benjamin
950
+ Elijah
951
+ Lucas
952
+ Mason
953
+ Logan
954
+ Alexander
955
+ Ethan
956
+ Jacob
957
+ Michael
958
+ Daniel
959
+ Henry
960
+ Jackson
961
+ Sebastian
962
+ Aiden
963
+ Matthew
964
+ Samuel
965
+ David
966
+ Joseph
967
+ Carter
968
+ Owen
969
+ Wyatt
970
+ John
971
+ Jack
972
+ Luke
973
+ Jayden
974
+ Dylan
975
+ Grayson
976
+ Levi
977
+ Isaac
978
+ Gabriel
979
+ Julian
980
+ Mateo
981
+ Anthony
982
+ Jaxon
983
+ Lincoln
984
+ Joshua
985
+ Christopher
986
+ Andrew
987
+ Theodore
988
+ Caleb
989
+ Ryan
990
+ Asher
991
+ Nathan
992
+ Thomas
993
+ Leo
994
+ Isaiah
995
+ Charles
996
+ Josiah
997
+ Hudson
998
+ Christian
999
+ Hunter
1000
+ Connor
1001
+ Eli
1002
+ Ezra
1003
+ Aaron
1004
+ Landon
1005
+ Adrian
1006
+ Jonathan
1007
+ Nolan
1008
+ Jeremiah
1009
+ Easton
1010
+ Elias
1011
+ Colton
1012
+ Cameron
1013
+ Carson
1014
+ Robert
1015
+ Angel
1016
+ Maverick
1017
+ Nicholas
1018
+ Dominic
1019
+ Jaxson
1020
+ Greyson
1021
+ Adam
1022
+ Ian
1023
+ Austin
1024
+ Santiago
1025
+ Jordan
1026
+ Cooper
1027
+ Brayden
1028
+ Roman
1029
+ Evan
1030
+ Ezekiel
1031
+ Xaviar
1032
+ Jose
1033
+ Jace
1034
+ Jameson
1035
+ Leonardo
1036
+ Axel
1037
+ Everett
1038
+ Kayden
1039
+ Miles
1040
+ Sawyer
1041
+ Jason
1042
+ Emma
1043
+ Olivia
1044
+ Ava
1045
+ Isabella
1046
+ Sophia
1047
+ Charlotte
1048
+ Mia
1049
+ Amelia
1050
+ Harper
1051
+ Evelyn
1052
+ Abigail
1053
+ Emily
1054
+ Elizabeth
1055
+ Mila
1056
+ Ella
1057
+ Avery
1058
+ Sofia
1059
+ Camila
1060
+ Aria
1061
+ Scarlett
1062
+ Victoria
1063
+ Madison
1064
+ Luna
1065
+ Grace
1066
+ Chloe
1067
+ Penelope
1068
+ Layla
1069
+ Riley
1070
+ Zoey
1071
+ Nora
1072
+ Lily
1073
+ Eleanor
1074
+ Hannah
1075
+ Lillian
1076
+ Addison
1077
+ Aubrey
1078
+ Ellie
1079
+ Stella
1080
+ Natalie
1081
+ Zoe
1082
+ Leah
1083
+ Hazel
1084
+ Violet
1085
+ Aurora
1086
+ Savannah
1087
+ Audrey
1088
+ Brooklyn
1089
+ Bella
1090
+ Claire
1091
+ Skylar
1092
+ Lucy
1093
+ Paisley
1094
+ Everly
1095
+ Anna
1096
+ Caroline
1097
+ Nova
1098
+ Genesis
1099
+ Emilia
1100
+ Kennedy
1101
+ Samantha
1102
+ Maya
1103
+ Willow
1104
+ Kinsley
1105
+ Naomi
1106
+ Aaliyah
1107
+ Elena
1108
+ Sarah
1109
+ Ariana
1110
+ Allison
1111
+ Gabriella
1112
+ Alice
1113
+ Madelyn
1114
+ Cora
1115
+ Ruby
1116
+ Eva
1117
+ Serenity
1118
+ Autumn
1119
+ Adeline
1120
+ Hailey
1121
+ Gianna
1122
+ Valentina
1123
+ Isla
1124
+ Eliana
1125
+ Quinn
1126
+ Nevaeh
1127
+ Ivy
1128
+ Sadie
1129
+ Piper
1130
+ Lydia
1131
+ Alexa
1132
+ Josephine
1133
+ Emery
1134
+ Julia
1135
+ Delilah
1136
+ Arianna
1137
+ Vivian
1138
+ Kaylee
1139
+ Sophie
1140
+ Brielle
1141
+ Madeline
1142
+ ]
1143
+ NAMES_LAST = %w[
1144
+ Smith
1145
+ Johnson
1146
+ Williams
1147
+ Brown
1148
+ Jones
1149
+ Miller
1150
+ Davis
1151
+ Wilson
1152
+ Anderson
1153
+ Taylor
1154
+ ]
1155
+ def initialize(contacts = nil)
1156
+ @contacts = contacts || 1000.times.map do |n|
1157
+ random_first_name_index = (rand*NAMES_FIRST.size).to_i
1158
+ random_last_name_index = (rand*NAMES_LAST.size).to_i
1159
+ first_name = NAMES_FIRST[random_first_name_index]
1160
+ last_name = NAMES_LAST[random_last_name_index]
1161
+ email = "#{first_name}@#{last_name}.com".downcase
1162
+ Contact.new(
1163
+ first_name: first_name,
1164
+ last_name: last_name,
1165
+ email: email
1166
+ )
1167
+ end
1168
+ end
1169
+
1170
+ def find(attribute_filter_map)
1171
+ @contacts.find_all do |contact|
1172
+ match = true
1173
+ attribute_filter_map.keys.each do |attribute_name|
1174
+ contact_value = contact.send(attribute_name).downcase
1175
+ filter_value = attribute_filter_map[attribute_name].downcase
1176
+ match = false unless contact_value.match(filter_value)
1177
+ end
1178
+ match
1179
+ end
1180
+ end
1181
+ end
1182
+ end
1183
+
1184
+ class ContactManager
1185
+ class ContactManagerPresenter
1186
+ attr_accessor :results
1187
+ @@contact_attributes = [:first_name, :last_name, :email]
1188
+ @@contact_attributes.each {|attribute_name| attr_accessor attribute_name}
1189
+
1190
+ def initialize(contact_repository = nil)
1191
+ @contact_repository = contact_repository || ContactRepository.new
1192
+ @results = []
1193
+ end
1194
+
1195
+ def list
1196
+ self.results = @contact_repository.find({})
1197
+ end
1198
+
1199
+ def find
1200
+ filter_map = {}
1201
+ @@contact_attributes.each do |attribute_name|
1202
+ filter_map[attribute_name] = self.send(attribute_name) if self.send(attribute_name)
1203
+ end
1204
+ self.results = @contact_repository.find(filter_map)
1205
+ @sort_attribute_name = nil
1206
+ @sort_direction_ascending = nil
1207
+ end
1208
+
1209
+ def toggle_sort(attribute_name)
1210
+ @sort_attribute_name = attribute_name
1211
+ @sort_direction_ascending = !@sort_direction_ascending
1212
+ sorted_results = self.results.sort_by {|contact| contact.send(attribute_name).downcase}
1213
+ sorted_results = sorted_results.reverse unless @sort_direction_ascending
1214
+ self.results = sorted_results
1215
+ end
1216
+ end
1217
+ end
1218
+
1219
+ class ContactManager
1220
+ include Glimmer
1221
+
1222
+ def initialize
1223
+ @contact_manager_presenter = ContactManagerPresenter.new
1224
+ @contact_manager_presenter.list
1225
+ end
1226
+
1227
+ def launch
1228
+ shell {
1229
+ text "Contact Manager"
1230
+ composite {
1231
+ composite {
1232
+ grid_layout 2, false
1233
+ label {text "First &Name: "}
1234
+ text {
1235
+ text bind(@contact_manager_presenter, :first_name)
1236
+ on_key_pressed {|key_event|
1237
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
1238
+ }
1239
+ }
1240
+ label {text "&Last Name: "}
1241
+ text {
1242
+ text bind(@contact_manager_presenter, :last_name)
1243
+ on_key_pressed {|key_event|
1244
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
1245
+ }
1246
+ }
1247
+ label {text "&Email: "}
1248
+ text {
1249
+ text bind(@contact_manager_presenter, :email)
1250
+ on_key_pressed {|key_event|
1251
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
1252
+ }
1253
+ }
1254
+ composite {
1255
+ grid_layout 2, false
1256
+ button {
1257
+ text "&Find"
1258
+ on_widget_selected {
1259
+ @contact_manager_presenter.find
1260
+ }
1261
+ }
1262
+ button {
1263
+ text "&List All"
1264
+ on_widget_selected {
1265
+ @contact_manager_presenter.list
1266
+ }
1267
+ }
1268
+ }
1269
+ }
1270
+
1271
+ table(:multi) { |table_proxy|
1272
+ layout_data {
1273
+ horizontal_alignment :fill
1274
+ vertical_alignment :fill
1275
+ grab_excess_horizontal_space true
1276
+ grab_excess_vertical_space true
1277
+ height_hint 200
1278
+ }
1279
+ table_column {
1280
+ text "First Name"
1281
+ width 80
1282
+ on_widget_selected {
1283
+ @contact_manager_presenter.toggle_sort(:first_name)
1284
+ }
1285
+ }
1286
+ table_column {
1287
+ text "Last Name"
1288
+ width 80
1289
+ on_widget_selected {
1290
+ @contact_manager_presenter.toggle_sort(:last_name)
1291
+ }
1292
+ }
1293
+ table_column {
1294
+ text "Email"
1295
+ width 200
1296
+ on_widget_selected {
1297
+ @contact_manager_presenter.toggle_sort(:email)
1298
+ }
1299
+ }
1300
+ items bind(@contact_manager_presenter, :results), column_properties(:first_name, :last_name, :email)
1301
+ on_mouse_down { |event|
1302
+ table_proxy.edit_table_item(event.table_item, event.column_index)
1303
+ }
1304
+ }
1305
+ }
1306
+ }.open
1307
+ end
1308
+ end
1309
+
1310
+ ContactManager.new.launch
1311
+
1312
+ ```
1313
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1314
+
1315
+ Glimmer DSL for SWT Contact Manager
1316
+
1317
+ ![Glimmer DSL for SWT Contact Manager](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager.png)
1318
+
1319
+ Glimmer DSL for SWT Contact Manager Find
1320
+
1321
+ ![Glimmer DSL for SWT Contact Manager Find](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-find.png)
1322
+
1323
+ Glimmer DSL for SWT Contact Manager Edit Started
1324
+
1325
+ ![Glimmer DSL for SWT Contact Manager Edit Started](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-edit-started.png)
1326
+
1327
+ Glimmer DSL for SWT Contact Manager Edit In Progress
1328
+
1329
+ ![Glimmer DSL for SWT Contact Manager Edit In Progress](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-edit-in-progress.png)
1330
+
1331
+ Glimmer DSL for SWT Contact Manager Edit Done
1332
+
1333
+ ![Glimmer DSL for SWT Contact Manager Edit Done](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-contact-manager-edit-done.png)
1334
+
1335
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
1336
+
1337
+ Start the Rails server:
1338
+ ```
1339
+ rails s
1340
+ ```
1341
+
1342
+ Visit `http://localhost:3000`
1343
+
1344
+ You should see "Tic Tac Toe"
1345
+
1346
+ Glimmer DSL for Opal Contact Manager
1347
+
1348
+ ![Glimmer DSL for Opal Contact Manager](images/glimmer-dsl-opal-contact-manager.png)
1349
+
1350
+ Glimmer DSL for Opal Contact Manager Find
1351
+
1352
+ ![Glimmer DSL for Opal Contact Manager Find](images/glimmer-dsl-opal-contact-manager-find.png)
1353
+
1354
+ Glimmer DSL for Opal Contact Manager Edit Started
1355
+
1356
+ ![Glimmer DSL for Opal Contact Manager Edit Started](images/glimmer-dsl-opal-contact-manager-edit-started.png)
1357
+
1358
+ Glimmer DSL for Opal Contact Manager Edit In Progress
1359
+
1360
+ ![Glimmer DSL for Opal Contact Manager Edit In Progress](images/glimmer-dsl-opal-contact-manager-edit-in-progress.png)
1361
+
1362
+ Glimmer DSL for Opal Contact Manager Edit Done
1363
+
1364
+ ![Glimmer DSL for Opal Contact Manager Edit Done](images/glimmer-dsl-opal-contact-manager-edit-done.png)
1365
+
1366
+ ## Sample App
1367
+
1368
+ [https://github.com/AndyObtiva/sample-glimmer-dsl-opal-rails5-app](https://github.com/AndyObtiva/sample-glimmer-dsl-opal-rails5-app)
1369
+
431
1370
  ## Help
432
1371
 
433
1372
  ### Issues
@@ -462,5 +1401,11 @@ These features have been suggested. You might see them in a future version of Gl
462
1401
 
463
1402
  ## License
464
1403
 
465
- Copyright (c) 2020 Andy Maleh.
466
- See LICENSE.txt for further details.
1404
+ [MIT](https://opensource.org/licenses/MIT)
1405
+
1406
+ Copyright (c) 2020 - Andy Maleh.
1407
+ See [LICENSE.txt](LICENSE.txt) for further details.
1408
+
1409
+ --
1410
+
1411
+ [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 />](https://github.com/AndyObtiva/glimmer) Built for [Glimmer](https://github.com/AndyObtiva/glimmer) (Ruby Desktop Development GUI Library).