glimmer-dsl-opal 0.6.1 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/README.md +489 -16
  4. data/VERSION +1 -1
  5. data/lib/display.rb +31 -0
  6. data/lib/file.rb +29 -0
  7. data/lib/glimmer-dsl-opal.rb +31 -3
  8. data/lib/glimmer-dsl-opal/ext/date.rb +11 -0
  9. data/lib/glimmer-dsl-opal/ext/struct.rb +37 -0
  10. data/lib/glimmer-dsl-opal/samples/hello/hello_browser.rb +1 -1
  11. data/lib/glimmer-dsl-opal/samples/hello/hello_button.rb +46 -0
  12. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_shell.rb +7 -7
  13. data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +283 -0
  14. data/lib/glimmer-dsl-swt.rb +20 -35
  15. data/lib/glimmer/data_binding/table_items_binding.rb +32 -19
  16. data/lib/glimmer/dsl/opal/block_property_expression.rb +41 -0
  17. data/lib/glimmer/dsl/opal/custom_widget_expression.rb +5 -0
  18. data/lib/glimmer/dsl/opal/dsl.rb +2 -0
  19. data/lib/glimmer/dsl/opal/widget_expression.rb +6 -2
  20. data/lib/glimmer/swt/combo_proxy.rb +40 -1
  21. data/lib/glimmer/swt/composite_proxy.rb +5 -1
  22. data/lib/glimmer/swt/control_editor.rb +54 -0
  23. data/lib/glimmer/swt/date_time_proxy.rb +66 -1
  24. data/lib/glimmer/swt/display_proxy.rb +4 -0
  25. data/lib/glimmer/swt/font_proxy.rb +4 -4
  26. data/lib/glimmer/swt/grid_layout_proxy.rb +7 -8
  27. data/lib/glimmer/swt/label_proxy.rb +11 -3
  28. data/lib/glimmer/swt/layout_data_proxy.rb +9 -3
  29. data/lib/glimmer/swt/layout_proxy.rb +1 -1
  30. data/lib/glimmer/swt/message_box_proxy.rb +3 -10
  31. data/lib/glimmer/swt/property_owner.rb +2 -2
  32. data/lib/glimmer/swt/shell_proxy.rb +8 -0
  33. data/lib/glimmer/swt/table_column_proxy.rb +71 -12
  34. data/lib/glimmer/swt/table_editor.rb +65 -0
  35. data/lib/glimmer/swt/table_item_proxy.rb +44 -1
  36. data/lib/glimmer/swt/table_proxy.rb +579 -12
  37. data/lib/glimmer/swt/text_proxy.rb +49 -1
  38. data/lib/glimmer/swt/widget_proxy.rb +106 -17
  39. data/lib/glimmer/ui/custom_shell.rb +9 -7
  40. data/lib/net/http.rb +1 -5
  41. data/lib/os.rb +36 -0
  42. data/lib/uri.rb +3 -3
  43. metadata +31 -9
  44. data/lib/glimmer/data_binding/ext/observable_model.rb +0 -40
@@ -7,9 +7,8 @@ module Glimmer
7
7
  .grid-layout {
8
8
  display: grid;
9
9
  grid-template-rows: min-content;
10
- justify-content: start;
11
10
  place-content: start;
12
- align-items: stretch;
11
+ align-items: stretch;
13
12
  }
14
13
  CSS
15
14
  attr_reader :num_columns, :make_columns_equal_width, :horizontal_spacing, :vertical_spacing, :margin_width, :margin_height
@@ -18,7 +17,7 @@ module Glimmer
18
17
  super(parent, args)
19
18
  self.horizontal_spacing = 10
20
19
  self.vertical_spacing = 10
21
- self.num_columns = @args.first || 1
20
+ self.num_columns = @args.first || 1
22
21
  reapply
23
22
  end
24
23
 
@@ -30,7 +29,7 @@ module Glimmer
30
29
  end
31
30
 
32
31
  def make_columns_equal_width=(equal_width)
33
- @make_columns_equal_width = equal_width
32
+ @make_columns_equal_width = equal_width
34
33
  # @parent.add_css_class('make_columns_equal_width') if @make_columns_equal_width
35
34
  reapply
36
35
  end
@@ -68,15 +67,15 @@ module Glimmer
68
67
  grid-column-gap: #{@horizontal_spacing}px;
69
68
  CSS
70
69
  if @parent.css_classes.include?('grid-layout')
71
- layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
70
+ layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
72
71
  @parent.dom_element.css(key, value) unless key.nil?
73
72
  end
74
73
  else
75
- layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
74
+ layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
76
75
  @parent.dom_element.css(key, 'initial') unless key.nil?
77
- end
76
+ end
78
77
  end
79
- end
78
+ end
80
79
  end
81
80
  end
82
81
  end
@@ -4,11 +4,10 @@ require 'glimmer/swt/widget_proxy'
4
4
  module Glimmer
5
5
  module SWT
6
6
  class LabelProxy < WidgetProxy
7
- attr_reader :text, :background_image, :image, :alignment
7
+ attr_reader :text, :background_image, :image
8
8
 
9
9
  def initialize(parent, args, block)
10
10
  super(parent, args, block)
11
- self.alignment = [:left, :center, :right].detect {|align| args.detect { |arg| SWTProxy[align] == arg } }
12
11
  end
13
12
 
14
13
  def text=(value)
@@ -32,6 +31,15 @@ module Glimmer
32
31
  def element
33
32
  'label'
34
33
  end
34
+
35
+ def alignment
36
+ if @alignment.nil?
37
+ found_arg = nil
38
+ @alignment = [:left, :center, :right].detect {|align| found_arg = args.detect { |arg| SWTProxy[align] == SWTProxy[arg] } }
39
+ args.delete(found_arg)
40
+ end
41
+ @alignment
42
+ end
35
43
 
36
44
  def alignment=(value)
37
45
  # TODO consider storing swt value in the future instead
@@ -44,7 +52,7 @@ module Glimmer
44
52
  label_id = id
45
53
  label_class = name
46
54
  @dom ||= html {
47
- label(id: label_id, class: label_class) {
55
+ label(id: label_id, class: label_class, style: "text-align: #{alignment};") {
48
56
  label_text
49
57
  }
50
58
  }.to_s
@@ -3,6 +3,7 @@ require 'glimmer/swt/property_owner'
3
3
  module Glimmer
4
4
  module SWT
5
5
  class LayoutDataProxy
6
+ # TODO make this polymorphic as GridData or RowData subclasses
6
7
  include Glimmer::SWT::PropertyOwner
7
8
  attr_reader :parent,
8
9
  :args,
@@ -47,7 +48,10 @@ module Glimmer
47
48
  if @horizontal_alignment == 'fill'
48
49
  @parent.dom_element.css('width', '100%') if width_hint.nil?
49
50
  else
50
- @parent.dom_element.css('text-align', @horizontal_alignment)
51
+ @parent.dom_element.css('text-align', @horizontal_alignment.to_s)
52
+ @parent.dom_element.css('place-self', @horizontal_alignment.to_s)
53
+ @parent.dom_element.css('margin-left', 'auto') if ['right', 'center'].include?(@horizontal_alignment.to_s)
54
+ @parent.dom_element.css('margin-right', 'auto') if ['left', 'center'].include?(@horizontal_alignment.to_s)
51
55
  end
52
56
  # TODO
53
57
  # reapply
@@ -85,13 +89,15 @@ module Glimmer
85
89
 
86
90
  def grab_excess_horizontal_space=(grab_excess_horizontal_space)
87
91
  @grab_excess_horizontal_space = grab_excess_horizontal_space
88
- @parent.dom_element.css('width', "100%") if @grab_excess_horizontal_space && width_hint.nil?
92
+ @parent.dom_element.css('width', "100%") if @grab_excess_horizontal_space && @horizontal_alignment == 'fill' && width_hint.nil?
93
+ @parent.dom_element.css('justify-self', @horizontal_alignment) if @grab_excess_horizontal_space && @horizontal_alignment != 'fill' && width_hint.nil?
94
+ @parent.parent.dom_element.css('justify-content', "normal") if @grab_excess_horizontal_space
89
95
  # reapply
90
96
  end
91
97
 
92
98
  def grab_excess_vertical_space=(grab_excess_vertical_space)
93
99
  @grab_excess_vertical_space = grab_excess_vertical_space
94
- @parent.dom_element.css('height', "100%") if @grab_excess_vertical_space && height_hint.nil?
100
+ @parent.dom_element.css('height', "100%") if @grab_excess_vertical_space && @vertical_alignment == 'fill' && height_hint.nil?
95
101
  # TODO
96
102
  # reapply
97
103
  end
@@ -18,7 +18,7 @@ module Glimmer
18
18
  a_layout_class = Glimmer::SWT.const_get(class_name_main.to_sym) rescue Glimmer::SWT.const_get(class_name_alternative.to_sym)
19
19
  a_layout_class if a_layout_class.ancestors.include?(Glimmer::SWT::LayoutProxy)
20
20
  rescue => e
21
- puts "Layout #{keyword} was not found!"
21
+ Glimmer::Config.logger.debug "Layout #{keyword} was not found!"
22
22
  nil
23
23
  end
24
24
 
@@ -1,4 +1,5 @@
1
1
  require 'glimmer/swt/widget_proxy'
2
+ require 'glimmer/swt/display_proxy'
2
3
 
3
4
  module Glimmer
4
5
  module SWT
@@ -7,7 +8,7 @@ module Glimmer
7
8
 
8
9
  def initialize(parent, args, block)
9
10
  i = 0
10
- @parent = parent
11
+ @parent = parent || DisplayProxy.instance.shells.last
11
12
  @args = args
12
13
  @block = block
13
14
  @children = Set.new
@@ -29,16 +30,8 @@ module Glimmer
29
30
  dom_element.find('.modal-content .message').html(@text)
30
31
  end
31
32
 
32
- def document
33
- element = self
34
- begin
35
- element = element.parent
36
- end while(element.parent)
37
- element
38
- end
39
-
40
33
  def open
41
- document.post_initialize_child(self)
34
+ parent.post_initialize_child(self)
42
35
  end
43
36
 
44
37
  def hide
@@ -7,7 +7,7 @@ module Glimmer
7
7
  end
8
8
 
9
9
  def set_attribute(attribute_name, *args)
10
- send(attribute_setter(attribute_name), *args) unless send(attribute_getter(attribute_name)) == args.first
10
+ send(attribute_setter(attribute_name), *args) unless args.size == 1 && send(attribute_getter(attribute_name)) == args.first
11
11
  end
12
12
 
13
13
  def attribute_setter(attribute_name)
@@ -16,7 +16,7 @@ module Glimmer
16
16
 
17
17
  def attribute_getter(attribute_name)
18
18
  attribute_name.to_s.underscore
19
- end
19
+ end
20
20
  end
21
21
  end
22
22
  end
@@ -21,6 +21,7 @@ module Glimmer
21
21
  @layout.margin_width = 0
22
22
  @layout.margin_height = 0
23
23
  self.minimum_size = Point.new(WIDTH_MIN, HEIGHT_MIN)
24
+ DisplayProxy.instance.shells << self
24
25
  end
25
26
 
26
27
  def element
@@ -207,6 +208,7 @@ module Glimmer
207
208
  body_class = ([name] + css_classes.to_a).join(' ')
208
209
  @dom ||= html {
209
210
  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
210
212
  style(class: 'common-style') {
211
213
  style_dom_css
212
214
  }
@@ -246,6 +248,12 @@ module Glimmer
246
248
  style(class: 'scrolled-composite-style') {
247
249
  Glimmer::SWT::ScrolledCompositeProxy::STYLE
248
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
+ }
249
257
  }
250
258
  }.to_s
251
259
  end
@@ -1,12 +1,51 @@
1
1
  require 'glimmer/swt/widget_proxy'
2
+ require 'glimmer/swt/swt_proxy'
2
3
 
3
4
  module Glimmer
4
5
  module SWT
5
6
  class TableColumnProxy < WidgetProxy
7
+ STYLE = <<~CSS
8
+ th.table-column {
9
+ background: rgb(246, 246, 246);
10
+ text-align: left;
11
+ padding: 5px;
12
+ }
13
+
14
+ th.table-column .sort-direction {
15
+ float: right;
16
+ }
17
+ CSS
6
18
  include Glimmer
7
19
 
8
- attr_reader :text, :width
20
+ attr_accessor :sort_block, :sort_by_block
21
+ attr_reader :text, :width,
22
+ :no_sort, :sort_property, :editor
23
+ alias no_sort? no_sort
24
+
25
+ def initialize(parent, args, block)
26
+ @no_sort = args.delete(:no_sort)
27
+ super(parent, args, block)
28
+ unless no_sort?
29
+ content {
30
+ on_widget_selected { |event|
31
+ parent.sort_by_column!(self)
32
+ }
33
+ }
34
+ end
35
+ end
9
36
 
37
+ def sort_property=(args)
38
+ @sort_property = args unless args.empty?
39
+ end
40
+
41
+ def sort_direction
42
+ parent.sort_direction if parent.sort_column == self
43
+ end
44
+
45
+ def redraw_sort_direction
46
+ sort_icon_dom_element.attr('class', sort_icon_class)
47
+ end
48
+
10
49
  def text=(value)
11
50
  @text = value
12
51
  redraw
@@ -21,36 +60,56 @@ module Glimmer
21
60
  parent.columns_path
22
61
  end
23
62
 
24
- def css
25
- <<~CSS
26
- width: #{width}px;
27
- CSS
28
- end
29
-
30
63
  def element
31
64
  'th'
32
65
  end
33
66
 
67
+ def sort_icon_class
68
+ @sort_icon_class = 'sort-direction'
69
+ @sort_icon_class += (sort_direction == SWTProxy[:up] ? ' ui-icon ui-icon-caret-1-n' : ' ui-icon ui-icon-caret-1-s') unless sort_direction.nil?
70
+ @sort_icon_class
71
+ end
72
+
73
+ def sort_icon_dom_element
74
+ dom_element.find('.sort-direction')
75
+ end
76
+
77
+ # Sets editor (e.g. combo)
78
+ def editor=(*args)
79
+ @editor = args
80
+ end
81
+
82
+ def editable?
83
+ !@editor&.include?(:none)
84
+ end
85
+
34
86
  def observation_request_to_event_mapping
35
87
  {
36
88
  'on_widget_selected' => {
37
- event: 'click'
89
+ event: 'click',
90
+ event_handler: -> (event_listener) {
91
+ -> (event) {
92
+ event_listener.call(event)
93
+ redraw_sort_direction
94
+ }
95
+ }
38
96
  },
39
97
  }
40
- end
98
+ end
41
99
 
42
100
  def dom
43
101
  table_column_text = text
44
102
  table_column_id = id
45
- table_column_id_style = css
103
+ table_column_id_style = "width: #{width}px;"
46
104
  table_column_css_classes = css_classes
47
105
  table_column_css_classes << name
48
106
  @dom ||= html {
49
107
  th(id: table_column_id, style: table_column_id_style, class: table_column_css_classes.to_a.join(' ')) {
50
- table_column_text
108
+ span {table_column_text}
109
+ span(class: sort_icon_class)
51
110
  }
52
111
  }.to_s
53
- end
112
+ end
54
113
  end
55
114
  end
56
115
  end
@@ -0,0 +1,65 @@
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/control_editor'
23
+
24
+ module Glimmer
25
+ module SWT
26
+ # Emulates SWT's native org.eclipse.swt.custom.TableEditor
27
+ class TableEditor < ControlEditor
28
+ alias table composite
29
+
30
+ def editor=(editor_widget, table_item, table_column_index)
31
+ # TODO consider making editor not gain an ID or gain a separate set of IDs to avoid clashing with standard widget predictability of ID
32
+ @table_item = table_item
33
+ @table_column_index = table_column_index
34
+ @editor_widget = editor_widget
35
+ @old_value = table_item.cell_dom_element(table_column_index).html
36
+ table_item.cell_dom_element(table_column_index).html('')
37
+ editor_widget.render(table_item.cell_dom_element(table_column_index))
38
+ # TODO tweak the width perfectly so it doesn't expand the table cell
39
+ # editor_widget.dom_element.css('width', 'calc(100% - 20px)')
40
+ editor_widget.dom_element.css('width', "#{minimumWidth}%") # TODO implement property with pixels (and perhaps derive percentage separately from pixels)
41
+ editor_widget.dom_element.css('height', "#{minimumHeight}px")
42
+ editor_widget.dom_element.add_class('table-editor')
43
+ # TODO consider relying on autofocus instead
44
+ editor_widget.dom_element.focus
45
+ # TODO consider doing the following line only for :text editor
46
+ editor_widget.dom_element.select
47
+ end
48
+ alias set_editor editor=
49
+ alias setEditor editor=
50
+
51
+ def cancel!
52
+ done!
53
+ end
54
+
55
+ def save!
56
+ done!
57
+ end
58
+
59
+ def done!
60
+ @table_item.cell_dom_element(@table_column_index).html(@old_value) unless @old_value.nil?
61
+ @old_value = nil
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,12 +1,43 @@
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 TableItemProxy < WidgetProxy
27
+ STYLE = <<~CSS
28
+ tr.table-item td {
29
+ padding-bottom: 0;
30
+ }
31
+ tr.table-item:nth-child(even):not(.selected) {
32
+ background: rgb(243, 244, 246);
33
+ }
34
+ CSS
35
+
6
36
  attr_reader :data
7
37
 
8
38
  def initialize(parent, args, block)
9
39
  super(parent, args, block)
40
+ # TODO check if there is a need to remove this observer when removing widget from table upon items update
10
41
  on_widget_selected { |event|
11
42
  parent.select(parent.index_of(self), event.meta?)
12
43
  }
@@ -53,8 +84,12 @@ module Glimmer
53
84
  'tr'
54
85
  end
55
86
 
87
+ def cell_dom_element(column_index)
88
+ dom_element.find("td:nth-child(#{column_index + 1})")
89
+ end
90
+
56
91
  def redraw
57
- super() #TODO re-enalbe and remove below lines
92
+ super() #TODO re-enable and remove below lines
58
93
 
59
94
  # TODO perhaps turn the following lambdas into methods
60
95
  table_item_edit_handler = lambda do |event, cancel = false|
@@ -104,6 +139,14 @@ module Glimmer
104
139
  redraw
105
140
  end
106
141
 
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
+
107
150
  def on_widget_selected(&block)
108
151
  event = 'click'
109
152
  delegate = $document.on(event, selector, &block)