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 +3 -0
- data/aurita-gui.gemspec +1 -1
- data/lib/aurita-gui/element.rb +39 -3
- data/lib/aurita-gui/form.rb +135 -21
- data/lib/aurita-gui/form/form_field.rb +70 -38
- data/spec/form.rb +28 -0
- data/spec/html.rb +6 -0
- metadata +3 -2
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
|
|
data/aurita-gui.gemspec
CHANGED
@@ -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.
|
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
|
data/lib/aurita-gui/element.rb
CHANGED
@@ -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
|
|
data/lib/aurita-gui/form.rb
CHANGED
@@ -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 =
|
30
|
-
|
31
|
-
|
32
|
-
|
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 =>
|
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
|
184
|
-
@method
|
185
|
-
@fields
|
186
|
-
@values
|
187
|
-
@method
|
188
|
-
@fields
|
189
|
-
@elements
|
190
|
-
@element_map
|
191
|
-
@values
|
192
|
-
@title
|
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 =
|
368
|
+
form_field_element.dom_id = field_name.gsub('.','_')
|
256
369
|
end
|
257
|
-
@element_map[
|
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 <<
|
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
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
76
|
-
@form
|
77
|
-
@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
|
80
|
-
@required
|
81
|
-
@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
|
|
data/spec/form.rb
ADDED
@@ -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
|
data/spec/html.rb
CHANGED
@@ -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.
|
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-
|
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
|