jquery_menu_aim-rails 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +41 -0
- data/lib/jquery_menu_aim/rails.rb +2 -0
- data/lib/jquery_menu_aim/rails/engine.rb +6 -0
- data/lib/jquery_menu_aim/rails/version.rb +5 -0
- data/vendor/assets/javascripts/jquery_menu_aim-rails/jquery.menu-aim.js +323 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 68cf3882d1d5fbba8e765bd632b4a1154ea74bf2
|
4
|
+
data.tar.gz: 74a3ca5aad77c7ab8db89ff03c252e83b711deeb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6fcd756e955d17846604d3eaee298b8037bf76056c78b2a4d3d1cfc1433a00f4f0693f336f50c9b7e8230557bd6efe667c0a6f9a243ae1ada1ddbc94da544ce8
|
7
|
+
data.tar.gz: cd2ee9cb4ade63d653541bf460302194e7a3cfcefc1f7d940a3c721531fc68159179c69251522b173e5347170cce841d693cf96f387e800274c6e30c55744ca0
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Chris Cressman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
jquery_menu_aim-rails
|
2
|
+
================================================================================
|
3
|
+
|
4
|
+
[jQuery-menu-aim](https://github.com/kamens/jQuery-menu-aim) packaged for the
|
5
|
+
Rails asset pipeline.
|
6
|
+
|
7
|
+
|
8
|
+
Usage
|
9
|
+
--------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
Add the gem to your Gemfile:
|
12
|
+
|
13
|
+
gem 'jquery_menu_aim-rails'
|
14
|
+
|
15
|
+
Load the library within an asset manifest such as `application.js`:
|
16
|
+
|
17
|
+
//= require jquery_menu_aim-rails/jquery.menu-aim
|
18
|
+
|
19
|
+
If you've included the gem in your Gemfile, Bundler will generally take care of
|
20
|
+
`require`ing the necessary files, but if for some reason you need to manually
|
21
|
+
`require` the gem:
|
22
|
+
|
23
|
+
require 'jquery_menu_aim/rails'
|
24
|
+
|
25
|
+
|
26
|
+
Versioning
|
27
|
+
--------------------------------------------------------------------------------
|
28
|
+
|
29
|
+
The [jQuery-menu-aim](https://github.com/kamens/jQuery-menu-aim) project
|
30
|
+
has no versioned releases*. The following table indicates which
|
31
|
+
version of the JS file (indicated by commit ID) is included with each version
|
32
|
+
of the gem.
|
33
|
+
|
34
|
+
| Gem Version | Commit ID |
|
35
|
+
| ----------- | --------- |
|
36
|
+
| 1.0.0 | [da3cb65](https://github.com/kamens/jQuery-menu-aim/commit/da3cb657f36a1876d6a34514ad1fb81f1dd2433c) |
|
37
|
+
|
38
|
+
*The project's readme states the current version is 1.1, however, it is
|
39
|
+
unclear how releases are managed and how users of the software can know which
|
40
|
+
version of the software they are using. This project therefore treats
|
41
|
+
jQuery-menu-aim as having no versioned releases.
|
@@ -0,0 +1,323 @@
|
|
1
|
+
/**
|
2
|
+
* menu-aim is a jQuery plugin for dropdown menus that can differentiate
|
3
|
+
* between a user trying hover over a dropdown item vs trying to navigate into
|
4
|
+
* a submenu's contents.
|
5
|
+
*
|
6
|
+
* menu-aim assumes that you have are using a menu with submenus that expand
|
7
|
+
* to the menu's right. It will fire events when the user's mouse enters a new
|
8
|
+
* dropdown item *and* when that item is being intentionally hovered over.
|
9
|
+
*
|
10
|
+
* __________________________
|
11
|
+
* | Monkeys >| Gorilla |
|
12
|
+
* | Gorillas >| Content |
|
13
|
+
* | Chimps >| Here |
|
14
|
+
* |___________|____________|
|
15
|
+
*
|
16
|
+
* In the above example, "Gorillas" is selected and its submenu content is
|
17
|
+
* being shown on the right. Imagine that the user's cursor is hovering over
|
18
|
+
* "Gorillas." When they move their mouse into the "Gorilla Content" area, they
|
19
|
+
* may briefly hover over "Chimps." This shouldn't close the "Gorilla Content"
|
20
|
+
* area.
|
21
|
+
*
|
22
|
+
* This problem is normally solved using timeouts and delays. menu-aim tries to
|
23
|
+
* solve this by detecting the direction of the user's mouse movement. This can
|
24
|
+
* make for quicker transitions when navigating up and down the menu. The
|
25
|
+
* experience is hopefully similar to amazon.com/'s "Shop by Department"
|
26
|
+
* dropdown.
|
27
|
+
*
|
28
|
+
* Use like so:
|
29
|
+
*
|
30
|
+
* $("#menu").menuAim({
|
31
|
+
* activate: $.noop, // fired on row activation
|
32
|
+
* deactivate: $.noop // fired on row deactivation
|
33
|
+
* });
|
34
|
+
*
|
35
|
+
* ...to receive events when a menu's row has been purposefully (de)activated.
|
36
|
+
*
|
37
|
+
* The following options can be passed to menuAim. All functions execute with
|
38
|
+
* the relevant row's HTML element as the execution context ('this'):
|
39
|
+
*
|
40
|
+
* .menuAim({
|
41
|
+
* // Function to call when a row is purposefully activated. Use this
|
42
|
+
* // to show a submenu's content for the activated row.
|
43
|
+
* activate: function() {},
|
44
|
+
*
|
45
|
+
* // Function to call when a row is deactivated.
|
46
|
+
* deactivate: function() {},
|
47
|
+
*
|
48
|
+
* // Function to call when mouse enters a menu row. Entering a row
|
49
|
+
* // does not mean the row has been activated, as the user may be
|
50
|
+
* // mousing over to a submenu.
|
51
|
+
* enter: function() {},
|
52
|
+
*
|
53
|
+
* // Function to call when mouse exits a menu row.
|
54
|
+
* exit: function() {},
|
55
|
+
*
|
56
|
+
* // Selector for identifying which elements in the menu are rows
|
57
|
+
* // that can trigger the above events. Defaults to "> li".
|
58
|
+
* rowSelector: "> li",
|
59
|
+
*
|
60
|
+
* // You may have some menu rows that aren't submenus and therefore
|
61
|
+
* // shouldn't ever need to "activate." If so, filter submenu rows w/
|
62
|
+
* // this selector. Defaults to "*" (all elements).
|
63
|
+
* submenuSelector: "*",
|
64
|
+
*
|
65
|
+
* // Direction the submenu opens relative to the main menu. Can be
|
66
|
+
* // left, right, above, or below. Defaults to "right".
|
67
|
+
* submenuDirection: "right"
|
68
|
+
* });
|
69
|
+
*
|
70
|
+
* https://github.com/kamens/jQuery-menu-aim
|
71
|
+
*/
|
72
|
+
(function($) {
|
73
|
+
|
74
|
+
$.fn.menuAim = function(opts) {
|
75
|
+
// Initialize menu-aim for all elements in jQuery collection
|
76
|
+
this.each(function() {
|
77
|
+
init.call(this, opts);
|
78
|
+
});
|
79
|
+
|
80
|
+
return this;
|
81
|
+
};
|
82
|
+
|
83
|
+
function init(opts) {
|
84
|
+
var $menu = $(this),
|
85
|
+
activeRow = null,
|
86
|
+
mouseLocs = [],
|
87
|
+
lastDelayLoc = null,
|
88
|
+
timeoutId = null,
|
89
|
+
options = $.extend({
|
90
|
+
rowSelector: "> li",
|
91
|
+
submenuSelector: "*",
|
92
|
+
submenuDirection: "right",
|
93
|
+
tolerance: 75, // bigger = more forgivey when entering submenu
|
94
|
+
enter: $.noop,
|
95
|
+
exit: $.noop,
|
96
|
+
activate: $.noop,
|
97
|
+
deactivate: $.noop,
|
98
|
+
exitMenu: $.noop
|
99
|
+
}, opts);
|
100
|
+
|
101
|
+
var MOUSE_LOCS_TRACKED = 3, // number of past mouse locations to track
|
102
|
+
DELAY = 300; // ms delay when user appears to be entering submenu
|
103
|
+
|
104
|
+
/**
|
105
|
+
* Keep track of the last few locations of the mouse.
|
106
|
+
*/
|
107
|
+
var mousemoveDocument = function(e) {
|
108
|
+
mouseLocs.push({x: e.pageX, y: e.pageY});
|
109
|
+
|
110
|
+
if (mouseLocs.length > MOUSE_LOCS_TRACKED) {
|
111
|
+
mouseLocs.shift();
|
112
|
+
}
|
113
|
+
};
|
114
|
+
|
115
|
+
/**
|
116
|
+
* Cancel possible row activations when leaving the menu entirely
|
117
|
+
*/
|
118
|
+
var mouseleaveMenu = function() {
|
119
|
+
if (timeoutId) {
|
120
|
+
clearTimeout(timeoutId);
|
121
|
+
}
|
122
|
+
|
123
|
+
// If exitMenu is supplied and returns true, deactivate the
|
124
|
+
// currently active row on menu exit.
|
125
|
+
if (options.exitMenu(this)) {
|
126
|
+
if (activeRow) {
|
127
|
+
options.deactivate(activeRow);
|
128
|
+
}
|
129
|
+
|
130
|
+
activeRow = null;
|
131
|
+
}
|
132
|
+
};
|
133
|
+
|
134
|
+
/**
|
135
|
+
* Trigger a possible row activation whenever entering a new row.
|
136
|
+
*/
|
137
|
+
var mouseenterRow = function() {
|
138
|
+
if (timeoutId) {
|
139
|
+
// Cancel any previous activation delays
|
140
|
+
clearTimeout(timeoutId);
|
141
|
+
}
|
142
|
+
|
143
|
+
options.enter(this);
|
144
|
+
possiblyActivate(this);
|
145
|
+
},
|
146
|
+
mouseleaveRow = function() {
|
147
|
+
options.exit(this);
|
148
|
+
};
|
149
|
+
|
150
|
+
/*
|
151
|
+
* Immediately activate a row if the user clicks on it.
|
152
|
+
*/
|
153
|
+
var clickRow = function() {
|
154
|
+
activate(this);
|
155
|
+
};
|
156
|
+
|
157
|
+
/**
|
158
|
+
* Activate a menu row.
|
159
|
+
*/
|
160
|
+
var activate = function(row) {
|
161
|
+
if (row == activeRow) {
|
162
|
+
return;
|
163
|
+
}
|
164
|
+
|
165
|
+
if (activeRow) {
|
166
|
+
options.deactivate(activeRow);
|
167
|
+
}
|
168
|
+
|
169
|
+
options.activate(row);
|
170
|
+
activeRow = row;
|
171
|
+
};
|
172
|
+
|
173
|
+
/**
|
174
|
+
* Possibly activate a menu row. If mouse movement indicates that we
|
175
|
+
* shouldn't activate yet because user may be trying to enter
|
176
|
+
* a submenu's content, then delay and check again later.
|
177
|
+
*/
|
178
|
+
var possiblyActivate = function(row) {
|
179
|
+
var delay = activationDelay();
|
180
|
+
|
181
|
+
if (delay) {
|
182
|
+
timeoutId = setTimeout(function() {
|
183
|
+
possiblyActivate(row);
|
184
|
+
}, delay);
|
185
|
+
} else {
|
186
|
+
activate(row);
|
187
|
+
}
|
188
|
+
};
|
189
|
+
|
190
|
+
/**
|
191
|
+
* Return the amount of time that should be used as a delay before the
|
192
|
+
* currently hovered row is activated.
|
193
|
+
*
|
194
|
+
* Returns 0 if the activation should happen immediately. Otherwise,
|
195
|
+
* returns the number of milliseconds that should be delayed before
|
196
|
+
* checking again to see if the row should be activated.
|
197
|
+
*/
|
198
|
+
var activationDelay = function() {
|
199
|
+
if (!activeRow || !$(activeRow).is(options.submenuSelector)) {
|
200
|
+
// If there is no other submenu row already active, then
|
201
|
+
// go ahead and activate immediately.
|
202
|
+
return 0;
|
203
|
+
}
|
204
|
+
|
205
|
+
var offset = $menu.offset(),
|
206
|
+
upperLeft = {
|
207
|
+
x: offset.left,
|
208
|
+
y: offset.top - options.tolerance
|
209
|
+
},
|
210
|
+
upperRight = {
|
211
|
+
x: offset.left + $menu.outerWidth(),
|
212
|
+
y: upperLeft.y
|
213
|
+
},
|
214
|
+
lowerLeft = {
|
215
|
+
x: offset.left,
|
216
|
+
y: offset.top + $menu.outerHeight() + options.tolerance
|
217
|
+
},
|
218
|
+
lowerRight = {
|
219
|
+
x: offset.left + $menu.outerWidth(),
|
220
|
+
y: lowerLeft.y
|
221
|
+
},
|
222
|
+
loc = mouseLocs[mouseLocs.length - 1],
|
223
|
+
prevLoc = mouseLocs[0];
|
224
|
+
|
225
|
+
if (!loc) {
|
226
|
+
return 0;
|
227
|
+
}
|
228
|
+
|
229
|
+
if (!prevLoc) {
|
230
|
+
prevLoc = loc;
|
231
|
+
}
|
232
|
+
|
233
|
+
if (prevLoc.x < offset.left || prevLoc.x > lowerRight.x ||
|
234
|
+
prevLoc.y < offset.top || prevLoc.y > lowerRight.y) {
|
235
|
+
// If the previous mouse location was outside of the entire
|
236
|
+
// menu's bounds, immediately activate.
|
237
|
+
return 0;
|
238
|
+
}
|
239
|
+
|
240
|
+
if (lastDelayLoc &&
|
241
|
+
loc.x == lastDelayLoc.x && loc.y == lastDelayLoc.y) {
|
242
|
+
// If the mouse hasn't moved since the last time we checked
|
243
|
+
// for activation status, immediately activate.
|
244
|
+
return 0;
|
245
|
+
}
|
246
|
+
|
247
|
+
// Detect if the user is moving towards the currently activated
|
248
|
+
// submenu.
|
249
|
+
//
|
250
|
+
// If the mouse is heading relatively clearly towards
|
251
|
+
// the submenu's content, we should wait and give the user more
|
252
|
+
// time before activating a new row. If the mouse is heading
|
253
|
+
// elsewhere, we can immediately activate a new row.
|
254
|
+
//
|
255
|
+
// We detect this by calculating the slope formed between the
|
256
|
+
// current mouse location and the upper/lower right points of
|
257
|
+
// the menu. We do the same for the previous mouse location.
|
258
|
+
// If the current mouse location's slopes are
|
259
|
+
// increasing/decreasing appropriately compared to the
|
260
|
+
// previous's, we know the user is moving toward the submenu.
|
261
|
+
//
|
262
|
+
// Note that since the y-axis increases as the cursor moves
|
263
|
+
// down the screen, we are looking for the slope between the
|
264
|
+
// cursor and the upper right corner to decrease over time, not
|
265
|
+
// increase (somewhat counterintuitively).
|
266
|
+
function slope(a, b) {
|
267
|
+
return (b.y - a.y) / (b.x - a.x);
|
268
|
+
};
|
269
|
+
|
270
|
+
var decreasingCorner = upperRight,
|
271
|
+
increasingCorner = lowerRight;
|
272
|
+
|
273
|
+
// Our expectations for decreasing or increasing slope values
|
274
|
+
// depends on which direction the submenu opens relative to the
|
275
|
+
// main menu. By default, if the menu opens on the right, we
|
276
|
+
// expect the slope between the cursor and the upper right
|
277
|
+
// corner to decrease over time, as explained above. If the
|
278
|
+
// submenu opens in a different direction, we change our slope
|
279
|
+
// expectations.
|
280
|
+
if (options.submenuDirection == "left") {
|
281
|
+
decreasingCorner = lowerLeft;
|
282
|
+
increasingCorner = upperLeft;
|
283
|
+
} else if (options.submenuDirection == "below") {
|
284
|
+
decreasingCorner = lowerRight;
|
285
|
+
increasingCorner = lowerLeft;
|
286
|
+
} else if (options.submenuDirection == "above") {
|
287
|
+
decreasingCorner = upperLeft;
|
288
|
+
increasingCorner = upperRight;
|
289
|
+
}
|
290
|
+
|
291
|
+
var decreasingSlope = slope(loc, decreasingCorner),
|
292
|
+
increasingSlope = slope(loc, increasingCorner),
|
293
|
+
prevDecreasingSlope = slope(prevLoc, decreasingCorner),
|
294
|
+
prevIncreasingSlope = slope(prevLoc, increasingCorner);
|
295
|
+
|
296
|
+
if (decreasingSlope < prevDecreasingSlope &&
|
297
|
+
increasingSlope > prevIncreasingSlope) {
|
298
|
+
// Mouse is moving from previous location towards the
|
299
|
+
// currently activated submenu. Delay before activating a
|
300
|
+
// new menu row, because user may be moving into submenu.
|
301
|
+
lastDelayLoc = loc;
|
302
|
+
return DELAY;
|
303
|
+
}
|
304
|
+
|
305
|
+
lastDelayLoc = null;
|
306
|
+
return 0;
|
307
|
+
};
|
308
|
+
|
309
|
+
/**
|
310
|
+
* Hook up initial menu events
|
311
|
+
*/
|
312
|
+
$menu
|
313
|
+
.mouseleave(mouseleaveMenu)
|
314
|
+
.find(options.rowSelector)
|
315
|
+
.mouseenter(mouseenterRow)
|
316
|
+
.mouseleave(mouseleaveRow)
|
317
|
+
.click(clickRow);
|
318
|
+
|
319
|
+
$(document).mousemove(mousemoveDocument);
|
320
|
+
|
321
|
+
};
|
322
|
+
})(jQuery);
|
323
|
+
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jquery_menu_aim-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Cressman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: jQuery-menu-aim packaged for the Rails asset pipeline.
|
14
|
+
email:
|
15
|
+
- ccressman@weblinc.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- LICENSE
|
21
|
+
- README.md
|
22
|
+
- lib/jquery_menu_aim/rails.rb
|
23
|
+
- lib/jquery_menu_aim/rails/engine.rb
|
24
|
+
- lib/jquery_menu_aim/rails/version.rb
|
25
|
+
- vendor/assets/javascripts/jquery_menu_aim-rails/jquery.menu-aim.js
|
26
|
+
homepage: http://github.com/chriscressman/jquery-menu-aim-rails
|
27
|
+
licenses:
|
28
|
+
- MIT
|
29
|
+
metadata: {}
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 2.4.8
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: jQuery-menu-aim packaged for the Rails asset pipeline.
|
50
|
+
test_files: []
|