glimmer-dsl-opal 0.0.5 → 0.1.0

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 (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).