booter 0.3.1 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +5 -0
- data/README.md +68 -5
- data/Rakefile +8 -0
- data/app/assets/stylesheets/bootstrap-tweaks.css +1 -0
- data/app/assets/stylesheets/bootstrap.css.scss +3 -0
- data/app/form_builders/bootstrap_form_builder.rb +59 -7
- data/app/helpers/booter_helper.rb +6 -1
- data/app/views/booter/_modal_form.html.erb +19 -0
- data/booter.gemspec +6 -0
- data/config/locales/booter.en.yml +3 -0
- data/config/locales/booter.ru.yml +4 -0
- data/lib/booter/version.rb +1 -1
- data/spec/controllers/home_controller_spec.rb +127 -0
- data/spec/controllers/modal_controller_spec.rb +33 -0
- data/spec/dummy/.gitignore +3 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/home_controller.rb +24 -0
- data/spec/dummy/app/controllers/modal_controller.rb +7 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/user.rb +6 -0
- data/spec/dummy/app/views/home/buttons.html.haml +6 -0
- data/spec/dummy/app/views/home/default_fields.html.haml +8 -0
- data/spec/dummy/app/views/home/errors_for.html.haml +2 -0
- data/spec/dummy/app/views/home/field_with_hint.html.haml +2 -0
- data/spec/dummy/app/views/home/submit_button.html.haml +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/modal/simple.html.haml +5 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +57 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +6 -0
- data/spec/dummy/db/migrate/20120406045208_create_user.rb +7 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/spec_helper.rb +24 -0
- metadata +114 -11
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,20 +4,83 @@ One more twitter bootstrap wrapper for Rails.
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
|
7
|
+
In your Gemfile, add the following dependencies:
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
``` ruby
|
10
|
+
gem 'booter'
|
11
|
+
```
|
12
|
+
|
13
|
+
Run:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Add `bootstrap` in your application.css:
|
20
|
+
|
21
|
+
``` css
|
22
|
+
/*
|
23
|
+
*= require bootstrap
|
24
|
+
* ...
|
25
|
+
*/
|
26
|
+
```
|
27
|
+
|
28
|
+
And optionally add 'bootstrap' in your application.js:
|
29
|
+
|
30
|
+
``` javascript
|
31
|
+
//= require jquery
|
32
|
+
//= require jquery_ujs
|
33
|
+
//= require bootstrap
|
34
|
+
//= ...
|
35
|
+
```
|
11
36
|
|
12
37
|
## Usage
|
13
38
|
|
14
39
|
Use <tt>nice_form_for</tt> helper method to draw nice bootstrap forms:
|
15
40
|
|
16
41
|
``` haml
|
17
|
-
|
42
|
+
-# Simple
|
43
|
+
= nice_form_for @user do |f|
|
18
44
|
= f.errors_for
|
19
45
|
= f.email_field :email
|
20
46
|
= f.password_field :password
|
47
|
+
= f.submit 'Sign in'
|
48
|
+
|
49
|
+
-# Complex
|
50
|
+
= nice_form_for @user do |f|
|
51
|
+
= f.errors_for
|
52
|
+
|
53
|
+
= f.email_field :email, class: 'input-medium'
|
54
|
+
= f.password_field :password
|
21
55
|
= f.check_box :remember_me
|
22
|
-
|
56
|
+
|
57
|
+
= f.actions do
|
58
|
+
= f.submit 'Sign in'
|
59
|
+
= f.button 'Cancel'
|
60
|
+
|
61
|
+
= f.button 'Danger button', style: :danger
|
62
|
+
= f.submit 'Submit without the primary class', style: :none
|
63
|
+
|
64
|
+
|
65
|
+
-# Modal
|
66
|
+
= nice_form_for @user, modal: true, id: 'auth' do |f|
|
67
|
+
= f.errors_for
|
68
|
+
= f.email_field :email
|
69
|
+
= f.password_field :password
|
70
|
+
= f.submit 'Sign in'
|
71
|
+
|
72
|
+
%p= link_to 'Open auth form', '#auth-modal', data: { toggle: 'modal' }
|
23
73
|
```
|
74
|
+
|
75
|
+
## Demo
|
76
|
+
|
77
|
+
See [live demo](http://growing-cloud-6915.heroku.com) or browse [source code](https://github.com/boshie/booter-demo)
|
78
|
+
|
79
|
+
## Contributors
|
80
|
+
|
81
|
+
* Alexey Vakhov - [https://github.com/avakhov](https://github.com/avakhov)
|
82
|
+
* Alexey Yurchenko - [https://github.com/alexesDev](https://github.com/alexesDev)
|
83
|
+
|
84
|
+
## Status
|
85
|
+
|
86
|
+
[<img src="https://secure.travis-ci.org/boshie/booter.png"/>](http://travis-ci.org/boshie/booter)
|
data/Rakefile
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
div.modal form {margin-bottom: 0}
|
@@ -1,5 +1,16 @@
|
|
1
1
|
class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
|
2
2
|
delegate :content_tag, :safe_join, to: :@template
|
3
|
+
attr_reader :form_actions_content # only for modal forms
|
4
|
+
|
5
|
+
def modal_title
|
6
|
+
if @options[:modal]
|
7
|
+
if @options[:modal].is_a?(Hash) and @options[:modal].key?(:title)
|
8
|
+
@options[:modal][:title]
|
9
|
+
else
|
10
|
+
I18n.t('booter.modal.title.' + @object.class.model_name, default: @object.class.model_name.human)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
3
14
|
|
4
15
|
def errors_for
|
5
16
|
return "" if @object.errors.empty?
|
@@ -21,17 +32,19 @@ class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
|
|
21
32
|
html.html_safe
|
22
33
|
end
|
23
34
|
|
24
|
-
%w[email_field password_field text_field text_area].each do |method_name|
|
35
|
+
%w[email_field file_field password_field text_field text_area].each do |method_name|
|
25
36
|
define_method method_name do |*args|
|
26
37
|
options = args.extract_options!
|
27
38
|
name = args.first
|
28
39
|
|
29
40
|
wrapper name, options.slice(:hint) do
|
30
41
|
options = options.except(:hint)
|
31
|
-
options[:class] = [options[:class], 'input-xxlarge'].compact
|
32
42
|
|
33
43
|
if method_name == 'text_area'
|
34
|
-
|
44
|
+
options[:rows] ||= 7
|
45
|
+
options[:cols] ||= 40
|
46
|
+
|
47
|
+
super(name, options)
|
35
48
|
else
|
36
49
|
super(name, options)
|
37
50
|
end
|
@@ -39,6 +52,16 @@ class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
|
|
39
52
|
end
|
40
53
|
end
|
41
54
|
|
55
|
+
def actions &block
|
56
|
+
begin
|
57
|
+
@actions_scope = true
|
58
|
+
content = @template.capture(&block)
|
59
|
+
ensure
|
60
|
+
@actions_scope = false
|
61
|
+
end
|
62
|
+
form_actions_wrapper content
|
63
|
+
end
|
64
|
+
|
42
65
|
def select(name, choices, options = {})
|
43
66
|
wrapper name do
|
44
67
|
super
|
@@ -53,10 +76,12 @@ class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
|
|
53
76
|
end
|
54
77
|
end
|
55
78
|
|
56
|
-
def submit
|
57
|
-
|
58
|
-
|
59
|
-
|
79
|
+
def submit value = nil, *args
|
80
|
+
form_actions_wrapper super(value, make_button_options(args, style: :primary))
|
81
|
+
end
|
82
|
+
|
83
|
+
def button value = nil, *args
|
84
|
+
form_actions_wrapper super(value, make_button_options(args))
|
60
85
|
end
|
61
86
|
|
62
87
|
def wrapper(name, options = {}, &block)
|
@@ -72,4 +97,31 @@ class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
|
|
72
97
|
]
|
73
98
|
end
|
74
99
|
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def form_actions_wrapper(content)
|
104
|
+
if @actions_scope
|
105
|
+
content
|
106
|
+
else
|
107
|
+
if @options[:modal]
|
108
|
+
@form_actions_content = content
|
109
|
+
''
|
110
|
+
else
|
111
|
+
content_tag :div, content, class: 'form-actions'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def make_button_options args, *default_args
|
117
|
+
options = default_args.extract_options!
|
118
|
+
options.merge! args.extract_options!
|
119
|
+
options[:class] ||= 'btn'
|
120
|
+
|
121
|
+
if options[:style] && options[:style].to_sym != :none
|
122
|
+
options[:class] += " btn-#{options[:style]}"
|
123
|
+
end
|
124
|
+
|
125
|
+
options.except(:style)
|
126
|
+
end
|
75
127
|
end
|
@@ -3,6 +3,11 @@ module BooterHelper
|
|
3
3
|
options[:builder] = BootstrapFormBuilder
|
4
4
|
options[:html] ||= {}
|
5
5
|
options[:html][:class] = 'form-horizontal'
|
6
|
-
|
6
|
+
|
7
|
+
if options[:modal]
|
8
|
+
render 'booter/modal_form', object: object, options: options, block: block
|
9
|
+
else
|
10
|
+
form_for(object, options, &block)
|
11
|
+
end
|
7
12
|
end
|
8
13
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<div class="modal hide fade" id="<%= options[:id] || object.class.name.gsub('::', '').underscore %>-modal">
|
2
|
+
<%= form_for object, options do |f| %>
|
3
|
+
<div class="modal-header">
|
4
|
+
<a class="close" data-dismiss="modal">×</a>
|
5
|
+
<h3><%= f.modal_title %></h3>
|
6
|
+
</div>
|
7
|
+
<div class="modal-body">
|
8
|
+
<%= capture f, &block %>
|
9
|
+
</div>
|
10
|
+
<div class="modal-footer">
|
11
|
+
<div class="pull-left">
|
12
|
+
<a href="#" data-dismiss="modal" class="btn"><%= t('booter.modal.close') %></a>
|
13
|
+
</div>
|
14
|
+
<div class="pull-right">
|
15
|
+
<%= f.form_actions_content %>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
data/booter.gemspec
CHANGED
@@ -16,4 +16,10 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.version = Booter::VERSION
|
17
17
|
|
18
18
|
gem.add_dependency 'rails', '~> 3.2'
|
19
|
+
|
20
|
+
gem.add_development_dependency 'haml'
|
21
|
+
gem.add_development_dependency 'sqlite3'
|
22
|
+
gem.add_development_dependency 'rspec-rails'
|
23
|
+
gem.add_development_dependency 'factory_girl_rails'
|
24
|
+
gem.add_development_dependency 'database_cleaner'
|
19
25
|
end
|
data/lib/booter/version.rb
CHANGED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HomeController do
|
4
|
+
render_views
|
5
|
+
|
6
|
+
it 'renders default field' do
|
7
|
+
get :default_fields
|
8
|
+
response.should be_success
|
9
|
+
|
10
|
+
assert_select "form[class=?]", /form-horizontal/ do
|
11
|
+
assert_select "div.control-group" do
|
12
|
+
assert_select 'label.control-label', 'Email'
|
13
|
+
assert_select 'div.controls' do
|
14
|
+
assert_select 'input[type=email]'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_select "div.control-group" do
|
19
|
+
assert_select 'label.control-label', 'Avatar'
|
20
|
+
assert_select 'div.controls' do
|
21
|
+
assert_select 'input[type=file]'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
assert_select "div.control-group" do
|
26
|
+
assert_select 'label.control-label', 'Password'
|
27
|
+
assert_select 'div.controls' do
|
28
|
+
assert_select 'input[type=password]'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
assert_select "div.control-group" do
|
33
|
+
assert_select 'label.control-label', 'Motto'
|
34
|
+
assert_select 'div.controls' do
|
35
|
+
assert_select 'input[type=text]'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
assert_select "div.control-group" do
|
40
|
+
assert_select 'label.control-label', 'About'
|
41
|
+
assert_select 'div.controls' do
|
42
|
+
assert_select 'textarea[rows=?][cols=?]', 7, 40
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_select "div.control-group" do
|
47
|
+
assert_select 'label.control-label', 'Role'
|
48
|
+
assert_select 'div.controls' do
|
49
|
+
assert_select 'select'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
assert_select "div.control-group" do
|
54
|
+
assert_select 'label.control-label', 'Remember me'
|
55
|
+
assert_select 'div.controls' do
|
56
|
+
assert_select 'label.checkbox' do
|
57
|
+
assert_select 'input[type=hidden][value=?]', 0
|
58
|
+
assert_select 'input[type=checkbox][value=?]', 1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'renders error message' do
|
66
|
+
get :errors_for
|
67
|
+
response.should be_success
|
68
|
+
|
69
|
+
assert_select "form[class=?]", /form-horizontal/ do
|
70
|
+
assert_select 'div.alert.alert-error' do
|
71
|
+
assert_select 'p' do
|
72
|
+
assert_select 'b', 'User: not saved because of 1 error'
|
73
|
+
end
|
74
|
+
assert_select 'ul' do
|
75
|
+
assert_select 'li', 'Email should be email'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'renders field with hint' do
|
82
|
+
get :field_with_hint
|
83
|
+
response.should be_success
|
84
|
+
|
85
|
+
assert_select "form" do
|
86
|
+
assert_select 'div.control-group' do
|
87
|
+
assert_select 'label.control-label', 'Email'
|
88
|
+
assert_select 'div.controls' do
|
89
|
+
assert_select 'input[type=email]'
|
90
|
+
assert_select 'p.help-block', 'Enter proper email address'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'renders different buttons' do
|
97
|
+
get :buttons
|
98
|
+
response.should be_success
|
99
|
+
|
100
|
+
assert_select "form" do
|
101
|
+
assert_select 'div.form-actions' do
|
102
|
+
assert_select 'input.btn.btn-primary[type=?][value=?]', 'submit', 'Sign in'
|
103
|
+
assert_select 'button.btn[type=?]', 'submit', 'Cancel'
|
104
|
+
assert_select 'button.btn.btn-danger[type=?]', 'submit', 'Danger button'
|
105
|
+
assert_select 'input.btn[type=?][value=?]', 'submit', 'Submit without the primary class'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'renders submit buttons wrapped in div.form-actions' do
|
111
|
+
get :submit_button
|
112
|
+
response.should be_success
|
113
|
+
|
114
|
+
assert_select "form" do
|
115
|
+
assert_select "div.control-group" do
|
116
|
+
assert_select 'label.control-label', 'Email'
|
117
|
+
assert_select 'div.controls' do
|
118
|
+
assert_select 'input[type=email]'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
assert_select 'div.form-actions' do
|
123
|
+
assert_select 'input.btn.btn-primary[type=?][value=?]', 'submit', 'Create User'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ModalController do
|
4
|
+
render_views
|
5
|
+
|
6
|
+
it 'renders' do
|
7
|
+
get :simple
|
8
|
+
response.should be_success
|
9
|
+
|
10
|
+
assert_select 'div.modal.hide.fade#auth-modal' do
|
11
|
+
assert_select 'form[class=?]', 'form-horizontal' do
|
12
|
+
assert_select '.modal-header' do
|
13
|
+
assert 'a.close[data-dismiss=?]', 'modal'
|
14
|
+
assert_select 'h3', 'User'
|
15
|
+
end
|
16
|
+
|
17
|
+
assert_select '.modal-body' do
|
18
|
+
assert_select 'input[type=email]'
|
19
|
+
assert_select 'input[type=password]'
|
20
|
+
end
|
21
|
+
|
22
|
+
assert_select '.modal-footer' do
|
23
|
+
assert_select '.pull-left' do
|
24
|
+
assert_select 'a[href=#][data-dismiss=?][class=?]', 'modal', 'btn'
|
25
|
+
end
|
26
|
+
assert_select '.pull-right' do
|
27
|
+
assert_select 'input[type=submit][class=?][value=?]', 'btn btn-primary', 'Sign in'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|