smock 0.1.213 → 0.1.214

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.
@@ -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
+
@@ -21,8 +21,8 @@
21
21
  overflow: hidden
22
22
  +transition( height 0.05s ease-in)
23
23
 
24
- .category-dropdown__categories__item__subcategories.show-me
25
- display: none
24
+ .category-dropdown__categories--expanded
25
+ width: 590px
26
26
 
27
27
  .category-dropdown__categories__list
28
28
  +space(min-height, 9)
@@ -47,3 +47,4 @@
47
47
  +space(top)
48
48
  right: 0
49
49
  width: 45%
50
+ height: 100%
@@ -34,9 +34,9 @@
34
34
  <a class="category-dropdown__control th-double-line th-inverse" href="#">Browse Categories</a>
35
35
  <div class="category-dropdown__categories th-size-normal ch-white-background">
36
36
  <ul class="category-dropdown__categories__list">
37
- <li>
37
+ <li data-submenu-id="1">
38
38
  <a href="#" class="th-size-medium th-double-line">Business &amp; Marketing</a>
39
- <ul class="category-dropdown__categories__item__subcategories show-me">
39
+ <ul id="1" class="category-dropdown__categories__item__subcategories show-me">
40
40
  <li><a href="#">Inforgraphic Design</a></li>
41
41
  <li><a href="#">Caricatures &amp; Cartoon Design</a></li>
42
42
  <li><a href="#">eBooks &amp; Digital Publishing</a></li>
@@ -44,57 +44,57 @@
44
44
  <li><a href="#">Website Customization &amp; Updates</a></li>
45
45
  </ul>
46
46
  </li>
47
- <li class="category-dropdown__categories__item">
47
+ <li data-submenu-id="2">
48
48
  <a href="#" class="th-size-medium th-double-line">Mobile &amp; Apps</a>
49
- <ul class="category-dropdown__categories__item__subcategories">
49
+ <ul id="2" class="category-dropdown__categories__item__subcategories">
50
50
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
51
51
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
52
52
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
53
53
  </ul>
54
54
  </li>
55
- <li class="category-dropdown__categories__item">
55
+ <li data-submenu-id="3">
56
56
  <a href="#" class="th-size-medium th-double-line">Ecommerce &amp; CMS Development</a>
57
- <ul class="category-dropdown__categories__item__subcategories">
57
+ <ul id="3" class="category-dropdown__categories__item__subcategories">
58
58
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
59
59
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
60
60
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
61
61
  </ul>
62
62
  </li>
63
- <li class="category-dropdown__categories__item">
63
+ <li data-submenu-id="4">
64
64
  <a href="#" class="th-size-medium th-double-line">Websites &amp; Programming</a>
65
- <ul class="category-dropdown__categories__item__subcategories">
65
+ <ul id="4" class="category-dropdown__categories__item__subcategories">
66
66
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
67
67
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
68
68
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
69
69
  </ul>
70
70
  </li>
71
- <li class="category-dropdown__categories__item">
71
+ <li data-submenu-id="5">
72
72
  <a href="#" class="th-size-medium th-double-line">Design &amp; Graphics</a>
73
- <ul class="category-dropdown__categories__item__subcategories">
73
+ <ul id="5" class="category-dropdown__categories__item__subcategories">
74
74
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
75
75
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
76
76
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
77
77
  </ul>
78
78
  </li>
79
- <li class="category-dropdown__categories__item">
79
+ <li data-submenu-id="6">
80
80
  <a href="#" class="th-size-medium th-double-line">Logos &amp; Branding</a>
81
- <ul class="category-dropdown__categories__item__subcategories">
81
+ <ul id="6" class="category-dropdown__categories__item__subcategories">
82
82
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
83
83
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
84
84
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
85
85
  </ul>
86
86
  </li>
87
- <li class="category-dropdown__categories__item">
87
+ <li data-submenu-id="7">
88
88
  <a href="#" class="th-size-medium th-double-line">WordPress</a>
89
- <ul class="category-dropdown__categories__item__subcategories">
89
+ <ul id="7" class="category-dropdown__categories__item__subcategories">
90
90
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
91
91
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
92
92
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
93
93
  </ul>
94
94
  </li>
95
- <li class="category-dropdown__categories__item">
95
+ <li data-submenu-id="8">
96
96
  <a href="#" class="th-size-medium th-double-line">Video &amp; Animation</a>
97
- <ul class="category-dropdown__categories__item__subcategories">
97
+ <ul id="8" class="category-dropdown__categories__item__subcategories">
98
98
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
99
99
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
100
100
  <li class="category-dropdown__categories__item__subcategories__item"><a href="#">Inforgraphic Design</a></li>
@@ -578,5 +578,8 @@
578
578
  </footer>
579
579
 
580
580
  <script src="../../smock.js"></script>
581
+ <script type="text/javascript" charset="utf-8">
582
+ var dropdown = new Smock.CategoryDropdown().ready();
583
+ </script>
581
584
  </body>
582
585
  </html>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": true,
3
3
  "devDependencies": {
4
- "webpack": "~1.4.15"
4
+ "webpack": "~1.4.15",
5
5
  "coffee-script": "~1.8.0"
6
6
  }
7
7
  }
@@ -2,15 +2,23 @@ var webpack = require("webpack");
2
2
  var path = require("path");
3
3
 
4
4
  module.exports = {
5
- entry: "./app/assets/javascripts/smock.coffee",
5
+ entry: {
6
+ "smock": "./app/assets/javascripts/smock.coffee"
7
+ },
6
8
  devtool: "source-map",
7
9
  output: {
8
- filename: "smock.js"
10
+ filename: "[name].js"
9
11
  },
10
12
  module: {
11
13
  loaders: [
12
14
  { test: /\.coffee$/, loader: "coffee-loader" },
13
15
  ]
14
- }
16
+ },
17
+ plugins: [
18
+ new webpack.ProvidePlugin({
19
+ "$": "./jquery.js",
20
+ "jQuery": "./jquery.js"
21
+ })
22
+ ]
15
23
  };
16
24