glimmer-dsl-opal 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +704 -40
  3. data/VERSION +1 -1
  4. data/lib/glimmer-dsl-opal.rb +3 -2
  5. data/lib/glimmer/data_binding/element_binding.rb +1 -1
  6. data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
  7. data/lib/glimmer/data_binding/list_selection_binding.rb +51 -0
  8. data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
  9. data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
  10. data/lib/glimmer/dsl/opal/button_expression.rb +1 -0
  11. data/lib/glimmer/dsl/opal/dsl.rb +15 -1
  12. data/lib/glimmer/dsl/opal/grid_layout_expression.rb +17 -0
  13. data/lib/glimmer/dsl/opal/layout_data_expression.rb +17 -0
  14. data/lib/glimmer/dsl/opal/list_expression.rb +17 -0
  15. data/lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb +42 -0
  16. data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
  17. data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
  18. data/lib/glimmer/dsl/opal/property_expression.rb +6 -2
  19. data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
  20. data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
  21. data/lib/glimmer/dsl/opal/text_expression.rb +22 -0
  22. data/lib/glimmer/opal/display_proxy.rb +23 -0
  23. data/lib/glimmer/opal/div_proxy.rb +9 -1
  24. data/lib/glimmer/opal/document_proxy.rb +131 -5
  25. data/lib/glimmer/opal/element_proxy.rb +246 -11
  26. data/lib/glimmer/opal/grid_layout_proxy.rb +54 -0
  27. data/lib/glimmer/opal/iframe_proxy.rb +23 -0
  28. data/lib/glimmer/opal/input_proxy.rb +16 -1
  29. data/lib/glimmer/opal/label_proxy.rb +2 -1
  30. data/lib/glimmer/opal/layout_data_proxy.rb +31 -0
  31. data/lib/glimmer/opal/list_proxy.rb +80 -0
  32. data/lib/glimmer/opal/modal.rb +94 -0
  33. data/lib/glimmer/opal/point.rb +5 -0
  34. data/lib/glimmer/opal/property_owner.rb +22 -0
  35. data/lib/glimmer/opal/select_proxy.rb +2 -1
  36. data/lib/glimmer/opal/tab_folder.rb +46 -0
  37. data/lib/glimmer/opal/tab_item.rb +98 -0
  38. data/lib/samples/elaborate/login.rb +0 -1
  39. data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
  40. data/lib/samples/hello/hello_tab.rb +2 -2
  41. 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: 'grid_layout')
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.title = value
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
- div.grid_layout > * {
31
- display: block;
32
- margin-bottom: 10px;
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
- attr_reader :parent, :args
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
- return if @children.include?(child)
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
- old_dom = @dom
21
- @dom = nil
22
- old_dom.replace dom
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
- event = observation_request_to_event_mapping[keyword][:event]
45
- event_handler = observation_request_to_event_mapping[keyword][:event_handler]
46
- event_listener = event_handler&.call(event_listener) || event_listener
47
- delegate = $document.on(event, selector, &event_listener)
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