formtastic 2.1.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|