kiss 1.1 → 1.7
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/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'
|