glimmer-dsl-opal 0.4.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -0
  3. data/README.md +892 -16
  4. data/VERSION +1 -1
  5. data/app/assets/images/glimmer/images/calendar.gif +0 -0
  6. data/app/assets/images/glimmer/images/ui-icons_222222_256x240.png +0 -0
  7. data/app/assets/images/glimmer/images/ui-icons_444444_256x240.png +0 -0
  8. data/app/assets/images/glimmer/images/ui-icons_555555_256x240.png +0 -0
  9. data/app/assets/images/glimmer/images/ui-icons_777620_256x240.png +0 -0
  10. data/app/assets/images/glimmer/images/ui-icons_777777_256x240.png +0 -0
  11. data/app/assets/images/glimmer/images/ui-icons_cc0000_256x240.png +0 -0
  12. data/app/assets/images/glimmer/images/ui-icons_ffffff_256x240.png +0 -0
  13. data/app/assets/stylesheets/glimmer/glimmer.css +15 -0
  14. data/app/assets/stylesheets/glimmer/jquery-ui.css +1312 -0
  15. data/app/assets/stylesheets/glimmer/jquery-ui.structure.css +886 -0
  16. data/app/assets/stylesheets/glimmer/jquery-ui.theme.css +443 -0
  17. data/app/assets/stylesheets/glimmer/jquery.ui.timepicker.css +57 -0
  18. data/lib/glimmer-dsl-opal.rb +16 -9
  19. data/lib/glimmer-dsl-opal/ext/date.rb +49 -3
  20. data/lib/glimmer-dsl-opal/samples/elaborate/tic_tac_toe.rb +23 -0
  21. data/lib/glimmer-dsl-opal/samples/hello/hello_checkbox.rb +85 -0
  22. data/lib/glimmer-dsl-opal/samples/hello/hello_checkbox_group.rb +68 -0
  23. data/lib/glimmer-dsl-opal/samples/hello/hello_combo.rb +5 -5
  24. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_widget.rb +3 -3
  25. data/lib/glimmer-dsl-opal/samples/hello/hello_date_time.rb +63 -0
  26. data/lib/glimmer-dsl-opal/samples/hello/hello_group.rb +104 -0
  27. data/lib/glimmer-dsl-opal/samples/hello/hello_list_single_selection.rb +1 -1
  28. data/lib/glimmer-dsl-opal/samples/hello/hello_radio.rb +108 -0
  29. data/lib/glimmer-dsl-opal/samples/hello/hello_radio_group.rb +84 -0
  30. data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +283 -0
  31. data/lib/glimmer-dsl-opal/vendor/jquery-ui-timepicker/GPL-LICENSE.txt +278 -0
  32. data/lib/glimmer-dsl-opal/vendor/jquery-ui-timepicker/MIT-LICENSE.txt +20 -0
  33. data/lib/glimmer-dsl-opal/vendor/jquery-ui-timepicker/jquery.ui.timepicker.css +57 -0
  34. data/lib/glimmer-dsl-opal/vendor/jquery-ui-timepicker/jquery.ui.timepicker.js +1496 -0
  35. data/lib/glimmer-dsl-opal/vendor/jquery-ui/AUTHORS.txt +333 -0
  36. data/lib/glimmer-dsl-opal/vendor/jquery-ui/LICENSE.txt +43 -0
  37. data/lib/glimmer-dsl-opal/vendor/jquery-ui/images/ui-icons_444444_256x240.png +0 -0
  38. data/lib/glimmer-dsl-opal/vendor/jquery-ui/images/ui-icons_555555_256x240.png +0 -0
  39. data/lib/glimmer-dsl-opal/vendor/jquery-ui/images/ui-icons_777620_256x240.png +0 -0
  40. data/lib/glimmer-dsl-opal/vendor/jquery-ui/images/ui-icons_777777_256x240.png +0 -0
  41. data/lib/glimmer-dsl-opal/vendor/jquery-ui/images/ui-icons_cc0000_256x240.png +0 -0
  42. data/lib/glimmer-dsl-opal/vendor/jquery-ui/images/ui-icons_ffffff_256x240.png +0 -0
  43. data/lib/glimmer-dsl-opal/vendor/jquery-ui/jquery-ui.min.css +7 -0
  44. data/lib/glimmer-dsl-opal/vendor/jquery-ui/jquery-ui.min.js +13 -0
  45. data/lib/glimmer-dsl-opal/vendor/jquery-ui/jquery-ui.structure.min.css +5 -0
  46. data/lib/glimmer-dsl-opal/vendor/jquery-ui/jquery-ui.theme.min.css +5 -0
  47. data/lib/glimmer-dsl-opal/vendor/jquery-ui/package.json +74 -0
  48. data/lib/glimmer-dsl-swt.rb +1 -0
  49. data/lib/glimmer/data_binding/element_binding.rb +2 -1
  50. data/lib/glimmer/data_binding/table_items_binding.rb +29 -18
  51. data/lib/glimmer/dsl/opal/block_property_expression.rb +41 -0
  52. data/lib/glimmer/dsl/opal/checkbox_group_selection_data_binding_expression.rb +61 -0
  53. data/lib/glimmer/dsl/opal/custom_widget_expression.rb +8 -6
  54. data/lib/glimmer/dsl/opal/dsl.rb +6 -0
  55. data/lib/glimmer/dsl/opal/property_expression.rb +4 -3
  56. data/lib/glimmer/dsl/opal/radio_group_selection_data_binding_expression.rb +61 -0
  57. data/lib/glimmer/dsl/opal/shell_expression.rb +7 -2
  58. data/lib/glimmer/dsl/opal/widget_expression.rb +6 -1
  59. data/lib/glimmer/engine.rb +9 -0
  60. data/lib/glimmer/swt.rb +3 -3
  61. data/lib/glimmer/swt/button_proxy.rb +16 -2
  62. data/lib/glimmer/swt/checkbox_proxy.rb +81 -0
  63. data/lib/glimmer/swt/color_proxy.rb +45 -45
  64. data/lib/glimmer/swt/combo_proxy.rb +6 -6
  65. data/lib/glimmer/swt/composite_proxy.rb +2 -2
  66. data/lib/glimmer/swt/custom/checkbox_group.rb +142 -0
  67. data/lib/glimmer/swt/custom/radio_group.rb +143 -0
  68. data/lib/glimmer/swt/date_time_proxy.rb +145 -0
  69. data/lib/glimmer/swt/display_proxy.rb +6 -2
  70. data/lib/glimmer/swt/fill_layout_proxy.rb +1 -1
  71. data/lib/glimmer/swt/grid_layout_proxy.rb +19 -8
  72. data/lib/glimmer/swt/group_proxy.rb +38 -0
  73. data/lib/glimmer/swt/label_proxy.rb +27 -7
  74. data/lib/glimmer/swt/layout_data_proxy.rb +39 -21
  75. data/lib/glimmer/swt/layout_proxy.rb +4 -4
  76. data/lib/glimmer/swt/list_proxy.rb +3 -3
  77. data/lib/glimmer/swt/make_shift_shell_proxy.rb +4 -4
  78. data/lib/glimmer/swt/message_box_proxy.rb +10 -8
  79. data/lib/glimmer/swt/property_owner.rb +2 -2
  80. data/lib/glimmer/swt/radio_proxy.rb +82 -0
  81. data/lib/glimmer/swt/row_layout_proxy.rb +33 -10
  82. data/lib/glimmer/swt/scrolled_composite_proxy.rb +20 -0
  83. data/lib/glimmer/swt/shell_proxy.rb +29 -9
  84. data/lib/glimmer/swt/tab_folder_proxy.rb +5 -5
  85. data/lib/glimmer/swt/tab_item_proxy.rb +7 -7
  86. data/lib/glimmer/swt/table_column_proxy.rb +62 -12
  87. data/lib/glimmer/swt/table_item_proxy.rb +14 -7
  88. data/lib/glimmer/swt/table_proxy.rb +225 -16
  89. data/lib/glimmer/swt/text_proxy.rb +50 -2
  90. data/lib/glimmer/swt/widget_proxy.rb +88 -39
  91. data/lib/glimmer/ui/custom_widget.rb +8 -8
  92. data/lib/net/http.rb +1 -5
  93. data/lib/uri.rb +3 -3
  94. metadata +56 -9
  95. data/lib/glimmer/data_binding/ext/observable_model.rb +0 -40
@@ -4,10 +4,10 @@ module Glimmer
4
4
  module SWT
5
5
  class TabItemProxy < CompositeProxy
6
6
  include Glimmer
7
- attr_reader :text, :content_visible
7
+ attr_reader :text, :content_visible
8
8
 
9
- def initialize(parent, args)
10
- super(parent, args)
9
+ def initialize(parent, args, block)
10
+ super(parent, args, block)
11
11
  content {
12
12
  on_widget_selected {
13
13
  @parent.hide_all_tab_content
@@ -35,7 +35,7 @@ module Glimmer
35
35
 
36
36
  def selector
37
37
  super + '-tab'
38
- end
38
+ end
39
39
 
40
40
  def observation_request_to_event_mapping
41
41
  {
@@ -47,7 +47,7 @@ module Glimmer
47
47
 
48
48
  def listener_path
49
49
  tab_path
50
- end
50
+ end
51
51
 
52
52
  def tab_path
53
53
  "#{parent.tabs_path} > ##{tab_id}"
@@ -72,13 +72,13 @@ module Glimmer
72
72
 
73
73
  # This contains the tab content
74
74
  def dom
75
- tab_item_id = id
75
+ tab_item_id = id
76
76
  tab_item_class_string = [name, 'hide'].join(' ')
77
77
  @dom ||= html {
78
78
  div(id: tab_item_id, class: tab_item_class_string) {
79
79
  }
80
80
  }.to_s
81
- end
81
+ end
82
82
  end
83
83
  end
84
84
  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
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
9
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,47 @@ 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
+
34
77
  def observation_request_to_event_mapping
35
78
  {
36
79
  'on_widget_selected' => {
37
- event: 'click'
80
+ event: 'click',
81
+ event_handler: -> (event_listener) {
82
+ -> (event) {
83
+ event_listener.call(event)
84
+ redraw_sort_direction
85
+ }
86
+ }
38
87
  },
39
88
  }
40
- end
89
+ end
41
90
 
42
91
  def dom
43
92
  table_column_text = text
44
93
  table_column_id = id
45
- table_column_id_style = css
94
+ table_column_id_style = "width: #{width}px;"
46
95
  table_column_css_classes = css_classes
47
96
  table_column_css_classes << name
48
97
  @dom ||= html {
49
98
  th(id: table_column_id, style: table_column_id_style, class: table_column_css_classes.to_a.join(' ')) {
50
- table_column_text
99
+ span {table_column_text}
100
+ span(class: sort_icon_class)
51
101
  }
52
102
  }.to_s
53
- end
103
+ end
54
104
  end
55
105
  end
56
106
  end
@@ -3,10 +3,17 @@ require 'glimmer/swt/widget_proxy'
3
3
  module Glimmer
4
4
  module SWT
5
5
  class TableItemProxy < WidgetProxy
6
+ STYLE = <<~CSS
7
+ tr.table-item:nth-child(even):not(.selected) {
8
+ background: rgb(243, 244, 246);
9
+ }
10
+ CSS
11
+
6
12
  attr_reader :data
7
13
 
8
- def initialize(parent, args)
9
- super(parent, args)
14
+ def initialize(parent, args, block)
15
+ super(parent, args, block)
16
+ # TODO check if there is a need to remove this observer when removing widget from table upon items update
10
17
  on_widget_selected { |event|
11
18
  parent.select(parent.index_of(self), event.meta?)
12
19
  }
@@ -54,7 +61,7 @@ module Glimmer
54
61
  end
55
62
 
56
63
  def redraw
57
- super() #TODO re-enalbe and remove below lines
64
+ super() #TODO re-enable and remove below lines
58
65
 
59
66
  # TODO perhaps turn the following lambdas into methods
60
67
  table_item_edit_handler = lambda do |event, cancel = false|
@@ -70,11 +77,11 @@ module Glimmer
70
77
  redraw
71
78
  end
72
79
  end
73
- table_item_edit_cancel_handler = lambda do |event|
80
+ table_item_edit_cancel_handler = lambda do |event|
74
81
  Async::Task.new do
75
82
  table_item_edit_handler.call(event, true)
76
83
  end
77
- end
84
+ end
78
85
  table_item_edit_key_handler = lambda do |event|
79
86
  Async::Task.new do
80
87
  if event.key_code == 13
@@ -91,7 +98,7 @@ module Glimmer
91
98
  Async::Task.new do
92
99
  table_item_input.focus
93
100
  table_item_input.on('keyup', &table_item_edit_key_handler)
94
- table_item_input.on('focusout', &table_item_edit_cancel_handler)
101
+ table_item_input.on('focusout', &table_item_edit_cancel_handler)
95
102
  end
96
103
  end
97
104
  end
@@ -132,7 +139,7 @@ module Glimmer
132
139
  tr(id: table_item_id, style: table_item_id_style, class: table_item_css_classes.to_a.join(' ')) {
133
140
  table_item_text_array.each_with_index do |table_item_text, column_index|
134
141
  td('data-column-index' => column_index) {
135
- if @edit_column_index == column_index
142
+ if @edit_column_index == column_index
136
143
  input(type: 'text', value: table_item_text, style: "max-width: #{table_item_max_width - 11}px;")
137
144
  else
138
145
  table_item_text
@@ -4,46 +4,82 @@ require 'glimmer/swt/table_column_proxy'
4
4
  module Glimmer
5
5
  module SWT
6
6
  class TableProxy < WidgetProxy
7
- attr_reader :columns, :selection
8
- attr_accessor :column_properties
7
+ attr_reader :columns, :selection,
8
+ :sort_type, :sort_column, :sort_property, :sort_block, :sort_by_block, :additional_sort_properties
9
+ attr_accessor :column_properties, :item_count, :data
9
10
  alias items children
11
+ alias model_binding data
10
12
 
11
- def initialize(parent, args)
12
- super(parent, args)
13
+ def initialize(parent, args, block)
14
+ super(parent, args, block)
13
15
  @columns = []
14
16
  @children = []
15
17
  @selection = []
18
+ if editable?
19
+ on_mouse_up { |event|
20
+ edit_table_item(event.table_item, event.column_index)
21
+ }
22
+ end
16
23
  end
17
24
 
18
25
  # Only table_columns may be added as children
19
- def add_child(child)
26
+ def post_initialize_child(child)
20
27
  if child.is_a?(TableColumnProxy)
21
28
  @columns << child
22
29
  else
23
- @children << child
30
+ @children << child
24
31
  end
25
32
  child.redraw
26
33
  end
27
34
 
35
+ def post_add_content
36
+ return if @initially_sorted
37
+ initial_sort!
38
+ @initially_sorted = true
39
+ end
40
+
41
+ def get_data(key=nil)
42
+ data
43
+ end
44
+
28
45
  def remove_all
29
46
  items.clear
30
47
  redraw
31
48
  end
32
49
 
50
+ def editable?
51
+ args.include?(:editable)
52
+ end
53
+ alias editable editable?
54
+
55
+ def selection
56
+ @selection.to_a
57
+ end
58
+
33
59
  def selection=(new_selection)
34
- changed = (@selection + new_selection) - (@selection & new_selection)
60
+ new_selection = new_selection.to_a
61
+ changed = (selection + new_selection) - (selection & new_selection)
35
62
  @selection = new_selection
36
63
  changed.each(&:redraw)
37
64
  end
38
65
 
39
- def items=(new_items)
66
+ def items=(new_items)
40
67
  @children = new_items
41
68
  redraw
42
69
  end
43
70
 
71
+ def item_count=(value)
72
+ @item_count = value
73
+ redraw_empty_items
74
+ end
75
+
76
+ def cells_for(model)
77
+ column_properties.map {|property| model.send(property)}
78
+ end
79
+
44
80
  def search(&condition)
45
81
  items.select {|item| condition.nil? || condition.call(item)}
46
- end
82
+ end
47
83
 
48
84
  def index_of(item)
49
85
  items.index(item)
@@ -61,8 +97,147 @@ module Glimmer
61
97
  self.selection = new_selection
62
98
  end
63
99
 
100
+ def search(&condition)
101
+ items.select {|item| condition.nil? || condition.call(item)}
102
+ end
103
+
104
+ def sort_block=(comparator)
105
+ @sort_block = comparator
106
+ end
107
+
108
+ def sort_by_block=(property_picker)
109
+ @sort_by_block = property_picker
110
+ end
111
+
112
+ def sort_property=(new_sort_property)
113
+ @sort_property = [new_sort_property].flatten.compact
114
+ end
115
+
116
+ def detect_sort_type
117
+ @sort_type = sort_property.size.times.map { String }
118
+ array = model_binding.evaluate_property
119
+ sort_property.each_with_index do |a_sort_property, i|
120
+ values = array.map { |object| object.send(a_sort_property) }
121
+ value_classes = values.map(&:class).uniq
122
+ if value_classes.size == 1
123
+ @sort_type[i] = value_classes.first
124
+ elsif value_classes.include?(Integer)
125
+ @sort_type[i] = Integer
126
+ elsif value_classes.include?(Float)
127
+ @sort_type[i] = Float
128
+ end
129
+ end
130
+ end
131
+
132
+ def column_sort_properties
133
+ column_properties.zip(columns.map(&:sort_property)).map do |pair|
134
+ [pair.compact.last].flatten.compact
135
+ end
136
+ end
137
+
138
+ def sort_direction
139
+ @sort_direction == :ascending ? SWTProxy[:up] : SWTProxy[:down]
140
+ end
141
+
142
+ def sort_direction=(value)
143
+ @sort_direction = value == SWTProxy[:up] ? :ascending : :descending
144
+ end
145
+
146
+ # Sorts by specified TableColumnProxy object. If nil, it uses the table default sort instead.
147
+ def sort_by_column!(table_column_proxy=nil)
148
+ index = columns.to_a.index(table_column_proxy) unless table_column_proxy.nil?
149
+ new_sort_property = table_column_proxy.nil? ? @sort_property : table_column_proxy.sort_property || [column_properties[index]]
150
+
151
+ return if table_column_proxy.nil? && new_sort_property.nil? && @sort_block.nil? && @sort_by_block.nil?
152
+ if new_sort_property && table_column_proxy.nil? && new_sort_property.size == 1 && (index = column_sort_properties.index(new_sort_property))
153
+ table_column_proxy = columns[index]
154
+ end
155
+ if new_sort_property && new_sort_property.size == 1 && !additional_sort_properties.to_a.empty?
156
+ selected_additional_sort_properties = additional_sort_properties.clone
157
+ if selected_additional_sort_properties.include?(new_sort_property.first)
158
+ selected_additional_sort_properties.delete(new_sort_property.first)
159
+ new_sort_property += selected_additional_sort_properties
160
+ else
161
+ new_sort_property += additional_sort_properties
162
+ end
163
+ end
164
+
165
+ new_sort_property = [new_sort_property].flatten.compact unless new_sort_property.is_a?(Array)
166
+ @sort_direction = @sort_direction.nil? || @sort_property.first != new_sort_property.first || @sort_direction == :descending ? :ascending : :descending
167
+
168
+ @sort_property = new_sort_property
169
+ table_column_index = column_properties.index(new_sort_property.to_s.to_sym)
170
+ table_column_proxy ||= columns[table_column_index] if table_column_index
171
+ @sort_column = table_column_proxy if table_column_proxy
172
+
173
+ if table_column_proxy
174
+ @sort_by_block = nil
175
+ @sort_block = nil
176
+ end
177
+ @sort_type = nil
178
+ if table_column_proxy&.sort_by_block
179
+ @sort_by_block = table_column_proxy.sort_by_block
180
+ elsif table_column_proxy&.sort_block
181
+ @sort_block = table_column_proxy.sort_block
182
+ else
183
+ detect_sort_type
184
+ end
185
+
186
+ sort!
187
+ end
188
+
189
+ def initial_sort!
190
+ sort_by_column!
191
+ end
192
+
193
+ def sort!
194
+ return unless sort_property && (sort_type || sort_block || sort_by_block)
195
+ array = model_binding.evaluate_property
196
+ array = array.sort_by(&:hash) # this ensures consistent subsequent sorting in case there are equivalent sorts to avoid an infinite loop
197
+ # Converting value to_s first to handle nil cases. Should work with numeric, boolean, and date fields
198
+ if sort_block
199
+ sorted_array = array.sort(&sort_block)
200
+ elsif sort_by_block
201
+ sorted_array = array.sort_by(&sort_by_block)
202
+ else
203
+ sorted_array = array.sort_by do |object|
204
+ sort_property.each_with_index.map do |a_sort_property, i|
205
+ value = object.send(a_sort_property)
206
+ # handle nil and difficult to compare types gracefully
207
+ if sort_type[i] == Integer
208
+ value = value.to_i
209
+ elsif sort_type[i] == Float
210
+ value = value.to_f
211
+ elsif sort_type[i] == String
212
+ value = value.to_s
213
+ end
214
+ value
215
+ end
216
+ end
217
+ end
218
+ sorted_array = sorted_array.reverse if @sort_direction == :descending
219
+ model_binding.call(sorted_array)
220
+ end
221
+
222
+ def additional_sort_properties=(*args)
223
+ @additional_sort_properties = args unless args.empty?
224
+ end
225
+
64
226
  def edit_table_item(table_item, column_index)
65
- table_item.edit(column_index)
227
+ table_item&.edit(column_index) unless column_index.nil?
228
+ end
229
+
230
+ def header_visible=(value)
231
+ @header_visible = value
232
+ if @header_visible
233
+ thead_dom_element.remove_class('hide')
234
+ else
235
+ thead_dom_element.add_class('hide')
236
+ end
237
+ end
238
+
239
+ def header_visible
240
+ @header_visible
66
241
  end
67
242
 
68
243
  def selector
@@ -84,9 +259,9 @@ module Glimmer
84
259
  event.singleton_class.send(:define_method, :column_index) do
85
260
  (table_data || event.target).attr('data-column-index')
86
261
  end
87
- event_listener.call(event)
262
+ event_listener.call(event)
88
263
  }
89
- }
264
+ }
90
265
 
91
266
  {
92
267
  'on_mouse_down' => {
@@ -96,13 +271,26 @@ module Glimmer
96
271
  'on_mouse_up' => {
97
272
  event: 'mouseup',
98
273
  event_handler: mouse_handler,
274
+ },
275
+ 'on_widget_selected' => {
276
+ event: 'mouseup',
99
277
  }
100
278
  }
101
279
  end
102
280
 
103
281
  def redraw
104
282
  super()
105
- @columns.to_a.each(&:redraw)
283
+ @columns.to_a.each(&:redraw)
284
+ redraw_empty_items
285
+ end
286
+
287
+ def redraw_empty_items
288
+ if @children&.size.to_i < item_count.to_i
289
+ item_count.to_i.times do
290
+ empty_columns = column_properties&.size.to_i.times.map { |i| "<td data-column-index='#{i}'></td>" }
291
+ items_dom_element.append("<tr class='table-item empty-table-item'>#{empty_columns}</tr>")
292
+ end
293
+ end
106
294
  end
107
295
 
108
296
  def element
@@ -125,7 +313,7 @@ module Glimmer
125
313
  Document.find(items_path)
126
314
  end
127
315
 
128
- def columns_dom
316
+ def columns_dom
129
317
  tr {
130
318
  }
131
319
  end
@@ -134,9 +322,13 @@ module Glimmer
134
322
  thead {
135
323
  columns_dom
136
324
  }
137
- end
325
+ end
326
+
327
+ def thead_dom_element
328
+ dom_element.find('thead')
329
+ end
138
330
 
139
- def items_dom
331
+ def items_dom
140
332
  tbody {
141
333
  }
142
334
  end
@@ -154,6 +346,23 @@ module Glimmer
154
346
  }
155
347
  }.to_s
156
348
  end
349
+
350
+ private
351
+
352
+ def property_type_converters
353
+ super.merge({
354
+ selection: lambda do |value|
355
+ if value.is_a?(Array)
356
+ search {|ti| value.include?(ti.get_data) }
357
+ else
358
+ search {|ti| ti.get_data == value}
359
+ end
360
+ end,
361
+ })
362
+ end
363
+
157
364
  end
365
+
158
366
  end
367
+
159
368
  end