case_form 0.0.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 (88) hide show
  1. data/CHANGELOG.rdoc +1 -0
  2. data/MIT-LICENSE.rdoc +20 -0
  3. data/Manifest +86 -0
  4. data/README.rdoc +0 -0
  5. data/Rakefile +30 -0
  6. data/TODO.rdoc +7 -0
  7. data/case_form.gemspec +31 -0
  8. data/lib/case_form.rb +88 -0
  9. data/lib/case_form/associations.rb +50 -0
  10. data/lib/case_form/buttons.rb +175 -0
  11. data/lib/case_form/core_ext/form_helper.rb +54 -0
  12. data/lib/case_form/core_ext/layout_helper.rb +16 -0
  13. data/lib/case_form/core_ext/sentence_error.rb +38 -0
  14. data/lib/case_form/element.rb +40 -0
  15. data/lib/case_form/element/base.rb +95 -0
  16. data/lib/case_form/element/button.rb +64 -0
  17. data/lib/case_form/element/error.rb +54 -0
  18. data/lib/case_form/element/errors/complex_error.rb +107 -0
  19. data/lib/case_form/element/errors/simple_error.rb +76 -0
  20. data/lib/case_form/element/fieldset.rb +35 -0
  21. data/lib/case_form/element/hint.rb +54 -0
  22. data/lib/case_form/element/input.rb +106 -0
  23. data/lib/case_form/element/inputs/collection/checkbox_input.rb +36 -0
  24. data/lib/case_form/element/inputs/collection/radio_input.rb +27 -0
  25. data/lib/case_form/element/inputs/collection/select_input.rb +22 -0
  26. data/lib/case_form/element/inputs/collection_input.rb +89 -0
  27. data/lib/case_form/element/inputs/datetime/date_input.rb +45 -0
  28. data/lib/case_form/element/inputs/datetime/date_time_input.rb +50 -0
  29. data/lib/case_form/element/inputs/datetime/time_input.rb +34 -0
  30. data/lib/case_form/element/inputs/datetime/time_zone_input.rb +24 -0
  31. data/lib/case_form/element/inputs/file_input.rb +13 -0
  32. data/lib/case_form/element/inputs/hidden_input.rb +17 -0
  33. data/lib/case_form/element/inputs/number_input.rb +42 -0
  34. data/lib/case_form/element/inputs/search_input.rb +32 -0
  35. data/lib/case_form/element/inputs/string_input.rb +18 -0
  36. data/lib/case_form/element/inputs/text_input.rb +19 -0
  37. data/lib/case_form/element/label.rb +52 -0
  38. data/lib/case_form/element/nested_model.rb +105 -0
  39. data/lib/case_form/element/nested_models/handle.rb +18 -0
  40. data/lib/case_form/element/nested_models/handles/destructor_handle.rb +47 -0
  41. data/lib/case_form/element/nested_models/handles/generator_handle.rb +55 -0
  42. data/lib/case_form/element_ext/associationable.rb +54 -0
  43. data/lib/case_form/element_ext/columnable.rb +21 -0
  44. data/lib/case_form/element_ext/naming.rb +17 -0
  45. data/lib/case_form/element_ext/validationable.rb +13 -0
  46. data/lib/case_form/errors.rb +189 -0
  47. data/lib/case_form/form_builder.rb +11 -0
  48. data/lib/case_form/inputs.rb +1095 -0
  49. data/lib/case_form/labels.rb +102 -0
  50. data/lib/case_form/version.rb +6 -0
  51. data/lib/generators/case_form/install_generator.rb +33 -0
  52. data/lib/generators/case_form/templates/case_form.rb +63 -0
  53. data/lib/generators/case_form/templates/javascripts/jquery.case_form.js +10 -0
  54. data/lib/generators/case_form/templates/javascripts/prototype.case_form.js +0 -0
  55. data/lib/generators/case_form/templates/locales/en.yml +28 -0
  56. data/lib/generators/case_form/templates/locales/pl.yml +28 -0
  57. data/lib/generators/case_form/templates/stylesheets/stylesheet.css +93 -0
  58. data/lib/generators/case_form/templates/stylesheets/stylesheet_changes.css +1 -0
  59. data/lib/generators/case_form/uninstall_generator.rb +30 -0
  60. data/rails/init.rb +1 -0
  61. data/test/element/button_test.rb +85 -0
  62. data/test/element/errors/complex_error_test.rb +140 -0
  63. data/test/element/errors/simple_error_test.rb +92 -0
  64. data/test/element/fieldset_test.rb +28 -0
  65. data/test/element/hint_test.rb +81 -0
  66. data/test/element/input_test.rb +197 -0
  67. data/test/element/inputs/collection/checkbox_input_test.rb +176 -0
  68. data/test/element/inputs/collection/radio_input_test.rb +156 -0
  69. data/test/element/inputs/collection/select_input_test.rb +152 -0
  70. data/test/element/inputs/datetime/date_input_test.rb +160 -0
  71. data/test/element/inputs/datetime/datetime_input_test.rb +227 -0
  72. data/test/element/inputs/datetime/time_input_test.rb +72 -0
  73. data/test/element/inputs/datetime/time_zone_input_test.rb +42 -0
  74. data/test/element/inputs/file_input_test.rb +13 -0
  75. data/test/element/inputs/hidden_input_test.rb +13 -0
  76. data/test/element/inputs/number_input_test.rb +50 -0
  77. data/test/element/inputs/search_input_test.rb +13 -0
  78. data/test/element/inputs/string_input_test.rb +33 -0
  79. data/test/element/inputs/text_input_test.rb +13 -0
  80. data/test/element/label_test.rb +62 -0
  81. data/test/element/nested_model_test.rb +163 -0
  82. data/test/element/nested_models/handles/destructor_handle_test.rb +35 -0
  83. data/test/element/nested_models/handles/generator_handle_test.rb +27 -0
  84. data/test/form_builder_test.rb +25 -0
  85. data/test/form_helper_test.rb +15 -0
  86. data/test/lib/models.rb +268 -0
  87. data/test/test_helper.rb +74 -0
  88. metadata +235 -0
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class DateInput < Input
5
+ self.allowed_options -= [:id]
6
+ self.allowed_options << [:placeholder, :readonly, :elements, :separator,
7
+ :year, :start_year, :end_year, :month, :short_month, :day,
8
+ :default, :date, :prompt, :blank, :disabled]
9
+
10
+ private
11
+ def default_options
12
+ options[:elements] ||= [:year, :month, :day]
13
+ options[:order] = options.delete(:elements)
14
+ options[:discard_year] = discard_element?(:year)
15
+ options[:discard_month] = discard_element?(:month)
16
+ options[:discard_day] = discard_element?(:day)
17
+ options[:start_year] ||= nested_date_options(:year, :start, Time.now.year - 10)
18
+ options[:end_year] ||= nested_date_options(:year, :end, Time.now.year + 10)
19
+ options[:use_month_names] = nested_date_options(:month, :names, nil)
20
+ options[:use_short_month] = nested_date_options(:month, :short, false)
21
+ options[:default] ||= options.delete(:date) || nil
22
+ options[:date_separator] = options.delete(:separator) || " - "
23
+ options[:include_blank] = options.delete(:blank) || false
24
+ super
25
+ end
26
+
27
+ def input
28
+ builder.date_select(specific_method, options, html_options)
29
+ end
30
+
31
+ def discard_element?(type)
32
+ case
33
+ when options.has_key?(type)
34
+ (options[type] == false) ? true : false
35
+ when options[:order].include?(type)
36
+ false
37
+ end
38
+ end
39
+
40
+ def nested_date_options(type, option, default)
41
+ options.delete("#{option}_#{type}".to_sym) || (options[type].delete(option) if options[type].present?) || default
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class DateTimeInput < Input
5
+ self.allowed_options -= [:id]
6
+ self.allowed_options << [:placeholder, :readonly, :elements, :disabled,
7
+ :separator, :datetime_separator, :date_separator, :time_separator,
8
+ :year, :start_year, :end_year, :month, :short_month, :day, :hour, :minute, :second,
9
+ :minute_step, :default, :datetime, :prompt, :blank]
10
+
11
+ private
12
+ def default_options
13
+ options[:elements] ||= [:year, :month, :day, :hour, :minute]
14
+ options[:order] = options.delete(:elements)
15
+ options[:discard_year] = discard_element?(:year)
16
+ options[:discard_month] = discard_element?(:month)
17
+ options[:discard_day] = discard_element?(:day)
18
+ options[:discard_hour] = discard_element?(:hour)
19
+ options[:discard_minute] = discard_element?(:minute)
20
+ options[:include_seconds] = discard_element?(:second, false, true)
21
+ options[:start_year] ||= nested_date_options(:year, :start, Time.now.year - 10)
22
+ options[:end_year] ||= nested_date_options(:year, :end, Time.now.year + 10)
23
+ options[:use_month_names] = nested_date_options(:month, :names, nil)
24
+ options[:use_short_month] = nested_date_options(:month, :short, false)
25
+ options[:minute_step] ||= nested_date_options(:minute, :step, 1)
26
+ options[:datetime_separator] ||= options.delete(:separator) || nil
27
+ options[:default] ||= options.delete(:datetime) || nil
28
+ options[:include_blank] = options.delete(:blank) || false
29
+ super
30
+ end
31
+
32
+ def input
33
+ builder.datetime_select(specific_method, options, html_options)
34
+ end
35
+
36
+ def discard_element?(type, t = true, f = false)
37
+ case
38
+ when options.has_key?(type)
39
+ (options[type] == false) ? t : f
40
+ else
41
+ options[:order].include?(type) ? f : t
42
+ end
43
+ end
44
+
45
+ def nested_date_options(type, option, default)
46
+ options.delete("#{option}_#{type}".to_sym) || (options[type].delete(option) if options[type].present?) || default
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class TimeInput < Input
5
+ self.allowed_options -= [:id]
6
+ self.allowed_options << [:placeholder, :readonly, :elements, :separator, :time, :default,
7
+ :prompt, :minute_step, :date, :blank, :disabled]
8
+
9
+ private
10
+ def default_options
11
+ options[:elements] ||= [:hour, :minute]
12
+ options[:time_separator] = options.delete(:separator) || " : "
13
+ options[:include_blank] = options.delete(:blank) || false
14
+ options[:include_seconds] = time_seconds?
15
+ options[:ignore_date] = with_date?
16
+ options[:default] ||= options.delete(:time) || nil
17
+ super
18
+ end
19
+
20
+ def input
21
+ builder.time_select(specific_method, options, html_options)
22
+ end
23
+
24
+ def time_seconds?
25
+ options[:elements].include?(:second) || false
26
+ end
27
+
28
+ def with_date?
29
+ @date ||= options.delete(:date) || false
30
+ !@date
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class TimeZoneInput < Input
5
+ self.allowed_options << [:readonly, :blank, :disabled,
6
+ :priority_zones, :zones, :default, :time_zone]
7
+
8
+ private
9
+ def default_options
10
+ options[:default] = options.delete(:time_zone) || "UTC"
11
+ options[:include_blank] = options.delete(:blank) || false
12
+ super
13
+ end
14
+
15
+ def input
16
+ builder.time_zone_select(specific_method, priority_zones, options, html_options)
17
+ end
18
+
19
+ def priority_zones
20
+ options.delete(:priority_zones) || nil
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class FileInput < Input
5
+ self.allowed_options << [:multiple, :readonly, :disabled]
6
+
7
+ private
8
+ def input
9
+ builder.file_field(specific_method, html_options)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class HiddenInput < Input
5
+ self.allowed_options -= [:autofocus, :required, :label, :hint, :error]
6
+
7
+ def generate
8
+ builder.hidden_field(specific_method, html_options)
9
+ end
10
+
11
+ private
12
+ def default_options
13
+ options[:class] ||= [:input, :hidden]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class NumberInput < Input
5
+ self.allowed_options << [:as, :min, :max, :in, :step, :readonly, :disabled]
6
+
7
+ private
8
+ def default_options
9
+ options[:min] ||= input_limit(:minimum)
10
+ options[:max] ||= input_limit(:maximum)
11
+ options[:step] ||= number_step
12
+ options[:size] ||= CaseForm.input_size
13
+ super
14
+ end
15
+
16
+ def input
17
+ builder.send("#{input_type}_field", specific_method, html_options)
18
+ end
19
+
20
+ def input_limit(type)
21
+ validations = object.class.validators_on(method).select { |v| v.kind == :length }
22
+ if validations.any?
23
+ validations.first.options[type]
24
+ elsif object_column_type?(:decimal)
25
+ value = (10**(object_column.precision - object_column.scale))-number_step
26
+ value = value*(-1) if type == :minimum
27
+ value.to_f
28
+ else
29
+ nil
30
+ end
31
+ end
32
+
33
+ def number_step
34
+ if object_column_type?(:decimal)
35
+ (10**(-object_column.scale)).to_f
36
+ else
37
+ CaseForm.number_step
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class SearchInput < Input
5
+ self.allowed_options -= [:required, :error, :hint]
6
+
7
+ private
8
+ def wrapper_options
9
+ wrapper_options = super
10
+ wrapper_options[:class] << :search
11
+ wrapper_options
12
+ end
13
+
14
+ def contents
15
+ contents = []
16
+ [:label, :input].each do |element|
17
+ if options[element] == false
18
+ options.delete(element)
19
+ next
20
+ else
21
+ contents << send(element)
22
+ end
23
+ end
24
+ contents.join.html_safe
25
+ end
26
+
27
+ def input
28
+ builder.search_field(specific_method, html_options)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,18 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class StringInput < Input
5
+ self.allowed_options << [:as, :size, :placeholder, :pattern, :disabled, :readonly, :maxlength]
6
+
7
+ private
8
+ def default_options
9
+ options[:size] ||= input_size
10
+ super
11
+ end
12
+
13
+ def input
14
+ builder.send("#{input_type}_field", specific_method, html_options)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class TextInput < Input
5
+ self.allowed_options << [:cols, :rows, :readonly, :maxlength, :escape, :disabled, :placeholder]
6
+
7
+ private
8
+ def default_options
9
+ options[:cols] ||= CaseForm.textarea_cols
10
+ options[:rows] ||= CaseForm.textarea_rows
11
+ super
12
+ end
13
+
14
+ def input
15
+ builder.text_area(specific_method, html_options)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,52 @@
1
+ module CaseForm
2
+ module Element
3
+ class Label < Base
4
+ include ElementExt::Validationable
5
+ include ElementExt::Columnable
6
+
7
+ self.allowed_options << [:for, :text, :required]
8
+
9
+ attr_accessor :method
10
+
11
+ # Initialize label object
12
+ #
13
+ def initialize(builder, method, options={})
14
+ @method = method
15
+ super(builder, options)
16
+ end
17
+
18
+ # Generate label with defined text and HTML options
19
+ #
20
+ def generate
21
+ template.label(object_name, method, text, html_options)
22
+ end
23
+
24
+ private
25
+ # Distribute default options for label.
26
+ #
27
+ def default_options
28
+ options[:class] ||= [:label]
29
+ options[:id] ||= "#{sanitized_object_name}_#{specific_method}_label"
30
+ end
31
+
32
+ # Generate label text with optional required symbol.
33
+ #
34
+ def text
35
+ @text = options.delete(:text) || translated_text
36
+ @text += CaseForm.require_symbol if required?
37
+ @text
38
+ end
39
+
40
+ # Translate label text with I18n.
41
+ #
42
+ def translated_text
43
+ lookups = []
44
+ lookups << :"activerecord.attributes.#{object_name}.#{method}"
45
+ lookups << :"activemodel.attributes.#{object_name}.#{method}"
46
+ lookups << :"case_form.attributes.#{object_name}.#{method}"
47
+ lookups << method.to_s.humanize
48
+ I18n.t(lookups.shift, :default => lookups)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,105 @@
1
+ # coding: utf-8
2
+ module CaseForm
3
+ module Element
4
+ class NestedModel < Base
5
+ include ElementExt::Associationable
6
+
7
+ self.allowed_options << [:destructor, :generator, :collection, :fields]
8
+
9
+ attr_accessor :method, :block
10
+
11
+ def initialize(builder, method, options={}, &block)
12
+ @method = validate_nested_attributes_association(method, builder.object)
13
+ @block = block
14
+ super(builder, options)
15
+ end
16
+
17
+ def generate
18
+ contents = []
19
+ contents << nested_model_contents
20
+ contents << builder.new_object(method, :fields => (block.nil? ? options[:fields] : block)) if allow_create?
21
+ contents.join.html_safe
22
+ end
23
+
24
+ private
25
+ def default_options
26
+ super
27
+ options[:custom] = {}
28
+ options[:custom][:association] = method
29
+ options[:collection] ||= default_collection
30
+ options[:fields] ||= default_fields
31
+ end
32
+
33
+ def nested_attributes_method_defined?
34
+ object.respond_to?(:"#{method}_attributes=")
35
+ end
36
+
37
+ def nested_model_contents
38
+ contents = []
39
+ nested_models = [collection].flatten.compact
40
+ nested_models.each do |object|
41
+ contents << nested_model(object)
42
+ end
43
+ Element::Fieldset.new(builder, :class => "#{method}_association").generate(contents.join.html_safe) unless contents.blank?
44
+ end
45
+
46
+ def nested_model(object)
47
+ template.content_tag(:div, nil, :class => "#{method}_association_inputs") do
48
+ builder.case_fields_for(method, object) do |b|
49
+ unless block.nil?
50
+ block.call(b) << (b.destroy_object if allow_destroy?)
51
+ else
52
+ fields = [options[:fields]].flatten
53
+ fields << :_destroy if allow_destroy?
54
+ template.concat(b.attributes(*fields))
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def allow_create?
61
+ if collection_association?
62
+ if options.has_key?(:generator)
63
+ options[:generator] != false
64
+ elsif block.is_a?(Proc)
65
+ false
66
+ else
67
+ true
68
+ end
69
+ else
70
+ false
71
+ end
72
+ end
73
+
74
+ def allow_destroy?
75
+ if collection_association?
76
+ if options.has_key?(:desctructor)
77
+ options[:destructor] != false
78
+ elsif block.is_a?(Proc)
79
+ false
80
+ else
81
+ object.class.nested_attributes_options[method.to_sym][:allow_destroy]
82
+ end
83
+ else
84
+ false
85
+ end
86
+ end
87
+
88
+ def default_collection
89
+ object.send(method) || (new_nested_model unless collection_association?)
90
+ end
91
+
92
+ def default_fields
93
+ association_class.content_columns.map(&:name).map(&:to_sym) - CaseForm.locked_columns
94
+ end
95
+
96
+ def new_nested_model
97
+ collection_association? ? association_class.new : object.send(:"build_#{method}")
98
+ end
99
+
100
+ def collection
101
+ options[:collection]
102
+ end
103
+ end
104
+ end
105
+ end