glimmer-dsl-opal 0.7.5 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +182 -12
  4. data/VERSION +1 -1
  5. data/lib/glimmer-dsl-opal.rb +8 -0
  6. data/lib/glimmer-dsl-opal/ext/class.rb +10 -0
  7. data/lib/{file.rb → glimmer-dsl-opal/ext/file.rb} +0 -0
  8. data/lib/glimmer-dsl-opal/samples/hello/hello_browser.rb +23 -0
  9. data/lib/glimmer-dsl-opal/samples/hello/hello_computed.rb +27 -0
  10. data/lib/glimmer-dsl-opal/samples/hello/hello_list_multi_selection.rb +62 -32
  11. data/lib/glimmer-dsl-opal/samples/hello/hello_list_single_selection.rb +47 -22
  12. data/lib/glimmer-dsl-opal/samples/hello/hello_message_box.rb +37 -0
  13. data/lib/glimmer-dsl-opal/samples/hello/hello_pop_up_context_menu.rb +84 -0
  14. data/lib/glimmer/data_binding/observable_element.rb +1 -1
  15. data/lib/glimmer/dsl/opal/custom_widget_expression.rb +1 -1
  16. data/lib/glimmer/dsl/opal/dsl.rb +2 -0
  17. data/lib/glimmer/dsl/opal/menu_bar_expression.rb +54 -0
  18. data/lib/glimmer/dsl/opal/menu_expression.rb +61 -0
  19. data/lib/glimmer/dsl/opal/widget_expression.rb +3 -2
  20. data/lib/glimmer/dsl/opal/widget_listener_expression.rb +2 -2
  21. data/lib/glimmer/swt/custom/checkbox_group.rb +2 -2
  22. data/lib/glimmer/swt/custom/radio_group.rb +2 -2
  23. data/lib/glimmer/swt/event_listener_proxy.rb +14 -4
  24. data/lib/glimmer/swt/grid_layout_proxy.rb +1 -0
  25. data/lib/glimmer/swt/label_proxy.rb +6 -3
  26. data/lib/glimmer/swt/list_proxy.rb +33 -0
  27. data/lib/glimmer/swt/menu_item_proxy.rb +87 -0
  28. data/lib/glimmer/swt/menu_proxy.rb +162 -0
  29. data/lib/glimmer/swt/message_box_proxy.rb +51 -57
  30. data/lib/glimmer/swt/property_owner.rb +2 -0
  31. data/lib/glimmer/swt/radio_proxy.rb +1 -1
  32. data/lib/glimmer/swt/shell_proxy.rb +32 -187
  33. data/lib/glimmer/swt/tab_folder_proxy.rb +43 -0
  34. data/lib/glimmer/swt/table_column_proxy.rb +3 -2
  35. data/lib/glimmer/swt/table_editor.rb +1 -1
  36. data/lib/glimmer/swt/table_item_proxy.rb +7 -5
  37. data/lib/glimmer/swt/table_proxy.rb +10 -0
  38. data/lib/glimmer/swt/widget_proxy.rb +313 -30
  39. data/lib/glimmer/ui/custom_shell.rb +1 -1
  40. data/lib/glimmer/ui/custom_widget.rb +3 -3
  41. metadata +20 -7
@@ -11,6 +11,7 @@ module Glimmer
11
11
  align-items: stretch;
12
12
  }
13
13
  CSS
14
+
14
15
  attr_reader :num_columns, :make_columns_equal_width, :horizontal_spacing, :vertical_spacing, :margin_width, :margin_height
15
16
 
16
17
  def initialize(parent, args)
@@ -12,7 +12,11 @@ module Glimmer
12
12
 
13
13
  def text=(value)
14
14
  @text = value
15
- dom_element.html(value)
15
+ dom_element.html(html_text)
16
+ end
17
+
18
+ def html_text
19
+ text.gsub("\n", '<br />')
16
20
  end
17
21
 
18
22
  def background_image=(*image_options)
@@ -48,12 +52,11 @@ module Glimmer
48
52
  end
49
53
 
50
54
  def dom
51
- label_text = @text
52
55
  label_id = id
53
56
  label_class = name
54
57
  @dom ||= html {
55
58
  label(id: label_id, class: label_class, style: "text-align: #{alignment};") {
56
- label_text
59
+ html_text
57
60
  }
58
61
  }.to_s
59
62
  end
@@ -3,6 +3,39 @@ require 'glimmer/swt/widget_proxy'
3
3
  module Glimmer
4
4
  module SWT
5
5
  class ListProxy < WidgetProxy
6
+ STYLE = <<~CSS
7
+ ul {
8
+ list-style: none;
9
+ padding: 0;
10
+ }
11
+ li {
12
+ cursor: default;
13
+ padding-left: 10px;
14
+ padding-right: 10px;
15
+ }
16
+ li.menu-item {
17
+ padding-left: initial;
18
+ padding-right: initial;
19
+ }
20
+ .ui-menu {
21
+ /* TODO consider auto-sizing in the future */
22
+ font-size: initial;
23
+ width: 150px;
24
+ border-radius: 5px;
25
+ }
26
+ .ui-menu-item:first-child > .ui-menu-item-wrapper {
27
+ border-top-left-radius: 5px;
28
+ border-top-right-radius: 5px;
29
+ }
30
+ .ui-menu-item:last-child > .ui-menu-item-wrapper {
31
+ border-bottom-left-radius: 5px;
32
+ border-bottom-right-radius: 5px;
33
+ }
34
+ li.empty-list-item {
35
+ color: transparent;
36
+ }
37
+ CSS
38
+
6
39
  ITEM_EMPTY = '_____'
7
40
  attr_reader :items, :selection
8
41
 
@@ -0,0 +1,87 @@
1
+ # Copyright (c) 2020 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # TODO implement set_menu or self.menu=
23
+
24
+ require 'glimmer/swt/widget_proxy'
25
+
26
+ module Glimmer
27
+ module SWT
28
+ # Proxy for org.eclipse.swt.widgets.MenuItem
29
+ #
30
+ # Follows the Proxy Design Pattern since it's a proxy for an HTML based menu
31
+ # Follows the Adapter Design Pattern since it's adapting a Glimmer DSL for SWT widget
32
+ class MenuItemProxy < WidgetProxy
33
+ def post_initialize_child(child)
34
+ @children << child
35
+ end
36
+
37
+ def text
38
+ @text
39
+ end
40
+
41
+ def text=(value)
42
+ @text = value
43
+ dom_element.html(html {div {value}}.to_s)
44
+ @text
45
+ end
46
+
47
+ def root_menu
48
+ the_menu = parent
49
+ the_menu = the_menu.parent_menu until the_menu.root_menu?
50
+ the_menu
51
+ end
52
+
53
+ def skip_content_on_render_blocks?
54
+ true
55
+ end
56
+
57
+ def observation_request_to_event_mapping
58
+ {
59
+ 'on_widget_selected' => {
60
+ event: 'mouseup',
61
+ event_handler: -> (event_listener) {
62
+ -> (event) {
63
+ remove_event_listener_proxies
64
+ root_menu.close
65
+ event_listener.call(event)
66
+ }
67
+ },
68
+ },
69
+ }
70
+ end
71
+
72
+ def element
73
+ 'li'
74
+ end
75
+
76
+ def dom
77
+ @dom ||= html {
78
+ li(id: id, class: name) {
79
+ div {
80
+ @text
81
+ }
82
+ }
83
+ }.to_s
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,162 @@
1
+ # Copyright (c) 2020 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/swt/widget_proxy'
23
+ require 'glimmer/swt/menu_item_proxy'
24
+
25
+ module Glimmer
26
+ module SWT
27
+ # Proxy for org.eclipse.swt.widgets.Menu
28
+ #
29
+ # Functions differently from other widget proxies.
30
+ #
31
+ # Glimmer automatically detects if this is a drop down menu
32
+ # or pop up menu from its parent if no SWT style is passed in.
33
+ #
34
+ # There are 3 possibilities:
35
+ # - SWT :bar style is passed in: Menu Bar
36
+ # - Parent is ShellProxy: Pop Up Menu (having style :pop_up)
37
+ # - Parent is another Menu: Drop Down Menu (having style :drop_down)
38
+ #
39
+ # In order to get the SWT Menu object, one must call `#swt_widget`.
40
+ #
41
+ # In the case of a Drop Down menu, this automatically creates an
42
+ # SWT MenuItem object with style :cascade
43
+ #
44
+ # In order to retrieve the menu item widget proxy, one must call `#menu_item_proxy`
45
+ #
46
+ # Follows the Proxy Design Pattern
47
+ class MenuProxy < WidgetProxy
48
+ attr_reader :menu_item_proxy, :menu_parent
49
+
50
+ def initialize(parent, args)
51
+ # TODO handle :bar swt style
52
+ # TODO handle :pop_up swt style
53
+ # TODO handle :cascade swt style
54
+ @children = []
55
+ index = args.delete(args.last) if args.last.is_a?(Numeric)
56
+ styles = args.map(&:to_sym)
57
+ if !styles.include?(:bar) && !parent.is_a?(MenuProxy)
58
+ styles = styles.unshift(:pop_up)
59
+ end
60
+
61
+ if parent.is_a?(MenuProxy)
62
+ @menu_item_proxy = SWT::WidgetProxy.for('menu_item', parent, [:cascade] + [index].compact)
63
+ super(@menu_item_proxy)
64
+ @menu_item_proxy.menu = self
65
+ elsif parent.is_a?(ShellProxy)
66
+ super(parent, style('menu', styles))
67
+ else
68
+ super(parent)
69
+ end
70
+
71
+ if styles.include?(:bar)
72
+ # Assumes a parent shell
73
+ parent.menu_bar = self
74
+ elsif styles.include?(:pop_up)
75
+ parent.menu = self
76
+ end
77
+ # TODO IMPLEMENT PROPERLY
78
+ # on_focus_lost {
79
+ # dispose
80
+ # }
81
+ end
82
+
83
+ def text
84
+ @menu_item_proxy&.text
85
+ end
86
+
87
+ def text=(text_value)
88
+ @menu_item_proxy&.text = text_value
89
+ end
90
+
91
+ def can_handle_observation_request?(observation_request, super_only: false)
92
+ super_result = super(observation_request)
93
+ if observation_request.start_with?('on_') && !super_result && !super_only
94
+ return menu_item_proxy.can_handle_observation_request?(observation_request)
95
+ else
96
+ super_result
97
+ end
98
+ end
99
+
100
+ def handle_observation_request(observation_request, block)
101
+ if can_handle_observation_request?(observation_request, super_only: true)
102
+ super
103
+ else
104
+ menu_item_proxy.handle_observation_request(observation_request, block)
105
+ end
106
+ end
107
+
108
+ def post_initialize_child(child)
109
+ if child && !@children.include?(child)
110
+ if child.is_a?(MenuItemProxy)
111
+ @children << child
112
+ else
113
+ @children << child.menu_item_proxy
114
+ end
115
+ end
116
+ end
117
+
118
+ def render
119
+ # TODO attach to top nav bar if parent is shell
120
+ # TODO attach listener to parent to display on right click
121
+ if parent.is_a?(MenuProxy) || parent.is_a?(MenuItemProxy) || parent.menu_requested?
122
+ super
123
+ if root_menu?
124
+ id_css = "##{id}"
125
+ `$(#{id_css}).menu();`
126
+ @close_event_handler = lambda do |event|
127
+ if event.target.parents('.ui-menu').empty?
128
+ close
129
+ end
130
+ end
131
+ Element['body'].on('click', &@close_event_handler)
132
+ @menu_initialized = true
133
+ end
134
+ end
135
+ end
136
+
137
+ def close
138
+ dom_element.remove
139
+ Element['body'].off('click', &@close_event_handler)
140
+ end
141
+
142
+ def root_menu?
143
+ !parent.is_a?(MenuProxy) && !parent.is_a?(MenuItemProxy)
144
+ end
145
+
146
+ def parent_menu
147
+ parent.parent unless root_menu?
148
+ end
149
+
150
+ def element
151
+ 'ul'
152
+ end
153
+
154
+ def dom
155
+ @dom ||= html {
156
+ ul(id: id, class: name) {
157
+ }
158
+ }.to_s
159
+ end
160
+ end
161
+ end
162
+ end
@@ -4,6 +4,49 @@ require 'glimmer/swt/display_proxy'
4
4
  module Glimmer
5
5
  module SWT
6
6
  class MessageBoxProxy < WidgetProxy
7
+ STYLE = <<~CSS
8
+ .modal {
9
+ position: fixed;
10
+ z-index: 1;
11
+ padding-top: 100px;
12
+ left: 0;
13
+ top: 0;
14
+ width: 100%;
15
+ height: 100%;
16
+ overflow: auto;
17
+ background-color: rgb(0,0,0);
18
+ background-color: rgba(0,0,0,0.4);
19
+ text-align: center;
20
+ }
21
+ .modal-content .text {
22
+ background: rgb(80, 116, 211);
23
+ color: white;
24
+ padding: 5px;
25
+ }
26
+ .modal-content .message {
27
+ padding: 20px;
28
+ }
29
+ .modal-content {
30
+ background-color: #fefefe;
31
+ padding-bottom: 15px;
32
+ border: 1px solid #888;
33
+ display: inline-block;
34
+ min-width: 200px;
35
+ }
36
+ CSS
37
+ # .close {
38
+ # color: #aaaaaa;
39
+ # float: right;
40
+ # font-weight: bold;
41
+ # margin: 5px;
42
+ # }
43
+ # .close:hover,
44
+ # .close:focus {
45
+ # color: #000;
46
+ # text-decoration: none;
47
+ # cursor: pointer;
48
+ # }
49
+
7
50
  attr_reader :text, :message
8
51
 
9
52
  def initialize(parent, args, block)
@@ -25,9 +68,13 @@ module Glimmer
25
68
  dom_element.find('.modal-content .text').html(@text)
26
69
  end
27
70
 
71
+ def html_message
72
+ message.gsub("\n", '<br />')
73
+ end
74
+
28
75
  def message=(msg)
29
76
  @message = msg
30
- dom_element.find('.modal-content .message').html(@text)
77
+ dom_element.find('.modal-content .message').html(html_message)
31
78
  end
32
79
 
33
80
  def open
@@ -62,68 +109,15 @@ module Glimmer
62
109
  }
63
110
  end
64
111
 
65
- def style_dom_modal_css
66
- <<~CSS
67
- .modal {
68
- position: fixed;
69
- z-index: 1;
70
- padding-top: 100px;
71
- left: 0;
72
- top: 0;
73
- width: 100%;
74
- height: 100%;
75
- overflow: auto;
76
- background-color: rgb(0,0,0);
77
- background-color: rgba(0,0,0,0.4);
78
- text-align: center;
79
- }
80
- .modal-content .text {
81
- background: rgb(80, 116, 211);
82
- color: white;
83
- padding: 5px;
84
- }
85
- .modal-content .message {
86
- padding: 20px;
87
- }
88
- .modal-content {
89
- background-color: #fefefe;
90
- padding-bottom: 15px;
91
- border: 1px solid #888;
92
- display: inline-block;
93
- min-width: 200px;
94
- }
95
- CSS
96
- # .close {
97
- # color: #aaaaaa;
98
- # float: right;
99
- # font-weight: bold;
100
- # margin: 5px;
101
- # }
102
- # .close:hover,
103
- # .close:focus {
104
- # color: #000;
105
- # text-decoration: none;
106
- # cursor: pointer;
107
- # }
108
- end
109
-
110
112
  def dom
111
- modal_id = id
112
- modal_style = css
113
- modal_text = text
114
- modal_message = message
115
- modal_class = ['modal', name].join(' ')
116
113
  @dom ||= html {
117
- div(id: modal_id, style: modal_style, class: modal_class) {
118
- style(class: 'modal-style') {
119
- style_dom_modal_css #.split("\n").map(&:strip).join(' ')
120
- }
114
+ div(id: id, class: "modal #{name}") {
121
115
  div(class: 'modal-content') {
122
116
  header(class: 'text') {
123
- modal_text
117
+ text
124
118
  }
125
119
  tag(_name: 'p', id: 'message', class: 'message') {
126
- modal_message
120
+ html_message
127
121
  }
128
122
  input(type: 'button', class: 'close', autofocus: 'autofocus', value: 'OK')
129
123
  }