facades 0.0.3 → 0.0.4

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.
@@ -0,0 +1,212 @@
1
+ module Facades::Builders
2
+ module FormBuilder
3
+ module Base
4
+ # Access the template object
5
+ attr_accessor :template
6
+ # Tracks the order in which fields are used in the form, this allows the easy rebuilding of the submitted form
7
+ # data when submitted since normally the hash isn't ordered.
8
+ attr_accessor :field_order
9
+ # Tracks the field currently being "processed"
10
+ attr_accessor :current_field_type
11
+
12
+
13
+ # Overrides fields_for to make sure the form builder is set properly
14
+ #
15
+ def fields_for(record_or_name_or_array, *args, &block) #:nodoc:
16
+ opts = args.extract_options!
17
+ opts[:builder] ||= ActionView::Base.default_form_builder
18
+ args.push(opts)
19
+ with_custom_error_proc do
20
+ super(record_or_name_or_array, *args, &block)
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ ##
27
+ #
28
+ # Checks to see if a particular attribute is required, if so, a "required" attribute is added to the field.
29
+ #
30
+ # @param [Symbol] attribute The attribute to check against validators
31
+ # @return [Boolean]
32
+ #
33
+ def attribute_required?(attribute)
34
+ validates_presence?(attribute) || validates_inclusion?(attribute)
35
+ end
36
+
37
+ # Convenience method to use the +content_tag+ method from our template
38
+ #
39
+ def content_tag(tag, content, options = {}, escape = true, &block) #:nodoc:
40
+ @template.content_tag(tag, content, options, escape, &block)
41
+ end
42
+
43
+ ##
44
+ # Checks to see if there are errors for the particular method or attribute
45
+ #
46
+ # @param [Symbol] method The method/attribute to check
47
+ #
48
+ # @return [Boolean]
49
+ #
50
+ def errors_on_attribute?(method)
51
+ return false if @object.nil?
52
+ !(@object.errors.empty? || !@object.errors[method.to_sym].present? || [@object.errors[method.to_sym]].flatten.empty?)
53
+ end
54
+
55
+ ##
56
+ #
57
+ # Checks a passed validator to see if it is required
58
+ # 'borrowed' from Formtastic by Justin French (see https://github.com/justinfrench/formtastic)
59
+ #
60
+ # @param [Hash] options Validator options
61
+ #
62
+ def options_require_validation?(options)
63
+
64
+ allow_blank = options[:allow_blank]
65
+ return !allow_blank unless allow_blank.nil?
66
+ if_condition = !options[:if].nil?
67
+ condition = if_condition ? options[:if] : options[:unless]
68
+
69
+ condition = if condition.respond_to?(:call)
70
+ condition.call(@object)
71
+ elsif condition.is_a?(::Symbol) && @object.respond_to?(condition)
72
+ @object.send(condition)
73
+ else
74
+ condition
75
+ end
76
+ if_condition ? !!condition : !condition
77
+ end
78
+
79
+ ##
80
+ #
81
+ # Checks an options hash to determine if a required method/attribute was overridden manually
82
+ # @param [Hash] options The options hash to check
83
+ #
84
+ #
85
+ def required_by_option?(options)
86
+ req = (options.is_a?(Hash) ? options.stringify_keys[:required] : options)
87
+ !(req.to_s === 'false' || req.nil?)
88
+ end
89
+
90
+ ##
91
+ #
92
+ # Wrapper method used by all form fields to customize the output
93
+ #
94
+ # @param [Symbol] helper_method Original Rails helper method name
95
+ # @param [Symbol] method Object method / symbol used for the element
96
+ # @param [Array] args Array of original arguments passed to the helper
97
+ #
98
+ # @return [String] Rendered HTML tag for the element
99
+ #
100
+ def render_field_as_custom(helper_method, method, *args)
101
+
102
+ @current_field_type = helper_method
103
+
104
+ options = args.extract_options!
105
+ (@field_order ||= []) << method
106
+
107
+ # Add an error class to the field if it has errors
108
+ #
109
+ if errors_on_attribute?(method)
110
+ klasses = (options.delete(:class) || "").split(" ")
111
+ klasses << 'field-with-error'
112
+ options[:class] = klasses.join(" ")
113
+ end
114
+
115
+ # Add a required attribute to the field if it is required
116
+ # Skip if false was passed as the required option
117
+ #
118
+ options[:required] = "required" if attribute_required?(method) && options.delete(:required).to_s != 'false'
119
+ options['data-validates-uniqueness'] = "true" if validates_uniqueness?(method)
120
+
121
+ result = send(:"_super_#{helper_method}", method, *(args << options))
122
+ messages = @object.nil? ? [] : @object.errors[method]
123
+ render_field_with_errors(method, result, messages)
124
+
125
+ end
126
+
127
+ ##
128
+ #
129
+ # Renders the passed +html_tag+ with the custom error_template
130
+ #
131
+ # @param [Symbol] method The method/attribute to check for errors
132
+ # @param [Object, String] html_tag Instance of an input tag or a string
133
+ # @param [Array] messages An array of all error messages to be added to the template
134
+ #
135
+ def render_field_with_errors(method, html_tag, messages)
136
+ return html_tag unless errors_on_attribute?(method)
137
+ error_template = %{
138
+ <span class="field-with-errors">
139
+ <%= html_tag %>
140
+ <span class="errors-for-field"><%= [messages].flatten.join(",") %></span>
141
+ </span>}
142
+
143
+ render_binding = binding
144
+ renderer = ERB.new(error_template)
145
+ renderer.result(render_binding).to_s.html_safe
146
+ end
147
+
148
+ ##
149
+ #
150
+ # Compiles an array of all validators for a particular attribute
151
+ # @param [Symbol] attribtue The attribute to check
152
+ #
153
+ def validators_for(attribute)
154
+
155
+ return [] if @object.nil?
156
+ return [] unless @object.class.respond_to?(:validators_on)
157
+
158
+ attribute = attribute.to_s.sub(/_id$/, '').to_sym
159
+ @object.class.validators_on(attribute).uniq
160
+
161
+ end
162
+
163
+ ##
164
+ #
165
+ # Convenience method to see if a particular attribute has validators
166
+ # @param [Symbol] attribute The attribute to check
167
+ #
168
+ def validators_for?(attribute)
169
+ !validators_for(attribute).empty?
170
+ end
171
+
172
+ ##
173
+ #
174
+ # Checks for a presence validation on a particular attribute
175
+ # @param [Symbol] attribute The attribute to check
176
+ #
177
+ def validates_presence?(attribute)
178
+ validator_of_type_exists?(validators_for(attribute), :presence)
179
+ end
180
+
181
+ ##
182
+ #
183
+ # Checks for a uniqueness validation on a particular attribute
184
+ # @param [Symbol] attribute The attribute to check
185
+ #
186
+ def validates_uniqueness?(attribute)
187
+ validator_of_type_exists?(validators_for(attribute), :uniqueness, false)
188
+ end
189
+
190
+ ##
191
+ #
192
+ # Checks for inclusion validation on a particular attribute
193
+ # @param [Symbol] attribute The attribute to check
194
+ #
195
+ def validates_inclusion?(attribute)
196
+ validator_of_type_exists?(validators_for(attribute), :inclusion)
197
+ end
198
+
199
+ private
200
+
201
+ def validator_of_type_exists?(validators, kind, check_options = true) #:nodoc: @private
202
+ validators.detect do |validator|
203
+ exists = (validator.kind.to_s == kind.to_s)
204
+ next exists unless (check_options && exists) && validator.options.present?
205
+ options_require_validation?(validator.options)
206
+ end
207
+ end
208
+
209
+
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,112 @@
1
+ module Facades::Builders
2
+ module FormBuilder
3
+ module Elements
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # create overrides for custom rendering
8
+ [:email_field, :password_field, :text_field, :text_area, :url_field].each do |method|
9
+ class_eval <<-FUNC, __FILE__, __LINE__ + 1
10
+
11
+ alias :_super_#{method} :#{method}
12
+
13
+ def #{method}(method_name, *args)
14
+ render_field_as_custom(:#{method}, method_name, *args)
15
+ end
16
+ FUNC
17
+ end
18
+ end
19
+
20
+ ##
21
+ # Modified label tag to support adding a 'required' asterisk to the end of the label.
22
+ # Same params as the original implementation
23
+ #
24
+ def label(method, text = nil, options = {}, &block) #:nodoc:
25
+
26
+ options, text = text, nil if text.is_a?(Hash)
27
+ text ||= method.to_s.humanize
28
+
29
+ options.stringify_keys!
30
+ klasses = (options.delete(['class']) || "").split(" ")
31
+ klasses << 'field-with-error' if errors_on_attribute?(method)
32
+ options['class'] = klasses.join(" ") unless klasses.compact.empty?
33
+
34
+ text = "#{text} <abbr title='Required'>*</abbr>".html_safe if attribute_required?(method) || required_by_option?(options.delete('required'))
35
+ super(method, text, options, &block)
36
+
37
+ end
38
+
39
+ ##
40
+ #
41
+ # Creates a button tag to be used in a form instead of the default input[type=submit]
42
+ # to help make CSS styling easier
43
+ #
44
+ # @param [String] value The text for the button
45
+ # @param [Hash] options HTML options to be passed to the button
46
+ # @option [String] icon If included, adds an image to the button to be used as an icon
47
+ #
48
+ def button(value = nil, options = {})
49
+
50
+ value, options = nil, value if value.is_a?(Hash)
51
+ value ||= submit_default_value
52
+
53
+ value = [image_tag(icon, :class => 'icon'), value].join(' ') if icon = options.delete(:icon)
54
+ klasses = (options.delete(:class) || "").split(" ")
55
+ klasses << "button"
56
+ options['class'] = klasses.join(" ")
57
+ content_tag(:button, value.to_s.html_safe, options.reverse_merge!({ "type" => "submit", "name" => "commit" }))
58
+
59
+ end
60
+
61
+ ##
62
+ #
63
+ # Generate a select tag with the 50 US states as options
64
+ #
65
+ # @param [Symbol] method The object method/attribute to be used
66
+ # @param [Hash] options Same as Rails' select options hash
67
+ # @option options [Symbol] :international Include an international option
68
+ # @option options [Symbol] :abbreviate Use an abbreviated version of the state name for the value
69
+ # @param [Hash] html_options Same as Rails' html_options hash
70
+ #
71
+ # @return [String] HTML select tag
72
+ #
73
+ def state_select(method, options = {}, html_options = {})
74
+ abbr = options.delete(:abbreviate)
75
+ abbr = !(abbr.nil? || abbr === false)
76
+ select(method, @template.options_for_select(options_for_state_select(abbr, options.delete(:international)), @object.try(:state)), options, html_options)
77
+ end
78
+
79
+ protected
80
+
81
+ ##
82
+ #
83
+ # Returns a list of US states as an array
84
+ #
85
+ # @param [Boolean] abbreviate Abbreviate the value
86
+ # @param [Boolean, String] incl_international Include an additional state for "International"
87
+ #
88
+ # @return [Array] An array of states
89
+ #
90
+ def options_for_state_select(abbreviate = false, incl_international = false)
91
+ incl_international ||= false
92
+ state_list = [
93
+ ['Alabama', "AL"],['Alaska', "AK"],['Arizona', "AZ"],['Arkansas', "AR"],['California', "CA"],['Colorado', "CO"],
94
+ ['Connecticut', "CT"],['District of Columbia', "DC"],['Delaware', "DE"],['Florida', "FL"],['Georgia', "GA"],
95
+ ['Hawaii', "HI"],['Idaho', "ID"],['Illinois', "IL"],['Indiana', "IN"],['Iowa', "IA"],['Kansas', "KS"],['Kentucky', "KY"],
96
+ ['Louisiana', "LA"],['Maine', "ME"],['Maryland', "MD"],['Massachusetts', "MA"],['Michigan', "MI"],['Minnesota', "MN"],
97
+ ['Mississippi', "MS"],['Missouri', "MO"],['Montana', "MT"],['Nebraska', "NE"],['Nevada', "NV"],['New Hampshire', "NH"],
98
+ ['New Jersey', "NJ"],['New Mexico', "NM"],['New York', "NY"],['North Carolina', "NC"],['North Dakota', "ND"],
99
+ ['Ohio', "OH"],['Oklahoma', "OK"],['Oregon', "OR"],['Pennsylvania', "PA"],['Rhode Island', "RI"],['South Carolina', "SC"],
100
+ ['South Dakota', "SD"],['Tennessee', "TN"],['Texas', "TX"],['Utah', "UT"],['Vermont', "VT"],['Virginia', "VA"],['Washington', "WA"],
101
+ ['West Virginia', "WV"],['Wisconsin', "WI"],['Wyoming', "WY"]
102
+
103
+ ].map do |state|
104
+ (abbreviate ? state : [state.first, state.first])
105
+ end
106
+ state_list << ['International', incl_international] unless incl_international === false
107
+ state_list
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,29 @@
1
+ module Facades::Builders
2
+ module FormHelper
3
+ ##
4
+ #
5
+ # Cusomizes the default form_for helper to add additional functionality
6
+ # All params are the same as Rails' form_for
7
+ #
8
+ # @param [Mixed] record_name_or_array
9
+ # @param [Array] args
10
+ # @param [Block] &block
11
+ #
12
+ def form_for(record_name_or_array, *args, &proc)
13
+
14
+ raise ArgumentError, "Missing block" unless block_given?
15
+
16
+ options = args.extract_options!
17
+ options.reverse_merge!(:builder => Facades::Builders::Form)
18
+ options[:html] ||= {}
19
+ options[:html].merge!('data-js-validatable' => true) if options.delete(:validate)
20
+
21
+ default_proc = ::ActionView::Base.field_error_proc
22
+ ::ActionView::Base.field_error_proc = lambda{ |html_tag, instance_tag| html_tag }
23
+ super(record_name_or_array, *(args << options), &proc)
24
+ ensure
25
+ ::ActionView::Base.field_error_proc = default_proc
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ require 'facades/builders/form/base'
2
+ require 'facades/builders/form/elements'
3
+ require 'facades/builders/form/helper'
4
+
5
+ module Facades
6
+ module Builders
7
+ class Form < ActionView::Helpers::FormBuilder #:nodoc:
8
+ include Facades::Builders::FormBuilder::Base
9
+ include Facades::Builders::FormBuilder::Elements
10
+
11
+ def with_custom_error_proc(&block)
12
+ default_proc = ::ActionView::Base.field_error_proc
13
+ ::ActionView::Base.field_error_proc = lambda{ |html_tag, instance_tag| html_tag }
14
+ yield
15
+ ensure
16
+ ::ActionView::Base.field_error_proc = default_proc
17
+ end
18
+
19
+ ActionView::Base.send(:include, Facades::Builders::FormHelper)
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,5 @@
1
+ require 'rails'
2
+
1
3
  # Stub engine to integrate asset pipeline.
2
4
  module Facades
3
5
  class Engine < Rails::Engine
@@ -1,3 +1,3 @@
1
1
  module Facades
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/facades.rb CHANGED
@@ -14,6 +14,7 @@ module Facades
14
14
 
15
15
  module Builders
16
16
  autoload :Sprite, 'facades/builders/sprite'
17
+ autoload :Form, 'facades/builders/form'
17
18
  end
18
19
 
19
20
  # When enabled, HTML5 elements are used within helpers
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facades
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-30 00:00:00.000000000Z
12
+ date: 2011-10-01 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sass
16
- requirement: &70151854513160 !ruby/object:Gem::Requirement
16
+ requirement: &70211602186260 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70151854513160
24
+ version_requirements: *70211602186260
25
25
  description: ! 'Facades is a front-end development framework which takes '
26
26
  email:
27
27
  - brent@kurbmedia.com
@@ -37,6 +37,10 @@ files:
37
37
  - app/views/facades/_pagination.html.erb
38
38
  - facades.gemspec
39
39
  - lib/facades.rb
40
+ - lib/facades/builders/form.rb
41
+ - lib/facades/builders/form/base.rb
42
+ - lib/facades/builders/form/elements.rb
43
+ - lib/facades/builders/form/helper.rb
40
44
  - lib/facades/builders/sprite.rb
41
45
  - lib/facades/builders/table.rb
42
46
  - lib/facades/debug/html.rb