Class: Kiss::Form::Field

Inherits:
Object show all
Defined in:
lib/kiss/form/field.rb

Overview

Base class for single-value fields.

Constant Summary collapse

CURRENCY_SYMBOLS =
{
  :dollars => '$'
}

Instance Method Summary collapse

Constructor Details

#initialize(form, *args, &block) ⇒ Field

Returns a new instance of Field.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/kiss/form/field.rb', line 64

def initialize(form, *args, &block)
  # call as method to allow subclasses to override
  self.form = form
  
  # defaults
  @_save = true
  @_currency = nil
  @_object = @_form.object
  @_attach_errors = true
  
  _instance_variables_set_from_attrs(args.to_attrs)
  instance_eval(&block) if block_given?
  
  raise 'field must have a name' unless @_name
  @_name = @_name
  @_key ||= @_name.to_sym
  @_label ||= @_name.titleize unless self.is_a?(SubmitField)
  
  @_errors = []
  @_format = Kiss::Format.lookup(@_format)
  @_tip = ((legend = @_format.legend) ? "(#{legend})" : nil) unless defined? @_tip
  
  # object's value (if present) overrides default form field value
  if @_object && (value = @_object[@_key])
    @_value = value
  end
  
  if @_currency.is_a?(Symbol)
    @_currency = CURRENCY_SYMBOLS[@_currency] || ''
  end
  
  @_form.has_required_fields ||= @_required
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object



48
49
50
# File 'lib/kiss/form/field.rb', line 48

def method_missing(method, *args, &block)
  @_form.action.send method, *args, &block
end

Instance Method Details

#add_error(message) ⇒ Object



113
114
115
116
117
# File 'lib/kiss/form/field.rb', line 113

def add_error(message)
  (@_attach_errors ? @_errors : form.errors) << message
  @_form.has_field_errors = true
  nil
end

#content_tag_html(tag_name, content, attrs = {}, extra_html = nil) ⇒ Object



237
238
239
240
# File 'lib/kiss/form/field.rb', line 237

def (tag_name, content, attrs = {}, extra_html = nil)
  return content.to_s.html_escape.gsub(/\n/, '<br/>') if attrs[:read_only] || @_read_only
  tag_start_html(tag_name, attrs, extra_html) + ">#{content}</#{tag_name}>"
end

#debug(*args) ⇒ Object



52
53
54
# File 'lib/kiss/form/field.rb', line 52

def debug(*args)
  @_form.delegate.request.debug(args.first, Kernel.caller[0])
end

#element_html(attrs = {}) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/kiss/form/field.rb', line 185

def element_html(attrs = {})
  attrs.merge!(
    :value => value_string
  )
  
  if width = @_format.input_width
    attrs[:style] ||= "width: #{width}px"
  end
  
  @_currency.to_s + input_tag_html(attrs) + tip_html(attrs)
end

#errors_htmlObject



173
174
175
176
177
178
179
180
181
182
183
# File 'lib/kiss/form/field.rb', line 173

def errors_html
  return nil unless @_errors.size > 0
          
  if @_errors.size == 1
    content = @_errors[0]
  else
    content = "<ul>" + @_errors.map {|e| "<li>#{e}</li>"}.join + "</ul>"
  end
  
  %Q(<span class="#{@_form.field_error_class}">#{content}</span><br clear="all" />)
end

#html(*args) ⇒ Object



201
202
203
204
# File 'lib/kiss/form/field.rb', line 201

def html(*args)
  errors = errors_html
  element_html(*args) + (errors ? ('<br/>' + errors) : '')
end

#input_tag_html(attrs = {}, extra_html = nil) ⇒ Object



242
243
244
245
246
247
248
# File 'lib/kiss/form/field.rb', line 242

def input_tag_html(attrs = {}, extra_html = nil)
  tag_html(
    'input',
    {:type => self.class.type}.merge(attrs),
    extra_html
  )
end

#paramObject



98
99
100
# File 'lib/kiss/form/field.rb', line 98

def param
  @_param ||= @_form.params[@_name]
end

#require_value(enter_verb = 'enter') ⇒ Object



123
124
125
126
127
128
129
# File 'lib/kiss/form/field.rb', line 123

def require_value(enter_verb = 'enter')
  if (param !~ /\S/)
    # value required
    add_error("Please #{enter_verb} #{@_label.downcase}.")
    return
  end
end

#resetObject



131
132
133
134
# File 'lib/kiss/form/field.rb', line 131

def reset
  @_value = @_default_value if defined?(@_default_value)
  @_param = nil
end

#set_value_to_hash(h) ⇒ Object



250
251
252
# File 'lib/kiss/form/field.rb', line 250

def set_value_to_hash(h)
  h[self.name] = self.value
end

#set_value_to_object(obj) ⇒ Object



254
255
256
257
258
259
260
261
# File 'lib/kiss/form/field.rb', line 254

def set_value_to_object(obj)
  k = self.key
  v = (self.value != nil || obj.class.db_schema[k].allow_null) ?
    self.value : (obj.class.db_schema[k][:default] ||= self.format.default)
  v = Digest.const_get(self.digest.to_sym).hexdigest(value) if self.digest
  
  obj[k] = v
end

#tag_html(tag_name, attrs = {}, extra_html = nil) ⇒ Object



231
232
233
234
235
# File 'lib/kiss/form/field.rb', line 231

def tag_html(tag_name, attrs = {}, extra_html = nil)
  return attrs[:value].html_escape.to_s.gsub(/\n/, '<br/>') if attrs[:read_only] || @_read_only
  
  tag_start_html(tag_name, attrs, extra_html) + ' />'
end

#tag_start_html(tag_name, attrs = {}, extra_html = nil) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/kiss/form/field.rb', line 206

def tag_start_html(tag_name, attrs = {}, extra_html = nil)
  attrs = attrs.clone
  attrs[:name] ||= @_name
  attrs[:size] ||= @_size if @_size
  attrs[:style] ||= @_style if @_style
  
  read_only = attrs.delete(:read_only) || @_read_only
  
  html_parts = ["<#{tag_name}"]
  
  html = attrs.delete(:html) || @_html
  attrs.each_pair {|k, v| html_parts.push %Q(#{k}="#{v}") }
  
  if html
    if html.is_a?(Hash)
      html.each_pair {|k, v| html_parts.push %Q(#{k}="#{v}") }
    else
      html_parts.push(@_html.to_s)
    end
  end
  
  html_parts.push(extra_html) if extra_html
  html_parts.join(' ')
end

#tip_html(attrs) ⇒ Object



197
198
199
# File 'lib/kiss/form/field.rb', line 197

def tip_html(attrs)
  (tip = attrs.has_key?(:tip) ? attrs[:tip] : @_tip) ? " <small>#{tip}</small>" : ''
end

#typeObject



60
61
62
# File 'lib/kiss/form/field.rb', line 60

def type
  self.class.type
end

#validate(enter_verb = 'enter') ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/kiss/form/field.rb', line 136

def validate(enter_verb = 'enter')
  @_default_value ||= value
  
  require_value(enter_verb) if @_required
  
  begin
    p = @_format.validate(param, @_form.context)
    p *= @_factor if p && @_factor
    value = p
  rescue Kiss::Format::ValidateError => e
    return add_error("#{label.capitalize} #{e.message}.")
  end
  
  if @_min_value_size && value.size < @_min_value_size
    return add_error("#{name.capitalize} must be at least #{@_min_value_size} characters long.")
  end
  if @_max_value_size && value.size < @_max_value_size
    return add_error("#{name.capitalize} must be no more than #{@_max_value_size} characters long.")
  end
  
  if @_match
    match_field = @_form.fields[@_match.to_s]
    if value != match_field.value
      return add_error("#{match_field.label.pluralize} don't match.")
    end
  end
  
  if @_save && @_unique
    dataset = @_object.model.filter(@_key => value)
    unless (@_object.new? ? dataset : dataset.exclude(@_object.pk_hash)).empty?
      return add_error("There is already another #{@_object.model.name.singularize.gsub('_', ' ')} with the same #{@_label.downcase.gsub('_', ' ')}.")
    end
  end
  
  @_value = value
end

#valueObject



102
103
104
# File 'lib/kiss/form/field.rb', line 102

def value
  @_value
end

#value_stringObject



106
107
108
109
110
111
# File 'lib/kiss/form/field.rb', line 106

def value_string
  return param if param
  v = self.value
  v = (v.to_f / @_factor) if v && @_factor
  value_to_s(v)
end

#value_to_s(value) ⇒ Object



119
120
121
# File 'lib/kiss/form/field.rb', line 119

def value_to_s(value)
  value ? @_format.value_to_s(value, @_form.context) : ''
end