aurita-gui 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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