# Kiss Form Field types.
class Kiss
class Form
class HiddenField < Field; end
class TextField < Field; end
class TextAreaField < Field
_attr_accessor :rows, :cols
def initialize(*args)
@_rows = 5
@_cols = 20
super(*args)
end
def element_html(attrs = {})
content_tag_html(
'textarea',
value_string,
attrs.merge(
:rows => @_rows ||= 1,
:cols => @_cols ||= 1
)
) + tip_html(attrs)
end
end
class PasswordField < Field
def element_html(*args)
input_tag_html(*args)
end
end
class FileField < Field
def element_html(attrs = {})
input_tag_html(attrs) + tip_html(attrs)
end
def get_file_name; end
def get_file_data; end
def require_value(enter_verb)
p = param
return add_error("Please choose #{label}") unless p && p[:type]
end
def validate
require_value(nil) if @_required
end
end
class SubmitField < Field
def initialize(*args)
@_save = false
super(*args)
end
def element_html(*args)
elements_html(*args).join(' ')
end
def elements_html(attrs = {})
@_options.map do |option|
input_tag_html(attrs.merge( :value => value_to_s(option) ))
end
end
end
# ------ MultiChoiceField
class MultiChoiceField < Field
def initialize(*args, &block)
@_options_display_transform = :to_s
super(*args, &block)
end
def option_pairs
pairs = if @_options_value_key
if @_options_display_key.is_a?(Proc)
@_options.map {|option| [ option[@_options_value_key], @_options_display_key.call(option) ]}
else
@_options.map {|option| [
option[@_options_value_key] || option.send(@_options_value_key),
option[@_options_display_key] || option.send(@_options_display_key)
]}
end
else
@_display_format = @_format
@_options.map {|option| [ option, option ]}
end
pairs
end
def has_option_value?(v)
!(@_options_value_key ?
@_options.select {|o| value_to_s(o[@_options_value_key]) == v } :
@_options.select {|o| value_to_s(o) == v }
).empty?
end
def validate
if @_other && param == 'other'
@_param = @_form.params[@_name+'.other']
end
super('select')
if @_value =~ /\S/ && !has_option_value?(@_value)
add_error "Invalid selection"
end
end
end
class SelectField < MultiChoiceField
def element_html(attrs = {})
return 'No options' unless @_options.size > 0
@_choose_here ||= 'Choose Here'
placeholder_html = %Q()
options_html = option_pairs.map do |option_value, option_display|
option_value_string = value_to_s(option_value)
selected = (value_string == option_value_string) ? ' selected' : ''
%Q()
end.join
content_tag_html('select', placeholder_html + options_html, attrs) + other_field_html + tip_html(attrs)
end
end
class RadioField < MultiChoiceField
def element_html(attrs = {})
column_layout(elements_html(attrs)) + other_field_html + tip_html(attrs)
end
def elements_html(attrs = {})
option_pairs.map do |option_value, option_display|
option_value_string = value_to_s(option_value)
input_tag_html(
attrs.merge( :type => 'radio', :value => option_value_string ),
(value_string == option_value_string) ? 'checked' : ''
) + @_currency.to_s + display_to_s(option_display)
end
end
end
class BooleanField < RadioField
def initialize(*args, &block)
@_options = [[1, 'Yes'], [0, 'No']]
super(*args, &block)
end
end
# ------ MultiValueField
class MultiValueField < MultiChoiceField
def param
@_form.params[@_name.to_s+'[]'] || []
end
def validate
begin
@_value = param.map { |p| @_format.validate(p) }
rescue Kiss::Format::ValidateError => e
return add_error("#{e.message.capitalize}")
end
if @_value.empty? && @_required
return add_error "Please select at least one #{@_label.downcase.singularize}"
end
if @_min_value_size && @_value.size < @_min_value_size
return add_error "Please select at least #{@_min_value_size.of(@_label.downcase)}"
end
if @_max_value_size && @_value.size > @_max_value_size
return add_error "Please select no more than #{@_max_value_size.of(@_label.downcase)}"
end
@_value.each do |v|
unless has_option_value?(v)
return add_error "Invalid selection"
end
end
end
def selected_option_values
@_selected_option_values ||= @_value ? Hash[ *(@_value.map {|v| [value_to_s(v), true]}.flatten) ] : {}
end
end
class CheckboxField < MultiValueField
def element_html(attrs = {})
hidden_options = @_hidden_join ? input_tag_html(
:type => 'hidden',
:name => "#{@_name}_options",
:value => option_pairs.map {|option_value, option_display| value_to_s(option_value) }.join(@_hidden_join)
) : ''
column_layout(elements_html(attrs)) + other_field_html + hidden_options + tip_html(attrs)
end
def elements_html(attrs = {})
name = @_name.to_s+'[]'
option_pairs.map do |option_value, option_display|
option_value_string = value_to_s(option_value)
input_tag_html(
attrs.merge( :name => name, :value => option_value_string ),
selected_option_values[option_value_string] ? 'checked' : ''
) + @_currency.to_s + display_to_s(option_display)
end
end
end
class MultiSelectField < MultiValueField
def element_html(attrs = {})
options_html = option_pairs.map do |option_value, option_display|
option_value_string = value_to_s(option_value)
selected = selected_option_values[option_value_string] ? ' selected' : ''
%Q()
end.join
content_tag_html(
'select',
options_html,
attrs,
'multiple'
)
end
end
# not implemented yet: MultiTextField,
end
end