formtastic-bootstrap 1.0.0

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 (72) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +12 -0
  4. data/Gemfile.lock +123 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +159 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/formtastic-bootstrap.gemspec +128 -0
  10. data/lib/action_view/helpers/text_field_date_helper.rb +166 -0
  11. data/lib/formtastic-bootstrap.rb +5 -0
  12. data/lib/formtastic-bootstrap/form_builder.rb +38 -0
  13. data/lib/formtastic-bootstrap/helpers.rb +19 -0
  14. data/lib/formtastic-bootstrap/helpers/buttons_helper.rb +47 -0
  15. data/lib/formtastic-bootstrap/helpers/fieldset_wrapper.rb +37 -0
  16. data/lib/formtastic-bootstrap/helpers/input_helper.rb +12 -0
  17. data/lib/formtastic-bootstrap/helpers/inputs_helper.rb +36 -0
  18. data/lib/formtastic-bootstrap/inputs.rb +28 -0
  19. data/lib/formtastic-bootstrap/inputs/base.rb +22 -0
  20. data/lib/formtastic-bootstrap/inputs/base/choices.rb +49 -0
  21. data/lib/formtastic-bootstrap/inputs/base/errors.rb +48 -0
  22. data/lib/formtastic-bootstrap/inputs/base/hints.rb +27 -0
  23. data/lib/formtastic-bootstrap/inputs/base/html.rb +21 -0
  24. data/lib/formtastic-bootstrap/inputs/base/labelling.rb +18 -0
  25. data/lib/formtastic-bootstrap/inputs/base/stringish.rb +18 -0
  26. data/lib/formtastic-bootstrap/inputs/base/timeish.rb +35 -0
  27. data/lib/formtastic-bootstrap/inputs/base/wrapping.rb +56 -0
  28. data/lib/formtastic-bootstrap/inputs/boolean_input.rb +33 -0
  29. data/lib/formtastic-bootstrap/inputs/check_boxes_input.rb +35 -0
  30. data/lib/formtastic-bootstrap/inputs/date_input.rb +16 -0
  31. data/lib/formtastic-bootstrap/inputs/datetime_input.rb +19 -0
  32. data/lib/formtastic-bootstrap/inputs/email_input.rb +15 -0
  33. data/lib/formtastic-bootstrap/inputs/file_input.rb +14 -0
  34. data/lib/formtastic-bootstrap/inputs/hidden_input.rb +12 -0
  35. data/lib/formtastic-bootstrap/inputs/number_input.rb +15 -0
  36. data/lib/formtastic-bootstrap/inputs/password_input.rb +15 -0
  37. data/lib/formtastic-bootstrap/inputs/phone_input.rb +15 -0
  38. data/lib/formtastic-bootstrap/inputs/radio_input.rb +32 -0
  39. data/lib/formtastic-bootstrap/inputs/range_input.rb +15 -0
  40. data/lib/formtastic-bootstrap/inputs/search_input.rb +15 -0
  41. data/lib/formtastic-bootstrap/inputs/select_input.rb +14 -0
  42. data/lib/formtastic-bootstrap/inputs/string_input.rb +15 -0
  43. data/lib/formtastic-bootstrap/inputs/text_input.rb +14 -0
  44. data/lib/formtastic-bootstrap/inputs/time_input.rb +16 -0
  45. data/lib/formtastic-bootstrap/inputs/url_input.rb +14 -0
  46. data/spec/builder/errors_spec.rb +214 -0
  47. data/spec/builder/semantic_fields_for_spec.rb +130 -0
  48. data/spec/helpers/input_helper_spec.rb +956 -0
  49. data/spec/helpers/inputs_helper_spec.rb +577 -0
  50. data/spec/inputs/boolean_input_spec.rb +193 -0
  51. data/spec/inputs/check_boxes_input_spec.rb +439 -0
  52. data/spec/inputs/date_input_spec.rb +147 -0
  53. data/spec/inputs/datetime_input_spec.rb +101 -0
  54. data/spec/inputs/email_input_spec.rb +59 -0
  55. data/spec/inputs/file_input_spec.rb +63 -0
  56. data/spec/inputs/hidden_input_spec.rb +122 -0
  57. data/spec/inputs/number_input_spec.rb +787 -0
  58. data/spec/inputs/password_input_spec.rb +73 -0
  59. data/spec/inputs/phone_input_spec.rb +59 -0
  60. data/spec/inputs/radio_input_spec.rb +240 -0
  61. data/spec/inputs/range_input_spec.rb +479 -0
  62. data/spec/inputs/search_input_spec.rb +59 -0
  63. data/spec/inputs/select_input_spec.rb +567 -0
  64. data/spec/inputs/string_input_spec.rb +182 -0
  65. data/spec/inputs/text_input_spec.rb +163 -0
  66. data/spec/inputs/time_input_spec.rb +206 -0
  67. data/spec/inputs/url_input_spec.rb +59 -0
  68. data/spec/spec_helper.rb +24 -0
  69. data/spec/support/custom_macros.rb +704 -0
  70. data/spec/support/depracation.rb +6 -0
  71. data/spec/support/formtastic_spec_helper.rb +382 -0
  72. metadata +204 -0
@@ -0,0 +1,166 @@
1
+ require 'action_view/helpers/form_tag_helper'
2
+
3
+ module ActionView
4
+ module Helpers
5
+
6
+ module TextFieldDateHelper
7
+
8
+ # These two handle an object with a method that returns a Date or Time object.
9
+ def date_text_field(object_name, method, options = {}, html_options = {})
10
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_date_text_field_tag(options, html_options)
11
+ end
12
+
13
+ def time_text_field(object_name, method, options = {}, html_options = {})
14
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_time_text_field_tag(options, html_options)
15
+ end
16
+
17
+ # These two handle Date and Time objects.
18
+ def text_field_date(date = Date.current, options = {}, html_options = {})
19
+ DateTimeSelector.new(date, options, html_options).text_field_date
20
+ end
21
+
22
+ def text_field_time(time = Time.current, options = {}, html_options = {})
23
+ DateTimeSelector.new(time, options, html_options).text_field_time
24
+ end
25
+ end
26
+
27
+ class DateTimeSelector
28
+
29
+ include ActionView::Helpers::FormTagHelper
30
+
31
+ def text_field_date
32
+ order = date_order.dup
33
+
34
+ @options[:discard_hour] = true
35
+ @options[:discard_minute] = true
36
+ @options[:discard_second] = true
37
+
38
+ @options[:discard_year] ||= true unless order.include?(:year)
39
+ @options[:discard_month] ||= true unless order.include?(:month)
40
+ @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
41
+
42
+ # Save this so we can restore it.
43
+ original_datetime_separator_separator = @options[:datetime_separator]
44
+ original_date_separator = @options[:date_separator]
45
+
46
+ @options[:datetime_separator] = ""
47
+ @options[:date_separator] = " "
48
+
49
+ # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
50
+ # valid (otherwise it could be 31 and February wouldn't be a valid date)
51
+ if @datetime && @options[:discard_day] && !@options[:discard_month]
52
+ @datetime = @datetime.change(:day => 1)
53
+ end
54
+
55
+ [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
56
+
57
+ build_text_field_from_types(order).tap do
58
+ # Restore.
59
+ @options[:datetime_separator] = original_datetime_separator_separator
60
+ @options[:date_separator] = original_date_separator
61
+ end
62
+ end
63
+
64
+ def text_field_time
65
+ order = []
66
+
67
+ @options[:discard_month] = true
68
+ @options[:discard_year] = true
69
+ @options[:discard_day] = true
70
+ @options[:discard_second] ||= true unless @options[:include_seconds]
71
+
72
+ # Save this so we can restore it.
73
+ original_datetime_separator = @options[:datetime_separator]
74
+ original_time_separator = @options[:time_separator]
75
+ original_date_separator = @options[:date_separator]
76
+
77
+ @options[:datetime_separator] = ''
78
+ @options[:time_separator] = ':'
79
+ @options[:date_separator] = " "
80
+
81
+ order += [:year, :month, :day] unless @options[:ignore_date]
82
+
83
+ order += [:hour, :minute]
84
+ order << :second if @options[:include_seconds]
85
+
86
+ build_text_field_from_types(order).tap do
87
+ # Restore.
88
+ @options[:datetime_separator] = original_datetime_separator
89
+ @options[:date_separator] = original_date_separator
90
+ @options[:time_separator] = original_time_separator
91
+ end
92
+ end
93
+
94
+ def text_field_second
95
+ unless @options[:use_hidden] || @options[:discard_second]
96
+ build_text(:second, sec)
97
+ end
98
+ end
99
+
100
+ def text_field_minute
101
+ unless @options[:use_hidden] || @options[:discard_minute]
102
+ build_text(:minute, min)
103
+ end
104
+ end
105
+
106
+ def text_field_hour
107
+ unless @options[:use_hidden] || @options[:discard_hour]
108
+ build_text(:hour, hour, :ampm => @options[:ampm])
109
+ end
110
+ end
111
+
112
+ def text_field_day
113
+ unless @options[:use_hidden] || @options[:discard_day]
114
+ build_text(:day, day, :leading_zeros => false)
115
+ end
116
+ end
117
+
118
+ def text_field_month
119
+ unless @options[:use_hidden] || @options[:discard_month]
120
+ build_text(:month, month.nil? ? "" : month_name(month), :leading_zeros => false)
121
+ end
122
+ end
123
+
124
+ def text_field_year
125
+ unless @options[:use_hidden] || @options[:discard_year]
126
+ build_text(:year, year, :leading_zeros => false)
127
+ end
128
+ end
129
+
130
+ def build_text_field_from_types(order)
131
+ input = ''
132
+ order.reverse.each do |type|
133
+ separator = separator(type) unless type == order.first # don't add on last field
134
+ input.insert(0, separator.to_s + send("text_field_#{type}").to_s)
135
+ end
136
+ text_field_tag("", input.html_safe, @html_options).html_safe
137
+ end
138
+
139
+ def build_text(selected, value, options = {})
140
+ unless value.nil?
141
+ options.reverse_merge!({:leading_zeros => true, :ampm => false})
142
+ leading_zeros = options.delete(:leading_zeros)
143
+ value = leading_zeros ? sprintf("%02d", value) : value
144
+ text = options[:ampm] ? AMPM_TRANSLATION[value] : value
145
+ else
146
+ ""
147
+ end
148
+ end
149
+
150
+ end
151
+
152
+ class InstanceTag #:nodoc:
153
+ def to_date_text_field_tag(options = {}, html_options = {})
154
+ datetime_selector(options, html_options).text_field_date.html_safe
155
+ end
156
+
157
+ def to_time_text_field_tag(options = {}, html_options = {})
158
+ datetime_selector(options, html_options).text_field_time.html_safe
159
+ end
160
+ end
161
+
162
+ autoload :TextFieldDateHelper
163
+ include TextFieldDateHelper
164
+
165
+ end
166
+ end
@@ -0,0 +1,5 @@
1
+ require "formtastic"
2
+ require "formtastic-bootstrap/helpers"
3
+ require "formtastic-bootstrap/inputs"
4
+ require "formtastic-bootstrap/form_builder"
5
+ require "action_view/helpers/text_field_date_helper"
@@ -0,0 +1,38 @@
1
+ module FormtasticBootstrap
2
+
3
+ class FormBuilder < Formtastic::FormBuilder
4
+
5
+ configure :default_inline_error_class, 'help-inline'
6
+ configure :default_block_error_class, 'help-block'
7
+ configure :default_inline_hint_class, 'help-inline'
8
+ configure :default_block_hint_class, 'help-block'
9
+
10
+ def self.default_error_class
11
+ # self.default_inline_error_class
12
+ raise
13
+ end
14
+
15
+ def self.default_error_class=(error_class)
16
+ # self.default_inline_error_class = error_class
17
+ # self.default_block_error_class = error_class
18
+ raise
19
+ end
20
+
21
+ def self.default_hint_class
22
+ # self.default_inline_hint_class
23
+ raise
24
+ end
25
+
26
+ def self.default_hint_class=(hint_class)
27
+ # self.default_inline_hint_class = hint_class
28
+ # self.default_block_hint_class = hint_class
29
+ raise
30
+ end
31
+
32
+ include FormtasticBootstrap::Helpers::InputHelper
33
+ include FormtasticBootstrap::Helpers::InputsHelper
34
+ include FormtasticBootstrap::Helpers::ButtonsHelper
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,19 @@
1
+ require "formtastic-bootstrap/helpers/buttons_helper"
2
+ require "formtastic-bootstrap/helpers/fieldset_wrapper"
3
+ require "formtastic-bootstrap/helpers/input_helper"
4
+ require "formtastic-bootstrap/helpers/inputs_helper"
5
+
6
+ module FormtasticBootstrap
7
+ module Helpers
8
+ # autoload :ErrorsHelper, 'formtastic/helpers/errors_helper'
9
+ # autoload :FieldsetWrapper, 'formtastic/helpers/fieldset_wrapper'
10
+ # autoload :FileColumnDetection, 'formtastic/helpers/file_column_detection'
11
+ # autoload :FormHelper, 'formtastic/helpers/form_helper'
12
+ # autoload :InputHelper, 'formtastic/helpers/input_helper'
13
+ # autoload :InputsHelper, 'formtastic/helpers/inputs_helper'
14
+ # autoload :LabelHelper, 'formtastic/helpers/label_helper'
15
+ # autoload :SemanticFormHelper, 'formtastic/helpers/semantic_form_helper'
16
+ # autoload :Reflection, 'formtastic/helpers/reflection'
17
+ end
18
+ end
19
+
@@ -0,0 +1,47 @@
1
+ module FormtasticBootstrap
2
+ module Helpers
3
+ module ButtonsHelper
4
+
5
+ include Formtastic::Helpers::ButtonsHelper
6
+
7
+ def buttons(*args, &block)
8
+ html_options = args.extract_options!
9
+ html_options[:class] ||= "actions"
10
+
11
+ if block_given?
12
+ template.content_tag(:div, html_options) do
13
+ yield
14
+ end
15
+ else
16
+ args = [:commit] if args.empty?
17
+ contents = args.map { |button_name| send(:"#{button_name}_button") }
18
+ template.content_tag(:div, html_options.except(:builder, :parent, :name)) do
19
+ Formtastic::Util.html_safe(contents)
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ def commit_button(*args)
26
+ options = args.extract_options!
27
+ text = options.delete(:label) || args.shift
28
+
29
+ text = (localized_string(commit_button_i18n_key, text, :action, :model => commit_button_object_name) ||
30
+ Formtastic::I18n.t(commit_button_i18n_key, :model => commit_button_object_name)) unless text.is_a?(::String)
31
+
32
+ button_html = options.delete(:button_html) || {}
33
+ button_html.merge!(:class => [button_html[:class], "btn", commit_button_i18n_key].compact.join(' '))
34
+
35
+ # TODO We don't have a wrapper. Add deprecation message.
36
+ # wrapper_html = options.delete(:wrapper_html) || {}
37
+ # wrapper_html[:class] = (commit_button_wrapper_html_class << wrapper_html[:class]).flatten.compact.join(' ')
38
+
39
+ accesskey = (options.delete(:accesskey) || default_commit_button_accesskey) unless button_html.has_key?(:accesskey)
40
+ button_html = button_html.merge(:accesskey => accesskey) if accesskey
41
+
42
+ Formtastic::Util.html_safe(submit(text, button_html))
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,37 @@
1
+ module FormtasticBootstrap
2
+ module Helpers
3
+ module FieldsetWrapper
4
+
5
+ include Formtastic::Helpers::FieldsetWrapper
6
+
7
+ protected
8
+
9
+ def field_set_and_list_wrapping(*args, &block) #:nodoc:
10
+ contents = args.last.is_a?(::Hash) ? '' : args.pop.flatten
11
+ html_options = args.extract_options!
12
+
13
+ legend = (html_options[:name] || '').to_s
14
+ legend %= parent_child_index(html_options[:parent]) if html_options[:parent]
15
+ legend = template.content_tag(:legend, Formtastic::Util.html_safe(legend)) unless legend.blank?
16
+
17
+ if block_given?
18
+ contents = if template.respond_to?(:is_haml?) && template.is_haml?
19
+ template.capture_haml(&block)
20
+ else
21
+ template.capture(&block)
22
+ end
23
+ end
24
+
25
+ # Ruby 1.9: String#to_s behavior changed, need to make an explicit join.
26
+ contents = contents.join if contents.respond_to?(:join)
27
+ fieldset = template.content_tag(:fieldset,
28
+ Formtastic::Util.html_safe(legend) << Formtastic::Util.html_safe(contents),
29
+ html_options.except(:builder, :parent, :name)
30
+ )
31
+
32
+ fieldset
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ module FormtasticBootstrap
2
+ module Helpers
3
+ module InputHelper
4
+ include Formtastic::Helpers::InputHelper
5
+
6
+ def standard_input_class_name(as)
7
+ "FormtasticBootstrap::Inputs::#{as.to_s.camelize}Input"
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ module FormtasticBootstrap
2
+ module Helpers
3
+ module InputsHelper
4
+ include FormtasticBootstrap::Helpers::FieldsetWrapper
5
+
6
+ def inputs(*args, &block)
7
+ wrap_it = @already_in_an_inputs_block ? true : false
8
+ @already_in_an_inputs_block = true
9
+
10
+ title = field_set_title_from_args(*args)
11
+ html_options = args.extract_options!
12
+ html_options[:class] ||= "inputs"
13
+ html_options[:name] = title
14
+
15
+ out = begin
16
+ if html_options[:for] # Nested form
17
+ inputs_for_nested_attributes(*(args << html_options), &block)
18
+ elsif block_given?
19
+ field_set_and_list_wrapping(*(args << html_options), &block)
20
+ else
21
+ legend = args.shift if args.first.is_a?(::String)
22
+ args = default_columns_for_object if @object && args.empty?
23
+ contents = fieldset_contents_from_column_list(args)
24
+ args.unshift(legend) if legend.present?
25
+ field_set_and_list_wrapping(*((args << html_options) << contents))
26
+ end
27
+ end
28
+
29
+ # out = template.content_tag(:li, out, :class => "input") if wrap_it
30
+ @already_in_an_inputs_block = false
31
+ out
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ require "formtastic-bootstrap/inputs/base"
2
+ require "formtastic-bootstrap/inputs/boolean_input"
3
+ require "formtastic-bootstrap/inputs/check_boxes_input"
4
+ require "formtastic-bootstrap/inputs/date_input"
5
+ require "formtastic-bootstrap/inputs/datetime_input"
6
+ require "formtastic-bootstrap/inputs/email_input"
7
+ require "formtastic-bootstrap/inputs/file_input"
8
+ require "formtastic-bootstrap/inputs/hidden_input"
9
+ require "formtastic-bootstrap/inputs/number_input"
10
+ require "formtastic-bootstrap/inputs/password_input"
11
+ require "formtastic-bootstrap/inputs/phone_input"
12
+ require "formtastic-bootstrap/inputs/radio_input"
13
+ require "formtastic-bootstrap/inputs/range_input"
14
+ require "formtastic-bootstrap/inputs/search_input"
15
+ require "formtastic-bootstrap/inputs/select_input"
16
+ require "formtastic-bootstrap/inputs/string_input"
17
+ require "formtastic-bootstrap/inputs/text_input"
18
+ require "formtastic-bootstrap/inputs/time_input"
19
+ require "formtastic-bootstrap/inputs/url_input"
20
+
21
+ module FormtasticBootstrap
22
+ module Inputs
23
+
24
+ include Base
25
+
26
+ end
27
+ end
28
+
@@ -0,0 +1,22 @@
1
+ require "formtastic-bootstrap/inputs/base/choices"
2
+ require "formtastic-bootstrap/inputs/base/errors"
3
+ require "formtastic-bootstrap/inputs/base/hints"
4
+ require "formtastic-bootstrap/inputs/base/html"
5
+ require "formtastic-bootstrap/inputs/base/labelling"
6
+ require "formtastic-bootstrap/inputs/base/stringish"
7
+ require "formtastic-bootstrap/inputs/base/timeish"
8
+ require "formtastic-bootstrap/inputs/base/wrapping"
9
+
10
+ module FormtasticBootstrap
11
+ module Inputs
12
+ module Base
13
+
14
+ include Errors
15
+ include Hints
16
+ include Html
17
+ include Labelling
18
+ include Wrapping
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ module FormtasticBootstrap
2
+ module Inputs
3
+ module Base
4
+ module Choices
5
+
6
+ def input_div_wrapping(&block)
7
+ template.content_tag(:div, choices_wrapping_html_options) do
8
+ [yield, error_html(:block), hint_html(:block)].join("\n").html_safe
9
+ end
10
+ end
11
+
12
+ def choices_wrapping_html_options
13
+ # TODO Call the Formtastic one explicity and append?
14
+ { :class => "choices input" }
15
+ end
16
+
17
+ def choices_group_wrapping(&block)
18
+ template.content_tag(:ul,
19
+ template.capture(&block),
20
+ choices_group_wrapping_html_options
21
+ )
22
+ end
23
+
24
+ def choices_group_wrapping_html_options
25
+ { :class => "choices-group inputs-list" }
26
+ end
27
+
28
+ def choice_label(choice)
29
+ "\n".html_safe + template.content_tag(:span) do
30
+ # (choice.is_a?(Array) ? choice.first : choice).to_s
31
+ (choice.is_a?(Array) ? choice.first : choice).to_s
32
+ end
33
+ end
34
+
35
+ # This is actually a label in Bootstrap.
36
+ def legend_html
37
+ template.content_tag(:label, label_html_options) do
38
+ render_label? ? label_text : "".html_safe
39
+ end
40
+ end
41
+
42
+ def label_html_options
43
+ super.merge(:for => nil)
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+ end