Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

Bugfixes:
- Your contribution here!
- form-control-danger is replaced with is-invalid for bootstrap 4.0.0.beta
- form-control-feedback is replaced with invalid-feedback for bootstrap 4.0.0.beta
- help texts are rendered with <small> tag instead of <span> tag, i.e. like in bootstrap 4.0.0.beta

Features:
- Your contribution here!
- is-valid will be applied to validated form field (i.e. not on unchanged or new records)
- custom: true option will generate bootstrap custom check boxes and options

## [2.7.0][] (2017-04-21)

Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ twitter bootstrap-style forms into your rails application.

* Ruby 1.9+
* Rails 4.0+
* Twitter Bootstrap 3.0+
* Twitter Bootstrap 4.0+

## Installation

Expand Down Expand Up @@ -55,13 +55,13 @@ This generates the following HTML:
<label for="user_password">Password</label>
<input class="form-control" id="user_password" name="user[password]" type="password">
</div>
<div class="checkbox">
<div class="form-check">
<label for="user_remember_me">
<input name="user[remember_me]" type="hidden" value="0">
<input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1"> Remember me
</label>
</div>
<input class="btn btn-default" name="commit" type="submit" value="Log In">
<input class="btn btn-secondary" name="commit" type="submit" value="Log In">
</form>
```

Expand Down Expand Up @@ -209,7 +209,7 @@ This automatically adds the `has-feedback` class to the `form-group`:

```html
<div class="form-group has-feedback">
<label class="control-label" for="user_login">Login</label>
<label class="form-control-label" for="user_login">Login</label>
<input class="form-control" id="user_login" name="user[login]" type="text" />
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
Expand All @@ -227,7 +227,7 @@ You can also prepend and append buttons. Note: The buttons must contain the
`btn` class to generate the correct markup.

```erb
<%= f.text_field :search, append: link_to("Go", "#", class: "btn btn-default") %>
<%= f.text_field :search, append: link_to("Go", "#", class: "btn btn-secondary") %>
```

To add a class to the input group wrapper, use `:input_group_class` option.
Expand All @@ -249,7 +249,7 @@ Which produces the following output:

```erb
<div class="form-group has-warning" data-foo="bar">
<label class="control-label" for="user_name">Id</label>
<label class="form-control-label" for="user_name">Id</label>
<input class="form-control" id="user_name" name="user[name]" type="text">
</div>
```
Expand Down Expand Up @@ -330,7 +330,7 @@ Here's the output:

```html
<div class="form-group">
<label class="col-sm-2 control-label" for="user_email">Email</label>
<label class="col-sm-2 form-control-label" for="user_email">Email</label>
<div class="col-sm-10">
<p class="form-control-static">test@email.com</p>
</div>
Expand All @@ -355,7 +355,7 @@ this defining these selects as `inline-block` and a width of `auto`.

### Submit Buttons

The `btn btn-default` css classes are automatically added to your submit
The `btn btn-secondary` css classes are automatically added to your submit
buttons.

```erb
Expand Down Expand Up @@ -468,10 +468,10 @@ error will be displayed below the field. Rails normally wraps the fields in a
div (field_with_errors), but this behavior is suppressed. Here's an example:

```html
<div class="form-group has-error">
<label class="control-label" for="user_email">Email</label>
<div class="form-group has-danger">
<label class="form-control-label" for="user_email">Email</label>
<input class="form-control" id="user_email" name="user[email]" type="email" value="">
<span class="help-block">can't be blank</span>
<span class="form-control-feedback">can't be blank</span>
</div>
```

Expand Down
64 changes: 49 additions & 15 deletions lib/bootstrap_form/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,24 @@ def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {},

def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_value = "0", &block)
options = options.symbolize_keys!
check_box_options = options.except(:label, :label_class, :help, :inline)
check_box_options = options.except(:label, :label_class, :help, :inline, :custom)
if options[:custom]
validation = ""
validation = "is-invalid" if has_error?(name)
validation = "is-valid" if is_valid?(name)
check_box_options[:class] = ["custom-control-input", validation, check_box_options[:class]].compact.join(' ')
else
check_box_options[:class] = ["form-check-input", check_box_options[:class]].compact.join(' ')
end

html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value)
label_content = block_given? ? capture(&block) : options[:label]
html.concat(" ").concat(label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize)
label_description = label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize
if options[:custom]
html.concat(content_tag(:span, "", class: "custom-control-indicator")).concat(content_tag(:span, label_description, class: "custom-control-description"))
else
html.concat(" ").concat(label_description)
end

label_name = name
# label's `for` attribute needs to match checkbox tag's id,
Expand All @@ -130,14 +143,15 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_
end

disabled_class = " disabled" if options[:disabled]
label_class = options[:label_class]
label_class = options[:label_class]
custom_label_class = options[:custom] ? "custom-control custom-checkbox" : "form-check-label"

if options[:inline]
label_class = " #{label_class}" if label_class
label(label_name, html, class: "checkbox-inline#{disabled_class}#{label_class}")
label(label_name, html, class: "form-check-inline#{disabled_class}#{label_class}")
else
content_tag(:div, class: "checkbox#{disabled_class}") do
label(label_name, html, class: label_class)
content_tag(:div, class: "form-check#{disabled_class}") do
label(label_name, html, class: [custom_label_class, label_class].compact.join(" "))
end
end
end
Expand All @@ -146,9 +160,15 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_

def radio_button_with_bootstrap(name, value, *args)
options = args.extract_options!.symbolize_keys!
args << options.except(:label, :label_class, :help, :inline)

html = radio_button_without_bootstrap(name, value, *args) + " " + options[:label]
radio_options = options.except(:label, :label_class, :help, :inline, :custom)
radio_options[:class] = ["custom-control-input", options[:class]].compact.join(' ') if options[:custom]
args << radio_options
html = radio_button_without_bootstrap(name, value, *args)
if options[:custom]
html.concat(content_tag(:span, "", class: "custom-control-indicator")).concat(content_tag(:span, options[:label], class: "custom-control-description"))
else
html.concat(" ").concat(options[:label])
end

disabled_class = " disabled" if options[:disabled]
label_class = options[:label_class]
Expand All @@ -157,6 +177,7 @@ def radio_button_with_bootstrap(name, value, *args)
label_class = " #{label_class}" if label_class
label(name, html, class: "radio-inline#{disabled_class}#{label_class}", value: value)
else
label_class = ["custom-control", "custom-radio", options[:class]].compact.join(' ') if options[:custom]
content_tag(:div, class: "radio#{disabled_class}") do
label(name, html, value: value, class: label_class)
end
Expand Down Expand Up @@ -198,6 +219,7 @@ def form_group(*args, &block)
name = args.first

options[:class] = ["form-group", options[:class]].compact.join(' ')
options[:class] << " row" if get_group_layout(options[:layout]) == :horizontal
options[:class] << " #{error_class}" if has_error?(name)
options[:class] << " #{feedback_class}" if options[:icon]

Expand Down Expand Up @@ -263,11 +285,11 @@ def control_class
end

def label_class
"control-label"
"form-control-label"
end

def error_class
"has-error"
"has-danger"
end

def feedback_class
Expand All @@ -282,6 +304,10 @@ def has_error?(name)
object.respond_to?(:errors) && !(name.nil? || object.errors[name].empty?)
end

def is_valid?(name)
object.respond_to?(:changed?) && object.respond_to?(:new_record?) && object.changed? && object.new_record? && !has_error?(name)
end

def required_attribute?(obj, attribute)

return false unless obj and attribute
Expand Down Expand Up @@ -313,6 +339,8 @@ def form_group_builder(method, options, html_options = nil)
css_options = html_options || options
control_classes = css_options.delete(:control_class) { control_class }
css_options[:class] = [control_classes, css_options[:class]].compact.join(" ")
css_options[:class] << " is-invalid" if has_error?(method)
css_options[:class] << " is-valid" if is_valid?(method)

options = convert_form_tag_options(method, options) if acts_like_form_tag

Expand Down Expand Up @@ -389,16 +417,22 @@ def generate_label(id, name, options, custom_label_col, group_layout)
end

def generate_help(name, help_text)
help_text = get_error_messages(name) if has_error?(name) && inline_errors
return if help_text === false
if has_error?(name) && inline_errors
help_text = get_error_messages(name)
help_klass = 'invalid-feedback'
help_tag = :span
end
return if help_text == false

help_klass ||= 'form-text text-muted'
help_text ||= get_help_text_by_i18n_key(name)
help_tag ||= :small

content_tag(:span, help_text, class: 'help-block') if help_text.present?
content_tag(help_tag, help_text, class: help_klass) if help_text.present?
end

def generate_icon(icon)
content_tag(:span, "", class: "glyphicon glyphicon-#{icon} form-control-feedback")
content_tag(:span, "", class: "glyphicon glyphicon-#{icon} invalid-feedback")
end

def get_error_messages(name)
Expand Down
11 changes: 2 additions & 9 deletions lib/bootstrap_form/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,8 @@ def bootstrap_form_for(object, options = {}, &block)
options[:html] ||= {}
options[:html][:role] ||= 'form'

layout = case options[:layout]
when :inline
"form-inline"
when :horizontal
"form-horizontal"
end

if layout
options[:html][:class] = [options[:html][:class], layout].compact.join(" ")
if options[:layout] == :inline
options[:html][:class] = [options[:html][:class], "form-inline"].compact.join(" ")
end

temporarily_disable_field_error_proc do
Expand Down
2 changes: 1 addition & 1 deletion lib/bootstrap_form/helpers/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module BootstrapForm
module Helpers
module Bootstrap
def submit(name = nil, options = {})
options.reverse_merge! class: 'btn btn-default'
options.reverse_merge! class: 'btn btn-secondary'
super(name, options)
end

Expand Down
Loading