glimmer-dsl-opal 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +367 -13
- data/VERSION +1 -1
- data/lib/glimmer-dsl-opal.rb +3 -2
- data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
- data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/dsl.rb +3 -0
- data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
- data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
- data/lib/glimmer/opal/display_proxy.rb +23 -0
- data/lib/glimmer/opal/document_proxy.rb +50 -0
- data/lib/glimmer/opal/element_proxy.rb +9 -3
- data/lib/glimmer/opal/grid_layout_proxy.rb +2 -1
- data/lib/glimmer/opal/input_proxy.rb +7 -3
- data/lib/glimmer/opal/modal.rb +94 -0
- data/lib/samples/elaborate/login.rb +0 -1
- data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1e27d44e69248f9febb6c2b8ce6d58d5f6a876d451b09d293769e3296e8c1ff
|
4
|
+
data.tar.gz: 30f77e89b509c325d8e609a2b6cda35425acb2b3e6f48ed8113c724208a1c0e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ee6ca73fef3795d270cf4980fd4392beb39bc2a4f240f5a0fe10014772206aa5da1ca502559a13da2abb3191f681d5f76041003d207736c4469be2709476d73
|
7
|
+
data.tar.gz: 381fde33081fca87a978babb4e3048acfacf70a56de249eb5ea44be9dd0c6f60139b278601d929110eb6f687f3dd65c31287458d8c98c0fc1e31c59c3b842d71
|
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=65 /> Glimmer DSL for Opal 0.0.
|
1
|
+
# <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=65 /> Glimmer DSL for Opal 0.0.7 (Web GUI for Desktop Apps)
|
2
2
|
[](http://badge.fury.io/rb/glimmer-dsl-opal)
|
3
3
|
[](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
4
4
|
|
@@ -6,7 +6,9 @@
|
|
6
6
|
|
7
7
|
It enables running [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps on the web via [Rails](https://rubyonrails.org/) 5 and [Opal](https://opalrb.com/) 1.
|
8
8
|
|
9
|
-
NOTE: Alpha Version 0.0.
|
9
|
+
NOTE: Alpha Version 0.0.7 only supports capabilities for the following [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt) [samples](https://github.com/AndyObtiva/glimmer#samples):
|
10
|
+
|
11
|
+
Hello Samples:
|
10
12
|
- [Hello, World!](#hello-world)
|
11
13
|
- [Hello, Combo!](#hello-combo)
|
12
14
|
- [Hello, Computed!](#hello-computed)
|
@@ -15,6 +17,10 @@ NOTE: Alpha Version 0.0.6 only supports Hello sample capabilities (detailed unde
|
|
15
17
|
- [Hello, Browser!](#hello-browser)
|
16
18
|
- [Hello, Tab!](#hello-tab)
|
17
19
|
|
20
|
+
Elaborate Samples:
|
21
|
+
- [Login](#login)
|
22
|
+
- [Tic Tac Toe](#tic-tac-toe)
|
23
|
+
|
18
24
|
Other Glimmer DSL gems:
|
19
25
|
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI)
|
20
26
|
- [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
|
@@ -57,9 +63,10 @@ Follow instructions to setup opal with a rails application: config/initializers/
|
|
57
63
|
|
58
64
|
Add the following to `Gemfile` (NOTE: if you run into issues, they are probably fixed in master or development/wip branch, you may check out instead):
|
59
65
|
```
|
60
|
-
gem 'opal-rails'
|
61
|
-
gem 'opal-
|
62
|
-
gem '
|
66
|
+
gem 'opal-rails', '~> 1.1.2'
|
67
|
+
gem 'opal-async', '~> 1.1.0'
|
68
|
+
gem 'opal-browser', '~> 0.2.0'
|
69
|
+
gem 'glimmer-dsl-opal', '~> 0.0.7', require: false
|
63
70
|
```
|
64
71
|
|
65
72
|
Edit `config/initializers/assets.rb` and add:
|
@@ -73,9 +80,11 @@ Add the following line to the top of an empty `app/assets/javascripts/applicatio
|
|
73
80
|
require 'glimmer-dsl-opal' # brings opal and opal browser too
|
74
81
|
```
|
75
82
|
|
76
|
-
##
|
83
|
+
## Samples
|
84
|
+
|
85
|
+
### Hello Samples
|
77
86
|
|
78
|
-
|
87
|
+
#### Hello, World!
|
79
88
|
|
80
89
|
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
81
90
|
|
@@ -107,7 +116,7 @@ You should see "Hello, World!"
|
|
107
116
|
|
108
117
|

|
109
118
|
|
110
|
-
|
119
|
+
#### Hello, Combo!
|
111
120
|
|
112
121
|
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
113
122
|
|
@@ -164,7 +173,7 @@ You should see "Hello, Combo!"
|
|
164
173
|
|
165
174
|

|
166
175
|
|
167
|
-
|
176
|
+
#### Hello, Computed!
|
168
177
|
|
169
178
|
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
170
179
|
|
@@ -276,7 +285,7 @@ You should see "Hello, Computed!"
|
|
276
285
|
|
277
286
|

|
278
287
|
|
279
|
-
|
288
|
+
#### Hello, List Single Selection!
|
280
289
|
|
281
290
|
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
282
291
|
|
@@ -333,7 +342,7 @@ You should see "Hello, List Single Selection!"
|
|
333
342
|
|
334
343
|

|
335
344
|
|
336
|
-
|
345
|
+
#### Hello, List Multi Selection!
|
337
346
|
|
338
347
|
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
339
348
|
|
@@ -400,7 +409,7 @@ You should see "Hello, List Multi Selection!"
|
|
400
409
|
|
401
410
|

|
402
411
|
|
403
|
-
|
412
|
+
#### Hello, Browser!
|
404
413
|
|
405
414
|
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
406
415
|
|
@@ -431,7 +440,7 @@ You should see "Hello, Browser!"
|
|
431
440
|
|
432
441
|

|
433
442
|
|
434
|
-
|
443
|
+
#### Hello, Tab!
|
435
444
|
|
436
445
|
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
437
446
|
|
@@ -480,6 +489,351 @@ You should see "Hello, Tab!"
|
|
480
489
|

|
481
490
|

|
482
491
|
|
492
|
+
### Elaborate Samples
|
493
|
+
|
494
|
+
#### Login
|
495
|
+
|
496
|
+
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
497
|
+
|
498
|
+
```ruby
|
499
|
+
require "observer"
|
500
|
+
|
501
|
+
#Presents login screen data
|
502
|
+
class LoginPresenter
|
503
|
+
|
504
|
+
attr_accessor :user_name
|
505
|
+
attr_accessor :password
|
506
|
+
attr_accessor :status
|
507
|
+
|
508
|
+
def initialize
|
509
|
+
@user_name = ""
|
510
|
+
@password = ""
|
511
|
+
@status = "Logged Out"
|
512
|
+
end
|
513
|
+
|
514
|
+
def status=(status)
|
515
|
+
@status = status
|
516
|
+
|
517
|
+
#TODO add feature to bind dependent properties to master property (2017-07-25 nested data binding)
|
518
|
+
notify_observers("logged_in")
|
519
|
+
notify_observers("logged_out")
|
520
|
+
end
|
521
|
+
|
522
|
+
def logged_in
|
523
|
+
self.status == "Logged In"
|
524
|
+
end
|
525
|
+
|
526
|
+
def logged_out
|
527
|
+
!self.logged_in
|
528
|
+
end
|
529
|
+
|
530
|
+
def login
|
531
|
+
self.status = "Logged In"
|
532
|
+
end
|
533
|
+
|
534
|
+
def logout
|
535
|
+
self.user_name = ""
|
536
|
+
self.password = ""
|
537
|
+
self.status = "Logged Out"
|
538
|
+
end
|
539
|
+
|
540
|
+
end
|
541
|
+
|
542
|
+
#Login screen
|
543
|
+
class Login
|
544
|
+
include Glimmer
|
545
|
+
|
546
|
+
def launch
|
547
|
+
presenter = LoginPresenter.new
|
548
|
+
@shell = shell {
|
549
|
+
text "Login"
|
550
|
+
composite {
|
551
|
+
grid_layout 2, false #two columns with differing widths
|
552
|
+
|
553
|
+
label { text "Username:" } # goes in column 1
|
554
|
+
text { # goes in column 2
|
555
|
+
text bind(presenter, :user_name)
|
556
|
+
enabled bind(presenter, :logged_out)
|
557
|
+
}
|
558
|
+
|
559
|
+
label { text "Password:" }
|
560
|
+
text(:password, :border) {
|
561
|
+
text bind(presenter, :password)
|
562
|
+
enabled bind(presenter, :logged_out)
|
563
|
+
}
|
564
|
+
|
565
|
+
label { text "Status:" }
|
566
|
+
label { text bind(presenter, :status) }
|
567
|
+
|
568
|
+
button {
|
569
|
+
text "Login"
|
570
|
+
enabled bind(presenter, :logged_out)
|
571
|
+
on_widget_selected { presenter.login }
|
572
|
+
}
|
573
|
+
|
574
|
+
button {
|
575
|
+
text "Logout"
|
576
|
+
enabled bind(presenter, :logged_in)
|
577
|
+
on_widget_selected { presenter.logout }
|
578
|
+
}
|
579
|
+
}
|
580
|
+
}
|
581
|
+
@shell.open
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
Login.new.launch
|
586
|
+
```
|
587
|
+
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
588
|
+
|
589
|
+

|
590
|
+

|
591
|
+

|
592
|
+
|
593
|
+
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
594
|
+
|
595
|
+
Start the Rails server:
|
596
|
+
```
|
597
|
+
rails s
|
598
|
+
```
|
599
|
+
|
600
|
+
Visit `http://localhost:3000`
|
601
|
+
|
602
|
+
You should see "Login" dialog
|
603
|
+
|
604
|
+

|
605
|
+

|
606
|
+

|
607
|
+
|
608
|
+
#### Tic Tac Toe
|
609
|
+
|
610
|
+
Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
|
611
|
+
|
612
|
+
```ruby
|
613
|
+
class TicTacToe
|
614
|
+
class Cell
|
615
|
+
EMPTY = ""
|
616
|
+
attr_accessor :sign, :empty
|
617
|
+
|
618
|
+
def initialize
|
619
|
+
reset
|
620
|
+
end
|
621
|
+
|
622
|
+
def mark(sign)
|
623
|
+
self.sign = sign
|
624
|
+
end
|
625
|
+
|
626
|
+
def reset
|
627
|
+
self.sign = EMPTY
|
628
|
+
end
|
629
|
+
|
630
|
+
def sign=(sign_symbol)
|
631
|
+
@sign = sign_symbol
|
632
|
+
self.empty = sign == EMPTY
|
633
|
+
end
|
634
|
+
|
635
|
+
def marked
|
636
|
+
!empty
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
class TicTacToe
|
642
|
+
class Board
|
643
|
+
DRAW = :draw
|
644
|
+
IN_PROGRESS = :in_progress
|
645
|
+
WIN = :win
|
646
|
+
attr :winning_sign
|
647
|
+
attr_accessor :game_status
|
648
|
+
|
649
|
+
def initialize
|
650
|
+
@sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
|
651
|
+
build_grid
|
652
|
+
@winning_sign = Cell::EMPTY
|
653
|
+
@game_status = IN_PROGRESS
|
654
|
+
end
|
655
|
+
|
656
|
+
#row and column numbers are 1-based
|
657
|
+
def mark(row, column)
|
658
|
+
self[row, column].mark(current_sign)
|
659
|
+
game_over? #updates winning sign
|
660
|
+
end
|
661
|
+
|
662
|
+
def current_sign
|
663
|
+
@current_sign = @sign_state_machine[@current_sign]
|
664
|
+
end
|
665
|
+
|
666
|
+
def [](row, column)
|
667
|
+
@grid[row-1][column-1]
|
668
|
+
end
|
669
|
+
|
670
|
+
def game_over?
|
671
|
+
win? or draw?
|
672
|
+
end
|
673
|
+
|
674
|
+
def win?
|
675
|
+
win = (row_win? or column_win? or diagonal_win?)
|
676
|
+
self.game_status=WIN if win
|
677
|
+
win
|
678
|
+
end
|
679
|
+
|
680
|
+
def reset
|
681
|
+
(1..3).each do |row|
|
682
|
+
(1..3).each do |column|
|
683
|
+
self[row, column].reset
|
684
|
+
end
|
685
|
+
end
|
686
|
+
@winning_sign = Cell::EMPTY
|
687
|
+
@current_sign = nil
|
688
|
+
self.game_status=IN_PROGRESS
|
689
|
+
end
|
690
|
+
|
691
|
+
private
|
692
|
+
|
693
|
+
def build_grid
|
694
|
+
@grid = []
|
695
|
+
3.times do |row_index| #0-based
|
696
|
+
@grid << []
|
697
|
+
3.times { @grid[row_index] << Cell.new }
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
def row_win?
|
702
|
+
(1..3).each do |row|
|
703
|
+
if row_has_same_sign(row)
|
704
|
+
@winning_sign = self[row, 1].sign
|
705
|
+
return true
|
706
|
+
end
|
707
|
+
end
|
708
|
+
false
|
709
|
+
end
|
710
|
+
|
711
|
+
def column_win?
|
712
|
+
(1..3).each do |column|
|
713
|
+
if column_has_same_sign(column)
|
714
|
+
@winning_sign = self[1, column].sign
|
715
|
+
return true
|
716
|
+
end
|
717
|
+
end
|
718
|
+
false
|
719
|
+
end
|
720
|
+
|
721
|
+
#needs refactoring if we ever decide to make the board size dynamic
|
722
|
+
def diagonal_win?
|
723
|
+
if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
|
724
|
+
@winning_sign = self[1, 1].sign
|
725
|
+
return true
|
726
|
+
end
|
727
|
+
if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
|
728
|
+
@winning_sign = self[3, 1].sign
|
729
|
+
return true
|
730
|
+
end
|
731
|
+
false
|
732
|
+
end
|
733
|
+
|
734
|
+
def draw?
|
735
|
+
@board_full = true
|
736
|
+
3.times do |x|
|
737
|
+
3.times do |y|
|
738
|
+
@board_full = false if self[x, y].empty
|
739
|
+
end
|
740
|
+
end
|
741
|
+
self.game_status = DRAW if @board_full
|
742
|
+
@board_full
|
743
|
+
end
|
744
|
+
|
745
|
+
def row_has_same_sign(number)
|
746
|
+
row_sign = self[number, 1].sign
|
747
|
+
[2, 3].each do |column|
|
748
|
+
return false unless row_sign == (self[number, column].sign)
|
749
|
+
end
|
750
|
+
true if self[number, 1].marked
|
751
|
+
end
|
752
|
+
|
753
|
+
def column_has_same_sign(number)
|
754
|
+
column_sign = self[1, number].sign
|
755
|
+
[2, 3].each do |row|
|
756
|
+
return false unless column_sign == (self[row, number].sign)
|
757
|
+
end
|
758
|
+
true if self[1, number].marked
|
759
|
+
end
|
760
|
+
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
class TicTacToe
|
765
|
+
include Glimmer
|
766
|
+
|
767
|
+
def initialize
|
768
|
+
@tic_tac_toe_board = Board.new
|
769
|
+
@shell = shell {
|
770
|
+
text "Tic-Tac-Toe"
|
771
|
+
composite {
|
772
|
+
grid_layout 3, true
|
773
|
+
(1..3).each { |row|
|
774
|
+
(1..3).each { |column|
|
775
|
+
button {
|
776
|
+
layout_data :fill, :fill, true, true
|
777
|
+
text bind(@tic_tac_toe_board[row, column], :sign)
|
778
|
+
enabled bind(@tic_tac_toe_board[row, column], :empty)
|
779
|
+
on_widget_selected {
|
780
|
+
@tic_tac_toe_board.mark(row, column)
|
781
|
+
}
|
782
|
+
}
|
783
|
+
}
|
784
|
+
}
|
785
|
+
}
|
786
|
+
}
|
787
|
+
observe(@tic_tac_toe_board, :game_status) { |game_status|
|
788
|
+
display_win_message if game_status == Board::WIN
|
789
|
+
display_draw_message if game_status == Board::DRAW
|
790
|
+
}
|
791
|
+
end
|
792
|
+
|
793
|
+
def display_win_message
|
794
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
795
|
+
end
|
796
|
+
|
797
|
+
def display_draw_message
|
798
|
+
display_game_over_message("Draw!")
|
799
|
+
end
|
800
|
+
|
801
|
+
def display_game_over_message(message_text)
|
802
|
+
message_box(@shell) {
|
803
|
+
text 'Game Over'
|
804
|
+
message message_text
|
805
|
+
}.open
|
806
|
+
@tic_tac_toe_board.reset
|
807
|
+
end
|
808
|
+
|
809
|
+
def open
|
810
|
+
@shell.open
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
TicTacToe.new.open
|
815
|
+
```
|
816
|
+
Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
|
817
|
+
|
818
|
+

|
819
|
+

|
820
|
+

|
821
|
+
|
822
|
+
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
823
|
+
|
824
|
+
Start the Rails server:
|
825
|
+
```
|
826
|
+
rails s
|
827
|
+
```
|
828
|
+
|
829
|
+
Visit `http://localhost:3000`
|
830
|
+
|
831
|
+
You should see "Tic Tac Toe"
|
832
|
+
|
833
|
+

|
834
|
+

|
835
|
+

|
836
|
+
|
483
837
|
## Help
|
484
838
|
|
485
839
|
### Issues
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.7
|
data/lib/glimmer-dsl-opal.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'opal'
|
2
|
-
require 'opal-
|
2
|
+
require 'opal-async'
|
3
3
|
require 'glimmer'
|
4
4
|
|
5
5
|
GLIMMER_DSL_OPAL_ROOT = File.expand_path('../..', __FILE__)
|
@@ -7,4 +7,5 @@ GLIMMER_DSL_OPAL_LIB = File.join(GLIMMER_DSL_OPAL_ROOT, 'lib')
|
|
7
7
|
|
8
8
|
$LOAD_PATH.unshift(GLIMMER_DSL_OPAL_LIB)
|
9
9
|
|
10
|
-
require 'glimmer/dsl/opal/dsl'
|
10
|
+
require 'glimmer/dsl/opal/dsl'
|
11
|
+
require 'glimmer/data_binding/ext/observable_model'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'glimmer/data_binding/observable'
|
2
|
+
require 'glimmer/data_binding/observer'
|
3
|
+
require 'glimmer/opal/display_proxy'
|
4
|
+
|
5
|
+
# This ensures all data-binding events happen async and block on modal display
|
6
|
+
|
7
|
+
module Glimmer
|
8
|
+
module DataBinding
|
9
|
+
# TODO prefix utility methods with double-underscore
|
10
|
+
module ObservableModel
|
11
|
+
include Observable
|
12
|
+
include Glimmer
|
13
|
+
|
14
|
+
def add_property_writer_observers(property_name)
|
15
|
+
property_writer_name = "#{property_name}="
|
16
|
+
method(property_writer_name)
|
17
|
+
ensure_array_object_observer(property_name, send(property_name))
|
18
|
+
begin
|
19
|
+
method("__original_#{property_writer_name}")
|
20
|
+
rescue
|
21
|
+
old_method = self.class.instance_method(property_writer_name)
|
22
|
+
define_singleton_method("__original_#{property_writer_name}", old_method)
|
23
|
+
define_singleton_method(property_writer_name) do |value|
|
24
|
+
old_value = self.send(property_name)
|
25
|
+
unregister_dependent_observers(property_name, old_value)
|
26
|
+
self.send("__original_#{property_writer_name}", value)
|
27
|
+
Glimmer::Opal::DisplayProxy.instance.async_exec do
|
28
|
+
notify_observers(property_name)
|
29
|
+
ensure_array_object_observer(property_name, value, old_value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
rescue => e
|
34
|
+
# ignore writing if no property writer exists
|
35
|
+
Glimmer::Config.logger&.debug "No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'glimmer/dsl/static_expression'
|
2
|
+
require 'glimmer/dsl/top_level_expression'
|
3
|
+
require 'glimmer/opal/display_proxy'
|
4
|
+
|
5
|
+
module Glimmer
|
6
|
+
module DSL
|
7
|
+
module Opal
|
8
|
+
class AsyncExecExpression < StaticExpression
|
9
|
+
include TopLevelExpression
|
10
|
+
|
11
|
+
def interpret(parent, keyword, *args, &block)
|
12
|
+
Glimmer::Opal::DisplayProxy.instance.async_exec(&block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/glimmer/dsl/opal/dsl.rb
CHANGED
@@ -19,6 +19,9 @@ require 'glimmer/dsl/opal/list_expression'
|
|
19
19
|
require 'glimmer/dsl/opal/browser_expression'
|
20
20
|
require 'glimmer/dsl/opal/tab_folder_expression'
|
21
21
|
require 'glimmer/dsl/opal/tab_item_expression'
|
22
|
+
require 'glimmer/dsl/opal/message_box_expression'
|
23
|
+
require 'glimmer/dsl/opal/async_exec_expression'
|
24
|
+
require 'glimmer/dsl/opal/observe_expression'
|
22
25
|
require 'glimmer/dsl/opal/layout_data_expression'
|
23
26
|
require 'glimmer/dsl/opal/list_selection_data_binding_expression'
|
24
27
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'glimmer/dsl/static_expression'
|
2
|
+
require 'glimmer/dsl/top_level_expression'
|
3
|
+
require 'glimmer/dsl/parent_expression'
|
4
|
+
require 'glimmer/opal/modal'
|
5
|
+
|
6
|
+
module Glimmer
|
7
|
+
module DSL
|
8
|
+
module Opal
|
9
|
+
class MessageBoxExpression < StaticExpression
|
10
|
+
include TopLevelExpression
|
11
|
+
include ParentExpression
|
12
|
+
|
13
|
+
def interpret(parent, keyword, *args, &block)
|
14
|
+
parent = args.delete_at(0)
|
15
|
+
Glimmer::Opal::Modal.new(parent, args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'glimmer/dsl/static_expression'
|
2
|
+
require 'glimmer/dsl/top_level_expression'
|
3
|
+
require 'glimmer/data_binding/observer'
|
4
|
+
require 'glimmer/data_binding/model_binding'
|
5
|
+
|
6
|
+
module Glimmer
|
7
|
+
module DSL
|
8
|
+
module Opal
|
9
|
+
class ObserveExpression < StaticExpression
|
10
|
+
include TopLevelExpression
|
11
|
+
|
12
|
+
REGEX_NESTED_OR_INDEXED_PROPERTY = /([^\[]+)(\[[^\]]+\])?/
|
13
|
+
|
14
|
+
def can_interpret?(parent, keyword, *args, &block)
|
15
|
+
keyword == 'observe' and
|
16
|
+
block_given? and
|
17
|
+
(args.size == 2) and
|
18
|
+
textual?(args[1])
|
19
|
+
end
|
20
|
+
|
21
|
+
def interpret(parent, keyword, *args, &block)
|
22
|
+
observer = DataBinding::Observer.proc(&block)
|
23
|
+
if args[1].to_s.match(REGEX_NESTED_OR_INDEXED_PROPERTY)
|
24
|
+
observer.observe(DataBinding::ModelBinding.new(args[0], args[1]))
|
25
|
+
else
|
26
|
+
observer.observe(args[0], args[1])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Glimmer
|
2
|
+
module Opal
|
3
|
+
class DisplayProxy
|
4
|
+
class << self
|
5
|
+
def instance
|
6
|
+
@instance ||= new
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def async_exec(&block)
|
11
|
+
executer = lambda do
|
12
|
+
if $document.at_css('.modal')
|
13
|
+
sleep(0.05)
|
14
|
+
Async::Task.new(&executer)
|
15
|
+
else
|
16
|
+
block.call
|
17
|
+
end
|
18
|
+
end
|
19
|
+
Async::Task.new(&executer)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -104,6 +104,56 @@ module Glimmer
|
|
104
104
|
.hide {
|
105
105
|
display: none !important;
|
106
106
|
}
|
107
|
+
|
108
|
+
/* The Modal (background) */
|
109
|
+
.modal {
|
110
|
+
position: fixed; /* Stay in place */
|
111
|
+
z-index: 1; /* Sit on top */
|
112
|
+
padding-top: 100px; /* Location of the box */
|
113
|
+
left: 0;
|
114
|
+
top: 0;
|
115
|
+
width: 100%; /* Full width */
|
116
|
+
height: 100%; /* Full height */
|
117
|
+
overflow: auto; /* Enable scroll if needed */
|
118
|
+
background-color: rgb(0,0,0); /* Fallback color */
|
119
|
+
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
120
|
+
text-align: center;
|
121
|
+
}
|
122
|
+
|
123
|
+
/* Modal Content */
|
124
|
+
.modal-content {
|
125
|
+
background-color: #fefefe;
|
126
|
+
margin: auto;
|
127
|
+
border: 1px solid #888;
|
128
|
+
display: inline-block;
|
129
|
+
min-width: 200px;
|
130
|
+
}
|
131
|
+
|
132
|
+
.modal-content .text {
|
133
|
+
background: rgb(80, 116, 211);
|
134
|
+
color: white;
|
135
|
+
padding: 5px;
|
136
|
+
}
|
137
|
+
|
138
|
+
.modal-content .message {
|
139
|
+
padding: 20px;
|
140
|
+
}
|
141
|
+
|
142
|
+
/* The Close Button */
|
143
|
+
.close {
|
144
|
+
color: #aaaaaa;
|
145
|
+
float: right;
|
146
|
+
# font-size: 18px;
|
147
|
+
font-weight: bold;
|
148
|
+
margin: 5px;
|
149
|
+
}
|
150
|
+
|
151
|
+
.close:hover,
|
152
|
+
.close:focus {
|
153
|
+
color: #000;
|
154
|
+
text-decoration: none;
|
155
|
+
cursor: pointer;
|
156
|
+
}
|
107
157
|
</style>
|
108
158
|
CSS
|
109
159
|
}
|
@@ -5,7 +5,7 @@ module Glimmer
|
|
5
5
|
class ElementProxy
|
6
6
|
include Glimmer
|
7
7
|
include PropertyOwner
|
8
|
-
attr_reader :parent, :args, :css_classes, :css, :children
|
8
|
+
attr_reader :parent, :args, :css_classes, :css, :children, :enabled
|
9
9
|
|
10
10
|
def initialize(parent, args)
|
11
11
|
@parent = parent
|
@@ -13,14 +13,20 @@ module Glimmer
|
|
13
13
|
@children = Set.new
|
14
14
|
@css_classes = Set.new
|
15
15
|
@css = ''
|
16
|
+
@enabled = true
|
16
17
|
@parent.add_child(self)
|
17
18
|
end
|
18
19
|
|
19
20
|
def add_child(child)
|
20
|
-
# return if @children.include?(child)
|
21
|
+
# return if @children.include?(child) # TODO consider adding an option to enable this if needed to prevent dom repetition
|
21
22
|
@children << child
|
22
23
|
dom << child.dom
|
23
24
|
end
|
25
|
+
|
26
|
+
def enabled=(value)
|
27
|
+
@enabled = value
|
28
|
+
redraw
|
29
|
+
end
|
24
30
|
|
25
31
|
def redraw
|
26
32
|
if @dom
|
@@ -189,7 +195,7 @@ module Glimmer
|
|
189
195
|
# },
|
190
196
|
InputProxy => {
|
191
197
|
:text => lambda do |observer|
|
192
|
-
on_modify_text { |modify_event|
|
198
|
+
on_modify_text { |modify_event|
|
193
199
|
observer.call(text)
|
194
200
|
}
|
195
201
|
end,
|
@@ -19,8 +19,10 @@ module Glimmer
|
|
19
19
|
event: 'keyup',
|
20
20
|
event_handler: -> (event_listener) {
|
21
21
|
-> (event) {
|
22
|
-
|
23
|
-
|
22
|
+
if args.last[:type] == 'text'
|
23
|
+
@text = event.target.value
|
24
|
+
event_listener.call(event)
|
25
|
+
end
|
24
26
|
}
|
25
27
|
}
|
26
28
|
}
|
@@ -32,8 +34,10 @@ module Glimmer
|
|
32
34
|
input_id = id
|
33
35
|
input_style = css
|
34
36
|
input_args = @args.last
|
37
|
+
input_disabled = @enabled ? {} : {'disabled': 'disabled'}
|
38
|
+
input_args = input_args.merge(type: 'password') if has_style?(:password)
|
35
39
|
@dom ||= DOM {
|
36
|
-
input input_args.merge(id: input_id, style: input_style, value: input_text)
|
40
|
+
input input_args.merge(id: input_id, style: input_style, value: input_text, style: 'min-width: 27px;').merge(input_disabled)
|
37
41
|
}
|
38
42
|
end
|
39
43
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'glimmer/opal/element_proxy'
|
2
|
+
|
3
|
+
module Glimmer
|
4
|
+
module Opal
|
5
|
+
class Modal < ElementProxy
|
6
|
+
attr_reader :text, :message
|
7
|
+
|
8
|
+
def initialize(parent, args)
|
9
|
+
i = 0
|
10
|
+
@parent = parent
|
11
|
+
@args = args
|
12
|
+
@children = Set.new
|
13
|
+
@css_classes = Set.new(['modal'])
|
14
|
+
@css = ''
|
15
|
+
@enabled = true
|
16
|
+
content do
|
17
|
+
on_widget_selected {
|
18
|
+
hide
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def text=(txt)
|
24
|
+
@text = txt
|
25
|
+
redraw if @dom
|
26
|
+
end
|
27
|
+
|
28
|
+
def message=(msg)
|
29
|
+
@message = msg
|
30
|
+
redraw if @dom
|
31
|
+
end
|
32
|
+
|
33
|
+
def document
|
34
|
+
element = self
|
35
|
+
begin
|
36
|
+
element = element.parent
|
37
|
+
end while(element.parent)
|
38
|
+
element
|
39
|
+
end
|
40
|
+
|
41
|
+
def open
|
42
|
+
document.add_child(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def hide
|
46
|
+
dom.remove
|
47
|
+
end
|
48
|
+
|
49
|
+
def content(&block)
|
50
|
+
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Opal::MessageBoxExpression.new, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def name
|
54
|
+
'div'
|
55
|
+
end
|
56
|
+
|
57
|
+
def selector
|
58
|
+
super + ' .close'
|
59
|
+
end
|
60
|
+
|
61
|
+
def observation_request_to_event_mapping
|
62
|
+
{
|
63
|
+
'on_widget_selected' => {
|
64
|
+
event: 'click'
|
65
|
+
},
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def dom
|
70
|
+
modal_id = id
|
71
|
+
modal_style = css
|
72
|
+
modal_text = text
|
73
|
+
modal_message = message
|
74
|
+
modal_css_classes = css_classes
|
75
|
+
modal_class = modal_css_classes.to_a.join(' ')
|
76
|
+
@dom ||= DOM {
|
77
|
+
div(id: modal_id, style: modal_style, class: modal_class) {
|
78
|
+
div(class: 'modal-content') {
|
79
|
+
header.text {
|
80
|
+
modal_text
|
81
|
+
}
|
82
|
+
p.message {
|
83
|
+
modal_message
|
84
|
+
}
|
85
|
+
input(type: 'button', class: 'close', autofocus: 'autofocus', value: 'OK')
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
require 'glimmer/dsl/opal/message_box_expression'
|
@@ -37,11 +37,11 @@ class TicTacToe
|
|
37
37
|
display_game_over_message("Draw!")
|
38
38
|
end
|
39
39
|
|
40
|
-
def display_game_over_message(
|
41
|
-
message_box
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
def display_game_over_message(message_text)
|
41
|
+
message_box(@shell) {
|
42
|
+
text 'Game Over'
|
43
|
+
message message_text
|
44
|
+
}.open
|
45
45
|
@tic_tac_toe_board.reset
|
46
46
|
end
|
47
47
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer-dsl-opal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -170,11 +170,13 @@ files:
|
|
170
170
|
- lib/glimmer-dsl-opal.rb
|
171
171
|
- lib/glimmer/config.rb
|
172
172
|
- lib/glimmer/data_binding/element_binding.rb
|
173
|
+
- lib/glimmer/data_binding/ext/observable_model.rb
|
173
174
|
- lib/glimmer/data_binding/list_selection_binding.rb
|
174
175
|
- lib/glimmer/data_binding/observable_element.rb
|
175
176
|
- lib/glimmer/dsl/engine.rb
|
176
177
|
- lib/glimmer/dsl/expression.rb
|
177
178
|
- lib/glimmer/dsl/expression_handler.rb
|
179
|
+
- lib/glimmer/dsl/opal/async_exec_expression.rb
|
178
180
|
- lib/glimmer/dsl/opal/bind_expression.rb
|
179
181
|
- lib/glimmer/dsl/opal/browser_expression.rb
|
180
182
|
- lib/glimmer/dsl/opal/button_expression.rb
|
@@ -188,6 +190,8 @@ files:
|
|
188
190
|
- lib/glimmer/dsl/opal/layout_data_expression.rb
|
189
191
|
- lib/glimmer/dsl/opal/list_expression.rb
|
190
192
|
- lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb
|
193
|
+
- lib/glimmer/dsl/opal/message_box_expression.rb
|
194
|
+
- lib/glimmer/dsl/opal/observe_expression.rb
|
191
195
|
- lib/glimmer/dsl/opal/property_expression.rb
|
192
196
|
- lib/glimmer/dsl/opal/shell_expression.rb
|
193
197
|
- lib/glimmer/dsl/opal/tab_folder_expression.rb
|
@@ -199,6 +203,7 @@ files:
|
|
199
203
|
- lib/glimmer/dsl/top_level_expression.rb
|
200
204
|
- lib/glimmer/error.rb
|
201
205
|
- lib/glimmer/invalid_keyword_error.rb
|
206
|
+
- lib/glimmer/opal/display_proxy.rb
|
202
207
|
- lib/glimmer/opal/div_proxy.rb
|
203
208
|
- lib/glimmer/opal/document_proxy.rb
|
204
209
|
- lib/glimmer/opal/element_proxy.rb
|
@@ -209,6 +214,7 @@ files:
|
|
209
214
|
- lib/glimmer/opal/label_proxy.rb
|
210
215
|
- lib/glimmer/opal/layout_data_proxy.rb
|
211
216
|
- lib/glimmer/opal/list_proxy.rb
|
217
|
+
- lib/glimmer/opal/modal.rb
|
212
218
|
- lib/glimmer/opal/point.rb
|
213
219
|
- lib/glimmer/opal/property_owner.rb
|
214
220
|
- lib/glimmer/opal/select_proxy.rb
|