kiss 1.1 → 1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/bin/kiss +151 -34
- data/data/scaffold.tgz +0 -0
- data/lib/kiss.rb +389 -742
- data/lib/kiss/accessors/controller.rb +47 -0
- data/lib/kiss/accessors/request.rb +106 -0
- data/lib/kiss/accessors/template.rb +23 -0
- data/lib/kiss/action.rb +502 -132
- data/lib/kiss/bench.rb +14 -5
- data/lib/kiss/debug.rb +14 -6
- data/lib/kiss/exception_report.rb +22 -299
- data/lib/kiss/ext/core.rb +700 -0
- data/lib/kiss/ext/rack.rb +33 -0
- data/lib/kiss/ext/sequel_database.rb +47 -0
- data/lib/kiss/ext/sequel_mysql_dataset.rb +23 -0
- data/lib/kiss/form.rb +404 -179
- data/lib/kiss/form/field.rb +183 -307
- data/lib/kiss/form/field_types.rb +239 -0
- data/lib/kiss/format.rb +88 -70
- data/lib/kiss/html/exception_report.css +222 -0
- data/lib/kiss/html/exception_report.html +210 -0
- data/lib/kiss/iterator.rb +14 -12
- data/lib/kiss/login.rb +8 -8
- data/lib/kiss/mailer.rb +68 -66
- data/lib/kiss/model.rb +323 -36
- data/lib/kiss/rack/bench.rb +16 -8
- data/lib/kiss/rack/email_errors.rb +25 -15
- data/lib/kiss/rack/errors_ok.rb +2 -2
- data/lib/kiss/rack/facebook.rb +6 -6
- data/lib/kiss/rack/file_not_found.rb +10 -8
- data/lib/kiss/rack/log_exceptions.rb +3 -3
- data/lib/kiss/rack/recorder.rb +2 -2
- data/lib/kiss/rack/show_debug.rb +2 -2
- data/lib/kiss/rack/show_exceptions.rb +2 -2
- data/lib/kiss/request.rb +435 -0
- data/lib/kiss/sequel_session.rb +15 -14
- data/lib/kiss/static_file.rb +20 -13
- data/lib/kiss/template.rb +327 -0
- metadata +60 -25
- data/lib/kiss/controller_accessors.rb +0 -81
- data/lib/kiss/hacks.rb +0 -188
- data/lib/kiss/sequel_mysql.rb +0 -25
- data/lib/kiss/template_methods.rb +0 -167
data/lib/kiss/form/field.rb
CHANGED
@@ -1,186 +1,259 @@
|
|
1
|
+
require 'kiss/form/field';
|
2
|
+
|
1
3
|
class Kiss
|
2
4
|
class Form
|
3
5
|
class Field
|
6
|
+
dsl_accessor :name, :type, :form, :currency, :label, :no_label, :prompt, :value, :read_only,
|
7
|
+
:ignore, :save, :options, :options_value_key, :options_display_key, :options_display_transform,
|
8
|
+
:required, :unique, :cancel, :columns, :style, :hidden_join, :html, :other, :other_field, :object,
|
9
|
+
:format, :display_format, :key, :match, :tip, :statement, :attach_errors, :factor, :digest,
|
10
|
+
:min_value_size, :max_value_size, :choose_here
|
11
|
+
alias_method :option_value_key, :options_value_key
|
12
|
+
alias_method :option_display_key, :options_display_key
|
13
|
+
alias_method :option_display_transform, :options_display_transform
|
14
|
+
alias_method :min_value_length, :min_value_size
|
15
|
+
alias_method :max_value_length, :max_value_size
|
4
16
|
|
5
|
-
|
6
|
-
|
7
|
-
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
@_form.action.send method, *args, &block
|
19
|
+
end
|
8
20
|
|
9
|
-
|
21
|
+
def options_keys(value, display)
|
22
|
+
@_options_value_key = value
|
23
|
+
@_options_display_key = display
|
24
|
+
end
|
25
|
+
alias_method :option_keys, :options_keys
|
26
|
+
|
27
|
+
def debug(*args)
|
28
|
+
@_form.delegate.request.debug(args.first, Kernel.caller[0])
|
29
|
+
end
|
10
30
|
|
11
|
-
def initialize(form,
|
12
|
-
|
13
|
-
@
|
14
|
-
@
|
31
|
+
def initialize(form, *args, &block)
|
32
|
+
# defaults
|
33
|
+
@_form = form
|
34
|
+
@_save = true
|
35
|
+
@_currency = nil
|
36
|
+
@_attrs = args.to_attrs
|
37
|
+
@_type = :text
|
38
|
+
@_object = @_form.object
|
39
|
+
@_save = true
|
40
|
+
@_attach_errors = true
|
41
|
+
|
42
|
+
_instance_variables_set_from_attrs(@_attrs)
|
43
|
+
instance_eval(&block) if block_given?
|
44
|
+
|
45
|
+
@_errors = []
|
46
|
+
|
47
|
+
@_format = Kiss::Format.lookup(@_format)
|
48
|
+
@_display_format = Kiss::Format.lookup(@_display_format)
|
15
49
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
:save => true
|
20
|
-
}.merge(attrs))
|
50
|
+
raise 'field must have a name' unless @_name
|
51
|
+
@_key ||= @_name
|
52
|
+
@_label ||= @_name.titleize unless @_type == :submit
|
21
53
|
|
22
|
-
|
54
|
+
# object's value overrides any form field value
|
55
|
+
# form field value is intended as default in case object value is missing
|
56
|
+
if @_object && (value = @_object[@_key.to_sym])
|
57
|
+
@_value = value
|
58
|
+
end
|
59
|
+
|
60
|
+
if @_currency.is_a?(Symbol)
|
61
|
+
@_currency = case @_currency
|
62
|
+
when :dollars
|
63
|
+
'$'
|
64
|
+
else
|
65
|
+
''
|
66
|
+
end
|
67
|
+
end
|
23
68
|
|
24
|
-
|
25
|
-
|
69
|
+
if @_options
|
70
|
+
if @_options[0].is_a?(Array)
|
71
|
+
@_options_value_key ||= 0
|
72
|
+
(@_options_display_key ||= (@_options[0].size == 1) ? 0 : 1)
|
73
|
+
elsif defined?(Kiss::Model) && @_options[0].is_a?(Kiss::Model)
|
74
|
+
model_klass = @_options[0].class
|
75
|
+
@_options_value_key ||= model_klass.value_column
|
76
|
+
@_options_display_key ||= model_klass.display_column
|
77
|
+
elsif @_options[0].is_a?(Hash)
|
78
|
+
@_options_value_key ||= :id
|
79
|
+
@_options_display_key ||= :name
|
80
|
+
end
|
81
|
+
end
|
26
82
|
|
27
|
-
@
|
83
|
+
@_tip = ((legend = @_format.legend) ? "(#{legend})" : nil) unless defined? @_tip
|
28
84
|
|
29
|
-
@
|
85
|
+
@_form.has_required_fields ||= @_required
|
30
86
|
end
|
31
87
|
|
32
88
|
def other_field_html
|
33
|
-
return '' unless @
|
89
|
+
return '' unless @_other
|
34
90
|
|
35
|
-
other_checked = @
|
91
|
+
other_checked = @_value && !option_pairs.any? {|v, d| v == @_value }
|
36
92
|
|
37
|
-
(@
|
93
|
+
(@_columns ? '<br/>' : ' ') + [
|
38
94
|
input_tag_html(
|
39
|
-
{ :value => 'other', :html => { :id => @
|
95
|
+
{ :value => 'other', :html => { :id => @_name+'.other' } },
|
40
96
|
other_checked ? 'checked' : ''
|
41
97
|
),
|
42
|
-
@
|
98
|
+
@_other[:label] || 'Other',
|
43
99
|
': ',
|
44
|
-
@
|
100
|
+
@_currency.to_s,
|
45
101
|
input_tag_html({
|
46
102
|
:type => :text,
|
47
|
-
:name => @
|
48
|
-
:value => other_checked ? value_to_s(@
|
103
|
+
:name => @_name+'.other',
|
104
|
+
:value => other_checked ? value_to_s(@_value) : nil,
|
49
105
|
:html => {
|
50
|
-
:onfocus => "document.getElementById('#{@
|
106
|
+
:onfocus => "document.getElementById('#{@_name}.other').checked = true"
|
51
107
|
}
|
52
|
-
}.merge(@
|
108
|
+
}.merge(@_other))
|
53
109
|
].join
|
54
110
|
end
|
55
111
|
|
56
112
|
def column_layout(elements_html)
|
57
|
-
if
|
58
|
-
|
59
|
-
|
113
|
+
if elements_html.empty?
|
114
|
+
''
|
115
|
+
elsif @_columns
|
116
|
+
layout_columns = [@_columns, elements_html.size].min
|
117
|
+
num_elements_per_column = ((elements_html.size + layout_columns - 1) / layout_columns).to_i
|
118
|
+
layout_columns = ((elements_html.size + num_elements_per_column - 1) / num_elements_per_column).to_i
|
119
|
+
|
120
|
+
style = "style=\"width: #{(100 / layout_columns).to_i - 1}%\""
|
60
121
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
["<tr>", elements_html[range], "</tr>"]
|
68
|
-
end,'</table>'].flatten.join
|
122
|
+
'<table class="kiss_field_columns"><tr>' +
|
123
|
+
(0...layout_columns).map do |i|
|
124
|
+
"<td #{style}>" + elements_html[i * num_elements_per_column, num_elements_per_column].join('<br/>') + "</td>"
|
125
|
+
end.join + '</table>'
|
126
|
+
else
|
127
|
+
elements_html.map {|h| "<nobr>#{h}</nobr>"}.join(' ')
|
69
128
|
end
|
70
|
-
|
71
|
-
# else columns <= 1
|
72
|
-
elements_html.join(' ')
|
73
129
|
end
|
74
130
|
|
75
|
-
# def sequel_value
|
76
|
-
# case @format
|
77
|
-
# when :date:
|
78
|
-
# return Kiss.mdy_to_ymd(value)
|
79
|
-
# when :datetime:
|
80
|
-
# datetime = value.sub(/([ap]m)\s*\Z/i,' \1')
|
81
|
-
# date, time, ampm = datetime.split(/\s+/)
|
82
|
-
#
|
83
|
-
# hours, minutes = time.split(/:/)
|
84
|
-
# hours = 0 if hours.to_i == 12 && ampm
|
85
|
-
# if (ampm.downcase == 'pm')
|
86
|
-
# hours = hours.to_i + 12
|
87
|
-
# end
|
88
|
-
#
|
89
|
-
# return Kiss.mdy_to_ymd(date) + " #{hours}:#{minutes}"
|
90
|
-
# when :month_year:
|
91
|
-
# month, year = value.sub(/\A\s*/,'').sub(/\s*\Z/,'').split(/\D+/)
|
92
|
-
# # convert two-digit years to four-digit years
|
93
|
-
# year = year.to_i
|
94
|
-
# if year < 100
|
95
|
-
# year += 1900
|
96
|
-
# year += 100 if year < Time.now.year - 95
|
97
|
-
# end
|
98
|
-
# return sprintf("%04d-%02d-01",year,month.to_i)
|
99
|
-
# else
|
100
|
-
# return value.is_a?(Array) ? value.map {|v| v.gsub(/,/,'\,')}.join(',') : value
|
101
|
-
# end
|
102
|
-
# end
|
103
|
-
|
104
131
|
def param
|
105
|
-
@
|
132
|
+
@_param ||= @_form.params[@_name.to_s]
|
106
133
|
end
|
107
134
|
|
108
135
|
def value
|
109
|
-
@
|
136
|
+
@_value
|
137
|
+
end
|
138
|
+
|
139
|
+
def value_string
|
140
|
+
v = value
|
141
|
+
v *= @_factor if v && @_factor
|
142
|
+
param || value_to_s(v)
|
110
143
|
end
|
111
144
|
|
112
145
|
def add_error(message)
|
113
|
-
@errors << message
|
114
|
-
@
|
146
|
+
(@_attach_errors ? @_errors : form.errors) << message
|
147
|
+
@_form.has_field_errors = true
|
148
|
+
nil
|
115
149
|
end
|
116
150
|
|
117
151
|
def value_to_s(value)
|
118
|
-
value ? @
|
152
|
+
value ? @_format.value_to_s(value, @_form.context) : ''
|
119
153
|
end
|
120
154
|
|
121
155
|
def display_to_s(value)
|
122
|
-
value ? @
|
156
|
+
value ? @_display_format.value_to_s(value).send(@_options_display_transform) : ''
|
123
157
|
end
|
124
158
|
|
125
|
-
def
|
126
|
-
if
|
159
|
+
def require_value(enter_verb = 'enter')
|
160
|
+
if (param !~ /\S/)
|
127
161
|
# value required
|
128
|
-
add_error("Please #{
|
162
|
+
add_error("Please #{enter_verb} #{@_label}")
|
129
163
|
return
|
130
164
|
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def reset
|
168
|
+
@_value = @_default_value if defined?(@_default_value)
|
169
|
+
@_param = nil
|
170
|
+
end
|
171
|
+
|
172
|
+
def validate(enter_verb = 'enter')
|
173
|
+
@_default_value ||= value
|
174
|
+
|
175
|
+
require_value(enter_verb) if @_required
|
131
176
|
|
132
177
|
begin
|
133
|
-
|
178
|
+
p = @_format.validate(param, @_form.context)
|
179
|
+
p *= @_factor if @_factor
|
180
|
+
value = p
|
134
181
|
rescue Kiss::Format::ValidateError => e
|
135
|
-
add_error("#{e.message.capitalize}")
|
182
|
+
return add_error("#{e.message.capitalize}")
|
183
|
+
end
|
184
|
+
|
185
|
+
if @_match
|
186
|
+
match_field = @_form.fields[@_match.to_s]
|
187
|
+
if value != match_field.value
|
188
|
+
return add_error("#{match_field.label.pluralize} don't match.")
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
if @_save && @_unique
|
193
|
+
dataset = @_object.model.filter(@_name.to_sym => value)
|
194
|
+
unless (@_object.new? ? dataset : dataset.exclude(@_object.pk_hash)).empty?
|
195
|
+
return add_error("There is already another #{@_object.model.name.singularize.gsub('_', ' ')} with the same #{@_label.downcase.gsub('_', ' ')}.")
|
196
|
+
end
|
136
197
|
end
|
137
198
|
|
138
|
-
@value
|
199
|
+
@_value = value
|
139
200
|
end
|
140
201
|
|
141
202
|
def errors_html
|
142
|
-
return nil unless @
|
203
|
+
return nil unless @_errors.size > 0
|
143
204
|
|
144
|
-
if @
|
145
|
-
content = @
|
205
|
+
if @_errors.size == 1
|
206
|
+
content = @_errors[0]
|
146
207
|
else
|
147
|
-
content = "<ul>" + @
|
208
|
+
content = "<ul>" + @_errors.map {|e| "<li>#{e}</li>"}.join + "</ul>"
|
148
209
|
end
|
149
210
|
|
150
|
-
%Q(<span class="#{@
|
211
|
+
%Q(<span class="#{@_form.field_error_class}">#{content}</span><br clear="all" />)
|
151
212
|
end
|
152
213
|
|
153
|
-
def element_html
|
154
|
-
attrs
|
155
|
-
|
156
|
-
|
214
|
+
def element_html(attrs = {})
|
215
|
+
attrs.merge!(
|
216
|
+
:value => value_string
|
217
|
+
)
|
218
|
+
|
219
|
+
if width = @_format.input_width
|
220
|
+
attrs[:style] ||= "width: #{width}px"
|
157
221
|
end
|
158
222
|
|
159
|
-
@
|
160
|
-
|
223
|
+
@_currency.to_s + input_tag_html( attrs ) + tip_html(attrs)
|
224
|
+
end
|
225
|
+
|
226
|
+
def table_row_html
|
227
|
+
form.component_html(self)
|
228
|
+
end
|
229
|
+
|
230
|
+
def tip_html(attrs)
|
231
|
+
(tip = attrs.has_key?(:tip) ? attrs[:tip] : @_tip) ? " <small>#{tip}</small>" : ''
|
161
232
|
end
|
162
233
|
|
163
|
-
def html
|
234
|
+
def html(*args)
|
164
235
|
errors = errors_html
|
165
|
-
element_html + (errors ? (@
|
236
|
+
element_html(*args) + (errors ? (@_columns ? '' : '<br/>') + %Q(#{errors}) : '')
|
166
237
|
end
|
167
238
|
|
168
239
|
def tag_start_html(tag_name, attrs = {}, extra_html = nil)
|
169
240
|
attrs = attrs.clone
|
170
|
-
attrs[:name] ||= @
|
171
|
-
attrs[:size] ||= @
|
172
|
-
attrs[:style] ||= @
|
241
|
+
attrs[:name] ||= @_name
|
242
|
+
attrs[:size] ||= @_size if @_size
|
243
|
+
attrs[:style] ||= @_style if @_style
|
244
|
+
|
245
|
+
read_only = attrs.delete(:read_only) || @_read_only
|
173
246
|
|
174
247
|
html_parts = ["<#{tag_name}"]
|
175
248
|
|
176
|
-
html = attrs.delete(:html) || @
|
177
|
-
attrs.each_pair {|k,v| html_parts.push %Q(#{k}="#{v}") }
|
249
|
+
html = attrs.delete(:html) || @_html
|
250
|
+
attrs.each_pair {|k, v| html_parts.push %Q(#{k}="#{v}") }
|
178
251
|
|
179
252
|
if html
|
180
253
|
if html.is_a?(Hash)
|
181
|
-
html.each_pair {|k,v| html_parts.push %Q(#{k}="#{v}") }
|
254
|
+
html.each_pair {|k, v| html_parts.push %Q(#{k}="#{v}") }
|
182
255
|
else
|
183
|
-
html_parts.push(@
|
256
|
+
html_parts.push(@_html.to_s)
|
184
257
|
end
|
185
258
|
end
|
186
259
|
|
@@ -189,222 +262,25 @@ class Kiss
|
|
189
262
|
end
|
190
263
|
|
191
264
|
def tag_html(tag_name, attrs = {}, extra_html = nil)
|
192
|
-
|
265
|
+
return attrs[:value].html_escape.to_s.gsub(/\n/, '<br/>') if attrs[:read_only] || @_read_only
|
266
|
+
|
267
|
+
tag_start_html(tag_name, attrs, extra_html) + ' />'
|
193
268
|
end
|
194
269
|
|
195
270
|
def content_tag_html(tag_name, content, attrs = {}, extra_html = nil)
|
196
|
-
|
271
|
+
return content.to_s.html_escape.gsub(/\n/, '<br/>') if attrs[:read_only] || @_read_only
|
272
|
+
tag_start_html(tag_name, attrs, extra_html) + ">#{content}</#{tag_name}>"
|
197
273
|
end
|
198
274
|
|
199
275
|
def input_tag_html(attrs = {}, extra_html = nil)
|
200
276
|
tag_html(
|
201
277
|
'input',
|
202
|
-
{:type => @
|
278
|
+
{:type => @_type}.merge(attrs),
|
203
279
|
extra_html
|
204
280
|
)
|
205
281
|
end
|
206
282
|
end
|
207
|
-
|
208
|
-
class HiddenField < Field; end
|
209
|
-
class TextField < Field; end
|
210
|
-
|
211
|
-
class TextAreaField < Field
|
212
|
-
attr_accessor :rows,:cols
|
213
|
-
|
214
|
-
def initialize(*args)
|
215
|
-
@rows = 5
|
216
|
-
@cols = 20
|
217
|
-
super(*args)
|
218
|
-
end
|
219
|
-
|
220
|
-
def element_html
|
221
|
-
content_tag_html(
|
222
|
-
'textarea',
|
223
|
-
param || value_to_s(@value),
|
224
|
-
{
|
225
|
-
:rows => @rows ||= 1,
|
226
|
-
:cols => @cols ||= 1
|
227
|
-
}
|
228
|
-
)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
class PasswordField < Field
|
233
|
-
def element_html
|
234
|
-
input_tag_html
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
class BooleanField < Field
|
239
|
-
def element_html
|
240
|
-
input_tag_html({ :value => 1 }, @value ? 'checked' : '')
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
class FileField < Field
|
245
|
-
def element_html
|
246
|
-
input_tag_html
|
247
|
-
end
|
248
|
-
|
249
|
-
def get_file_name
|
250
|
-
|
251
|
-
end
|
252
|
-
|
253
|
-
def get_file_data
|
254
|
-
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
class SubmitField < Field
|
259
|
-
def initialize(*args)
|
260
|
-
@save = false
|
261
|
-
super(*args)
|
262
|
-
end
|
263
|
-
|
264
|
-
def element_html
|
265
|
-
elements_html.join(' ')
|
266
|
-
end
|
267
|
-
|
268
|
-
def elements_html
|
269
|
-
@options.map do |option|
|
270
|
-
input_tag_html({ :value => value_to_s(option) })
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
# ------ MultiChoiceField
|
276
|
-
|
277
|
-
class MultiChoiceField < Field
|
278
|
-
def option_pairs
|
279
|
-
(defined? @options_value_key) ?
|
280
|
-
@options.map {|option| [ option[@options_value_key], option[@options_display_key] ]} :
|
281
|
-
begin
|
282
|
-
@display_format = @format
|
283
|
-
@options.map {|option| [ option, option ] }
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def matched_options(value)
|
288
|
-
value = [value].flatten
|
289
|
-
@options_value_key ?
|
290
|
-
@options.select {|o| value.select {|v| o[@options_value_key] == v } }.flatten :
|
291
|
-
@options.select {|o| value.select {|v| o == v } }.flatten
|
292
|
-
end
|
293
|
-
|
294
|
-
def validate
|
295
|
-
if @other && param == 'other'
|
296
|
-
@param = @form.params[@name+'.other']
|
297
|
-
end
|
298
|
-
super('select')
|
299
|
-
|
300
|
-
if @value =~ /\S/ && matched_options(@value).size == 0
|
301
|
-
add_error "Invalid selection"
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
class SelectField < MultiChoiceField
|
307
|
-
def element_html
|
308
|
-
return 'No options' unless @options.size > 0
|
309
|
-
|
310
|
-
placeholder_html = %Q(<option value="">Choose Here</option>)
|
311
|
-
|
312
|
-
options_html = option_pairs.map do |value,display|
|
313
|
-
selected = (@value.to_s == value.to_s) ? ' selected' : ''
|
314
|
-
%Q(<option value="#{value_to_s(value)}"#{selected}>#{display}</option>)
|
315
|
-
end.join
|
316
|
-
|
317
|
-
content_tag_html('select', placeholder_html + options_html) + other_field_html
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
class RadioField < MultiChoiceField
|
322
|
-
def element_html
|
323
|
-
column_layout(elements_html) + other_field_html
|
324
|
-
end
|
325
|
-
|
326
|
-
def elements_html
|
327
|
-
option_pairs.map do |value,display|
|
328
|
-
input_tag_html(
|
329
|
-
{ :value => value_to_s(value) },
|
330
|
-
(@value.to_s == value.to_s) ? 'checked' : ''
|
331
|
-
) + @currency.to_s + display_to_s(display)
|
332
|
-
end
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
|
337
|
-
# ------ MultiValueField
|
338
|
-
|
339
|
-
class MultiValueField < MultiChoiceField
|
340
|
-
def param
|
341
|
-
@form.params[@name.to_s+'[]'] || []
|
342
|
-
end
|
343
|
-
|
344
|
-
def validate
|
345
|
-
begin
|
346
|
-
@value = param.map { |p| @format.validate(p) }
|
347
|
-
rescue Kiss::Format::ValidateError => e
|
348
|
-
add_error("#{e.message.capitalize}")
|
349
|
-
return
|
350
|
-
end
|
351
|
-
|
352
|
-
if @value.size > 0
|
353
|
-
@value.each do |v|
|
354
|
-
unless (matched_options(v).size > 0)
|
355
|
-
add_error "#Invalid selection"
|
356
|
-
return
|
357
|
-
end
|
358
|
-
end
|
359
|
-
elsif @required
|
360
|
-
add_error "Please select at least one #{@label}"
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
def selected_option_values
|
365
|
-
@selected_option_values ||= @value ? Hash[ *(@value.map {|v| [v.to_s,true]}.flatten) ] : {}
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
class CheckboxField < MultiValueField
|
370
|
-
def element_html
|
371
|
-
hidden_options = @hidden_join ? input_tag_html(
|
372
|
-
:type => 'hidden',
|
373
|
-
:name => "#{@name}_options",
|
374
|
-
:value => option_pairs.map {|v,d| value_to_s(v) }.join(@hidden_join)
|
375
|
-
) : ''
|
376
|
-
|
377
|
-
column_layout(elements_html) + other_field_html + hidden_options
|
378
|
-
end
|
379
|
-
|
380
|
-
def elements_html
|
381
|
-
name = @name.to_s+'[]'
|
382
|
-
option_pairs.map do |value,display|
|
383
|
-
input_tag_html(
|
384
|
-
{ :name => name, :value => value_to_s(value) },
|
385
|
-
selected_option_values[value.to_s] ? 'checked' : ''
|
386
|
-
) + @currency.to_s + display_to_s(display)
|
387
|
-
end
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
class MultiSelectField < MultiValueField
|
392
|
-
def element_html
|
393
|
-
options_html = option_pairs.map do |value,display|
|
394
|
-
selected = selected_option_values[value] ? ' selected' : ''
|
395
|
-
%Q(<option value="#{value_to_s(value)}"#{selected}>#{display}</option>)
|
396
|
-
end.join
|
397
|
-
|
398
|
-
content_tag_html(
|
399
|
-
'select',
|
400
|
-
options_html,
|
401
|
-
{},
|
402
|
-
'multiple'
|
403
|
-
)
|
404
|
-
end
|
405
|
-
end
|
406
283
|
end
|
407
284
|
end
|
408
285
|
|
409
|
-
|
410
|
-
# :multitext => MultiTextField,
|
286
|
+
require 'kiss/form/field_types'
|