jquery_menu_aim-rails 1.0.0

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 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: []