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,19 @@
1
+ class <%= name.camelize %>Input <%= @extension_sentence %>
2
+ <%- if !options[:extend] -%>
3
+ include Formtastic::Inputs::Base
4
+ <%- end -%>
5
+
6
+ <%- if !options[:extend] || (options[:extend] == "extend") -%>
7
+ def to_html
8
+ # Add your custom input definition here.
9
+ <%- if options[:extend] == "extend" -%>
10
+ super
11
+ <%- end -%>
12
+ end
13
+
14
+ <%- else -%>
15
+ def input_html_options
16
+ # Add your custom input extension here.
17
+ end
18
+ <%- end -%>
19
+ end
data/lib/locale/en.yml CHANGED
@@ -4,4 +4,7 @@ en:
4
4
  :no: 'No'
5
5
  :create: 'Create %{model}'
6
6
  :update: 'Update %{model}'
7
+ :submit: 'Submit %{model}'
8
+ :cancel: 'Cancel %{model}'
9
+ :reset: 'Reset %{model}'
7
10
  :required: 'required'
@@ -0,0 +1,224 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta content="noindex,nofollow" name="robots">
5
+ <meta charset="utf-8">
6
+ <title>Formtastic</title>
7
+
8
+ <link href="/formtastic.css" rel="stylesheet" type="text/css" />
9
+ <!--[if IE 6]><link href="/formtastic_ie6.css" rel="stylesheet" type="text/css" /><![endif]-->
10
+ <!--[if IE 7]><link href="/formtastic_ie7.css" rel="stylesheet" type="text/css" /><![endif]-->
11
+
12
+ <style>
13
+ body {
14
+ font-family: helvetica, arial;
15
+ font-size: 12px;
16
+ }
17
+ </style>
18
+ </head>
19
+ </html>
20
+ <body>
21
+ <h1>Formtastic</h1>
22
+
23
+ <form action="basic_inputs.html" class="formtastic gem" id="new_gem" method="get">
24
+ <fieldset class="inputs">
25
+ <ol>
26
+ <li class="input string stringish optional" id="gem_summary_input">
27
+ <label class="label" for="gem_summary">Summary</label>
28
+ <input id="gem_summary" name="gem[summary]" type="text" value="A Rails form builder plugin/gem with semantically rich and accessible markup" maxlength="255">
29
+ </li>
30
+
31
+ <li class="input text optional" id="gem_description_input">
32
+ <label class="label" for="gem_description">Description</label>
33
+ <textarea id="gem_description" rows="5">A Rails form builder plugin/gem with semantically rich and accessible markup</textarea>
34
+ </li>
35
+
36
+ <li class="input url stringish optional" id="gem_url_input">
37
+ <label class="label" for="gem_url">URL</label>
38
+ <input id="gem_url" name="gem[url]" type="url">
39
+ <p class="inline-hints">Example: https://github.com/justinfrench/formtastic</p>
40
+ </li>
41
+
42
+ <li class="input password stringish required" id="gem_password_input">
43
+ <label class="label" for="gem_password">Password<abbr title="required">*</abbr></label>
44
+ <input id="gem_password" name="gem[password]" type="password">
45
+ <p class="inline-errors">can't be blank</p>
46
+ </li>
47
+
48
+ <li class="input password stringish required" id="gem_password_input">
49
+ <label class="label" for="gem_password_confirmation">Password confirmation<abbr title="required">*</abbr></label>
50
+ <input id="gem_password_confirmation" name="gem[password_confirmation]" type="password">
51
+ <p class="inline-errors">can't be blank</p>
52
+ </li>
53
+
54
+ <li class="input numeric stringish optional" id="gem_downloads_input">
55
+ <label class="label" for="gem_downloads">Downloads</label>
56
+ <input id="gem_downloads" name="gem[downloads]" type="numeric" value="209,354">
57
+ </li>
58
+
59
+ <li class="input file optional" id="gem_file_input">
60
+ <label class="label" for="gem_file">File</label>
61
+ <input id="gem_file" name="gem[file]" type="file" value="value">
62
+ </li>
63
+
64
+ <li class="input email stringish optional" id="gem_email_input">
65
+ <label class="label" for="gem_email">Email</label>
66
+ <input id="gem_email" name="gem[email]" type="email">
67
+ </li>
68
+
69
+ <li class="input phone stringish optional" id="gem_phone_input">
70
+ <label class="label" for="gem_phone">Phone</label>
71
+ <input id="gem_phone" name="gem[phone]" type="phone">
72
+ </li>
73
+
74
+ <li class="input search stringish optional" id="gem_search_input">
75
+ <label class="label" for="gem_search">Search</label>
76
+ <input id="gem_search" name="gem[search]" type="search">
77
+ </li>
78
+
79
+ <li class="input date optional">
80
+ <fieldset class="fragments">
81
+ <legend class="label"><label>First release</label></legend>
82
+ <ol class="fragments-group">
83
+ <li class="fragment">
84
+ <label>Year</label>
85
+ <select id="gem_first_release_1i" name="gem[first_release][1i]">
86
+ <option>2009</option>
87
+ </select>
88
+ </li>
89
+ <li class="fragment">
90
+ <label>Month</label>
91
+ <select id="gem_first_release_2i" name="gem[first_release][2i]">
92
+ <option>October</option>
93
+ </select>
94
+ </li>
95
+ <li class="fragment">
96
+ <label>Day</label>
97
+ <select id="gem_first_release_3i" name="gem[first_release][3i]">
98
+ <option>15</option>
99
+ </select>
100
+ </li>
101
+ </ol>
102
+ </fieldset>
103
+ </li>
104
+
105
+ <li class="input date_picker optional">
106
+ <label class="label" for="gem_expiry">Expiry date</label>
107
+ <input id="gem_expiry" name="gem[gem_expiry]" type="date" size="10" maxlength="10" min="2012-01-01" max="2012-12-31" step="1" value="2012-01-01">
108
+ </li>
109
+
110
+ <li class="input datetime_picker optional">
111
+ <label class="label" for="gem_expiry">Expiry datetime-local</label>
112
+ <input id="gem_expiry" name="gem[gem_expiry]" type="datetime-local" size="16" maxlength="16" min="2012-01-01T00:00" max="2012-12-31T23:59" step="1800">
113
+ </li>
114
+
115
+ <li class="input datetime_picker optional">
116
+ <label class="label" for="gem_expiry">Expiry datetime</label>
117
+ <input id="gem_expiry" name="gem[gem_expiry]" type="datetime" size="16" maxlength="16" min="2012-01-01T00:00" max="2012-12-31T23:59" step="1800">
118
+ </li>
119
+
120
+ <li class="input time_picker optional">
121
+ <label class="label" for="gem_expiry">Expiry time</label>
122
+ <input id="gem_expiry" name="gem[gem_expiry]" type="time" size="5" maxlength="5" min="T00:00" max="23:59" step="60">
123
+ </li>
124
+
125
+ <li class="input string stringish optional autofocus" id="gem_autofocus_input">
126
+ <label class="label" for="gem_autofocus">Autofocus</label>
127
+ <input id="gem_autofocus" name="gem[autofocus]" type="text" value="The focus is set to this field" autofocus="autofocus">
128
+ </li>
129
+
130
+ <li class="input boolean optional" id="gem_terms_and_conditions_input">
131
+ <label for="gem_terms_and_conditions">
132
+ <input id="gem_terms_and_conditions" name="gem[terms_and_conditions]" type="checkbox" value="1" checked="checked">
133
+ I agree to your draconian terms of service even though I didn't read them
134
+ </label>
135
+ </li>
136
+
137
+ <li class="input select optional" id="gem_awesomeness_input">
138
+ <label class="label" for="gem_awesomeness">Select</label>
139
+ <select id="gem_awesomeness" name="gem[awesomeness]">
140
+ <option value="5">First choice</option>
141
+ <option value="4">Second choice</option>
142
+ </select>
143
+ </li>
144
+
145
+ <li class="input radio optional">
146
+ <fieldset class="choices">
147
+ <legend class="label"><label>Rate</label></legend>
148
+ <ol class="choices-group">
149
+ <li class="choice">
150
+ <label><input id="gem_rate_five" name="gem[rate]" type="radio" checked="checked"> Five</label></label>
151
+ </li>
152
+ <li class="choice">
153
+ <label><input id="gem_rate_four" name="gem[rate]" type="radio"> Four</label></label>
154
+ </li>
155
+ <li class="choice">
156
+ <label><input id="gem_rate_three" name="gem[rate]" type="radio"> Three</label></label>
157
+ </li>
158
+ <li class="choice">
159
+ <label><input id="gem_rate_two" name="gem[rate]" type="radio"> Two</label></label>
160
+ </li>
161
+ <li class="choice">
162
+ <label><input id="gem_rate_one" name="gem[rate]" type="radio"> One</label></label>
163
+ </li>
164
+ </ol>
165
+ </fieldset>
166
+ </li>
167
+
168
+ <li class="input check_boxes optional">
169
+ <fieldset class="choices">
170
+ <legend class="label"><label>Browsers</label></legend>
171
+ <ol class="choices-group">
172
+ <li class="choice">
173
+ <label><input id="gem_browser_google_chrome" name="gem[browser][]" type="checkbox"> Google Chrome</label></label>
174
+ </li>
175
+ <li class="choice">
176
+ <label><input id="gem_browser_apple_safari" name="gem[browser][]" type="checkbox"> Apple Safari</label></label>
177
+ </li>
178
+ <li class="choice">
179
+ <label><input id="gem_browser_mozilla_firefox" name="gem[browser][]" type="checkbox"> Mozilla Firefox</label></label>
180
+ </li>
181
+ <li class="choice">
182
+ <label><input id="gem_browser_opera" name="gem[browser][]" type="checkbox"> Opera</label></label>
183
+ </li>
184
+ <li class="choice">
185
+ <label><input id="gem_browser_internet_explorer" name="gem[browser][]" type="checkbox"> Internet Explorer (Although you really can't call it a browser can you? This is some long text to force wrapping.)</label></label>
186
+ </li>
187
+ </ol>
188
+ </fieldset>
189
+ </li>
190
+ </ol>
191
+ </fieldset>
192
+
193
+ <fieldset class="buttons">
194
+ <ol>
195
+ <li class="button commit">
196
+ <input class="create" id="gem_submit" type="submit">
197
+ </li>
198
+ </ol>
199
+ </fieldset>
200
+
201
+ <fieldset class="actions">
202
+ <ol>
203
+ <li class="action input_action">
204
+ <input id="gem_submit" type="submit" value="Create Thing">
205
+ </li>
206
+ </ol>
207
+ </fieldset>
208
+
209
+ <fieldset class="actions">
210
+ <ol>
211
+ <li class="action button_action">
212
+ <button id="gem_submit" type="submit">Create Thing</button>
213
+ </li>
214
+ <li class="action button_action">
215
+ <button id="gem_submit" type="reset">Reset</button>
216
+ </li>
217
+ <li class="action link_action">
218
+ <a href="#">Cancel</a>
219
+ </li>
220
+ </ol>
221
+ </fieldset>
222
+ </form>
223
+ </body>
224
+ </html>
data/sample/config.ru ADDED
@@ -0,0 +1,69 @@
1
+ module Rack
2
+ module Formtastic
3
+ class Samples
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ @status, @headers, @body = @app.call(env)
10
+ @env = env
11
+
12
+ @body = '' if favicon?
13
+ @body = static_file if !favicon? && static_file?
14
+ @body = stylesheet if stylesheet?
15
+ @headers ||= {}
16
+ @headers['Content-Type'] = mime(extension)
17
+ [@status, @headers, @body]
18
+ end
19
+
20
+ def static_file?
21
+ !stylesheet?
22
+ end
23
+
24
+ def stylesheet?
25
+ @env["PATH_INFO"] =~ /\.(css)/
26
+ end
27
+
28
+ def favicon?
29
+ @env["PATH_INFO"] =~ /favicon.ico$/
30
+ end
31
+
32
+ def extension
33
+ @env["PATH_INFO"].split(".").last
34
+ end
35
+
36
+ def mime(extension)
37
+ mimes[extension] || mimes['html']
38
+ end
39
+
40
+ def mimes
41
+ {
42
+ 'ico' => 'image/x-icon',
43
+ 'html' => 'text/html',
44
+ 'css' => 'text/css',
45
+ 'js' => 'text/javascript'
46
+ }
47
+ end
48
+
49
+ def static_file
50
+ ::File.open(file_path)
51
+ end
52
+
53
+ def stylesheet
54
+ ::File.open(::File.join("../app/assets/stylesheets", file_path))
55
+ end
56
+
57
+ def file_path
58
+ @env["PATH_INFO"].gsub(/^\//, '').gsub(/^$/, 'index.html')
59
+ end
60
+
61
+ end
62
+ end
63
+ end
64
+
65
+ use Rack::ContentLength
66
+ use Rack::Formtastic::Samples
67
+
68
+ app = lambda { |env| [200, @headers, @body] }
69
+ run app
data/sample/index.html ADDED
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>untitled</title>
6
+ </head>
7
+ <body>
8
+
9
+ <ul>
10
+ <li><a href="/basic_inputs.html">Basic Inputs</li>
11
+ </ul>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'formtastic/action_class_finder'
4
+
5
+ describe Formtastic::ActionClassFinder do
6
+ include FormtasticSpecHelper
7
+
8
+ it_behaves_like 'Specialized Class Finder' do
9
+ let(:default) { Formtastic::Actions }
10
+ let(:namespaces_setting) { :action_namespaces }
11
+ end
12
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'ButtonAction', 'when submitting' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+
12
+ concat(semantic_form_for(@new_post) do |builder|
13
+ concat(builder.action(:submit, :as => :button))
14
+ end)
15
+ end
16
+
17
+ it 'should render a submit type of button' do
18
+ output_buffer.should have_tag('li.action.button_action button[@type="submit"]')
19
+ end
20
+
21
+ end
22
+
23
+ describe 'ButtonAction', 'when resetting' do
24
+
25
+ include FormtasticSpecHelper
26
+
27
+ before do
28
+ @output_buffer = ''
29
+ mock_everything
30
+
31
+ concat(semantic_form_for(@new_post) do |builder|
32
+ concat(builder.action(:reset, :as => :button))
33
+ end)
34
+ end
35
+
36
+ it 'should render a reset type of button' do
37
+ output_buffer.should have_tag('li.action.button_action button[@type="reset"]', :text => "Reset Post")
38
+ end
39
+
40
+ it 'should not render a value attribute' do
41
+ output_buffer.should_not have_tag('li.action.button_action button[@value]')
42
+ end
43
+
44
+ end
45
+
46
+ describe 'InputAction', 'when cancelling' do
47
+
48
+ include FormtasticSpecHelper
49
+
50
+ before do
51
+ @output_buffer = ''
52
+ mock_everything
53
+ end
54
+
55
+ it 'should raise an error' do
56
+ lambda {
57
+ concat(semantic_form_for(@new_post) do |builder|
58
+ concat(builder.action(:cancel, :as => :button))
59
+ end)
60
+ }.should raise_error(Formtastic::UnsupportedMethodForAction)
61
+ end
62
+
63
+ end
@@ -0,0 +1,521 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'InputAction::Base' do
5
+
6
+ # Most basic Action class to test Base
7
+ class ::GenericAction
8
+ include ::Formtastic::Actions::Base
9
+
10
+ def supported_methods
11
+ [:submit, :reset, :cancel]
12
+ end
13
+
14
+ def to_html
15
+ wrapper do
16
+ builder.submit(text, button_html)
17
+ end
18
+ end
19
+ end
20
+
21
+ include FormtasticSpecHelper
22
+
23
+ before do
24
+ @output_buffer = ''
25
+ mock_everything
26
+ end
27
+
28
+ describe 'wrapping HTML' do
29
+
30
+ before do
31
+ concat(semantic_form_for(@new_post) do |builder|
32
+ concat(builder.action(:submit, :as => :generic,
33
+ :wrapper_html => { :foo => 'bah' }
34
+ ))
35
+ end)
36
+ end
37
+
38
+ it 'should add the #foo id to the li' do
39
+ output_buffer.should have_tag('li#post_submit_action')
40
+ end
41
+
42
+ it 'should add the .action and .generic_action classes to the li' do
43
+ output_buffer.should have_tag('li.action.generic_action')
44
+ end
45
+
46
+ it 'should pass :wrapper_html HTML attributes to the wrapper' do
47
+ output_buffer.should have_tag('li.action.generic_action[@foo="bah"]')
48
+ end
49
+
50
+ context "when a custom :id is provided" do
51
+
52
+ before do
53
+ concat(semantic_form_for(@new_post) do |builder|
54
+ concat(builder.action(:submit, :as => :generic,
55
+ :wrapper_html => { :id => 'foo_bah_bing' }
56
+ ))
57
+ end)
58
+ end
59
+
60
+ it "should use the custom id" do
61
+ output_buffer.should have_tag('li#foo_bah_bing')
62
+ end
63
+
64
+ end
65
+
66
+ context "when a custom class is provided as a string" do
67
+
68
+ before do
69
+ concat(semantic_form_for(@new_post) do |builder|
70
+ concat(builder.action(:submit, :as => :generic,
71
+ :wrapper_html => { :class => 'foo_bah_bing' }
72
+ ))
73
+ end)
74
+ end
75
+
76
+ it "should add the custom class strng to the existing classes" do
77
+ output_buffer.should have_tag('li.action.generic_action.foo_bah_bing')
78
+ end
79
+
80
+ end
81
+
82
+ context "when a custom class is provided as an array" do
83
+
84
+ before do
85
+ concat(semantic_form_for(@new_post) do |builder|
86
+ concat(builder.action(:submit, :as => :generic,
87
+ :wrapper_html => { :class => ['foo_bah_bing', 'zing_boo'] }
88
+ ))
89
+ end)
90
+ end
91
+
92
+ it "should add the custom class strng to the existing classes" do
93
+ output_buffer.should have_tag('li.action.generic_action.foo_bah_bing.zing_boo')
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+
100
+ describe 'button HTML' do
101
+
102
+ before do
103
+ concat(semantic_form_for(@new_post) do |builder|
104
+ concat(builder.action(:submit, :as => :generic,
105
+ :button_html => { :foo => 'bah' }
106
+ ))
107
+ end)
108
+ end
109
+
110
+ it 'should pass :button_html HTML attributes to the button' do
111
+ output_buffer.should have_tag('li.action.generic_action input[@foo="bah"]')
112
+ end
113
+
114
+ it 'should respect a default_commit_button_accesskey configuration with nil' do
115
+ with_config :default_commit_button_accesskey, nil do
116
+ concat(semantic_form_for(@new_post) do |builder|
117
+ concat(builder.action(:submit, :as => :generic))
118
+ end)
119
+ output_buffer.should_not have_tag('li.action input[@accesskey]')
120
+ end
121
+ end
122
+
123
+ it 'should respect a default_commit_button_accesskey configuration with a String' do
124
+ with_config :default_commit_button_accesskey, 's' do
125
+ concat(semantic_form_for(@new_post) do |builder|
126
+ concat(builder.action(:submit, :as => :generic))
127
+ end)
128
+ output_buffer.should have_tag('li.action input[@accesskey="s"]')
129
+ end
130
+ end
131
+
132
+ it 'should respect an accesskey through options over configration' do
133
+ with_config :default_commit_button_accesskey, 's' do
134
+ concat(semantic_form_for(@new_post) do |builder|
135
+ concat(builder.action(:submit, :as => :generic, :accesskey => 'o'))
136
+ end)
137
+ output_buffer.should_not have_tag('li.action input[@accesskey="s"]')
138
+ output_buffer.should have_tag('li.action input[@accesskey="o"]')
139
+ end
140
+ end
141
+
142
+ end
143
+
144
+ describe 'labelling' do
145
+
146
+ describe 'when used without object' do
147
+
148
+ describe 'when explicit label is provided' do
149
+ it 'should render an input with the explicitly specified label' do
150
+ concat(semantic_form_for(:post, :url => 'http://example.com') do |builder|
151
+ concat(builder.action(:submit, :as => :generic, :label => "Click!"))
152
+ concat(builder.action(:reset, :as => :generic, :label => "Reset!"))
153
+ concat(builder.action(:cancel, :as => :generic, :label => "Cancel!"))
154
+ end)
155
+ output_buffer.should have_tag('li.generic_action input[@value="Click!"]')
156
+ output_buffer.should have_tag('li.generic_action input[@value="Reset!"]')
157
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel!"]')
158
+ end
159
+ end
160
+
161
+ describe 'when no explicit label is provided' do
162
+ describe 'when no I18n-localized label is provided' do
163
+ before do
164
+ ::I18n.backend.store_translations :en, :formtastic => {
165
+ :submit => 'Submit %{model}',
166
+ :reset => 'Reset %{model}',
167
+ :cancel => 'Cancel %{model}',
168
+ :actions => {
169
+ :message => {
170
+ :submit => 'Submit message',
171
+ :reset => 'Reset message',
172
+ :cancel => 'Cancel message'
173
+ }
174
+ }
175
+ }
176
+ end
177
+
178
+ after do
179
+ ::I18n.backend.reload!
180
+ end
181
+
182
+ it 'should render an input with default I18n-localized label (fallback)' do
183
+ concat(semantic_form_for(:post, :url => 'http://example.com') do |builder|
184
+ concat(builder.action(:submit, :as => :generic))
185
+ concat(builder.action(:reset, :as => :generic))
186
+ concat(builder.action(:cancel, :as => :generic))
187
+ end)
188
+ output_buffer.should have_tag('li.generic_action input[@value="Submit Post"]')
189
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel Post"]')
190
+ output_buffer.should have_tag('li.generic_action input[@value="Reset Post"]')
191
+ end
192
+
193
+ it 'should render an input with custom resource name localized label' do
194
+ concat(semantic_form_for(:post, :as => :message, :url => 'http://example.com') do |builder|
195
+ concat(builder.action(:submit, :as => :generic))
196
+ concat(builder.action(:reset, :as => :generic))
197
+ concat(builder.action(:cancel, :as => :generic))
198
+ end)
199
+ output_buffer.should have_tag('li.generic_action input[@value="Submit message"]')
200
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel message"]')
201
+ output_buffer.should have_tag('li.generic_action input[@value="Reset message"]')
202
+ end
203
+ end
204
+
205
+ describe 'when I18n-localized label is provided' do
206
+
207
+ before do
208
+ ::I18n.backend.store_translations :en,
209
+ :formtastic => {
210
+ :actions => {
211
+ :submit => 'Custom Submit',
212
+ :reset => 'Custom Reset',
213
+ :cancel => 'Custom Cancel'
214
+ }
215
+ }
216
+ end
217
+
218
+ after do
219
+ ::I18n.backend.reload!
220
+ end
221
+
222
+ it 'should render an input with localized label (I18n)' do
223
+ with_config :i18n_lookups_by_default, true do
224
+ ::I18n.backend.store_translations :en,
225
+ :formtastic => {
226
+ :actions => {
227
+ :post => {
228
+ :submit => 'Custom Submit %{model}',
229
+ :reset => 'Custom Reset %{model}',
230
+ :cancel => 'Custom Cancel %{model}'
231
+ }
232
+ }
233
+ }
234
+
235
+ concat(semantic_form_for(:post, :url => 'http://example.com') do |builder|
236
+ concat(builder.action(:submit, :as => :generic))
237
+ concat(builder.action(:reset, :as => :generic))
238
+ concat(builder.action(:cancel, :as => :generic))
239
+ end)
240
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Submit Post"]})
241
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Reset Post"]})
242
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Cancel Post"]})
243
+ end
244
+ end
245
+
246
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
247
+ with_config :i18n_lookups_by_default, true do
248
+ concat(semantic_form_for(:post, :url => 'http://example.com') do |builder|
249
+ concat(builder.action(:submit, :as => :generic))
250
+ concat(builder.action(:reset, :as => :generic))
251
+ concat(builder.action(:cancel, :as => :generic))
252
+ end)
253
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Submit"]})
254
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Reset"]})
255
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Cancel"]})
256
+ end
257
+ end
258
+
259
+ end
260
+ end
261
+ end
262
+
263
+ describe 'when used on a new record' do
264
+ before do
265
+ @new_post.stub(:new_record?).and_return(true)
266
+ end
267
+
268
+ describe 'when explicit label is provided' do
269
+ it 'should render an input with the explicitly specified label' do
270
+ concat(semantic_form_for(@new_post) do |builder|
271
+ concat(builder.action(:submit, :as => :generic, :label => "Click!"))
272
+ concat(builder.action(:reset, :as => :generic, :label => "Reset!"))
273
+ concat(builder.action(:cancel, :as => :generic, :label => "Cancel!"))
274
+ end)
275
+ output_buffer.should have_tag('li.generic_action input[@value="Click!"]')
276
+ output_buffer.should have_tag('li.generic_action input[@value="Reset!"]')
277
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel!"]')
278
+ end
279
+ end
280
+
281
+ describe 'when no explicit label is provided' do
282
+ describe 'when no I18n-localized label is provided' do
283
+ before do
284
+ ::I18n.backend.store_translations :en, :formtastic => {
285
+ :create => 'Create %{model}',
286
+ :reset => 'Reset %{model}',
287
+ :cancel => 'Cancel %{model}'
288
+ }
289
+ end
290
+
291
+ after do
292
+ ::I18n.backend.reload!
293
+ end
294
+
295
+ it 'should render an input with default I18n-localized label (fallback)' do
296
+ concat(semantic_form_for(@new_post) do |builder|
297
+ concat(builder.action(:submit, :as => :generic))
298
+ concat(builder.action(:reset, :as => :generic))
299
+ concat(builder.action(:cancel, :as => :generic))
300
+ end)
301
+ output_buffer.should have_tag('li.generic_action input[@value="Create Post"]')
302
+ output_buffer.should have_tag('li.generic_action input[@value="Reset Post"]')
303
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel Post"]')
304
+ end
305
+ end
306
+
307
+ describe 'when I18n-localized label is provided' do
308
+ before do
309
+ ::I18n.backend.store_translations :en,
310
+ :formtastic => {
311
+ :actions => {
312
+ :create => 'Custom Create',
313
+ :reset => 'Custom Reset',
314
+ :cancel => 'Custom Cancel'
315
+ }
316
+ }
317
+ end
318
+
319
+ after do
320
+ ::I18n.backend.reload!
321
+ end
322
+
323
+ it 'should render an input with localized label (I18n)' do
324
+ with_config :i18n_lookups_by_default, true do
325
+ ::I18n.backend.store_translations :en,
326
+ :formtastic => {
327
+ :actions => {
328
+ :post => {
329
+ :create => 'Custom Create %{model}',
330
+ :reset => 'Custom Reset %{model}',
331
+ :cancel => 'Custom Cancel %{model}'
332
+ }
333
+ }
334
+ }
335
+ concat(semantic_form_for(@new_post) do |builder|
336
+ concat(builder.action(:submit, :as => :generic))
337
+ concat(builder.action(:reset, :as => :generic))
338
+ concat(builder.action(:cancel, :as => :generic))
339
+ end)
340
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Create Post"]})
341
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Reset Post"]})
342
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Cancel Post"]})
343
+ end
344
+ end
345
+
346
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
347
+ with_config :i18n_lookups_by_default, true do
348
+ concat(semantic_form_for(@new_post) do |builder|
349
+ concat(builder.action(:submit, :as => :generic))
350
+ concat(builder.action(:reset, :as => :generic))
351
+ concat(builder.action(:cancel, :as => :generic))
352
+ end)
353
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Create"]})
354
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Reset"]})
355
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Cancel"]})
356
+ end
357
+ end
358
+
359
+ end
360
+ end
361
+ end
362
+
363
+ describe 'when used on an existing record' do
364
+ before do
365
+ @new_post.stub(:persisted?).and_return(true)
366
+ end
367
+
368
+ describe 'when explicit label is provided' do
369
+ it 'should render an input with the explicitly specified label' do
370
+ concat(semantic_form_for(@new_post) do |builder|
371
+ concat(builder.action(:submit, :as => :generic, :label => "Click!"))
372
+ concat(builder.action(:reset, :as => :generic, :label => "Reset!"))
373
+ concat(builder.action(:cancel, :as => :generic, :label => "Cancel!"))
374
+ end)
375
+ output_buffer.should have_tag('li.generic_action input[@value="Click!"]')
376
+ output_buffer.should have_tag('li.generic_action input[@value="Reset!"]')
377
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel!"]')
378
+ end
379
+ end
380
+
381
+ describe 'when no explicit label is provided' do
382
+ describe 'when no I18n-localized label is provided' do
383
+ before do
384
+ ::I18n.backend.store_translations :en, :formtastic => {
385
+ :update => 'Save %{model}',
386
+ :reset => 'Reset %{model}',
387
+ :cancel => 'Cancel %{model}',
388
+ :actions => {
389
+ :message => {
390
+ :submit => 'Submit message',
391
+ :reset => 'Reset message',
392
+ :cancel => 'Cancel message'
393
+ }
394
+ }
395
+ }
396
+ end
397
+
398
+ after do
399
+ ::I18n.backend.reload!
400
+ end
401
+
402
+ it 'should render an input with default I18n-localized label (fallback)' do
403
+ concat(semantic_form_for(@new_post) do |builder|
404
+ concat(builder.action(:submit, :as => :generic))
405
+ concat(builder.action(:reset, :as => :generic))
406
+ concat(builder.action(:cancel, :as => :generic))
407
+ end)
408
+ output_buffer.should have_tag('li.generic_action input[@value="Save Post"]')
409
+ output_buffer.should have_tag('li.generic_action input[@value="Reset Post"]')
410
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel Post"]')
411
+ end
412
+
413
+ it 'should render an input with custom resource name localized label' do
414
+ concat(semantic_form_for(:post, :as => :message, :url => 'http://example.com') do |builder|
415
+ concat(builder.action(:submit, :as => :generic))
416
+ concat(builder.action(:reset, :as => :generic))
417
+ concat(builder.action(:cancel, :as => :generic))
418
+ end)
419
+ output_buffer.should have_tag('li.generic_action input[@value="Submit message"]')
420
+ output_buffer.should have_tag('li.generic_action input[@value="Cancel message"]')
421
+ output_buffer.should have_tag('li.generic_action input[@value="Reset message"]')
422
+ end
423
+ end
424
+
425
+ describe 'when I18n-localized label is provided' do
426
+ before do
427
+ ::I18n.backend.reload!
428
+ ::I18n.backend.store_translations :en,
429
+ :formtastic => {
430
+ :actions => {
431
+ :update => 'Custom Save',
432
+ :reset => 'Custom Reset',
433
+ :cancel => 'Custom Cancel'
434
+ }
435
+ }
436
+ end
437
+
438
+ after do
439
+ ::I18n.backend.reload!
440
+ end
441
+
442
+ it 'should render an input with localized label (I18n)' do
443
+ with_config :i18n_lookups_by_default, true do
444
+ ::I18n.backend.store_translations :en,
445
+ :formtastic => {
446
+ :actions => {
447
+ :post => {
448
+ :update => 'Custom Save %{model}',
449
+ :reset => 'Custom Reset %{model}',
450
+ :cancel => 'Custom Cancel %{model}'
451
+ }
452
+ }
453
+ }
454
+ concat(semantic_form_for(@new_post) do |builder|
455
+ concat(builder.action(:submit, :as => :generic))
456
+ concat(builder.action(:reset, :as => :generic))
457
+ concat(builder.action(:cancel, :as => :generic))
458
+ end)
459
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Save Post"]})
460
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Reset Post"]})
461
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Cancel Post"]})
462
+ end
463
+ end
464
+
465
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
466
+ with_config :i18n_lookups_by_default, true do
467
+ concat(semantic_form_for(@new_post) do |builder|
468
+ concat(builder.action(:submit, :as => :generic))
469
+ concat(builder.action(:reset, :as => :generic))
470
+ concat(builder.action(:cancel, :as => :generic))
471
+ end)
472
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Save"]})
473
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Reset"]})
474
+ output_buffer.should have_tag(%Q{li.generic_action input[@value="Custom Cancel"]})
475
+ ::I18n.backend.store_translations :en, :formtastic => {}
476
+ end
477
+ end
478
+
479
+ end
480
+ end
481
+ end
482
+ end
483
+
484
+ describe 'when the model is two words' do
485
+
486
+ before do
487
+ output_buffer = ''
488
+ class ::UserPost
489
+ extend ActiveModel::Naming if defined?(ActiveModel::Naming)
490
+ include ActiveModel::Conversion if defined?(ActiveModel::Conversion)
491
+
492
+ def id
493
+ end
494
+
495
+ def persisted?
496
+ end
497
+
498
+ # Rails does crappy human_name
499
+ def self.human_name
500
+ "User post"
501
+ end
502
+ end
503
+ @new_user_post = ::UserPost.new
504
+
505
+ @new_user_post.stub(:new_record?).and_return(true)
506
+ concat(semantic_form_for(@new_user_post, :url => '') do |builder|
507
+ concat(builder.action(:submit, :as => :generic))
508
+ concat(builder.action(:reset, :as => :generic))
509
+ concat(builder.action(:cancel, :as => :generic))
510
+ end)
511
+ end
512
+
513
+ it "should render the string as the value of the button" do
514
+ output_buffer.should have_tag('li input[@value="Create User post"]')
515
+ output_buffer.should have_tag('li input[@value="Reset User post"]')
516
+ output_buffer.should have_tag('li input[@value="Cancel User post"]')
517
+ end
518
+
519
+ end
520
+
521
+ end