twitter_bootstrap_form_for 1.0.5 → 2.0.1.0.rc1
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/CHANGELOG.markdown
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
Twitter Bootstrap Form For Changes
|
2
2
|
==================================
|
3
3
|
|
4
|
+
## 1.0.6 (unreleased)
|
5
|
+
- use base FormBuilder rather than user-specified default
|
6
|
+
for inline inputs (re-re-closes [\#2])
|
7
|
+
|
4
8
|
## 1.0.5 (2011-11-28) ##
|
5
9
|
- properly name inline input fields (re-closes [\#2])
|
6
10
|
|
data/README.markdown
CHANGED
@@ -18,10 +18,11 @@ Just Rails. But you were going to use that anyway, weren't you?
|
|
18
18
|
## Syntax ##
|
19
19
|
|
20
20
|
```haml
|
21
|
-
|
21
|
+
/ supports both vertical and horizontal forms
|
22
|
+
= twitter_bootstrap_form_for @user, :html => { :class => 'form-horizontal'} do |user|
|
22
23
|
|
23
24
|
/ wraps a section in a fieldset with the provided legend text
|
24
|
-
= user.
|
25
|
+
= user.fieldset 'Sign up', :class => 'sign_up' do
|
25
26
|
|
26
27
|
/ generates a standard email field
|
27
28
|
= user.email_field :email, :placeholder => 'me@example.com'
|
@@ -38,31 +39,31 @@ Just Rails. But you were going to use that anyway, weren't you?
|
|
38
39
|
/ input fields with custom add-ons
|
39
40
|
= user.text_field :twitter_id, 'Twitter', :class => 'medium', :add_on => :prepend do
|
40
41
|
%span.add-on @
|
41
|
-
|
42
|
+
|
42
43
|
/ select fields now have the second parameter as a label
|
43
|
-
= user.date_select :born_on, 'Born on', {}, :class => '
|
44
|
+
= user.date_select :born_on, 'Born on', {}, :class => 'span2'
|
44
45
|
|
45
|
-
/ inline inputs
|
46
|
-
= user.
|
47
|
-
#{
|
48
|
-
#{
|
49
|
-
#{
|
46
|
+
/ inline inputs
|
47
|
+
= user.label 'Interests' do |controls|
|
48
|
+
#{controls.text_field :interest_1, :class => 'span2 inline'},
|
49
|
+
#{controls.text_field :interest_2, :class => 'span2 inline'}, and
|
50
|
+
#{controls.text_field :interest_3, :class => 'span2 inline'}
|
50
51
|
|
51
52
|
/ group of radio buttons
|
52
|
-
= user.
|
53
|
-
=
|
54
|
-
=
|
53
|
+
= user.label 'Email Preferences' do |controls|
|
54
|
+
= controls.radio_button :email, :html, 'HTML Email', :checked => true
|
55
|
+
= controls.radio_button :email, :plain, 'Plain Text'
|
55
56
|
|
56
57
|
/ group of checkboxes
|
57
|
-
= user.
|
58
|
-
=
|
59
|
-
=
|
60
|
-
=
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
58
|
+
= user.label 'Agreements' do |controls|
|
59
|
+
= controls.check_box :agree, 'I agree to the abusive Terms and Conditions'
|
60
|
+
= controls.check_box :spam, 'I agree to receive all sorts of spam'
|
61
|
+
= controls.check_box :spammer, 'I agree to let the site spam others through my Twitter account'
|
62
|
+
|
63
|
+
/ wraps buttons in a distinctive style
|
64
|
+
= user.actions do
|
65
|
+
= user.submit 'Sign up'
|
66
|
+
= user.button 'Cancel'
|
66
67
|
```
|
67
68
|
|
68
69
|
That code produces the following output, with no custom stylesheets.
|
@@ -73,9 +74,13 @@ That's it. All of the Rails field helpers you know and love work just like
|
|
73
74
|
their normal FormBuilder counterparts, but with minor extensions to expose
|
74
75
|
the functionality anticipated by Twitter Bootstrap.
|
75
76
|
|
76
|
-
##
|
77
|
+
## Form Helper Changes ##
|
78
|
+
|
79
|
+
The changes this `FormBuilder` effects to the existing Rails form helpers is
|
80
|
+
simple:
|
77
81
|
|
78
|
-
|
82
|
+
* the second parameter becomes the label (pass false to disable, nil for default)
|
83
|
+
* the last options hash accepts an `:add_on` key
|
84
|
+
* if a block is passed, the HTML it outputs is placed immediately after the input
|
79
85
|
|
80
86
|
[Twitter Bootstrap]: http://twitter.github.com/bootstrap/
|
81
|
-
[issue #28]: https://github.com/stouset/twitter_bootstrap_form_for/issues/28
|
data/examples/screenshot.png
CHANGED
Binary file
|
@@ -26,32 +26,59 @@ class TwitterBootstrapFormFor::FormBuilder < ActionView::Helpers::FormBuilder
|
|
26
26
|
# Wraps the contents of the block passed in a fieldset with optional
|
27
27
|
# +legend+ text.
|
28
28
|
#
|
29
|
-
def
|
29
|
+
def fieldset(legend = nil, options = {})
|
30
30
|
template.content_tag(:fieldset, options) do
|
31
31
|
template.concat template.content_tag(:legend, legend) unless legend.nil?
|
32
|
-
|
32
|
+
yield
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
#
|
37
|
-
# Wraps
|
38
|
-
#
|
39
|
-
|
37
|
+
# Wraps action buttons into their own styled container.
|
38
|
+
#
|
39
|
+
def actions(&block)
|
40
|
+
template.content_tag(:div, :class => 'form-actions', &block)
|
41
|
+
end
|
42
|
+
|
40
43
|
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
# Attaches a label to the inputs rendered inside of the block passed to it.
|
45
|
+
# Associates the label with the input for the +attribute+ given. If +text+
|
46
|
+
#is passed, uses that as the text for the label; otherwise humanizes the
|
47
|
+
# +attribute+ name.
|
48
|
+
#
|
49
|
+
def label(attribute, text = '', options = {}, &block)
|
50
|
+
text, attribute = attribute, nil if attribute.kind_of? String
|
51
|
+
|
52
|
+
options = { :class => 'control-label' }.merge(options)
|
53
|
+
id = _wrapper_id attribute, 'control_group'
|
54
|
+
classes = _wrapper_classes attribute, 'control-group'
|
55
|
+
|
56
|
+
template.content_tag(:div, :id => id, :class => classes) do
|
57
|
+
template.concat case
|
58
|
+
when attribute && text then super(attribute, text, options, &nil)
|
59
|
+
when attribute then super(attribute, nil, options, &nil)
|
60
|
+
when text then template.label_tag(nil, text, options, &nil)
|
61
|
+
end
|
62
|
+
|
63
|
+
template.concat template.content_tag(:div, :class => 'controls') {
|
64
|
+
template.fields_for(
|
65
|
+
self.object_name,
|
66
|
+
self.object,
|
67
|
+
self.options.merge(:builder => TwitterBootstrapFormFor::FormControls),
|
68
|
+
&block
|
69
|
+
)
|
46
70
|
}
|
47
71
|
end
|
48
72
|
end
|
49
73
|
|
50
74
|
#
|
51
|
-
#
|
75
|
+
# Renders a button with default classes to style it as a form button.
|
52
76
|
#
|
53
|
-
def
|
54
|
-
|
77
|
+
def button(value = nil, options = {})
|
78
|
+
super value, {
|
79
|
+
:type => 'button',
|
80
|
+
:class => 'btn',
|
81
|
+
}.merge(options)
|
55
82
|
end
|
56
83
|
|
57
84
|
#
|
@@ -59,119 +86,50 @@ class TwitterBootstrapFormFor::FormBuilder < ActionView::Helpers::FormBuilder
|
|
59
86
|
# button.
|
60
87
|
#
|
61
88
|
def submit(value = nil, options = {})
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
#
|
68
|
-
# Creates bootstrap wrapping before yielding a plain old rails builder
|
69
|
-
# to the supplied block.
|
70
|
-
#
|
71
|
-
def inline(label = nil, &block)
|
72
|
-
template.content_tag(:div, :class => 'clearfix') do
|
73
|
-
template.concat template.content_tag(:label, label) if label.present?
|
74
|
-
template.concat template.content_tag(:div, :class => 'input') {
|
75
|
-
template.content_tag(:div, :class => 'inline-inputs') do
|
76
|
-
template.fields_for(
|
77
|
-
self.object_name,
|
78
|
-
self.object,
|
79
|
-
self.options.merge(:builder => ActionView::Base.default_form_builder),
|
80
|
-
&block
|
81
|
-
)
|
82
|
-
end
|
83
|
-
}
|
84
|
-
end
|
89
|
+
self.button value, {
|
90
|
+
:type => 'submit',
|
91
|
+
:class => 'btn btn-primary',
|
92
|
+
}.merge(options)
|
85
93
|
end
|
86
94
|
|
87
95
|
INPUTS.each do |input|
|
88
96
|
define_method input do |attribute, *args, &block|
|
89
|
-
options
|
90
|
-
|
91
|
-
classes = [ 'input' ]
|
92
|
-
classes << ('input-' + options.delete(:add_on).to_s) if options[:add_on]
|
93
|
-
|
94
|
-
self.div_wrapper(attribute) do
|
95
|
-
template.concat self.label(attribute, label) if label
|
96
|
-
template.concat template.content_tag(:div, :class => classes.join(' ')) {
|
97
|
-
template.concat super(attribute, *(args << options))
|
98
|
-
template.concat error_span(attribute)
|
99
|
-
block.call if block.present?
|
100
|
-
}
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
97
|
+
options = args.extract_options!
|
98
|
+
text = args.any? ? args.shift : ''
|
104
99
|
|
105
|
-
|
106
|
-
|
107
|
-
label = args.first.nil? ? '' : args.shift
|
108
|
-
target = self.object_name.to_s + '_' + attribute.to_s
|
109
|
-
label_attrs = toggle == :check_box ? { :for => target } : {}
|
110
|
-
|
111
|
-
template.content_tag(:li) do
|
112
|
-
template.concat template.content_tag(:label, label_attrs) {
|
113
|
-
template.concat super(attribute, *args)
|
114
|
-
template.concat ' ' # give the input and span some room
|
115
|
-
template.concat template.content_tag(:span, label)
|
116
|
-
}
|
100
|
+
self.label(attribute, text) do |builder|
|
101
|
+
builder.send(input, attribute, *(args << options), &block)
|
117
102
|
end
|
118
103
|
end
|
119
104
|
end
|
120
105
|
|
121
106
|
protected
|
122
107
|
|
123
|
-
#
|
124
|
-
# Wraps the contents of +block+ inside a +tag+ with an appropriate class and
|
125
|
-
# id for the object's +attribute+. HTML options can be overridden by passing
|
126
|
-
# an +options+ hash.
|
127
|
-
#
|
128
|
-
def div_wrapper(attribute, options = {}, &block)
|
129
|
-
options[:id] = _wrapper_id attribute, options[:id]
|
130
|
-
options[:class] = _wrapper_classes attribute, options[:class], 'clearfix'
|
131
|
-
|
132
|
-
template.content_tag :div, options, &block
|
133
|
-
end
|
134
|
-
|
135
|
-
def error_span(attribute, options = {})
|
136
|
-
options[:class] ||= 'help-inline'
|
137
|
-
|
138
|
-
template.content_tag(
|
139
|
-
:span, self.errors_for(attribute),
|
140
|
-
:class => options[:class]
|
141
|
-
) if self.errors_on?(attribute)
|
142
|
-
end
|
143
|
-
|
144
108
|
def errors_on?(attribute)
|
145
109
|
self.object.errors[attribute].present? if self.object.respond_to?(:errors)
|
146
110
|
end
|
147
111
|
|
148
|
-
def errors_for(attribute)
|
149
|
-
self.object.errors[attribute].try(:join, ', ')
|
150
|
-
end
|
151
|
-
|
152
112
|
private
|
153
113
|
|
154
114
|
#
|
155
115
|
# Returns an HTML id to uniquely identify the markup around an input field.
|
156
|
-
# If a +default+ is provided, it uses that one instead.
|
157
116
|
#
|
158
|
-
def _wrapper_id(attribute,
|
159
|
-
|
117
|
+
def _wrapper_id(attribute, suffix = nil)
|
118
|
+
[
|
160
119
|
_object_name + _object_index,
|
161
120
|
_attribute_name(attribute),
|
162
|
-
|
163
|
-
].join('_')
|
121
|
+
suffix,
|
122
|
+
].compact.join('_') if attribute
|
164
123
|
end
|
165
124
|
|
166
125
|
#
|
167
126
|
# Returns any classes necessary for the wrapper div around fields for
|
168
127
|
# +attribute+, such as 'errors' if any errors are present on the attribute.
|
169
|
-
#
|
128
|
+
# Merges any +classes+ passed in.
|
170
129
|
#
|
171
130
|
def _wrapper_classes(attribute, *classes)
|
172
|
-
classes.
|
173
|
-
|
174
|
-
end.join(' ')
|
131
|
+
classes.push 'error' if attribute and self.errors_on?(attribute)
|
132
|
+
classes.compact.join(' ')
|
175
133
|
end
|
176
134
|
|
177
135
|
def _attribute_name(attribute)
|
@@ -190,3 +148,68 @@ class TwitterBootstrapFormFor::FormBuilder < ActionView::Helpers::FormBuilder
|
|
190
148
|
end.to_s
|
191
149
|
end
|
192
150
|
end
|
151
|
+
|
152
|
+
class TwitterBootstrapFormFor::FormControls < ActionView::Helpers::FormBuilder
|
153
|
+
attr_reader :template
|
154
|
+
attr_reader :object
|
155
|
+
attr_reader :object_name
|
156
|
+
|
157
|
+
TwitterBootstrapFormFor::FormBuilder::INPUTS.each do |input|
|
158
|
+
define_method input do |attribute, *args, &block|
|
159
|
+
options = args.extract_options!
|
160
|
+
add_on = options.delete(:add_on)
|
161
|
+
tag = add_on.present? ? :div : :span
|
162
|
+
classes = [ "input", add_on ].compact.join('-')
|
163
|
+
|
164
|
+
template.content_tag(tag, :class => classes) do
|
165
|
+
template.concat super attribute, *(args << options)
|
166
|
+
template.concat self.error_span(attribute) if self.errors_on?(attribute)
|
167
|
+
block.call if block.present?
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def check_box(attribute, text, options = {}, checked_value = 1, unchecked_value = 0)
|
173
|
+
klasses = _merge_classes 'checkbox', options.delete(:inline) && 'inline'
|
174
|
+
|
175
|
+
self.label(attribute, :class => klasses) do
|
176
|
+
template.concat super(attribute, options, checked_value, unchecked_value)
|
177
|
+
template.concat text
|
178
|
+
yield if block_given?
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def radio_button(attribute, value, text = nil, options = {})
|
183
|
+
klasses = _merge_classes 'radio', options.delete(:inline) && 'inline'
|
184
|
+
|
185
|
+
self.label(attribute, :class => klasses) do
|
186
|
+
template.concat super(attribute, value, options)
|
187
|
+
template.concat text || value.to_s.humanize.titleize
|
188
|
+
yield if block_given?
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
protected
|
193
|
+
|
194
|
+
def error_span(attribute, options = {})
|
195
|
+
options[:class] = _merge_classes options[:class], 'help-inline'
|
196
|
+
|
197
|
+
template.content_tag :span,
|
198
|
+
self.errors_for(attribute),
|
199
|
+
:class => options[:class]
|
200
|
+
end
|
201
|
+
|
202
|
+
def errors_for(attribute)
|
203
|
+
self.object.errors[attribute].try(:join, ', ')
|
204
|
+
end
|
205
|
+
|
206
|
+
def errors_on?(attribute)
|
207
|
+
self.object.errors[attribute].present? if self.object.respond_to?(:errors)
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def _merge_classes(string, *classes)
|
213
|
+
string.to_s.split(' ').push(*classes.compact).join(' ')
|
214
|
+
end
|
215
|
+
end
|
@@ -18,13 +18,13 @@ module TwitterBootstrapFormFor::FormHelpers
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
BLANK_FIELD_ERROR_PROC = lambda {|input, _| input }
|
21
|
+
BLANK_FIELD_ERROR_PROC = lambda {|input, *_| input }
|
22
22
|
|
23
23
|
def _override_field_error_proc
|
24
|
-
original_field_error_proc
|
25
|
-
|
24
|
+
original_field_error_proc = ::ActionView::Base.field_error_proc
|
25
|
+
::ActionView::Base.field_error_proc = BLANK_FIELD_ERROR_PROC
|
26
26
|
yield
|
27
27
|
ensure
|
28
|
-
|
28
|
+
::ActionView::Base.field_error_proc = original_field_error_proc
|
29
29
|
end
|
30
30
|
end
|
metadata
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twitter_bootstrap_form_for
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
5
|
-
prerelease:
|
4
|
+
version: 2.0.1.0.rc1
|
5
|
+
prerelease: 8
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Stephen Touset
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-02-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: railties
|
16
|
-
requirement: &
|
16
|
+
requirement: &70350113394920 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70350113394920
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: actionpack
|
27
|
-
requirement: &
|
27
|
+
requirement: &70350113394060 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '3'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70350113394060
|
36
36
|
description: A custom Rails FormBuilder that assumes the use of Twitter Bootstrap
|
37
37
|
email:
|
38
38
|
- stephen@touset.org
|
@@ -65,9 +65,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
66
|
none: false
|
67
67
|
requirements:
|
68
|
-
- - ! '
|
68
|
+
- - ! '>'
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version:
|
70
|
+
version: 1.3.1
|
71
71
|
requirements: []
|
72
72
|
rubyforge_project:
|
73
73
|
rubygems_version: 1.8.11
|
@@ -75,3 +75,4 @@ signing_key:
|
|
75
75
|
specification_version: 3
|
76
76
|
summary: Rails form builder optimized for Twitter Bootstrap
|
77
77
|
test_files: []
|
78
|
+
has_rdoc:
|