easy_menu 0.2.2
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.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/MIT-LICENSE +19 -0
- data/README +4 -0
- data/app/assets/images/arrows.png +0 -0
- data/app/assets/images/checkbox_selected.png +0 -0
- data/app/assets/images/checkbox_selected_hovered.png +0 -0
- data/app/assets/javascripts/easy_menu_jquery.js +59 -0
- data/app/assets/javascripts/easy_menu_prototype.js +56 -0
- data/app/assets/stylesheets/_easy_menu_mixins.scss +252 -0
- data/app/assets/stylesheets/easy_menu.css.scss +216 -0
- data/app/helpers/menu_bar.rb +310 -0
- data/app/helpers/menu_bar_helper.rb +5 -0
- data/config/initializers/easy_menu_scss_extensions.rb +21 -0
- data/lib/easy_menu.rb +7 -0
- data/lib/easy_menu_configuration.rb +60 -0
- data/lib/easy_menu_helpers.rb +36 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e4f6990701058e22283c180fef8fe41a1ec80951
|
4
|
+
data.tar.gz: 28e9fc33e9e1e32424885884bf9967ba8cc48129
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6a2f590cdc0d64bbeb095272a4008cccb46925382564126dfe0d9b102becbd82a5600c13ae2b35495ebea4c6abfbdcd2723d03389f80a5a9ad4cbb4c7cc41b15
|
7
|
+
data.tar.gz: a6c806734115f44e2ceea6a437956c75b8948b1ec3c6b8e3b193b7273a78eef5db66db9dce63fe0d91f7cbc8293ed57bb2715920fe99c6bd1b95a37d423a40fa
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2011 by Nicholas Jakobsen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,59 @@
|
|
1
|
+
$(document).ready(function() {
|
2
|
+
var menuBarRootSelector = '.menu_bar:not(.no_js) ';
|
3
|
+
|
4
|
+
// Because some browsers don't support submit buttons outside of forms triggering form submits,
|
5
|
+
// do it in javascript just to make sure it happens
|
6
|
+
$(document).on('click', 'input[type=submit][form]', function(){
|
7
|
+
if (form = document.getElementById(this.getAttribute('form'))) {
|
8
|
+
// If the form is already submitting, we want don't want to submit it again.
|
9
|
+
if ($(form).hasClass('submitting')) {
|
10
|
+
return false;
|
11
|
+
}
|
12
|
+
|
13
|
+
var tempCommit = $("<input type='submit' name='commit' style='display:none'>");
|
14
|
+
tempCommit.attr('value', $(this).attr('value'));
|
15
|
+
form.appendChild(tempCommit[0]);
|
16
|
+
tempCommit.click();
|
17
|
+
return false;
|
18
|
+
}
|
19
|
+
});
|
20
|
+
// Used by the above click handler to determine if the browser already submitted the form.
|
21
|
+
$('form').submit(function() {
|
22
|
+
$(this).addClass('submitting');
|
23
|
+
});
|
24
|
+
|
25
|
+
// Allow users to open an close menus by clicking
|
26
|
+
$(menuBarRootSelector + '.menu_bar_content.with_menu').removeClass('no_js');
|
27
|
+
$(menuBarRootSelector + '.menu_bar_content.with_menu .menu_bar_item').click(function(){
|
28
|
+
var mbc = $(this).closest('.menu_bar_content');
|
29
|
+
$(menuBarRootSelector + '.menu_bar_content.with_menu').not(mbc).removeClass('open');
|
30
|
+
mbc.toggleClass('open');
|
31
|
+
});
|
32
|
+
|
33
|
+
$('body').click(function(event){
|
34
|
+
if ($(event.target).closest('.menu_bar_content.with_menu .menu_bar_item').length > 0) { return } // Don't close the menus if the click came from a menu
|
35
|
+
$(menuBarRootSelector + '.menu_bar_content.with_menu.open').removeClass('open');
|
36
|
+
});
|
37
|
+
|
38
|
+
// Disable Elements with a disable condition when that condition is met
|
39
|
+
$(menuBarRootSelector + '.menu_bar_item[data-disable-event-element]').each(function(){
|
40
|
+
var mbi = $(this);
|
41
|
+
var observableElement = eval(mbi.getAttribute('data-disable-event-element'));
|
42
|
+
var event = mbi.getAttribute('data-disable-event');
|
43
|
+
var condition = mbi.getAttribute('data-disable-condition') || true;
|
44
|
+
|
45
|
+
var setState = function(){
|
46
|
+
if (eval(condition)){
|
47
|
+
mbi.addClass('disabled');
|
48
|
+
} else {
|
49
|
+
mbi.removeClass('disabled');
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
// Init the current state and bind the observer
|
54
|
+
if (observableElement && event){
|
55
|
+
setState();
|
56
|
+
observableElement.bind(event, setState);
|
57
|
+
}
|
58
|
+
});
|
59
|
+
});
|
@@ -0,0 +1,56 @@
|
|
1
|
+
$(document).observe('dom:loaded', function() {
|
2
|
+
var menuBarRootSelector = '.menu_bar:not(.no_js) ';
|
3
|
+
|
4
|
+
// Because some browsers don't support submit buttons outside of forms triggering form submits,
|
5
|
+
// do it in javascript just to make sure it happens
|
6
|
+
Element.on(document.body, 'click', 'input[type=submit][form]', function(event){
|
7
|
+
var element = event.element();
|
8
|
+
if (form = document.getElementById(element.getAttribute('form'))) {
|
9
|
+
event.stop();
|
10
|
+
// If the form is already submitting, we want don't want to submit it again.
|
11
|
+
if ($(form).hasClassName('submitting')) {
|
12
|
+
return;
|
13
|
+
}
|
14
|
+
|
15
|
+
var tempCommit = new Element('input', {type:'submit', name:'commit', style:'display: none', 'value':element.getAttribute('value')});
|
16
|
+
form.appendChild(tempCommit[0]);
|
17
|
+
tempCommit.click();
|
18
|
+
}
|
19
|
+
});
|
20
|
+
// Used by the above click handler to determine if the browser already submitted the form.
|
21
|
+
$$('form').invoke('observe', 'submit', function(event) { event.element().addClassName('submitting') });
|
22
|
+
|
23
|
+
// Allow users to open an close menus by clicking
|
24
|
+
$$(menuBarRootSelector + '.menu_bar_content.with_menu').invoke('removeClassName', 'no_js');
|
25
|
+
$$(menuBarRootSelector + '.menu_bar_content.with_menu .menu_bar_item').invoke('observe', 'click', function(event){
|
26
|
+
var mbc = $(event.element()).up('.menu_bar_content');
|
27
|
+
$$('.menu_bar_content.with_menu').without(mbc).invoke('removeClassName', 'open');
|
28
|
+
mbc.toggleClassName('open');
|
29
|
+
});
|
30
|
+
Element.observe(document.body, 'click', function(event){
|
31
|
+
if (event.findElement('.menu_bar_content.with_menu .menu_bar_item')){ return } // Don't close the menus if the click came from a menu trigger
|
32
|
+
$$(menuBarRootSelector + '.menu_bar_content.with_menu.open').invoke('removeClassName', 'open');
|
33
|
+
});
|
34
|
+
|
35
|
+
// Disable Elements with a disable condition when that condition is met
|
36
|
+
$$(menuBarRootSelector + '.menu_bar_item[data-disable-event-element]').each(function(element){
|
37
|
+
var mbi = $(element);
|
38
|
+
var observableElement = eval(mbi.getAttribute('data-disable-event-element'));
|
39
|
+
var event = mbi.getAttribute('data-disable-event');
|
40
|
+
var condition = mbi.getAttribute('data-disable-condition') || true;
|
41
|
+
|
42
|
+
function setState(){
|
43
|
+
if (eval(condition)){
|
44
|
+
mbi.addClassName('disabled');
|
45
|
+
} else {
|
46
|
+
mbi.removeClassName('disabled');
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
// Init the current state and bind the observer
|
51
|
+
if (observableElement && event){
|
52
|
+
setState();
|
53
|
+
$(observableElement).observe(event, setState);
|
54
|
+
}
|
55
|
+
});
|
56
|
+
});
|
@@ -0,0 +1,252 @@
|
|
1
|
+
// VARIABLES
|
2
|
+
$menu-bar-item-horizontal-padding: 7px;
|
3
|
+
$menu-bar-item-height: 26px;
|
4
|
+
$menu-bar-item-min-width: $menu-bar-item-height;
|
5
|
+
$menu-bar-item-border-radius: 2px;
|
6
|
+
$menu-bar-item-border-darken: .1;
|
7
|
+
$menu-bar-item-border-shadow-darken: .3;
|
8
|
+
$menu-bar-item-border-width: 1px;
|
9
|
+
$menu-bar-item-border-colour: rgba(0,0,0, $menu-bar-item-border-darken);
|
10
|
+
$menu-bar-item-border-shadow-colour: rgba(0,0,0, $menu-bar-item-border-shadow-darken);
|
11
|
+
$menu-bar-item-light-colour: #FEFEFE;
|
12
|
+
$menu-bar-item-dark-colour: #DDDEDE;
|
13
|
+
$menu-bar-item-text-color: #333;
|
14
|
+
$menu-bar-item-disabled-text-color: #999;
|
15
|
+
$menu-bar-item-spacing: 10px;
|
16
|
+
$menu-bar-height: 2*$menu-bar-item-border-width + $menu-bar-item-height;
|
17
|
+
$menu-bar-font: bold 12px 'Arial', 'sans-serif';
|
18
|
+
$menu-bar-separator-height: 26px;
|
19
|
+
$menu-border-width: 1px;
|
20
|
+
$menu-vertical-padding: 0.2em;
|
21
|
+
$menu-item-vertical-padding: 0.4em;
|
22
|
+
$menu-item-horizontal-padding: 2em;
|
23
|
+
$menu-item-disabled-text-color: #AAA;
|
24
|
+
// Make the button border appear even when in a group by popping the button up above its siblings
|
25
|
+
$menu-bar-item-zindex: 1;
|
26
|
+
$menu-bar-item-hover-zindex: 2;
|
27
|
+
$menu-bar-item-pressed-zindex: 3;
|
28
|
+
|
29
|
+
// HELPERS
|
30
|
+
|
31
|
+
@mixin no-select{
|
32
|
+
-moz-user-select: none;
|
33
|
+
-webkit-user-select: none;
|
34
|
+
user-select: none;
|
35
|
+
}
|
36
|
+
@mixin no-drag{
|
37
|
+
-moz-user-drag: none;
|
38
|
+
-webkit-user-drag: none;
|
39
|
+
user-drag: none;
|
40
|
+
}
|
41
|
+
@mixin menu-bar-item-border-shadow-with-fallback($background-colour: $menu-bar-item-dark-colour){
|
42
|
+
border-bottom-color: darken($background-colour, percentage($menu-bar-item-border-shadow-darken)); // Fallback
|
43
|
+
border-bottom-color: $menu-bar-item-border-shadow-colour;
|
44
|
+
}
|
45
|
+
@mixin menu-bar-item-border-colour-with-fallback($background-colour: $menu-bar-item-dark-colour){
|
46
|
+
border-color: darken($background-colour, percentage($menu-bar-item-border-darken)); // Fallback
|
47
|
+
border-color: $menu-bar-item-border-colour;
|
48
|
+
@include menu-bar-item-border-shadow-with-fallback($background-colour);
|
49
|
+
}
|
50
|
+
@mixin menu-bar-item-border($background-colour: $menu-bar-item-dark-colour){
|
51
|
+
border: $menu-bar-item-border-width solid;
|
52
|
+
@include menu-bar-item-border-colour-with-fallback($background-colour);
|
53
|
+
border-radius: $menu-bar-item-border-radius;
|
54
|
+
-moz-transition: border-color 0.2s linear;
|
55
|
+
-webkit-transition: border-color 0.2s linear;
|
56
|
+
|
57
|
+
}
|
58
|
+
@mixin gradient($start, $end){
|
59
|
+
// IE 9+
|
60
|
+
background-image: data_url('image/svg+xml', '<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">
|
61
|
+
<linearGradient id="grad-ucgg-generated" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0%" y2="100%">
|
62
|
+
<stop offset="0%" stop-color="#{$start}" stop-opacity="1"/>
|
63
|
+
<stop offset="100%" stop-color="#{$end}" stop-opacity="1"/>
|
64
|
+
</linearGradient>
|
65
|
+
<rect x="0" y="0" width="1" height="1" fill="url(#grad-ucgg-generated)" />
|
66
|
+
</svg>');
|
67
|
+
|
68
|
+
background-image: -moz-linear-gradient(top, $start 0%, $end 100%);
|
69
|
+
background-image: -webkit-linear-gradient(top, $start 0%, $end 100%);
|
70
|
+
background-image: linear-gradient(top, $start 0%, $end 100%);
|
71
|
+
background-repeat: no-repeat;
|
72
|
+
}
|
73
|
+
@mixin button_colour($light, $dark, $text-colour: white, $text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25), $shift: 15px){
|
74
|
+
color: $text-colour !important; // Make this important because host app may override hover colours, but we don't want to be affected
|
75
|
+
text-shadow: $text-shadow;
|
76
|
+
@include menu-bar-item-border($dark);
|
77
|
+
|
78
|
+
background-color: mix($light, $dark);
|
79
|
+
|
80
|
+
// Don't override the background if the browser doesn't support gradients otherwise the buttons will be too dark
|
81
|
+
&:not(oldbrowser){
|
82
|
+
@include gradient($light, $dark);
|
83
|
+
background-color: $dark;
|
84
|
+
}
|
85
|
+
|
86
|
+
&:hover:not(:active):not(.disabled):not(.selected){
|
87
|
+
-moz-transition: background-position 0.1s linear;
|
88
|
+
-webkit-transition: background-position 0.1s linear;
|
89
|
+
background-position: 0 (-$shift);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
// STYLES
|
94
|
+
@mixin menu_bar_item{
|
95
|
+
@include menu_bar_item_base;
|
96
|
+
@include menu_bar_item_hover;
|
97
|
+
@include menu_bar_item_pressed;
|
98
|
+
|
99
|
+
@include menu_bar_item_default_colour;
|
100
|
+
&.danger{ @include menu_bar_item_danger_colour }
|
101
|
+
&.primary{ @include menu_bar_item_primary_colour }
|
102
|
+
&.info{ @include menu_bar_item_info_colour }
|
103
|
+
&.success{ @include menu_bar_item_success_colour }
|
104
|
+
&.warning{ @include menu_bar_item_warning_colour }
|
105
|
+
&.inverse{ @include menu_bar_item_inverse_colour }
|
106
|
+
|
107
|
+
@include menu_bar_item_disabled;
|
108
|
+
}
|
109
|
+
|
110
|
+
@mixin menu_bar_item_base{
|
111
|
+
@include menu-bar-item-border;
|
112
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); // Bevelled top edge
|
113
|
+
min-width: $menu-bar-item-min-width - 2*$menu-bar-item-horizontal-padding;
|
114
|
+
padding: 0 $menu-bar-item-horizontal-padding;
|
115
|
+
display: inline-block;
|
116
|
+
font: $menu-bar-font;
|
117
|
+
line-height: $menu-bar-item-height;
|
118
|
+
white-space: nowrap;
|
119
|
+
text-align: center;
|
120
|
+
cursor: pointer;
|
121
|
+
|
122
|
+
// Place the button above any nested menu
|
123
|
+
position: relative;
|
124
|
+
z-index: $menu-bar-item-zindex;
|
125
|
+
|
126
|
+
img{
|
127
|
+
vertical-align: middle;
|
128
|
+
position: relative;
|
129
|
+
bottom: 1px;
|
130
|
+
}
|
131
|
+
|
132
|
+
> a, > label{
|
133
|
+
cursor: pointer; // Override browser default on labels
|
134
|
+
text-decoration: none;
|
135
|
+
// Make the a fill the hoverable area of the button so clicking anywhere triggers the link
|
136
|
+
margin: -$menu-bar-item-horizontal-padding (-$menu-bar-item-horizontal-padding - $menu-bar-item-border-width);
|
137
|
+
padding: $menu-bar-item-horizontal-padding ($menu-bar-item-horizontal-padding + $menu-bar-item-border-width);
|
138
|
+
}
|
139
|
+
a:link, a:visited{
|
140
|
+
color: inherit;
|
141
|
+
}
|
142
|
+
|
143
|
+
// Hide the inputs without making them display none. IE doesn't click them if they are display none.
|
144
|
+
input[type='submit']{
|
145
|
+
position: absolute;
|
146
|
+
z-index: -1;
|
147
|
+
left: -9999px;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
@mixin menu_bar_item_hover{
|
151
|
+
&:hover{
|
152
|
+
border-color: #888; // Fallback
|
153
|
+
border-color: rgba(0,0,0, $menu-bar-item-border-darken * 2);
|
154
|
+
border-bottom-color: rgba(0,0,0, $menu-bar-item-border-shadow-darken * 2);
|
155
|
+
z-index: $menu-bar-item-hover-zindex;
|
156
|
+
position: relative;
|
157
|
+
}
|
158
|
+
}
|
159
|
+
@mixin menu_bar_item_pressed{
|
160
|
+
&:active, &.selected{
|
161
|
+
border-color: #555; // Fallback
|
162
|
+
border-color: rgba(0,0,0, $menu-bar-item-border-darken * 2);
|
163
|
+
box-shadow: 0 -1px 1px rgba(255, 255, 255, 0.4) inset, 0 2px 2px rgba(0, 0, 0, .3) inset;
|
164
|
+
z-index: $menu-bar-item-pressed-zindex;
|
165
|
+
position: relative;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
@mixin menu_bar_item_disabled{
|
170
|
+
&.disabled{
|
171
|
+
@include button_colour(#fefefe, #dddede, $menu-bar-item-disabled-text-color, 0 1px 1px rgba(255, 255, 255, 0.75));
|
172
|
+
cursor: default;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
@mixin menu_bar_item_default_colour{
|
177
|
+
@include button_colour($menu-bar-item-light-colour, $menu-bar-item-dark-colour, $menu-bar-item-text-color, 0 1px 1px rgba(255, 255, 255, 0.75), 5px);
|
178
|
+
}
|
179
|
+
@mixin menu_bar_item_danger_colour{
|
180
|
+
@include button_colour(#EE5F5B, #BD362F);
|
181
|
+
}
|
182
|
+
@mixin menu_bar_item_primary_colour{
|
183
|
+
@include button_colour(#0088CC, #0055CC);
|
184
|
+
}
|
185
|
+
@mixin menu_bar_item_info_colour{
|
186
|
+
@include button_colour(#5BC0DE, #2F96B4);
|
187
|
+
}
|
188
|
+
@mixin menu_bar_item_success_colour{
|
189
|
+
@include button_colour(#62C462, #51A351);
|
190
|
+
}
|
191
|
+
@mixin menu_bar_item_warning_colour{
|
192
|
+
@include button_colour(#FBB450, #F89406);
|
193
|
+
}
|
194
|
+
@mixin menu_bar_item_inverse_colour{
|
195
|
+
@include button_colour(#555555, #222222);
|
196
|
+
}
|
197
|
+
|
198
|
+
@mixin text-field{
|
199
|
+
border-radius: $menu-bar-item-border-radius;
|
200
|
+
border: 1px solid #AAA;
|
201
|
+
height: $menu-bar-height;
|
202
|
+
-moz-box-sizing: border-box;
|
203
|
+
-webkit-box-sizing: border-box;
|
204
|
+
box-sizing: border-box;
|
205
|
+
margin: 0;
|
206
|
+
padding-left: $menu-bar-item-horizontal-padding; // Define individually so we don't override top padding. IE8 issue
|
207
|
+
padding-right: $menu-bar-item-horizontal-padding; // Define individually so we don't override top padding. IE8 issue
|
208
|
+
}
|
209
|
+
|
210
|
+
@mixin menu_item{
|
211
|
+
@include menu_item_base;
|
212
|
+
@include menu_item_hover;
|
213
|
+
@include menu_item_disabled;
|
214
|
+
}
|
215
|
+
|
216
|
+
@mixin menu_item_base{
|
217
|
+
white-space: nowrap;
|
218
|
+
font: $menu-bar-font;
|
219
|
+
padding: $menu-item-vertical-padding $menu-item-horizontal-padding;
|
220
|
+
cursor: pointer;
|
221
|
+
|
222
|
+
a {
|
223
|
+
color: $menu-bar-item-text-color;
|
224
|
+
padding: $menu-item-vertical-padding $menu-item-horizontal-padding;
|
225
|
+
margin: (-$menu-item-vertical-padding) (-$menu-item-horizontal-padding);
|
226
|
+
display: block;
|
227
|
+
text-decoration: none;
|
228
|
+
}
|
229
|
+
}
|
230
|
+
@mixin menu_item_hover {
|
231
|
+
&.selected a {
|
232
|
+
background: url("/assets/checkbox_selected.png") no-repeat 5px center;
|
233
|
+
|
234
|
+
&:hover {
|
235
|
+
background: url("/assets/checkbox_selected_hovered.png") no-repeat 5px center;
|
236
|
+
}
|
237
|
+
}
|
238
|
+
&:hover {
|
239
|
+
background: #08C;
|
240
|
+
color: white;
|
241
|
+
|
242
|
+
a {
|
243
|
+
color: inherit;
|
244
|
+
}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
@mixin menu_item_disabled{
|
248
|
+
&.disabled, &.disabled a{
|
249
|
+
cursor: default;
|
250
|
+
color: $menu-item-disabled-text-color;
|
251
|
+
}
|
252
|
+
}
|
@@ -0,0 +1,216 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
|
+
*= require_self
|
6
|
+
*/
|
7
|
+
|
8
|
+
@import 'easy_menu_mixins';
|
9
|
+
|
10
|
+
// STYLES
|
11
|
+
.menu_bar.default_theme{
|
12
|
+
display: block;
|
13
|
+
margin: 0;
|
14
|
+
padding: 0;
|
15
|
+
list-style: none;
|
16
|
+
height: $menu-bar-height;
|
17
|
+
position: relative;
|
18
|
+
z-index: 0; // Scope all positioned elements z-index within the menu so they don't move above or below other page elements, only each other
|
19
|
+
|
20
|
+
// MENU BAR_GROUP
|
21
|
+
.menu_bar_group{
|
22
|
+
padding: 0;
|
23
|
+
|
24
|
+
.menu_bar_content{
|
25
|
+
margin-left: -$menu-bar-item-spacing - $menu-bar-item-border-width;
|
26
|
+
|
27
|
+
.menu_bar_item{
|
28
|
+
border-radius: 0;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
.menu_bar_content:first-child{
|
33
|
+
margin-left: 0;
|
34
|
+
|
35
|
+
.menu_bar_item{
|
36
|
+
border-top-left-radius: $menu-bar-item-border-radius;
|
37
|
+
border-bottom-left-radius: $menu-bar-item-border-radius;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
.menu_bar_content:last-child{
|
41
|
+
margin-right: 0;
|
42
|
+
|
43
|
+
.menu_bar_item{
|
44
|
+
border-top-right-radius: $menu-bar-item-border-radius;
|
45
|
+
border-bottom-right-radius: $menu-bar-item-border-radius;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
}
|
50
|
+
|
51
|
+
// MENU BAR CONTENT
|
52
|
+
.menu_bar_content{
|
53
|
+
display: inline-block;
|
54
|
+
vertical-align: middle;
|
55
|
+
margin: 0 $menu-bar-item-spacing 0 0;
|
56
|
+
|
57
|
+
// MENU BAR ITEMS
|
58
|
+
.menu_bar_item{
|
59
|
+
@include menu_bar_item;
|
60
|
+
@include no-select;
|
61
|
+
@include no-drag;
|
62
|
+
}
|
63
|
+
|
64
|
+
// MENU BAR SEPARATOR
|
65
|
+
.menu_bar_separator{
|
66
|
+
background-color: #AAA;
|
67
|
+
border-right: 1px solid #F7F7F7;
|
68
|
+
opacity: 0.5;
|
69
|
+
display: inline-block;
|
70
|
+
height: $menu-bar-separator-height;
|
71
|
+
padding-right: 1px;
|
72
|
+
vertical-align: middle;
|
73
|
+
}
|
74
|
+
|
75
|
+
// MENUS
|
76
|
+
.menu{
|
77
|
+
background: none repeat scroll 0 0 white;
|
78
|
+
@include menu-bar-item-border;
|
79
|
+
border-radius: 0 0 2px 2px;
|
80
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
|
81
|
+
list-style: none outside none;
|
82
|
+
margin-top: -$menu-border-width - $menu-bar-item-border-width; // Make the button appear to be part of the clicked trigger button
|
83
|
+
padding: $menu-vertical-padding 0;
|
84
|
+
position: absolute;
|
85
|
+
display: none;
|
86
|
+
|
87
|
+
.menu_content{
|
88
|
+
display: block;
|
89
|
+
padding: 0;
|
90
|
+
margin: 0;
|
91
|
+
position: relative;
|
92
|
+
|
93
|
+
.menu_item{
|
94
|
+
@include menu_item;
|
95
|
+
}
|
96
|
+
.menu_group_title{
|
97
|
+
@include menu_item_base;
|
98
|
+
background: none repeat scroll 0 0 #EEEEEE;
|
99
|
+
color: #888888;
|
100
|
+
font-weight: bold;
|
101
|
+
margin: $menu-item-vertical-padding 0;
|
102
|
+
white-space: nowrap;
|
103
|
+
}
|
104
|
+
.menu_group{
|
105
|
+
padding: 0;
|
106
|
+
margin: 0;
|
107
|
+
}
|
108
|
+
|
109
|
+
.menu_separator{
|
110
|
+
border-top: 1px solid #E0E0E0;
|
111
|
+
margin: $menu-item-vertical-padding 0;
|
112
|
+
}
|
113
|
+
|
114
|
+
}
|
115
|
+
|
116
|
+
// Subsequent menu groups
|
117
|
+
.menu_content + .menu_content .menu_group_title{
|
118
|
+
border-top: 1px solid #E0E0E0;
|
119
|
+
margin-top: $menu-item-vertical-padding;
|
120
|
+
}
|
121
|
+
|
122
|
+
}
|
123
|
+
&.with_menu {
|
124
|
+
.menu_bar_item .arrow{
|
125
|
+
background: url('/assets/arrows.png') center 87px;
|
126
|
+
display: inline-block;
|
127
|
+
margin-left: 3px;
|
128
|
+
height: 10px;
|
129
|
+
width: 10px;
|
130
|
+
vertical-align: middle;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
&.with_menu.no_js:hover, &.with_menu.open{
|
134
|
+
.menu_bar_item {
|
135
|
+
background: white;
|
136
|
+
border-radius: 2px 2px 0 0;
|
137
|
+
@include menu-bar-item-border-colour-with-fallback;
|
138
|
+
border-bottom: none;
|
139
|
+
margin-bottom: $menu-bar-item-border-width; // Make up for the loss of border so the button doesn't shift
|
140
|
+
box-shadow: none;
|
141
|
+
}
|
142
|
+
|
143
|
+
z-index: $menu-bar-item-pressed-zindex + 2; // Position all the contents of this menu_content above any other menu bar item (the pressed item being the highest)
|
144
|
+
.menu {
|
145
|
+
display: block;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
// Allow right alignment of buttons
|
150
|
+
&.right{
|
151
|
+
float: right;
|
152
|
+
margin: 0 0 0 $menu-bar-item-spacing;
|
153
|
+
|
154
|
+
.menu {
|
155
|
+
right: 0;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
// CLICK BLOCKER (only appears if the element is disabled)
|
160
|
+
position: relative; // So click blocker can fill the button area
|
161
|
+
.disabled + .click_blocker{
|
162
|
+
height: 100%;
|
163
|
+
left: 0;
|
164
|
+
position: absolute;
|
165
|
+
top: 0;
|
166
|
+
width: 100%;
|
167
|
+
z-index: $menu-bar-item-zindex + 3;
|
168
|
+
}
|
169
|
+
|
170
|
+
// INPUTS IN THE MENU
|
171
|
+
form{
|
172
|
+
display: inline-block;
|
173
|
+
}
|
174
|
+
input[type=search]{
|
175
|
+
@include text-field;
|
176
|
+
-webkit-appearance: textfield;
|
177
|
+
-webkit-padding-start: 0;
|
178
|
+
-webkit-padding-end: 0;
|
179
|
+
}
|
180
|
+
input[type=text]{
|
181
|
+
@include text-field;
|
182
|
+
}
|
183
|
+
|
184
|
+
.menu_bar_item{
|
185
|
+
input[type='checkbox']{
|
186
|
+
// Make input align properly when used in the menu bar, especially if used in a menu trigger in IE.
|
187
|
+
margin: 0;
|
188
|
+
display: inline-block;
|
189
|
+
vertical-align: top;
|
190
|
+
height: $menu-bar-item-height;
|
191
|
+
}
|
192
|
+
select{
|
193
|
+
@include menu_bar_item_base;
|
194
|
+
// @include menu_bar_item_hover;
|
195
|
+
height: $menu-bar-height;
|
196
|
+
font: $menu-bar-font;
|
197
|
+
padding: 0.4em;
|
198
|
+
|
199
|
+
option{
|
200
|
+
text-shadow: none;
|
201
|
+
padding: 0.4em;
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
.menu_bar.toggle_menu{
|
208
|
+
.menu_bar_content:first-child .menu_bar_item{
|
209
|
+
border-top-left-radius: 14px;
|
210
|
+
border-bottom-left-radius: 14px;
|
211
|
+
}
|
212
|
+
.menu_bar_content:last-child .menu_bar_item{
|
213
|
+
border-top-right-radius: 14px;
|
214
|
+
border-bottom-right-radius: 14px;
|
215
|
+
}
|
216
|
+
}
|
@@ -0,0 +1,310 @@
|
|
1
|
+
# TODO make menu bar group an actual group instead of a state toggle
|
2
|
+
class MenuBar
|
3
|
+
include EasyMenu::Helpers
|
4
|
+
include EasyMenu::Configuration
|
5
|
+
|
6
|
+
attr_reader :content
|
7
|
+
|
8
|
+
def initialize(template, options = {})
|
9
|
+
@template = template
|
10
|
+
@options = options.reverse_merge(:theme => config[:default_theme_class], :remove_dangling_separators => true)
|
11
|
+
config.merge! options[:config] if options[:config] # Allow per menu overriding of configuration
|
12
|
+
config[:template] = @template
|
13
|
+
|
14
|
+
@content = []
|
15
|
+
|
16
|
+
yield self if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty?
|
20
|
+
@content.blank?
|
21
|
+
end
|
22
|
+
|
23
|
+
def group(options = {})
|
24
|
+
initialize_options(options)
|
25
|
+
|
26
|
+
mbg = MenuBarGroup.new(@template, options.merge(@options.slice(:config)))
|
27
|
+
mbc = MenuBarContent.new(config, mbg, options[:menu_bar_content])
|
28
|
+
|
29
|
+
yield mbg if block_given?
|
30
|
+
|
31
|
+
@content << mbc
|
32
|
+
|
33
|
+
return mbg
|
34
|
+
end
|
35
|
+
|
36
|
+
def menu_bar_content(content = nil, options = {}, &block)
|
37
|
+
initialize_options(options)
|
38
|
+
|
39
|
+
if block_given?
|
40
|
+
options = content || options
|
41
|
+
content = block.call
|
42
|
+
end
|
43
|
+
|
44
|
+
mbc = MenuBarContent.new(config, content, options)
|
45
|
+
@content << mbc
|
46
|
+
|
47
|
+
return mbc
|
48
|
+
end
|
49
|
+
|
50
|
+
def menu_bar_item(content, options = {})
|
51
|
+
initialize_options(options)
|
52
|
+
|
53
|
+
raise if config[:template].is_a?(Hash) || config[:template].nil?
|
54
|
+
|
55
|
+
mbi = MenuBarItem.new config, content, options
|
56
|
+
@content << MenuBarContent.new(config, mbi, options[:menu_bar_content])
|
57
|
+
|
58
|
+
return mbi
|
59
|
+
end
|
60
|
+
|
61
|
+
def menu_bar_input(content, options = {})
|
62
|
+
initialize_options(options)
|
63
|
+
|
64
|
+
mbin = MenuBarInput.new config, content, options
|
65
|
+
mbi = MenuBarItem.new config, mbin, options[:menu_bar_item]
|
66
|
+
@content << MenuBarContent.new(config, mbi, options[:menu_bar_content])
|
67
|
+
|
68
|
+
return mbi
|
69
|
+
end
|
70
|
+
|
71
|
+
def menu(button_text, options = {})
|
72
|
+
initialize_options(options)
|
73
|
+
|
74
|
+
arrow = @template.content_tag(:span, '', :class => config[:menu_bar_item_arrow_class])
|
75
|
+
|
76
|
+
m = Menu.new(config, options)
|
77
|
+
mbt = MenuBarTrigger.new(config, button_text.html_safe + arrow, m, options[:menu_bar_item])
|
78
|
+
|
79
|
+
yield m if block_given?
|
80
|
+
|
81
|
+
# We give the menu bar content a special class so we can treat its contents differently than one without a menu inside
|
82
|
+
@content << MenuBarContent.new(config, mbt, merge_class(options[:menu_bar_content], config[:menu_bar_content_with_menu_class]))
|
83
|
+
|
84
|
+
return m
|
85
|
+
end
|
86
|
+
|
87
|
+
def separator(options = {})
|
88
|
+
s = @template.content_tag :div, '', :class => config[:menu_bar_separator_class]
|
89
|
+
@content << MenuBarContent.new(config, s, options.reverse_merge(:remove_if_dangling => @options[:remove_dangling_separators]))
|
90
|
+
|
91
|
+
return s
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_s
|
95
|
+
@content.pop if @content.last && @content.last.options[:remove_if_dangling]
|
96
|
+
wrap_content(@content.join.html_safe)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def initialize_options(options)
|
102
|
+
options[:menu_bar_item] ||= {}
|
103
|
+
options[:menu_bar_content] ||= {}
|
104
|
+
|
105
|
+
# Alignment always lies with the content wrapper
|
106
|
+
options[:menu_bar_content][:align] = options.delete(:align)
|
107
|
+
|
108
|
+
return options
|
109
|
+
end
|
110
|
+
|
111
|
+
def html_options
|
112
|
+
html_opts = @options.slice(*html_option_keys)
|
113
|
+
|
114
|
+
# Set up the css class
|
115
|
+
merge_class(html_opts, css_class, @options[:theme])
|
116
|
+
merge_class(html_opts, 'no_js') if @options[:js] == false
|
117
|
+
|
118
|
+
return html_opts
|
119
|
+
end
|
120
|
+
|
121
|
+
# ABSTRACT CLASSES
|
122
|
+
|
123
|
+
class AbstractContent
|
124
|
+
include EasyMenu::Helpers
|
125
|
+
|
126
|
+
attr_reader :content, :config, :options
|
127
|
+
def initialize(config, content, options = {})
|
128
|
+
raise if config[:template].is_a?(Hash) || config[:template].nil?
|
129
|
+
@config = config
|
130
|
+
@template = config[:template]
|
131
|
+
@content = Array(content)
|
132
|
+
@options = options
|
133
|
+
end
|
134
|
+
|
135
|
+
def empty?
|
136
|
+
@content.join.blank?
|
137
|
+
end
|
138
|
+
|
139
|
+
def to_s
|
140
|
+
empty? ? '' : wrap_content(@content.join.html_safe) # Don't render anything if empty
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def html_options
|
146
|
+
html_opts = @options.slice(*html_option_keys)
|
147
|
+
merge_class(html_opts, css_class, @options[:align])
|
148
|
+
|
149
|
+
return html_opts
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class AbstractItem < AbstractContent
|
154
|
+
def selected(condition = :unset)
|
155
|
+
@options[:selected] = (condition == :unset ? true : condition)
|
156
|
+
|
157
|
+
return self
|
158
|
+
end
|
159
|
+
|
160
|
+
def disabled(*args)
|
161
|
+
@click_blocker_html_options = args.extract_options!
|
162
|
+
@options[:disabled] = args.present? ? args.first : true
|
163
|
+
|
164
|
+
return self
|
165
|
+
end
|
166
|
+
|
167
|
+
# Set the button up to disable when a particular DOM Event occurs
|
168
|
+
def disable_when(observable_dom_element, dom_event, js_condition, click_blocker_html_options = {})
|
169
|
+
@options[:disable_when] = {:element => observable_dom_element, :event => dom_event, :condition => js_condition}
|
170
|
+
@click_blocker_html_options = click_blocker_html_options
|
171
|
+
return self
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
def wrap_content(content)
|
177
|
+
output = super
|
178
|
+
output << @template.content_tag(:div, '', click_blocker_html_options) if @options[:disabled] || @options[:disable_when]
|
179
|
+
|
180
|
+
return output
|
181
|
+
end
|
182
|
+
|
183
|
+
def html_options
|
184
|
+
html_opts = @options.slice(*html_option_keys)
|
185
|
+
|
186
|
+
if @options[:disable_when]
|
187
|
+
html_opts[:'data-disable-event-element'] = @options[:disable_when][:element]
|
188
|
+
html_opts[:'data-disable-event'] = @options[:disable_when][:event]
|
189
|
+
html_opts[:'data-disable-condition'] = @options[:disable_when][:condition]
|
190
|
+
end
|
191
|
+
|
192
|
+
merge_class(html_opts, css_class)
|
193
|
+
merge_class(html_opts, config[:selected_class]) if @options[:selected]
|
194
|
+
merge_class(html_opts, config[:disabled_class]) if @options[:disabled]
|
195
|
+
|
196
|
+
return html_opts
|
197
|
+
end
|
198
|
+
|
199
|
+
def click_blocker_html_options
|
200
|
+
html_opts = @click_blocker_html_options
|
201
|
+
html_opts.reverse_merge! :title => @options[:title] # Default the title text to be the same as the unblocked title text
|
202
|
+
|
203
|
+
merge_class(html_opts, config[:click_blocker_class])
|
204
|
+
|
205
|
+
return html_opts
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# CLASSES
|
210
|
+
|
211
|
+
class MenuBarGroup < MenuBar
|
212
|
+
end
|
213
|
+
|
214
|
+
class MenuBarContent < AbstractContent
|
215
|
+
end
|
216
|
+
|
217
|
+
class MenuBarItem < AbstractItem
|
218
|
+
end
|
219
|
+
|
220
|
+
class MenuBarTrigger < MenuBarItem
|
221
|
+
def initialize(config, content, menu, options)
|
222
|
+
@menu = menu
|
223
|
+
super(config, content, options)
|
224
|
+
end
|
225
|
+
|
226
|
+
# If the menu has no content, don't show the menu bar trigger
|
227
|
+
def empty?
|
228
|
+
@menu.empty?
|
229
|
+
end
|
230
|
+
|
231
|
+
def to_s
|
232
|
+
super + @menu.to_s
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class MenuBarInput < AbstractContent
|
237
|
+
end
|
238
|
+
|
239
|
+
class Menu < AbstractContent
|
240
|
+
def initialize(config, options = {})
|
241
|
+
raise if config[:template].is_a?(Hash) || config[:template].nil?
|
242
|
+
|
243
|
+
@config = config
|
244
|
+
@template = config[:template]
|
245
|
+
@options = options
|
246
|
+
@content = []
|
247
|
+
|
248
|
+
yield self if block_given?
|
249
|
+
end
|
250
|
+
|
251
|
+
def group(title, options = {})
|
252
|
+
initialize_options(options)
|
253
|
+
|
254
|
+
mgt = @template.content_tag(config[:menu_group_title_element], title, merge_class(options[:menu_group_title], config[:menu_group_title_class]))
|
255
|
+
mg = MenuGroup.new(config, options)
|
256
|
+
|
257
|
+
yield mg if block_given?
|
258
|
+
|
259
|
+
@content << MenuContent.new(config, [mgt, mg], options[:menu_content])
|
260
|
+
|
261
|
+
return mg
|
262
|
+
end
|
263
|
+
|
264
|
+
def menu_content(content = nil, options = {}, &block)
|
265
|
+
initialize_options(options)
|
266
|
+
|
267
|
+
if block_given?
|
268
|
+
options = content || options
|
269
|
+
content = block.call
|
270
|
+
end
|
271
|
+
|
272
|
+
@content << MenuContent.new(config, content, options)
|
273
|
+
end
|
274
|
+
|
275
|
+
def menu_item(content, options = {})
|
276
|
+
initialize_options(options)
|
277
|
+
|
278
|
+
mi = MenuItem.new(config, content, options)
|
279
|
+
@content << MenuContent.new(config, mi, options[:menu_content])
|
280
|
+
|
281
|
+
return mi
|
282
|
+
end
|
283
|
+
|
284
|
+
def separator
|
285
|
+
s = @template.content_tag :div, '', :class => config[:menu_separator_class]
|
286
|
+
@content << MenuContent.new(config, s)
|
287
|
+
|
288
|
+
return s
|
289
|
+
end
|
290
|
+
|
291
|
+
private
|
292
|
+
|
293
|
+
def initialize_options(options)
|
294
|
+
options[:menu_item] ||= {}
|
295
|
+
options[:menu_content] ||= {}
|
296
|
+
options[:menu_group_title] ||= {}
|
297
|
+
|
298
|
+
return options
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
class MenuGroup < Menu
|
303
|
+
end
|
304
|
+
|
305
|
+
class MenuContent < AbstractContent
|
306
|
+
end
|
307
|
+
|
308
|
+
class MenuItem < AbstractItem
|
309
|
+
end
|
310
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
# tools.ietf.org/html/rfc2397
|
4
|
+
# developer.mozilla.org/en/data_URIs
|
5
|
+
|
6
|
+
if defined?(Sass)
|
7
|
+
puts "Loading Easy Menu SCSS extensions"
|
8
|
+
module Sass::Script::Functions
|
9
|
+
def data_url(content_type, content)
|
10
|
+
outuri = "data:#{unquote(content_type)};base64,#{Base64.encode64(unquote(content).to_s.gsub(/\s*$\s*/,''))}"
|
11
|
+
|
12
|
+
# IE8 has a 32KiB limit on data uri
|
13
|
+
# en.wikipedia.org/wiki/Data_URI_scheme
|
14
|
+
if outuri.length > 32768
|
15
|
+
raise ArgumentError.new("Data URI is greater than 32KiB in size, that is the max size of data urls in IE8.")
|
16
|
+
end
|
17
|
+
|
18
|
+
Sass::Script::String.new("url('#{outuri}')")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/easy_menu.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module EasyMenu
|
2
|
+
module Configuration
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
class_attribute :config
|
6
|
+
self.config = Hash.new{|hash, key| raise "#{key} has not been set in Easy Menu Configuration"}.merge(Default)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
Default = {
|
11
|
+
# CLASSES
|
12
|
+
|
13
|
+
:default_theme_class => 'default_theme',
|
14
|
+
:menu_bar_class => 'menu_bar',
|
15
|
+
:menu_bar_content_class => 'menu_bar_content',
|
16
|
+
:menu_bar_group_class => 'menu_bar_group',
|
17
|
+
:menu_bar_content_with_menu_class => 'with_menu no_js', # no_js class will be removed by browser if it has js, disabling the hover behaviour and enabling a click behaviour
|
18
|
+
:menu_bar_item_class => 'menu_bar_item',
|
19
|
+
:menu_bar_item_arrow_class => 'arrow',
|
20
|
+
:menu_bar_input_class => 'menu_bar_input',
|
21
|
+
:menu_bar_separator_class => 'menu_bar_separator',
|
22
|
+
:menu_bar_trigger_class => :menu_bar_item, # This element is a menu item but behaves differently
|
23
|
+
:menu_class => 'menu',
|
24
|
+
:menu_content_class => 'menu_content',
|
25
|
+
:menu_group_class => 'menu_group',
|
26
|
+
:menu_group_title_class => 'menu_group_title',
|
27
|
+
:menu_item_class => 'menu_item',
|
28
|
+
:menu_separator_class => 'menu_separator',
|
29
|
+
:click_blocker_class => 'click_blocker',
|
30
|
+
:selected_class => 'selected',
|
31
|
+
:disabled_class => 'disabled',
|
32
|
+
:grouped_class => 'grouped',
|
33
|
+
:first_group_item_class => 'first_group_item',
|
34
|
+
:last_group_item_class => 'last_group_item',
|
35
|
+
|
36
|
+
# ELEMENTS
|
37
|
+
:menu_bar_element => :ul,
|
38
|
+
:menu_bar_group_element => :ul,
|
39
|
+
:menu_bar_content_element => :li,
|
40
|
+
:menu_bar_item_element => :div,
|
41
|
+
:menu_bar_trigger_element => :div,
|
42
|
+
:menu_bar_input_element => :label,
|
43
|
+
|
44
|
+
:menu_element => :ul,
|
45
|
+
:menu_content_element => :li,
|
46
|
+
:menu_group_title_element => :div,
|
47
|
+
:menu_group_element => :ul,
|
48
|
+
:menu_item_element => :div
|
49
|
+
}
|
50
|
+
|
51
|
+
Bootstrap = {
|
52
|
+
:menu_bar_content_with_menu_class => 'dropdown',
|
53
|
+
:menu_bar_item_arrow_class => 'caret',
|
54
|
+
:menu_class => 'dropdown-menu',
|
55
|
+
:menu_item_element => nil,
|
56
|
+
:menu_bar_trigger_element => :a,
|
57
|
+
:menu_bar_trigger_class => 'dropdown-toggle'
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module EasyMenu
|
2
|
+
module Helpers
|
3
|
+
HTML_OPTIONS = [:id, :class, :title, :style, :data]
|
4
|
+
|
5
|
+
# Determines the config name from the class name.
|
6
|
+
# e.g. MenuBar => 'menu_bar'
|
7
|
+
def config_name
|
8
|
+
self.class.name.demodulize.underscore
|
9
|
+
end
|
10
|
+
|
11
|
+
def css_class
|
12
|
+
config[:"#{config_name}_class"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def wrapper_element
|
16
|
+
config[:"#{config_name}_element"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def wrap_content(content)
|
20
|
+
if (wrapper_element)
|
21
|
+
@template.content_tag wrapper_element, content, html_options
|
22
|
+
else
|
23
|
+
content
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def merge_class(hash, *classes)
|
28
|
+
hash[:class] = ([hash[:class]] + classes.flatten).select(&:present?).join(' ')
|
29
|
+
return hash
|
30
|
+
end
|
31
|
+
|
32
|
+
def html_option_keys
|
33
|
+
HTML_OPTIONS + @options.keys.select{|key| key.to_s.starts_with? 'data-'}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easy_menu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Jakobsen
|
8
|
+
- Ryan Wallace
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-01-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '3.1'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '3.1'
|
28
|
+
description:
|
29
|
+
email:
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- Gemfile
|
35
|
+
- MIT-LICENSE
|
36
|
+
- README
|
37
|
+
- app/assets/images/arrows.png
|
38
|
+
- app/assets/images/checkbox_selected.png
|
39
|
+
- app/assets/images/checkbox_selected_hovered.png
|
40
|
+
- app/assets/javascripts/easy_menu_jquery.js
|
41
|
+
- app/assets/javascripts/easy_menu_prototype.js
|
42
|
+
- app/assets/stylesheets/_easy_menu_mixins.scss
|
43
|
+
- app/assets/stylesheets/easy_menu.css.scss
|
44
|
+
- app/helpers/menu_bar.rb
|
45
|
+
- app/helpers/menu_bar_helper.rb
|
46
|
+
- config/initializers/easy_menu_scss_extensions.rb
|
47
|
+
- lib/easy_menu.rb
|
48
|
+
- lib/easy_menu_configuration.rb
|
49
|
+
- lib/easy_menu_helpers.rb
|
50
|
+
homepage:
|
51
|
+
licenses: []
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 2.2.1
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: Simple menu bar dsl for Rails views
|
73
|
+
test_files: []
|