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.
- data/lib/facades/builders/form/base.rb +212 -0
- data/lib/facades/builders/form/elements.rb +112 -0
- data/lib/facades/builders/form/helper.rb +29 -0
- data/lib/facades/builders/form.rb +22 -0
- data/lib/facades/support/rails.rb +2 -0
- data/lib/facades/version.rb +1 -1
- data/lib/facades.rb +1 -0
- metadata +8 -4
@@ -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
|
data/lib/facades/version.rb
CHANGED
data/lib/facades.rb
CHANGED
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.
|
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-
|
12
|
+
date: 2011-10-01 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sass
|
16
|
-
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: *
|
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
|