glimmer-dsl-opal 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +16 -14
- data/VERSION +1 -1
- data/lib/glimmer-dsl-opal.rb +58 -0
- data/lib/glimmer-dsl-opal/ext/date.rb +1 -1
- data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +3 -3
- data/lib/glimmer-dsl-swt.rb +20 -35
- data/lib/glimmer/data_binding/table_items_binding.rb +4 -2
- data/lib/glimmer/dsl/opal/widget_expression.rb +6 -2
- data/lib/glimmer/swt/composite_proxy.rb +5 -1
- data/lib/glimmer/swt/control_editor.rb +53 -0
- data/lib/glimmer/swt/layout_proxy.rb +1 -1
- 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 +28 -0
- data/lib/glimmer/swt/table_proxy.rb +357 -11
- data/lib/glimmer/swt/widget_proxy.rb +73 -9
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4e81c8aae870295468f5c0e573da962daa58837efda4742c9855313ae29f42a
|
4
|
+
data.tar.gz: 40df246c27977d3fa862a452cdfb2dd99ad0b506374408c69e25666b3fc7fa50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c46c3bdfcc129557ac54640d2d905cb7495f010ff1b81422c5b55529a01ecb67c698b4724029b62b9cbc6bcb46727763185ba1b4469c0355259d16acd1f228f1
|
7
|
+
data.tar.gz: 803c487121b4092f024fabca666e359fcdfeca87482b95a391e6b857b19dca28f46a845fc46e6c189e73254c1aa3a1f53d8cbe51c113f425be5019544a353913
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.7.1
|
4
|
+
|
5
|
+
- Combo table editor (enabled in Hello, Table! sample)
|
6
|
+
- Fix issue with table cell selection for editing not working
|
7
|
+
- Remove widget from parent upon dispose
|
8
|
+
- Remove listeners upon widget dispose
|
9
|
+
|
3
10
|
## 0.7.0
|
4
11
|
|
5
12
|
- Hello, Table! Sample
|
@@ -127,3 +134,4 @@
|
|
127
134
|
|
128
135
|
- Initial support for webifying Glimmer SWT apps
|
129
136
|
- Support for Shell and Label widgets (text property only).
|
137
|
+
- Hello, World! sample support
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Opal 0.7.
|
1
|
+
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Opal 0.7.1 (Pure Ruby Web GUI)
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/glimmer-dsl-opal.svg)](http://badge.fury.io/rb/glimmer-dsl-opal)
|
3
3
|
[![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
4
4
|
|
@@ -8,11 +8,11 @@
|
|
8
8
|
|
9
9
|
Use in one of two ways:
|
10
10
|
- **Direct:** build the GUI of web apps with the same friendly desktop GUI Ruby syntax as [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt), thus requiring a lot less code than web technologies that is in pure Ruby and avoiding opaque web concepts like 'render' and 'reactive'. No HTML/JS/CSS skills are even required. Web designers may be involved with CSS styling only if needed.
|
11
|
-
- **Adapter:**
|
11
|
+
- **Adapter:** auto-webify [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps (i.e. apps built with [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)) via [Opal](https://opalrb.com/) on [Rails](https://rubyonrails.org/) without changing a line of code. Just insert them as a single require statement in a Rails app, and BOOM! They're running on the web! Apps may then optionally be custom-styled for the web by web designers with standard CSS if needed.
|
12
12
|
|
13
13
|
Glimmer DSL for Opal successfully reuses the entire [Glimmer](https://github.com/AndyObtiva/glimmer) core DSL engine in [Opal Ruby](https://opalrb.com/) inside a web browser, and as such inherits the full range of powerful Glimmer desktop [data-binding](https://github.com/AndyObtiva/glimmer#data-binding) capabilities for the web.
|
14
14
|
|
15
|
-
NOTE: Alpha Version 0.7.
|
15
|
+
NOTE: Alpha Version 0.7.1 only supports bare-minimum capabilities for the following [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt) [samples](https://github.com/AndyObtiva/glimmer#samples):
|
16
16
|
|
17
17
|
Hello:
|
18
18
|
|
@@ -49,16 +49,6 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
|
|
49
49
|
- [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
|
50
50
|
- [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS (Cascading Style Sheets)
|
51
51
|
|
52
|
-
## Background
|
53
|
-
|
54
|
-
The original idea behind Glimmer DSL for Opal was that you start by having a [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) desktop app that communicates with a Rails API for any web/cloud concerns. The GUI DSL is very simple in Glimmer DSL for SWT. Once the app is built. You simply embed it in a Rails app as a one line require statement after adding the Glimmer DSL for Opal gem, and BOOM, it just works on the web inside a web browser with the same server/client communication you had in the desktop app (I am working on adding minimal support for net/http in Opal so that desktop apps that use it continue to work in a web browser).
|
55
|
-
|
56
|
-
Part of the idea is that web browsers just render GUI widgets similar to those of a desktop app (after all a web browser is a desktop app), so whether you run your GUI on the desktop or on the web should just be a low-level concern, hopefully automated completely with Glimmer DSL for Opal.
|
57
|
-
|
58
|
-
Last but not least, you would likely want some special branding on the web, so you can push that off to a web designer who would be more than happy to do the web graphic design and customize the look and feel with pure CSS (no need for programming with Ruby or JavaScript). This enables a clean separation of concerns and distribution of tasks among developers and designers, let alone saving effort on the web GUI by reusing the desktop GUI as a base right off the bat.
|
59
|
-
|
60
|
-
Alternatively, web developers may directly use [Glimmer DSL for Opal](https://rubygems.org/gems/glimmer-dsl-opal) to build the GUI of web apps since it is as simple as desktop development, thus requiring a lot less code that is in pure Ruby only (as demonstrated in examples below) and avoiding opaque web concepts like 'render' and 'reactive' due to treating GUI as persistent just like desktop apps do. No HTML/JS/CSS skills are even required. Still, web designers may be involved with CSS only if needed, thanks to the clean semantic markup [Glimmer DSL for Opal](https://rubygems.org/gems/glimmer-dsl-opal) produces.
|
61
|
-
|
62
52
|
## Supported Glimmer DSL Keywords
|
63
53
|
|
64
54
|
The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt) have partial support in Opal:
|
@@ -99,6 +89,16 @@ Event loop:
|
|
99
89
|
- `display`
|
100
90
|
- `async_exec`
|
101
91
|
|
92
|
+
## Background
|
93
|
+
|
94
|
+
The original idea behind Glimmer DSL for Opal was that you start by having a [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) desktop app that communicates with a Rails API for any web/cloud concerns. The pure Ruby [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) is very simple, so it is more productive to build GUI in it since it does not go through a server/client request/response cycle and can be iterated on locally with a much shorter feedback cycle. Once the GUI and the rest of the app is built. You simply embed it in a Rails app as a one line require statement after adding the Glimmer DSL for Opal gem, and BOOM, it just works on the web inside a web browser with the same server/client communication you had in the desktop app (I am working on adding minimal support for net/http in Opal so that desktop apps that use it continue to work in a web browser. Until then, just use [Opal-jQuery](https://github.com/opal/opal-jquery) http support). That way, you get two apps for one: desktop and web.
|
95
|
+
|
96
|
+
Part of the idea is that web browsers just render GUI widgets similar to those of a desktop app (after all a web browser is a desktop app), so whether you run your GUI on the desktop or on the web should just be a low-level concern, hopefully automated completely with Glimmer DSL for Opal.
|
97
|
+
|
98
|
+
Last but not least, you would likely want some special branding on the web, so you can push that off to a web designer who would be more than happy to do the web graphic design and customize the look and feel with pure CSS (no need for programming with Ruby or JavaScript). This enables a clean separation of concerns and distribution of tasks among developers and designers, let alone saving effort on the web GUI by reusing the desktop GUI as a base right off the bat.
|
99
|
+
|
100
|
+
Alternatively, web developers may directly use [Glimmer DSL for Opal](https://rubygems.org/gems/glimmer-dsl-opal) to build the GUI of web apps since it is as simple as desktop development, thus requiring a lot less code that is in pure Ruby only (as demonstrated in examples below) and avoiding opaque web concepts like 'render' and 'reactive' due to treating GUI as persistent just like desktop apps do. No HTML/JS/CSS skills are even required. Still, web designers may be involved with CSS only if needed, thanks to the clean semantic markup [Glimmer DSL for Opal](https://rubygems.org/gems/glimmer-dsl-opal) automatically produces.
|
101
|
+
|
102
102
|
## Pre-requisites
|
103
103
|
|
104
104
|
- Rails 5: [https://github.com/rails/rails/tree/5-2-stable](https://github.com/rails/rails/tree/5-2-stable)
|
@@ -133,7 +133,7 @@ Add the following to `Gemfile`:
|
|
133
133
|
gem 'opal-rails', '~> 1.1.2'
|
134
134
|
gem 'opal-async', '~> 1.2.0'
|
135
135
|
gem 'opal-jquery', '~> 0.4.4'
|
136
|
-
gem 'glimmer-dsl-opal', '~> 0.7.
|
136
|
+
gem 'glimmer-dsl-opal', '~> 0.7.1'
|
137
137
|
gem 'glimmer-dsl-xml', '~> 1.1.0', require: false
|
138
138
|
gem 'glimmer-dsl-css', '~> 1.1.0', require: false
|
139
139
|
|
@@ -170,6 +170,8 @@ Edit `app/views/layouts/application.html.erb` and add the following below other
|
|
170
170
|
<%= stylesheet_link_tag 'glimmer/glimmer', media: 'all', 'data-turbolinks-track': 'reload' %>
|
171
171
|
```
|
172
172
|
|
173
|
+
Clear the file `app/views/welcomes/index.html.erb` from any content.
|
174
|
+
|
173
175
|
Open a `Document.ready?` block and add inside it Glimmer GUI DSL code or a require statement for one of the samples below.
|
174
176
|
|
175
177
|
```ruby
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.1
|
data/lib/glimmer-dsl-opal.rb
CHANGED
@@ -1,3 +1,24 @@
|
|
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 'opal'
|
2
23
|
|
3
24
|
GLIMMER_DSL_OPAL_ROOT = File.expand_path('../..', __FILE__)
|
@@ -45,6 +66,7 @@ if RUBY_ENGINE == 'opal'
|
|
45
66
|
require 'glimmer-dsl-xml'
|
46
67
|
require 'glimmer-dsl-css'
|
47
68
|
Element.alias_native :replace_with, :replaceWith
|
69
|
+
Element.alias_native :select
|
48
70
|
|
49
71
|
# Glimmer::Config.loop_max_count = 20
|
50
72
|
|
@@ -54,6 +76,42 @@ if RUBY_ENGINE == 'opal'
|
|
54
76
|
result ||= method == '<<'
|
55
77
|
result ||= method == 'handle'
|
56
78
|
end
|
79
|
+
|
80
|
+
class OS
|
81
|
+
class << self
|
82
|
+
def windows?
|
83
|
+
# No Op in Opal
|
84
|
+
end
|
85
|
+
|
86
|
+
def mac?
|
87
|
+
# No Op in Opal
|
88
|
+
end
|
89
|
+
|
90
|
+
def linux?
|
91
|
+
# No Op in Opal
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class File
|
97
|
+
class << self
|
98
|
+
def read(*args, &block)
|
99
|
+
# TODO implement via asset downloads in the future
|
100
|
+
# No Op in Opal
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Display
|
106
|
+
class << self
|
107
|
+
def setAppName(app_name)
|
108
|
+
# No Op in Opal
|
109
|
+
end
|
110
|
+
def setAppVersion(version)
|
111
|
+
# No Op in Opal
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
57
115
|
else
|
58
116
|
require_relative 'glimmer/engine'
|
59
117
|
end
|
@@ -45,7 +45,7 @@ class Time
|
|
45
45
|
alias new_original new
|
46
46
|
def new(*args)
|
47
47
|
if args.size >= 7
|
48
|
-
|
48
|
+
Glimmer::Config.logger.debug "Dropped timezone #{args[6]} from Time.new(#{args.map(&:to_s)}) constructor arguments since Opal does not support it!"
|
49
49
|
args = args[0...6]
|
50
50
|
end
|
51
51
|
new_original(*args)
|
@@ -218,17 +218,17 @@ class HelloTable
|
|
218
218
|
table_column {
|
219
219
|
text 'Ballpark'
|
220
220
|
width 180
|
221
|
-
|
221
|
+
editor :none
|
222
222
|
}
|
223
223
|
table_column {
|
224
224
|
text 'Home Team'
|
225
225
|
width 150
|
226
|
-
|
226
|
+
editor :combo, :read_only # read_only is simply an SWT style passed to combo widget
|
227
227
|
}
|
228
228
|
table_column {
|
229
229
|
text 'Away Team'
|
230
230
|
width 150
|
231
|
-
|
231
|
+
editor :combo, :read_only # read_only is simply an SWT style passed to combo widget
|
232
232
|
}
|
233
233
|
table_column {
|
234
234
|
text 'Promotion'
|
data/lib/glimmer-dsl-swt.rb
CHANGED
@@ -1,37 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# No Op in Opal
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class Display
|
27
|
-
class << self
|
28
|
-
def setAppName(app_name)
|
29
|
-
# No Op in Opal
|
30
|
-
end
|
31
|
-
def setAppVersion(version)
|
32
|
-
# No Op in Opal
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
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.
|
36
21
|
|
37
22
|
require 'glimmer-dsl-opal'
|
@@ -35,7 +35,7 @@ module Glimmer
|
|
35
35
|
model_cells = new_model_collection.to_a.map {|m| @table.cells_for(m)}
|
36
36
|
return if table_cells == model_cells
|
37
37
|
if new_model_collection and new_model_collection.is_a?(Array)
|
38
|
-
# @table_items_observer_registration&.unobserve
|
38
|
+
# @table_items_observer_registration&.unobserve # TODO re-enable
|
39
39
|
@table_items_observer_registration = observe(new_model_collection, @column_properties)
|
40
40
|
add_dependent(@table_observer_registration => @table_items_observer_registration)
|
41
41
|
@model_collection = new_model_collection
|
@@ -45,8 +45,10 @@ module Glimmer
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def populate_table(model_collection, parent, column_properties)
|
48
|
-
|
48
|
+
@skip_populate_table = model_collection&.sort_by(&:hash).map {|m| @table.column_properties.map {|p| m.send(p)}} == @last_populated_model_collection_properties
|
49
|
+
return if @skip_populate_table
|
49
50
|
@last_populated_model_collection = model_collection
|
51
|
+
@last_populated_model_collection_properties = model_collection&.sort_by(&:hash).map {|m| @table.column_properties.map {|p| m.send(p)}}
|
50
52
|
# TODO improve performance
|
51
53
|
selected_table_item_models = parent.selection.map(&:get_data)
|
52
54
|
old_items = parent.items
|
@@ -20,8 +20,12 @@ module Glimmer
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def add_content(parent, &block)
|
23
|
-
|
24
|
-
|
23
|
+
if parent.rendered?
|
24
|
+
super(parent, &block)
|
25
|
+
parent.post_add_content
|
26
|
+
else
|
27
|
+
parent.add_content_on_render(&block)
|
28
|
+
end
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -0,0 +1,53 @@
|
|
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
|
+
module Glimmer
|
23
|
+
module SWT
|
24
|
+
# Emulates SWT's native org.eclipse.swt.custom.ControlEditor
|
25
|
+
class ControlEditor
|
26
|
+
ATTRIBUTES = [:grabHorizontal, :grabVertical, :horizontalAlignment, :verticalAlignment, :minimumWidth, :minimumHeight]
|
27
|
+
attr_accessor *ATTRIBUTES
|
28
|
+
ATTRIBUTES.each do |attribute|
|
29
|
+
alias_method attribute.underscore, attribute
|
30
|
+
alias_method "#{attribute.underscore}=", "#{attribute}="
|
31
|
+
end
|
32
|
+
|
33
|
+
# TODO consider supporting a java_attr_accessor to get around having to generate all the aliases manually
|
34
|
+
attr_accessor :editor
|
35
|
+
alias getEditor editor
|
36
|
+
alias get_editor editor
|
37
|
+
alias setEditor editor=
|
38
|
+
alias set_editor editor=
|
39
|
+
|
40
|
+
# TODO implement `#layout` method if needed
|
41
|
+
|
42
|
+
attr_reader :composite
|
43
|
+
|
44
|
+
def initialize(composite)
|
45
|
+
@composite = composite
|
46
|
+
end
|
47
|
+
|
48
|
+
# TODO implement showing editor for composite or canvas
|
49
|
+
# def editor=(widget)
|
50
|
+
# end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
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
|
|
@@ -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', '90%') # just a good enough approximation
|
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
|
|
@@ -1,20 +1,242 @@
|
|
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.minimumHeight = 10
|
47
|
+
table_editor_widget_proxy = text(*args) {
|
48
|
+
text model.send(property)
|
49
|
+
focus true
|
50
|
+
on_focus_lost {
|
51
|
+
table_proxy.finish_edit!
|
52
|
+
}
|
53
|
+
on_key_pressed { |key_event|
|
54
|
+
if key_event.keyCode == swt(:cr)
|
55
|
+
table_proxy.finish_edit!
|
56
|
+
elsif key_event.keyCode == swt(:esc)
|
57
|
+
table_proxy.cancel_edit!
|
58
|
+
end
|
59
|
+
}
|
60
|
+
}
|
61
|
+
# table_editor_widget_proxy.swt_widget.selectAll # TODO select all
|
62
|
+
table_editor_widget_proxy
|
63
|
+
end,
|
64
|
+
},
|
65
|
+
combo: {
|
66
|
+
widget_value_property: :text,
|
67
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
68
|
+
first_time = true
|
69
|
+
table_proxy.table_editor.minimumHeight = 18
|
70
|
+
table_editor_widget_proxy = combo(*args) {
|
71
|
+
items model.send("#{property}_options")
|
72
|
+
text model.send(property)
|
73
|
+
focus true
|
74
|
+
on_focus_lost {
|
75
|
+
table_proxy.finish_edit!
|
76
|
+
}
|
77
|
+
on_key_pressed { |key_event|
|
78
|
+
if key_event.keyCode == swt(:cr)
|
79
|
+
table_proxy.finish_edit!
|
80
|
+
elsif key_event.keyCode == swt(:esc)
|
81
|
+
table_proxy.cancel_edit!
|
82
|
+
end
|
83
|
+
}
|
84
|
+
on_widget_selected {
|
85
|
+
if !OS.windows? || !first_time || first_time && model.send(property) != table_editor_widget_proxy.text
|
86
|
+
table_proxy.finish_edit!
|
87
|
+
end
|
88
|
+
}
|
89
|
+
}
|
90
|
+
table_editor_widget_proxy
|
91
|
+
end,
|
92
|
+
},
|
93
|
+
checkbox: {
|
94
|
+
widget_value_property: :selection,
|
95
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
96
|
+
first_time = true
|
97
|
+
table_proxy.table_editor.minimumHeight = 25
|
98
|
+
checkbox(*args) {
|
99
|
+
selection model.send(property)
|
100
|
+
focus true
|
101
|
+
on_widget_selected {
|
102
|
+
table_proxy.finish_edit!
|
103
|
+
}
|
104
|
+
on_focus_lost {
|
105
|
+
table_proxy.finish_edit!
|
106
|
+
}
|
107
|
+
on_key_pressed { |key_event|
|
108
|
+
if key_event.keyCode == swt(:cr)
|
109
|
+
table_proxy.finish_edit!
|
110
|
+
elsif key_event.keyCode == swt(:esc)
|
111
|
+
table_proxy.cancel_edit!
|
112
|
+
end
|
113
|
+
}
|
114
|
+
}
|
115
|
+
end,
|
116
|
+
},
|
117
|
+
date: {
|
118
|
+
widget_value_property: :date_time,
|
119
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
120
|
+
first_time = true
|
121
|
+
table_proxy.table_editor.minimumHeight = 25
|
122
|
+
date(*args) {
|
123
|
+
date_time model.send(property)
|
124
|
+
focus true
|
125
|
+
on_focus_lost {
|
126
|
+
table_proxy.finish_edit!
|
127
|
+
}
|
128
|
+
on_key_pressed { |key_event|
|
129
|
+
if key_event.keyCode == swt(:cr)
|
130
|
+
table_proxy.finish_edit!
|
131
|
+
elsif key_event.keyCode == swt(:esc)
|
132
|
+
table_proxy.cancel_edit!
|
133
|
+
end
|
134
|
+
}
|
135
|
+
}
|
136
|
+
end,
|
137
|
+
},
|
138
|
+
date_drop_down: {
|
139
|
+
widget_value_property: :date_time,
|
140
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
141
|
+
first_time = true
|
142
|
+
table_proxy.table_editor.minimumHeight = 25
|
143
|
+
date_drop_down(*args) {
|
144
|
+
date_time model.send(property)
|
145
|
+
focus true
|
146
|
+
on_focus_lost {
|
147
|
+
table_proxy.finish_edit!
|
148
|
+
}
|
149
|
+
on_key_pressed { |key_event|
|
150
|
+
if key_event.keyCode == swt(:cr)
|
151
|
+
table_proxy.finish_edit!
|
152
|
+
elsif key_event.keyCode == swt(:esc)
|
153
|
+
table_proxy.cancel_edit!
|
154
|
+
end
|
155
|
+
}
|
156
|
+
}
|
157
|
+
end,
|
158
|
+
},
|
159
|
+
time: {
|
160
|
+
widget_value_property: :date_time,
|
161
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
162
|
+
first_time = true
|
163
|
+
table_proxy.table_editor.minimumHeight = 25
|
164
|
+
time(*args) {
|
165
|
+
date_time model.send(property)
|
166
|
+
focus true
|
167
|
+
on_focus_lost {
|
168
|
+
table_proxy.finish_edit!
|
169
|
+
}
|
170
|
+
on_key_pressed { |key_event|
|
171
|
+
if key_event.keyCode == swt(:cr)
|
172
|
+
table_proxy.finish_edit!
|
173
|
+
elsif key_event.keyCode == swt(:esc)
|
174
|
+
table_proxy.cancel_edit!
|
175
|
+
end
|
176
|
+
}
|
177
|
+
}
|
178
|
+
end,
|
179
|
+
},
|
180
|
+
radio: {
|
181
|
+
widget_value_property: :selection,
|
182
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
183
|
+
first_time = true
|
184
|
+
table_proxy.table_editor.minimumHeight = 25
|
185
|
+
radio(*args) {
|
186
|
+
selection model.send(property)
|
187
|
+
focus true
|
188
|
+
on_widget_selected {
|
189
|
+
table_proxy.finish_edit!
|
190
|
+
}
|
191
|
+
on_focus_lost {
|
192
|
+
table_proxy.finish_edit!
|
193
|
+
}
|
194
|
+
on_key_pressed { |key_event|
|
195
|
+
if key_event.keyCode == swt(:cr)
|
196
|
+
table_proxy.finish_edit!
|
197
|
+
elsif key_event.keyCode == swt(:esc)
|
198
|
+
table_proxy.cancel_edit!
|
199
|
+
end
|
200
|
+
}
|
201
|
+
}
|
202
|
+
end,
|
203
|
+
},
|
204
|
+
spinner: {
|
205
|
+
widget_value_property: :selection,
|
206
|
+
editor_gui: lambda do |args, model, property, table_proxy|
|
207
|
+
first_time = true
|
208
|
+
table_proxy.table_editor.minimumHeight = 25
|
209
|
+
table_editor_widget_proxy = spinner(*args) {
|
210
|
+
selection model.send(property)
|
211
|
+
focus true
|
212
|
+
on_focus_lost {
|
213
|
+
table_proxy.finish_edit!
|
214
|
+
}
|
215
|
+
on_key_pressed { |key_event|
|
216
|
+
if key_event.keyCode == swt(:cr)
|
217
|
+
table_proxy.finish_edit!
|
218
|
+
elsif key_event.keyCode == swt(:esc)
|
219
|
+
table_proxy.cancel_edit!
|
220
|
+
end
|
221
|
+
}
|
222
|
+
}
|
223
|
+
table_editor_widget_proxy
|
224
|
+
end,
|
225
|
+
},
|
226
|
+
}
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
13
230
|
def initialize(parent, args, block)
|
14
231
|
super(parent, args, block)
|
15
232
|
@columns = []
|
16
233
|
@children = []
|
234
|
+
@editors = []
|
17
235
|
@selection = []
|
236
|
+
@table_editor = TableEditor.new(self)
|
237
|
+
@table_editor.horizontalAlignment = SWTProxy[:left]
|
238
|
+
@table_editor.grabHorizontal = true
|
239
|
+
@table_editor.minimumHeight = 20
|
18
240
|
if editable?
|
19
241
|
on_mouse_up { |event|
|
20
242
|
edit_table_item(event.table_item, event.column_index)
|
@@ -26,10 +248,24 @@ module Glimmer
|
|
26
248
|
def post_initialize_child(child)
|
27
249
|
if child.is_a?(TableColumnProxy)
|
28
250
|
@columns << child
|
29
|
-
|
251
|
+
child.render
|
252
|
+
elsif child.is_a?(TableItemProxy)
|
30
253
|
@children << child
|
254
|
+
child.render
|
255
|
+
else
|
256
|
+
@editors << child
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Executes for the parent of a child that just got disposed
|
261
|
+
def post_dispose_child(child)
|
262
|
+
if child.is_a?(TableColumnProxy)
|
263
|
+
@columns&.delete(child)
|
264
|
+
elsif child.is_a?(TableItemProxy)
|
265
|
+
@children&.delete(child)
|
266
|
+
else
|
267
|
+
@editors&.delete(child)
|
31
268
|
end
|
32
|
-
child.redraw
|
33
269
|
end
|
34
270
|
|
35
271
|
def post_add_content
|
@@ -38,6 +274,10 @@ module Glimmer
|
|
38
274
|
@initially_sorted = true
|
39
275
|
end
|
40
276
|
|
277
|
+
def default_layout
|
278
|
+
nil
|
279
|
+
end
|
280
|
+
|
41
281
|
def get_data(key=nil)
|
42
282
|
data
|
43
283
|
end
|
@@ -97,10 +337,6 @@ module Glimmer
|
|
97
337
|
self.selection = new_selection
|
98
338
|
end
|
99
339
|
|
100
|
-
def search(&condition)
|
101
|
-
items.select {|item| condition.nil? || condition.call(item)}
|
102
|
-
end
|
103
|
-
|
104
340
|
def sort_block=(comparator)
|
105
341
|
@sort_block = comparator
|
106
342
|
end
|
@@ -223,9 +459,118 @@ module Glimmer
|
|
223
459
|
@additional_sort_properties = args unless args.empty?
|
224
460
|
end
|
225
461
|
|
226
|
-
def
|
227
|
-
|
462
|
+
def editor=(args)
|
463
|
+
@editor = args
|
464
|
+
end
|
465
|
+
|
466
|
+
# Indicates if table is in edit mode, thus displaying a text widget for a table item cell
|
467
|
+
def edit_mode?
|
468
|
+
!!@edit_mode
|
469
|
+
end
|
470
|
+
|
471
|
+
def cancel_edit!
|
472
|
+
@cancel_edit&.call if @edit_mode
|
473
|
+
end
|
474
|
+
|
475
|
+
def finish_edit!
|
476
|
+
@finish_edit&.call if @edit_mode
|
477
|
+
end
|
478
|
+
|
479
|
+
# 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.
|
480
|
+
# It is set to false once change is saved to model
|
481
|
+
def edit_in_progress?
|
482
|
+
!!@edit_in_progress
|
483
|
+
end
|
484
|
+
|
485
|
+
def edit_selected_table_item(column_index, before_write: nil, after_write: nil, after_cancel: nil)
|
486
|
+
edit_table_item(selection.first, column_index, before_write: before_write, after_write: after_write, after_cancel: after_cancel)
|
487
|
+
end
|
488
|
+
|
489
|
+
# TODO migrate the following to the next method
|
490
|
+
# def edit_table_item(table_item, column_index)
|
491
|
+
# table_item&.edit(column_index) unless column_index.nil?
|
492
|
+
# end
|
493
|
+
|
494
|
+
def edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil)
|
495
|
+
return if table_item.nil? || (@edit_mode && @edit_table_item == table_item && @edit_column_index == column_index)
|
496
|
+
@edit_column_index = column_index
|
497
|
+
@edit_table_item = table_item
|
498
|
+
column_index = column_index.to_i
|
499
|
+
model = table_item.data
|
500
|
+
property = column_properties[column_index]
|
501
|
+
cancel_edit!
|
502
|
+
return unless columns[column_index].editable?
|
503
|
+
action_taken = false
|
504
|
+
@edit_mode = true
|
505
|
+
|
506
|
+
editor_config = columns[column_index].editor || editor
|
507
|
+
editor_config = [editor_config].flatten.compact
|
508
|
+
editor_widget_options = editor_config.last.is_a?(Hash) ? editor_config.last : {}
|
509
|
+
editor_widget_arg_last_index = editor_config.last.is_a?(Hash) ? -2 : -1
|
510
|
+
editor_widget = (editor_config[0] || :text).to_sym
|
511
|
+
editor_widget_args = editor_config[1..editor_widget_arg_last_index]
|
512
|
+
model_editing_property = editor_widget_options[:property] || property
|
513
|
+
widget_value_property = TableProxy::editors.symbolize_keys[editor_widget][:widget_value_property]
|
514
|
+
|
515
|
+
@cancel_edit = lambda do |event=nil|
|
516
|
+
@cancel_in_progress = true
|
517
|
+
@table_editor.cancel!
|
518
|
+
@table_editor_widget_proxy&.dispose
|
519
|
+
@table_editor_widget_proxy = nil
|
520
|
+
after_cancel&.call
|
521
|
+
@edit_in_progress = false
|
522
|
+
@cancel_in_progress = false
|
523
|
+
@cancel_edit = nil
|
524
|
+
@edit_table_item = @edit_column_index = nil if (@edit_mode && @edit_table_item == table_item && @edit_column_index == column_index)
|
525
|
+
@edit_mode = false
|
526
|
+
end
|
527
|
+
|
528
|
+
@finish_edit = lambda do |event=nil|
|
529
|
+
new_value = @table_editor_widget_proxy&.send(widget_value_property)
|
530
|
+
if table_item.disposed?
|
531
|
+
@cancel_edit.call
|
532
|
+
elsif !new_value.nil? && !action_taken && !@edit_in_progress && !@cancel_in_progress
|
533
|
+
action_taken = true
|
534
|
+
@edit_in_progress = true
|
535
|
+
if new_value == model.send(model_editing_property)
|
536
|
+
@cancel_edit.call
|
537
|
+
else
|
538
|
+
before_write&.call
|
539
|
+
@table_editor.save!(widget_value_property: widget_value_property)
|
540
|
+
model.send("#{model_editing_property}=", new_value) # makes table update itself, so must search for selected table item again
|
541
|
+
# Table refresh happens here because of model update triggering observers, so must retrieve table item again
|
542
|
+
edited_table_item = search { |ti| ti.data == model }.first
|
543
|
+
show_item(edited_table_item)
|
544
|
+
@table_editor_widget_proxy&.dispose
|
545
|
+
@table_editor_widget_proxy = nil
|
546
|
+
after_write&.call(edited_table_item)
|
547
|
+
@edit_in_progress = false
|
548
|
+
@edit_table_item = @edit_column_index = nil
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
content {
|
554
|
+
@table_editor_widget_proxy = TableProxy::editors.symbolize_keys[editor_widget][:editor_gui].call(editor_widget_args, model, model_editing_property, self)
|
555
|
+
}
|
556
|
+
@table_editor.set_editor(@table_editor_widget_proxy, table_item, column_index)
|
557
|
+
rescue => e
|
558
|
+
Glimmer::Config.logger.error {e.full_message}
|
559
|
+
raise e
|
560
|
+
end
|
561
|
+
|
562
|
+
def show_item(table_item)
|
563
|
+
table_item.dom_element.focus
|
564
|
+
end
|
565
|
+
|
566
|
+
def add_listener(underscored_listener_name, &block)
|
567
|
+
enhanced_block = lambda do |event|
|
568
|
+
event.extend(TableListenerEvent)
|
569
|
+
block.call(event)
|
570
|
+
end
|
571
|
+
super(underscored_listener_name, &enhanced_block)
|
228
572
|
end
|
573
|
+
|
229
574
|
|
230
575
|
def header_visible=(value)
|
231
576
|
@header_visible = value
|
@@ -337,7 +682,8 @@ module Glimmer
|
|
337
682
|
table_id = id
|
338
683
|
table_id_style = css
|
339
684
|
table_id_css_classes = css_classes
|
340
|
-
table_id_css_classes << 'table'
|
685
|
+
table_id_css_classes << 'table' unless table_id_css_classes.include?('table')
|
686
|
+
table_id_css_classes << 'editable' if editable? && !table_id_css_classes.include?('editable')
|
341
687
|
table_id_css_classes_string = table_id_css_classes.to_a.join(' ')
|
342
688
|
@dom ||= html {
|
343
689
|
table(id: table_id, style: table_id_style, class: table_id_css_classes_string) {
|
@@ -29,7 +29,10 @@ module Glimmer
|
|
29
29
|
include Glimmer
|
30
30
|
include PropertyOwner
|
31
31
|
|
32
|
-
attr_reader :parent, :args, :path, :children, :enabled, :foreground, :background, :font, :focus
|
32
|
+
attr_reader :parent, :args, :path, :children, :enabled, :foreground, :background, :font, :focus, :disposed?, :rendered
|
33
|
+
alias isDisposed disposed?
|
34
|
+
alias is_disposed disposed?
|
35
|
+
alias rendered? rendered
|
33
36
|
|
34
37
|
class << self
|
35
38
|
# Factory Method that translates a Glimmer DSL keyword into a WidgetProxy object
|
@@ -103,6 +106,7 @@ module Glimmer
|
|
103
106
|
@block = block
|
104
107
|
@children = Set.new # TODO consider moving to composite
|
105
108
|
@enabled = true
|
109
|
+
@data = {}
|
106
110
|
DEFAULT_INITIALIZERS[self.class.underscored_widget_name(self)]&.call(self)
|
107
111
|
@parent.post_initialize_child(self) # TODO rename to post_initialize_child to be closer to glimmer-dsl-swt terminology
|
108
112
|
end
|
@@ -113,17 +117,52 @@ module Glimmer
|
|
113
117
|
child.render
|
114
118
|
end
|
115
119
|
|
120
|
+
# Executes for the parent of a child that just got disposed
|
121
|
+
def post_dispose_child(child)
|
122
|
+
@children&.delete(child)
|
123
|
+
end
|
124
|
+
|
116
125
|
# Executes at the closing of a parent widget curly braces after all children/properties have been added/set
|
117
126
|
def post_add_content
|
118
127
|
# No Op by default
|
119
128
|
end
|
120
129
|
|
130
|
+
def set_data(key=nil, value)
|
131
|
+
@data[key] = value
|
132
|
+
end
|
133
|
+
alias setData set_data
|
134
|
+
alias data= set_data
|
135
|
+
|
136
|
+
def get_data(key=nil)
|
137
|
+
@data[key]
|
138
|
+
end
|
139
|
+
alias getData get_data
|
140
|
+
alias data get_data
|
141
|
+
|
121
142
|
def css_classes
|
122
143
|
dom_element.attr('class').to_s.split
|
123
144
|
end
|
124
145
|
|
125
146
|
def dispose
|
147
|
+
remove_all_listeners
|
126
148
|
Document.find(path).remove
|
149
|
+
parent&.post_dispose_child(self)
|
150
|
+
# TODO fire on_widget_disposed listener
|
151
|
+
@disposed = true
|
152
|
+
end
|
153
|
+
|
154
|
+
def remove_all_listeners
|
155
|
+
observation_request_to_event_mapping.keys.each do |keyword|
|
156
|
+
[observation_request_to_event_mapping[keyword]].flatten.each do |mapping|
|
157
|
+
@observation_requests[keyword].to_a.each do |event_listener|
|
158
|
+
event = mapping[:event]
|
159
|
+
event_handler = mapping[:event_handler]
|
160
|
+
event_element_css_selector = mapping[:event_element_css_selector]
|
161
|
+
the_listener_dom_element = event_element_css_selector ? Element[event_element_css_selector] : listener_dom_element
|
162
|
+
the_listener_dom_element.off(event)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
127
166
|
end
|
128
167
|
|
129
168
|
def path
|
@@ -172,12 +211,17 @@ module Glimmer
|
|
172
211
|
@parent.path
|
173
212
|
end
|
174
213
|
|
175
|
-
def
|
214
|
+
def parent_dom_element
|
215
|
+
Document.find(parent_path)
|
216
|
+
end
|
217
|
+
|
218
|
+
def render(custom_parent_dom_element = nil)
|
219
|
+
the_parent_dom_element = custom_parent_dom_element || parent_dom_element
|
176
220
|
old_element = dom_element
|
177
221
|
brand_new = @dom.nil? || old_element.empty?
|
178
|
-
build_dom
|
222
|
+
build_dom(!custom_parent_dom_element) # TODO handle custom parent layout by passing parent instead of parent dom element
|
179
223
|
if brand_new
|
180
|
-
|
224
|
+
the_parent_dom_element.append(@dom)
|
181
225
|
else
|
182
226
|
old_element.replace_with(@dom)
|
183
227
|
end
|
@@ -190,13 +234,29 @@ module Glimmer
|
|
190
234
|
children.each do |child|
|
191
235
|
child.render
|
192
236
|
end
|
237
|
+
@rendered = true
|
238
|
+
content_on_render_blocks.each { |content_block| content(&content_block) }
|
193
239
|
end
|
194
240
|
alias redraw render
|
195
241
|
|
196
|
-
def
|
242
|
+
def content_on_render_blocks
|
243
|
+
@content_on_render_blocks ||= []
|
244
|
+
end
|
245
|
+
|
246
|
+
def add_content_on_render(&content_block)
|
247
|
+
if rendered?
|
248
|
+
content_block.call
|
249
|
+
else
|
250
|
+
content_on_render_blocks << content_block
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def build_dom(layout=true)
|
255
|
+
# TODO consider passing parent element instead and having table item include a table cell widget only for opal
|
197
256
|
@dom = nil
|
198
257
|
@dom = dom
|
199
258
|
@dom = @parent.layout.dom(@dom) if @parent.respond_to?(:layout) && @parent.layout
|
259
|
+
@dom
|
200
260
|
end
|
201
261
|
|
202
262
|
def content(&block)
|
@@ -271,10 +331,6 @@ module Glimmer
|
|
271
331
|
element
|
272
332
|
end
|
273
333
|
|
274
|
-
def parent_dom_element
|
275
|
-
Document.find(parent_path)
|
276
|
-
end
|
277
|
-
|
278
334
|
def listener_path
|
279
335
|
path
|
280
336
|
end
|
@@ -334,6 +390,14 @@ module Glimmer
|
|
334
390
|
super(attribute_name, *args) # PropertyOwner
|
335
391
|
end
|
336
392
|
|
393
|
+
def method_missing(method, *args, &block)
|
394
|
+
if method.to_s.start_with?('on_')
|
395
|
+
handle_observation_request(method, &block)
|
396
|
+
else
|
397
|
+
super(method, *args, &block)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
337
401
|
def apply_property_type_converters(attribute_name, args)
|
338
402
|
if args.count == 1
|
339
403
|
value = args.first
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer-dsl-opal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -311,6 +311,7 @@ files:
|
|
311
311
|
- lib/glimmer/swt/color_proxy.rb
|
312
312
|
- lib/glimmer/swt/combo_proxy.rb
|
313
313
|
- lib/glimmer/swt/composite_proxy.rb
|
314
|
+
- lib/glimmer/swt/control_editor.rb
|
314
315
|
- lib/glimmer/swt/custom/checkbox_group.rb
|
315
316
|
- lib/glimmer/swt/custom/radio_group.rb
|
316
317
|
- lib/glimmer/swt/date_time_proxy.rb
|
@@ -338,6 +339,7 @@ files:
|
|
338
339
|
- lib/glimmer/swt/tab_folder_proxy.rb
|
339
340
|
- lib/glimmer/swt/tab_item_proxy.rb
|
340
341
|
- lib/glimmer/swt/table_column_proxy.rb
|
342
|
+
- lib/glimmer/swt/table_editor.rb
|
341
343
|
- lib/glimmer/swt/table_item_proxy.rb
|
342
344
|
- lib/glimmer/swt/table_proxy.rb
|
343
345
|
- lib/glimmer/swt/text_proxy.rb
|