glimmer-dsl-opal 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4c1b8623cfb624fda19e969ff546ad75a41d32331c9c5c3cabd267a74c96b62
4
- data.tar.gz: 4b84ff762bbc5cecc3eefbf4e0dbd7f95501658523751e2a2936405974a662a6
3
+ metadata.gz: '009ae1a27f92b9fe4ae8d28374761c84a8a46add536c37b49c67aba167a121b7'
4
+ data.tar.gz: baf143fe8365b8a3164eaf74adc4a3df720521557003d0507f09580f0da9b6b3
5
5
  SHA512:
6
- metadata.gz: da478774923d89f49c1fbc050f9234f24a728781dddc7f38a1790795efdf5f1d9228982859e6027fd4e90d3ad61d8254275df4882a9453c61f0bbfcf16c7e089
7
- data.tar.gz: f8a46956d0caf08f7ab94bb183e02131acd808f4e17d084d961e15c79ea044c9dc16cb20a436e94ea63a26446cc6ce6b5467878634c04960a8464b38ee26666d
6
+ metadata.gz: 81014168a1822232725770564b6f8a4522f08a4e93db72c4986966deaeac28eaffe7674f9446d7abf2d5a3a6056eec38a7f12508c72f751734bd8dc6356fdc2c
7
+ data.tar.gz: 800d13580d55f8c1255a68b7c07f6c4e7bdfb9308d3a41b14e44e94b50dd66056c9e437df38f73f2d04643633937cd0a99edba8a1ed174194cf8ce0be25328bf
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.14.0
4
+
5
+ - Initial Net::HTTP support for get and post_form
6
+ - Added "Weather" elaborate sample (minus multi-threaded refetches)
7
+ - Updated Hello, Button!, Hello, Combo!, and Hello, Computed! from Glimmer DSL for SWT
8
+
3
9
  ## 0.13.0
4
10
 
5
11
  - Support Shine data-binding syntax in custom widgets
data/README.md CHANGED
@@ -1,4 +1,4 @@
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.13.0 (Pure Ruby Web GUI)
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.14.0 (Pure Ruby Web GUI)
2
2
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-opal.svg)](http://badge.fury.io/rb/glimmer-dsl-opal)
3
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)
4
4
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  Use in one of two ways:
10
10
  - **Direct:** build the GUI of web apps with the same friendly desktop GUI Ruby syntax as [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt), thus requiring a lot less code than web technologies that is in pure Ruby and avoiding opaque web concepts like 'render' and 'reactive'. No HTML/JS/CSS skills are even required. Web designers may be involved with CSS styling only if needed.
11
- - **Adapter:** auto-webify [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps (i.e. apps built with [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)) via [Opal](https://opalrb.com/) on [Rails](https://rubyonrails.org/) without changing a line of code. Just insert them as a single require statement in a Rails app, and BOOM! They're running on the web! Apps may then optionally be custom-styled for the web by web designers with standard CSS if needed.
11
+ - **Adapter:** auto-webify [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps (i.e. apps built with [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)) via [Opal](https://opalrb.com/) on [Rails](https://rubyonrails.org/) without changing a line of GUI code. Just insert them as a single require statement in a Rails app, and BOOM! They're running on the web! Apps may then optionally be custom-styled for the web by web designers with standard CSS if needed.
12
12
 
13
13
  Glimmer DSL for Opal successfully reuses the entire [Glimmer](https://github.com/AndyObtiva/glimmer) core DSL engine in [Opal Ruby](https://opalrb.com/) inside a web browser, and as such inherits the full range of Glimmer desktop [data-binding](https://github.com/AndyObtiva/glimmer#data-binding) capabilities for the web (including Shine syntax using `<=>` and `<=` for bidirectional [two-way] and unidirectional [one-way] data-binding respectively).
14
14
 
@@ -103,7 +103,7 @@ shell {
103
103
 
104
104
  ![Glimmer DSL for SWT Hello Table](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-table.png)
105
105
 
106
- **Hello, Table! (same code) running on the web via Opal on Rails (using the [glimmer-dsl-opal](https://rubygems.org/gems/glimmer-dsl-opal) gem):**
106
+ **Hello, Table! (same GUI code) running on the web via Opal on Rails (using the [glimmer-dsl-opal](https://rubygems.org/gems/glimmer-dsl-opal) gem):**
107
107
 
108
108
  ![Glimmer DSL for Opal Hello Table](images/glimmer-dsl-opal-hello-table.png)
109
109
 
@@ -141,7 +141,7 @@ Hello, Table! Game Booked
141
141
 
142
142
  NOTE: Glimmer DSL for Opal is an alpha project. Please help make better by contributing, adopting for small or low risk projects, and providing feedback. It is still an early alpha, so the more feedback and issues you report the better.
143
143
 
144
- **Alpha Version** 0.13.0 only supports bare-minimum capabilities for the included [samples](https://github.com/AndyObtiva/glimmer-dsl-opal#samples) (originally written for [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt))
144
+ **Alpha Version** 0.14.0 only supports bare-minimum capabilities for the included [samples](https://github.com/AndyObtiva/glimmer-dsl-opal#samples) (originally written for [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt))
145
145
 
146
146
  Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
147
147
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
@@ -151,7 +151,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
151
151
 
152
152
  ## Table of Contents
153
153
 
154
- - [Glimmer DSL for Opal 0.13.0 (Pure Ruby Web GUI)](#-glimmer-dsl-for-opal-0130-pure-ruby-web-gui)
154
+ - [Glimmer DSL for Opal 0.14.0 (Pure Ruby Web GUI)](#-glimmer-dsl-for-opal-0140-pure-ruby-web-gui)
155
155
  - [Principles](#principles)
156
156
  - [Background](#background)
157
157
  - [Pre-requisites](#pre-requisites)
@@ -184,6 +184,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
184
184
  - [Login](#login)
185
185
  - [Tic Tac Toe](#tic-tac-toe)
186
186
  - [Contact Manager](#contact-manager)
187
+ - [Weather](#weather)
187
188
  - [External Samples](#external-samples)
188
189
  - [Glimmer Calculator](#glimmer-calculator)
189
190
  - [Glimmer Supporting Libraries](#glimmer-supporting-libraries)
@@ -205,7 +206,6 @@ Please keep in mind this is a live list of innovative ideas, some of which have
205
206
  - **HTML is for creating documents not interactive applications**. As such, software engineers can avoid it and focus on creating web applications more productively with Glimmer DSL for Opal in pure Ruby instead (just like they do in desktop development) while content creators and web designers can be the ones responsible for creating HTML documents for web content purposes only as HTML was originally intended. That way, Glimmer web GUI is used and embedded in web pages when providing users with applications while the rest of the web pages are maintained by non-engineers as pure HTML. This achieves a correct separation of responsibilities and better productivity and maintainability.
206
207
  - **Approximate styles by developers via the Glimmer GUI DSL. Perfect styles by designers via pure CSS**. Developers can simply build GUI with approximate styling similar to desktop GUI and mockups without worrying about pixel-perfect aesthetics. Web designers can take styling further with pure CSS since every HTML element auto-generated by Glimmer DSL for Opal has a predictable ID and CSS class. This achieves a proper separation of responsibilities between developers and designers.
207
208
  - **Web servers are used just like servers in traditional client/server architecture**, meaning they simply provide RMI services to enable centralizing some of the application logic and data in the cloud to make available everywhere and enable data-sharing with others.
208
- - **Everybody In!** All JS frameworks sadly suffer from very major software design handicaps because of trying to ensure data security, so you end up with a very strict separation between server data and client data, making your head spin and worrying more about hackers and attackers than serving users. Try again! Thanks to the principle of Everybody In, Glimmer DSL for Opal apps have a very unique software architecture that revolves around the idea of multi-tenancy. Basically, every user gets their own server-side real-estate, that is a fully-secure-and-independent server-side instance that has its own user database, so hackers are not only intentionally allowed in, they are WELCOMED! As such, instead of protecting all users' data with an iron fist over a shared server/database (a terribly insecure architecture no matter how profilerate), you simply provide each user their own fully-independent server/client real-estate, thus be able to focus on serving them in the best way possible by writing code that is so simple it is just like desktop application code, but living in the Cloud on the Web. In summary, just code web as if you're on the desktop and be happy!
209
209
  - **Forget Routers!** Glimmer DSL for Opal supports auto-routing of custom shells (windows), which are opened as separate tabs in a web browser with automatically generated routes and bookmarkable URLs.
210
210
 
211
211
  ## Background
@@ -252,7 +252,7 @@ Add the following to `Gemfile`:
252
252
  gem 'opal-rails', '~> 1.1.2'
253
253
  gem 'opal-async', '~> 1.2.0'
254
254
  gem 'opal-jquery', '~> 0.4.4'
255
- gem 'glimmer-dsl-opal', '~> 0.13.0'
255
+ gem 'glimmer-dsl-opal', '~> 0.14.0'
256
256
  gem 'glimmer-dsl-xml', '~> 1.2.0', require: false
257
257
  gem 'glimmer-dsl-css', '~> 1.2.0', require: false
258
258
 
@@ -441,48 +441,50 @@ require 'glimmer-dsl-opal/samples/hello/hello_combo'
441
441
  Or add the Glimmer code directly if you prefer to play around with it:
442
442
 
443
443
  ```ruby
444
- class Person
445
- attr_accessor :country, :country_options
446
-
447
- def initialize
448
- self.country_options = ['', 'Canada', 'US', 'Mexico']
449
- reset_country
450
- end
451
-
452
- def reset_country
453
- self.country = 'Canada'
444
+ class HelloCombo
445
+ class Person
446
+ attr_accessor :country, :country_options
447
+
448
+ def initialize
449
+ self.country_options = ['', 'Canada', 'US', 'Mexico']
450
+ reset_country!
451
+ end
452
+
453
+ def reset_country!
454
+ self.country = 'Canada'
455
+ end
454
456
  end
455
- end
456
457
 
457
- class HelloCombo
458
- include Glimmer
458
+ include Glimmer::UI::CustomShell
459
459
 
460
- def launch
461
- person = Person.new
462
-
460
+ before_body {
461
+ @person = Person.new
462
+ }
463
+
464
+ body {
463
465
  shell {
464
466
  row_layout(:vertical) {
465
- pack false
467
+ fill true
466
468
  }
467
469
 
468
470
  text 'Hello, Combo!'
469
471
 
470
472
  combo(:read_only) {
471
- selection <=> [person, :country]
473
+ selection <=> [@person, :country] # also binds to country_options by convention
472
474
  }
473
475
 
474
476
  button {
475
477
  text 'Reset Selection'
476
478
 
477
479
  on_widget_selected do
478
- person.reset_country
480
+ @person.reset_country!
479
481
  end
480
482
  }
481
- }.open
482
- end
483
+ }
484
+ }
483
485
  end
484
486
 
485
- HelloCombo.new.launch
487
+ HelloCombo.launch
486
488
  ```
487
489
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
488
490
 
@@ -534,17 +536,17 @@ class HelloComputed
534
536
  end
535
537
  end
536
538
 
537
- include Glimmer
539
+ include Glimmer::UI::CustomShell
538
540
 
539
- def initialize
541
+ before_body {
540
542
  @contact = Contact.new(
541
543
  first_name: 'Barry',
542
544
  last_name: 'McKibbin',
543
545
  year_of_birth: 1985
544
546
  )
545
- end
547
+ }
546
548
 
547
- def launch
549
+ body {
548
550
  shell {
549
551
  text 'Hello, Computed!'
550
552
 
@@ -601,11 +603,11 @@ class HelloComputed
601
603
  }
602
604
  }
603
605
  }
604
- }.open
605
- end
606
+ }
607
+ }
606
608
  end
607
609
 
608
- HelloComputed.new.launch
610
+ HelloComputed.launch
609
611
  ```
610
612
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
611
613
 
@@ -633,44 +635,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
633
635
  require 'glimmer-dsl-opal/samples/hello/hello_list_single_selection'
634
636
  ```
635
637
 
636
- Or add the Glimmer code directly if you prefer to play around with it:
637
-
638
- ```ruby
639
- class Person
640
- attr_accessor :country, :country_options
641
-
642
- def initialize
643
- self.country_options=["", "Canada", "US", "Mexico"]
644
- self.country = "Canada"
645
- end
646
-
647
- def reset_country
648
- self.country = "Canada"
649
- end
650
- end
651
-
652
- class HelloListSingleSelection
653
- include Glimmer
654
- def launch
655
- person = Person.new
656
- shell {
657
- composite {
658
- list {
659
- selection bind(person, :country)
660
- }
661
- button {
662
- text "Reset"
663
- on_widget_selected do
664
- person.reset_country
665
- end
666
- }
667
- }
668
- }.open
669
- end
670
- end
671
-
672
- HelloListSingleSelection.new.launch
673
- ```
674
638
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
675
639
 
676
640
  ![Glimmer DSL for SWT Hello List Single Selection](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-list-single-selection.png)
@@ -696,63 +660,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
696
660
  require 'glimmer-dsl-opal/samples/hello/hello_list_multi_selection'
697
661
  ```
698
662
 
699
- Or add the Glimmer code directly if you prefer to play around with it:
700
-
701
- ```ruby
702
- class HelloListMultiSelection
703
- class Person
704
- attr_accessor :provinces, :provinces_options
705
-
706
- def initialize
707
- self.provinces_options = [
708
- '',
709
- 'Alberta',
710
- 'British Columbia',
711
- 'Manitoba',
712
- 'New Brunswick',
713
- 'Newfoundland and Labrador',
714
- 'Northwest Territories',
715
- 'Nova Scotia',
716
- 'Nunavut',
717
- 'Ontario',
718
- 'Prince Edward Island',
719
- 'Quebec',
720
- 'Saskatchewan',
721
- 'Yukon'
722
- ]
723
- reset_provinces
724
- end
725
-
726
- def reset_provinces
727
- self.provinces = ['Quebec', 'Manitoba', 'Alberta']
728
- end
729
- end
730
-
731
- include Glimmer
732
-
733
- def launch
734
- person = Person.new
735
-
736
- shell {
737
- grid_layout
738
-
739
- text 'Hello, List Multi Selection!'
740
-
741
- list(:multi) {
742
- selection bind(person, :provinces)
743
- }
744
-
745
- button {
746
- text 'Reset Selections To Default Values'
747
-
748
- on_widget_selected { person.reset_provinces }
749
- }
750
- }.open
751
- end
752
- end
753
-
754
- HelloListMultiSelection.new.launch
755
- ```
756
663
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
757
664
 
758
665
  ![Glimmer DSL for SWT Hello List Multi Selection](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-list-multi-selection.png)
@@ -778,18 +685,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
778
685
  require 'glimmer-dsl-opal/samples/hello/hello_browser'
779
686
  ```
780
687
 
781
- Or add the Glimmer code directly if you prefer to play around with it:
782
-
783
- ```ruby
784
- include Glimmer
785
-
786
- shell {
787
- minimum_size 1024, 860
788
- browser {
789
- url 'http://brightonresort.com/about'
790
- }
791
- }.open
792
- ```
793
688
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
794
689
 
795
690
  ![Glimmer DSL for SWT Hello Browser](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-browser.png)
@@ -894,7 +789,7 @@ class GreetingLabel
894
789
  after_body {
895
790
  return if colors.nil?
896
791
 
897
- Thread.new {
792
+ Thread.new { # imported from Glimmer DSL for SWT. In Opal, avoid Threads and sleep to avoid blocking GUI.
898
793
  colors.cycle { |color|
899
794
  async_exec {
900
795
  self.color = color
@@ -909,7 +804,7 @@ class GreetingLabel
909
804
  label(swt_style) {
910
805
  text "#{greeting}, #{name}!"
911
806
  font @font
912
- foreground bind(self, :color)
807
+ foreground <=> [self, :color]
913
808
  }
914
809
  }
915
810
 
@@ -1131,103 +1026,14 @@ You should see "Hello, Custom Widget!"
1131
1026
 
1132
1027
  #### Hello, Radio!
1133
1028
 
1029
+ This is the low level way of using `radio`
1030
+
1134
1031
  Add the following require statement to `app/assets/javascripts/application.rb`
1135
1032
 
1136
1033
  ```ruby
1137
1034
  require 'glimmer-dsl-opal/samples/hello/hello_radio'
1138
1035
  ```
1139
1036
 
1140
- Or add the Glimmer code directly if you prefer to play around with it:
1141
-
1142
- ```ruby
1143
- class HelloRadio
1144
- class Person
1145
- attr_accessor :male, :female, :child, :teen, :adult, :senior
1146
-
1147
- def initialize
1148
- reset
1149
- end
1150
-
1151
- def reset
1152
- self.male = nil
1153
- self.female = nil
1154
- self.child = nil
1155
- self.teen = nil
1156
- self.adult = true
1157
- self.senior = nil
1158
- end
1159
- end
1160
-
1161
- include Glimmer
1162
-
1163
- def launch
1164
- person = Person.new
1165
-
1166
- shell {
1167
- text 'Hello, Radio!'
1168
- row_layout :vertical
1169
-
1170
- label {
1171
- text 'Gender:'
1172
- font style: :bold
1173
- }
1174
-
1175
- composite {
1176
- row_layout
1177
-
1178
- radio {
1179
- text 'Male'
1180
- selection bind(person, :male)
1181
- }
1182
-
1183
- radio {
1184
- text 'Female'
1185
- selection bind(person, :female)
1186
- }
1187
- }
1188
-
1189
- label {
1190
- text 'Age Group:'
1191
- font style: :bold
1192
- }
1193
-
1194
- composite {
1195
- row_layout
1196
-
1197
- radio {
1198
- text 'Child'
1199
- selection bind(person, :child)
1200
- }
1201
-
1202
- radio {
1203
- text 'Teen'
1204
- selection bind(person, :teen)
1205
- }
1206
-
1207
- radio {
1208
- text 'Adult'
1209
- selection bind(person, :adult)
1210
- }
1211
-
1212
- radio {
1213
- text 'Senior'
1214
- selection bind(person, :senior)
1215
- }
1216
- }
1217
-
1218
- button {
1219
- text 'Reset'
1220
-
1221
- on_widget_selected do
1222
- person.reset
1223
- end
1224
- }
1225
- }.open
1226
- end
1227
- end
1228
-
1229
- HelloRadio.new.launch
1230
- ```
1231
1037
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1232
1038
 
1233
1039
  ![Glimmer DSL for SWT Hello Radio](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-radio.png)
@@ -1247,6 +1053,8 @@ You should see "Hello, Radio!"
1247
1053
 
1248
1054
  #### Hello, Radio Group!
1249
1055
 
1056
+ `radio_group` is a level higher than `radio` in abstraction. It generates a group of radio widgets based on available options in model `attribute_options` methods.
1057
+
1250
1058
  Add the following require statement to `app/assets/javascripts/application.rb`
1251
1059
 
1252
1060
  ```ruby
@@ -1261,7 +1069,7 @@ class HelloRadioGroup
1261
1069
  attr_accessor :gender, :age_group
1262
1070
 
1263
1071
  def initialize
1264
- reset
1072
+ reset!
1265
1073
  end
1266
1074
 
1267
1075
  def gender_options
@@ -1272,17 +1080,19 @@ class HelloRadioGroup
1272
1080
  ['Child', 'Teen', 'Adult', 'Senior']
1273
1081
  end
1274
1082
 
1275
- def reset
1083
+ def reset!
1276
1084
  self.gender = nil
1277
1085
  self.age_group = 'Adult'
1278
1086
  end
1279
1087
  end
1280
1088
 
1281
- include Glimmer
1089
+ include Glimmer::UI::CustomShell
1282
1090
 
1283
- def launch
1284
- person = Person.new
1285
-
1091
+ before_body {
1092
+ @person = Person.new
1093
+ }
1094
+
1095
+ body {
1286
1096
  shell {
1287
1097
  text 'Hello, Radio Group!'
1288
1098
  row_layout :vertical
@@ -1294,7 +1104,7 @@ class HelloRadioGroup
1294
1104
 
1295
1105
  radio_group {
1296
1106
  row_layout :horizontal
1297
- selection <=> [person, :gender]
1107
+ selection <=> [@person, :gender]
1298
1108
  }
1299
1109
 
1300
1110
  label {
@@ -1304,21 +1114,21 @@ class HelloRadioGroup
1304
1114
 
1305
1115
  radio_group {
1306
1116
  row_layout :horizontal
1307
- selection <=> [person, :age_group]
1117
+ selection <=> [@person, :age_group]
1308
1118
  }
1309
1119
 
1310
1120
  button {
1311
1121
  text 'Reset'
1312
1122
 
1313
1123
  on_widget_selected do
1314
- person.reset
1124
+ @person.reset!
1315
1125
  end
1316
1126
  }
1317
- }.open
1318
- end
1127
+ }
1128
+ }
1319
1129
  end
1320
1130
 
1321
- HelloRadioGroup.new.launch
1131
+ HelloRadioGroup.launch
1322
1132
  ```
1323
1133
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1324
1134
 
@@ -1339,99 +1149,14 @@ You should see "Hello, Radio Group!"
1339
1149
 
1340
1150
  #### Hello, Group!
1341
1151
 
1152
+ Not to be confused with `radio_group` or `checkbox_group`, `group` simply groups arbitrary widgets together and adds a title header above them.
1153
+
1342
1154
  Add the following require statement to `app/assets/javascripts/application.rb`
1343
1155
 
1344
1156
  ```ruby
1345
1157
  require 'glimmer-dsl-opal/samples/hello/hello_group'
1346
1158
  ```
1347
1159
 
1348
- Or add the Glimmer code directly if you prefer to play around with it:
1349
-
1350
- ```ruby
1351
- class HelloGroup
1352
- class Person
1353
- attr_accessor :male, :female, :child, :teen, :adult, :senior
1354
-
1355
- def initialize
1356
- reset
1357
- end
1358
-
1359
- def reset
1360
- self.male = nil
1361
- self.female = nil
1362
- self.child = nil
1363
- self.teen = nil
1364
- self.adult = true
1365
- self.senior = nil
1366
- end
1367
- end
1368
-
1369
- include Glimmer
1370
-
1371
- def launch
1372
- person = Person.new
1373
-
1374
- shell {
1375
- text 'Hello, Group!'
1376
- row_layout :vertical
1377
-
1378
- group {
1379
- row_layout
1380
-
1381
- text 'Gender'
1382
- font style: :bold
1383
-
1384
- radio {
1385
- text 'Male'
1386
- selection <=> [person, :male]
1387
- }
1388
-
1389
- radio {
1390
- text 'Female'
1391
- selection <=> [person, :female]
1392
- }
1393
- }
1394
-
1395
- group {
1396
- row_layout
1397
-
1398
- text 'Age Group'
1399
- font style: :bold
1400
-
1401
- radio {
1402
- text 'Child'
1403
- selection bind(person, :child)
1404
- }
1405
-
1406
- radio {
1407
- text 'Teen'
1408
- selection bind(person, :teen)
1409
- }
1410
-
1411
- radio {
1412
- text 'Adult'
1413
- selection bind(person, :adult)
1414
- }
1415
-
1416
- radio {
1417
- text 'Senior'
1418
- selection bind(person, :senior)
1419
- }
1420
- }
1421
-
1422
- button {
1423
- text 'Reset'
1424
-
1425
- on_widget_selected do
1426
- person.reset
1427
- end
1428
- }
1429
- }.open
1430
- end
1431
- end
1432
-
1433
- HelloGroup.new.launch
1434
- ```
1435
1160
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1436
1161
 
1437
1162
  ![Glimmer DSL for SWT Hello Group](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-group.png)
@@ -1451,80 +1176,14 @@ You should see "Hello, Group!"
1451
1176
 
1452
1177
  #### Hello, Checkbox!
1453
1178
 
1179
+ This is the low level way of using `checkbox`
1180
+
1454
1181
  Add the following require statement to `app/assets/javascripts/application.rb`
1455
1182
 
1456
1183
  ```ruby
1457
1184
  require 'glimmer-dsl-opal/samples/hello/hello_checkbox'
1458
1185
  ```
1459
1186
 
1460
- Or add the Glimmer code directly if you prefer to play around with it:
1461
-
1462
- ```ruby
1463
- class HelloCheckbox
1464
- class Person
1465
- attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing
1466
-
1467
- def initialize
1468
- reset_activities
1469
- end
1470
-
1471
- def reset_activities
1472
- self.skiing = false
1473
- self.snowboarding = true
1474
- self.snowmobiling = false
1475
- self.snowshoeing = false
1476
- end
1477
- end
1478
-
1479
- include Glimmer
1480
-
1481
- def launch
1482
- person = Person.new
1483
-
1484
- shell {
1485
- text 'Hello, Checkbox!'
1486
- row_layout :vertical
1487
-
1488
- label {
1489
- text 'Check all snow activities you are interested in:'
1490
- font style: :bold
1491
- }
1492
-
1493
- composite {
1494
- checkbox {
1495
- text 'Skiing'
1496
- selection bind(person, :skiing)
1497
- }
1498
-
1499
- checkbox {
1500
- text 'Snowboarding'
1501
- selection bind(person, :snowboarding)
1502
- }
1503
-
1504
- checkbox {
1505
- text 'Snowmobiling'
1506
- selection bind(person, :snowmobiling)
1507
- }
1508
-
1509
- checkbox {
1510
- text 'Snowshoeing'
1511
- selection bind(person, :snowshoeing)
1512
- }
1513
- }
1514
-
1515
- button {
1516
- text 'Reset Activities'
1517
-
1518
- on_widget_selected do
1519
- person.reset_activities
1520
- end
1521
- }
1522
- }.open
1523
- end
1524
- end
1525
-
1526
- HelloCheckbox.new.launch
1527
- ```
1528
1187
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1529
1188
 
1530
1189
  ![Glimmer DSL for SWT Hello Checkbox](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-checkbox.png)
@@ -1544,6 +1203,8 @@ You should see "Hello, Checkbox!"
1544
1203
 
1545
1204
  #### Hello, Checkbox Group!
1546
1205
 
1206
+ `checkbox_group` is a level higher than `checkbox` in abstraction. It generates a group of checkbox widgets based on available options in model `attribute_options` methods.
1207
+
1547
1208
  Add the following require statement to `app/assets/javascripts/application.rb`
1548
1209
 
1549
1210
  ```ruby
@@ -1570,11 +1231,13 @@ class HelloCheckboxGroup
1570
1231
  end
1571
1232
  end
1572
1233
 
1573
- include Glimmer
1234
+ include Glimmer::UI::CustomShell
1574
1235
 
1575
- def launch
1576
- person = Person.new
1577
-
1236
+ before_body {
1237
+ @person = Person.new
1238
+ }
1239
+
1240
+ body {
1578
1241
  shell {
1579
1242
  text 'Hello, Checkbox Group!'
1580
1243
  row_layout :vertical
@@ -1585,21 +1248,21 @@ class HelloCheckboxGroup
1585
1248
  }
1586
1249
 
1587
1250
  checkbox_group {
1588
- selection <=> [person, :activities]
1251
+ selection <=> [@person, :activities]
1589
1252
  }
1590
1253
 
1591
1254
  button {
1592
1255
  text 'Reset Activities'
1593
1256
 
1594
1257
  on_widget_selected do
1595
- person.reset_activities
1258
+ @person.reset_activities
1596
1259
  end
1597
1260
  }
1598
- }.open
1599
- end
1261
+ }
1262
+ }
1600
1263
  end
1601
1264
 
1602
- HelloCheckboxGroup.new.launch
1265
+ HelloCheckboxGroup.launch
1603
1266
  ```
1604
1267
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1605
1268
 
@@ -1607,354 +1270,50 @@ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObt
1607
1270
 
1608
1271
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
1609
1272
 
1610
- Start the Rails server:
1611
- ```
1612
- rails s
1613
- ```
1614
-
1615
- Visit `http://localhost:3000`
1616
-
1617
- You should see "Hello, Checkbox Group!"
1618
-
1619
- ![Glimmer DSL for Opal Hello Checkbox Group](images/glimmer-dsl-opal-hello-checkbox-group.png)
1620
-
1621
- #### Hello, Date Time!
1622
-
1623
- Add the following require statement to `app/assets/javascripts/application.rb`
1624
-
1625
- ```ruby
1626
- require 'glimmer-dsl-opal/samples/hello/hello_date_time'
1627
- ```
1628
-
1629
- Or add the Glimmer code directly if you prefer to play around with it:
1630
-
1631
- ```ruby
1632
- class HelloDateTime
1633
- class Person
1634
- attr_accessor :date_of_birth
1635
- end
1636
-
1637
- include Glimmer
1638
-
1639
- def launch
1640
- person = Person.new
1641
- person.date_of_birth = DateTime.new(2013, 7, 12, 18, 37, 23)
1642
-
1643
- shell {
1644
- row_layout :vertical
1645
-
1646
- text 'Hello, Date Time!'
1647
- minimum_size 180, 180
1648
-
1649
- label {
1650
- text 'Date of Birth'
1651
- font height: 16, style: :bold
1652
- }
1653
-
1654
- date { # alias for date_time(:date)
1655
- date_time bind(person, :date_of_birth)
1656
- }
1657
-
1658
- date_drop_down { # alias for date_time(:date, :drop_down)
1659
- date_time bind(person, :date_of_birth)
1660
- }
1661
-
1662
- time { # alias for date_time(:time)
1663
- date_time bind(person, :date_of_birth)
1664
- }
1665
-
1666
- calendar { # alias for date_time(:calendar)
1667
- date_time bind(person, :date_of_birth)
1668
- }
1669
- }.open
1670
- end
1671
- end
1672
-
1673
- HelloDateTime.new.launch
1674
- ```
1675
-
1676
- Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1677
-
1678
- ![Glimmer DSL for SWT Hello Checkbox Group](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-date-time.png)
1679
-
1680
- Glimmer app on the web (using `glimmer-dsl-opal` gem):
1681
-
1682
- Start the Rails server:
1683
- ```
1684
- rails s
1685
- ```
1686
-
1687
- Visit `http://localhost:3000`
1688
-
1689
- You should see "Hello, Date Time!"
1690
-
1691
- ![Glimmer DSL for Opal Hello Date Time](images/glimmer-dsl-opal-hello-date-time.png)
1692
-
1693
- #### Hello, Table!
1694
-
1695
- Note: This [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) sample has near-complete support, but is missing table context menus at the moment.
1696
-
1697
- Add the following require statement to `app/assets/javascripts/application.rb`
1698
-
1699
- ```ruby
1700
- require 'glimmer-dsl-opal/samples/hello/hello_table'
1701
- ```
1702
-
1703
- Or add the Glimmer code directly if you prefer to play around with it:
1704
-
1705
- ```ruby
1706
- class HelloTable
1707
- class BaseballGame
1708
- class << self
1709
- attr_accessor :selected_game
1710
-
1711
- def all_playoff_games
1712
- @all_playoff_games ||= {
1713
- 'NLDS' => [
1714
- new(Time.new(2037, 10, 6, 12, 0), 'Chicago Cubs', 'Milwaukee Brewers', 'Free Bobblehead'),
1715
- new(Time.new(2037, 10, 7, 12, 0), 'Chicago Cubs', 'Milwaukee Brewers'),
1716
- new(Time.new(2037, 10, 8, 12, 0), 'Milwaukee Brewers', 'Chicago Cubs'),
1717
- new(Time.new(2037, 10, 9, 12, 0), 'Milwaukee Brewers', 'Chicago Cubs'),
1718
- new(Time.new(2037, 10, 10, 12, 0), 'Milwaukee Brewers', 'Chicago Cubs', 'Free Umbrella'),
1719
- new(Time.new(2037, 10, 6, 18, 0), 'Cincinnati Reds', 'St Louis Cardinals', 'Free Bobblehead'),
1720
- new(Time.new(2037, 10, 7, 18, 0), 'Cincinnati Reds', 'St Louis Cardinals'),
1721
- new(Time.new(2037, 10, 8, 18, 0), 'St Louis Cardinals', 'Cincinnati Reds'),
1722
- new(Time.new(2037, 10, 9, 18, 0), 'St Louis Cardinals', 'Cincinnati Reds'),
1723
- new(Time.new(2037, 10, 10, 18, 0), 'St Louis Cardinals', 'Cincinnati Reds', 'Free Umbrella'),
1724
- ],
1725
- 'ALDS' => [
1726
- new(Time.new(2037, 10, 6, 12, 0), 'New York Yankees', 'Boston Red Sox', 'Free Bobblehead'),
1727
- new(Time.new(2037, 10, 7, 12, 0), 'New York Yankees', 'Boston Red Sox'),
1728
- new(Time.new(2037, 10, 8, 12, 0), 'Boston Red Sox', 'New York Yankees'),
1729
- new(Time.new(2037, 10, 9, 12, 0), 'Boston Red Sox', 'New York Yankees'),
1730
- new(Time.new(2037, 10, 10, 12, 0), 'Boston Red Sox', 'New York Yankees', 'Free Umbrella'),
1731
- new(Time.new(2037, 10, 6, 18, 0), 'Houston Astros', 'Cleveland Indians', 'Free Bobblehead'),
1732
- new(Time.new(2037, 10, 7, 18, 0), 'Houston Astros', 'Cleveland Indians'),
1733
- new(Time.new(2037, 10, 8, 18, 0), 'Cleveland Indians', 'Houston Astros'),
1734
- new(Time.new(2037, 10, 9, 18, 0), 'Cleveland Indians', 'Houston Astros'),
1735
- new(Time.new(2037, 10, 10, 18, 0), 'Cleveland Indians', 'Houston Astros', 'Free Umbrella'),
1736
- ],
1737
- 'NLCS' => [
1738
- new(Time.new(2037, 10, 12, 12, 0), 'Chicago Cubs', 'Cincinnati Reds', 'Free Towel'),
1739
- new(Time.new(2037, 10, 13, 12, 0), 'Chicago Cubs', 'Cincinnati Reds'),
1740
- new(Time.new(2037, 10, 14, 12, 0), 'Cincinnati Reds', 'Chicago Cubs'),
1741
- new(Time.new(2037, 10, 15, 18, 0), 'Cincinnati Reds', 'Chicago Cubs'),
1742
- new(Time.new(2037, 10, 16, 18, 0), 'Cincinnati Reds', 'Chicago Cubs'),
1743
- new(Time.new(2037, 10, 17, 18, 0), 'Chicago Cubs', 'Cincinnati Reds'),
1744
- new(Time.new(2037, 10, 18, 12, 0), 'Chicago Cubs', 'Cincinnati Reds', 'Free Poncho'),
1745
- ],
1746
- 'ALCS' => [
1747
- new(Time.new(2037, 10, 12, 12, 0), 'Houston Astros', 'Boston Red Sox', 'Free Towel'),
1748
- new(Time.new(2037, 10, 13, 12, 0), 'Houston Astros', 'Boston Red Sox'),
1749
- new(Time.new(2037, 10, 14, 12, 0), 'Boston Red Sox', 'Houston Astros'),
1750
- new(Time.new(2037, 10, 15, 18, 0), 'Boston Red Sox', 'Houston Astros'),
1751
- new(Time.new(2037, 10, 16, 18, 0), 'Boston Red Sox', 'Houston Astros'),
1752
- new(Time.new(2037, 10, 17, 18, 0), 'Houston Astros', 'Boston Red Sox'),
1753
- new(Time.new(2037, 10, 18, 12, 0), 'Houston Astros', 'Boston Red Sox', 'Free Poncho'),
1754
- ],
1755
- 'World Series' => [
1756
- new(Time.new(2037, 10, 20, 18, 0), 'Chicago Cubs', 'Boston Red Sox', 'Free Baseball Cap'),
1757
- new(Time.new(2037, 10, 21, 18, 0), 'Chicago Cubs', 'Boston Red Sox'),
1758
- new(Time.new(2037, 10, 22, 18, 0), 'Boston Red Sox', 'Chicago Cubs'),
1759
- new(Time.new(2037, 10, 23, 18, 0), 'Boston Red Sox', 'Chicago Cubs'),
1760
- new(Time.new(2037, 10, 24, 18, 0), 'Boston Red Sox', 'Chicago Cubs'),
1761
- new(Time.new(2037, 10, 25, 18, 0), 'Chicago Cubs', 'Boston Red Sox'),
1762
- new(Time.new(2037, 10, 26, 18, 0), 'Chicago Cubs', 'Boston Red Sox', 'Free World Series Polo'),
1763
- ]
1764
- }
1765
- end
1766
-
1767
- def playoff_type
1768
- @playoff_type ||= 'World Series'
1769
- end
1770
-
1771
- def playoff_type=(new_playoff_type)
1772
- @playoff_type = new_playoff_type
1773
- self.schedule=(all_playoff_games[@playoff_type])
1774
- end
1775
-
1776
- def playoff_type_options
1777
- all_playoff_games.keys
1778
- end
1779
-
1780
- def schedule
1781
- @schedule ||= all_playoff_games[playoff_type]
1782
- end
1783
-
1784
- def schedule=(new_schedule)
1785
- @schedule = new_schedule
1786
- end
1787
- end
1788
-
1789
- include Glimmer
1790
- include Glimmer::DataBinding::ObservableModel
1791
-
1792
- TEAM_BALLPARKS = {
1793
- 'Boston Red Sox' => 'Fenway Park',
1794
- 'Chicago Cubs' => 'Wrigley Field',
1795
- 'Cincinnati Reds' => 'Great American Ball Park',
1796
- 'Cleveland Indians' => 'Progressive Field',
1797
- 'Houston Astros' => 'Minute Maid Park',
1798
- 'Milwaukee Brewers' => 'Miller Park',
1799
- 'New York Yankees' => 'Yankee Stadium',
1800
- 'St Louis Cardinals' => 'Busch Stadium',
1801
- }
1802
-
1803
- attr_accessor :date_time, :home_team, :away_team, :ballpark, :promotion
1804
-
1805
- def initialize(date_time, home_team, away_team, promotion = 'N/A')
1806
- self.date_time = date_time
1807
- self.home_team = home_team
1808
- self.away_team = away_team
1809
- self.promotion = promotion
1810
- observe(self, :date_time) do |new_value|
1811
- notify_observers(:game_date)
1812
- notify_observers(:game_time)
1813
- end
1814
- end
1815
-
1816
- def home_team=(home_team_value)
1817
- if home_team_value != away_team
1818
- @home_team = home_team_value
1819
- self.ballpark = TEAM_BALLPARKS[@home_team]
1820
- end
1821
- end
1822
-
1823
- def away_team=(away_team_value)
1824
- if away_team_value != home_team
1825
- @away_team = away_team_value
1826
- end
1827
- end
1828
-
1829
- def date
1830
- Date.new(date_time.year, date_time.month, date_time.day)
1831
- end
1832
-
1833
- def time
1834
- Time.new(0, 1, 1, date_time.hour, date_time.min, date_time.sec, '+00:00')
1835
- end
1836
-
1837
- def game_date
1838
- date_time.strftime("%m/%d/%Y")
1839
- end
1840
-
1841
- def game_time
1842
- date_time.strftime("%I:%M %p")
1843
- end
1844
-
1845
- def home_team_options
1846
- TEAM_BALLPARKS.keys
1847
- end
1848
-
1849
- def away_team_options
1850
- TEAM_BALLPARKS.keys
1851
- end
1852
-
1853
- def ballpark_options
1854
- [TEAM_BALLPARKS[@home_team], TEAM_BALLPARKS[@away_team]]
1855
- end
1856
-
1857
- def to_s
1858
- "#{home_team} vs #{away_team} at #{ballpark} on #{game_date} #{game_time}"
1859
- end
1860
-
1861
- def book!
1862
- "Thank you for booking #{to_s}"
1863
- end
1864
- end
1865
-
1866
- include Glimmer
1867
-
1868
- def launch
1869
- shell {
1870
- grid_layout
1871
-
1872
- text 'Hello, Table!'
1873
-
1874
- label {
1875
- layout_data :center, :center, true, false
1876
-
1877
- text 'Baseball Playoff Schedule'
1878
- font height: 30, style: :bold
1879
- }
1880
-
1881
- combo(:read_only) {
1882
- layout_data :center, :center, true, false
1883
- selection bind(BaseballGame, :playoff_type)
1884
- font height: 16
1885
- }
1886
-
1887
- table(:editable) { |table_proxy|
1888
- layout_data :fill, :fill, true, true
1889
-
1890
- table_column {
1891
- text 'Game Date'
1892
- width 150
1893
- sort_property :date # ensure sorting by real date value (not `game_date` string specified in items below)
1894
- editor :date_drop_down, property: :date_time
1895
- }
1896
- table_column {
1897
- text 'Game Time'
1898
- width 150
1899
- sort_property :time # ensure sorting by real time value (not `game_time` string specified in items below)
1900
- editor :time, property: :date_time
1901
- }
1902
- table_column {
1903
- text 'Ballpark'
1904
- width 180
1905
- editor :none
1906
- }
1907
- table_column {
1908
- text 'Home Team'
1909
- width 150
1910
- editor :combo, :read_only # read_only is simply an SWT style passed to combo widget
1911
- }
1912
- table_column {
1913
- text 'Away Team'
1914
- width 150
1915
- editor :combo, :read_only # read_only is simply an SWT style passed to combo widget
1916
- }
1917
- table_column {
1918
- text 'Promotion'
1919
- width 150
1920
- # default text editor is used here
1921
- }
1922
-
1923
- # Data-bind table items (rows) to a model collection property, specifying column properties ordering per nested model
1924
- items bind(BaseballGame, :schedule), column_properties(:game_date, :game_time, :ballpark, :home_team, :away_team, :promotion)
1925
-
1926
- # Data-bind table selection
1927
- selection bind(BaseballGame, :selected_game)
1928
-
1929
- # Default initial sort property
1930
- sort_property :date
1931
-
1932
- # Sort by these additional properties after handling sort by the column the user clicked
1933
- additional_sort_properties :date, :time, :home_team, :away_team, :ballpark, :promotion
1934
- }
1935
-
1936
- button {
1937
- text 'Book Selected Game'
1938
- layout_data :center, :center, true, false
1939
- font height: 16
1940
- enabled bind(BaseballGame, :selected_game)
1941
-
1942
- on_widget_selected {
1943
- book_selected_game
1944
- }
1945
- }
1946
- }.open
1947
- end
1948
-
1949
- def book_selected_game
1950
- message_box {
1951
- text 'Baseball Game Booked!'
1952
- message BaseballGame.selected_game.book!
1953
- }.open
1954
- end
1955
- end
1956
-
1957
- HelloTable.new.launch
1273
+ Start the Rails server:
1274
+ ```
1275
+ rails s
1276
+ ```
1277
+
1278
+ Visit `http://localhost:3000`
1279
+
1280
+ You should see "Hello, Checkbox Group!"
1281
+
1282
+ ![Glimmer DSL for Opal Hello Checkbox Group](images/glimmer-dsl-opal-hello-checkbox-group.png)
1283
+
1284
+ #### Hello, Date Time!
1285
+
1286
+ Add the following require statement to `app/assets/javascripts/application.rb`
1287
+
1288
+ ```ruby
1289
+ require 'glimmer-dsl-opal/samples/hello/hello_date_time'
1290
+ ```
1291
+
1292
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1293
+
1294
+ ![Glimmer DSL for SWT Hello Checkbox Group](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-date-time.png)
1295
+
1296
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
1297
+
1298
+ Start the Rails server:
1299
+ ```
1300
+ rails s
1301
+ ```
1302
+
1303
+ Visit `http://localhost:3000`
1304
+
1305
+ You should see "Hello, Date Time!"
1306
+
1307
+ ![Glimmer DSL for Opal Hello Date Time](images/glimmer-dsl-opal-hello-date-time.png)
1308
+
1309
+ #### Hello, Table!
1310
+
1311
+ Note: This [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) sample has near-complete support, but is missing table context menus at the moment.
1312
+
1313
+ Add the following require statement to `app/assets/javascripts/application.rb`
1314
+
1315
+ ```ruby
1316
+ require 'glimmer-dsl-opal/samples/hello/hello_table'
1958
1317
  ```
1959
1318
 
1960
1319
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
@@ -2051,30 +1410,30 @@ Or add the Glimmer code directly if you prefer to play around with it:
2051
1410
 
2052
1411
  ```ruby
2053
1412
  class HelloButton
2054
- include Glimmer
1413
+ include Glimmer::UI::CustomShell
2055
1414
 
2056
1415
  attr_accessor :count
2057
1416
 
2058
- def initialize
1417
+ before_body {
2059
1418
  @count = 0
2060
- end
1419
+ }
2061
1420
 
2062
- def launch
1421
+ body {
2063
1422
  shell {
2064
1423
  text 'Hello, Button!'
2065
1424
 
2066
1425
  button {
2067
- text bind(self, :count) {|value| "Click To Increment: #{value} "}
1426
+ text <= [self, :count, on_read: ->(value) { "Click To Increment: #{value} " }]
2068
1427
 
2069
1428
  on_widget_selected {
2070
1429
  self.count += 1
2071
1430
  }
2072
1431
  }
2073
- }.open
2074
- end
1432
+ }
1433
+ }
2075
1434
  end
2076
1435
 
2077
- HelloButton.new.launch
1436
+ HelloButton.launch
2078
1437
  ```
2079
1438
 
2080
1439
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
@@ -2694,19 +2053,24 @@ class LoginPresenter
2694
2053
  end
2695
2054
 
2696
2055
  class Login
2697
- include Glimmer
2056
+ include Glimmer::UI::CustomShell
2057
+
2058
+ before_body {
2059
+ @presenter = LoginPresenter.new
2060
+ }
2698
2061
 
2699
- def launch
2700
- presenter = LoginPresenter.new
2701
- @shell = shell {
2062
+ body {
2063
+ shell {
2702
2064
  text "Login"
2065
+
2703
2066
  composite {
2704
2067
  grid_layout 2, false #two columns with differing widths
2705
2068
 
2706
2069
  label { text "Username:" } # goes in column 1
2707
2070
  @user_name_text = text { # goes in column 2
2708
- text bind(presenter, :user_name)
2709
- enabled bind(presenter, :logged_out)
2071
+ text <=> [@presenter, :user_name]
2072
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
2073
+
2710
2074
  on_key_pressed { |event|
2711
2075
  @password_text.set_focus if event.keyCode == swt(:cr)
2712
2076
  }
@@ -2714,43 +2078,47 @@ class Login
2714
2078
 
2715
2079
  label { text "Password:" }
2716
2080
  @password_text = text(:password, :border) {
2717
- text bind(presenter, :password)
2718
- enabled bind(presenter, :logged_out)
2081
+ text <=> [@presenter, :password]
2082
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
2083
+
2719
2084
  on_key_pressed { |event|
2720
- presenter.login if event.keyCode == swt(:cr)
2085
+ @presenter.login! if event.keyCode == swt(:cr)
2721
2086
  }
2722
2087
  }
2723
2088
 
2724
2089
  label { text "Status:" }
2725
- label { text bind(presenter, :status) }
2090
+ label { text <= [@presenter, :status] }
2726
2091
 
2727
2092
  button {
2728
2093
  text "Login"
2729
- enabled bind(presenter, :logged_out)
2730
- on_widget_selected { presenter.login }
2094
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
2095
+
2096
+ on_widget_selected { @presenter.login! }
2731
2097
  on_key_pressed { |event|
2732
- presenter.login if event.keyCode == swt(:cr)
2098
+ if event.keyCode == swt(:cr)
2099
+ @presenter.login!
2100
+ end
2733
2101
  }
2734
2102
  }
2735
2103
 
2736
2104
  button {
2737
2105
  text "Logout"
2738
- enabled bind(presenter, :logged_in)
2739
- on_widget_selected { presenter.logout }
2106
+ enabled <= [@presenter, :logged_in?, computed_by: :status]
2107
+
2108
+ on_widget_selected { @presenter.logout! }
2740
2109
  on_key_pressed { |event|
2741
2110
  if event.keyCode == swt(:cr)
2742
- presenter.logout
2111
+ @presenter.logout!
2743
2112
  @user_name_text.set_focus
2744
2113
  end
2745
2114
  }
2746
2115
  }
2747
2116
  }
2748
2117
  }
2749
- @shell.open
2750
- end
2118
+ }
2751
2119
  end
2752
2120
 
2753
- Login.new.launch
2121
+ Login.launch
2754
2122
  ```
2755
2123
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
2756
2124
 
@@ -2781,214 +2149,7 @@ Add the following require statement to `app/assets/javascripts/application.rb`
2781
2149
  require 'glimmer-dsl-opal/samples/elaborate/tic_tac_toe'
2782
2150
  ```
2783
2151
 
2784
- Or add the Glimmer code directly if you prefer to play around with it:
2785
-
2786
2152
  ```ruby
2787
- class TicTacToe
2788
- class Cell
2789
- EMPTY = ""
2790
- attr_accessor :sign, :empty
2791
-
2792
- def initialize
2793
- reset
2794
- end
2795
-
2796
- def mark(sign)
2797
- self.sign = sign
2798
- end
2799
-
2800
- def reset
2801
- self.sign = EMPTY
2802
- end
2803
-
2804
- def sign=(sign_symbol)
2805
- @sign = sign_symbol
2806
- self.empty = sign == EMPTY
2807
- end
2808
-
2809
- def marked
2810
- !empty
2811
- end
2812
- end
2813
- end
2814
-
2815
- class TicTacToe
2816
- class Board
2817
- DRAW = :draw
2818
- IN_PROGRESS = :in_progress
2819
- WIN = :win
2820
- attr :winning_sign
2821
- attr_accessor :game_status
2822
-
2823
- def initialize
2824
- @sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
2825
- build_grid
2826
- @winning_sign = Cell::EMPTY
2827
- @game_status = IN_PROGRESS
2828
- end
2829
-
2830
- #row and column numbers are 1-based
2831
- def mark(row, column)
2832
- self[row, column].mark(current_sign)
2833
- game_over? #updates winning sign
2834
- end
2835
-
2836
- def current_sign
2837
- @current_sign = @sign_state_machine[@current_sign]
2838
- end
2839
-
2840
- def [](row, column)
2841
- @grid[row-1][column-1]
2842
- end
2843
-
2844
- def game_over?
2845
- win? or draw?
2846
- end
2847
-
2848
- def win?
2849
- win = (row_win? or column_win? or diagonal_win?)
2850
- self.game_status=WIN if win
2851
- win
2852
- end
2853
-
2854
- def reset
2855
- (1..3).each do |row|
2856
- (1..3).each do |column|
2857
- self[row, column].reset
2858
- end
2859
- end
2860
- @winning_sign = Cell::EMPTY
2861
- @current_sign = nil
2862
- self.game_status=IN_PROGRESS
2863
- end
2864
-
2865
- private
2866
-
2867
- def build_grid
2868
- @grid = []
2869
- 3.times do |row_index| #0-based
2870
- @grid << []
2871
- 3.times { @grid[row_index] << Cell.new }
2872
- end
2873
- end
2874
-
2875
- def row_win?
2876
- (1..3).each do |row|
2877
- if row_has_same_sign(row)
2878
- @winning_sign = self[row, 1].sign
2879
- return true
2880
- end
2881
- end
2882
- false
2883
- end
2884
-
2885
- def column_win?
2886
- (1..3).each do |column|
2887
- if column_has_same_sign(column)
2888
- @winning_sign = self[1, column].sign
2889
- return true
2890
- end
2891
- end
2892
- false
2893
- end
2894
-
2895
- #needs refactoring if we ever decide to make the board size dynamic
2896
- def diagonal_win?
2897
- if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
2898
- @winning_sign = self[1, 1].sign
2899
- return true
2900
- end
2901
- if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
2902
- @winning_sign = self[3, 1].sign
2903
- return true
2904
- end
2905
- false
2906
- end
2907
-
2908
- def draw?
2909
- @board_full = true
2910
- 3.times do |x|
2911
- 3.times do |y|
2912
- @board_full = false if self[x, y].empty
2913
- end
2914
- end
2915
- self.game_status = DRAW if @board_full
2916
- @board_full
2917
- end
2918
-
2919
- def row_has_same_sign(number)
2920
- row_sign = self[number, 1].sign
2921
- [2, 3].each do |column|
2922
- return false unless row_sign == (self[number, column].sign)
2923
- end
2924
- true if self[number, 1].marked
2925
- end
2926
-
2927
- def column_has_same_sign(number)
2928
- column_sign = self[1, number].sign
2929
- [2, 3].each do |row|
2930
- return false unless column_sign == (self[row, number].sign)
2931
- end
2932
- true if self[1, number].marked
2933
- end
2934
-
2935
- end
2936
- end
2937
-
2938
- class TicTacToe
2939
- include Glimmer
2940
-
2941
- def initialize
2942
- @tic_tac_toe_board = Board.new
2943
- @shell = shell {
2944
- text "Tic-Tac-Toe"
2945
- minimum_size 150, 178
2946
- composite {
2947
- grid_layout 3, true
2948
- (1..3).each { |row|
2949
- (1..3).each { |column|
2950
- button {
2951
- layout_data :fill, :fill, true, true
2952
- text bind(@tic_tac_toe_board[row, column], :sign)
2953
- enabled bind(@tic_tac_toe_board[row, column], :empty)
2954
- font style: :bold, height: 20
2955
- on_widget_selected {
2956
- @tic_tac_toe_board.mark(row, column)
2957
- }
2958
- }
2959
- }
2960
- }
2961
- }
2962
- }
2963
- observe(@tic_tac_toe_board, :game_status) { |game_status|
2964
- display_win_message if game_status == Board::WIN
2965
- display_draw_message if game_status == Board::DRAW
2966
- }
2967
- end
2968
-
2969
- def display_win_message
2970
- display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
2971
- end
2972
-
2973
- def display_draw_message
2974
- display_game_over_message("Draw!")
2975
- end
2976
-
2977
- def display_game_over_message(message_text)
2978
- message_box(@shell) {
2979
- text 'Game Over'
2980
- message message_text
2981
- }.open
2982
- @tic_tac_toe_board.reset
2983
- end
2984
-
2985
- def open
2986
- @shell.open
2987
- end
2988
- end
2989
-
2990
- TicTacToe.new.open
2991
- ```
2992
2153
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
2993
2154
 
2994
2155
  ![Glimmer DSL for SWT Tic Tac Toe](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-tic-tac-toe.png)
@@ -3018,321 +2179,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
3018
2179
  require 'glimmer-dsl-opal/samples/elaborate/contact_manager'
3019
2180
  ```
3020
2181
 
3021
- Or add the Glimmer code directly if you prefer to play around with it:
3022
-
3023
- ```ruby
3024
- class ContactManager
3025
- class Contact
3026
- attr_accessor :first_name, :last_name, :email
3027
-
3028
- def initialize(attribute_map)
3029
- @first_name = attribute_map[:first_name]
3030
- @last_name = attribute_map[:last_name]
3031
- @email = attribute_map[:email]
3032
- end
3033
- end
3034
- end
3035
-
3036
- class ContactManager
3037
- class ContactRepository
3038
- NAMES_FIRST = %w[
3039
- Liam
3040
- Noah
3041
- William
3042
- James
3043
- Oliver
3044
- Benjamin
3045
- Elijah
3046
- Lucas
3047
- Mason
3048
- Logan
3049
- Alexander
3050
- Ethan
3051
- Jacob
3052
- Michael
3053
- Daniel
3054
- Henry
3055
- Jackson
3056
- Sebastian
3057
- Aiden
3058
- Matthew
3059
- Samuel
3060
- David
3061
- Joseph
3062
- Carter
3063
- Owen
3064
- Wyatt
3065
- John
3066
- Jack
3067
- Luke
3068
- Jayden
3069
- Dylan
3070
- Grayson
3071
- Levi
3072
- Isaac
3073
- Gabriel
3074
- Julian
3075
- Mateo
3076
- Anthony
3077
- Jaxon
3078
- Lincoln
3079
- Joshua
3080
- Christopher
3081
- Andrew
3082
- Theodore
3083
- Caleb
3084
- Ryan
3085
- Asher
3086
- Nathan
3087
- Thomas
3088
- Leo
3089
- Isaiah
3090
- Charles
3091
- Josiah
3092
- Hudson
3093
- Christian
3094
- Hunter
3095
- Connor
3096
- Eli
3097
- Ezra
3098
- Aaron
3099
- Landon
3100
- Adrian
3101
- Jonathan
3102
- Nolan
3103
- Jeremiah
3104
- Easton
3105
- Elias
3106
- Colton
3107
- Cameron
3108
- Carson
3109
- Robert
3110
- Angel
3111
- Maverick
3112
- Nicholas
3113
- Dominic
3114
- Jaxson
3115
- Greyson
3116
- Adam
3117
- Ian
3118
- Austin
3119
- Santiago
3120
- Jordan
3121
- Cooper
3122
- Brayden
3123
- Roman
3124
- Evan
3125
- Ezekiel
3126
- Xaviar
3127
- Jose
3128
- Jace
3129
- Jameson
3130
- Leonardo
3131
- Axel
3132
- Everett
3133
- Kayden
3134
- Miles
3135
- Sawyer
3136
- Jason
3137
- Emma
3138
- Olivia
3139
- ]
3140
- NAMES_LAST = %w[
3141
- Smith
3142
- Johnson
3143
- Williams
3144
- Brown
3145
- Jones
3146
- Miller
3147
- Davis
3148
- Wilson
3149
- Anderson
3150
- Taylor
3151
- ]
3152
- def initialize(contacts = nil)
3153
- @contacts = contacts || 100.times.map do |n|
3154
- random_first_name_index = (rand*NAMES_FIRST.size).to_i
3155
- random_last_name_index = (rand*NAMES_LAST.size).to_i
3156
- first_name = NAMES_FIRST[random_first_name_index]
3157
- last_name = NAMES_LAST[random_last_name_index]
3158
- email = "#{first_name}@#{last_name}.com".downcase
3159
- Contact.new(
3160
- first_name: first_name,
3161
- last_name: last_name,
3162
- email: email
3163
- )
3164
- end
3165
- end
3166
-
3167
- def find(attribute_filter_map)
3168
- @contacts.find_all do |contact|
3169
- match = true
3170
- attribute_filter_map.keys.each do |attribute_name|
3171
- contact_value = contact.send(attribute_name).downcase
3172
- filter_value = attribute_filter_map[attribute_name].downcase
3173
- match = false unless contact_value.match(filter_value)
3174
- end
3175
- match
3176
- end
3177
- end
3178
- end
3179
- end
3180
-
3181
- class ContactManager
3182
- class ContactManagerPresenter
3183
- attr_accessor :results
3184
- @@contact_attributes = [:first_name, :last_name, :email]
3185
- @@contact_attributes.each {|attribute_name| attr_accessor attribute_name}
3186
-
3187
- def initialize(contact_repository = nil)
3188
- @contact_repository = contact_repository || ContactRepository.new
3189
- @results = []
3190
- end
3191
-
3192
- def list
3193
- self.results = @contact_repository.find({})
3194
- end
3195
-
3196
- def find
3197
- filter_map = {}
3198
- @@contact_attributes.each do |attribute_name|
3199
- filter_map[attribute_name] = self.send(attribute_name) if self.send(attribute_name)
3200
- end
3201
- self.results = @contact_repository.find(filter_map)
3202
- @sort_attribute_name = nil
3203
- @sort_direction_ascending = nil
3204
- end
3205
-
3206
- def toggle_sort(attribute_name)
3207
- @sort_attribute_name = attribute_name
3208
- @sort_direction_ascending = !@sort_direction_ascending
3209
- sorted_results = self.results.sort_by {|contact| contact.send(attribute_name).downcase}
3210
- sorted_results = sorted_results.reverse unless @sort_direction_ascending
3211
- self.results = sorted_results
3212
- end
3213
- end
3214
- end
3215
-
3216
- class ContactManager
3217
- include Glimmer
3218
-
3219
- def initialize
3220
- @contact_manager_presenter = ContactManagerPresenter.new
3221
- @contact_manager_presenter.list
3222
- end
3223
-
3224
- def launch
3225
- shell {
3226
- text "Contact Manager"
3227
- composite {
3228
- group {
3229
- grid_layout(2, false) {
3230
- margin_width 0
3231
- margin_height 0
3232
- }
3233
- layout_data :fill, :center, true, false
3234
- text 'Lookup Contacts'
3235
- font height: 24
3236
-
3237
- label {
3238
- layout_data :right, :center, false, false
3239
- text "First &Name: "
3240
- font height: 16
3241
- }
3242
- text {
3243
- layout_data :fill, :center, true, false
3244
- text bind(@contact_manager_presenter, :first_name)
3245
- on_key_pressed {|key_event|
3246
- @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
3247
- }
3248
- }
3249
-
3250
- label {
3251
- layout_data :right, :center, false, false
3252
- text "&Last Name: "
3253
- font height: 16
3254
- }
3255
- text {
3256
- layout_data :fill, :center, true, false
3257
- text bind(@contact_manager_presenter, :last_name)
3258
- on_key_pressed {|key_event|
3259
- @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
3260
- }
3261
- }
3262
-
3263
- label {
3264
- layout_data :right, :center, false, false
3265
- text "&Email: "
3266
- font height: 16
3267
- }
3268
- text {
3269
- layout_data :fill, :center, true, false
3270
- text bind(@contact_manager_presenter, :email)
3271
- on_key_pressed {|key_event|
3272
- @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
3273
- }
3274
- }
3275
-
3276
- composite {
3277
- row_layout {
3278
- margin_width 0
3279
- margin_height 0
3280
- }
3281
- layout_data(:right, :center, false, false) {
3282
- horizontal_span 2
3283
- }
3284
-
3285
- button {
3286
- text "&Find"
3287
- on_widget_selected { @contact_manager_presenter.find }
3288
- on_key_pressed {|key_event|
3289
- @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
3290
- }
3291
- }
3292
-
3293
- button {
3294
- text "&List All"
3295
- on_widget_selected { @contact_manager_presenter.list }
3296
- on_key_pressed {|key_event|
3297
- @contact_manager_presenter.list if key_event.keyCode == swt(:cr)
3298
- }
3299
- }
3300
- }
3301
- }
3302
-
3303
- table(:multi) { |table_proxy|
3304
- layout_data {
3305
- horizontal_alignment :fill
3306
- vertical_alignment :fill
3307
- grab_excess_horizontal_space true
3308
- grab_excess_vertical_space true
3309
- height_hint 200
3310
- }
3311
- table_column {
3312
- text "First Name"
3313
- width 80
3314
- }
3315
- table_column {
3316
- text "Last Name"
3317
- width 80
3318
- }
3319
- table_column {
3320
- text "Email"
3321
- width 200
3322
- }
3323
- items bind(@contact_manager_presenter, :results),
3324
- column_properties(:first_name, :last_name, :email)
3325
- on_mouse_up { |event|
3326
- table_proxy.edit_table_item(event.table_item, event.column_index)
3327
- }
3328
- }
3329
- }
3330
- }.open
3331
- end
3332
- end
3333
-
3334
- ContactManager.new.launch
3335
- ```
3336
2182
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
3337
2183
 
3338
2184
  Glimmer DSL for SWT Contact Manager
@@ -3386,6 +2232,39 @@ Glimmer DSL for Opal Contact Manager Edit Done
3386
2232
 
3387
2233
  ![Glimmer DSL for Opal Contact Manager Edit Done](images/glimmer-dsl-opal-contact-manager-edit-done.png)
3388
2234
 
2235
+ #### Weather
2236
+
2237
+ Add the following require statement to `app/assets/javascripts/application.rb`
2238
+
2239
+ ```ruby
2240
+ require 'glimmer-dsl-opal/samples/elaborate/weather'
2241
+ ```
2242
+
2243
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
2244
+
2245
+ ![Weather Montreal C](https://github.com/AMaleh/glimmer-dsl-swt/raw/master/images/glimmer-weather-montreal-celsius.png)
2246
+
2247
+ ![Weather Montreal F](https://github.com/AMaleh/glimmer-dsl-swt/raw/master/images/glimmer-weather-montreal-fahrenheit.png)
2248
+
2249
+ ![Weather Atlanta F](https://github.com/AMaleh /glimmer-dsl-swt/raw/master/images/glimmer-weather-atlanta-fahrenheit.png)
2250
+
2251
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
2252
+
2253
+ Start the Rails server:
2254
+ ```
2255
+ rails s
2256
+ ```
2257
+
2258
+ Visit `http://localhost:3000`
2259
+
2260
+ You should see "Weather"
2261
+
2262
+ ![Opal Weather Montreal C](/images/glimmer-dsl-opal-weather-montreal-celsius.png)
2263
+
2264
+ ![Opal Weather Montreal F](/images/glimmer-dsl-opal-weather-montreal-fahrenheit.png)
2265
+
2266
+ ![Opal Weather Atlanta F](/images/glimmer-dsl-opal-weather-atlanta-fahrenheit.png)
2267
+
3389
2268
  ### External Samples
3390
2269
 
3391
2270
  #### Glimmer Calculator