storefront 0.2.1 → 0.2.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.
Files changed (73) hide show
  1. data/Rakefile +2 -2
  2. data/lib/storefront.rb +21 -3
  3. data/lib/storefront/configuration.rb +154 -0
  4. data/lib/storefront/dashboard.rb +8 -7
  5. data/lib/storefront/form.rb +70 -53
  6. data/lib/storefront/form/base.rb +50 -0
  7. data/lib/storefront/form/builder.rb +124 -0
  8. data/lib/storefront/form/errors.rb +20 -46
  9. data/lib/storefront/form/field.rb +102 -0
  10. data/lib/storefront/form/fieldset.rb +44 -0
  11. data/lib/storefront/form/hint.rb +34 -0
  12. data/lib/storefront/form/input.rb +191 -0
  13. data/lib/storefront/form/inputs/checkbox.rb +12 -0
  14. data/lib/storefront/form/inputs/date.rb +16 -0
  15. data/lib/storefront/form/inputs/file.rb +12 -0
  16. data/lib/storefront/form/inputs/hidden.rb +11 -0
  17. data/lib/storefront/form/inputs/radio.rb +11 -0
  18. data/lib/storefront/form/inputs/range.rb +15 -0
  19. data/lib/storefront/form/inputs/select.rb +68 -0
  20. data/lib/storefront/form/inputs/string.rb +89 -0
  21. data/lib/storefront/form/inputs/submit.rb +24 -0
  22. data/lib/storefront/form/inputs/textarea.rb +19 -0
  23. data/lib/storefront/form/inputs/value.rb +16 -0
  24. data/lib/storefront/form/label.rb +35 -0
  25. data/lib/storefront/helpers/attribute_helper.rb +29 -8
  26. data/lib/storefront/helpers/body_helper.rb +1 -1
  27. data/lib/storefront/helpers/cache_helper.rb +2 -2
  28. data/lib/storefront/helpers/component_helper.rb +34 -19
  29. data/lib/storefront/helpers/dashboard_helper.rb +9 -17
  30. data/lib/storefront/helpers/definition_list_helper.rb +82 -14
  31. data/lib/storefront/helpers/form_helper.rb +7 -2
  32. data/lib/storefront/helpers/head_helper.rb +2 -2
  33. data/lib/storefront/helpers/image_helper.rb +1 -25
  34. data/lib/storefront/helpers/list_helper.rb +120 -32
  35. data/lib/storefront/helpers/locale_helper.rb +98 -28
  36. data/lib/storefront/helpers/page_helper.rb +78 -60
  37. data/lib/storefront/helpers/request_helper.rb +3 -0
  38. data/lib/storefront/helpers/table_helper.rb +1 -1
  39. data/lib/storefront/helpers/template_helper.rb +11 -0
  40. data/lib/storefront/helpers/time_helper.rb +2 -2
  41. data/lib/storefront/helpers/widget_helper.rb +153 -2
  42. data/lib/storefront/model_helper.rb +17 -0
  43. data/lib/storefront/proxies/attribute_proxy.rb +150 -0
  44. data/lib/storefront/proxies/model_proxy.rb +249 -0
  45. data/lib/storefront/railtie.rb +4 -2
  46. data/lib/storefront/table.rb +7 -0
  47. data/test/form_helper_test.rb +1 -1
  48. metadata +25 -27
  49. data/init.rb +0 -1
  50. data/lib/storefront/form/elements.rb +0 -101
  51. data/lib/storefront/form/fields.rb +0 -420
  52. data/lib/storefront/form/hints.rb +0 -18
  53. data/lib/storefront/form/inputs.rb +0 -258
  54. data/lib/storefront/form/labels.rb +0 -81
  55. data/lib/storefront/form/model.rb +0 -84
  56. data/lib/storefront/microdata/address.rb +0 -7
  57. data/lib/storefront/microdata/event.rb +0 -13
  58. data/lib/storefront/microdata/geo.rb +0 -7
  59. data/lib/storefront/microdata/organization.rb +0 -7
  60. data/lib/storefront/microdata/person.rb +0 -7
  61. data/lib/storefront/microformat/event.rb +0 -7
  62. data/lib/storefront/microformat/person.rb +0 -7
  63. data/lib/storefront/models/container.rb +0 -0
  64. data/lib/storefront/models/element.rb +0 -15
  65. data/lib/storefront/models/form.rb +0 -0
  66. data/lib/storefront/models/form_element.rb +0 -0
  67. data/lib/storefront/models/link.rb +0 -0
  68. data/lib/storefront/models/list.rb +0 -0
  69. data/lib/storefront/models/list_element.rb +0 -0
  70. data/lib/storefront/models/table.rb +0 -0
  71. data/lib/storefront/models/term.rb +0 -0
  72. data/lib/storefront/models/term_list.rb +0 -0
  73. data/lib/storefront/models/validation.rb +0 -0
@@ -0,0 +1,124 @@
1
+ module Storefront
2
+ class Form
3
+ class Builder < Storefront::Form::Base
4
+ delegate :object, :parent, :to => :model
5
+
6
+ def fieldset(*args, &block)
7
+ options = default_options!(args.extract_options!)
8
+ options[:label] ||= args.shift
9
+
10
+ Storefront::Form::Fieldset.new(options).render(&block)
11
+ end
12
+
13
+ def fields(*args, &block)
14
+ options = args.extract_options!
15
+ options[:as] = :fields
16
+ options[:label] ||= false
17
+ attr_name = args.shift || attribute.name
18
+ template.capture_haml do
19
+ result = field attr_name, options do |_field|
20
+ template.haml_concat fieldset(&block).gsub(/\n$/, "")
21
+ end
22
+ template.haml_concat result.gsub(/\n$/, "")
23
+ end
24
+ end
25
+
26
+ def fields_for(*args, &block)
27
+ options = args.extract_options!
28
+ attribute = args.shift
29
+ macro = model.macro_for(attribute)
30
+ attr_name = nil
31
+
32
+ if options[:as] == :object
33
+ attr_name = attribute.to_s
34
+ else
35
+ attr_name = config.rename_nested_attributes ? "#{attribute}_attributes" : attribute.to_s
36
+ end
37
+
38
+ # do something here for counts
39
+ sub_parent = model.object
40
+ sub_object = args.shift
41
+
42
+ index = options.delete(:index)
43
+
44
+ unless index.present? && index.is_a?(::String)
45
+ if sub_object.blank? && index.present?
46
+ sub_object = sub_parent.send(attribute)[index]
47
+ elsif index.blank? && sub_object.present? && macro == :has_many
48
+ index = sub_parent.send(attribute).index(sub_object)
49
+ end
50
+ end
51
+
52
+ sub_object ||= model.default(attribute) || model.to_s.camelize.constantize.new
53
+ keys = [model.keys, attr_name]
54
+
55
+ model = Storefront::ModelProxy.new(
56
+ :object => sub_object,
57
+ :parent => sub_parent,
58
+ :keys => keys
59
+ )
60
+
61
+ options.merge!(
62
+ :template => template,
63
+ :model => model,
64
+ :parent_index => index,
65
+ :access_keys => access_keys,
66
+ :tabindex => tabindex
67
+ )
68
+ Storefront::Form::Builder.new(options).render(&block)
69
+ end
70
+
71
+ def field(*args, &block)
72
+ options = args.extract_options!
73
+ attribute_name = args.shift || attribute.name
74
+ attribute = Storefront::AttributeProxy.new(
75
+ :name => attribute_name,
76
+ :model => @model,
77
+ :required => options[:required] == true,
78
+ :disabled => options[:disabled] == true,
79
+ :top_level => options[:attribute] == false
80
+ )
81
+
82
+ options.reverse_merge!(
83
+ :template => template,
84
+ :model => model,
85
+ :attribute => attribute,
86
+ :parent_index => parent_index,
87
+ :index => index,
88
+ :field_html => options[:field_html] || {},
89
+ :input_html => options[:input_html] || {},
90
+ :label_html => options[:label_html] || {},
91
+ :error_html => options[:error_html] || {},
92
+ :hint_html => options[:hint_html] || {}
93
+ )
94
+
95
+ Storefront::Form::Field.new(options).render(&block)
96
+ end
97
+
98
+ def button(*args, &block)
99
+ options = args.extract_options!
100
+ options.reverse_merge!(:as => :submit)
101
+ options[:value] = args.shift || "Submit"
102
+ field(options[:value], options, &block)
103
+ end
104
+
105
+ def submit(*args, &block)
106
+ template.capture_haml do
107
+ result = fieldset :class => config.submit_fieldset_class do |fields|
108
+ template.haml_concat fields.button(*args).gsub(/\n$/, "")
109
+ yield(fields) if block_given?
110
+ end
111
+ template.haml_concat result.gsub(/\n$/, "")
112
+ end
113
+ end
114
+
115
+ def partial(path, options = {})
116
+ @template.render :partial => path, :locals => options.merge(:fields => self)
117
+ end
118
+
119
+ def render(&block)
120
+ yield(self)
121
+ end
122
+ end
123
+ end
124
+ end
@@ -1,57 +1,31 @@
1
1
  module Storefront
2
2
  class Form
3
- module Errors
4
- def errors_for(key, options = {})
5
- value = options[:error_attributes].delete(:value)
3
+ class Errors < Storefront::Form::Base
4
+ def initialize(options = {})
5
+ super
6
+
7
+ attributes.merge!(options[:error_html]) if options[:error_html]
8
+ attributes.delete :error_html
9
+ attributes.delete :error
10
+ # error
11
+ merge_class! @attributes, config.error_class
12
+ # aria-invalid = true|grammar|spelling
13
+ # aria-hidden
14
+ attributes[:id] ||= attribute.to_id(:type => :error, :index => index, :parent_index => parent_index) if config.id_enabled_on.include?("error")
15
+ @value = model.errors_for(attribute.name)
16
+ end
17
+
18
+ def render(&block)
6
19
  template.capture_haml do
7
20
  if value.present?
8
- template.haml_tag :output, options[:error_attributes] do
9
- template.haml_concat value.html_safe
21
+ template.haml_tag config.error_tag, attributes do
22
+ template.haml_concat value.join("\n").html_safe.gsub(/\n$/)
10
23
  end
11
- else
12
- template.haml_tag :output, options[:error_attributes]
13
- end
14
- end
15
- end
16
-
17
- def errors_on?(attribute, options = {})
18
-
19
- end
20
-
21
- def required?(attribute)
22
- attribute_sym = attribute.to_s.sub(/_id$/, '').to_sym
23
-
24
- if @object && @object.class.respond_to?(:reflect_on_validations_for)
25
- @object.class.reflect_on_validations_for(attribute_sym).any? do |validation|
26
- (validation.macro == :validates_presence_of || validation.macro == :validates_inclusion_of) &&
27
- validation.name == attribute_sym &&
28
- (validation.options.present? ? options_require_validation?(validation.options) : true)
29
- end
30
- else
31
- if @object && @object.class.respond_to?(:validators_on)
32
- !@object.class.validators_on(attribute_sym).find{|validator| (validator.kind == :presence || validator.kind == :inclusion) && (validator.options.present? ? options_require_validation?(validator.options) : true)}.nil?
33
- else
34
- true
24
+ elsif config.always_include_error_tag
25
+ template.haml_tag config.error_tag, attributes
35
26
  end
36
27
  end
37
28
  end
38
-
39
- def options_require_validation?(options) #nodoc
40
- allow_blank = options[:allow_blank]
41
- return !allow_blank unless allow_blank.nil?
42
- if_condition = !options[:if].nil?
43
- condition = if_condition ? options[:if] : options[:unless]
44
-
45
- condition = if condition.respond_to?(:call)
46
- condition.call(@object)
47
- elsif condition.is_a?(::Symbol) && @object.respond_to?(condition)
48
- @object.send(condition)
49
- else
50
- condition
51
- end
52
-
53
- if_condition ? !!condition : !condition
54
- end
55
29
  end
56
30
  end
57
31
  end
@@ -0,0 +1,102 @@
1
+ module Storefront
2
+ class Form
3
+ # input :name, :as => :string, :class => "string something", :label_method => x, :value_method => y
4
+ # disabled, readonly, accesskey, tabindex
5
+ # button, checkbox, color, date, datetime, datetime-local, email, file, hidden, image, month, number, password, radio, range , reset, search, submit, tel, text, time, url, week
6
+ # input :phone, :mask => /\d\d\d-\d\d\d-\d\d\d\d/, :hint => "Enter your phone number", :tip => "This is so we can call you."
7
+ class Field < Storefront::Form::Builder
8
+ def initialize(options = {})
9
+ super
10
+
11
+ # input type
12
+ options[:as] ||= attribute.input_type(options)
13
+ @input_type = options[:as]
14
+ @inputs = []
15
+
16
+ # class
17
+
18
+ classes = [config.field_class, input_type]
19
+
20
+ unless [:submit, :fieldset].include?(input_type)
21
+ classes += [
22
+ attribute.required? ? config.required_class : config.optional_class,
23
+ attribute.errors? ? config.error_class : config.valid_class,
24
+ ]
25
+ if attribute.validations.present?
26
+ classes << config.validate_class
27
+ end
28
+ end
29
+
30
+ merge_class! attributes, *classes.compact.uniq.map(&:to_s)
31
+
32
+ # id
33
+ if attributes[:id].blank? && config.id_enabled_on.include?("field")
34
+ attributes[:id] = attribute.to_id(:type => :field, :index => index, :parent_index => parent_index)
35
+ end
36
+
37
+ unless [:hidden, :submit].include?(input_type)
38
+ # errors
39
+ @errors = Storefront::Form::Errors.new(options.slice(:error_html, :error, :model, :index, :parent_index, :attribute, :template))
40
+
41
+ # label
42
+ @label = Storefront::Form::Label.new(options.slice(:label_html, :label, :model, :index, :parent_index, :attribute, :template))
43
+
44
+ # hint
45
+ @hints = Storefront::Form::Hint.new(options.slice(:hint_html, :hint, :model, :index, :parent_index, :attribute, :template))
46
+ end
47
+
48
+ unless input_type == :fieldset
49
+ # inputs
50
+ @input_attributes = default_options!.merge(attributes.except(:id, :class, :field_html, :attributes, :error_html, :label_html, :hint_html))
51
+ end
52
+
53
+ merge_class! options[:field_html], attributes[:class]
54
+
55
+ @attributes = options[:field_html].merge(:id => attributes[:id])
56
+ end
57
+
58
+ def input(*args)
59
+ #@tabindex = @tabindex + 1
60
+ options = args.extract_options!
61
+ key = args.shift || attribute.name
62
+ @inputs << input_for(input_type, key, options)
63
+ end
64
+
65
+ def render(&block)
66
+ template.capture_haml do
67
+ template.haml_tag :li, attributes do
68
+ input(attribute.name) unless block_given?
69
+ elements = extract_elements!(attributes)
70
+
71
+ result = elements.map do |element|
72
+ Array(send(element)).map(&:render)
73
+ end
74
+ template.haml_concat result.flatten.join.gsub(/\n$/, "") if result.present?
75
+
76
+ yield(self) if block_given? # template.capture_haml(self, &block)
77
+ end
78
+ end
79
+ end
80
+
81
+ protected
82
+ attr_reader :errors, :labels, :inputs, :hints, :label, :input_type
83
+
84
+ def input_for(key, attribute, options = {})
85
+ Storefront::Form::Input.find(key.to_sym).new(@input_attributes.merge(options))
86
+ end
87
+
88
+ def extract_elements!(options = {})
89
+ elements = []
90
+ if [:hidden, :submit].include?(input_type)
91
+ elements << :inputs
92
+ else
93
+ if @label.present? && @label.value?
94
+ elements << :label
95
+ end
96
+ elements = elements.concat [:inputs, :hints, :errors]
97
+ end
98
+ elements
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,44 @@
1
+ module Storefront
2
+ class Form
3
+ class Fieldset < Storefront::Form::Base
4
+ attr_reader :builder
5
+
6
+ def initialize(options = {})
7
+ super
8
+
9
+ @label = localize(:titles, options[:label], nil, (attributes[:locale_options] || {}).merge(:allow_blank => true)) if options[:label].present?
10
+
11
+ merge_class! attributes, *[
12
+ config.fieldset_class
13
+ ]
14
+
15
+ attributes[:id] ||= label.underscore.strip.gsub(/[_\s]+/, config.separator) if label.present?
16
+ attributes.delete(:index)
17
+ attributes.delete(:parent_index)
18
+ attributes.delete(:label)
19
+
20
+ @builder = Storefront::Form::Builder.new(
21
+ :template => template,
22
+ :model => model,
23
+ :attribute => attribute,
24
+ :index => index,
25
+ :parent_index => parent_index
26
+ )
27
+ end
28
+
29
+ # form.inputs :basic_info, :locale_options => {:count => 1, :past => true}
30
+ def render(&block)
31
+ template.capture_haml do
32
+ template.haml_tag :fieldset, attributes do
33
+ template.haml_tag :legend, :class => config.legend_class do
34
+ template.haml_tag :span, label
35
+ end if label.present?
36
+ template.haml_tag config.field_list_tag, :class => config.list_class do
37
+ builder.render(&block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ module Storefront
2
+ class Form
3
+ class Hint < Storefront::Form::Base
4
+ def initialize(options = {})
5
+ super
6
+
7
+ attributes.merge!(options[:hint_html]) if options[:hint_html]
8
+ attributes.delete :hint_html
9
+ attributes.delete :hint
10
+
11
+ unless options[:hint] == false
12
+ merge_class! attributes, config.hint_class
13
+ attributes[:id] ||= attribute.to_id(:type => :hint, :index => index, :parent_index => parent_index) if config.id_enabled_on.include?("hint")
14
+ if config.include_aria && config.hint_is_popup
15
+ attributes[:role] ||= :tooltip
16
+ end
17
+ @value = localize(:hints, attribute.name, options[:hint].is_a?(::String) ? options[:hint] : nil, :allow_blank => true)
18
+ end
19
+ end
20
+
21
+ def render(&block)
22
+ template.capture_haml do
23
+ if value.present?
24
+ template.haml_tag config.hint_tag, attributes do
25
+ template.haml_concat value.html_safe.gsub(/\n$/, "")
26
+ end
27
+ elsif config.always_include_hint_tag
28
+ template.haml_tag config.hint_tag, attributes
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,191 @@
1
+ module Storefront
2
+ class Form
3
+ class Input < Storefront::Form::Base
4
+ class << self
5
+ attr_accessor :resolves
6
+
7
+ def resolves(*input_types)
8
+ @resolves ||= []
9
+ @resolves = @resolves.concat(input_types.flatten.compact).uniq
10
+ end
11
+
12
+ def resolves?(name)
13
+ @resolves ||= []
14
+ @resolves.include?(name)
15
+ end
16
+
17
+ def registry
18
+ @registry ||= Dir[::File.join(::File.dirname(__FILE__), "inputs", "*")].map do |path|
19
+ next unless ::File.extname(path) == ".rb"
20
+ "Storefront::Form::#{::File.basename(path, ::File.extname(path)).camelize}".constantize
21
+ end.compact
22
+ end
23
+
24
+ def find(name)
25
+ registry.detect do |input_class|
26
+ input_class.resolves?(name)
27
+ end
28
+ end
29
+ end
30
+
31
+ def initialize(options = {})
32
+ super
33
+
34
+ # input type
35
+ options[:as] ||= attribute.input_type(options)
36
+ @input_type = options[:as]
37
+ @include_blank = options[:include_blank] != false
38
+ @value = options[:value]
39
+ @dynamic = options[:dynamic] == true
40
+
41
+ classes = [input_type, self.class.name.split("::").last.underscore, attribute.name.to_s.underscore.strip.gsub(/[_\s]+/, config.separator)]
42
+
43
+ if options[:input_html].present?
44
+ classes << options[:input_html].delete(:class)
45
+ end
46
+
47
+ unless [:submit].include?(input_type)
48
+ classes += [
49
+ attribute.required? ? config.required_class : config.optional_class,
50
+ attribute.errors? ? config.error_class : config.valid_class,
51
+ "input"
52
+ ]
53
+
54
+ if attribute.validations.present?
55
+ classes << config.validate_class
56
+ end
57
+ end
58
+
59
+ # class
60
+ merge_class! attributes, *classes.compact.uniq.map(&:to_s)
61
+
62
+ # id
63
+ attributes[:id] ||= attribute.to_id(:index => index, :parent_index => parent_index)
64
+
65
+ # validations
66
+ attributes.merge!(attribute.validations) if config.inline_validations && attribute.validations.present?
67
+ attributes[:placeholder] = options[:placeholder] if options[:placeholder].present?
68
+
69
+ # name
70
+ attributes[:name] ||= attribute.to_param(:index => index, :parent_index => parent_index)
71
+
72
+ # value
73
+ attributes[:value] ||= attribute.value(options[:value])
74
+
75
+ # attributes[:tabindex] = @tabindex
76
+ attributes[:maxlength] = options[:max] if options[:max].present?
77
+
78
+ # expressions
79
+ pattern = options[:match]
80
+ pattern = pattern.source if pattern.is_a?(::Regexp)
81
+ attributes[:"data-match"] = pattern if pattern.present?
82
+ attributes[:"aria-required"] = attribute.required.to_s if attribute.required?
83
+
84
+ # access key
85
+ access_key = attributes[:accesskey] || attribute.access_key
86
+ attributes[:accesskey] = access_key
87
+
88
+ attributes.merge!(options[:input_html]) if options[:input_html]
89
+
90
+ attributes.delete :include_blank
91
+ attributes.delete :input_html
92
+ attributes.delete :include_template
93
+ attributes.delete :as
94
+ attributes.delete :dynamic
95
+ attributes.delete :max
96
+ attributes.delete :min
97
+ attributes.delete :parent_index
98
+
99
+ attributes[:required] = "true" if attributes.delete(:required) == true
100
+ attributes[:disabled] = "true" if attributes.delete(:disabled) == true
101
+ attributes[:autofocus] = "true" if attributes.delete(:autofocus) == true
102
+ attributes[:"data-dynamic"] = "true" if @dynamic
103
+
104
+ attributes[:title] ||= attributes[:placeholder] if attributes[:placeholder].present?
105
+
106
+ autocomplete = attributes.delete(:autocomplete)
107
+ if autocomplete && config.include_aria
108
+ attributes[:"aria-autocomplete"] = case autocomplete
109
+ when :inline, :list, :both
110
+ autocomplete.to_s
111
+ else
112
+ "both"
113
+ end
114
+ end
115
+ end
116
+
117
+ def render(&block)
118
+ send(:"#{@input_type}_input")
119
+ end
120
+
121
+ protected
122
+ attr_reader :include_blank
123
+
124
+ def simple_input(type, options = {}, &block)
125
+ template.capture_haml do
126
+ template.haml_tag :input, extract_attributes!(type, options), &block
127
+ if @dynamic
128
+ template.haml_tag :ul, :class => "buttons" do
129
+ template.haml_tag :li do
130
+ template.haml_tag :a, config.add_label, :class => :add, :role => :button, :type => :button, :href => "#"
131
+ end
132
+ template.haml_tag :li do
133
+ template.haml_tag :a, config.remove_label, :class => :remove, :role => :button, :type => :button, :href => "#"
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ def rich_input(type, options = {}, &block)
141
+ template.capture_haml do
142
+ result = template.rich_button :inner_html => extract_attributes!(type, options), :as => :input
143
+ template.haml_concat result.gsub(/\n$/, "") if result
144
+ end
145
+ end
146
+
147
+ def extract_attributes!(type, options = {})
148
+ if [:numeric, :string, :password, :text, :phone, :url, :email].include?(type)
149
+ attributes = model.default_string_options(attribute.name, type).merge(self.attributes)
150
+ else
151
+ attributes = self.attributes
152
+ end
153
+
154
+ merge_class! attributes, options.delete(:class)
155
+
156
+ attributes[:type] = input_type_for(type)
157
+
158
+ attributes.merge(options)
159
+ end
160
+
161
+ def base_input(tag, *args, &block)
162
+ options = args.extract_options!
163
+ attributes = self.attributes
164
+ text = args.shift
165
+
166
+ template.capture_haml do
167
+ if block_given?
168
+ template.haml_tag tag, attributes, &block
169
+ else
170
+ if text.present?
171
+ template.haml_tag tag, text, attributes
172
+ else
173
+ template.haml_tag tag, attributes
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ def input_type_for(type)
180
+ case type
181
+ when :password, :text, :url, :email, :file, :textarea, :search, :submit, :radio, :checkbox
182
+ type
183
+ when :phone, :tel
184
+ :tel
185
+ else
186
+ :string
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end