aurita-gui 0.3.1 → 0.3.2

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.
data/TODO CHANGED
@@ -2,6 +2,9 @@
2
2
  - Implement <fieldset>
3
3
  - Implement <optgroup>
4
4
 
5
+ - Fixme: Setting values only works after all elements have been added
6
+ (values won't be set for elements added after form.values=)
7
+
5
8
  - Implement element.sibling[:dom_id] --> element
6
9
  - Implement XPath1.0 method (parent, sibling, descendant, following ...)
7
10
 
@@ -14,7 +14,7 @@ as stand-alone library in any context (such as rails).
14
14
  As there seems to be a lack of ruby form generators, i decided to release this
15
15
  part of Aurita in a single gem with no dependencies.
16
16
  EOF
17
- s.version = '0.3.1'
17
+ s.version = '0.3.2'
18
18
  s.author = 'Tobias Fuchs'
19
19
  s.email = 'fuchs@atomnode.net'
20
20
  s.date = Time.now
@@ -42,6 +42,19 @@ module GUI
42
42
  # by any derived class like Aurita::GUI::Form or
43
43
  # Aurita::GUI::Table.
44
44
  #
45
+ # == Notes
46
+ #
47
+ # Double-quotes in tag parameters will be escaped
48
+ # when rendering to string.
49
+ #
50
+ # e = Element.new(:onclick => 'alert("message");')
51
+ #
52
+ # The value of parameter :onclick does not change,
53
+ # but will be escaped when rendering:
54
+ #
55
+ # e.onclick == 'alert("message");'
56
+ # e.to_s == '<div onclick="alert(\"message\");"></div>'
57
+ #
45
58
  class Element
46
59
 
47
60
  @@element_count = 0
@@ -85,11 +98,11 @@ module GUI
85
98
 
86
99
  # Return DOM id of this element.
87
100
  def dom_id
88
- @attrib[:id]
101
+ @attrib[:id] if @attrib
89
102
  end
90
103
  # Set DOM id of this element.
91
104
  def dom_id=(value)
92
- @attrib[:id] = value
105
+ @attrib[:id] = value if @attrib
93
106
  end
94
107
 
95
108
  # Render this element to a string and append another
@@ -168,7 +181,7 @@ module GUI
168
181
  end
169
182
  if !value.nil? then
170
183
  value = value.to_s
171
- attrib_string << ' ' << name.to_s + '="' << value + '"'
184
+ attrib_string << ' ' << name.to_s + '="' << value.gsub('"','\"') + '"'
172
185
  end
173
186
  }
174
187
 
@@ -188,6 +201,29 @@ module GUI
188
201
  def each(&block)
189
202
  @content.each(&block)
190
203
  end
204
+
205
+ def css_classes
206
+ css_classes = @attrib[:class]
207
+ if css_classes.kind_of? Array
208
+ css_classes.flatten!
209
+ elsif css_classes.kind_of? String
210
+ css_classes = css_classes.split(' ')
211
+ else # e.g. Symbol
212
+ css_classes = [ css_classes ]
213
+ end
214
+ css_classes.collect { |c| c.to_sym if c }
215
+ return css_classes
216
+ end
217
+
218
+ def add_class(css_class_name)
219
+ @attrib[:class] = (css_classes << css_class_name.to_sym)
220
+ end
221
+
222
+ def remove_class(css_class_name)
223
+ classes = css_classes
224
+ classes.delete(css_class_name.to_sym)
225
+ @attrib[:class] = classes
226
+ end
191
227
 
192
228
  end # class
193
229
 
@@ -22,23 +22,114 @@ module Aurita
22
22
  module GUI
23
23
 
24
24
 
25
+ # Default decorator for form fields.
26
+ # Decorates single entry of form to <li> element, setting CSS
27
+ # classes and DOM ids.
28
+ # To use your own field decorator, derive it from Aurita::GUI::Element
29
+ # (maybe indirectly via one of its derivates) and define its
30
+ # constructor to expect a single Form_Field instance.
31
+ # The field decorator has to wrap the actual form field.
32
+ #
33
+ # See the source code of Aurita::GUI::Form_Field_Wrapper for a
34
+ # simple implementation.
35
+ #
36
+ # Tell a form to use a specific field decorator by
37
+ #
38
+ # the_form.field_decorator = My_Field_Decorator
39
+ #
40
+ # To use your own implementation as defaut, overload Form.initialize
41
+ # like
42
+ #
43
+ # class My_Form < Aurita::GUI::Form
44
+ # def initialize(params={}, &block)
45
+ # super(params, &block)
46
+ # @field_decorator = My_Field_Decorator
47
+ # emd
48
+ # end
49
+ #
50
+ # Or write a factory (*hint hint*) like:
51
+ #
52
+ # class Form_Factory
53
+ # def self.form(params={}, &block)
54
+ # form = Aurita::GUI::Form.new(params, &block)
55
+ # form.field_decorator = My_Field_Decorator
56
+ # return form
57
+ # end
58
+ # end
59
+ #
60
+ # See also: Form_Content_Wrapper (pretty much the same).
61
+ #
25
62
  class Form_Field_Wrapper < Aurita::GUI::Element
26
63
  attr_accessor :field
27
64
 
28
65
  def initialize(field)
29
- label_params = { :for => field.dom_id, :force_closing_tag => true }
30
- label_params[:id] = field.dom_id.to_s + '_label'
31
- label = field.label
32
- @content = [ HTML.label(label_params) { label }, field ]
66
+ label_params = false
67
+ if field.label then
68
+ label_params = { :for => field.dom_id, :force_closing_tag => true }
69
+ label_params[:id] = field.dom_id.to_s + '_label' if field.dom_id
70
+ label = field.label
71
+ @content = [ HTML.label(label_params) { label }, field ]
72
+ else
73
+ @content = field
74
+ end
75
+ css_classes = field.class.to_s.split('::')[-1].downcase + '_wrap form_field'
76
+ css_classes << ' required' if field.required?
77
+ css_classes << ' invalid' if field.invalid?
33
78
  params = { :tag => :li,
34
79
  :content => @content,
35
80
  :id => field.dom_id + '_wrap',
36
- :class => field.class.to_s.split('::')[-1].downcase + '_wrap form_field' }
81
+ :class => css_classes }
37
82
  super(params)
38
83
  end
39
84
 
40
85
  end
41
86
 
87
+ # Default decorator for form contents (list of form fields).
88
+ # Decorates all entries of form to <ul> element, setting CSS
89
+ # class 'form_field'.
90
+ # To use your own field decorator, derive it from Aurita::GUI::Element
91
+ # (maybe indirectly via one of its derivates) and define its
92
+ # constructor to expect a list of Form_Field instances as
93
+ # content attribute (either in params or as block).
94
+ # The content decorator has to wrap the actual array of form fields.
95
+ #
96
+ # See the source code of Aurita::GUI::Form_Content_Wrapper for a
97
+ # simple implementation.
98
+ #
99
+ # Tell a form to use a specific content decorator by
100
+ #
101
+ # the_form.content_decorator = My_Content_Decorator
102
+ #
103
+ # To use your own implementation as defaut, overload Form.initialize
104
+ # like
105
+ #
106
+ # class My_Form < Aurita::GUI::Form
107
+ # def initialize(params={}, &block)
108
+ # super(params, &block)
109
+ # @content_decorator = My_Content_Decorator
110
+ # emd
111
+ # end
112
+ #
113
+ # Or write a factory (*hint hint*) like:
114
+ #
115
+ # class Form_Factory
116
+ # def self.form(params={}, &block)
117
+ # form = Aurita::GUI::Form.new(params, &block)
118
+ # form.content_decorator = My_Content_Decorator
119
+ # return form
120
+ # end
121
+ # end
122
+ #
123
+ # See also: Form_Field_Wrapper (pretty much the same).
124
+ #
125
+ class Form_Content_Wrapper < Aurita::GUI::Element
126
+ def initialize(params={}, &block)
127
+ params[:tag] = :ul
128
+ params[:class] = :form_fields
129
+ super(params, &block)
130
+ end
131
+ end
132
+
42
133
  # Usage examples:
43
134
  #
44
135
  # form = Form.new(:method => :put # default: :post
@@ -174,23 +265,43 @@ module GUI
174
265
  #
175
266
  # puts form.to_s
176
267
  #
268
+ # === Further customization
269
+ #
270
+ # The default form decorators (Form_Field_Wrapper and
271
+ # Form_Content_Wrapper) do their best to guess DOM ids
272
+ # and CSS classes. In case you want to implement your
273
+ # own decorators - e.g. in case you don't want any
274
+ # 'guessed' CSS classes at all - you can overwrite them
275
+ # via
276
+ #
277
+ # the_form.field_decorator = My_Field_Decorator
278
+ #
279
+ # and
280
+ #
281
+ # the_form.content_decorator = My_Content_Decorator
282
+ #
283
+ # See documentation to Form_Field_Wrapper and
284
+ # Form_Content_Wrapper for instructions on how to
285
+ # implement custom form decorators.
177
286
  #
178
287
  class Form < Element
179
288
 
180
- attr_accessor :method, :target, :action, :fields, :elements, :element_map, :values
289
+ attr_accessor :method, :target, :action, :fields, :elements, :element_map, :values, :field_decorator, :content_decorator
181
290
 
182
- def initialize(params, &block)
183
- @action = params[:action]
184
- @method = params[:method]
185
- @fields = params[:fields]
186
- @values = params[:values]
187
- @method ||= :post
188
- @fields ||= []
189
- @elements = []
190
- @element_map = {}
191
- @values ||= {}
192
- @title = false
291
+ def initialize(params={}, &block)
292
+ @action = params[:action]
293
+ @method = params[:method]
294
+ @fields = params[:fields]
295
+ @values = params[:values]
296
+ @method ||= :post
297
+ @fields ||= []
298
+ @elements = []
299
+ @element_map = {}
300
+ @values ||= {}
301
+ @title = false
193
302
  @custom_fields = false
303
+ @field_decorator = Aurita::GUI::Form_Field_Wrapper
304
+ @content_decorator = Aurita::GUI::Form_Content_Wrapper
194
305
  if block_given? then
195
306
  yield.each { |e| add(e) }
196
307
  end
@@ -251,10 +362,12 @@ module GUI
251
362
  # TODO: Should overwrite previous field element
252
363
  # with same field name.
253
364
  def add(form_field_element)
365
+ field_name = form_field_element.name.to_s
366
+ form_field_element.value = @values[field_name] unless form_field_element.value.to_s != ''
254
367
  if !form_field_element.dom_id then
255
- form_field_element.dom_id = form_field_element.name.to_s.gsub('.','_')
368
+ form_field_element.dom_id = field_name.gsub('.','_')
256
369
  end
257
- @element_map[form_field_element.name.to_s] = form_field_element
370
+ @element_map[field_name] = form_field_element
258
371
  @elements << form_field_element
259
372
  @content = false # Invalidate
260
373
  end
@@ -342,7 +455,7 @@ module GUI
342
455
  if element.kind_of? Aurita::GUI::Hidden_Field then
343
456
  @content << element
344
457
  else
345
- @content << Form_Field_Wrapper.new(element)
458
+ @content << @field_decorator.new(element)
346
459
  end
347
460
  end
348
461
  }
@@ -353,7 +466,8 @@ module GUI
353
466
  @content << element.to_hidden_field()
354
467
  end
355
468
  }
356
- @content = HTML.ul(:class => :form_fields) { @content }
469
+ fields_id = dom_id().to_s+'_fields' if dom_id()
470
+ @content = @content_decorator.new(:id => fields_id) { @content }
357
471
  return @content
358
472
  end
359
473
 
@@ -6,12 +6,34 @@ require('aurita-gui/form/form_error')
6
6
  module Aurita
7
7
  module GUI
8
8
 
9
- # Class Form_Field is an abstract base class for
10
- # built-in form fields (Input_Field, Hidden_Field,
9
+ # Class Form_Field is an abstract base class for built-in
10
+ # form fields (Input_Field, Hidden_Field,
11
11
  # Radio_Field, Checkbox_Field, Select_Field,
12
12
  # Textarea_Field) or any custom form field type.
13
- # It is a wrapper for GUI::Element, extending it
14
- # by parameters @name, @label and @value.
13
+ # It is a wrapper for GUI::Element, extending it by
14
+ # parameters @name, @label and @value.
15
+ #
16
+ # Form_Field can be used directly as a decorator for any
17
+ # instance of Element.
18
+ # This is useful in case you want to add GUI component
19
+ # to a form that is not derived from Form_Field itself.
20
+ # To do so, pass an Element instance to the constructor's
21
+ # block.
22
+ # Note that in any case, a Form_Field instance requires
23
+ # the :name attribute, even if this doesn't make
24
+ # sense at first glance when not adding a 'real' form
25
+ # field. This is necessary as it could not be accessed
26
+ # after adding it to the form otherwise.
27
+ #
28
+ # Example:
29
+ #
30
+ # button = Button.new(:onclick => 'submit();') { 'OK' }
31
+ # button_field = Form_Field.new(:name => :submit_button) { button }
32
+ # form.add(button_field)
33
+ #
34
+ #
35
+ # In common cases, you won't use Form_Field directly,
36
+ # but one of it's derivates.
15
37
  #
16
38
  # Usage:
17
39
  #
@@ -65,20 +87,28 @@ module GUI
65
87
  #
66
88
  # i.editable!
67
89
  #
90
+ # You can also store an expected data type in an Form_Field.
91
+ # This is just for convenience for e.g. form generators.
92
+ # So far, Form_Field@data_type won't be interpreted by
93
+ # any part of Aurita::GUI.
94
+ #
68
95
  class Form_Field < Element
69
96
 
70
- attr_accessor :type, :form, :label, :value, :required, :hidden
97
+ attr_accessor :type, :form, :label, :value, :required, :hidden, :data_type, :invalid, :hint
71
98
 
72
- def initialize(params)
99
+ def initialize(params, &block)
73
100
  # @value = params[:value]
74
101
  raise Form_Error.new('Must provide parameter :name for ' << self.class.to_s) unless params[:name]
75
- @form = params[:parent]
76
- @form ||= params[:form]
77
- @label = params[:label]
102
+ @form = params[:parent]
103
+ @form ||= params[:form]
104
+ @label = params[:label]
78
105
  # Get value from params unless set by derived constructor:
79
- @value = params[:value] unless @value
80
- @required = params[:required]
81
- @hidden = params[:hidden]
106
+ @value = params[:value] unless @value
107
+ @required = params[:required]
108
+ @hidden = params[:hidden]
109
+ @data_type = params[:data_type]
110
+ @invalid = params[:invalid]
111
+ @hint = params[:hint]
82
112
  # Do not delete parameter value, as it is a
83
113
  # standard for <input> elements.
84
114
  # Field types not supporting the value attribute
@@ -90,7 +120,14 @@ module GUI
90
120
  params.delete(:label)
91
121
  params.delete(:required)
92
122
  params.delete(:hidden)
123
+ params.delete(:data_type)
124
+ params.delete(:invalid)
125
+ params.delete(:hint)
93
126
  params[:parent] = @form
127
+ if block_given? then
128
+ @element = yield
129
+ params[:content] = @element
130
+ end
94
131
  super(params)
95
132
  end
96
133
 
@@ -103,7 +140,8 @@ module GUI
103
140
 
104
141
  # Virtual method.
105
142
  def element
106
- raise Form_Error.new('Cannot render abstract class Form_Field')
143
+ raise Form_Error.new('Cannot render abstract class Form_Field') unless @element
144
+ @element
107
145
  end
108
146
 
109
147
  # Render this form field element to a
@@ -160,6 +198,25 @@ module GUI
160
198
  end
161
199
  end
162
200
 
201
+ # Mark field element as invalid (e.g. missing value).
202
+ def invalid!
203
+ @invalid = true
204
+ add_class(:invalid)
205
+ end
206
+ # Whether this field element is marked as invalid.
207
+ def invalid?
208
+ @invalid == true
209
+ end
210
+ # Set :invalid flag (true | false).
211
+ def invalid=(is_invalid)
212
+ @invalid = is_invalid
213
+ if is_invalid then
214
+ add_class(:invalid)
215
+ else
216
+ remove_class(:invalid)
217
+ end
218
+ end
219
+
163
220
  # Set field element to disabled mode.
164
221
  # See Aurita::GUI::Form for more information
165
222
  # on rendering modes.
@@ -225,31 +282,6 @@ module GUI
225
282
  (@hidden == true)
226
283
  end
227
284
 
228
- protected
229
-
230
- def css_classes
231
- css_classes = @attrib[:class]
232
- if css_classes.kind_of? Array
233
- css_classes.flatten!
234
- elsif css_classes.kind_of? String
235
- css_classes = css_classes.split(' ')
236
- else # e.g. Symbol
237
- css_classes = [ css_classes ]
238
- end
239
- css_classes.collect { |c| c.to_sym if c }
240
- return css_classes
241
- end
242
-
243
- def add_class(css_class_name)
244
- @attrib[:class] = (css_classes << css_class_name.to_sym)
245
- end
246
-
247
- def remove_class(css_class_name)
248
- classes = css_classes
249
- classes.delete(css_class_name.to_sym)
250
- @attrib[:class] = classes
251
- end
252
-
253
285
  end # class
254
286
 
255
287
 
@@ -0,0 +1,28 @@
1
+
2
+ require('rubygems')
3
+ require('aurita-gui/form')
4
+
5
+ include Aurita::GUI
6
+
7
+ describe Aurita::GUI::Form, "basic rendering" do
8
+ before do
9
+ @form = Form.new()
10
+ @text_field = Input_Field.new(:name => :textfield)
11
+ end
12
+
13
+ it "should probvide method #add to add form fields" do
14
+ @form.add(@text_field)
15
+ end
16
+
17
+ it "should allow access to form fields by index" do
18
+ text_field = Input_Field.new(:name => :compare_me)
19
+ @form.add(text_field)
20
+ @form.elements[0].should == text_field
21
+ end
22
+
23
+ it "should wrap form fields as list elements (<li>...</li>)" do
24
+ @form.add(@text_field)
25
+ @form.to_s.should == '<form><ul class="form_fields"><li class="input_field_wrap form_field" id="textfield_wrap"><input type="text" name="textfield" id="textfield" /></li></ul></form>'
26
+ end
27
+
28
+ end
@@ -36,4 +36,10 @@ describe Aurita::GUI::HTML, "basic rendering" do
36
36
  @e.to_s.should == '<div class="outer"><h2 id="header">Header</h2><p id="content">Altered</p></div>'
37
37
  end
38
38
 
39
+ it "should escape double-quotes in tag parameters" do
40
+ e = Element.new(:onclick => 'alert("message");')
41
+ e.onclick.should == 'alert("message");'
42
+ e.to_s.should == '<div onclick="alert(\"message\");"></div>'
43
+ end
44
+
39
45
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aurita-gui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Fuchs
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-15 00:00:00 +01:00
12
+ date: 2009-01-20 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -58,6 +58,7 @@ files:
58
58
  - lib/aurita-gui/form/input_field.rb
59
59
  - lib/aurita-gui/form/date_field.rb
60
60
  - spec/;
61
+ - spec/form.rb
61
62
  - spec/html.rb
62
63
  - spec/element.rb
63
64
  has_rdoc: true