glimmer-dsl-opal 0.6.1 → 0.7.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/README.md +293 -7
- data/VERSION +1 -1
- data/lib/glimmer-dsl-opal.rb +1 -2
- data/lib/glimmer-dsl-opal/ext/date.rb +11 -0
- data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +283 -0
- data/lib/glimmer/data_binding/table_items_binding.rb +29 -18
- data/lib/glimmer/dsl/opal/block_property_expression.rb +41 -0
- data/lib/glimmer/dsl/opal/dsl.rb +2 -0
- data/lib/glimmer/swt/display_proxy.rb +4 -0
- data/lib/glimmer/swt/message_box_proxy.rb +2 -1
- data/lib/glimmer/swt/property_owner.rb +2 -2
- data/lib/glimmer/swt/shell_proxy.rb +8 -0
- data/lib/glimmer/swt/table_column_proxy.rb +62 -12
- data/lib/glimmer/swt/table_item_proxy.rb +8 -1
- data/lib/glimmer/swt/table_proxy.rb +213 -4
- data/lib/glimmer/swt/text_proxy.rb +48 -0
- data/lib/glimmer/swt/widget_proxy.rb +12 -1
- data/lib/net/http.rb +1 -5
- data/lib/uri.rb +3 -3
- metadata +10 -9
- data/lib/glimmer/data_binding/ext/observable_model.rb +0 -40
@@ -12,26 +12,32 @@ module Glimmer
|
|
12
12
|
include DataBinding::Observer
|
13
13
|
|
14
14
|
def initialize(parent, model_binding, column_properties)
|
15
|
-
@
|
15
|
+
@last_populated_model_collection = nil
|
16
16
|
@table = parent
|
17
17
|
@model_binding = model_binding
|
18
18
|
@column_properties = column_properties
|
19
|
-
|
20
|
-
@table.column_properties = @column_properties
|
21
|
-
##else # assume custom widget
|
22
|
-
## @table.body_root.column_properties = @column_properties
|
23
|
-
end
|
24
|
-
call(@model_binding.evaluate_property)
|
25
|
-
model = model_binding.base_model
|
26
|
-
observe(model, model_binding.property_name_expression)
|
19
|
+
@table.data = @model_binding
|
27
20
|
##@table.on_widget_disposed do |dispose_event| # doesn't seem needed within Opal
|
28
21
|
## unregister_all_observables
|
29
22
|
##end
|
23
|
+
if @table.respond_to?(:column_properties=)
|
24
|
+
@table.column_properties = @column_properties
|
25
|
+
else # assume custom widget
|
26
|
+
@table.body_root.column_properties = @column_properties
|
27
|
+
end
|
28
|
+
@table_observer_registration = observe(model_binding)
|
29
|
+
call
|
30
30
|
end
|
31
31
|
|
32
32
|
def call(new_model_collection=nil)
|
33
|
+
new_model_collection = @model_binding.evaluate_property # this ensures applying converters (e.g. :on_read)
|
34
|
+
table_cells = @table.items.map {|item| @table.column_properties.size.times.map {|i| item.get_text(i)} }
|
35
|
+
model_cells = new_model_collection.to_a.map {|m| @table.cells_for(m)}
|
36
|
+
return if table_cells == model_cells
|
33
37
|
if new_model_collection and new_model_collection.is_a?(Array)
|
34
|
-
|
38
|
+
# @table_items_observer_registration&.unobserve
|
39
|
+
@table_items_observer_registration = observe(new_model_collection, @column_properties)
|
40
|
+
add_dependent(@table_observer_registration => @table_items_observer_registration)
|
35
41
|
@model_collection = new_model_collection
|
36
42
|
end
|
37
43
|
populate_table(@model_collection, @table, @column_properties)
|
@@ -39,8 +45,8 @@ module Glimmer
|
|
39
45
|
end
|
40
46
|
|
41
47
|
def populate_table(model_collection, parent, column_properties)
|
42
|
-
return if model_collection&.sort_by(&:hash) == @
|
43
|
-
@
|
48
|
+
return if model_collection&.sort_by(&:hash) == @last_populated_model_collection&.sort_by(&:hash)
|
49
|
+
@last_populated_model_collection = model_collection
|
44
50
|
# TODO improve performance
|
45
51
|
selected_table_item_models = parent.selection.map(&:get_data)
|
46
52
|
old_items = parent.items
|
@@ -55,16 +61,21 @@ module Glimmer
|
|
55
61
|
table_item.id = old_item_ids_per_model[model.hash] if old_item_ids_per_model[model.hash]
|
56
62
|
end
|
57
63
|
selected_table_items = parent.search {|item| selected_table_item_models.include?(item.get_data) }
|
58
|
-
|
59
|
-
parent.selection = selected_table_items unless selected_table_items.empty?
|
64
|
+
parent.selection = selected_table_items
|
60
65
|
parent.redraw
|
61
66
|
end
|
62
67
|
|
63
68
|
def sort_table(model_collection, parent, column_properties)
|
64
|
-
return if model_collection == @
|
65
|
-
|
66
|
-
|
67
|
-
|
69
|
+
return if model_collection == @last_sorted_model_collection
|
70
|
+
if model_collection == @last_populated_model_collection
|
71
|
+
# Reapply the last table sort. The model collection has just been populated since it diverged from what it was before
|
72
|
+
parent.sort!
|
73
|
+
else
|
74
|
+
# The model collection was sorted by the model, but beyond sorting, it did not change from the last populated model collection.
|
75
|
+
parent.items = parent.items.sort_by { |item| model_collection.index(item.get_data) }
|
76
|
+
@last_sorted_model_collection = @last_populated_model_collection = model_collection
|
77
|
+
end
|
78
|
+
end
|
68
79
|
end
|
69
80
|
end
|
70
81
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright (c) 2007-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/dsl/expression'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module DSL
|
26
|
+
module Opal
|
27
|
+
class BlockPropertyExpression < Expression
|
28
|
+
def can_interpret?(parent, keyword, *args, &block)
|
29
|
+
block_given? and
|
30
|
+
args.size == 0 and
|
31
|
+
parent.respond_to?("#{keyword}_block=")
|
32
|
+
end
|
33
|
+
|
34
|
+
def interpret(parent, keyword, *args, &block)
|
35
|
+
parent.send("#{keyword}_block=", block)
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/glimmer/dsl/opal/dsl.rb
CHANGED
@@ -25,6 +25,7 @@ require 'glimmer/dsl/opal/custom_widget_expression'
|
|
25
25
|
require 'glimmer/dsl/opal/swt_expression'
|
26
26
|
require 'glimmer/dsl/opal/radio_group_selection_data_binding_expression'
|
27
27
|
require 'glimmer/dsl/opal/checkbox_group_selection_data_binding_expression'
|
28
|
+
require 'glimmer/dsl/opal/block_property_expression'
|
28
29
|
|
29
30
|
module Glimmer
|
30
31
|
module DSL
|
@@ -42,6 +43,7 @@ module Glimmer
|
|
42
43
|
data_binding
|
43
44
|
font
|
44
45
|
layout
|
46
|
+
block_property
|
45
47
|
property
|
46
48
|
widget
|
47
49
|
]
|
@@ -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.first
|
11
12
|
@args = args
|
12
13
|
@block = block
|
13
14
|
@children = Set.new
|
@@ -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
|
-
|
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 =
|
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
14
|
def initialize(parent, args, block)
|
9
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-
|
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|
|
@@ -4,15 +4,22 @@ 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
|
-
|
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
13
|
def initialize(parent, args, block)
|
12
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
|
@@ -25,13 +32,33 @@ module Glimmer
|
|
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
|
-
|
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
|
@@ -41,6 +68,15 @@ module Glimmer
|
|
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
82
|
end
|
@@ -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
|
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
|
@@ -96,6 +271,9 @@ 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
|
@@ -103,6 +281,16 @@ module Glimmer
|
|
103
281
|
def redraw
|
104
282
|
super()
|
105
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
|
@@ -136,6 +324,10 @@ module Glimmer
|
|
136
324
|
}
|
137
325
|
end
|
138
326
|
|
327
|
+
def thead_dom_element
|
328
|
+
dom_element.find('thead')
|
329
|
+
end
|
330
|
+
|
139
331
|
def items_dom
|
140
332
|
tbody {
|
141
333
|
}
|
@@ -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
|