glimmer-dsl-opal 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +95 -20
  3. data/VERSION +1 -1
  4. data/lib/glimmer-dsl-opal.rb +10 -8
  5. data/lib/glimmer/data_binding/element_binding.rb +35 -0
  6. data/lib/glimmer/data_binding/observable_element.rb +14 -0
  7. data/lib/glimmer/dsl/opal/bind_expression.rb +37 -0
  8. data/lib/glimmer/dsl/opal/button_expression.rb +17 -0
  9. data/lib/glimmer/dsl/opal/combo_expression.rb +17 -0
  10. data/lib/glimmer/dsl/opal/combo_selection_data_binding_expression.rb +40 -0
  11. data/lib/glimmer/dsl/opal/composite_expression.rb +17 -0
  12. data/lib/glimmer/dsl/opal/data_binding_expression.rb +34 -0
  13. data/lib/glimmer/dsl/opal/dsl.rb +9 -0
  14. data/lib/glimmer/dsl/opal/label_expression.rb +2 -2
  15. data/lib/glimmer/dsl/opal/property_expression.rb +1 -1
  16. data/lib/glimmer/dsl/opal/shell_expression.rb +2 -2
  17. data/lib/glimmer/dsl/opal/widget_listener_expression.rb +18 -0
  18. data/lib/glimmer/opal/div_proxy.rb +14 -0
  19. data/lib/glimmer/opal/{shell.rb → document_proxy.rb} +19 -5
  20. data/lib/glimmer/opal/element_proxy.rb +52 -0
  21. data/lib/glimmer/opal/event_listener_proxy.rb +18 -0
  22. data/lib/glimmer/opal/input_proxy.rb +30 -0
  23. data/lib/glimmer/opal/label_proxy.rb +24 -0
  24. data/lib/glimmer/opal/select_proxy.rb +58 -0
  25. data/lib/samples/elaborate/contact_manager.rb +95 -0
  26. data/lib/samples/elaborate/contact_manager/contact.rb +11 -0
  27. data/lib/samples/elaborate/contact_manager/contact_manager_presenter.rb +36 -0
  28. data/lib/samples/elaborate/contact_manager/contact_repository.rb +244 -0
  29. data/lib/samples/elaborate/launch +6 -0
  30. data/lib/samples/elaborate/login.rb +88 -0
  31. data/lib/samples/elaborate/tic_tac_toe.rb +53 -0
  32. data/lib/samples/elaborate/tic_tac_toe/board.rb +124 -0
  33. data/lib/samples/elaborate/tic_tac_toe/cell.rb +27 -0
  34. data/lib/samples/hello/hello_browser.rb +8 -0
  35. data/lib/samples/hello/hello_combo.rb +34 -0
  36. data/lib/samples/hello/hello_computed.rb +69 -0
  37. data/lib/samples/hello/hello_computed/contact.rb +21 -0
  38. data/lib/samples/hello/hello_list_multi_selection.rb +44 -0
  39. data/lib/samples/hello/hello_list_single_selection.rb +34 -0
  40. data/lib/samples/hello/hello_tab.rb +24 -0
  41. data/lib/samples/hello/hello_world.rb +8 -0
  42. data/lib/samples/hello/launch +10 -0
  43. data/lib/samples/launch +4 -0
  44. metadata +39 -6
  45. data/lib/glimmer/opal/label.rb +0 -31
@@ -1,6 +1,6 @@
1
1
  require 'glimmer/dsl/static_expression'
2
2
  require 'glimmer/dsl/parent_expression'
3
- require 'glimmer/opal/label'
3
+ require 'glimmer/opal/label_proxy'
4
4
 
5
5
  module Glimmer
6
6
  module DSL
@@ -9,7 +9,7 @@ module Glimmer
9
9
  include ParentExpression
10
10
 
11
11
  def interpret(parent, keyword, *args, &block)
12
- Glimmer::Opal::Label.new(parent, args)
12
+ Glimmer::Opal::LabelProxy.new(parent, args)
13
13
  end
14
14
  end
15
15
  end
@@ -7,7 +7,7 @@ module Glimmer
7
7
  include TopLevelExpression
8
8
 
9
9
  def can_interpret?(parent, keyword, *args, &block)
10
- keyword.to_s == 'text'
10
+ parent and keyword and block.nil?
11
11
  end
12
12
 
13
13
  def interpret(parent, keyword, *args, &block)
@@ -1,7 +1,7 @@
1
1
  require 'glimmer/dsl/static_expression'
2
2
  require 'glimmer/dsl/top_level_expression'
3
3
  require 'glimmer/dsl/parent_expression'
4
- require 'glimmer/opal/shell'
4
+ require 'glimmer/opal/document_proxy'
5
5
 
6
6
  module Glimmer
7
7
  module DSL
@@ -11,7 +11,7 @@ module Glimmer
11
11
  include ParentExpression
12
12
 
13
13
  def interpret(parent, keyword, *args, &block)
14
- Glimmer::Opal::Shell.new(args)
14
+ Glimmer::Opal::DocumentProxy.new(args)
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,18 @@
1
+ require 'glimmer/dsl/expression'
2
+
3
+ module Glimmer
4
+ module DSL
5
+ module Opal
6
+ class WidgetListenerExpression < Expression
7
+
8
+ def can_interpret?(parent, keyword, *args, &block)
9
+ keyword.start_with?('on_') and args.empty? and block_given?
10
+ end
11
+
12
+ def interpret(parent, keyword, *args, &block)
13
+ parent.handle_observation_request(keyword, &block)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require 'glimmer/opal/element_proxy'
2
+
3
+ module Glimmer
4
+ module Opal
5
+ class DivProxy < ElementProxy
6
+ def dom
7
+ div_id = id
8
+ @dom ||= DOM {
9
+ div(id: div_id, class: 'grid_layout')
10
+ }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,10 +1,15 @@
1
+ require 'glimmer/opal/element_proxy'
2
+
1
3
  module Glimmer
2
4
  module Opal
3
- class Shell
5
+ class DocumentProxy < ElementProxy
6
+ # TODO consider renaming to ShellProxy to match SWT API
7
+
4
8
  def initialize(args)
5
9
  @args = args
6
10
  @children = []
7
11
  $document.ready do
12
+ $document.head.replace(head_dom)
8
13
  $document.body.replace(dom)
9
14
  end
10
15
  end
@@ -17,10 +22,19 @@ module Glimmer
17
22
  $document.title = value
18
23
  end
19
24
 
20
- def add_child(child)
21
- return if @children.include?(child)
22
- @children << child
23
- dom << child.dom
25
+ def head_dom
26
+ @head_dom ||= DOM {
27
+ head {
28
+ <<~CSS
29
+ <style>
30
+ div.grid_layout > * {
31
+ display: block;
32
+ margin-bottom: 10px;
33
+ }
34
+ </style>
35
+ CSS
36
+ }
37
+ }
24
38
  end
25
39
 
26
40
  def dom
@@ -0,0 +1,52 @@
1
+ module Glimmer
2
+ module Opal
3
+ class ElementProxy
4
+ attr_reader :parent, :args
5
+
6
+ def initialize(parent, args)
7
+ @parent = parent
8
+ @args = args
9
+ @children = []
10
+ @parent.add_child(self)
11
+ end
12
+
13
+ def add_child(child)
14
+ return if @children.include?(child)
15
+ @children << child
16
+ dom << child.dom
17
+ end
18
+
19
+ def redraw
20
+ old_dom = @dom
21
+ @dom = nil
22
+ old_dom.replace dom
23
+ end
24
+
25
+ # Subclasses must override with their own mappings
26
+ def observation_request_to_event_mapping
27
+ {}
28
+ end
29
+
30
+ def name
31
+ self.class.name.split('::').last.underscore.sub(/_proxy$/, '')
32
+ end
33
+
34
+ def id
35
+ "#{name}-#{hash}"
36
+ end
37
+
38
+ # Subclasses can override with their own selector
39
+ def selector
40
+ "#{name}##{id}"
41
+ end
42
+
43
+ def handle_observation_request(keyword, &event_listener)
44
+ event = observation_request_to_event_mapping[keyword][:event]
45
+ event_handler = observation_request_to_event_mapping[keyword][:event_handler]
46
+ event_listener = event_handler&.call(event_listener) || event_listener
47
+ delegate = $document.on(event, selector, &event_listener)
48
+ EventListenerProxy.new(element_proxy: self, event: event, selector: selector, delegate: delegate)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,18 @@
1
+ module Glimmer
2
+ module Opal
3
+ class EventListenerProxy
4
+ attr_reader :element_proxy, :event, :selector, :delegate
5
+
6
+ def initialize(element_proxy:, event:, selector:, delegate:)
7
+ @element_proxy = element_proxy
8
+ @event = event
9
+ @selector = selector
10
+ @delegate = delegate
11
+ end
12
+
13
+ def unregister
14
+ $document.off(@delegate)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ require 'glimmer/opal/element_proxy'
2
+
3
+ module Glimmer
4
+ module Opal
5
+ class InputProxy < ElementProxy
6
+ attr_reader :text
7
+
8
+ def text=(value)
9
+ @text = value
10
+ redraw
11
+ end
12
+
13
+ def observation_request_to_event_mapping
14
+ {
15
+ 'on_widget_selected' => {
16
+ event: 'click'
17
+ }
18
+ }
19
+ end
20
+
21
+ def dom
22
+ input_text = @text
23
+ input_id = id
24
+ @dom ||= DOM {
25
+ input id: input_id, type: 'button', value: input_text
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ require 'glimmer/opal/element_proxy'
2
+
3
+ module Glimmer
4
+ module Opal
5
+ class LabelProxy < ElementProxy
6
+ attr_reader :text
7
+
8
+ def text=(value)
9
+ @text = value
10
+ redraw
11
+ end
12
+
13
+ def dom
14
+ label_text = @text
15
+ label_id = id
16
+ @dom ||= DOM {
17
+ label(id: label_id) {
18
+ label_text
19
+ }
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,58 @@
1
+ require 'glimmer/data_binding/observable_element'
2
+ require 'glimmer/opal/event_listener_proxy'
3
+ require 'glimmer/opal/element_proxy'
4
+
5
+ module Glimmer
6
+ module Opal
7
+ class SelectProxy < ElementProxy
8
+ include Glimmer::DataBinding::ObservableElement
9
+ attr_reader :text, :items
10
+
11
+ def initialize(parent, args)
12
+ super(parent, args)
13
+ @items = []
14
+ end
15
+
16
+ def text=(value)
17
+ @text = value
18
+ redraw
19
+ end
20
+
21
+ def items=(the_items)
22
+ @items = the_items
23
+ redraw
24
+ end
25
+
26
+ def observation_request_to_event_mapping
27
+ {
28
+ 'on_widget_selected' => {
29
+ event: 'change',
30
+ event_handler: -> (event_listener) {
31
+ -> (event) {
32
+ @text = event.target.value
33
+ event_listener.call(event)
34
+ }
35
+ }
36
+ }
37
+ }
38
+ end
39
+
40
+ def dom
41
+ select_text = @text
42
+ items = @items
43
+ select_id = id
44
+ @dom ||= DOM {
45
+ select(id: select_id) {
46
+ items.to_a.each do |item|
47
+ option_hash = {value: item}
48
+ option_hash[:selected] = 'selected' if select_text == item
49
+ option(option_hash) {
50
+ item
51
+ }
52
+ end
53
+ }
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,95 @@
1
+ require_relative "contact_manager/contact_manager_presenter"
2
+
3
+ class ContactManager
4
+ include Glimmer
5
+
6
+ def initialize
7
+ @contact_manager_presenter = ContactManagerPresenter.new
8
+ @contact_manager_presenter.list
9
+ end
10
+
11
+ def launch
12
+ shell {
13
+ text "Contact Manager"
14
+ composite {
15
+ composite {
16
+ grid_layout 2, false
17
+ label {text "First &Name: "}
18
+ text {
19
+ text bind(@contact_manager_presenter, :first_name)
20
+ on_key_pressed {|key_event|
21
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
22
+ }
23
+ }
24
+ label {text "&Last Name: "}
25
+ text {
26
+ text bind(@contact_manager_presenter, :last_name)
27
+ on_key_pressed {|key_event|
28
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
29
+ }
30
+ }
31
+ label {text "&Email: "}
32
+ text {
33
+ text bind(@contact_manager_presenter, :email)
34
+ on_key_pressed {|key_event|
35
+ @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
36
+ }
37
+ }
38
+ composite {
39
+ grid_layout 2, false
40
+ button {
41
+ text "&Find"
42
+ on_widget_selected {
43
+ @contact_manager_presenter.find
44
+ }
45
+ }
46
+ button {
47
+ text "&List All"
48
+ on_widget_selected {
49
+ @contact_manager_presenter.list
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ table(:multi) { |table_proxy|
56
+ layout_data {
57
+ horizontal_alignment :fill
58
+ vertical_alignment :fill
59
+ grab_excess_horizontal_space true
60
+ grab_excess_vertical_space true
61
+ height_hint 200
62
+ }
63
+ table_column {
64
+ text "First Name"
65
+ width 80
66
+ on_widget_selected {
67
+ @contact_manager_presenter.toggle_sort(:first_name)
68
+ }
69
+ }
70
+ table_column {
71
+ text "Last Name"
72
+ width 80
73
+ on_widget_selected {
74
+ @contact_manager_presenter.toggle_sort(:last_name)
75
+ }
76
+ }
77
+ table_column {
78
+ text "Email"
79
+ width 200
80
+ on_widget_selected {
81
+ @contact_manager_presenter.toggle_sort(:email)
82
+ }
83
+ }
84
+ items bind(@contact_manager_presenter, :results),
85
+ column_properties(:first_name, :last_name, :email)
86
+ on_mouse_down { |event|
87
+ table_proxy.edit_table_item(event.table_item, event.column_index)
88
+ }
89
+ }
90
+ }
91
+ }.open
92
+ end
93
+ end
94
+
95
+ ContactManager.new.launch
@@ -0,0 +1,11 @@
1
+ class ContactManager
2
+ class Contact
3
+ attr_accessor :first_name, :last_name, :email
4
+
5
+ def initialize(attribute_map)
6
+ @first_name = attribute_map[:first_name]
7
+ @last_name = attribute_map[:last_name]
8
+ @email = attribute_map[:email]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ require_relative "contact_repository"
2
+
3
+ class ContactManager
4
+ class ContactManagerPresenter
5
+ attr_accessor :results
6
+ @@contact_attributes = [:first_name, :last_name, :email]
7
+ @@contact_attributes.each {|attribute_name| attr_accessor attribute_name}
8
+
9
+ def initialize(contact_repository = nil)
10
+ @contact_repository = contact_repository || ContactRepository.new
11
+ @results = []
12
+ end
13
+
14
+ def list
15
+ self.results = @contact_repository.find({})
16
+ end
17
+
18
+ def find
19
+ filter_map = {}
20
+ @@contact_attributes.each do |attribute_name|
21
+ filter_map[attribute_name] = self.send(attribute_name) if self.send(attribute_name)
22
+ end
23
+ self.results = @contact_repository.find(filter_map)
24
+ @sort_attribute_name = nil
25
+ @sort_direction_ascending = nil
26
+ end
27
+
28
+ def toggle_sort(attribute_name)
29
+ @sort_attribute_name = attribute_name
30
+ @sort_direction_ascending = !@sort_direction_ascending
31
+ sorted_results = self.results.sort_by {|contact| contact.send(attribute_name).downcase}
32
+ sorted_results = sorted_results.reverse unless @sort_direction_ascending
33
+ self.results = sorted_results
34
+ end
35
+ end
36
+ end