formtastic 2.1.0 → 4.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.
- checksums.yaml +7 -0
- data/.gitattributes +1 -0
- data/.github/workflows/test.yml +61 -0
- data/.gitignore +4 -2
- data/CHANGELOG.md +52 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +105 -0
- data/MIT-LICENSE +1 -1
- data/{README.textile → README.md} +204 -219
- data/RELEASE_PROCESS +3 -1
- data/Rakefile +27 -29
- data/app/assets/stylesheets/formtastic.css +3 -2
- data/bin/appraisal +8 -0
- data/formtastic.gemspec +11 -14
- data/gemfiles/rails_5.2/Gemfile +5 -0
- data/gemfiles/rails_6.0/Gemfile +5 -0
- data/gemfiles/rails_6.1/Gemfile +5 -0
- data/gemfiles/rails_edge/Gemfile +13 -0
- data/lib/formtastic/action_class_finder.rb +18 -0
- data/lib/formtastic/actions/button_action.rb +55 -60
- data/lib/formtastic/actions/input_action.rb +59 -57
- data/lib/formtastic/actions/link_action.rb +68 -67
- data/lib/formtastic/actions.rb +6 -3
- data/lib/formtastic/deprecation.rb +5 -0
- data/lib/formtastic/engine.rb +3 -1
- data/lib/formtastic/form_builder.rb +35 -16
- data/lib/formtastic/helpers/action_helper.rb +34 -28
- data/lib/formtastic/helpers/enum.rb +13 -0
- data/lib/formtastic/helpers/errors_helper.rb +2 -2
- data/lib/formtastic/helpers/fieldset_wrapper.rb +16 -12
- data/lib/formtastic/helpers/form_helper.rb +19 -16
- data/lib/formtastic/helpers/input_helper.rb +69 -97
- data/lib/formtastic/helpers/inputs_helper.rb +35 -25
- data/lib/formtastic/helpers/reflection.rb +4 -4
- data/lib/formtastic/helpers.rb +1 -2
- data/lib/formtastic/html_attributes.rb +12 -1
- data/lib/formtastic/i18n.rb +1 -1
- data/lib/formtastic/input_class_finder.rb +18 -0
- data/lib/formtastic/inputs/base/choices.rb +2 -2
- data/lib/formtastic/inputs/base/collections.rb +46 -14
- data/lib/formtastic/inputs/base/database.rb +7 -2
- data/lib/formtastic/inputs/base/datetime_pickerish.rb +85 -0
- data/lib/formtastic/inputs/base/errors.rb +7 -7
- data/lib/formtastic/inputs/base/hints.rb +2 -2
- data/lib/formtastic/inputs/base/html.rb +10 -9
- data/lib/formtastic/inputs/base/labelling.rb +5 -8
- data/lib/formtastic/inputs/base/naming.rb +4 -4
- data/lib/formtastic/inputs/base/numeric.rb +1 -1
- data/lib/formtastic/inputs/base/options.rb +3 -4
- data/lib/formtastic/inputs/base/stringish.rb +10 -2
- data/lib/formtastic/inputs/base/timeish.rb +34 -22
- data/lib/formtastic/inputs/base/validations.rb +41 -13
- data/lib/formtastic/inputs/base/wrapping.rb +29 -26
- data/lib/formtastic/inputs/base.rb +22 -15
- data/lib/formtastic/inputs/boolean_input.rb +26 -12
- data/lib/formtastic/inputs/check_boxes_input.rb +39 -31
- data/lib/formtastic/inputs/color_input.rb +41 -0
- data/lib/formtastic/inputs/country_input.rb +24 -5
- data/lib/formtastic/inputs/datalist_input.rb +41 -0
- data/lib/formtastic/inputs/date_picker_input.rb +93 -0
- data/lib/formtastic/inputs/{date_input.rb → date_select_input.rb} +1 -1
- data/lib/formtastic/inputs/datetime_picker_input.rb +103 -0
- data/lib/formtastic/inputs/{datetime_input.rb → datetime_select_input.rb} +1 -1
- data/lib/formtastic/inputs/file_input.rb +2 -2
- data/lib/formtastic/inputs/hidden_input.rb +2 -6
- data/lib/formtastic/inputs/radio_input.rb +28 -22
- data/lib/formtastic/inputs/select_input.rb +36 -39
- data/lib/formtastic/inputs/time_picker_input.rb +99 -0
- data/lib/formtastic/inputs/{time_input.rb → time_select_input.rb} +6 -2
- data/lib/formtastic/inputs/time_zone_input.rb +16 -6
- data/lib/formtastic/inputs.rb +32 -21
- data/lib/formtastic/localized_string.rb +1 -1
- data/lib/formtastic/localizer.rb +24 -24
- data/lib/formtastic/namespaced_class_finder.rb +99 -0
- data/lib/formtastic/version.rb +1 -1
- data/lib/formtastic.rb +20 -10
- data/lib/generators/formtastic/form/form_generator.rb +10 -4
- data/lib/generators/formtastic/input/input_generator.rb +46 -0
- data/lib/generators/formtastic/install/install_generator.rb +5 -19
- data/lib/generators/templates/_form.html.slim +2 -2
- data/lib/generators/templates/formtastic.rb +46 -25
- data/lib/generators/templates/input.rb +19 -0
- data/sample/basic_inputs.html +23 -3
- data/script/integration-template.rb +74 -0
- data/script/integration.sh +19 -0
- data/spec/action_class_finder_spec.rb +12 -0
- data/spec/actions/button_action_spec.rb +8 -8
- data/spec/actions/generic_action_spec.rb +92 -56
- data/spec/actions/input_action_spec.rb +7 -7
- data/spec/actions/link_action_spec.rb +10 -10
- data/spec/builder/custom_builder_spec.rb +36 -20
- data/spec/builder/error_proc_spec.rb +4 -4
- data/spec/builder/semantic_fields_for_spec.rb +28 -29
- data/spec/fast_spec_helper.rb +12 -0
- data/spec/generators/formtastic/form/form_generator_spec.rb +45 -32
- data/spec/generators/formtastic/input/input_generator_spec.rb +124 -0
- data/spec/generators/formtastic/install/install_generator_spec.rb +9 -9
- data/spec/helpers/action_helper_spec.rb +75 -103
- data/spec/helpers/actions_helper_spec.rb +17 -17
- data/spec/helpers/form_helper_spec.rb +84 -33
- data/spec/helpers/input_helper_spec.rb +333 -285
- data/spec/helpers/inputs_helper_spec.rb +167 -121
- data/spec/helpers/reflection_helper_spec.rb +3 -3
- data/spec/helpers/semantic_errors_helper_spec.rb +23 -23
- data/spec/i18n_spec.rb +26 -26
- data/spec/input_class_finder_spec.rb +10 -0
- data/spec/inputs/base/collections_spec.rb +76 -0
- data/spec/inputs/base/validations_spec.rb +480 -0
- data/spec/inputs/boolean_input_spec.rb +100 -65
- data/spec/inputs/check_boxes_input_spec.rb +200 -101
- data/spec/inputs/color_input_spec.rb +85 -0
- data/spec/inputs/country_input_spec.rb +20 -20
- data/spec/inputs/custom_input_spec.rb +3 -4
- data/spec/inputs/datalist_input_spec.rb +61 -0
- data/spec/inputs/date_picker_input_spec.rb +449 -0
- data/spec/inputs/date_select_input_spec.rb +249 -0
- data/spec/inputs/datetime_picker_input_spec.rb +490 -0
- data/spec/inputs/datetime_select_input_spec.rb +209 -0
- data/spec/inputs/email_input_spec.rb +5 -5
- data/spec/inputs/file_input_spec.rb +6 -6
- data/spec/inputs/hidden_input_spec.rb +22 -35
- data/spec/inputs/include_blank_spec.rb +11 -11
- data/spec/inputs/label_spec.rb +62 -25
- data/spec/inputs/number_input_spec.rb +112 -112
- data/spec/inputs/password_input_spec.rb +5 -5
- data/spec/inputs/phone_input_spec.rb +5 -5
- data/spec/inputs/placeholder_spec.rb +6 -6
- data/spec/inputs/radio_input_spec.rb +99 -55
- data/spec/inputs/range_input_spec.rb +66 -66
- data/spec/inputs/readonly_spec.rb +50 -0
- data/spec/inputs/search_input_spec.rb +5 -5
- data/spec/inputs/select_input_spec.rb +170 -170
- data/spec/inputs/string_input_spec.rb +68 -16
- data/spec/inputs/text_input_spec.rb +16 -16
- data/spec/inputs/time_picker_input_spec.rb +455 -0
- data/spec/inputs/time_select_input_spec.rb +261 -0
- data/spec/inputs/time_zone_input_spec.rb +54 -28
- data/spec/inputs/url_input_spec.rb +5 -5
- data/spec/inputs/with_options_spec.rb +7 -7
- data/spec/localizer_spec.rb +39 -17
- data/spec/namespaced_class_finder_spec.rb +79 -0
- data/spec/schema.rb +21 -0
- data/spec/spec_helper.rb +254 -221
- data/spec/support/custom_macros.rb +128 -95
- data/spec/support/shared_examples.rb +12 -0
- data/spec/support/specialized_class_finder_shared_example.rb +27 -0
- data/spec/support/test_environment.rb +26 -10
- metadata +177 -238
- data/.travis.yml +0 -8
- data/Appraisals +0 -11
- data/CHANGELOG +0 -371
- data/gemfiles/rails-3.0.gemfile +0 -7
- data/gemfiles/rails-3.1.gemfile +0 -7
- data/gemfiles/rails-3.2.gemfile +0 -7
- data/lib/formtastic/helpers/buttons_helper.rb +0 -310
- data/lib/formtastic/inputs/base/grouped_collections.rb +0 -77
- data/lib/formtastic/util.rb +0 -25
- data/lib/tasks/verify_rcov.rb +0 -44
- data/spec/helpers/buttons_helper_spec.rb +0 -166
- data/spec/helpers/commit_button_helper_spec.rb +0 -530
- data/spec/inputs/date_input_spec.rb +0 -227
- data/spec/inputs/datetime_input_spec.rb +0 -185
- data/spec/inputs/time_input_spec.rb +0 -267
- data/spec/support/deferred_garbage_collection.rb +0 -21
|
@@ -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
|
|
@@ -6,7 +6,7 @@ module Formtastic
|
|
|
6
6
|
# own `time_select`.
|
|
7
7
|
#
|
|
8
8
|
# @see Formtastic::Inputs::Base::Timeish Timeish module for documentation of date, time and datetime input options.
|
|
9
|
-
class
|
|
9
|
+
class TimeSelectInput
|
|
10
10
|
include Base
|
|
11
11
|
include Base::Timeish
|
|
12
12
|
|
|
@@ -15,8 +15,12 @@ module Formtastic
|
|
|
15
15
|
time_fragments
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def value_or_default_value
|
|
19
|
+
value ? value : Time.current
|
|
20
|
+
end
|
|
21
|
+
|
|
18
22
|
def fragment_value(fragment)
|
|
19
|
-
|
|
23
|
+
value_or_default_value.send(fragment)
|
|
20
24
|
end
|
|
21
25
|
|
|
22
26
|
def hidden_fragments
|
|
@@ -28,9 +28,19 @@ module Formtastic
|
|
|
28
28
|
#
|
|
29
29
|
# @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
|
|
30
30
|
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
|
|
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
|
|
34
44
|
include Base
|
|
35
45
|
|
|
36
46
|
def to_html
|
|
@@ -39,10 +49,10 @@ module Formtastic
|
|
|
39
49
|
builder.time_zone_select(method, priority_zones, input_options, input_html_options)
|
|
40
50
|
end
|
|
41
51
|
end
|
|
42
|
-
|
|
52
|
+
|
|
43
53
|
def priority_zones
|
|
44
|
-
options[:priority_zones] ||
|
|
54
|
+
options[:priority_zones] || Formtastic::FormBuilder.priority_time_zones
|
|
45
55
|
end
|
|
46
56
|
end
|
|
47
57
|
end
|
|
48
|
-
end
|
|
58
|
+
end
|
data/lib/formtastic/inputs.rb
CHANGED
|
@@ -4,28 +4,39 @@ module Formtastic
|
|
|
4
4
|
|
|
5
5
|
autoload :Base
|
|
6
6
|
autoload :Basic
|
|
7
|
-
autoload :BooleanInput
|
|
8
|
-
autoload :CheckBoxesInput
|
|
9
|
-
autoload :CountryInput
|
|
10
|
-
autoload :DateInput
|
|
11
|
-
autoload :DatetimeInput
|
|
12
|
-
autoload :EmailInput
|
|
13
|
-
autoload :FileInput
|
|
14
|
-
autoload :HiddenInput
|
|
15
|
-
autoload :NumberInput
|
|
16
|
-
autoload :NumericInput
|
|
17
|
-
autoload :PasswordInput
|
|
18
|
-
autoload :PhoneInput
|
|
19
|
-
autoload :RadioInput
|
|
20
|
-
autoload :RangeInput
|
|
21
|
-
autoload :SearchInput
|
|
22
|
-
autoload :SelectInput
|
|
23
|
-
autoload :StringInput
|
|
24
|
-
autoload :TextInput
|
|
25
|
-
autoload :TimeInput
|
|
26
|
-
autoload :TimeZoneInput
|
|
27
7
|
autoload :Timeish
|
|
28
|
-
|
|
8
|
+
|
|
9
|
+
eager_autoload do
|
|
10
|
+
autoload :BooleanInput
|
|
11
|
+
autoload :CheckBoxesInput
|
|
12
|
+
autoload :ColorInput
|
|
13
|
+
autoload :CountryInput
|
|
14
|
+
autoload :DatalistInput
|
|
15
|
+
autoload :DateInput
|
|
16
|
+
autoload :DatePickerInput
|
|
17
|
+
autoload :DatetimePickerInput
|
|
18
|
+
autoload :DateSelectInput
|
|
19
|
+
autoload :DatetimeInput
|
|
20
|
+
autoload :DatetimeSelectInput
|
|
21
|
+
autoload :EmailInput
|
|
22
|
+
autoload :FileInput
|
|
23
|
+
autoload :HiddenInput
|
|
24
|
+
autoload :NumberInput
|
|
25
|
+
autoload :NumericInput
|
|
26
|
+
autoload :PasswordInput
|
|
27
|
+
autoload :PhoneInput
|
|
28
|
+
autoload :RadioInput
|
|
29
|
+
autoload :RangeInput
|
|
30
|
+
autoload :SearchInput
|
|
31
|
+
autoload :SelectInput
|
|
32
|
+
autoload :StringInput
|
|
33
|
+
autoload :TextInput
|
|
34
|
+
autoload :TimeInput
|
|
35
|
+
autoload :TimePickerInput
|
|
36
|
+
autoload :TimeSelectInput
|
|
37
|
+
autoload :TimeZoneInput
|
|
38
|
+
autoload :UrlInput
|
|
39
|
+
end
|
|
29
40
|
end
|
|
30
41
|
end
|
|
31
42
|
|
|
@@ -7,7 +7,7 @@ module Formtastic
|
|
|
7
7
|
|
|
8
8
|
protected
|
|
9
9
|
|
|
10
|
-
def localized_string(key, value, type, options = {})
|
|
10
|
+
def localized_string(key, value, type, options = {}) # @private
|
|
11
11
|
current_builder = respond_to?(:builder) ? builder : self
|
|
12
12
|
localizer = Formtastic::FormBuilder.i18n_localizer.new(current_builder)
|
|
13
13
|
localizer.localize(key, value, type, options)
|
data/lib/formtastic/localizer.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module Formtastic
|
|
2
|
-
# Implementation for looking up localized values within Formtastic using I18n, if no
|
|
2
|
+
# Implementation for looking up localized values within Formtastic using I18n, if no
|
|
3
3
|
# explicit value (like the `:label` option) is set and I18n-lookups are enabled in the
|
|
4
4
|
# configuration.
|
|
5
5
|
#
|
|
@@ -28,50 +28,50 @@ module Formtastic
|
|
|
28
28
|
def get(key)
|
|
29
29
|
cache[key]
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
def has_key?(key)
|
|
33
33
|
cache.has_key?(key)
|
|
34
34
|
end
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
def set(key, result)
|
|
37
37
|
cache[key] = result
|
|
38
38
|
end
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
def cache
|
|
41
41
|
@cache ||= {}
|
|
42
42
|
end
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
def clear!
|
|
45
45
|
cache.clear
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
attr_accessor :builder
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
def self.cache
|
|
52
52
|
@cache ||= Cache.new
|
|
53
53
|
end
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
def initialize(current_builder)
|
|
56
|
-
self.builder = current_builder
|
|
56
|
+
self.builder = current_builder
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
def localize(key, value, type, options = {})
|
|
59
|
+
def localize(key, value, type, options = {}) # @private
|
|
60
60
|
key = value if value.is_a?(::Symbol)
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
if value.is_a?(::String)
|
|
63
63
|
escape_html_entities(value)
|
|
64
64
|
else
|
|
65
65
|
use_i18n = value.nil? ? i18n_lookups_by_default : (value != false)
|
|
66
66
|
use_cache = i18n_cache_lookups
|
|
67
67
|
cache = self.class.cache
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
if use_i18n
|
|
70
70
|
model_name, nested_model_name = normalize_model_name(builder.model_name.underscore)
|
|
71
71
|
|
|
72
72
|
action_name = builder.template.params[:action].to_s rescue ''
|
|
73
73
|
attribute_name = key.to_s
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
# look in the cache first
|
|
76
76
|
if use_cache
|
|
77
77
|
cache_key = [::I18n.locale, action_name, model_name, nested_model_name, attribute_name, key, value, type, options]
|
|
@@ -86,7 +86,7 @@ module Formtastic
|
|
|
86
86
|
i18n_path.gsub!('%{model}', model_name)
|
|
87
87
|
i18n_path.gsub!('%{nested_model}', nested_model_name) unless nested_model_name.nil?
|
|
88
88
|
i18n_path.gsub!('%{attribute}', attribute_name)
|
|
89
|
-
i18n_path.
|
|
89
|
+
i18n_path.tr!('..', '.')
|
|
90
90
|
i18n_path.to_sym
|
|
91
91
|
end
|
|
92
92
|
defaults << ''
|
|
@@ -101,9 +101,9 @@ module Formtastic
|
|
|
101
101
|
# This is effectively what Rails label helper does for i18n lookup
|
|
102
102
|
options[:scope] = [:helpers, type]
|
|
103
103
|
options[:default] = defaults
|
|
104
|
-
i18n_value = ::I18n.t(default_key, options)
|
|
104
|
+
i18n_value = ::I18n.t(default_key, **options)
|
|
105
105
|
end
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
# save the result to the cache
|
|
108
108
|
result = (i18n_value.is_a?(::String) && i18n_value.present?) ? escape_html_entities(i18n_value) : nil
|
|
109
109
|
cache.set(cache_key, result) if use_cache
|
|
@@ -115,14 +115,14 @@ module Formtastic
|
|
|
115
115
|
protected
|
|
116
116
|
|
|
117
117
|
def normalize_model_name(name)
|
|
118
|
-
if
|
|
119
|
-
#
|
|
120
|
-
|
|
121
|
-
elsif name =~ /(.+)\[(.+)\]/
|
|
122
|
-
# Rails 3 (and 3.1?) nested builder case with :post rather than @post
|
|
118
|
+
if name =~ /(.+)\[(.+)\]/
|
|
119
|
+
# Nested builder case with :post rather than @post
|
|
120
|
+
# TODO: check if this is no longer required with a minimum of Rails 4.1
|
|
123
121
|
[$1, $2]
|
|
122
|
+
elsif builder.respond_to?(:options) && builder.options.key?(:as)
|
|
123
|
+
[builder.options[:as].to_s]
|
|
124
124
|
elsif builder.respond_to?(:options) && builder.options.key?(:parent_builder)
|
|
125
|
-
# Rails 3.0 nested builder work-around case, where :parent_builder is provided by f.semantic_form_for
|
|
125
|
+
# Rails 3.0+ nested builder work-around case, where :parent_builder is provided by f.semantic_form_for
|
|
126
126
|
[builder.options[:parent_builder].object_name.to_s, name]
|
|
127
127
|
else
|
|
128
128
|
# Non-nested case
|
|
@@ -130,7 +130,7 @@ module Formtastic
|
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
def escape_html_entities(string)
|
|
133
|
+
def escape_html_entities(string) # @private
|
|
134
134
|
if (builder.escape_html_entities_in_hints_and_labels) ||
|
|
135
135
|
(self.respond_to?(:escape_html_entities_in_hints_and_labels) && escape_html_entities_in_hints_and_labels)
|
|
136
136
|
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
|
|
@@ -141,7 +141,7 @@ module Formtastic
|
|
|
141
141
|
def i18n_lookups_by_default
|
|
142
142
|
builder.i18n_lookups_by_default
|
|
143
143
|
end
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
def i18n_cache_lookups
|
|
146
146
|
builder.i18n_cache_lookups
|
|
147
147
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Formtastic
|
|
2
|
+
# This class implements class resolution in a namespace chain. It
|
|
3
|
+
# is used both by Formtastic::Helpers::InputHelper and
|
|
4
|
+
# Formtastic::Helpers::ActionHelper to look up action and input classes.
|
|
5
|
+
#
|
|
6
|
+
# @example Implementing own class finder
|
|
7
|
+
# # You can implement own class finder that for example prefixes the class name or uses custom module.
|
|
8
|
+
# class MyInputClassFinder < Formtastic::NamespacedClassFinder
|
|
9
|
+
# def initialize(namespaces)
|
|
10
|
+
# super [MyNamespace] + namespaces # first lookup in MyNamespace then the defaults
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# private
|
|
14
|
+
#
|
|
15
|
+
# def class_name(as)
|
|
16
|
+
# "My#{super}Input" # for example MyStringInput
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# # in config/initializers/formtastic.rb
|
|
21
|
+
# Formtastic::FormBuilder.input_class_finder = MyInputClassFinder
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
class NamespacedClassFinder
|
|
25
|
+
attr_reader :namespaces # @private
|
|
26
|
+
|
|
27
|
+
# @private
|
|
28
|
+
class NotFoundError < NameError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.use_const_defined?
|
|
32
|
+
defined?(Rails) && ::Rails.application && ::Rails.application.config.respond_to?(:eager_load) && ::Rails.application.config.eager_load
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @param namespaces [Array<Module>]
|
|
36
|
+
def initialize(namespaces)
|
|
37
|
+
@namespaces = namespaces.flatten
|
|
38
|
+
@cache = {}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Looks up the given reference in the configured namespaces.
|
|
42
|
+
#
|
|
43
|
+
# Two finder methods are provided, one for development tries to
|
|
44
|
+
# reference the constant directly, triggering Rails' autoloading
|
|
45
|
+
# const_missing machinery; the second one instead for production
|
|
46
|
+
# checks with .const_defined before referencing the constant.
|
|
47
|
+
#
|
|
48
|
+
def find(as)
|
|
49
|
+
@cache[as] ||= resolve(as)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def resolve(as)
|
|
53
|
+
class_name = class_name(as)
|
|
54
|
+
|
|
55
|
+
finder(class_name) or raise NotFoundError, "class #{class_name}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Converts symbol to class name
|
|
59
|
+
# Overridden in subclasses to create `StringInput` and `ButtonAction`
|
|
60
|
+
# @example
|
|
61
|
+
# class_name(:string) == "String"
|
|
62
|
+
|
|
63
|
+
def class_name(as)
|
|
64
|
+
as.to_s.camelize
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
if use_const_defined?
|
|
70
|
+
def finder(class_name) # @private
|
|
71
|
+
find_with_const_defined(class_name)
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
def finder(class_name) # @private
|
|
75
|
+
find_by_trying(class_name)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Looks up the given class name in the configured namespaces in order,
|
|
80
|
+
# returning the first one that has the class name constant defined.
|
|
81
|
+
def find_with_const_defined(class_name)
|
|
82
|
+
@namespaces.find do |namespace|
|
|
83
|
+
if namespace.const_defined?(class_name)
|
|
84
|
+
break namespace.const_get(class_name)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Use auto-loading in development environment
|
|
90
|
+
def find_by_trying(class_name)
|
|
91
|
+
@namespaces.find do |namespace|
|
|
92
|
+
begin
|
|
93
|
+
break namespace.const_get(class_name)
|
|
94
|
+
rescue NameError
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
data/lib/formtastic/version.rb
CHANGED
data/lib/formtastic.rb
CHANGED
|
@@ -4,30 +4,40 @@ require 'formtastic/engine' if defined?(::Rails)
|
|
|
4
4
|
module Formtastic
|
|
5
5
|
extend ActiveSupport::Autoload
|
|
6
6
|
|
|
7
|
-
autoload :FormBuilder
|
|
8
7
|
autoload :Helpers
|
|
9
8
|
autoload :HtmlAttributes
|
|
10
|
-
autoload :I18n
|
|
11
|
-
autoload :Inputs
|
|
12
|
-
autoload :Actions
|
|
13
9
|
autoload :LocalizedString
|
|
14
10
|
autoload :Localizer
|
|
15
|
-
autoload :
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
autoload :NamespacedClassFinder
|
|
12
|
+
autoload :InputClassFinder
|
|
13
|
+
autoload :ActionClassFinder
|
|
14
|
+
autoload :Deprecation
|
|
15
|
+
|
|
16
|
+
eager_autoload do
|
|
17
|
+
autoload :I18n
|
|
18
|
+
autoload :FormBuilder
|
|
19
|
+
autoload :Inputs
|
|
20
|
+
autoload :Actions
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @public
|
|
18
24
|
class UnknownInputError < NameError
|
|
19
25
|
end
|
|
20
|
-
|
|
26
|
+
|
|
21
27
|
# @private
|
|
22
28
|
class UnknownActionError < NameError
|
|
23
29
|
end
|
|
24
|
-
|
|
30
|
+
|
|
25
31
|
# @private
|
|
26
32
|
class PolymorphicInputWithoutCollectionError < ArgumentError
|
|
27
33
|
end
|
|
28
|
-
|
|
34
|
+
|
|
29
35
|
# @private
|
|
30
36
|
class UnsupportedMethodForAction < ArgumentError
|
|
31
37
|
end
|
|
32
38
|
|
|
39
|
+
# @private
|
|
40
|
+
class UnsupportedEnumCollection < NameError
|
|
41
|
+
end
|
|
42
|
+
|
|
33
43
|
end
|
|
@@ -4,14 +4,20 @@ module Formtastic
|
|
|
4
4
|
# files without confirmation.
|
|
5
5
|
#
|
|
6
6
|
# @example
|
|
7
|
+
# !!!shell
|
|
7
8
|
# $ rails generate formtastic:form Post
|
|
8
9
|
# @example Copy the partial code to the pasteboard rather than generating a partial
|
|
10
|
+
# !!!shell
|
|
9
11
|
# $ rails generate formtastic:form Post --copy
|
|
10
|
-
# @example Return HAML output instead of default
|
|
11
|
-
#
|
|
12
|
+
# @example Return HAML or Slim output instead of default ERB
|
|
13
|
+
# !!!shell
|
|
14
|
+
# $ rails generate formtastic:form Post --template-engine haml
|
|
15
|
+
# $ rails generate formtastic:form Post --template-engine slim
|
|
12
16
|
# @example Generate a form for specific model attributes
|
|
17
|
+
# !!!shell
|
|
13
18
|
# $ rails generate formtastic:form Post title:string body:text
|
|
14
19
|
# @example Generate a form for a specific controller
|
|
20
|
+
# !!!shell
|
|
15
21
|
# $ rails generate formtastic:form Post --controller admin/posts
|
|
16
22
|
class FormGenerator < Rails::Generators::NamedBase
|
|
17
23
|
desc "Generates a Formtastic form partial based on an existing model."
|
|
@@ -69,7 +75,7 @@ module Formtastic
|
|
|
69
75
|
# Skips Active Record Timestamps.
|
|
70
76
|
def content_columns
|
|
71
77
|
model.content_columns.select do |column|
|
|
72
|
-
!Formtastic::
|
|
78
|
+
!Formtastic::FormBuilder.skipped_columns.include? column.name.to_sym
|
|
73
79
|
end
|
|
74
80
|
end
|
|
75
81
|
|
|
@@ -102,4 +108,4 @@ module Formtastic
|
|
|
102
108
|
end
|
|
103
109
|
|
|
104
110
|
end
|
|
105
|
-
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Formtastic
|
|
2
|
+
|
|
3
|
+
# Modify existing inputs, subclass them, or create your own from scratch.
|
|
4
|
+
# @example
|
|
5
|
+
# !!!shell
|
|
6
|
+
# $ rails generate formtastic:input HatSize
|
|
7
|
+
|
|
8
|
+
# @example Define input name using underscore convention
|
|
9
|
+
# !!!shell
|
|
10
|
+
# $ rails generate formtastic:input hat_size
|
|
11
|
+
|
|
12
|
+
# @example Override an existing input behavior
|
|
13
|
+
# !!!shell
|
|
14
|
+
# $ rails generate formtastic:input string --extend
|
|
15
|
+
|
|
16
|
+
# @example Extend an existing input behavior
|
|
17
|
+
# !!!shell
|
|
18
|
+
# $ rails generate formtastic:input FlexibleText --extend string
|
|
19
|
+
class InputGenerator < Rails::Generators::NamedBase
|
|
20
|
+
|
|
21
|
+
argument :name, :type => :string, :required => true, :banner => 'FILE_NAME'
|
|
22
|
+
|
|
23
|
+
source_root File.expand_path('../../../templates', __FILE__)
|
|
24
|
+
|
|
25
|
+
class_option :extend
|
|
26
|
+
|
|
27
|
+
def create
|
|
28
|
+
normalize_file_name
|
|
29
|
+
define_extension_sentence
|
|
30
|
+
template "input.rb", "app/inputs/#{name.underscore}_input.rb"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def normalize_file_name
|
|
36
|
+
name.chomp!("Input") if name.ends_with?("Input")
|
|
37
|
+
name.chomp!("_input") if name.ends_with?("_input")
|
|
38
|
+
name.chomp!("input") if name.ends_with?("input")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def define_extension_sentence
|
|
42
|
+
@extension_sentence = "< Formtastic::Inputs::#{name.camelize}Input" if options[:extend] == "extend"
|
|
43
|
+
@extension_sentence ||= "< Formtastic::Inputs::#{options[:extend].camelize}Input" if options[:extend]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -1,32 +1,18 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
3
|
module Formtastic
|
|
4
|
-
# Copies
|
|
5
|
-
# to config/initializers/formtastic.rb (all Rails versions).
|
|
4
|
+
# Copies a config initializer to config/initializers/formtastic.rb
|
|
6
5
|
#
|
|
7
6
|
# @example
|
|
7
|
+
# !!!shell
|
|
8
8
|
# $ rails generate formtastic:install
|
|
9
|
-
#
|
|
10
|
-
# @todo Test with Rails 3.0
|
|
11
9
|
class InstallGenerator < Rails::Generators::Base
|
|
12
10
|
source_root File.expand_path('../../../templates', __FILE__)
|
|
13
11
|
class_option :template_engine
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def copy_files
|
|
19
|
-
copy_file 'formtastic.rb', 'config/initializers/formtastic.rb'
|
|
20
|
-
end
|
|
21
|
-
else
|
|
22
|
-
# Rails 3.0 doesn't have an asset pipeline, so we copy in CSS too
|
|
23
|
-
desc "Copies some CSS files to public/stylesheets/ and a config initializer to config/initializers/formtastic.rb"
|
|
24
|
-
def copy_files
|
|
25
|
-
template 'formtastic.rb', 'config/initializers/formtastic.rb'
|
|
26
|
-
template '../../../app/assets/stylesheets/formtastic.css', 'public/stylesheets/formtastic.css'
|
|
27
|
-
template '../../../app/assets/stylesheets/formtastic_ie6.css', 'public/stylesheets/formtastic_ie6.css'
|
|
28
|
-
template '../../../app/assets/stylesheets/formtastic_ie7.css', 'public/stylesheets/formtastic_ie7.css'
|
|
29
|
-
end
|
|
13
|
+
desc "Copies a config initializer to config/initializers/formtastic.rb"
|
|
14
|
+
def copy_files
|
|
15
|
+
copy_file 'formtastic.rb', 'config/initializers/formtastic.rb'
|
|
30
16
|
end
|
|
31
17
|
|
|
32
18
|
def copy_scaffold_template
|