glimmer-dsl-opal 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|