glimmer-dsl-opal 0.0.2 → 0.0.7
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/README.md +704 -40
- data/VERSION +1 -1
- data/lib/glimmer-dsl-opal.rb +3 -2
- data/lib/glimmer/data_binding/element_binding.rb +1 -1
- data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
- data/lib/glimmer/data_binding/list_selection_binding.rb +51 -0
- data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/button_expression.rb +1 -0
- data/lib/glimmer/dsl/opal/dsl.rb +15 -1
- data/lib/glimmer/dsl/opal/grid_layout_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/layout_data_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/list_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb +42 -0
- data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
- data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
- data/lib/glimmer/dsl/opal/property_expression.rb +6 -2
- data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/text_expression.rb +22 -0
- data/lib/glimmer/opal/display_proxy.rb +23 -0
- data/lib/glimmer/opal/div_proxy.rb +9 -1
- data/lib/glimmer/opal/document_proxy.rb +131 -5
- data/lib/glimmer/opal/element_proxy.rb +246 -11
- data/lib/glimmer/opal/grid_layout_proxy.rb +54 -0
- data/lib/glimmer/opal/iframe_proxy.rb +23 -0
- data/lib/glimmer/opal/input_proxy.rb +16 -1
- data/lib/glimmer/opal/label_proxy.rb +2 -1
- data/lib/glimmer/opal/layout_data_proxy.rb +31 -0
- data/lib/glimmer/opal/list_proxy.rb +80 -0
- data/lib/glimmer/opal/modal.rb +94 -0
- data/lib/glimmer/opal/point.rb +5 -0
- data/lib/glimmer/opal/property_owner.rb +22 -0
- data/lib/glimmer/opal/select_proxy.rb +2 -1
- data/lib/glimmer/opal/tab_folder.rb +46 -0
- data/lib/glimmer/opal/tab_item.rb +98 -0
- data/lib/samples/elaborate/login.rb +0 -1
- data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
- data/lib/samples/hello/hello_tab.rb +2 -2
- metadata +25 -2
@@ -3,10 +3,18 @@ require 'glimmer/opal/element_proxy'
|
|
3
3
|
module Glimmer
|
4
4
|
module Opal
|
5
5
|
class DivProxy < ElementProxy
|
6
|
+
attr_reader :layout
|
7
|
+
|
8
|
+
def initialize(parent, args)
|
9
|
+
super(parent, args)
|
10
|
+
@layout = GridLayoutProxy.new(self, [])
|
11
|
+
end
|
12
|
+
|
6
13
|
def dom
|
7
14
|
div_id = id
|
15
|
+
div_style = css
|
8
16
|
@dom ||= DOM {
|
9
|
-
div(id: div_id, class: '
|
17
|
+
div(id: div_id, class: 'grid-layout', style: div_style)
|
10
18
|
}
|
11
19
|
end
|
12
20
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'glimmer/opal/element_proxy'
|
2
|
+
require 'glimmer/opal/point'
|
2
3
|
|
3
4
|
module Glimmer
|
4
5
|
module Opal
|
5
6
|
class DocumentProxy < ElementProxy
|
6
7
|
# TODO consider renaming to ShellProxy to match SWT API
|
8
|
+
attr_reader :minimum_size
|
7
9
|
|
8
10
|
def initialize(args)
|
9
11
|
@args = args
|
@@ -19,18 +21,139 @@ module Glimmer
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def text=(value)
|
22
|
-
$document.
|
24
|
+
$document.ready do
|
25
|
+
$document.title = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def minimum_size=(width_or_minimum_size, height = nil)
|
30
|
+
@minimum_size = height.nil? ? width_or_minimum_size : Point.new(width_or_minimum_size, height)
|
31
|
+
redraw
|
23
32
|
end
|
24
33
|
|
25
34
|
def head_dom
|
35
|
+
# TODO make grid-layout support grab excess space false
|
26
36
|
@head_dom ||= DOM {
|
27
37
|
head {
|
28
38
|
<<~CSS
|
29
39
|
<style>
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
html {
|
41
|
+
width: 100%;
|
42
|
+
height: 100%;
|
43
|
+
}
|
44
|
+
body {
|
45
|
+
width: 100%;
|
46
|
+
height: 100%;
|
47
|
+
margin: 0;
|
48
|
+
}
|
49
|
+
body > iframe {
|
50
|
+
width: 100%;
|
51
|
+
height: 100%;
|
52
|
+
}
|
53
|
+
ul {
|
54
|
+
list-style: none;
|
55
|
+
padding: 0;
|
56
|
+
}
|
57
|
+
li {
|
58
|
+
cursor: default;
|
59
|
+
padding-left: 10px;
|
60
|
+
padding-right: 10px;
|
61
|
+
}
|
62
|
+
li.selected-list-item {
|
63
|
+
background: rgb(80, 116, 211);
|
64
|
+
color: white;
|
65
|
+
}
|
66
|
+
li.empty-list-item {
|
67
|
+
color: transparent;
|
68
|
+
}
|
69
|
+
.tabs {
|
70
|
+
overflow: hidden;
|
71
|
+
border: 1px solid #ccc;
|
72
|
+
background-color: #f1f1f1;
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Style the buttons inside the tab */
|
76
|
+
.tabs .tab {
|
77
|
+
background-color: inherit;
|
78
|
+
float: left;
|
79
|
+
border: none;
|
80
|
+
outline: none;
|
81
|
+
cursor: pointer;
|
82
|
+
padding: 14px 16px;
|
83
|
+
transition: 0.3s;
|
84
|
+
font-size: 17px;
|
85
|
+
}
|
86
|
+
|
87
|
+
/* Change background color of buttons on hover */
|
88
|
+
.tabs .tab:hover {
|
89
|
+
background-color: #ddd;
|
90
|
+
}
|
91
|
+
|
92
|
+
/* Create an active/current tablink class */
|
93
|
+
.tabs .tab.active {
|
94
|
+
background-color: #ccc;
|
95
|
+
}
|
96
|
+
|
97
|
+
/* Style the tab content */
|
98
|
+
.tab-item {
|
99
|
+
padding: 6px 12px;
|
100
|
+
border: 1px solid #ccc;
|
101
|
+
border-top: none;
|
102
|
+
}
|
103
|
+
|
104
|
+
.hide {
|
105
|
+
display: none !important;
|
106
|
+
}
|
107
|
+
|
108
|
+
/* The Modal (background) */
|
109
|
+
.modal {
|
110
|
+
position: fixed; /* Stay in place */
|
111
|
+
z-index: 1; /* Sit on top */
|
112
|
+
padding-top: 100px; /* Location of the box */
|
113
|
+
left: 0;
|
114
|
+
top: 0;
|
115
|
+
width: 100%; /* Full width */
|
116
|
+
height: 100%; /* Full height */
|
117
|
+
overflow: auto; /* Enable scroll if needed */
|
118
|
+
background-color: rgb(0,0,0); /* Fallback color */
|
119
|
+
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
120
|
+
text-align: center;
|
121
|
+
}
|
122
|
+
|
123
|
+
/* Modal Content */
|
124
|
+
.modal-content {
|
125
|
+
background-color: #fefefe;
|
126
|
+
margin: auto;
|
127
|
+
border: 1px solid #888;
|
128
|
+
display: inline-block;
|
129
|
+
min-width: 200px;
|
130
|
+
}
|
131
|
+
|
132
|
+
.modal-content .text {
|
133
|
+
background: rgb(80, 116, 211);
|
134
|
+
color: white;
|
135
|
+
padding: 5px;
|
136
|
+
}
|
137
|
+
|
138
|
+
.modal-content .message {
|
139
|
+
padding: 20px;
|
140
|
+
}
|
141
|
+
|
142
|
+
/* The Close Button */
|
143
|
+
.close {
|
144
|
+
color: #aaaaaa;
|
145
|
+
float: right;
|
146
|
+
# font-size: 18px;
|
147
|
+
font-weight: bold;
|
148
|
+
margin: 5px;
|
33
149
|
}
|
150
|
+
|
151
|
+
.close:hover,
|
152
|
+
.close:focus {
|
153
|
+
color: #000;
|
154
|
+
text-decoration: none;
|
155
|
+
cursor: pointer;
|
156
|
+
}
|
34
157
|
</style>
|
35
158
|
CSS
|
36
159
|
}
|
@@ -38,8 +161,11 @@ module Glimmer
|
|
38
161
|
end
|
39
162
|
|
40
163
|
def dom
|
164
|
+
i = 0
|
165
|
+
body_style = ''
|
166
|
+
body_style += "min-width: #{@minimum_size.x}px; min-height: #{@minimum_size.y}px;" if @minimum_size
|
41
167
|
@dom ||= DOM {
|
42
|
-
body {
|
168
|
+
body(style: body_style) {
|
43
169
|
}
|
44
170
|
}
|
45
171
|
end
|
@@ -1,25 +1,45 @@
|
|
1
|
+
require 'glimmer/opal/property_owner'
|
2
|
+
|
1
3
|
module Glimmer
|
2
4
|
module Opal
|
3
5
|
class ElementProxy
|
4
|
-
|
6
|
+
include Glimmer
|
7
|
+
include PropertyOwner
|
8
|
+
attr_reader :parent, :args, :css_classes, :css, :children, :enabled
|
5
9
|
|
6
10
|
def initialize(parent, args)
|
7
11
|
@parent = parent
|
8
12
|
@args = args
|
9
|
-
@children =
|
13
|
+
@children = Set.new
|
14
|
+
@css_classes = Set.new
|
15
|
+
@css = ''
|
16
|
+
@enabled = true
|
10
17
|
@parent.add_child(self)
|
11
18
|
end
|
12
19
|
|
13
20
|
def add_child(child)
|
14
|
-
|
21
|
+
# return if @children.include?(child) # TODO consider adding an option to enable this if needed to prevent dom repetition
|
15
22
|
@children << child
|
16
23
|
dom << child.dom
|
17
24
|
end
|
25
|
+
|
26
|
+
def enabled=(value)
|
27
|
+
@enabled = value
|
28
|
+
redraw
|
29
|
+
end
|
18
30
|
|
19
31
|
def redraw
|
20
|
-
|
21
|
-
|
22
|
-
|
32
|
+
if @dom
|
33
|
+
old_dom = @dom
|
34
|
+
@dom = nil
|
35
|
+
old_dom.replace dom
|
36
|
+
else
|
37
|
+
dom
|
38
|
+
end
|
39
|
+
@children.each do |child|
|
40
|
+
child.redraw
|
41
|
+
add_child(child)
|
42
|
+
end
|
23
43
|
end
|
24
44
|
|
25
45
|
# Subclasses must override with their own mappings
|
@@ -32,6 +52,7 @@ module Glimmer
|
|
32
52
|
end
|
33
53
|
|
34
54
|
def id
|
55
|
+
# TODO replace hash with autoincrement per name
|
35
56
|
"#{name}-#{hash}"
|
36
57
|
end
|
37
58
|
|
@@ -40,13 +61,227 @@ module Glimmer
|
|
40
61
|
"#{name}##{id}"
|
41
62
|
end
|
42
63
|
|
64
|
+
def add_css_class(css_class)
|
65
|
+
@css_classes << css_class
|
66
|
+
redraw
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_css_classes(css_classes)
|
70
|
+
@css_classes += css_classes
|
71
|
+
redraw
|
72
|
+
end
|
73
|
+
|
74
|
+
def remove_css_class(css_class)
|
75
|
+
@css_classes.delete(css_class)
|
76
|
+
redraw
|
77
|
+
end
|
78
|
+
|
79
|
+
def remove_css_classes(css_classes)
|
80
|
+
@css_classes -= css_classes
|
81
|
+
redraw
|
82
|
+
end
|
83
|
+
|
84
|
+
def clear_css_classes(css_class)
|
85
|
+
@css_classes.clear
|
86
|
+
redraw
|
87
|
+
end
|
88
|
+
|
89
|
+
def css=(css)
|
90
|
+
@css = css
|
91
|
+
redraw
|
92
|
+
end
|
93
|
+
|
94
|
+
def has_style?(symbol)
|
95
|
+
@args.include?(symbol) # not a very solid implementation. Bring SWT constants eventually
|
96
|
+
end
|
97
|
+
|
43
98
|
def handle_observation_request(keyword, &event_listener)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
99
|
+
return unless observation_request_to_event_mapping.keys.include?(keyword)
|
100
|
+
event = nil
|
101
|
+
delegate = nil
|
102
|
+
[observation_request_to_event_mapping[keyword]].flatten.each do |mapping|
|
103
|
+
event = mapping[:event]
|
104
|
+
event_handler = mapping[:event_handler]
|
105
|
+
potential_event_listener = event_handler&.call(event_listener)
|
106
|
+
event_listener = event_handler&.call(event_listener) || event_listener
|
107
|
+
delegate = $document.on(event, selector, &event_listener)
|
108
|
+
end
|
48
109
|
EventListenerProxy.new(element_proxy: self, event: event, selector: selector, delegate: delegate)
|
49
|
-
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_observer(observer, property_name)
|
113
|
+
property_listener_installers = self.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
|
114
|
+
widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
|
115
|
+
widget_listener_installers.to_a.each do |widget_listener_installer|
|
116
|
+
widget_listener_installer.call(observer)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def set_attribute(attribute_name, *args)
|
121
|
+
apply_property_type_converters(attribute_name, args)
|
122
|
+
super(attribute_name, *args)
|
123
|
+
end
|
124
|
+
|
125
|
+
def apply_property_type_converters(attribute_name, args)
|
126
|
+
if args.count == 1
|
127
|
+
value = args.first
|
128
|
+
converter = property_type_converters[attribute_name.to_sym]
|
129
|
+
args[0] = converter.call(value) if converter
|
130
|
+
end
|
131
|
+
# if args.count == 1 && args.first.is_a?(ColorProxy)
|
132
|
+
# g_color = args.first
|
133
|
+
# args[0] = g_color.swt_color
|
134
|
+
# end
|
135
|
+
end
|
136
|
+
|
137
|
+
def property_type_converters
|
138
|
+
@property_type_converters ||= {
|
139
|
+
# :background => color_converter,
|
140
|
+
# :background_image => lambda do |value|
|
141
|
+
# if value.is_a?(String)
|
142
|
+
# if value.start_with?('uri:classloader')
|
143
|
+
# value = value.sub(/^uri\:classloader\:\//, '')
|
144
|
+
# object = java.lang.Object.new
|
145
|
+
# value = object.java_class.resource_as_stream(value)
|
146
|
+
# value = java.io.BufferedInputStream.new(value)
|
147
|
+
# end
|
148
|
+
# image_data = ImageData.new(value)
|
149
|
+
# on_event_Resize do |resize_event|
|
150
|
+
# new_image_data = image_data.scaledTo(@swt_widget.getSize.x, @swt_widget.getSize.y)
|
151
|
+
# @swt_widget.getBackgroundImage&.dispose
|
152
|
+
# @swt_widget.setBackgroundImage(Image.new(@swt_widget.getDisplay, new_image_data))
|
153
|
+
# end
|
154
|
+
# Image.new(@swt_widget.getDisplay, image_data)
|
155
|
+
# else
|
156
|
+
# value
|
157
|
+
# end
|
158
|
+
# end,
|
159
|
+
# :foreground => color_converter,
|
160
|
+
# :font => lambda do |value|
|
161
|
+
# if value.is_a?(Hash)
|
162
|
+
# font_properties = value
|
163
|
+
# FontProxy.new(self, font_properties).swt_font
|
164
|
+
# else
|
165
|
+
# value
|
166
|
+
# end
|
167
|
+
# end,
|
168
|
+
# :items => lambda do |value|
|
169
|
+
# value.to_java :string
|
170
|
+
# end,
|
171
|
+
:text => lambda do |value|
|
172
|
+
# if swt_widget.is_a?(Browser)
|
173
|
+
# value.to_s
|
174
|
+
# else
|
175
|
+
value.to_s
|
176
|
+
# end
|
177
|
+
end,
|
178
|
+
# :visible => lambda do |value|
|
179
|
+
# !!value
|
180
|
+
# end,
|
181
|
+
}
|
182
|
+
end
|
183
|
+
|
184
|
+
def widget_property_listener_installers
|
185
|
+
@swt_widget_property_listener_installers ||= {
|
186
|
+
# ElementProxy => {
|
187
|
+
# :focus => lambda do |observer|
|
188
|
+
# on_focus_gained { |focus_event|
|
189
|
+
# observer.call(true)
|
190
|
+
# }
|
191
|
+
# on_focus_lost { |focus_event|
|
192
|
+
# observer.call(false)
|
193
|
+
# }
|
194
|
+
# end,
|
195
|
+
# },
|
196
|
+
InputProxy => {
|
197
|
+
:text => lambda do |observer|
|
198
|
+
on_modify_text { |modify_event|
|
199
|
+
observer.call(text)
|
200
|
+
}
|
201
|
+
end,
|
202
|
+
# :caret_position => lambda do |observer|
|
203
|
+
# on_event_keydown { |event|
|
204
|
+
# observer.call(getCaretPosition)
|
205
|
+
# }
|
206
|
+
# on_event_keyup { |event|
|
207
|
+
# observer.call(getCaretPosition)
|
208
|
+
# }
|
209
|
+
# on_event_mousedown { |event|
|
210
|
+
# observer.call(getCaretPosition)
|
211
|
+
# }
|
212
|
+
# on_event_mouseup { |event|
|
213
|
+
# observer.call(getCaretPosition)
|
214
|
+
# }
|
215
|
+
# end,
|
216
|
+
# :selection => lambda do |observer|
|
217
|
+
# on_event_keydown { |event|
|
218
|
+
# observer.call(getSelection)
|
219
|
+
# }
|
220
|
+
# on_event_keyup { |event|
|
221
|
+
# observer.call(getSelection)
|
222
|
+
# }
|
223
|
+
# on_event_mousedown { |event|
|
224
|
+
# observer.call(getSelection)
|
225
|
+
# }
|
226
|
+
# on_event_mouseup { |event|
|
227
|
+
# observer.call(getSelection)
|
228
|
+
# }
|
229
|
+
# end,
|
230
|
+
# :selection_count => lambda do |observer|
|
231
|
+
# on_event_keydown { |event|
|
232
|
+
# observer.call(getSelectionCount)
|
233
|
+
# }
|
234
|
+
# on_event_keyup { |event|
|
235
|
+
# observer.call(getSelectionCount)
|
236
|
+
# }
|
237
|
+
# on_event_mousedown { |event|
|
238
|
+
# observer.call(getSelectionCount)
|
239
|
+
# }
|
240
|
+
# on_event_mouseup { |event|
|
241
|
+
# observer.call(getSelectionCount)
|
242
|
+
# }
|
243
|
+
# end,
|
244
|
+
# :top_index => lambda do |observer|
|
245
|
+
# @last_top_index = getTopIndex
|
246
|
+
# on_paint_control { |event|
|
247
|
+
# if getTopIndex != @last_top_index
|
248
|
+
# @last_top_index = getTopIndex
|
249
|
+
# observer.call(@last_top_index)
|
250
|
+
# end
|
251
|
+
# }
|
252
|
+
# end,
|
253
|
+
},
|
254
|
+
# Java::OrgEclipseSwtCustom::StyledText => {
|
255
|
+
# :text => lambda do |observer|
|
256
|
+
# on_modify_text { |modify_event|
|
257
|
+
# observer.call(getText)
|
258
|
+
# }
|
259
|
+
# end,
|
260
|
+
# },
|
261
|
+
# InputProxy => {
|
262
|
+
# :selection => lambda do |observer|
|
263
|
+
# on_widget_selected { |selection_event|
|
264
|
+
# observer.call(getSelection)
|
265
|
+
# }
|
266
|
+
# end
|
267
|
+
# },
|
268
|
+
# Java::OrgEclipseSwtWidgets::MenuItem => {
|
269
|
+
# :selection => lambda do |observer|
|
270
|
+
# on_widget_selected { |selection_event|
|
271
|
+
# observer.call(getSelection)
|
272
|
+
# }
|
273
|
+
# end
|
274
|
+
# },
|
275
|
+
# Java::OrgEclipseSwtWidgets::Spinner => {
|
276
|
+
# :selection => lambda do |observer|
|
277
|
+
# on_widget_selected { |selection_event|
|
278
|
+
# observer.call(getSelection)
|
279
|
+
# }
|
280
|
+
# end
|
281
|
+
# },
|
282
|
+
}
|
283
|
+
end
|
284
|
+
|
50
285
|
end
|
51
286
|
end
|
52
287
|
end
|