glimmer-dsl-opal 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/README.md +453 -48
  4. data/VERSION +1 -1
  5. data/lib/display.rb +31 -0
  6. data/lib/glimmer-dsl-opal.rb +15 -36
  7. data/lib/glimmer-dsl-opal/ext/class.rb +10 -0
  8. data/lib/glimmer-dsl-opal/ext/file.rb +29 -0
  9. data/lib/glimmer-dsl-opal/ext/struct.rb +37 -0
  10. data/lib/glimmer-dsl-opal/samples/elaborate/contact_manager.rb +50 -23
  11. data/lib/glimmer-dsl-opal/samples/elaborate/login.rb +22 -5
  12. data/lib/glimmer-dsl-opal/samples/hello/hello_browser.rb +24 -1
  13. data/lib/glimmer-dsl-opal/samples/hello/hello_button.rb +46 -0
  14. data/lib/glimmer-dsl-opal/samples/hello/hello_computed.rb +27 -0
  15. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_shell.rb +7 -7
  16. data/lib/glimmer-dsl-opal/samples/hello/hello_list_multi_selection.rb +62 -32
  17. data/lib/glimmer-dsl-opal/samples/hello/hello_list_single_selection.rb +47 -22
  18. data/lib/glimmer-dsl-opal/samples/hello/hello_message_box.rb +37 -0
  19. data/lib/glimmer-dsl-opal/samples/hello/hello_pop_up_context_menu.rb +84 -0
  20. data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +2 -2
  21. data/lib/glimmer/data_binding/observable_element.rb +1 -1
  22. data/lib/glimmer/data_binding/table_items_binding.rb +3 -3
  23. data/lib/glimmer/dsl/opal/custom_widget_expression.rb +6 -0
  24. data/lib/glimmer/dsl/opal/dsl.rb +2 -0
  25. data/lib/glimmer/dsl/opal/menu_bar_expression.rb +54 -0
  26. data/lib/glimmer/dsl/opal/menu_expression.rb +61 -0
  27. data/lib/glimmer/dsl/opal/widget_expression.rb +3 -2
  28. data/lib/glimmer/dsl/opal/widget_listener_expression.rb +2 -2
  29. data/lib/glimmer/swt/combo_proxy.rb +40 -1
  30. data/lib/glimmer/swt/control_editor.rb +2 -1
  31. data/lib/glimmer/swt/custom/checkbox_group.rb +2 -2
  32. data/lib/glimmer/swt/custom/radio_group.rb +2 -2
  33. data/lib/glimmer/swt/date_time_proxy.rb +66 -1
  34. data/lib/glimmer/swt/event_listener_proxy.rb +14 -4
  35. data/lib/glimmer/swt/font_proxy.rb +4 -4
  36. data/lib/glimmer/swt/grid_layout_proxy.rb +21 -12
  37. data/lib/glimmer/swt/label_proxy.rb +17 -6
  38. data/lib/glimmer/swt/layout_data_proxy.rb +10 -7
  39. data/lib/glimmer/swt/list_proxy.rb +33 -0
  40. data/lib/glimmer/swt/menu_item_proxy.rb +87 -0
  41. data/lib/glimmer/swt/menu_proxy.rb +162 -0
  42. data/lib/glimmer/swt/message_box_proxy.rb +53 -67
  43. data/lib/glimmer/swt/property_owner.rb +2 -0
  44. data/lib/glimmer/swt/radio_proxy.rb +1 -1
  45. data/lib/glimmer/swt/shell_proxy.rb +32 -187
  46. data/lib/glimmer/swt/tab_folder_proxy.rb +43 -0
  47. data/lib/glimmer/swt/table_column_proxy.rb +4 -3
  48. data/lib/glimmer/swt/table_editor.rb +2 -2
  49. data/lib/glimmer/swt/table_item_proxy.rb +15 -5
  50. data/lib/glimmer/swt/table_proxy.rb +34 -12
  51. data/lib/glimmer/swt/text_proxy.rb +1 -1
  52. data/lib/glimmer/swt/widget_proxy.rb +335 -38
  53. data/lib/glimmer/ui/custom_shell.rb +9 -7
  54. data/lib/glimmer/ui/custom_widget.rb +3 -3
  55. data/lib/os.rb +36 -0
  56. metadata +36 -3
@@ -2,6 +2,8 @@ module Glimmer
2
2
  module SWT
3
3
  # Adapts Glimmer UI classes to SWT JavaBean property owner classes (which are now adapted to Opal)
4
4
  module PropertyOwner
5
+ # TODO consider adding has_attribute?
6
+
5
7
  def get_attribute(attribute_name)
6
8
  send(attribute_getter(attribute_name))
7
9
  end
@@ -4,7 +4,7 @@ module Glimmer
4
4
  module SWT
5
5
  class RadioProxy < WidgetProxy
6
6
  # TODO add a create method that ensures passing :radio style in if not there
7
- STYLE=<<~CSS
7
+ STYLE = <<~CSS
8
8
  .radio {
9
9
  display: inline;
10
10
  }
@@ -1,12 +1,34 @@
1
1
  require 'glimmer/swt/widget_proxy'
2
+ require 'glimmer/swt/layout_proxy'
2
3
  require 'glimmer/swt/display_proxy'
3
4
  require 'glimmer/swt/point'
4
5
 
5
6
  module Glimmer
6
7
  module SWT
7
8
  class ShellProxy < CompositeProxy
9
+ STYLE = <<~CSS
10
+ html {
11
+ width: 100%;
12
+ height: 100%;
13
+ }
14
+ body {
15
+ width: 100%;
16
+ height: 100%;
17
+ margin: 0;
18
+ }
19
+ .shell {
20
+ height: 100%;
21
+ margin: 0;
22
+ }
23
+ .shell iframe {
24
+ width: 100%;
25
+ height: 100%;
26
+ }
27
+ CSS
28
+
8
29
  # TODO consider renaming to ShellProxy to match SWT API
9
30
  attr_reader :minimum_size
31
+ attr_accessor :menu_bar # TODO implement menu bar rendering
10
32
 
11
33
  WIDTH_MIN = 130
12
34
  HEIGHT_MIN = 0
@@ -52,208 +74,31 @@ module Glimmer
52
74
  .hide {
53
75
  display: none !important;
54
76
  }
55
- .selected, .tabs .tab.selected {
77
+ .selected {
56
78
  background: rgb(80, 116, 211);
57
79
  color: white;
58
80
  }
59
81
  CSS
60
82
  end
61
83
 
62
- def style_dom_shell_css
63
- <<~CSS
64
- html {
65
- width: 100%;
66
- height: 100%;
67
- }
68
- body {
69
- width: 100%;
70
- height: 100%;
71
- margin: 0;
72
- }
73
- .shell {
74
- height: 100%;
75
- margin: 0;
76
- }
77
- .shell iframe {
78
- width: 100%;
79
- height: 100%;
80
- }
81
- CSS
82
- end
83
-
84
- def style_dom_list_css
85
- <<~CSS
86
- ul {
87
- list-style: none;
88
- padding: 0;
89
- }
90
- li {
91
- cursor: default;
92
- padding-left: 10px;
93
- padding-right: 10px;
94
- }
95
- li.empty-list-item {
96
- color: transparent;
97
- }
98
- CSS
99
- end
100
-
101
- def style_dom_tab_css
102
- <<~CSS
103
- .tabs .tab {
104
- background-color: inherit;
105
- float: left;
106
- border: none;
107
- outline: none;
108
- cursor: pointer;
109
- padding: 14px 16px;
110
- transition: 0.3s;
111
- font-size: 17px;
112
- }
113
- .tabs {
114
- overflow: hidden;
115
- border: 1px solid #ccc;
116
- background-color: #f1f1f1;
117
- }
118
- CSS
119
- end
120
-
121
- def style_dom_tab_item_css
122
- <<~CSS
123
- /* Create an selected/current tablink class */
124
- .tabs .tab.selected {
125
- background-color: #ccc;
126
- }
127
- /* Change background color of buttons on hover */
128
- .tabs .tab:hover {
129
- background-color: #ddd;
130
- }
131
- /* Style the tab content */
132
- .tab-item {
133
- padding: 6px 12px;
134
- border: 1px solid #ccc;
135
- border-top: none;
136
- }
137
- CSS
138
- end
139
-
140
- def style_dom_modal_css
141
- <<~CSS
142
- /* The Modal (background) */
143
- .modal {
144
- position: fixed; /* Stay in place */
145
- z-index: 1; /* Sit on top */
146
- padding-top: 100px; /* Location of the box */
147
- left: 0;
148
- top: 0;
149
- width: 100%; /* Full width */
150
- height: 100%; /* Full height */
151
- overflow: auto; /* Enable scroll if needed */
152
- background-color: rgb(0,0,0); /* Fallback color */
153
- background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
154
- text-align: center;
155
- }
156
-
157
- /* Modal Content */
158
- .modal-content {
159
- background-color: #fefefe;
160
- margin: auto;
161
- border: 1px solid #888;
162
- display: inline-block;
163
- min-width: 200px;
164
- }
165
-
166
- .modal-content .text {
167
- background: rgb(80, 116, 211);
168
- color: white;
169
- padding: 5px;
170
- }
171
-
172
- .modal-content .message {
173
- padding: 20px;
174
- }
175
-
176
- /* The Close Button */
177
- .close {
178
- color: #aaaaaa;
179
- float: right;
180
- font-weight: bold;
181
- margin: 5px;
182
- }
183
-
184
- .close:hover,
185
- .close:focus {
186
- color: #000;
187
- text-decoration: none;
188
- cursor: pointer;
189
- }
190
- CSS
191
- end
192
-
193
- def style_dom_table_css
194
- <<~CSS
195
- table {
196
- border-spacing: 0;
197
- }
198
-
199
- table tr th,td {
200
- cursor: default;
201
- }
202
- CSS
203
- end
204
-
205
84
  def dom
206
85
  i = 0
207
86
  body_id = id
208
87
  body_class = ([name] + css_classes.to_a).join(' ')
209
88
  @dom ||= html {
210
89
  div(id: body_id, class: body_class) {
211
- # TODO support the idea of dynamic CSS building on close of shell that adds only as much CSS as needed for widgets that were mentioned
90
+ # TODO consider supporting the idea of dynamic CSS building on close of shell that adds only as much CSS as needed for widgets that were mentioned
212
91
  style(class: 'common-style') {
213
92
  style_dom_css
214
93
  }
215
- style(class: 'shell-style') {
216
- style_dom_shell_css
217
- }
218
- style(class: 'list-style') {
219
- style_dom_list_css
220
- }
221
- style(class: 'tab-style') {
222
- style_dom_tab_css
223
- }
224
- # style(class: 'tab-item-style') {
225
- # style_dom_tab_item_css
226
- # }
227
- # style(class: 'modal-style') {
228
- # style_dom_modal_css
229
- # }
230
- style(class: 'table-style') {
231
- style_dom_table_css
232
- }
233
- style(class: 'fill-layout-style') {
234
- Glimmer::SWT::FillLayoutProxy::STYLE
235
- }
236
- style(class: 'row-layout-style') {
237
- Glimmer::SWT::RowLayoutProxy::STYLE
238
- }
239
- style(class: 'grid-layout-style') {
240
- Glimmer::SWT::GridLayoutProxy::STYLE
241
- }
242
- style(class: 'checkbox-style') {
243
- Glimmer::SWT::CheckboxProxy::STYLE
244
- }
245
- style(class: 'radio-style') {
246
- Glimmer::SWT::RadioProxy::STYLE
247
- }
248
- style(class: 'scrolled-composite-style') {
249
- Glimmer::SWT::ScrolledCompositeProxy::STYLE
250
- }
251
- style(class: 'table-item-style') {
252
- Glimmer::SWT::TableItemProxy::STYLE
253
- }
254
- style(class: 'table-column-style') {
255
- Glimmer::SWT::TableColumnProxy::STYLE
256
- }
94
+ [LayoutProxy, WidgetProxy].map(&:descendants).reduce(:+).each do |style_class|
95
+ if style_class.constants.include?('STYLE')
96
+ style(class: "#{style_class.name.split(':').last.underscore.gsub('_', '-').sub(/-proxy$/, '')}-style") {
97
+ style_class::STYLE
98
+ }
99
+ end
100
+ end
101
+ ''
257
102
  }
258
103
  }.to_s
259
104
  end
@@ -1,8 +1,51 @@
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
+
1
22
  require 'glimmer/swt/widget_proxy'
2
23
 
3
24
  module Glimmer
4
25
  module SWT
5
26
  class TabFolderProxy < WidgetProxy
27
+ STYLE = <<~CSS
28
+ .tabs .tab.selected {
29
+ background: rgb(80, 116, 211);
30
+ color: white;
31
+ }
32
+ .tabs .tab {
33
+ background-color: inherit;
34
+ float: left;
35
+ border: none;
36
+ outline: none;
37
+ cursor: pointer;
38
+ padding: 14px 16px;
39
+ transition: 0.3s;
40
+ font-size: 17px;
41
+ }
42
+ .tabs {
43
+ overflow: hidden;
44
+ border: 1px solid #ccc;
45
+ background-color: #f1f1f1;
46
+ }
47
+ CSS
48
+
6
49
  attr_reader :tabs
7
50
 
8
51
  def initialize(parent, args, block)
@@ -4,6 +4,8 @@ require 'glimmer/swt/swt_proxy'
4
4
  module Glimmer
5
5
  module SWT
6
6
  class TableColumnProxy < WidgetProxy
7
+ include Glimmer
8
+
7
9
  STYLE = <<~CSS
8
10
  th.table-column {
9
11
  background: rgb(246, 246, 246);
@@ -15,8 +17,7 @@ module Glimmer
15
17
  float: right;
16
18
  }
17
19
  CSS
18
- include Glimmer
19
-
20
+
20
21
  attr_accessor :sort_block, :sort_by_block
21
22
  attr_reader :text, :width,
22
23
  :no_sort, :sort_property, :editor
@@ -75,7 +76,7 @@ module Glimmer
75
76
  end
76
77
 
77
78
  # Sets editor (e.g. combo)
78
- def editor=(args)
79
+ def editor=(*args)
79
80
  @editor = args
80
81
  end
81
82
 
@@ -34,10 +34,10 @@ module Glimmer
34
34
  @editor_widget = editor_widget
35
35
  @old_value = table_item.cell_dom_element(table_column_index).html
36
36
  table_item.cell_dom_element(table_column_index).html('')
37
- editor_widget.render(table_item.cell_dom_element(table_column_index))
37
+ editor_widget.render(custom_parent_dom_element: table_item.cell_dom_element(table_column_index))
38
38
  # TODO tweak the width perfectly so it doesn't expand the table cell
39
39
  # editor_widget.dom_element.css('width', 'calc(100% - 20px)')
40
- editor_widget.dom_element.css('width', '90%') # just a good enough approximation
40
+ editor_widget.dom_element.css('width', "#{minimumWidth}%") # TODO implement property with pixels (and perhaps derive percentage separately from pixels)
41
41
  editor_widget.dom_element.css('height', "#{minimumHeight}px")
42
42
  editor_widget.dom_element.add_class('table-editor')
43
43
  # TODO consider relying on autofocus instead
@@ -39,7 +39,7 @@ module Glimmer
39
39
  super(parent, args, block)
40
40
  # TODO check if there is a need to remove this observer when removing widget from table upon items update
41
41
  on_widget_selected { |event|
42
- parent.select(parent.index_of(self), event.meta?)
42
+ parent.select(parent.index_of(self), (event.meta? if event.respond_to?(:meta?)))
43
43
  }
44
44
  end
45
45
 
@@ -139,10 +139,20 @@ module Glimmer
139
139
  redraw
140
140
  end
141
141
 
142
- def on_widget_selected(&block)
143
- event = 'click'
144
- delegate = $document.on(event, selector, &block)
145
- EventListenerProxy.new(element_proxy: self, event: event, selector: selector, delegate: delegate)
142
+ def redraw_selection
143
+ if parent.selection.include?(self)
144
+ dom_element.add_class('selected')
145
+ else
146
+ dom_element.remove_class('selected')
147
+ end
148
+ end
149
+
150
+ def observation_request_to_event_mapping
151
+ {
152
+ 'on_widget_selected' => {
153
+ event: 'mouseup',
154
+ }
155
+ }
146
156
  end
147
157
 
148
158
  def max_column_width(column_index)
@@ -27,6 +27,16 @@ require 'glimmer/swt/table_editor'
27
27
  module Glimmer
28
28
  module SWT
29
29
  class TableProxy < CompositeProxy
30
+ STYLE = <<~CSS
31
+ table {
32
+ border-spacing: 0;
33
+ }
34
+
35
+ table tr th,td {
36
+ cursor: default;
37
+ }
38
+ CSS
39
+
30
40
  attr_reader :columns, :selection,
31
41
  :sort_type, :sort_column, :sort_property, :sort_block, :sort_by_block, :additional_sort_properties,
32
42
  :editor, :table_editor
@@ -43,6 +53,7 @@ module Glimmer
43
53
  text: {
44
54
  widget_value_property: :text,
45
55
  editor_gui: lambda do |args, model, property, table_proxy|
56
+ table_proxy.table_editor.minimumWidth = 90
46
57
  table_proxy.table_editor.minimumHeight = 10
47
58
  table_editor_widget_proxy = text(*args) {
48
59
  text model.send(property)
@@ -66,6 +77,7 @@ module Glimmer
66
77
  widget_value_property: :text,
67
78
  editor_gui: lambda do |args, model, property, table_proxy|
68
79
  first_time = true
80
+ table_proxy.table_editor.minimumWidth = 90
69
81
  table_proxy.table_editor.minimumHeight = 18
70
82
  table_editor_widget_proxy = combo(*args) {
71
83
  items model.send("#{property}_options")
@@ -118,11 +130,12 @@ module Glimmer
118
130
  widget_value_property: :date_time,
119
131
  editor_gui: lambda do |args, model, property, table_proxy|
120
132
  first_time = true
121
- table_proxy.table_editor.minimumHeight = 25
133
+ table_proxy.table_editor.minimumWidth = 90
134
+ table_proxy.table_editor.minimumHeight = 15
122
135
  date(*args) {
123
136
  date_time model.send(property)
124
137
  focus true
125
- on_focus_lost {
138
+ on_widget_selected {
126
139
  table_proxy.finish_edit!
127
140
  }
128
141
  on_key_pressed { |key_event|
@@ -139,11 +152,12 @@ module Glimmer
139
152
  widget_value_property: :date_time,
140
153
  editor_gui: lambda do |args, model, property, table_proxy|
141
154
  first_time = true
142
- table_proxy.table_editor.minimumHeight = 25
155
+ table_proxy.table_editor.minimumWidth = 80
156
+ table_proxy.table_editor.minimumHeight = 15
143
157
  date_drop_down(*args) {
144
158
  date_time model.send(property)
145
159
  focus true
146
- on_focus_lost {
160
+ on_widget_selected {
147
161
  table_proxy.finish_edit!
148
162
  }
149
163
  on_key_pressed { |key_event|
@@ -160,10 +174,14 @@ module Glimmer
160
174
  widget_value_property: :date_time,
161
175
  editor_gui: lambda do |args, model, property, table_proxy|
162
176
  first_time = true
163
- table_proxy.table_editor.minimumHeight = 25
177
+ table_proxy.table_editor.minimumWidth = 80
178
+ table_proxy.table_editor.minimumHeight = 15
164
179
  time(*args) {
165
180
  date_time model.send(property)
166
181
  focus true
182
+ on_widget_selected {
183
+ table_proxy.finish_edit!
184
+ }
167
185
  on_focus_lost {
168
186
  table_proxy.finish_edit!
169
187
  }
@@ -236,6 +254,7 @@ module Glimmer
236
254
  @table_editor = TableEditor.new(self)
237
255
  @table_editor.horizontalAlignment = SWTProxy[:left]
238
256
  @table_editor.grabHorizontal = true
257
+ @table_editor.minimumWidth = 90
239
258
  @table_editor.minimumHeight = 20
240
259
  if editable?
241
260
  on_mouse_up { |event|
@@ -300,11 +319,12 @@ module Glimmer
300
319
  new_selection = new_selection.to_a
301
320
  changed = (selection + new_selection) - (selection & new_selection)
302
321
  @selection = new_selection
303
- changed.each(&:redraw)
322
+ changed.each(&:redraw_selection)
304
323
  end
305
324
 
306
325
  def items=(new_items)
307
326
  @children = new_items
327
+ # TODO optimize in the future by sorting elements in DOM directly when no change to elements occur other than sort
308
328
  redraw
309
329
  end
310
330
 
@@ -346,7 +366,7 @@ module Glimmer
346
366
  end
347
367
 
348
368
  def sort_property=(new_sort_property)
349
- @sort_property = [new_sort_property].flatten.compact
369
+ @sort_property = new_sort_property.to_collection
350
370
  end
351
371
 
352
372
  def detect_sort_type
@@ -367,7 +387,7 @@ module Glimmer
367
387
 
368
388
  def column_sort_properties
369
389
  column_properties.zip(columns.map(&:sort_property)).map do |pair|
370
- [pair.compact.last].flatten.compact
390
+ pair.compact.last.to_collection
371
391
  end
372
392
  end
373
393
 
@@ -398,7 +418,7 @@ module Glimmer
398
418
  end
399
419
  end
400
420
 
401
- new_sort_property = [new_sort_property].flatten.compact unless new_sort_property.is_a?(Array)
421
+ new_sort_property = new_sort_property.to_collection unless new_sort_property.is_a?(Array)
402
422
  @sort_direction = @sort_direction.nil? || @sort_property.first != new_sort_property.first || @sort_direction == :descending ? :ascending : :descending
403
423
 
404
424
  @sort_property = new_sort_property
@@ -504,7 +524,7 @@ module Glimmer
504
524
  @edit_mode = true
505
525
 
506
526
  editor_config = columns[column_index].editor || editor
507
- editor_config = [editor_config].flatten.compact
527
+ editor_config = editor_config.to_collection
508
528
  editor_widget_options = editor_config.last.is_a?(Hash) ? editor_config.last : {}
509
529
  editor_widget_arg_last_index = editor_config.last.is_a?(Hash) ? -2 : -1
510
530
  editor_widget = (editor_config[0] || :text).to_sym
@@ -604,7 +624,8 @@ module Glimmer
604
624
  event.singleton_class.send(:define_method, :column_index) do
605
625
  (table_data || event.target).attr('data-column-index')
606
626
  end
607
- event_listener.call(event)
627
+
628
+ event_listener.call(event) unless event.table_item.nil? && event.column_index.nil?
608
629
  }
609
630
  }
610
631
 
@@ -619,7 +640,8 @@ module Glimmer
619
640
  },
620
641
  'on_widget_selected' => {
621
642
  event: 'mouseup',
622
- }
643
+ event_handler: mouse_handler,
644
+ },
623
645
  }
624
646
  end
625
647