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 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,2 @@
1
+ require 'jquery_menu_aim/rails/engine'
2
+ require 'jquery_menu_aim/rails/version'
@@ -0,0 +1,6 @@
1
+ module JqueryMenuAim
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module JqueryMenuAim
2
+ module Rails
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -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: []