easy_menu 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|