nuatt-formtastic 0.2.2 → 0.2.3

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 (68) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +635 -0
  3. data/lib/formtastic.rb +24 -0
  4. data/lib/formtastic/form_builder.rb +75 -0
  5. data/lib/formtastic/helpers.rb +15 -0
  6. data/lib/formtastic/helpers/buttons_helper.rb +277 -0
  7. data/lib/formtastic/helpers/errors_helper.rb +124 -0
  8. data/lib/formtastic/helpers/fieldset_wrapper.rb +62 -0
  9. data/lib/formtastic/helpers/file_column_detection.rb +16 -0
  10. data/lib/formtastic/helpers/form_helper.rb +221 -0
  11. data/lib/formtastic/helpers/input_helper.rb +357 -0
  12. data/lib/formtastic/helpers/inputs_helper.rb +381 -0
  13. data/lib/formtastic/helpers/reflection.rb +12 -0
  14. data/lib/formtastic/helpers/semantic_form_helper.rb +11 -0
  15. data/lib/formtastic/html_attributes.rb +21 -0
  16. data/lib/formtastic/i18n.rb +32 -0
  17. data/lib/formtastic/inputs.rb +29 -0
  18. data/lib/formtastic/inputs/base.rb +50 -0
  19. data/lib/formtastic/inputs/base/associations.rb +33 -0
  20. data/lib/formtastic/inputs/base/choices.rb +88 -0
  21. data/lib/formtastic/inputs/base/collections.rb +94 -0
  22. data/lib/formtastic/inputs/base/database.rb +17 -0
  23. data/lib/formtastic/inputs/base/errors.rb +58 -0
  24. data/lib/formtastic/inputs/base/fileish.rb +23 -0
  25. data/lib/formtastic/inputs/base/grouped_collections.rb +77 -0
  26. data/lib/formtastic/inputs/base/hints.rb +31 -0
  27. data/lib/formtastic/inputs/base/html.rb +51 -0
  28. data/lib/formtastic/inputs/base/labelling.rb +53 -0
  29. data/lib/formtastic/inputs/base/naming.rb +54 -0
  30. data/lib/formtastic/inputs/base/options.rb +18 -0
  31. data/lib/formtastic/inputs/base/stringish.rb +30 -0
  32. data/lib/formtastic/inputs/base/timeish.rb +125 -0
  33. data/lib/formtastic/inputs/base/validations.rb +125 -0
  34. data/lib/formtastic/inputs/base/wrapping.rb +38 -0
  35. data/lib/formtastic/inputs/boolean_input.rb +87 -0
  36. data/lib/formtastic/inputs/check_boxes_input.rb +169 -0
  37. data/lib/formtastic/inputs/country_input.rb +66 -0
  38. data/lib/formtastic/inputs/date_input.rb +14 -0
  39. data/lib/formtastic/inputs/datetime_input.rb +9 -0
  40. data/lib/formtastic/inputs/email_input.rb +40 -0
  41. data/lib/formtastic/inputs/file_input.rb +42 -0
  42. data/lib/formtastic/inputs/hidden_input.rb +66 -0
  43. data/lib/formtastic/inputs/number_input.rb +72 -0
  44. data/lib/formtastic/inputs/numeric_input.rb +20 -0
  45. data/lib/formtastic/inputs/password_input.rb +40 -0
  46. data/lib/formtastic/inputs/phone_input.rb +41 -0
  47. data/lib/formtastic/inputs/radio_input.rb +146 -0
  48. data/lib/formtastic/inputs/search_input.rb +40 -0
  49. data/lib/formtastic/inputs/select_input.rb +208 -0
  50. data/lib/formtastic/inputs/string_input.rb +34 -0
  51. data/lib/formtastic/inputs/text_input.rb +47 -0
  52. data/lib/formtastic/inputs/time_input.rb +14 -0
  53. data/lib/formtastic/inputs/time_zone_input.rb +48 -0
  54. data/lib/formtastic/inputs/url_input.rb +40 -0
  55. data/lib/formtastic/localized_string.rb +96 -0
  56. data/lib/formtastic/railtie.rb +12 -0
  57. data/lib/formtastic/semantic_form_builder.rb +11 -0
  58. data/lib/formtastic/util.rb +25 -0
  59. data/lib/generators/formtastic/form/form_generator.rb +95 -0
  60. data/lib/generators/formtastic/install/install_generator.rb +23 -0
  61. data/lib/generators/templates/_form.html.erb +7 -0
  62. data/lib/generators/templates/_form.html.haml +5 -0
  63. data/lib/generators/templates/formtastic.css +145 -0
  64. data/lib/generators/templates/formtastic.rb +74 -0
  65. data/lib/generators/templates/formtastic_changes.css +14 -0
  66. data/lib/locale/en.yml +7 -0
  67. data/lib/tasks/verify_rcov.rb +44 -0
  68. metadata +206 -19
@@ -0,0 +1,34 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a `<input type="text">` wrapped in the standard
5
+ # `<li>` wrapper. This is the default input choice for database columns of the `:string` type,
6
+ # and is the default choice for all inputs when no other logical input type can be inferred.
7
+ # You can force any input to be a string input with `:as => :string`.
8
+ #
9
+ # @example Full form context and output
10
+ #
11
+ # <%= semantic_form_for(@user) do |f| %>
12
+ # <%= f.inputs do %>
13
+ # <%= f.input :first_name, :as => :string %>
14
+ # <% end %>
15
+ # <% end %>
16
+ #
17
+ # <form...>
18
+ # <fieldset>
19
+ # <ol>
20
+ # <li class="string">
21
+ # <label for="user_first_name">First name</label>
22
+ # <input type="text" id="user_first_name" name="user[first_name]">
23
+ # </li>
24
+ # </ol>
25
+ # </fieldset>
26
+ # </form>
27
+ #
28
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
29
+ class StringInput
30
+ include Base
31
+ include Base::Stringish
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,47 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a `<textarea>` wrapped in the standard
5
+ # `<li>` wrapper. This is the default input choice for database columns of the `:text` type,
6
+ # but can forced on any text-like input with `:as => :text`.
7
+ #
8
+ # @example Full form context and output
9
+ #
10
+ # <%= semantic_form_for(@user) do |f| %>
11
+ # <%= f.inputs do %>
12
+ # <%= f.input :first_name, :as => :string %>
13
+ # <% end %>
14
+ # <% end %>
15
+ #
16
+ # <form...>
17
+ # <fieldset>
18
+ # <ol>
19
+ # <li class="string">
20
+ # <label for="user_first_name">First name</label>
21
+ # <input type="text" id="user_first_name" name="user[first_name]">
22
+ # </li>
23
+ # </ol>
24
+ # </fieldset>
25
+ # </form>
26
+ #
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
28
+ class TextInput
29
+ include Base
30
+
31
+ def input_html_options
32
+ {
33
+ :cols => builder.default_text_area_width,
34
+ :rows => builder.default_text_area_height
35
+ }.merge(super)
36
+ end
37
+
38
+ def to_html
39
+ input_wrapping do
40
+ label_html <<
41
+ builder.text_area(method, input_html_options)
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,14 @@
1
+ module Formtastic
2
+ module Inputs
3
+ # @see Formtastic::Inputs::Timeish Timeish module for documetation of date, time and datetime input options.
4
+ class TimeInput
5
+ include Base
6
+ include Base::Timeish
7
+
8
+ # we don't want year / month / day fragments in a time select
9
+ def date_fragments
10
+ []
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a `<label>` with a `<select>` containing a series of time zones (using Rails' own
5
+ # `time_zone_select` helper), wrapped in the standard `<li>` wrapper.
6
+
7
+ # This is the default input choice for attributes matching /time_zone/, but can be applied to
8
+ # any text-like input with `:as => :time_zone`.
9
+ #
10
+ # @example Full form context and output
11
+ #
12
+ # <%= semantic_form_for(@user) do |f| %>
13
+ # <%= f.inputs do %>
14
+ # <%= f.input :time_zone, :as => :time_zone %>
15
+ # <% end %>
16
+ # <% end %>
17
+ #
18
+ # <form...>
19
+ # <fieldset>
20
+ # <ol>
21
+ # <li class="time_zone">
22
+ # <label for="user_time_zone">Time zone</label>
23
+ # <input type="text" id="user_time_zone" name="user[time_zone]">
24
+ # </li>
25
+ # </ol>
26
+ # </fieldset>
27
+ # </form>
28
+ #
29
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
30
+ #
31
+ # @todo document :priority_zones option
32
+ # @todo configurable default :priority_zones?
33
+ class TimeZoneInput
34
+ include Base
35
+
36
+ def to_html
37
+ input_wrapping do
38
+ label_html <<
39
+ builder.time_zone_select(method, priority_zones, input_options, input_html_options)
40
+ end
41
+ end
42
+
43
+ def priority_zones
44
+ options[:priority_zones] || [] # TODO config?
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a HTML5 `<input type="url">` wrapped in the standard
5
+ # `<li>` wrapper. This is the default input choice for all attributes matching
6
+ # `/^url$|^website$|_url$/`, but can be applied to any text-like input with `:as => :url`.
7
+ #
8
+ # @example Full form context and output
9
+ #
10
+ # <%= semantic_form_for(@user) do |f| %>
11
+ # <%= f.inputs do %>
12
+ # <%= f.input :home_page, :as => :url %>
13
+ # <% end %>
14
+ # <% end %>
15
+ #
16
+ # <form...>
17
+ # <fieldset>
18
+ # <ol>
19
+ # <li class="url">
20
+ # <label for="user_home_page">Home page</label>
21
+ # <input type="number" id="user_home_page" name="user[home_page]">
22
+ # </li>
23
+ # </ol>
24
+ # </fieldset>
25
+ # </form>
26
+ #
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
28
+ class UrlInput
29
+ include Base
30
+ include Base::Stringish
31
+
32
+ def to_html
33
+ input_wrapping do
34
+ label_html <<
35
+ builder.url_field(method, input_html_options)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,96 @@
1
+ module Formtastic
2
+ # @private
3
+ module LocalizedString
4
+
5
+ protected
6
+
7
+ # Internal generic method for looking up localized values within Formtastic
8
+ # using I18n, if no explicit value is set and I18n-lookups are enabled.
9
+ #
10
+ # Enabled/Disable this by setting:
11
+ #
12
+ # Formtastic::FormBuilder.i18n_lookups_by_default = true/false
13
+ #
14
+ # Lookup priority:
15
+ #
16
+ # 'formtastic.%{type}.%{model}.%{action}.%{attribute}'
17
+ # 'formtastic.%{type}.%{model}.%{attribute}'
18
+ # 'formtastic.%{type}.%{attribute}'
19
+ #
20
+ # Example:
21
+ #
22
+ # 'formtastic.labels.post.edit.title'
23
+ # 'formtastic.labels.post.title'
24
+ # 'formtastic.labels.title'
25
+ #
26
+ # NOTE: Generic, but only used for form input titles/labels/hints/actions (titles = legends, actions = buttons).
27
+ #
28
+ def localized_string(key, value, type, options = {}) #:nodoc:
29
+ key = value if value.is_a?(::Symbol)
30
+
31
+ if value.is_a?(::String)
32
+ escape_html_entities(value)
33
+ else
34
+ use_i18n = value.nil? ? i18n_lookups_by_default : (value != false)
35
+
36
+ if use_i18n
37
+ model_name, nested_model_name = normalize_model_name(self.model_name.underscore)
38
+ action_name = template.params[:action].to_s rescue ''
39
+ attribute_name = key.to_s
40
+
41
+ defaults = Formtastic::I18n::SCOPES.reject do |i18n_scope|
42
+ nested_model_name.nil? && i18n_scope.match(/nested_model/)
43
+ end.collect do |i18n_scope|
44
+ i18n_path = i18n_scope.dup
45
+ i18n_path.gsub!('%{action}', action_name)
46
+ i18n_path.gsub!('%{model}', model_name)
47
+ i18n_path.gsub!('%{nested_model}', nested_model_name) unless nested_model_name.nil?
48
+ i18n_path.gsub!('%{attribute}', attribute_name)
49
+ i18n_path.gsub!('..', '.')
50
+ i18n_path.to_sym
51
+ end
52
+ defaults << ''
53
+
54
+ defaults.uniq!
55
+
56
+ default_key = defaults.shift
57
+ i18n_value = Formtastic::I18n.t(default_key,
58
+ options.merge(:default => defaults, :scope => type.to_s.pluralize.to_sym))
59
+ if i18n_value.blank? && type == :label
60
+ # This is effectively what Rails label helper does for i18n lookup
61
+ options[:scope] = [:helpers, type]
62
+ options[:default] = defaults
63
+ i18n_value = ::I18n.t(default_key, options)
64
+ end
65
+ i18n_value = escape_html_entities(i18n_value) if i18n_value.is_a?(::String)
66
+ i18n_value.blank? ? nil : i18n_value
67
+ end
68
+ end
69
+ end
70
+
71
+ def model_name
72
+ @object.present? ? @object.class.name : @object_name.to_s.classify
73
+ end
74
+
75
+ def normalize_model_name(name)
76
+ if name =~ /(.+)\[(.+)\]/
77
+ [$1, $2]
78
+ else
79
+ [name]
80
+ end
81
+ end
82
+
83
+ def escape_html_entities(string) #:nodoc:
84
+ if (respond_to?(:builder) && builder.escape_html_entities_in_hints_and_labels) ||
85
+ (self.respond_to?(:escape_html_entities_in_hints_and_labels) && escape_html_entities_in_hints_and_labels)
86
+ string = template.escape_once(string) unless string.respond_to?(:html_safe?) && string.html_safe? == true # Acceppt html_safe flag as indicator to skip escaping
87
+ end
88
+ string
89
+ end
90
+
91
+ def i18n_lookups_by_default
92
+ respond_to?(:builder) ? builder.i18n_lookups_by_default : i18n_lookups_by_default
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module Formtastic
4
+ # @private
5
+ class Railtie < Rails::Railtie
6
+ initializer 'formtastic.initialize' do
7
+ ActiveSupport.on_load(:action_view) do
8
+ include Formtastic::Helpers::FormHelper
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Formtastic
2
+ # Quick hack/shim so that any code expecting the old SemanticFormBuilder class still works.
3
+ # TODO remove from 2.0 with a helpful upgrade path/warning.
4
+ # @private
5
+ class SemanticFormBuilder < Formtastic::FormBuilder
6
+ def initialize(*args)
7
+ ActiveSupport::Deprecation.warn('Formtastic::SemanticFormBuilder has been deprecated in favor of Formtastic::FormBuilder.', caller)
8
+ super
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ # Adapted from the rails3 compatibility shim in Haml 2.2
4
+ module Formtastic
5
+ # @private
6
+ module Util
7
+ extend self
8
+ ## Rails XSS Safety
9
+
10
+ # Returns the given text, marked as being HTML-safe.
11
+ # With older versions of the Rails XSS-safety mechanism,
12
+ # this destructively modifies the HTML-safety of `text`.
13
+ #
14
+ # @param text [String]
15
+ # @return [String] `text`, marked as HTML-safe
16
+ def html_safe(text)
17
+ if text.respond_to?(:html_safe)
18
+ text.html_safe
19
+ else
20
+ text
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+ module Formtastic
3
+ # Generates a Formtastic form partial based on an existing model. It will not overwrite existing
4
+ # files without confirmation.
5
+ #
6
+ # @example
7
+ # $ rails generate formtastic:form Post
8
+ # @example Copy the partial code to the pasteboard rather than generating a partial
9
+ # $ rails generate formtastic:form Post --copy
10
+ # @example Return HAML output instead of ERB
11
+ # $ rails generate formtastic:form Post --haml
12
+ # @example Generate a form for specific model attributes
13
+ # $ rails generate formtastic:form Post title:string body:text
14
+ # @example Generate a form for a specific controller
15
+ # $ rails generate formtastic:form Post --controller admin/posts
16
+ class FormGenerator < Rails::Generators::NamedBase
17
+ desc "Generates a Formtastic form partial based on an existing model."
18
+
19
+ argument :name, :type => :string, :required => true, :banner => 'MyExistingModel'
20
+ argument :attributes, :type => :array, :default => [], :banner => 'attribute attribute'
21
+
22
+ class_option :haml, :type => :boolean, :default => false, :group => :formtastic,
23
+ :desc => "Generate HAML instead of ERB"
24
+
25
+ class_option :partial, :type => :boolean, :default => true, :group => :formtastic,
26
+ :desc => 'Generate a form partial in the model views path (eg `posts/_form.html.erb`)'
27
+
28
+ class_option :copy, :type => :boolean, :default => false, :group => :formtastic,
29
+ :desc => 'Copy the generated code the clipboard instead of generating a partial file."'
30
+
31
+ class_option :controller, :type => :string, :default => false, :group => :formtastic,
32
+ :desc => 'Generate for custom controller/view path - in case model and controller namespace is different, i.e. "admin/posts"'
33
+
34
+ source_root File.expand_path('../../../templates', __FILE__)
35
+
36
+ def create_or_show
37
+ @attributes = reflected_attributes if @attributes.empty?
38
+
39
+ if options[:copy]
40
+ template = File.read("#{self.class.source_root}/_form.html.#{template_type}")
41
+ erb = ERB.new(template, nil, '-')
42
+ generated_code = erb.result(binding).strip rescue nil
43
+ puts "The following code has been to the clipboard, just paste it in your views:" if save_to_clipboard(generated_code)
44
+ puts generated_code || "Error: Nothing generated. Does the model exist?"
45
+ else
46
+ empty_directory "app/views/#{controller_path}"
47
+ template "_form.html.#{template_type}", "app/views/#{controller_path}/_form.html.#{template_type}"
48
+ end
49
+ end
50
+
51
+ protected
52
+
53
+ def template_type
54
+ @template_type ||= options[:haml] ? :haml : :erb
55
+ end
56
+
57
+ def controller_path
58
+ @controller_path ||= if options[:controller]
59
+ options[:controller].underscore
60
+ else
61
+ name.underscore.pluralize
62
+ end
63
+ end
64
+
65
+ def reflected_attributes
66
+ columns = model.content_columns.map{|column| column.name}
67
+ columns += model.reflect_on_all_associations.map{|association| association.name.to_s}
68
+ columns -= %w(created_at updated_at)
69
+ end
70
+
71
+ def model
72
+ @model ||= name.camelize.constantize
73
+ end
74
+
75
+ def save_to_clipboard(data)
76
+ return unless data
77
+
78
+ begin
79
+ case RUBY_PLATFORM
80
+ when /win32/
81
+ require 'win32/clipboard'
82
+ ::Win32::Clipboard.data = data
83
+ when /darwin/ # mac
84
+ `echo "#{data}" | pbcopy`
85
+ else # linux/unix
86
+ `echo "#{data}" | xsel --clipboard` || `echo "#{data}" | xclip`
87
+ end
88
+ rescue LoadError
89
+ false
90
+ else
91
+ true
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ module Formtastic
4
+ # Copies formtastic.css and formtastic_changes.css to public/stylesheets/ and a config initializer
5
+ # to config/initializers/formtastic_config.rb.
6
+ #
7
+ # @example
8
+ # $ rails generate formtastic:install
9
+ #
10
+ # @todo Revisit in Rails 3.1 where public assets are treated differently
11
+ class InstallGenerator < Rails::Generators::Base
12
+ desc "Copies formtastic.css and formtastic_changes.css to public/stylesheets/ and a config initializer to config/initializers/formtastic_config.rb"
13
+
14
+ source_root File.expand_path('../../../templates', __FILE__)
15
+
16
+ def copy_files
17
+ template 'formtastic.rb', 'config/initializers/formtastic.rb'
18
+
19
+ template 'formtastic.css', 'public/stylesheets/formtastic.css'
20
+ template 'formtastic_changes.css', 'public/stylesheets/formtastic_changes.css'
21
+ end
22
+ end
23
+ end