formtastic 1.2.4 → 3.1.5

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 (189) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +46 -0
  5. data/.yardopts +1 -0
  6. data/Appraisals +43 -0
  7. data/CHANGELOG +54 -0
  8. data/DEPRECATIONS +52 -0
  9. data/Gemfile +3 -0
  10. data/README.md +629 -0
  11. data/RELEASE_PROCESS +6 -0
  12. data/Rakefile +35 -0
  13. data/app/assets/stylesheets/formtastic.css +289 -0
  14. data/app/assets/stylesheets/formtastic_ie6.css +33 -0
  15. data/app/assets/stylesheets/formtastic_ie7.css +23 -0
  16. data/formtastic.gemspec +42 -0
  17. data/gemfiles/rails_3.2.gemfile +9 -0
  18. data/gemfiles/rails_4.0.4.gemfile +8 -0
  19. data/gemfiles/rails_4.1.gemfile +8 -0
  20. data/gemfiles/rails_4.2.gemfile +8 -0
  21. data/gemfiles/rails_4.gemfile +8 -0
  22. data/gemfiles/rails_5.0.gemfile +8 -0
  23. data/gemfiles/rails_edge.gemfile +15 -0
  24. data/lib/formtastic.rb +40 -1945
  25. data/lib/formtastic/action_class_finder.rb +18 -0
  26. data/lib/formtastic/actions.rb +11 -0
  27. data/lib/formtastic/actions/base.rb +156 -0
  28. data/lib/formtastic/actions/button_action.rb +67 -0
  29. data/lib/formtastic/actions/buttonish.rb +17 -0
  30. data/lib/formtastic/actions/input_action.rb +70 -0
  31. data/lib/formtastic/actions/link_action.rb +88 -0
  32. data/lib/formtastic/deprecation.rb +42 -0
  33. data/lib/formtastic/engine.rb +11 -0
  34. data/lib/formtastic/form_builder.rb +124 -0
  35. data/lib/formtastic/helpers.rb +16 -0
  36. data/lib/formtastic/helpers/action_helper.rb +162 -0
  37. data/lib/formtastic/helpers/actions_helper.rb +168 -0
  38. data/lib/formtastic/helpers/enum.rb +13 -0
  39. data/lib/formtastic/helpers/errors_helper.rb +81 -0
  40. data/lib/formtastic/helpers/fieldset_wrapper.rb +80 -0
  41. data/lib/formtastic/helpers/file_column_detection.rb +16 -0
  42. data/lib/formtastic/helpers/form_helper.rb +203 -0
  43. data/lib/formtastic/helpers/input_helper.rb +407 -0
  44. data/lib/formtastic/helpers/inputs_helper.rb +411 -0
  45. data/lib/formtastic/helpers/reflection.rb +37 -0
  46. data/lib/formtastic/html_attributes.rb +32 -0
  47. data/lib/formtastic/i18n.rb +4 -2
  48. data/lib/formtastic/input_class_finder.rb +18 -0
  49. data/lib/formtastic/inputs.rb +39 -0
  50. data/lib/formtastic/inputs/base.rb +76 -0
  51. data/lib/formtastic/inputs/base/associations.rb +31 -0
  52. data/lib/formtastic/inputs/base/choices.rb +108 -0
  53. data/lib/formtastic/inputs/base/collections.rb +159 -0
  54. data/lib/formtastic/inputs/base/database.rb +22 -0
  55. data/lib/formtastic/inputs/base/datetime_pickerish.rb +85 -0
  56. data/lib/formtastic/inputs/base/errors.rb +58 -0
  57. data/lib/formtastic/inputs/base/fileish.rb +23 -0
  58. data/lib/formtastic/inputs/base/hints.rb +31 -0
  59. data/lib/formtastic/inputs/base/html.rb +53 -0
  60. data/lib/formtastic/inputs/base/labelling.rb +52 -0
  61. data/lib/formtastic/inputs/base/naming.rb +42 -0
  62. data/lib/formtastic/inputs/base/numeric.rb +50 -0
  63. data/lib/formtastic/inputs/base/options.rb +17 -0
  64. data/lib/formtastic/inputs/base/placeholder.rb +17 -0
  65. data/lib/formtastic/inputs/base/stringish.rb +38 -0
  66. data/lib/formtastic/inputs/base/timeish.rb +241 -0
  67. data/lib/formtastic/inputs/base/validations.rb +215 -0
  68. data/lib/formtastic/inputs/base/wrapping.rb +50 -0
  69. data/lib/formtastic/inputs/boolean_input.rb +118 -0
  70. data/lib/formtastic/inputs/check_boxes_input.rb +197 -0
  71. data/lib/formtastic/inputs/color_input.rb +42 -0
  72. data/lib/formtastic/inputs/country_input.rb +86 -0
  73. data/lib/formtastic/inputs/datalist_input.rb +41 -0
  74. data/lib/formtastic/inputs/date_picker_input.rb +93 -0
  75. data/lib/formtastic/inputs/date_select_input.rb +34 -0
  76. data/lib/formtastic/inputs/datetime_picker_input.rb +103 -0
  77. data/lib/formtastic/inputs/datetime_select_input.rb +12 -0
  78. data/lib/formtastic/inputs/email_input.rb +41 -0
  79. data/lib/formtastic/inputs/file_input.rb +42 -0
  80. data/lib/formtastic/inputs/hidden_input.rb +62 -0
  81. data/lib/formtastic/inputs/number_input.rb +88 -0
  82. data/lib/formtastic/inputs/password_input.rb +41 -0
  83. data/lib/formtastic/inputs/phone_input.rb +42 -0
  84. data/lib/formtastic/inputs/radio_input.rb +163 -0
  85. data/lib/formtastic/inputs/range_input.rb +95 -0
  86. data/lib/formtastic/inputs/search_input.rb +41 -0
  87. data/lib/formtastic/inputs/select_input.rb +235 -0
  88. data/lib/formtastic/inputs/string_input.rb +36 -0
  89. data/lib/formtastic/inputs/text_input.rb +48 -0
  90. data/lib/formtastic/inputs/time_picker_input.rb +99 -0
  91. data/lib/formtastic/inputs/time_select_input.rb +38 -0
  92. data/lib/formtastic/inputs/time_zone_input.rb +58 -0
  93. data/lib/formtastic/inputs/url_input.rb +41 -0
  94. data/lib/formtastic/localized_string.rb +17 -0
  95. data/lib/formtastic/localizer.rb +152 -0
  96. data/lib/formtastic/namespaced_class_finder.rb +99 -0
  97. data/lib/formtastic/util.rb +35 -16
  98. data/lib/formtastic/version.rb +3 -0
  99. data/lib/generators/formtastic/form/form_generator.rb +64 -37
  100. data/lib/generators/formtastic/input/input_generator.rb +46 -0
  101. data/lib/generators/formtastic/install/install_generator.rb +13 -5
  102. data/lib/generators/templates/_form.html.erb +10 -4
  103. data/lib/generators/templates/_form.html.haml +8 -4
  104. data/lib/generators/templates/_form.html.slim +8 -0
  105. data/lib/generators/templates/formtastic.rb +77 -44
  106. data/lib/generators/templates/input.rb +19 -0
  107. data/lib/locale/en.yml +3 -0
  108. data/sample/basic_inputs.html +224 -0
  109. data/sample/config.ru +69 -0
  110. data/sample/index.html +14 -0
  111. data/spec/action_class_finder_spec.rb +12 -0
  112. data/spec/actions/button_action_spec.rb +63 -0
  113. data/spec/actions/generic_action_spec.rb +521 -0
  114. data/spec/actions/input_action_spec.rb +59 -0
  115. data/spec/actions/link_action_spec.rb +92 -0
  116. data/spec/builder/custom_builder_spec.rb +116 -0
  117. data/spec/builder/error_proc_spec.rb +27 -0
  118. data/spec/builder/semantic_fields_for_spec.rb +142 -0
  119. data/spec/fast_spec_helper.rb +12 -0
  120. data/spec/generators/formtastic/form/form_generator_spec.rb +131 -0
  121. data/spec/generators/formtastic/input/input_generator_spec.rb +124 -0
  122. data/spec/generators/formtastic/install/install_generator_spec.rb +47 -0
  123. data/spec/helpers/action_helper_spec.rb +19 -0
  124. data/spec/helpers/actions_helper_spec.rb +143 -0
  125. data/spec/helpers/form_helper_spec.rb +218 -0
  126. data/spec/helpers/input_helper_spec.rb +6 -0
  127. data/spec/helpers/inputs_helper_spec.rb +655 -0
  128. data/spec/helpers/namespaced_action_helper_spec.rb +43 -0
  129. data/spec/helpers/namespaced_input_helper_spec.rb +36 -0
  130. data/spec/helpers/reflection_helper_spec.rb +32 -0
  131. data/spec/helpers/semantic_errors_helper_spec.rb +112 -0
  132. data/spec/i18n_spec.rb +210 -0
  133. data/spec/input_class_finder_spec.rb +10 -0
  134. data/spec/inputs/base/collections_spec.rb +76 -0
  135. data/spec/inputs/base/validations_spec.rb +342 -0
  136. data/spec/inputs/boolean_input_spec.rb +254 -0
  137. data/spec/inputs/check_boxes_input_spec.rb +546 -0
  138. data/spec/inputs/color_input_spec.rb +97 -0
  139. data/spec/inputs/country_input_spec.rb +133 -0
  140. data/spec/inputs/custom_input_spec.rb +55 -0
  141. data/spec/inputs/datalist_input_spec.rb +61 -0
  142. data/spec/inputs/date_picker_input_spec.rb +449 -0
  143. data/spec/inputs/date_select_input_spec.rb +235 -0
  144. data/spec/inputs/datetime_picker_input_spec.rb +490 -0
  145. data/spec/inputs/datetime_select_input_spec.rb +193 -0
  146. data/spec/inputs/email_input_spec.rb +85 -0
  147. data/spec/inputs/file_input_spec.rb +89 -0
  148. data/spec/inputs/hidden_input_spec.rb +135 -0
  149. data/spec/inputs/include_blank_spec.rb +78 -0
  150. data/spec/inputs/label_spec.rb +149 -0
  151. data/spec/inputs/number_input_spec.rb +815 -0
  152. data/spec/inputs/password_input_spec.rb +99 -0
  153. data/spec/inputs/phone_input_spec.rb +85 -0
  154. data/spec/inputs/placeholder_spec.rb +71 -0
  155. data/spec/inputs/radio_input_spec.rb +328 -0
  156. data/spec/inputs/range_input_spec.rb +505 -0
  157. data/spec/inputs/readonly_spec.rb +50 -0
  158. data/spec/inputs/search_input_spec.rb +84 -0
  159. data/spec/inputs/select_input_spec.rb +615 -0
  160. data/spec/inputs/string_input_spec.rb +260 -0
  161. data/spec/inputs/text_input_spec.rb +187 -0
  162. data/spec/inputs/time_picker_input_spec.rb +455 -0
  163. data/spec/inputs/time_select_input_spec.rb +248 -0
  164. data/spec/inputs/time_zone_input_spec.rb +143 -0
  165. data/spec/inputs/url_input_spec.rb +85 -0
  166. data/spec/inputs/with_options_spec.rb +43 -0
  167. data/spec/localizer_spec.rb +130 -0
  168. data/spec/namespaced_class_finder_spec.rb +79 -0
  169. data/spec/spec.opts +2 -0
  170. data/spec/spec_helper.rb +525 -0
  171. data/spec/support/custom_macros.rb +564 -0
  172. data/spec/support/deprecation.rb +6 -0
  173. data/spec/support/shared_examples.rb +1313 -0
  174. data/spec/support/specialized_class_finder_shared_example.rb +27 -0
  175. data/spec/support/test_environment.rb +31 -0
  176. data/spec/util_spec.rb +66 -0
  177. metadata +434 -161
  178. data/README.textile +0 -682
  179. data/generators/form/USAGE +0 -16
  180. data/generators/form/form_generator.rb +0 -111
  181. data/generators/formtastic/formtastic_generator.rb +0 -26
  182. data/init.rb +0 -5
  183. data/lib/formtastic/layout_helper.rb +0 -12
  184. data/lib/formtastic/railtie.rb +0 -14
  185. data/lib/generators/templates/formtastic.css +0 -145
  186. data/lib/generators/templates/formtastic_changes.css +0 -14
  187. data/lib/generators/templates/rails2/_form.html.erb +0 -5
  188. data/lib/generators/templates/rails2/_form.html.haml +0 -4
  189. data/rails/init.rb +0 -2
@@ -0,0 +1,36 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a `<input type="text">` wrapped in the standard
5
+ # `<li>` wrapper. This is the default input choice for database columns of the `:string` type,
6
+ # and is the default choice for all inputs when no other logical input type can be inferred.
7
+ # You can force any input to be a string input with `:as => :string`.
8
+ #
9
+ # @example Full form context and output
10
+ #
11
+ # <%= semantic_form_for(@user) do |f| %>
12
+ # <%= f.inputs do %>
13
+ # <%= f.input :first_name, :as => :string %>
14
+ # <% end %>
15
+ # <% end %>
16
+ #
17
+ # <form...>
18
+ # <fieldset>
19
+ # <ol>
20
+ # <li class="string">
21
+ # <label for="user_first_name">First name</label>
22
+ # <input type="text" id="user_first_name" name="user[first_name]">
23
+ # </li>
24
+ # </ol>
25
+ # </fieldset>
26
+ # </form>
27
+ #
28
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
29
+ class StringInput
30
+ include Base
31
+ include Base::Stringish
32
+ include Base::Placeholder
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,48 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a `<textarea>` wrapped in the standard
5
+ # `<li>` wrapper. This is the default input choice for database columns of the `:text` type,
6
+ # but can forced on any text-like input with `:as => :text`.
7
+ #
8
+ # @example Full form context and output
9
+ #
10
+ # <%= semantic_form_for(@user) do |f| %>
11
+ # <%= f.inputs do %>
12
+ # <%= f.input :first_name, :as => :text %>
13
+ # <% end %>
14
+ # <% end %>
15
+ #
16
+ # <form...>
17
+ # <fieldset>
18
+ # <ol>
19
+ # <li class="text">
20
+ # <label for="user_first_name">First name</label>
21
+ # <textarea cols="30" id="user_first_name" name="user[first_name]" rows="20"></textarea>
22
+ # </li>
23
+ # </ol>
24
+ # </fieldset>
25
+ # </form>
26
+ #
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
28
+ class TextInput
29
+ include Base
30
+ include Base::Placeholder
31
+
32
+ def input_html_options
33
+ {
34
+ :cols => builder.default_text_area_width,
35
+ :rows => builder.default_text_area_height
36
+ }.merge(super)
37
+ end
38
+
39
+ def to_html
40
+ input_wrapping do
41
+ label_html <<
42
+ builder.text_area(method, input_html_options)
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,99 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a HTML5 `<input type="time">` wrapped in the standard
5
+ # `<li>` wrapper. This is an alternative to `:time_select` for `:date`, `:time`, `:datetime`
6
+ # database columns. You can use this input with `:as => :time_picker`.
7
+ #
8
+ # *Please note:* Formtastic only provides suitable markup for a date picker, but does not supply
9
+ # any additional CSS or Javascript to render calendar-style date pickers. Browsers that support
10
+ # this input type (such as Mobile Webkit and Opera on the desktop) will render a native widget.
11
+ # Browsers that don't will default to a plain text field`<input type="text">` and can be
12
+ # poly-filled with some Javascript and a UI library of your choice.
13
+ #
14
+ # @example Full form context and output
15
+ #
16
+ # <%= semantic_form_for(@post) do |f| %>
17
+ # <%= f.inputs do %>
18
+ # <%= f.input :publish_at, :as => :time_picker %>
19
+ # <% end %>
20
+ # <% end %>
21
+ #
22
+ # <form...>
23
+ # <fieldset>
24
+ # <ol>
25
+ # <li class="string">
26
+ # <label for="post_publish_at">First name</label>
27
+ # <input type="date" id="post_publish_at" name="post[publish_at]">
28
+ # </li>
29
+ # </ol>
30
+ # </fieldset>
31
+ # </form>
32
+ #
33
+ # @example Setting the size (defaults to 5 for HH:MM)
34
+ # <%= f.input :publish_at, :as => :time_picker, :size => 20 %>
35
+ # <%= f.input :publish_at, :as => :time_picker, :input_html => { :size => 20 } %>
36
+ #
37
+ # @example Setting the maxlength (defaults to 5 for HH:MM)
38
+ # <%= f.input :publish_at, :as => :time_picker, :maxlength => 20 %>
39
+ # <%= f.input :publish_at, :as => :time_picker, :input_html => { :maxlength => 20 } %>
40
+ #
41
+ # @example Setting the value (defaults to HH:MM for Date and Time objects, otherwise renders string)
42
+ # <%= f.input :publish_at, :as => :time_picker, :input_html => { :value => "14:14" } %>
43
+ #
44
+ # @example Setting the step attribute (defaults to 60)
45
+ # <%= f.input :publish_at, :as => :time_picker, :step => 120 %>
46
+ # <%= f.input :publish_at, :as => :time_picker, :input_html => { :step => 120 } %>
47
+ #
48
+ # @example Setting the step attribute with a macro
49
+ # <%= f.input :publish_at, :as => :time_picker, :step => :second %>
50
+ # <%= f.input :publish_at, :as => :time_picker, :step => :minute %>
51
+ # <%= f.input :publish_at, :as => :time_picker, :step => :quarter_hour %>
52
+ # <%= f.input :publish_at, :as => :time_picker, :step => :fifteen_minutes %>
53
+ # <%= f.input :publish_at, :as => :time_picker, :step => :half_hour %>
54
+ # <%= f.input :publish_at, :as => :time_picker, :step => :thirty_minutes %>
55
+ # <%= f.input :publish_at, :as => :time_picker, :step => :hour %>
56
+ # <%= f.input :publish_at, :as => :time_picker, :step => :sixty_minutes %>
57
+ #
58
+ # @example Setting the min attribute
59
+ # <%= f.input :publish_at, :as => :time_picker, :min => "09:00" %>
60
+ # <%= f.input :publish_at, :as => :time_picker, :input_html => { :min => "01:00" } %>
61
+ #
62
+ # @example Setting the max attribute
63
+ # <%= f.input :publish_at, :as => :time_picker, :max => "18:00" %>
64
+ # <%= f.input :publish_at, :as => :time_picker, :input_html => { :max => "18:00" } %>
65
+ #
66
+ # @example Setting the placeholder attribute
67
+ # <%= f.input :publish_at, :as => :time_picker, :placeholder => "HH:MM" %>
68
+ # <%= f.input :publish_at, :as => :time_picker, :input_html => { :placeholder => "HH:MM" } %>
69
+ #
70
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
71
+ class TimePickerInput
72
+ include Base
73
+ include Base::Stringish
74
+ include Base::DatetimePickerish
75
+
76
+ def html_input_type
77
+ "time"
78
+ end
79
+
80
+ def default_size
81
+ 5
82
+ end
83
+
84
+ def value
85
+ return options[:input_html][:value] if options[:input_html] && options[:input_html].key?(:value)
86
+ val = object.send(method)
87
+ return "00:00" if val.is_a?(Date)
88
+ return val.strftime("%H:%M") if val.is_a?(Time)
89
+ return val if val.nil?
90
+ val.to_s
91
+ end
92
+
93
+ def default_step
94
+ 60
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,38 @@
1
+ module Formtastic
2
+ module Inputs
3
+ # Outputs a series of select boxes for the fragments that make up a time (hour, minute, second).
4
+ # Unless `:ignore_date` is true, it will render hidden inputs for the year, month and day as
5
+ # well, defaulting to `Time.current` if the form object doesn't have a value, much like Rails'
6
+ # own `time_select`.
7
+ #
8
+ # @see Formtastic::Inputs::Base::Timeish Timeish module for documentation of date, time and datetime input options.
9
+ class TimeSelectInput
10
+ include Base
11
+ include Base::Timeish
12
+
13
+ # we don't want year / month / day fragments if :ignore_date => true
14
+ def fragments
15
+ time_fragments
16
+ end
17
+
18
+ def value_or_default_value
19
+ value ? value : Time.current
20
+ end
21
+
22
+ def fragment_value(fragment)
23
+ value_or_default_value.send(fragment)
24
+ end
25
+
26
+ def hidden_fragments
27
+ if !options[:ignore_date]
28
+ date_fragments.map do |fragment|
29
+ template.hidden_field_tag(hidden_field_name(fragment), fragment_value(fragment), :id => fragment_id(fragment), :disabled => input_html_options[:disabled] )
30
+ end.join.html_safe
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,58 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a `<label>` with a `<select>` containing a series of time zones (using Rails' own
5
+ # `time_zone_select` helper), wrapped in the standard `<li>` wrapper.
6
+
7
+ # This is the default input choice for attributes matching /time_zone/, but can be applied to
8
+ # any text-like input with `:as => :time_zone`.
9
+ #
10
+ # @example Full form context and output
11
+ #
12
+ # <%= semantic_form_for(@user) do |f| %>
13
+ # <%= f.inputs do %>
14
+ # <%= f.input :time_zone, :as => :time_zone %>
15
+ # <% end %>
16
+ # <% end %>
17
+ #
18
+ # <form...>
19
+ # <fieldset>
20
+ # <ol>
21
+ # <li class="time_zone">
22
+ # <label for="user_time_zone">Time zone</label>
23
+ # <input type="text" id="user_time_zone" name="user[time_zone]">
24
+ # </li>
25
+ # </ol>
26
+ # </fieldset>
27
+ # </form>
28
+ #
29
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
30
+ #
31
+ # The priority_zones option:
32
+ # Since this input actually uses Rails' `time_zone_select` helper, the :priority_zones
33
+ # option needs to be an array of ActiveSupport::TimeZone objects.
34
+ #
35
+ # And you can configure default value using
36
+ #
37
+ # ```
38
+ # Formtastic::FormBuilder.priority_time_zones = [timezone1, timezone2]
39
+ # ```
40
+ #
41
+ # See http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/time_zone_select for more information.
42
+ #
43
+ class TimeZoneInput
44
+ include Base
45
+
46
+ def to_html
47
+ input_wrapping do
48
+ label_html <<
49
+ builder.time_zone_select(method, priority_zones, input_options, input_html_options)
50
+ end
51
+ end
52
+
53
+ def priority_zones
54
+ options[:priority_zones] || Formtastic::FormBuilder.priority_time_zones
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,41 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a HTML5 `<input type="url">` wrapped in the standard
5
+ # `<li>` wrapper. This is the default input choice for all attributes matching
6
+ # `/^url$|^website$|_url$/`, but can be applied to any text-like input with `:as => :url`.
7
+ #
8
+ # @example Full form context and output
9
+ #
10
+ # <%= semantic_form_for(@user) do |f| %>
11
+ # <%= f.inputs do %>
12
+ # <%= f.input :home_page, :as => :url %>
13
+ # <% end %>
14
+ # <% end %>
15
+ #
16
+ # <form...>
17
+ # <fieldset>
18
+ # <ol>
19
+ # <li class="url">
20
+ # <label for="user_home_page">Home page</label>
21
+ # <input type="number" id="user_home_page" name="user[home_page]">
22
+ # </li>
23
+ # </ol>
24
+ # </fieldset>
25
+ # </form>
26
+ #
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
28
+ class UrlInput
29
+ include Base
30
+ include Base::Stringish
31
+ include Base::Placeholder
32
+
33
+ def to_html
34
+ input_wrapping do
35
+ label_html <<
36
+ builder.url_field(method, input_html_options)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ module Formtastic
2
+ module LocalizedString
3
+
4
+ def model_name
5
+ @object.present? ? @object.class.name : @object_name.to_s.classify
6
+ end
7
+
8
+ protected
9
+
10
+ def localized_string(key, value, type, options = {}) # @private
11
+ current_builder = respond_to?(:builder) ? builder : self
12
+ localizer = Formtastic::FormBuilder.i18n_localizer.new(current_builder)
13
+ localizer.localize(key, value, type, options)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,152 @@
1
+ module Formtastic
2
+ # Implementation for looking up localized values within Formtastic using I18n, if no
3
+ # explicit value (like the `:label` option) is set and I18n-lookups are enabled in the
4
+ # configuration.
5
+ #
6
+ # You can subclass this to implement your own Localizer, and configure Formtastic to use this
7
+ # localizer with:
8
+ #
9
+ # Formtastic::FormBuilder.i18n_localizer
10
+ #
11
+ # Enabled/disable i18n lookups completely with:
12
+ #
13
+ # Formtastic::FormBuilder.i18n_lookups_by_default = true/false
14
+ #
15
+ # Lookup priority:
16
+ #
17
+ # 'formtastic.%{type}.%{model}.%{action}.%{attribute}'
18
+ # 'formtastic.%{type}.%{model}.%{attribute}'
19
+ # 'formtastic.%{type}.%{attribute}'
20
+ #
21
+ # Example:
22
+ #
23
+ # 'formtastic.labels.post.edit.title'
24
+ # 'formtastic.labels.post.title'
25
+ # 'formtastic.labels.title'
26
+ class Localizer
27
+ class Cache
28
+ def get(key)
29
+ cache[key]
30
+ end
31
+
32
+ def has_key?(key)
33
+ cache.has_key?(key)
34
+ end
35
+
36
+ def set(key, result)
37
+ cache[key] = result
38
+ end
39
+
40
+ def cache
41
+ @cache ||= {}
42
+ end
43
+
44
+ def clear!
45
+ cache.clear
46
+ end
47
+ end
48
+
49
+ attr_accessor :builder
50
+
51
+ def self.cache
52
+ @cache ||= Cache.new
53
+ end
54
+
55
+ def initialize(current_builder)
56
+ self.builder = current_builder
57
+ end
58
+
59
+ def localize(key, value, type, options = {}) # @private
60
+ key = value if value.is_a?(::Symbol)
61
+
62
+ if value.is_a?(::String)
63
+ escape_html_entities(value)
64
+ else
65
+ use_i18n = value.nil? ? i18n_lookups_by_default : (value != false)
66
+ use_cache = i18n_cache_lookups
67
+ cache = self.class.cache
68
+
69
+ if use_i18n
70
+ model_name, nested_model_name = normalize_model_name(builder.model_name.underscore)
71
+
72
+ action_name = builder.template.params[:action].to_s rescue ''
73
+ attribute_name = key.to_s
74
+
75
+ # look in the cache first
76
+ if use_cache
77
+ cache_key = [::I18n.locale, action_name, model_name, nested_model_name, attribute_name, key, value, type, options]
78
+ return cache.get(cache_key) if cache.has_key?(cache_key)
79
+ end
80
+
81
+ defaults = Formtastic::I18n::SCOPES.reject do |i18n_scope|
82
+ nested_model_name.nil? && i18n_scope.match(/nested_model/)
83
+ end.collect do |i18n_scope|
84
+ i18n_path = i18n_scope.dup
85
+ i18n_path.gsub!('%{action}', action_name)
86
+ i18n_path.gsub!('%{model}', model_name)
87
+ i18n_path.gsub!('%{nested_model}', nested_model_name) unless nested_model_name.nil?
88
+ i18n_path.gsub!('%{attribute}', attribute_name)
89
+ i18n_path.tr!('..', '.')
90
+ i18n_path.to_sym
91
+ end
92
+ defaults << ''
93
+
94
+ defaults.uniq!
95
+
96
+ default_key = defaults.shift
97
+ i18n_value = Formtastic::I18n.t(default_key,
98
+ options.merge(:default => defaults, :scope => type.to_s.pluralize.to_sym))
99
+ i18n_value = i18n_value.is_a?(::String) ? i18n_value : nil
100
+ if i18n_value.blank? && type == :label
101
+ # This is effectively what Rails label helper does for i18n lookup
102
+ options[:scope] = [:helpers, type]
103
+ options[:default] = defaults
104
+ i18n_value = ::I18n.t(default_key, options)
105
+ end
106
+
107
+ # save the result to the cache
108
+ result = (i18n_value.is_a?(::String) && i18n_value.present?) ? escape_html_entities(i18n_value) : nil
109
+ cache.set(cache_key, result) if use_cache
110
+ result
111
+ end
112
+ end
113
+ end
114
+
115
+ protected
116
+
117
+ def normalize_model_name(name)
118
+ if !name =~ /\[/ && builder.respond_to?(:parent_builder) && builder.parent_builder.object_name
119
+ # Rails 3.1 nested builder case
120
+ [builder.parent_builder.object_name.to_s, name]
121
+ elsif name =~ /(.+)\[(.+)\]/
122
+ # Rails 3 (and 3.1?) nested builder case with :post rather than @post
123
+ [$1, $2]
124
+ elsif builder.respond_to?(:options) && builder.options.key?(:as)
125
+ [builder.options[:as].to_s]
126
+ elsif builder.respond_to?(:options) && builder.options.key?(:parent_builder)
127
+ # Rails 3.0 nested builder work-around case, where :parent_builder is provided by f.semantic_form_for
128
+ [builder.options[:parent_builder].object_name.to_s, name]
129
+ else
130
+ # Non-nested case
131
+ [name]
132
+ end
133
+ end
134
+
135
+ def escape_html_entities(string) # @private
136
+ if (builder.escape_html_entities_in_hints_and_labels) ||
137
+ (self.respond_to?(:escape_html_entities_in_hints_and_labels) && escape_html_entities_in_hints_and_labels)
138
+ string = builder.template.escape_once(string) unless string.respond_to?(:html_safe?) && string.html_safe? == true # Accept html_safe flag as indicator to skip escaping
139
+ end
140
+ string
141
+ end
142
+
143
+ def i18n_lookups_by_default
144
+ builder.i18n_lookups_by_default
145
+ end
146
+
147
+ def i18n_cache_lookups
148
+ builder.i18n_cache_lookups
149
+ end
150
+
151
+ end
152
+ end