glimmer-dsl-opal 0.7.0 → 0.7.5
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 +41 -0
- data/README.md +290 -53
- data/VERSION +1 -1
- data/lib/display.rb +31 -0
- data/lib/file.rb +29 -0
- data/lib/glimmer-dsl-opal.rb +30 -1
- data/lib/glimmer-dsl-opal/ext/date.rb +1 -1
- data/lib/glimmer-dsl-opal/ext/struct.rb +37 -0
- data/lib/glimmer-dsl-opal/samples/elaborate/contact_manager.rb +50 -23
- data/lib/glimmer-dsl-opal/samples/elaborate/login.rb +22 -5
- data/lib/glimmer-dsl-opal/samples/hello/hello_browser.rb +1 -1
- data/lib/glimmer-dsl-opal/samples/hello/hello_button.rb +46 -0
- data/lib/glimmer-dsl-opal/samples/hello/hello_custom_shell.rb +7 -7
- data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +5 -5
- data/lib/glimmer-dsl-swt.rb +20 -35
- data/lib/glimmer/data_binding/table_items_binding.rb +6 -4
- data/lib/glimmer/dsl/opal/custom_widget_expression.rb +6 -0
- data/lib/glimmer/dsl/opal/widget_expression.rb +6 -2
- data/lib/glimmer/swt/combo_proxy.rb +40 -1
- data/lib/glimmer/swt/composite_proxy.rb +5 -1
- data/lib/glimmer/swt/control_editor.rb +54 -0
- data/lib/glimmer/swt/date_time_proxy.rb +66 -1
- data/lib/glimmer/swt/font_proxy.rb +4 -4
- data/lib/glimmer/swt/grid_layout_proxy.rb +20 -12
- data/lib/glimmer/swt/label_proxy.rb +11 -3
- data/lib/glimmer/swt/layout_data_proxy.rb +10 -7
- data/lib/glimmer/swt/layout_proxy.rb +1 -1
- data/lib/glimmer/swt/message_box_proxy.rb +2 -10
- data/lib/glimmer/swt/table_column_proxy.rb +9 -0
- data/lib/glimmer/swt/table_editor.rb +65 -0
- data/lib/glimmer/swt/table_item_proxy.rb +36 -0
- data/lib/glimmer/swt/table_proxy.rb +375 -17
- data/lib/glimmer/swt/text_proxy.rb +1 -1
- data/lib/glimmer/swt/widget_proxy.rb +99 -21
- data/lib/glimmer/ui/custom_shell.rb +9 -7
- data/lib/os.rb +36 -0
- metadata +25 -3
@@ -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
|
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,
|
@@ -44,10 +45,11 @@ module Glimmer
|
|
44
45
|
def horizontal_alignment=(horizontal_alignment)
|
45
46
|
@horizontal_alignment = horizontal_alignment
|
46
47
|
return if @horizontal_alignment.nil?
|
47
|
-
if @horizontal_alignment
|
48
|
-
@parent.dom_element.css('
|
49
|
-
|
50
|
-
@parent.dom_element.css('
|
48
|
+
if @horizontal_alignment != 'fill'
|
49
|
+
@parent.dom_element.css('text-align', @horizontal_alignment.to_s)
|
50
|
+
@parent.dom_element.css('place-self', @horizontal_alignment.to_s)
|
51
|
+
@parent.dom_element.css('margin-left', 'auto') if ['right', 'center'].include?(@horizontal_alignment.to_s)
|
52
|
+
@parent.dom_element.css('margin-right', 'auto') if ['left', 'center'].include?(@horizontal_alignment.to_s)
|
51
53
|
end
|
52
54
|
# TODO
|
53
55
|
# reapply
|
@@ -85,18 +87,19 @@ module Glimmer
|
|
85
87
|
|
86
88
|
def grab_excess_horizontal_space=(grab_excess_horizontal_space)
|
87
89
|
@grab_excess_horizontal_space = grab_excess_horizontal_space
|
88
|
-
@parent.dom_element.css('
|
90
|
+
@parent.dom_element.css('justify-self', @horizontal_alignment) if @grab_excess_horizontal_space && @horizontal_alignment != 'fill' && width_hint.nil?
|
91
|
+
@parent.parent.dom_element.css('justify-content', "normal") if @grab_excess_horizontal_space
|
89
92
|
# reapply
|
90
93
|
end
|
91
94
|
|
92
95
|
def grab_excess_vertical_space=(grab_excess_vertical_space)
|
93
96
|
@grab_excess_vertical_space = grab_excess_vertical_space
|
94
|
-
@parent.dom_element.css('height', "100%") if @grab_excess_vertical_space && height_hint.nil?
|
95
|
-
# TODO
|
97
|
+
@parent.dom_element.css('height', "100%") if @grab_excess_vertical_space && @vertical_alignment == 'fill' && height_hint.nil?
|
96
98
|
# reapply
|
97
99
|
end
|
98
100
|
|
99
101
|
def reapply
|
102
|
+
# TODO remove reapply method
|
100
103
|
# @parent.css = <<~CSS
|
101
104
|
# CSS
|
102
105
|
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
|
-
|
21
|
+
Glimmer::Config.logger.debug "Layout #{keyword} was not found!"
|
22
22
|
nil
|
23
23
|
end
|
24
24
|
|
@@ -8,7 +8,7 @@ module Glimmer
|
|
8
8
|
|
9
9
|
def initialize(parent, args, block)
|
10
10
|
i = 0
|
11
|
-
@parent = parent || DisplayProxy.instance.shells.
|
11
|
+
@parent = parent || DisplayProxy.instance.shells.last
|
12
12
|
@args = args
|
13
13
|
@block = block
|
14
14
|
@children = Set.new
|
@@ -30,16 +30,8 @@ module Glimmer
|
|
30
30
|
dom_element.find('.modal-content .message').html(@text)
|
31
31
|
end
|
32
32
|
|
33
|
-
def document
|
34
|
-
element = self
|
35
|
-
begin
|
36
|
-
element = element.parent
|
37
|
-
end while(element.parent)
|
38
|
-
element
|
39
|
-
end
|
40
|
-
|
41
33
|
def open
|
42
|
-
|
34
|
+
parent.post_initialize_child(self)
|
43
35
|
end
|
44
36
|
|
45
37
|
def hide
|
@@ -74,6 +74,15 @@ module Glimmer
|
|
74
74
|
dom_element.find('.sort-direction')
|
75
75
|
end
|
76
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
|
+
|
77
86
|
def observation_request_to_event_mapping
|
78
87
|
{
|
79
88
|
'on_widget_selected' => {
|
@@ -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,9 +1,33 @@
|
|
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
|
6
27
|
STYLE = <<~CSS
|
28
|
+
tr.table-item td {
|
29
|
+
padding-bottom: 0;
|
30
|
+
}
|
7
31
|
tr.table-item:nth-child(even):not(.selected) {
|
8
32
|
background: rgb(243, 244, 246);
|
9
33
|
}
|
@@ -60,6 +84,10 @@ module Glimmer
|
|
60
84
|
'tr'
|
61
85
|
end
|
62
86
|
|
87
|
+
def cell_dom_element(column_index)
|
88
|
+
dom_element.find("td:nth-child(#{column_index + 1})")
|
89
|
+
end
|
90
|
+
|
63
91
|
def redraw
|
64
92
|
super() #TODO re-enable and remove below lines
|
65
93
|
|
@@ -111,6 +139,14 @@ module Glimmer
|
|
111
139
|
redraw
|
112
140
|
end
|
113
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
|
+
|
114
150
|
def on_widget_selected(&block)
|
115
151
|
event = 'click'
|
116
152
|
delegate = $document.on(event, selector, &block)
|
@@ -1,20 +1,251 @@
|
|
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
|
require 'glimmer/swt/table_column_proxy'
|
24
|
+
require 'glimmer/swt/table_item_proxy'
|
25
|
+
require 'glimmer/swt/table_editor'
|
3
26
|
|
4
27
|
module Glimmer
|
5
28
|
module SWT
|
6
|
-
class TableProxy <
|
29
|
+
class TableProxy < CompositeProxy
|
7
30
|
attr_reader :columns, :selection,
|
8
|
-
:sort_type, :sort_column, :sort_property, :sort_block, :sort_by_block, :additional_sort_properties
|
31
|
+
:sort_type, :sort_column, :sort_property, :sort_block, :sort_by_block, :additional_sort_properties,
|
32
|
+
:editor, :table_editor
|
9
33
|
attr_accessor :column_properties, :item_count, :data
|
10
34
|
alias items children
|
11
35
|
alias model_binding data
|
12
36
|
|
37
|
+
class << self
|
38
|
+
include Glimmer
|
39
|
+
|
40
|
+
def editors
|
41
|
+
@editors ||= {
|
42
|
+
# ensure editor can work with string keys not just symbols (leave one string in for testing)
|
43
|
+
text: {
|
44
|
+
widget_value_property: :text,
|
45
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
46
|
+
table_proxy.table_editor.minimumWidth = 90
|
47
|
+
table_proxy.table_editor.minimumHeight = 10
|
48
|
+
table_editor_widget_proxy = text(*args) {
|
49
|
+
text model.send(property)
|
50
|
+
focus true
|
51
|
+
on_focus_lost {
|
52
|
+
table_proxy.finish_edit!
|
53
|
+
}
|
54
|
+
on_key_pressed { |key_event|
|
55
|
+
if key_event.keyCode == swt(:cr)
|
56
|
+
table_proxy.finish_edit!
|
57
|
+
elsif key_event.keyCode == swt(:esc)
|
58
|
+
table_proxy.cancel_edit!
|
59
|
+
end
|
60
|
+
}
|
61
|
+
}
|
62
|
+
# table_editor_widget_proxy.swt_widget.selectAll # TODO select all
|
63
|
+
table_editor_widget_proxy
|
64
|
+
end,
|
65
|
+
},
|
66
|
+
combo: {
|
67
|
+
widget_value_property: :text,
|
68
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
69
|
+
first_time = true
|
70
|
+
table_proxy.table_editor.minimumWidth = 90
|
71
|
+
table_proxy.table_editor.minimumHeight = 18
|
72
|
+
table_editor_widget_proxy = combo(*args) {
|
73
|
+
items model.send("#{property}_options")
|
74
|
+
text model.send(property)
|
75
|
+
focus true
|
76
|
+
on_focus_lost {
|
77
|
+
table_proxy.finish_edit!
|
78
|
+
}
|
79
|
+
on_key_pressed { |key_event|
|
80
|
+
if key_event.keyCode == swt(:cr)
|
81
|
+
table_proxy.finish_edit!
|
82
|
+
elsif key_event.keyCode == swt(:esc)
|
83
|
+
table_proxy.cancel_edit!
|
84
|
+
end
|
85
|
+
}
|
86
|
+
on_widget_selected {
|
87
|
+
if !OS.windows? || !first_time || first_time && model.send(property) != table_editor_widget_proxy.text
|
88
|
+
table_proxy.finish_edit!
|
89
|
+
end
|
90
|
+
}
|
91
|
+
}
|
92
|
+
table_editor_widget_proxy
|
93
|
+
end,
|
94
|
+
},
|
95
|
+
checkbox: {
|
96
|
+
widget_value_property: :selection,
|
97
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
98
|
+
first_time = true
|
99
|
+
table_proxy.table_editor.minimumHeight = 25
|
100
|
+
checkbox(*args) {
|
101
|
+
selection model.send(property)
|
102
|
+
focus true
|
103
|
+
on_widget_selected {
|
104
|
+
table_proxy.finish_edit!
|
105
|
+
}
|
106
|
+
on_focus_lost {
|
107
|
+
table_proxy.finish_edit!
|
108
|
+
}
|
109
|
+
on_key_pressed { |key_event|
|
110
|
+
if key_event.keyCode == swt(:cr)
|
111
|
+
table_proxy.finish_edit!
|
112
|
+
elsif key_event.keyCode == swt(:esc)
|
113
|
+
table_proxy.cancel_edit!
|
114
|
+
end
|
115
|
+
}
|
116
|
+
}
|
117
|
+
end,
|
118
|
+
},
|
119
|
+
date: {
|
120
|
+
widget_value_property: :date_time,
|
121
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
122
|
+
first_time = true
|
123
|
+
table_proxy.table_editor.minimumWidth = 90
|
124
|
+
table_proxy.table_editor.minimumHeight = 15
|
125
|
+
date(*args) {
|
126
|
+
date_time model.send(property)
|
127
|
+
focus true
|
128
|
+
on_widget_selected {
|
129
|
+
table_proxy.finish_edit!
|
130
|
+
}
|
131
|
+
on_key_pressed { |key_event|
|
132
|
+
if key_event.keyCode == swt(:cr)
|
133
|
+
table_proxy.finish_edit!
|
134
|
+
elsif key_event.keyCode == swt(:esc)
|
135
|
+
table_proxy.cancel_edit!
|
136
|
+
end
|
137
|
+
}
|
138
|
+
}
|
139
|
+
end,
|
140
|
+
},
|
141
|
+
date_drop_down: {
|
142
|
+
widget_value_property: :date_time,
|
143
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
144
|
+
first_time = true
|
145
|
+
table_proxy.table_editor.minimumWidth = 80
|
146
|
+
table_proxy.table_editor.minimumHeight = 15
|
147
|
+
date_drop_down(*args) {
|
148
|
+
date_time model.send(property)
|
149
|
+
focus true
|
150
|
+
on_widget_selected {
|
151
|
+
table_proxy.finish_edit!
|
152
|
+
}
|
153
|
+
on_key_pressed { |key_event|
|
154
|
+
if key_event.keyCode == swt(:cr)
|
155
|
+
table_proxy.finish_edit!
|
156
|
+
elsif key_event.keyCode == swt(:esc)
|
157
|
+
table_proxy.cancel_edit!
|
158
|
+
end
|
159
|
+
}
|
160
|
+
}
|
161
|
+
end,
|
162
|
+
},
|
163
|
+
time: {
|
164
|
+
widget_value_property: :date_time,
|
165
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
166
|
+
first_time = true
|
167
|
+
table_proxy.table_editor.minimumWidth = 80
|
168
|
+
table_proxy.table_editor.minimumHeight = 15
|
169
|
+
time(*args) {
|
170
|
+
date_time model.send(property)
|
171
|
+
focus true
|
172
|
+
on_widget_selected {
|
173
|
+
table_proxy.finish_edit!
|
174
|
+
}
|
175
|
+
on_focus_lost {
|
176
|
+
table_proxy.finish_edit!
|
177
|
+
}
|
178
|
+
on_key_pressed { |key_event|
|
179
|
+
if key_event.keyCode == swt(:cr)
|
180
|
+
table_proxy.finish_edit!
|
181
|
+
elsif key_event.keyCode == swt(:esc)
|
182
|
+
table_proxy.cancel_edit!
|
183
|
+
end
|
184
|
+
}
|
185
|
+
}
|
186
|
+
end,
|
187
|
+
},
|
188
|
+
radio: {
|
189
|
+
widget_value_property: :selection,
|
190
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
191
|
+
first_time = true
|
192
|
+
table_proxy.table_editor.minimumHeight = 25
|
193
|
+
radio(*args) {
|
194
|
+
selection model.send(property)
|
195
|
+
focus true
|
196
|
+
on_widget_selected {
|
197
|
+
table_proxy.finish_edit!
|
198
|
+
}
|
199
|
+
on_focus_lost {
|
200
|
+
table_proxy.finish_edit!
|
201
|
+
}
|
202
|
+
on_key_pressed { |key_event|
|
203
|
+
if key_event.keyCode == swt(:cr)
|
204
|
+
table_proxy.finish_edit!
|
205
|
+
elsif key_event.keyCode == swt(:esc)
|
206
|
+
table_proxy.cancel_edit!
|
207
|
+
end
|
208
|
+
}
|
209
|
+
}
|
210
|
+
end,
|
211
|
+
},
|
212
|
+
spinner: {
|
213
|
+
widget_value_property: :selection,
|
214
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
215
|
+
first_time = true
|
216
|
+
table_proxy.table_editor.minimumHeight = 25
|
217
|
+
table_editor_widget_proxy = spinner(*args) {
|
218
|
+
selection model.send(property)
|
219
|
+
focus true
|
220
|
+
on_focus_lost {
|
221
|
+
table_proxy.finish_edit!
|
222
|
+
}
|
223
|
+
on_key_pressed { |key_event|
|
224
|
+
if key_event.keyCode == swt(:cr)
|
225
|
+
table_proxy.finish_edit!
|
226
|
+
elsif key_event.keyCode == swt(:esc)
|
227
|
+
table_proxy.cancel_edit!
|
228
|
+
end
|
229
|
+
}
|
230
|
+
}
|
231
|
+
table_editor_widget_proxy
|
232
|
+
end,
|
233
|
+
},
|
234
|
+
}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
13
238
|
def initialize(parent, args, block)
|
14
239
|
super(parent, args, block)
|
15
240
|
@columns = []
|
16
241
|
@children = []
|
242
|
+
@editors = []
|
17
243
|
@selection = []
|
244
|
+
@table_editor = TableEditor.new(self)
|
245
|
+
@table_editor.horizontalAlignment = SWTProxy[:left]
|
246
|
+
@table_editor.grabHorizontal = true
|
247
|
+
@table_editor.minimumWidth = 90
|
248
|
+
@table_editor.minimumHeight = 20
|
18
249
|
if editable?
|
19
250
|
on_mouse_up { |event|
|
20
251
|
edit_table_item(event.table_item, event.column_index)
|
@@ -26,10 +257,24 @@ module Glimmer
|
|
26
257
|
def post_initialize_child(child)
|
27
258
|
if child.is_a?(TableColumnProxy)
|
28
259
|
@columns << child
|
29
|
-
|
260
|
+
child.render
|
261
|
+
elsif child.is_a?(TableItemProxy)
|
30
262
|
@children << child
|
263
|
+
child.render
|
264
|
+
else
|
265
|
+
@editors << child
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# Executes for the parent of a child that just got disposed
|
270
|
+
def post_dispose_child(child)
|
271
|
+
if child.is_a?(TableColumnProxy)
|
272
|
+
@columns&.delete(child)
|
273
|
+
elsif child.is_a?(TableItemProxy)
|
274
|
+
@children&.delete(child)
|
275
|
+
else
|
276
|
+
@editors&.delete(child)
|
31
277
|
end
|
32
|
-
child.redraw
|
33
278
|
end
|
34
279
|
|
35
280
|
def post_add_content
|
@@ -38,6 +283,10 @@ module Glimmer
|
|
38
283
|
@initially_sorted = true
|
39
284
|
end
|
40
285
|
|
286
|
+
def default_layout
|
287
|
+
nil
|
288
|
+
end
|
289
|
+
|
41
290
|
def get_data(key=nil)
|
42
291
|
data
|
43
292
|
end
|
@@ -60,11 +309,12 @@ module Glimmer
|
|
60
309
|
new_selection = new_selection.to_a
|
61
310
|
changed = (selection + new_selection) - (selection & new_selection)
|
62
311
|
@selection = new_selection
|
63
|
-
changed.each(&:
|
312
|
+
changed.each(&:redraw_selection)
|
64
313
|
end
|
65
314
|
|
66
315
|
def items=(new_items)
|
67
316
|
@children = new_items
|
317
|
+
# TODO optimize in the future by sorting elements in DOM directly when no change to elements occur other than sort
|
68
318
|
redraw
|
69
319
|
end
|
70
320
|
|
@@ -97,10 +347,6 @@ module Glimmer
|
|
97
347
|
self.selection = new_selection
|
98
348
|
end
|
99
349
|
|
100
|
-
def search(&condition)
|
101
|
-
items.select {|item| condition.nil? || condition.call(item)}
|
102
|
-
end
|
103
|
-
|
104
350
|
def sort_block=(comparator)
|
105
351
|
@sort_block = comparator
|
106
352
|
end
|
@@ -110,7 +356,7 @@ module Glimmer
|
|
110
356
|
end
|
111
357
|
|
112
358
|
def sort_property=(new_sort_property)
|
113
|
-
@sort_property =
|
359
|
+
@sort_property = new_sort_property.to_collection
|
114
360
|
end
|
115
361
|
|
116
362
|
def detect_sort_type
|
@@ -131,7 +377,7 @@ module Glimmer
|
|
131
377
|
|
132
378
|
def column_sort_properties
|
133
379
|
column_properties.zip(columns.map(&:sort_property)).map do |pair|
|
134
|
-
|
380
|
+
pair.compact.last.to_collection
|
135
381
|
end
|
136
382
|
end
|
137
383
|
|
@@ -162,7 +408,7 @@ module Glimmer
|
|
162
408
|
end
|
163
409
|
end
|
164
410
|
|
165
|
-
new_sort_property =
|
411
|
+
new_sort_property = new_sort_property.to_collection unless new_sort_property.is_a?(Array)
|
166
412
|
@sort_direction = @sort_direction.nil? || @sort_property.first != new_sort_property.first || @sort_direction == :descending ? :ascending : :descending
|
167
413
|
|
168
414
|
@sort_property = new_sort_property
|
@@ -223,9 +469,118 @@ module Glimmer
|
|
223
469
|
@additional_sort_properties = args unless args.empty?
|
224
470
|
end
|
225
471
|
|
226
|
-
def
|
227
|
-
|
472
|
+
def editor=(args)
|
473
|
+
@editor = args
|
474
|
+
end
|
475
|
+
|
476
|
+
# Indicates if table is in edit mode, thus displaying a text widget for a table item cell
|
477
|
+
def edit_mode?
|
478
|
+
!!@edit_mode
|
479
|
+
end
|
480
|
+
|
481
|
+
def cancel_edit!
|
482
|
+
@cancel_edit&.call if @edit_mode
|
483
|
+
end
|
484
|
+
|
485
|
+
def finish_edit!
|
486
|
+
@finish_edit&.call if @edit_mode
|
487
|
+
end
|
488
|
+
|
489
|
+
# Indicates if table is editing a table item because the user hit ENTER or focused out after making a change in edit mode to a table item cell.
|
490
|
+
# It is set to false once change is saved to model
|
491
|
+
def edit_in_progress?
|
492
|
+
!!@edit_in_progress
|
493
|
+
end
|
494
|
+
|
495
|
+
def edit_selected_table_item(column_index, before_write: nil, after_write: nil, after_cancel: nil)
|
496
|
+
edit_table_item(selection.first, column_index, before_write: before_write, after_write: after_write, after_cancel: after_cancel)
|
228
497
|
end
|
498
|
+
|
499
|
+
# TODO migrate the following to the next method
|
500
|
+
# def edit_table_item(table_item, column_index)
|
501
|
+
# table_item&.edit(column_index) unless column_index.nil?
|
502
|
+
# end
|
503
|
+
|
504
|
+
def edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil)
|
505
|
+
return if table_item.nil? || (@edit_mode && @edit_table_item == table_item && @edit_column_index == column_index)
|
506
|
+
@edit_column_index = column_index
|
507
|
+
@edit_table_item = table_item
|
508
|
+
column_index = column_index.to_i
|
509
|
+
model = table_item.data
|
510
|
+
property = column_properties[column_index]
|
511
|
+
cancel_edit!
|
512
|
+
return unless columns[column_index].editable?
|
513
|
+
action_taken = false
|
514
|
+
@edit_mode = true
|
515
|
+
|
516
|
+
editor_config = columns[column_index].editor || editor
|
517
|
+
editor_config = editor_config.to_collection
|
518
|
+
editor_widget_options = editor_config.last.is_a?(Hash) ? editor_config.last : {}
|
519
|
+
editor_widget_arg_last_index = editor_config.last.is_a?(Hash) ? -2 : -1
|
520
|
+
editor_widget = (editor_config[0] || :text).to_sym
|
521
|
+
editor_widget_args = editor_config[1..editor_widget_arg_last_index]
|
522
|
+
model_editing_property = editor_widget_options[:property] || property
|
523
|
+
widget_value_property = TableProxy::editors.symbolize_keys[editor_widget][:widget_value_property]
|
524
|
+
|
525
|
+
@cancel_edit = lambda do |event=nil|
|
526
|
+
@cancel_in_progress = true
|
527
|
+
@table_editor.cancel!
|
528
|
+
@table_editor_widget_proxy&.dispose
|
529
|
+
@table_editor_widget_proxy = nil
|
530
|
+
after_cancel&.call
|
531
|
+
@edit_in_progress = false
|
532
|
+
@cancel_in_progress = false
|
533
|
+
@cancel_edit = nil
|
534
|
+
@edit_table_item = @edit_column_index = nil if (@edit_mode && @edit_table_item == table_item && @edit_column_index == column_index)
|
535
|
+
@edit_mode = false
|
536
|
+
end
|
537
|
+
|
538
|
+
@finish_edit = lambda do |event=nil|
|
539
|
+
new_value = @table_editor_widget_proxy&.send(widget_value_property)
|
540
|
+
if table_item.disposed?
|
541
|
+
@cancel_edit.call
|
542
|
+
elsif !new_value.nil? && !action_taken && !@edit_in_progress && !@cancel_in_progress
|
543
|
+
action_taken = true
|
544
|
+
@edit_in_progress = true
|
545
|
+
if new_value == model.send(model_editing_property)
|
546
|
+
@cancel_edit.call
|
547
|
+
else
|
548
|
+
before_write&.call
|
549
|
+
@table_editor.save!(widget_value_property: widget_value_property)
|
550
|
+
model.send("#{model_editing_property}=", new_value) # makes table update itself, so must search for selected table item again
|
551
|
+
# Table refresh happens here because of model update triggering observers, so must retrieve table item again
|
552
|
+
edited_table_item = search { |ti| ti.data == model }.first
|
553
|
+
show_item(edited_table_item)
|
554
|
+
@table_editor_widget_proxy&.dispose
|
555
|
+
@table_editor_widget_proxy = nil
|
556
|
+
after_write&.call(edited_table_item)
|
557
|
+
@edit_in_progress = false
|
558
|
+
@edit_table_item = @edit_column_index = nil
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
content {
|
564
|
+
@table_editor_widget_proxy = TableProxy::editors.symbolize_keys[editor_widget][:editor_gui].call(editor_widget_args, model, model_editing_property, self)
|
565
|
+
}
|
566
|
+
@table_editor.set_editor(@table_editor_widget_proxy, table_item, column_index)
|
567
|
+
rescue => e
|
568
|
+
Glimmer::Config.logger.error {e.full_message}
|
569
|
+
raise e
|
570
|
+
end
|
571
|
+
|
572
|
+
def show_item(table_item)
|
573
|
+
table_item.dom_element.focus
|
574
|
+
end
|
575
|
+
|
576
|
+
def add_listener(underscored_listener_name, &block)
|
577
|
+
enhanced_block = lambda do |event|
|
578
|
+
event.extend(TableListenerEvent)
|
579
|
+
block.call(event)
|
580
|
+
end
|
581
|
+
super(underscored_listener_name, &enhanced_block)
|
582
|
+
end
|
583
|
+
|
229
584
|
|
230
585
|
def header_visible=(value)
|
231
586
|
@header_visible = value
|
@@ -259,7 +614,8 @@ module Glimmer
|
|
259
614
|
event.singleton_class.send(:define_method, :column_index) do
|
260
615
|
(table_data || event.target).attr('data-column-index')
|
261
616
|
end
|
262
|
-
|
617
|
+
|
618
|
+
event_listener.call(event) unless event.table_item.nil? && event.column_index.nil?
|
263
619
|
}
|
264
620
|
}
|
265
621
|
|
@@ -274,7 +630,8 @@ module Glimmer
|
|
274
630
|
},
|
275
631
|
'on_widget_selected' => {
|
276
632
|
event: 'mouseup',
|
277
|
-
|
633
|
+
event_handler: mouse_handler,
|
634
|
+
},
|
278
635
|
}
|
279
636
|
end
|
280
637
|
|
@@ -337,7 +694,8 @@ module Glimmer
|
|
337
694
|
table_id = id
|
338
695
|
table_id_style = css
|
339
696
|
table_id_css_classes = css_classes
|
340
|
-
table_id_css_classes << 'table'
|
697
|
+
table_id_css_classes << 'table' unless table_id_css_classes.include?('table')
|
698
|
+
table_id_css_classes << 'editable' if editable? && !table_id_css_classes.include?('editable')
|
341
699
|
table_id_css_classes_string = table_id_css_classes.to_a.join(' ')
|
342
700
|
@dom ||= html {
|
343
701
|
table(id: table_id, style: table_id_style, class: table_id_css_classes_string) {
|