glimmer-dsl-opal 0.10.0 → 0.12.0

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/README.md +84 -22
  4. data/VERSION +1 -1
  5. data/lib/display.rb +3 -0
  6. data/lib/glimmer-dsl-opal.rb +1 -1
  7. data/lib/glimmer-dsl-opal/ext/glimmer/dsl/engine.rb +5 -2
  8. data/lib/glimmer-dsl-opal/samples/elaborate/contact_manager.rb +17 -13
  9. data/lib/glimmer-dsl-opal/samples/elaborate/login.rb +55 -28
  10. data/lib/glimmer-dsl-opal/samples/elaborate/tic_tac_toe.rb +2 -2
  11. data/lib/glimmer-dsl-opal/samples/hello/hello_button.rb +1 -1
  12. data/lib/glimmer-dsl-opal/samples/hello/hello_checkbox.rb +4 -4
  13. data/lib/glimmer-dsl-opal/samples/hello/hello_combo.rb +1 -1
  14. data/lib/glimmer-dsl-opal/samples/hello/hello_computed.rb +5 -5
  15. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_shell.rb +1 -1
  16. data/lib/glimmer-dsl-opal/samples/hello/hello_date_time.rb +4 -4
  17. data/lib/glimmer-dsl-opal/samples/hello/hello_group.rb +6 -6
  18. data/lib/glimmer-dsl-opal/samples/hello/hello_list_multi_selection.rb +1 -1
  19. data/lib/glimmer-dsl-opal/samples/hello/hello_list_single_selection.rb +1 -1
  20. data/lib/glimmer-dsl-opal/samples/hello/hello_radio.rb +6 -6
  21. data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +2 -2
  22. data/lib/glimmer/data_binding/table_items_binding.rb +3 -2
  23. data/lib/glimmer/dsl/opal/bind_expression.rb +24 -25
  24. data/lib/glimmer/dsl/opal/custom_widget_expression.rb +6 -6
  25. data/lib/glimmer/dsl/opal/dsl.rb +4 -0
  26. data/lib/glimmer/dsl/opal/menu_expression.rb +1 -1
  27. data/lib/glimmer/dsl/opal/message_box_expression.rb +1 -1
  28. data/lib/glimmer/dsl/opal/property_expression.rb +2 -1
  29. data/lib/glimmer/dsl/opal/shape_expression.rb +26 -0
  30. data/lib/glimmer/dsl/opal/shell_expression.rb +1 -1
  31. data/lib/glimmer/dsl/opal/shine_data_binding_expression.rb +49 -0
  32. data/lib/glimmer/dsl/opal/table_items_data_binding_expression.rb +2 -2
  33. data/lib/glimmer/dsl/opal/widget_expression.rb +1 -1
  34. data/lib/glimmer/swt/combo_proxy.rb +1 -0
  35. data/lib/glimmer/swt/composite_proxy.rb +18 -2
  36. data/lib/glimmer/swt/dialog_proxy.rb +47 -32
  37. data/lib/glimmer/swt/display_proxy.rb +128 -9
  38. data/lib/glimmer/swt/grid_layout_proxy.rb +28 -33
  39. data/lib/glimmer/swt/latest_dialog_proxy.rb +3 -1
  40. data/lib/glimmer/swt/latest_message_box_proxy.rb +3 -1
  41. data/lib/glimmer/swt/latest_shell_proxy.rb +6 -2
  42. data/lib/glimmer/swt/layout_proxy.rb +32 -9
  43. data/lib/glimmer/swt/message_box_proxy.rb +20 -10
  44. data/lib/glimmer/swt/row_layout_proxy.rb +13 -6
  45. data/lib/glimmer/swt/shell_proxy.rb +30 -8
  46. data/lib/glimmer/swt/table_proxy.rb +19 -3
  47. data/lib/glimmer/swt/widget_proxy.rb +50 -19
  48. data/lib/glimmer/ui/custom_shell.rb +23 -6
  49. data/lib/glimmer/util/proc_tracker.rb +16 -5
  50. metadata +11 -9
@@ -0,0 +1,49 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/dsl/expression'
23
+ require 'glimmer/data_binding/model_binding'
24
+ require 'glimmer/swt/table_proxy'
25
+ require 'glimmer/data_binding/shine'
26
+
27
+ module Glimmer
28
+ module DSL
29
+ module Opal
30
+ class ShineDataBindingExpression < Expression
31
+ def can_interpret?(parent, keyword, *args, &block)
32
+ args.size == 0 and
33
+ block.nil? and
34
+ (
35
+ (parent.respond_to?(:set_attribute) and parent.respond_to?(keyword)) or
36
+ (parent.is_a?(Glimmer::SWT::TableProxy)) # TODO support tree element
37
+ )
38
+ # TODO support canvas elements
39
+ # and
40
+ # !(parent.respond_to?(:swt_widget) && parent.swt_widget.class == org.eclipse.swt.widgets.Canvas && keyword == 'image')
41
+ end
42
+
43
+ def interpret(parent, keyword, *args, &block)
44
+ Glimmer::DataBinding::Shine.new(parent, keyword)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -12,10 +12,10 @@ module Glimmer
12
12
  keyword == "items" and
13
13
  block.nil? and
14
14
  parent.is_a?(Glimmer::SWT::TableProxy) and
15
- args.size == 2 and
15
+ args.size.between?(1, 2) and
16
16
  args[0].is_a?(DataBinding::ModelBinding) and
17
17
  args[0].evaluate_property.is_a?(Array) and
18
- args[1].is_a?(Array)
18
+ (args[1].nil? or args[1].is_a?(Array))
19
19
  end
20
20
 
21
21
  def interpret(parent, keyword, *args, &block)
@@ -20,7 +20,7 @@ module Glimmer
20
20
  Glimmer::SWT::WidgetProxy.for(keyword, parent, args, block)
21
21
  end
22
22
 
23
- def add_content(parent, &block)
23
+ def add_content(parent, keyword, *args, &block)
24
24
  if parent.rendered? || parent.skip_content_on_render_blocks?
25
25
  super(parent, &block)
26
26
  parent.post_add_content
@@ -6,6 +6,7 @@ module Glimmer
6
6
  class ComboProxy < WidgetProxy
7
7
  include Glimmer::DataBinding::ObservableElement
8
8
  attr_reader :text, :items
9
+ attr_accessor :selection # virtual attribute just to pass the shine data-binding test (TODO THINK OF A BETTER WAY OF HANDLING THIS)
9
10
 
10
11
  def initialize(parent, args, block)
11
12
  super(parent, args, block)
@@ -4,8 +4,6 @@ require 'glimmer/swt/widget_proxy'
4
4
  module Glimmer
5
5
  module SWT
6
6
  class CompositeProxy < WidgetProxy
7
- attr_reader :layout
8
-
9
7
  def initialize(parent, args, block)
10
8
  super(parent, args, block)
11
9
  @layout = default_layout
@@ -27,9 +25,27 @@ module Glimmer
27
25
  def layout=(the_layout)
28
26
  @layout = the_layout
29
27
  end
28
+ alias set_layout layout=
29
+ alias setLayout layout=
30
30
 
31
+ def get_layout
32
+ @layout
33
+ end
34
+ alias getLayout get_layout #TODO consider pregenerating these aliases with an easy method in the future
35
+
36
+ def pack(*args)
37
+ # No Op (just a shim) TODO consider if it should be implemented
38
+ end
39
+
40
+ def layout​(changed = nil, all = nil)
41
+ # TODO implement layout(changed = nil, all = nil) just as per SWT API
42
+ @layout&.layout(self, changed)
43
+ end
44
+
31
45
  end
32
46
 
47
+ CanvasProxy = CompositeProxy # TODO implement fully eventually
48
+
33
49
  end
34
50
 
35
51
  end
@@ -63,14 +63,12 @@ module Glimmer
63
63
  i = 0
64
64
  @parent = parent
65
65
  @parent = nil if parent.is_a?(LatestShellProxy)
66
- @parent ||= DisplayProxy.instance.shells.last || ShellProxy.new([])
66
+ @parent ||= DisplayProxy.instance.shells.detect(&:open?) || ShellProxy.new([])
67
67
  @args = args
68
68
  @block = block
69
69
  @children = Set.new
70
70
  @enabled = true
71
- # on_widget_selected {
72
- # hide
73
- # }
71
+ DisplayProxy.instance.opened_dialogs.last&.suspend_event_handling
74
72
  DisplayProxy.instance.dialogs << self
75
73
  @parent.post_initialize_child(self)
76
74
  end
@@ -84,35 +82,39 @@ module Glimmer
84
82
  end
85
83
  end
86
84
 
85
+ def open?
86
+ @open
87
+ end
88
+
87
89
  def open
88
- unless @init
89
- dom_element.remove_class('hide')
90
- dom_element.dialog({'auto_open' => false})
91
- @init = true
92
- dom_element.dialog('option', 'appendTo', parent.path)
93
- dom_element.dialog('option', 'modal', true) # NOTE: Not Working! Doing manually below by relying on overlay in ShellProxy.
94
- if DisplayProxy.instance.dialogs.size == 1 # only add for first dialog open
95
- Element['.dialog-overlay'].remove_class('hide')
96
- end
97
- dom_element.dialog('option', 'closeOnEscape', true)
98
- dom_element.dialog('option', 'draggable', true)
99
- dom_element.dialog('option', 'width', 'auto')
100
- dom_element.dialog('option', 'minHeight', 'none')
101
- dom_element.on('dialogclose') do
102
- unless @hiding
103
- close
104
- else
105
- @hiding = false
90
+ owned_proc = Glimmer::Util::ProcTracker.new(owner: self, invoked_from: :open) {
91
+ shell.open(async: false) unless shell.open?
92
+ unless @init
93
+ dom_element.remove_class('hide')
94
+ dom_element.dialog('auto_open' => false)
95
+ @init = true
96
+ dom_element.dialog('option', 'appendTo', parent.path)
97
+ dom_element.dialog('option', 'modal', true) # NOTE: Not Working! Doing manually below by relying on overlay in ShellProxy.
98
+ unless DisplayProxy.instance.dialogs.any?(&:open?) # only add for first dialog open
99
+ Element['.dialog-overlay'].remove_class('hide')
100
+ end
101
+ dom_element.dialog('option', 'closeOnEscape', true)
102
+ dom_element.dialog('option', 'draggable', true)
103
+ dom_element.dialog('option', 'width', 'auto')
104
+ dom_element.dialog('option', 'minHeight', 'none')
105
+ dom_element.on('dialogclose') do
106
+ unless @hiding
107
+ close
108
+ else
109
+ @hiding = false
110
+ end
106
111
  end
112
+ else
113
+ dom_element.dialog('open')
107
114
  end
108
- else
109
- dom_element.dialog('open')
110
- end
111
- @open = true
112
- end
113
-
114
- def open?
115
- @open
115
+ @open = true
116
+ }
117
+ DisplayProxy.instance.async_exec(owned_proc)
116
118
  end
117
119
 
118
120
  def hide
@@ -128,12 +130,15 @@ module Glimmer
128
130
  @open = false
129
131
  @init = false
130
132
  Element['.dialog-overlay'].add_class('hide') unless DisplayProxy.instance.dialogs.any?(&:open?)
133
+ parent.children.delete(self)
134
+ shell.close if shell.children.empty?
131
135
  DisplayProxy.instance.dialogs.delete(self)
136
+ DisplayProxy.instance.opened_dialogs.last&.resume_event_handling
132
137
  end
133
138
 
134
139
 
135
140
  def content(&block)
136
- Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Opal::DialogExpression.new, &block)
141
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Opal::DialogExpression.new, 'dialog', &block)
137
142
  end
138
143
 
139
144
  def path
@@ -144,6 +149,16 @@ module Glimmer
144
149
  end
145
150
  end
146
151
 
152
+ def suspend_event_handling
153
+ super
154
+ Element["[aria-describedby=#{id}]"].css('z-index', 9)
155
+ end
156
+
157
+ def resume_event_handling
158
+ super
159
+ Element["[aria-describedby=#{id}]"].css('z-index', 100)
160
+ end
161
+
147
162
  # def selector
148
163
  # super + ' .close'
149
164
  # end
@@ -162,7 +177,7 @@ module Glimmer
162
177
 
163
178
  def dom
164
179
  @dom ||= html {
165
- div(id: id, class: "#{name} hide", title: text) {
180
+ div(id: id, class: "#{name} modal hide", title: text) {
166
181
  }
167
182
  }.to_s
168
183
  end
@@ -1,3 +1,5 @@
1
+ require 'glimmer/swt/widget_proxy'
2
+
1
3
  module Glimmer
2
4
  module SWT
3
5
  class DisplayProxy < WidgetProxy
@@ -5,6 +7,9 @@ module Glimmer
5
7
  def instance
6
8
  @instance ||= new
7
9
  end
10
+
11
+ attr_accessor :open_custom_shells_in_current_window
12
+ alias open_custom_shells_in_current_window? open_custom_shells_in_current_window
8
13
  end
9
14
 
10
15
  def initialize
@@ -36,20 +41,46 @@ module Glimmer
36
41
  @dialogs ||= []
37
42
  end
38
43
 
44
+ def modals
45
+ message_boxes + dialogs
46
+ end
47
+
48
+ def message_box_open?
49
+ message_boxes.any?(&:open?)
50
+ end
51
+
52
+ def dialog_open?
53
+ dialogs.any?(&:open?)
54
+ end
55
+
56
+ def opened_dialogs
57
+ dialogs.select(&:open?)
58
+ end
59
+
60
+ def modal_open?
61
+ message_box_open? or dialog_open?
62
+ end
63
+
39
64
  def render
40
65
  # No rendering as body is rendered as part of ShellProxy.. this class only serves as an SWT Display utility
41
66
  end
42
67
 
43
- def async_exec(&block)
44
- executer = lambda do
45
- if Document.find('.modal').to_a.empty?
46
- block.call
47
- else
48
- sleep(0.05)
49
- Async::Task.new(&executer)
50
- end
68
+ def beep
69
+ # TODO (simulate beep from SWT display flashing the screen and making a noise if possible)
70
+ end
71
+
72
+ def async_exec(proc_tracker = nil, &block)
73
+ block = proc_tracker unless proc_tracker.nil?
74
+ queue = nil # general queue
75
+ if !proc_tracker.nil? && proc_tracker.invoked_from.to_s == 'open' && modal_open? &&
76
+ (
77
+ proc_tracker.owner.is_a?(MessageBoxProxy) ||
78
+ (dialog_open? && proc_tracker.owner.is_a?(DialogProxy) && opened_dialogs.last == WidgetProxy.widget_handling_listener&.dialog_ancestor)
79
+ )
80
+ queue = WidgetProxy.widget_handling_listener
51
81
  end
52
- Async::Task.new(&executer)
82
+ return block.call if !modal_open?
83
+ schedule_async_exec(block, queue)
53
84
  end
54
85
  # sync_exec kept for API compatibility reasons
55
86
  alias sync_exec async_exec
@@ -64,7 +95,34 @@ module Glimmer
64
95
  event.singleton_class.define_method(:character) do
65
96
  which || key_code
66
97
  end
98
+ event.define_singleton_method(:keyCode) {event.which}
99
+ event.define_singleton_method(:key_code, &event.method(:keyCode))
100
+ event.define_singleton_method(:character) {event.which.chr}
101
+ event.define_singleton_method(:stateMask) do
102
+ state_mask = 0
103
+ state_mask |= SWTProxy[:alt] if event.alt_key
104
+ state_mask |= SWTProxy[:ctrl] if event.ctrl_key
105
+ state_mask |= SWTProxy[:shift] if event.shift_key
106
+ state_mask |= SWTProxy[:command] if event.meta_key
107
+ state_mask
108
+ end
109
+ event.define_singleton_method(:state_mask, &event.method(:stateMask))
110
+ doit = true
111
+ event.define_singleton_method(:doit=) do |value|
112
+ doit = value
113
+ end
114
+ event.define_singleton_method(:doit) { doit }
67
115
  event_listener.call(event)
116
+
117
+ # TODO Fix doit false, it's not stopping input
118
+ unless doit
119
+ event.prevent
120
+ event.prevent_default
121
+ event.stop_propagation
122
+ event.stop_immediate_propagation
123
+ end
124
+
125
+ doit
68
126
  }
69
127
  }
70
128
  },
@@ -75,13 +133,74 @@ module Glimmer
75
133
  event.singleton_class.define_method(:character) do
76
134
  which || key_code
77
135
  end
136
+ event.define_singleton_method(:keyCode) {event.which}
137
+ event.define_singleton_method(:key_code, &event.method(:keyCode))
138
+ event.define_singleton_method(:character) {event.which.chr}
139
+ event.define_singleton_method(:stateMask) do
140
+ state_mask = 0
141
+ state_mask |= SWTProxy[:alt] if event.alt_key
142
+ state_mask |= SWTProxy[:ctrl] if event.ctrl_key
143
+ state_mask |= SWTProxy[:shift] if event.shift_key
144
+ state_mask |= SWTProxy[:command] if event.meta_key
145
+ state_mask
146
+ end
147
+ event.define_singleton_method(:state_mask, &event.method(:stateMask))
148
+ doit = true
149
+ event.define_singleton_method(:doit=) do |value|
150
+ doit = value
151
+ end
152
+ event.define_singleton_method(:doit) { doit }
78
153
  event_listener.call(event) if event.key_code != 13 && (event.key_code == 127 || event.key_code <= 31)
154
+
155
+ # TODO Fix doit false, it's not stopping input
156
+ unless doit
157
+ event.prevent
158
+ event.prevent_default
159
+ event.stop_propagation
160
+ event.stop_immediate_propagation
161
+ end
162
+
163
+ doit
79
164
  }
80
165
  }
81
166
  }
82
167
  ]
83
168
  }
84
169
  end
170
+
171
+ private
172
+
173
+ def async_exec_queues
174
+ @async_exec_queues ||= {}
175
+ end
176
+
177
+ def async_exec_queue(widget_handling_listener = nil)
178
+ async_exec_queues[widget_handling_listener] ||= []
179
+ end
180
+
181
+ def no_widget_handling_listener_work?
182
+ async_exec_queues.reject {|key, value| key.nil?}.values.reduce(:+).to_a.empty?
183
+ end
184
+
185
+ def schedule_async_exec(block, queue)
186
+ async_exec_queue(queue).unshift(block)
187
+
188
+ # TODO consider the need for locking to avoid race conditions (rare or impossible case)
189
+ if async_exec_queue(queue).size == 1
190
+ executer = lambda do
191
+ # queue could be a widget handling listener queue
192
+ # TODO see if there are more intricate cases of opening a dialog from a widget listener handler
193
+ if !message_box_open? && (!dialog_open? || queue&.dialog_ancestor == opened_dialogs.last) && ((!queue.nil? && async_exec_queues.keys.last == queue) || no_widget_handling_listener_work?)
194
+ block = async_exec_queue(queue).pop
195
+ block&.call
196
+ Async::Task.new(delay: 1, &executer) if async_exec_queue(queue).any?
197
+ else
198
+ Async::Task.new(delay: 100, &executer)
199
+ end
200
+ end
201
+ Async::Task.new(delay: 1, &executer)
202
+ end
203
+ end
85
204
  end
86
205
  end
87
206
  end
@@ -14,39 +14,46 @@ module Glimmer
14
14
 
15
15
  attr_reader :num_columns, :make_columns_equal_width, :horizontal_spacing, :vertical_spacing, :margin_width, :margin_height
16
16
 
17
- def initialize(parent, args)
18
- super(parent, args)
19
- self.horizontal_spacing = 10
20
- self.vertical_spacing = 10
21
- self.margin_width = 15
22
- self.margin_height = 15
23
- self.num_columns = @args.first || 1
24
- reapply
25
- end
26
-
27
17
  def num_columns=(columns)
28
18
  @num_columns = columns
29
19
  # TODO do the following instead of reapply
30
20
  # @parent.add_css_class("num-columns-#{@num_columns}")
31
- reapply
21
+ # reinitialize # TODO reimplement without using reinitialize
22
+ layout_css = <<~CSS
23
+ grid-template-columns: #{'auto ' * @num_columns.to_i};
24
+ grid-row-gap: #{@vertical_spacing}px;
25
+ grid-column-gap: #{@horizontal_spacing}px;
26
+ CSS
27
+ if @parent.css_classes.include?('grid-layout')
28
+ layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
29
+ @parent.dom_element.css(key, value) unless key.nil?
30
+ end
31
+ if @parent.is_a?(GroupProxy)
32
+ @parent.dom_element.find('legend').css('grid-column-start', "span #{@num_columns.to_i}")
33
+ end
34
+ else
35
+ layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
36
+ @parent.dom_element.css(key, 'initial') unless key.nil?
37
+ end
38
+ end
32
39
  end
33
40
 
34
41
  def make_columns_equal_width=(equal_width)
35
42
  @make_columns_equal_width = equal_width
36
43
  # @parent.add_css_class('make_columns_equal_width') if @make_columns_equal_width
37
- reapply
44
+ # reinitialize # TODO reimplement without using reinitialize
38
45
  end
39
46
 
40
47
  def horizontal_spacing=(spacing)
41
48
  @horizontal_spacing = spacing
42
49
  # @parent.add_css_class("horizontal-spacing-#{@horizontal_spacing}")
43
- reapply
50
+ # reinitialize # TODO reimplement without using reinitialize
44
51
  end
45
52
 
46
53
  def vertical_spacing=(spacing)
47
54
  @vertical_spacing = spacing
48
55
  # @parent.add_css_class("vertical-spacing-#{@vertical_spacing}")
49
- reapply
56
+ # reinitialize # TODO reimplement without using reinitialize
50
57
  end
51
58
 
52
59
  def margin_width=(pixels)
@@ -66,25 +73,13 @@ module Glimmer
66
73
  @parent.dom_element.css('padding-bottom', effective_margin_height)
67
74
  end
68
75
 
69
- def reapply
70
- # TODO get rid of this method
71
- layout_css = <<~CSS
72
- grid-template-columns: #{'auto ' * @num_columns.to_i};
73
- grid-row-gap: #{@vertical_spacing}px;
74
- grid-column-gap: #{@horizontal_spacing}px;
75
- CSS
76
- if @parent.css_classes.include?('grid-layout')
77
- layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
78
- @parent.dom_element.css(key, value) unless key.nil?
79
- end
80
- if @parent.is_a?(GroupProxy)
81
- @parent.dom_element.find('legend').css('grid-column-start', "span #{@num_columns.to_i}")
82
- end
83
- else
84
- layout_css.split(";").map(&:strip).map {|l| l.split(':').map(&:strip)}.each do |key, value|
85
- @parent.dom_element.css(key, 'initial') unless key.nil?
86
- end
87
- end
76
+ def initialize(parent, args)
77
+ super(parent, args)
78
+ self.horizontal_spacing = 10
79
+ self.vertical_spacing = 10
80
+ self.margin_width = 15
81
+ self.margin_height = 15
82
+ self.num_columns = @args.first || 1
88
83
  end
89
84
  end
90
85
  end