glimmer-dsl-opal 0.12.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +179 -1296
  4. data/VERSION +1 -1
  5. data/app/controllers/glimmer/application_controller.rb +4 -0
  6. data/app/controllers/glimmer/image_paths_controller.rb +46 -0
  7. data/app/views/glimmer/image_paths/index.html.erb +1 -0
  8. data/{lib/glimmer-dsl-opal/samples/hello/hello_computed/contact.rb → config/routes.rb} +2 -20
  9. data/lib/glimmer-dsl-opal.rb +9 -3
  10. data/lib/glimmer-dsl-opal/ext/file.rb +25 -0
  11. data/lib/glimmer-dsl-opal/samples/elaborate/contact_manager.rb +0 -2
  12. data/lib/glimmer-dsl-opal/samples/elaborate/weather.rb +157 -0
  13. data/lib/glimmer-dsl-opal/samples/hello/hello_button.rb +7 -7
  14. data/lib/glimmer-dsl-opal/samples/hello/hello_checkbox.rb +16 -14
  15. data/lib/glimmer-dsl-opal/samples/hello/hello_checkbox_group.rb +14 -9
  16. data/lib/glimmer-dsl-opal/samples/hello/hello_combo.rb +24 -22
  17. data/lib/glimmer-dsl-opal/samples/hello/hello_computed.rb +27 -9
  18. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_shell.rb +15 -11
  19. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_widget.rb +1 -1
  20. data/lib/glimmer-dsl-opal/samples/hello/hello_radio.rb +18 -16
  21. data/lib/glimmer-dsl-opal/samples/hello/hello_radio_group.rb +17 -12
  22. data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +29 -21
  23. data/lib/glimmer-dsl-opal/samples/hello/hello_table/baseball_park.png +0 -0
  24. data/lib/glimmer/config.rb +11 -0
  25. data/lib/glimmer/dsl/opal/custom_widget_expression.rb +2 -2
  26. data/lib/glimmer/engine.rb +21 -0
  27. data/lib/glimmer/swt/composite_proxy.rb +34 -0
  28. data/lib/glimmer/swt/label_proxy.rb +15 -2
  29. data/lib/glimmer/swt/shell_proxy.rb +43 -0
  30. data/lib/glimmer/swt/table_item_proxy.rb +3 -0
  31. data/lib/glimmer/ui/custom_widget.rb +11 -2
  32. data/lib/net/http.rb +15 -6
  33. metadata +9 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a5328b8fd90117a9774e990256d5650ab8c15cd2745a29a466384261a1ead8a
4
- data.tar.gz: 2cfceae33c796f8aea84036dba490aa55ca94b5f7785c0c2f75dbc5e27535259
3
+ metadata.gz: f8072dfb955151aa374817c0f2f175bf9c7adfd115eca1bbd6df6c2c3b0725e4
4
+ data.tar.gz: 94304037d23dfe1719087fc93d3dc9056be7701f6fdac1044bfe2719e61e43b0
5
5
  SHA512:
6
- metadata.gz: e574405ade34c331a168a3dd2814112269dff90a72d58678f06246d94246e2a1c7bfc7e56163df61c2805fc58764a5da48687273ce98ce5c10cf27cf52fb5d51
7
- data.tar.gz: 297d37971d6939413fa2dd2535169b486a7c5332395f34b5d2f2c0697f41fce67c61c613dba83575b88e5904ef128354f5846e9e7e96963aa065f93050f2476d
6
+ metadata.gz: 7f85477240562b1eb7c3bfb3e147577bf6ac7f265c54b6d5acad7ae295a65b1226ff41798eb2a8d41804d2c56d999992f6e6e98b64bde1bed5708c52c46862f0
7
+ data.tar.gz: 847b86e900e53586993c74982b37d68ede27f399982188187de524dec31b1d5ffdf0ffc31694da38510060f3e5224c71acc7ca85d75fdef398a8e42c287ca666
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.16.0
4
+
5
+ - Support label widget background_image attribute
6
+ - Have File.expand_path support expanding paths even if they did not base off of __dir__ or __FILE__
7
+ - Custom specification of gems having image paths via server-side configuration in Glimmer::Config.gems_having_image_paths
8
+
9
+ ## 0.15.1
10
+
11
+ - Auto-expose images of gems that depend on glimmer-dsl-opal as downloadable asset links providing `/glimmer/image_paths` server call to obtain them
12
+ - Update Hello, Table! to work with image background
13
+
14
+ ## 0.14.0
15
+
16
+ - Initial Net::HTTP support for get and post_form
17
+ - Added "Weather" elaborate sample (minus multi-threaded refetches)
18
+ - Updated Hello, Button!, Hello, Combo!, and Hello, Computed! from Glimmer DSL for SWT
19
+
20
+ ## 0.13.0
21
+
22
+ - Support Shine data-binding syntax in custom widgets
23
+ - Update Hello, Checkbox!, Hello, Checkbox Group!, Hello, Radio! and Hello, Radio Group! to utilize Shine data-binding syntax from latest glimmer-dsl-swt
24
+
3
25
  ## 0.12.0
4
26
 
5
27
  - Support CustomShell.launch opening in the same window if no other shell is open or DisplayProxy.open_custom_shells_in_current_window = true is set
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.12.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.16.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,12 +8,14 @@
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
 
15
15
  #### Hello, Table! Sample
16
16
 
17
+ Code: [lib/glimmer-dsl-opal/samples/hello/hello_table.rb](lib/glimmer-dsl-opal/samples/hello/hello_table.rb)
18
+
17
19
  Glimmer GUI code from [glimmer-dsl-opal/samples/hello/hello_table.rb](lib/glimmer-dsl-opal/samples/hello/hello_table.rb):
18
20
 
19
21
  ```ruby
@@ -103,7 +105,7 @@ shell {
103
105
 
104
106
  ![Glimmer DSL for SWT Hello Table](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-table.png)
105
107
 
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):**
108
+ **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
109
 
108
110
  ![Glimmer DSL for Opal Hello Table](images/glimmer-dsl-opal-hello-table.png)
109
111
 
@@ -141,7 +143,7 @@ Hello, Table! Game Booked
141
143
 
142
144
  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
145
 
144
- **Alpha Version** 0.12.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))
146
+ **Alpha Version** 0.16.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
147
 
146
148
  Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
147
149
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
@@ -151,7 +153,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
151
153
 
152
154
  ## Table of Contents
153
155
 
154
- - [Glimmer DSL for Opal 0.12.0 (Pure Ruby Web GUI)](#-glimmer-dsl-for-opal-0110-pure-ruby-web-gui)
156
+ - [Glimmer DSL for Opal 0.16.0 (Pure Ruby Web GUI)](#-glimmer-dsl-for-opal-0160-pure-ruby-web-gui)
155
157
  - [Principles](#principles)
156
158
  - [Background](#background)
157
159
  - [Pre-requisites](#pre-requisites)
@@ -184,6 +186,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
184
186
  - [Login](#login)
185
187
  - [Tic Tac Toe](#tic-tac-toe)
186
188
  - [Contact Manager](#contact-manager)
189
+ - [Weather](#weather)
187
190
  - [External Samples](#external-samples)
188
191
  - [Glimmer Calculator](#glimmer-calculator)
189
192
  - [Glimmer Supporting Libraries](#glimmer-supporting-libraries)
@@ -205,7 +208,6 @@ Please keep in mind this is a live list of innovative ideas, some of which have
205
208
  - **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
209
  - **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
210
  - **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
211
  - **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
212
 
211
213
  ## Background
@@ -252,7 +254,7 @@ Add the following to `Gemfile`:
252
254
  gem 'opal-rails', '~> 1.1.2'
253
255
  gem 'opal-async', '~> 1.2.0'
254
256
  gem 'opal-jquery', '~> 0.4.4'
255
- gem 'glimmer-dsl-opal', '~> 0.12.0'
257
+ gem 'glimmer-dsl-opal', '~> 0.16.0'
256
258
  gem 'glimmer-dsl-xml', '~> 1.2.0', require: false
257
259
  gem 'glimmer-dsl-css', '~> 1.2.0', require: false
258
260
 
@@ -441,48 +443,50 @@ require 'glimmer-dsl-opal/samples/hello/hello_combo'
441
443
  Or add the Glimmer code directly if you prefer to play around with it:
442
444
 
443
445
  ```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'
446
+ class HelloCombo
447
+ class Person
448
+ attr_accessor :country, :country_options
449
+
450
+ def initialize
451
+ self.country_options = ['', 'Canada', 'US', 'Mexico']
452
+ reset_country!
453
+ end
454
+
455
+ def reset_country!
456
+ self.country = 'Canada'
457
+ end
454
458
  end
455
- end
456
459
 
457
- class HelloCombo
458
- include Glimmer
460
+ include Glimmer::UI::CustomShell
459
461
 
460
- def launch
461
- person = Person.new
462
-
462
+ before_body {
463
+ @person = Person.new
464
+ }
465
+
466
+ body {
463
467
  shell {
464
468
  row_layout(:vertical) {
465
- pack false
469
+ fill true
466
470
  }
467
471
 
468
472
  text 'Hello, Combo!'
469
473
 
470
474
  combo(:read_only) {
471
- selection <=> [person, :country]
475
+ selection <=> [@person, :country] # also binds to country_options by convention
472
476
  }
473
477
 
474
478
  button {
475
479
  text 'Reset Selection'
476
480
 
477
481
  on_widget_selected do
478
- person.reset_country
482
+ @person.reset_country!
479
483
  end
480
484
  }
481
- }.open
482
- end
485
+ }
486
+ }
483
487
  end
484
488
 
485
- HelloCombo.new.launch
489
+ HelloCombo.launch
486
490
  ```
487
491
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
488
492
 
@@ -534,17 +538,17 @@ class HelloComputed
534
538
  end
535
539
  end
536
540
 
537
- include Glimmer
541
+ include Glimmer::UI::CustomShell
538
542
 
539
- def initialize
543
+ before_body {
540
544
  @contact = Contact.new(
541
545
  first_name: 'Barry',
542
546
  last_name: 'McKibbin',
543
547
  year_of_birth: 1985
544
548
  )
545
- end
549
+ }
546
550
 
547
- def launch
551
+ body {
548
552
  shell {
549
553
  text 'Hello, Computed!'
550
554
 
@@ -601,11 +605,11 @@ class HelloComputed
601
605
  }
602
606
  }
603
607
  }
604
- }.open
605
- end
608
+ }
609
+ }
606
610
  end
607
611
 
608
- HelloComputed.new.launch
612
+ HelloComputed.launch
609
613
  ```
610
614
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
611
615
 
@@ -633,44 +637,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
633
637
  require 'glimmer-dsl-opal/samples/hello/hello_list_single_selection'
634
638
  ```
635
639
 
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
640
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
675
641
 
676
642
  ![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 +662,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
696
662
  require 'glimmer-dsl-opal/samples/hello/hello_list_multi_selection'
697
663
  ```
698
664
 
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
665
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
757
666
 
758
667
  ![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 +687,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
778
687
  require 'glimmer-dsl-opal/samples/hello/hello_browser'
779
688
  ```
780
689
 
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
690
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
794
691
 
795
692
  ![Glimmer DSL for SWT Hello Browser](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-browser.png)
@@ -894,7 +791,7 @@ class GreetingLabel
894
791
  after_body {
895
792
  return if colors.nil?
896
793
 
897
- Thread.new {
794
+ Thread.new { # imported from Glimmer DSL for SWT. In Opal, avoid Threads and sleep to avoid blocking GUI.
898
795
  colors.cycle { |color|
899
796
  async_exec {
900
797
  self.color = color
@@ -909,7 +806,7 @@ class GreetingLabel
909
806
  label(swt_style) {
910
807
  text "#{greeting}, #{name}!"
911
808
  font @font
912
- foreground bind(self, :color)
809
+ foreground <=> [self, :color]
913
810
  }
914
811
  }
915
812
 
@@ -1131,103 +1028,14 @@ You should see "Hello, Custom Widget!"
1131
1028
 
1132
1029
  #### Hello, Radio!
1133
1030
 
1031
+ This is the low level way of using `radio`
1032
+
1134
1033
  Add the following require statement to `app/assets/javascripts/application.rb`
1135
1034
 
1136
1035
  ```ruby
1137
1036
  require 'glimmer-dsl-opal/samples/hello/hello_radio'
1138
1037
  ```
1139
1038
 
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
1039
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1232
1040
 
1233
1041
  ![Glimmer DSL for SWT Hello Radio](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-radio.png)
@@ -1247,6 +1055,8 @@ You should see "Hello, Radio!"
1247
1055
 
1248
1056
  #### Hello, Radio Group!
1249
1057
 
1058
+ `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.
1059
+
1250
1060
  Add the following require statement to `app/assets/javascripts/application.rb`
1251
1061
 
1252
1062
  ```ruby
@@ -1261,7 +1071,7 @@ class HelloRadioGroup
1261
1071
  attr_accessor :gender, :age_group
1262
1072
 
1263
1073
  def initialize
1264
- reset
1074
+ reset!
1265
1075
  end
1266
1076
 
1267
1077
  def gender_options
@@ -1272,17 +1082,19 @@ class HelloRadioGroup
1272
1082
  ['Child', 'Teen', 'Adult', 'Senior']
1273
1083
  end
1274
1084
 
1275
- def reset
1085
+ def reset!
1276
1086
  self.gender = nil
1277
1087
  self.age_group = 'Adult'
1278
1088
  end
1279
1089
  end
1280
1090
 
1281
- include Glimmer
1091
+ include Glimmer::UI::CustomShell
1282
1092
 
1283
- def launch
1284
- person = Person.new
1285
-
1093
+ before_body {
1094
+ @person = Person.new
1095
+ }
1096
+
1097
+ body {
1286
1098
  shell {
1287
1099
  text 'Hello, Radio Group!'
1288
1100
  row_layout :vertical
@@ -1294,7 +1106,7 @@ class HelloRadioGroup
1294
1106
 
1295
1107
  radio_group {
1296
1108
  row_layout :horizontal
1297
- selection bind(person, :gender)
1109
+ selection <=> [@person, :gender]
1298
1110
  }
1299
1111
 
1300
1112
  label {
@@ -1304,21 +1116,21 @@ class HelloRadioGroup
1304
1116
 
1305
1117
  radio_group {
1306
1118
  row_layout :horizontal
1307
- selection bind(person, :age_group)
1119
+ selection <=> [@person, :age_group]
1308
1120
  }
1309
1121
 
1310
1122
  button {
1311
1123
  text 'Reset'
1312
1124
 
1313
1125
  on_widget_selected do
1314
- person.reset
1126
+ @person.reset!
1315
1127
  end
1316
1128
  }
1317
- }.open
1318
- end
1129
+ }
1130
+ }
1319
1131
  end
1320
1132
 
1321
- HelloRadioGroup.new.launch
1133
+ HelloRadioGroup.launch
1322
1134
  ```
1323
1135
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1324
1136
 
@@ -1339,99 +1151,14 @@ You should see "Hello, Radio Group!"
1339
1151
 
1340
1152
  #### Hello, Group!
1341
1153
 
1154
+ Not to be confused with `radio_group` or `checkbox_group`, `group` simply groups arbitrary widgets together and adds a title header above them.
1155
+
1342
1156
  Add the following require statement to `app/assets/javascripts/application.rb`
1343
1157
 
1344
1158
  ```ruby
1345
1159
  require 'glimmer-dsl-opal/samples/hello/hello_group'
1346
1160
  ```
1347
1161
 
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 bind(person, :male)
1387
- }
1388
-
1389
- radio {
1390
- text 'Female'
1391
- selection bind(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
1162
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1436
1163
 
1437
1164
  ![Glimmer DSL for SWT Hello Group](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-group.png)
@@ -1451,130 +1178,68 @@ You should see "Hello, Group!"
1451
1178
 
1452
1179
  #### Hello, Checkbox!
1453
1180
 
1181
+ This is the low level way of using `checkbox`
1182
+
1454
1183
  Add the following require statement to `app/assets/javascripts/application.rb`
1455
1184
 
1456
1185
  ```ruby
1457
1186
  require 'glimmer-dsl-opal/samples/hello/hello_checkbox'
1458
1187
  ```
1459
1188
 
1189
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1190
+
1191
+ ![Glimmer DSL for SWT Hello Checkbox](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-checkbox.png)
1192
+
1193
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
1194
+
1195
+ Start the Rails server:
1196
+ ```
1197
+ rails s
1198
+ ```
1199
+
1200
+ Visit `http://localhost:3000`
1201
+
1202
+ You should see "Hello, Checkbox!"
1203
+
1204
+ ![Glimmer DSL for Opal Hello Checkbox](images/glimmer-dsl-opal-hello-checkbox.png)
1205
+
1206
+ #### Hello, Checkbox Group!
1207
+
1208
+ `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.
1209
+
1210
+ Add the following require statement to `app/assets/javascripts/application.rb`
1211
+
1212
+ ```ruby
1213
+ require 'glimmer-dsl-opal/samples/hello/hello_checkbox_group'
1214
+ ```
1215
+
1460
1216
  Or add the Glimmer code directly if you prefer to play around with it:
1461
1217
 
1462
1218
  ```ruby
1463
- class HelloCheckbox
1219
+ class HelloCheckboxGroup
1464
1220
  class Person
1465
- attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing
1221
+ attr_accessor :activities
1466
1222
 
1467
1223
  def initialize
1468
1224
  reset_activities
1469
1225
  end
1470
1226
 
1227
+ def activities_options
1228
+ ['Skiing', 'Snowboarding', 'Snowmobiling', 'Snowshoeing']
1229
+ end
1230
+
1471
1231
  def reset_activities
1472
- self.skiing = false
1473
- self.snowboarding = true
1474
- self.snowmobiling = false
1475
- self.snowshoeing = false
1232
+ self.activities = ['Snowboarding']
1476
1233
  end
1477
1234
  end
1478
1235
 
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
- Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1529
-
1530
- ![Glimmer DSL for SWT Hello Checkbox](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-checkbox.png)
1531
-
1532
- Glimmer app on the web (using `glimmer-dsl-opal` gem):
1533
-
1534
- Start the Rails server:
1535
- ```
1536
- rails s
1537
- ```
1538
-
1539
- Visit `http://localhost:3000`
1540
-
1541
- You should see "Hello, Checkbox!"
1542
-
1543
- ![Glimmer DSL for Opal Hello Checkbox](images/glimmer-dsl-opal-hello-checkbox.png)
1544
-
1545
- #### Hello, Checkbox Group!
1546
-
1547
- Add the following require statement to `app/assets/javascripts/application.rb`
1548
-
1549
- ```ruby
1550
- require 'glimmer-dsl-opal/samples/hello/hello_checkbox_group'
1551
- ```
1552
-
1553
- Or add the Glimmer code directly if you prefer to play around with it:
1554
-
1555
- ```ruby
1556
- class HelloCheckboxGroup
1557
- class Person
1558
- attr_accessor :activities
1559
-
1560
- def initialize
1561
- reset_activities
1562
- end
1563
-
1564
- def activities_options
1565
- ['Skiing', 'Snowboarding', 'Snowmobiling', 'Snowshoeing']
1566
- end
1567
-
1568
- def reset_activities
1569
- self.activities = ['Snowboarding']
1570
- end
1571
- end
1236
+ include Glimmer::UI::CustomShell
1572
1237
 
1573
- include Glimmer
1238
+ before_body {
1239
+ @person = Person.new
1240
+ }
1574
1241
 
1575
- def launch
1576
- person = Person.new
1577
-
1242
+ body {
1578
1243
  shell {
1579
1244
  text 'Hello, Checkbox Group!'
1580
1245
  row_layout :vertical
@@ -1585,21 +1250,21 @@ class HelloCheckboxGroup
1585
1250
  }
1586
1251
 
1587
1252
  checkbox_group {
1588
- selection bind(person, :activities)
1253
+ selection <=> [@person, :activities]
1589
1254
  }
1590
1255
 
1591
1256
  button {
1592
1257
  text 'Reset Activities'
1593
1258
 
1594
1259
  on_widget_selected do
1595
- person.reset_activities
1260
+ @person.reset_activities
1596
1261
  end
1597
1262
  }
1598
- }.open
1599
- end
1263
+ }
1264
+ }
1600
1265
  end
1601
1266
 
1602
- HelloCheckboxGroup.new.launch
1267
+ HelloCheckboxGroup.launch
1603
1268
  ```
1604
1269
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1605
1270
 
@@ -1626,53 +1291,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
1626
1291
  require 'glimmer-dsl-opal/samples/hello/hello_date_time'
1627
1292
  ```
1628
1293
 
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
1294
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1677
1295
 
1678
1296
  ![Glimmer DSL for SWT Hello Checkbox Group](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-date-time.png)
@@ -1700,263 +1318,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
1700
1318
  require 'glimmer-dsl-opal/samples/hello/hello_table'
1701
1319
  ```
1702
1320
 
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
1958
- ```
1959
-
1960
1321
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
1961
1322
 
1962
1323
  ![Glimmer DSL for SWT Hello Table](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-hello-table.png)
@@ -2051,30 +1412,30 @@ Or add the Glimmer code directly if you prefer to play around with it:
2051
1412
 
2052
1413
  ```ruby
2053
1414
  class HelloButton
2054
- include Glimmer
1415
+ include Glimmer::UI::CustomShell
2055
1416
 
2056
1417
  attr_accessor :count
2057
1418
 
2058
- def initialize
1419
+ before_body {
2059
1420
  @count = 0
2060
- end
1421
+ }
2061
1422
 
2062
- def launch
1423
+ body {
2063
1424
  shell {
2064
1425
  text 'Hello, Button!'
2065
1426
 
2066
1427
  button {
2067
- text bind(self, :count) {|value| "Click To Increment: #{value} "}
1428
+ text <= [self, :count, on_read: ->(value) { "Click To Increment: #{value} " }]
2068
1429
 
2069
1430
  on_widget_selected {
2070
1431
  self.count += 1
2071
1432
  }
2072
1433
  }
2073
- }.open
2074
- end
1434
+ }
1435
+ }
2075
1436
  end
2076
1437
 
2077
- HelloButton.new.launch
1438
+ HelloButton.launch
2078
1439
  ```
2079
1440
 
2080
1441
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
@@ -2694,19 +2055,24 @@ class LoginPresenter
2694
2055
  end
2695
2056
 
2696
2057
  class Login
2697
- include Glimmer
2058
+ include Glimmer::UI::CustomShell
2059
+
2060
+ before_body {
2061
+ @presenter = LoginPresenter.new
2062
+ }
2698
2063
 
2699
- def launch
2700
- presenter = LoginPresenter.new
2701
- @shell = shell {
2064
+ body {
2065
+ shell {
2702
2066
  text "Login"
2067
+
2703
2068
  composite {
2704
2069
  grid_layout 2, false #two columns with differing widths
2705
2070
 
2706
2071
  label { text "Username:" } # goes in column 1
2707
2072
  @user_name_text = text { # goes in column 2
2708
- text bind(presenter, :user_name)
2709
- enabled bind(presenter, :logged_out)
2073
+ text <=> [@presenter, :user_name]
2074
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
2075
+
2710
2076
  on_key_pressed { |event|
2711
2077
  @password_text.set_focus if event.keyCode == swt(:cr)
2712
2078
  }
@@ -2714,43 +2080,47 @@ class Login
2714
2080
 
2715
2081
  label { text "Password:" }
2716
2082
  @password_text = text(:password, :border) {
2717
- text bind(presenter, :password)
2718
- enabled bind(presenter, :logged_out)
2083
+ text <=> [@presenter, :password]
2084
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
2085
+
2719
2086
  on_key_pressed { |event|
2720
- presenter.login if event.keyCode == swt(:cr)
2087
+ @presenter.login! if event.keyCode == swt(:cr)
2721
2088
  }
2722
2089
  }
2723
2090
 
2724
2091
  label { text "Status:" }
2725
- label { text bind(presenter, :status) }
2092
+ label { text <= [@presenter, :status] }
2726
2093
 
2727
2094
  button {
2728
2095
  text "Login"
2729
- enabled bind(presenter, :logged_out)
2730
- on_widget_selected { presenter.login }
2096
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
2097
+
2098
+ on_widget_selected { @presenter.login! }
2731
2099
  on_key_pressed { |event|
2732
- presenter.login if event.keyCode == swt(:cr)
2100
+ if event.keyCode == swt(:cr)
2101
+ @presenter.login!
2102
+ end
2733
2103
  }
2734
2104
  }
2735
2105
 
2736
2106
  button {
2737
2107
  text "Logout"
2738
- enabled bind(presenter, :logged_in)
2739
- on_widget_selected { presenter.logout }
2108
+ enabled <= [@presenter, :logged_in?, computed_by: :status]
2109
+
2110
+ on_widget_selected { @presenter.logout! }
2740
2111
  on_key_pressed { |event|
2741
2112
  if event.keyCode == swt(:cr)
2742
- presenter.logout
2113
+ @presenter.logout!
2743
2114
  @user_name_text.set_focus
2744
2115
  end
2745
2116
  }
2746
2117
  }
2747
2118
  }
2748
2119
  }
2749
- @shell.open
2750
- end
2120
+ }
2751
2121
  end
2752
2122
 
2753
- Login.new.launch
2123
+ Login.launch
2754
2124
  ```
2755
2125
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
2756
2126
 
@@ -2781,214 +2151,7 @@ Add the following require statement to `app/assets/javascripts/application.rb`
2781
2151
  require 'glimmer-dsl-opal/samples/elaborate/tic_tac_toe'
2782
2152
  ```
2783
2153
 
2784
- Or add the Glimmer code directly if you prefer to play around with it:
2785
-
2786
2154
  ```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
2155
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
2993
2156
 
2994
2157
  ![Glimmer DSL for SWT Tic Tac Toe](https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/images/glimmer-tic-tac-toe.png)
@@ -3018,321 +2181,6 @@ Add the following require statement to `app/assets/javascripts/application.rb`
3018
2181
  require 'glimmer-dsl-opal/samples/elaborate/contact_manager'
3019
2182
  ```
3020
2183
 
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
2184
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
3337
2185
 
3338
2186
  Glimmer DSL for SWT Contact Manager
@@ -3386,6 +2234,41 @@ Glimmer DSL for Opal Contact Manager Edit Done
3386
2234
 
3387
2235
  ![Glimmer DSL for Opal Contact Manager Edit Done](images/glimmer-dsl-opal-contact-manager-edit-done.png)
3388
2236
 
2237
+ #### Weather
2238
+
2239
+ Code: [lib/glimmer-dsl-opal/samples/elaborate/weather](lib/glimmer-dsl-opal/samples/elaborate/weather.rb)
2240
+
2241
+ Add the following require statement to `app/assets/javascripts/application.rb`
2242
+
2243
+ ```ruby
2244
+ require 'glimmer-dsl-opal/samples/elaborate/weather'
2245
+ ```
2246
+
2247
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
2248
+
2249
+ ![Weather Montreal C](https://github.com/AMaleh/glimmer-dsl-swt/raw/master/images/glimmer-weather-montreal-celsius.png)
2250
+
2251
+ ![Weather Montreal F](https://github.com/AMaleh/glimmer-dsl-swt/raw/master/images/glimmer-weather-montreal-fahrenheit.png)
2252
+
2253
+ ![Weather Atlanta F](https://github.com/AMaleh/glimmer-dsl-swt/raw/master/images/glimmer-weather-atlanta-fahrenheit.png)
2254
+
2255
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
2256
+
2257
+ Start the Rails server:
2258
+ ```
2259
+ rails s
2260
+ ```
2261
+
2262
+ Visit `http://localhost:3000`
2263
+
2264
+ You should see "Weather"
2265
+
2266
+ ![Opal Weather Montreal C](/images/glimmer-dsl-opal-weather-montreal-celsius.png)
2267
+
2268
+ ![Opal Weather Montreal F](/images/glimmer-dsl-opal-weather-montreal-fahrenheit.png)
2269
+
2270
+ ![Opal Weather Atlanta F](/images/glimmer-dsl-opal-weather-atlanta-fahrenheit.png)
2271
+
3389
2272
  ### External Samples
3390
2273
 
3391
2274
  #### Glimmer Calculator