the_role 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Bye_bye_CanCan_I_got_the_Role.png +0 -0
  2. data/README.md +82 -92
  3. data/app/assets/javascripts/admin_the_role.js +3 -0
  4. data/app/assets/javascripts/bootstrap-dropdown.js +100 -0
  5. data/app/assets/stylesheets/admin_the_role.css +7 -0
  6. data/app/assets/stylesheets/alerts.less +58 -0
  7. data/app/assets/stylesheets/button-groups.less +191 -0
  8. data/app/assets/stylesheets/buttons.less +191 -0
  9. data/app/assets/stylesheets/custom.scss +3 -0
  10. data/app/assets/stylesheets/dropdowns.less +143 -0
  11. data/app/assets/stylesheets/forms.less +583 -0
  12. data/app/assets/stylesheets/grid.less +5 -0
  13. data/app/assets/stylesheets/headers.scss +15 -0
  14. data/app/assets/stylesheets/layouts.less +17 -0
  15. data/app/assets/stylesheets/mix.scss +41 -0
  16. data/app/assets/stylesheets/mixins.less +646 -0
  17. data/app/assets/stylesheets/reset.css +117 -0
  18. data/app/assets/stylesheets/role_set.less +136 -0
  19. data/app/assets/stylesheets/scaffolding.less +29 -0
  20. data/app/assets/stylesheets/variables.less +206 -0
  21. data/app/assets/stylesheets/wells.less +27 -0
  22. data/app/controllers/admin/role_sections_controller.rb +40 -17
  23. data/app/controllers/admin/roles_controller.rb +8 -6
  24. data/app/views/admin/roles/_role.html.haml +53 -0
  25. data/app/views/admin/roles/_sidebar.html.haml +8 -0
  26. data/app/views/admin/roles/edit.html.haml +2 -42
  27. data/app/views/admin/roles/index.haml +2 -15
  28. data/app/views/admin/roles/new.html.haml +5 -4
  29. data/app/views/layouts/the_role.html.haml +24 -0
  30. data/config/routes.rb +5 -1
  31. data/lib/the_role/engine.rb +2 -2
  32. data/lib/the_role/hash.rb +50 -14
  33. data/lib/the_role/modules/base.rb +4 -4
  34. data/lib/the_role/modules/controller_requires.rb +4 -15
  35. data/lib/the_role/modules/role_model.rb +14 -13
  36. data/lib/the_role/param_helper.rb +15 -0
  37. data/lib/the_role/version.rb +1 -1
  38. data/lib/the_role.rb +13 -11
  39. data/pic.png +0 -0
  40. data/the_role.gemspec +5 -2
  41. metadata +58 -16
  42. data/app/assets/stylesheets/the_role/form.css +0 -57
  43. data/app/assets/stylesheets/the_role/headers.css.scss +0 -15
  44. data/app/assets/stylesheets/the_role/style.css.scss +0 -75
  45. data/lib/the_role/modules/param_helper.rb +0 -7
Binary file
data/README.md CHANGED
@@ -1,10 +1,14 @@
1
- # gem 'the_role'
1
+ # gem 'the_role' (alpha v0.1)
2
2
 
3
- ## Bye bye CanCan, I got The Role!
3
+ | Bye bye CanCan, I got The Role! | Description |
4
+ |:------------- |:-------------|
5
+ | ![Bye bye CanCan, I got The Role!](https://github.com/the-teacher/the_role/raw/master/Bye_bye_CanCan_I_got_the_Role.png) | TheRole is an authorization library for Ruby on Rails which restricts what resources a given user is allowed to access. All permissions are defined in with 2-level-hash, and store in database with JSON.<br><br>TheRole - Semantic, lightweight role system with an administrative interface.<br><br>Role is a two-level hash, consisting of the **sections** and nested **rules**.<br><br>**Section** may be associated with **controller** name.<br><br>**Rule** may be associated with **action** name.<br><br>Section can have many rules.<br><br>Rule can have **true** or **false** value<br><br>**Sections** and nested **Rules** provide **ACL** (**Access Control List**)<br><br>Role **stored in the database as JSON** string.<br><br>Using of hashes, makes role system extremely easy to configure and use.<br> |
4
6
 
5
- Semantic, lightweight role system with an administrative interface
7
+ ### GUI
6
8
 
7
- ![TheSortableTree](https://github.com/the-teacher/the_role/raw/master/pic.png)
9
+ | TheRole management web interface |
10
+ |:-------------:|
11
+ |![TheRole](https://github.com/the-teacher/the_role/raw/master/pic.png)|
8
12
 
9
13
  ## What does it mean semantic?
10
14
 
@@ -14,73 +18,55 @@ Look at hash. If you can understand access rules - this role system is semantica
14
18
 
15
19
  ``` ruby
16
20
  role = {
17
- :pages => {
18
- :index => true,
19
- :show => true,
20
- :new => false,
21
- :edit => false,
22
- :update => false,
23
- :destroy => false
21
+ 'pages' => {
22
+ 'index' => true,
23
+ 'show' => true,
24
+ 'new' => false,
25
+ 'edit' => false,
26
+ 'update' => false,
27
+ 'destroy' => false
24
28
  },
25
- :articles => {
26
- :index => true,
27
- :show => true
28
- }
29
- :twitter => {
30
- :button => true,
31
- :follow => false
29
+ 'articles' => {
30
+ 'index' => true,
31
+ 'show' => true
32
+ },
33
+ 'twitter' => {
34
+ 'button' => true,
35
+ 'follow' => false
32
36
  }
33
37
  }
34
38
  ```
35
39
 
36
- ### How it works
37
-
38
- Role - is a two-level hash, consisting of the sections and rules.
39
-
40
- **Section** may be associated with the name of a **controller**.
41
-
42
- **Rule** may be associated with the name of **action** in the controller.
43
-
44
- Section may contain a set of rules.
45
-
46
- **Rule in Section** can be set to **true** and **false**, this provide **ACL** (**Access Control List**)
47
-
48
- Role hash **stored in the database as YAML** string.
49
- Using of hashes, makes it extremely easy to configure access rules in the role.
50
-
51
40
  ### Virtual sections and rules
52
41
 
53
- Usually, we use real names of controllers as names of sections, and we use names of real actions in controllers as names of section's rules.
54
-
55
- Like this:
42
+ Usually, we use real names of controllers and actions for names of sections and rules:
56
43
 
57
44
  ``` ruby
58
45
  current_user.has_role?(:pages, :show)
59
46
  ```
60
47
 
61
- But you can also create virtual sections and rules:
62
-
48
+ But, also, you can use virtual names of sections, and virtual names of section's rules.
63
49
 
64
50
  ``` ruby
65
51
  current_user.has_role?(:twitter, :button)
66
52
  current_user.has_role?(:facebook, :like)
67
53
  ```
68
54
 
69
- These sections and the rules are not associated with real controllers and actions.
70
55
  And you can use them as well as other access rules.
71
56
 
72
- ### Install and use
57
+ # Install
73
58
 
74
59
  ``` ruby
75
60
  gem 'the_role'
76
61
  ```
77
62
 
78
63
  ``` ruby
79
- bundle install
64
+ bundle
80
65
  ```
81
66
 
82
- Add **role_id:integer** to User Model Migration
67
+ ### Migrate
83
68
 
69
+ Add **role_id:integer** to User Model Migration
84
70
 
85
71
  ``` ruby
86
72
  rake the_role_engine:install:migrations
@@ -95,18 +81,16 @@ rails g model role --migration=false
95
81
  rake db:create && rake db:migrate
96
82
  ```
97
83
 
98
- Creating roles for test (**not required**)
84
+ ### Fake roles for test (not required)
85
+
86
+ Creating roles for test
99
87
 
100
88
  ``` ruby
101
89
  rake db:roles:test
102
90
  >> Administrator, Moderator of pages, User, Demo
103
91
  ```
104
92
 
105
- Define aliases method for correctly work TheRole's controllers
106
-
107
- **authenticate_user!** or any other method from your auth system
108
-
109
- **access_denied** or any other method for processing access denied situation
93
+ ### Change your ApplicationController
110
94
 
111
95
  **Example for Devise2**
112
96
 
@@ -118,55 +102,48 @@ class ApplicationController < ActionController::Base
118
102
  render :text => 'access_denied: requires an role' and return
119
103
  end
120
104
 
121
- # define aliases for correctly work of TheRole admin panel
122
- # *authenticate_user!* - method from Devise2
123
- # *access_denied* - define it before alias_method
124
- # before_filter :role_object_finder, :only => [:edit, :update, :rebuild, :destroy]
125
- alias_method :role_login_required, :authenticate_user!
126
- alias_method :role_access_denied, :access_denied
105
+ alias_method :login_required, :authenticate_user!
106
+ alias_method :role_access_denied, :access_denied
127
107
 
128
108
  end
129
109
  ```
130
110
 
131
- Using with any controller
132
-
133
- ``` ruby
134
- class PagesController < ApplicationController
135
- # Devise2 and TheRole before_filters
136
- before_filter :role_login_required, :except => [:index, :show]
137
- before_filter :role_require, :except => [:index, :show]
138
-
139
- before_filter :find_page, :only => [:edit, :update, :destroy]
140
- before_filter :owner_require, :only => [:edit, :update, :destroy]
111
+ Define aliases method for correctly work TheRole's controllers
141
112
 
142
- end
143
- ```
113
+ **authenticate_user!** or any other method from your auth system
144
114
 
145
- ### WARNING! IT'S IMPORTANT
115
+ **access_denied** or any other method for processing access denied situation
146
116
 
147
- When you checking **owner_require** - you should before this to define variable **@object_for_ownership_checking** in finder method.
148
117
 
149
- For example:
118
+ ### Using with any controller
150
119
 
151
120
  ``` ruby
152
121
  class PagesController < ApplicationController
153
- before_filter :find_page, :only => [:edit, :update, :destroy]
154
- before_filter :owner_require, :only => [:edit, :update, :destroy]
155
-
122
+ # Devise2 and TheRole before_filters
123
+ before_filter :login_required, :except => [:index, :show]
124
+ before_filter :role_required, :except => [:index, :show]
125
+
126
+ before_filter :find_page, :only => [:edit, :update, :destroy]
127
+ before_filter :owner_required, :only => [:edit, :update, :destroy]
128
+
156
129
  private
157
130
 
158
131
  def find_page
159
132
  @page = Page.find params[:id]
160
- @object_for_ownership_checking = @page
133
+ @ownership_checking_object = @page
161
134
  end
162
135
  end
163
136
  ```
164
137
 
165
- ### Who is the Administrator?
138
+ **owner_required** method require **@ownership_checking_object** variable, with cheked object.
139
+
140
+ ### Who is Administrator?
166
141
 
167
- Administrator - a user who can access any section and the rules of your application.
168
- The administrator is the owner of any objects in your application.
169
- Administrator - a user in the role-hash of which there is a section **system** and rule **administrator**.
142
+ Administrator it's a user who can access any section and the rules of your application.
143
+
144
+ Administrator is the owner of any objects in your application.
145
+
146
+ Administrator it's a user, which has virtual section **system** and rule **administrator** in the role-hash.
170
147
 
171
148
 
172
149
  ``` ruby
@@ -177,13 +154,15 @@ admin_role_fragment = {
177
154
  }
178
155
  ```
179
156
 
180
- ### Who is the Moderator?
157
+ ### Who is Moderator?
158
+
159
+ Moderator it's a user, which has access to any actions of some section(s).
181
160
 
182
- Moderator - a user who can access any actions of sections.
183
- Moderator is the owner of any objects of this class.
184
- Moderator - user which has in a section **moderator** rule with name of real or virtual section (controller).
161
+ Moderator is's owner of any objects of some class.
185
162
 
186
- There is role hash of Moderator of Pages (controller) and Twitter (virtual section)
163
+ Moderator it's a user, which has a virtual section **moderator**, with **section name** as rule name.
164
+
165
+ There is Moderator of Pages (controller) and Twitter (virtual section)
187
166
 
188
167
  ``` ruby
189
168
  moderator_role_fragment = {
@@ -195,9 +174,17 @@ moderator_role_fragment = {
195
174
  }
196
175
  ```
197
176
 
198
- ### User methods
177
+ ### Who is Owner?
178
+
179
+ Administrator is owner of any object in system.
180
+
181
+ Moderator of pages is owner of any page.
199
182
 
200
- Has a user an access to **action** of **section**?
183
+ User is owner of object, when **Object#user_id == User#id**.
184
+
185
+ # User Model methods
186
+
187
+ Has a user an access to **rule** of **section** (action of controller)?
201
188
 
202
189
  ``` ruby
203
190
  current_user.has_role?(:pages, :show) => true | false
@@ -227,22 +214,25 @@ current_user.owner?(@blog) => true | false
227
214
  current_user.owner?(@article) => true | false
228
215
  ```
229
216
 
230
- ### Role methods
217
+ # Base Role methods
231
218
 
232
219
  ``` ruby
233
- # Find a Role by name
234
- @role.find_by_name(:user)
220
+ # User's role
221
+ @role = current_user.role
235
222
  ```
236
223
 
237
224
  ``` ruby
238
- # User Model like methods
225
+ # Find a Role by name
226
+ @role = Role.find_by_name(:user)
227
+ ```
239
228
 
229
+ ``` ruby
240
230
  @role.has?(:pages, :show) => true | false
241
231
  @role.moderator?(:pages) => true | false
242
232
  @role.admin? => true | false
243
233
  ```
244
234
 
245
- ## CRUD API
235
+ # CRUD API (for console users)
246
236
 
247
237
  #### CREATE
248
238
 
@@ -261,10 +251,10 @@ current_user.owner?(@article) => true | false
261
251
  ``` ruby
262
252
  @role.to_hash => Hash
263
253
 
264
- # YAML string
265
- @role.to_yaml => String
254
+ # JSON string
255
+ @role.to_json => String
266
256
 
267
- # YAML string
257
+ # JSON string
268
258
  @role.to_s => String
269
259
  ```
270
260
 
@@ -0,0 +1,3 @@
1
+ //= require jquery
2
+ //= require jquery_ujs
3
+ //= require bootstrap-dropdown
@@ -0,0 +1,100 @@
1
+ /* ============================================================
2
+ * bootstrap-dropdown.js v2.0.4
3
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
4
+ * ============================================================
5
+ * Copyright 2012 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ============================================================ */
19
+
20
+
21
+ !function ($) {
22
+
23
+ "use strict"; // jshint ;_;
24
+
25
+
26
+ /* DROPDOWN CLASS DEFINITION
27
+ * ========================= */
28
+
29
+ var toggle = '[data-toggle="dropdown"]'
30
+ , Dropdown = function (element) {
31
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
32
+ $('html').on('click.dropdown.data-api', function () {
33
+ $el.parent().removeClass('open')
34
+ })
35
+ }
36
+
37
+ Dropdown.prototype = {
38
+
39
+ constructor: Dropdown
40
+
41
+ , toggle: function (e) {
42
+ var $this = $(this)
43
+ , $parent
44
+ , selector
45
+ , isActive
46
+
47
+ if ($this.is('.disabled, :disabled')) return
48
+
49
+ selector = $this.attr('data-target')
50
+
51
+ if (!selector) {
52
+ selector = $this.attr('href')
53
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
54
+ }
55
+
56
+ $parent = $(selector)
57
+ $parent.length || ($parent = $this.parent())
58
+
59
+ isActive = $parent.hasClass('open')
60
+
61
+ clearMenus()
62
+
63
+ if (!isActive) $parent.toggleClass('open')
64
+
65
+ return false
66
+ }
67
+
68
+ }
69
+
70
+ function clearMenus() {
71
+ $(toggle).parent().removeClass('open')
72
+ }
73
+
74
+
75
+ /* DROPDOWN PLUGIN DEFINITION
76
+ * ========================== */
77
+
78
+ $.fn.dropdown = function (option) {
79
+ return this.each(function () {
80
+ var $this = $(this)
81
+ , data = $this.data('dropdown')
82
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
83
+ if (typeof option == 'string') data[option].call($this)
84
+ })
85
+ }
86
+
87
+ $.fn.dropdown.Constructor = Dropdown
88
+
89
+
90
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
91
+ * =================================== */
92
+
93
+ $(function () {
94
+ $('html').on('click.dropdown.data-api', clearMenus)
95
+ $('body')
96
+ .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
97
+ .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
98
+ })
99
+
100
+ }(window.jQuery);
@@ -0,0 +1,7 @@
1
+ /*
2
+ *= require 'mix'
3
+ *= require 'reset'
4
+ *= require 'custom'
5
+ *= require 'headers'
6
+ *= require 'role_set'
7
+ */
@@ -0,0 +1,58 @@
1
+ // ALERT STYLES
2
+ // ------------
3
+
4
+ // Base alert styles
5
+ .alert {
6
+ padding: 8px 35px 8px 14px;
7
+ margin-bottom: @baseLineHeight;
8
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
9
+ background-color: @warningBackground;
10
+ border: 1px solid @warningBorder;
11
+ .border-radius(4px);
12
+ color: @warningText;
13
+ }
14
+ .alert-heading {
15
+ color: inherit;
16
+ }
17
+
18
+ // Adjust close link position
19
+ .alert .close {
20
+ position: relative;
21
+ top: -2px;
22
+ right: -21px;
23
+ line-height: 18px;
24
+ }
25
+
26
+ // Alternate styles
27
+ // ----------------
28
+
29
+ .alert-success {
30
+ background-color: @successBackground;
31
+ border-color: @successBorder;
32
+ color: @successText;
33
+ }
34
+ .alert-danger,
35
+ .alert-error {
36
+ background-color: @errorBackground;
37
+ border-color: @errorBorder;
38
+ color: @errorText;
39
+ }
40
+ .alert-info {
41
+ background-color: @infoBackground;
42
+ border-color: @infoBorder;
43
+ color: @infoText;
44
+ }
45
+
46
+ // Block alerts
47
+ // ------------------------
48
+ .alert-block {
49
+ padding-top: 14px;
50
+ padding-bottom: 14px;
51
+ }
52
+ .alert-block > p,
53
+ .alert-block > ul {
54
+ margin-bottom: 0;
55
+ }
56
+ .alert-block p + p {
57
+ margin-top: 5px;
58
+ }
@@ -0,0 +1,191 @@
1
+ // BUTTON GROUPS
2
+ // -------------
3
+
4
+
5
+ // Make the div behave like a button
6
+ .btn-group {
7
+ position: relative;
8
+ .clearfix(); // clears the floated buttons
9
+ .ie7-restore-left-whitespace();
10
+ }
11
+
12
+ // Space out series of button groups
13
+ .btn-group + .btn-group {
14
+ margin-left: 5px;
15
+ }
16
+
17
+ // Optional: Group multiple button groups together for a toolbar
18
+ .btn-toolbar {
19
+ margin-top: @baseLineHeight / 2;
20
+ margin-bottom: @baseLineHeight / 2;
21
+ .btn-group {
22
+ display: inline-block;
23
+ .ie7-inline-block();
24
+ }
25
+ }
26
+
27
+ // Float them, remove border radius, then re-add to first and last elements
28
+ .btn-group > .btn {
29
+ position: relative;
30
+ float: left;
31
+ margin-left: -1px;
32
+ .border-radius(0);
33
+ }
34
+ // Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
35
+ .btn-group > .btn:first-child {
36
+ margin-left: 0;
37
+ -webkit-border-top-left-radius: 4px;
38
+ -moz-border-radius-topleft: 4px;
39
+ border-top-left-radius: 4px;
40
+ -webkit-border-bottom-left-radius: 4px;
41
+ -moz-border-radius-bottomleft: 4px;
42
+ border-bottom-left-radius: 4px;
43
+ }
44
+ // Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it
45
+ .btn-group > .btn:last-child,
46
+ .btn-group > .dropdown-toggle {
47
+ -webkit-border-top-right-radius: 4px;
48
+ -moz-border-radius-topright: 4px;
49
+ border-top-right-radius: 4px;
50
+ -webkit-border-bottom-right-radius: 4px;
51
+ -moz-border-radius-bottomright: 4px;
52
+ border-bottom-right-radius: 4px;
53
+ }
54
+ // Reset corners for large buttons
55
+ .btn-group > .btn.large:first-child {
56
+ margin-left: 0;
57
+ -webkit-border-top-left-radius: 6px;
58
+ -moz-border-radius-topleft: 6px;
59
+ border-top-left-radius: 6px;
60
+ -webkit-border-bottom-left-radius: 6px;
61
+ -moz-border-radius-bottomleft: 6px;
62
+ border-bottom-left-radius: 6px;
63
+ }
64
+ .btn-group > .btn.large:last-child,
65
+ .btn-group > .large.dropdown-toggle {
66
+ -webkit-border-top-right-radius: 6px;
67
+ -moz-border-radius-topright: 6px;
68
+ border-top-right-radius: 6px;
69
+ -webkit-border-bottom-right-radius: 6px;
70
+ -moz-border-radius-bottomright: 6px;
71
+ border-bottom-right-radius: 6px;
72
+ }
73
+
74
+ // On hover/focus/active, bring the proper btn to front
75
+ .btn-group > .btn:hover,
76
+ .btn-group > .btn:focus,
77
+ .btn-group > .btn:active,
78
+ .btn-group > .btn.active {
79
+ z-index: 2;
80
+ }
81
+
82
+ // On active and open, don't show outline
83
+ .btn-group .dropdown-toggle:active,
84
+ .btn-group.open .dropdown-toggle {
85
+ outline: 0;
86
+ }
87
+
88
+
89
+
90
+ // Split button dropdowns
91
+ // ----------------------
92
+
93
+ // Give the line between buttons some depth
94
+ .btn-group > .dropdown-toggle {
95
+ padding-left: 8px;
96
+ padding-right: 8px;
97
+ .box-shadow(~"inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
98
+ *padding-top: 4px;
99
+ *padding-bottom: 4px;
100
+ }
101
+ .btn-group > .btn-mini.dropdown-toggle {
102
+ padding-left: 5px;
103
+ padding-right: 5px;
104
+ }
105
+ .btn-group > .btn-small.dropdown-toggle {
106
+ *padding-top: 4px;
107
+ *padding-bottom: 4px;
108
+ }
109
+ .btn-group > .btn-large.dropdown-toggle {
110
+ padding-left: 12px;
111
+ padding-right: 12px;
112
+ }
113
+
114
+ .btn-group.open {
115
+
116
+ // The clickable button for toggling the menu
117
+ // Remove the gradient and set the same inset shadow as the :active state
118
+ .dropdown-toggle {
119
+ background-image: none;
120
+ .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
121
+ }
122
+
123
+ // Keep the hover's background when dropdown is open
124
+ .btn.dropdown-toggle {
125
+ background-color: @btnBackgroundHighlight;
126
+ }
127
+ .btn-primary.dropdown-toggle {
128
+ background-color: @btnPrimaryBackgroundHighlight;
129
+ }
130
+ .btn-warning.dropdown-toggle {
131
+ background-color: @btnWarningBackgroundHighlight;
132
+ }
133
+ .btn-danger.dropdown-toggle {
134
+ background-color: @btnDangerBackgroundHighlight;
135
+ }
136
+ .btn-success.dropdown-toggle {
137
+ background-color: @btnSuccessBackgroundHighlight;
138
+ }
139
+ .btn-info.dropdown-toggle {
140
+ background-color: @btnInfoBackgroundHighlight;
141
+ }
142
+ .btn-inverse.dropdown-toggle {
143
+ background-color: @btnInverseBackgroundHighlight;
144
+ }
145
+ }
146
+
147
+
148
+ // Reposition the caret
149
+ .btn .caret {
150
+ margin-top: 7px;
151
+ margin-left: 0;
152
+ }
153
+ .btn:hover .caret,
154
+ .open.btn-group .caret {
155
+ .opacity(100);
156
+ }
157
+ // Carets in other button sizes
158
+ .btn-mini .caret {
159
+ margin-top: 5px;
160
+ }
161
+ .btn-small .caret {
162
+ margin-top: 6px;
163
+ }
164
+ .btn-large .caret {
165
+ margin-top: 6px;
166
+ border-left-width: 5px;
167
+ border-right-width: 5px;
168
+ border-top-width: 5px;
169
+ }
170
+ // Upside down carets for .dropup
171
+ .dropup .btn-large .caret {
172
+ border-bottom: 5px solid @black;
173
+ border-top: 0;
174
+ }
175
+
176
+
177
+
178
+ // Account for other colors
179
+ .btn-primary,
180
+ .btn-warning,
181
+ .btn-danger,
182
+ .btn-info,
183
+ .btn-success,
184
+ .btn-inverse {
185
+ .caret {
186
+ border-top-color: @white;
187
+ border-bottom-color: @white;
188
+ .opacity(75);
189
+ }
190
+ }
191
+