foundation-rails 6.5.3.0 → 6.6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile.lock +100 -86
  3. data/bower.json +2 -2
  4. data/foundation-rails.gemspec +5 -5
  5. data/lib/foundation/rails/version.rb +1 -1
  6. data/lib/generators/foundation/templates/_settings.scss +37 -11
  7. data/vendor/assets/js/foundation.cjs.js +1060 -370
  8. data/vendor/assets/js/foundation.cjs.js.map +1 -1
  9. data/vendor/assets/js/foundation.es6.js +926 -326
  10. data/vendor/assets/js/foundation.es6.js.map +1 -1
  11. data/vendor/assets/js/foundation.esm.js +1048 -358
  12. data/vendor/assets/js/foundation.esm.js.map +1 -1
  13. data/vendor/assets/js/foundation.js +1063 -393
  14. data/vendor/assets/js/foundation.js.map +1 -1
  15. data/vendor/assets/js/foundation.min.js +1 -1
  16. data/vendor/assets/js/foundation.min.js.map +1 -1
  17. data/vendor/assets/js/plugins/foundation.abide.js +201 -11
  18. data/vendor/assets/js/plugins/foundation.abide.js.map +1 -1
  19. data/vendor/assets/js/plugins/foundation.abide.min.js +1 -1
  20. data/vendor/assets/js/plugins/foundation.abide.min.js.map +1 -1
  21. data/vendor/assets/js/plugins/foundation.accordion.js +22 -19
  22. data/vendor/assets/js/plugins/foundation.accordion.js.map +1 -1
  23. data/vendor/assets/js/plugins/foundation.accordion.min.js +1 -1
  24. data/vendor/assets/js/plugins/foundation.accordion.min.js.map +1 -1
  25. data/vendor/assets/js/plugins/foundation.accordionMenu.js +2 -4
  26. data/vendor/assets/js/plugins/foundation.accordionMenu.js.map +1 -1
  27. data/vendor/assets/js/plugins/foundation.accordionMenu.min.js +1 -1
  28. data/vendor/assets/js/plugins/foundation.accordionMenu.min.js.map +1 -1
  29. data/vendor/assets/js/plugins/foundation.core.js +140 -28
  30. data/vendor/assets/js/plugins/foundation.core.js.map +1 -1
  31. data/vendor/assets/js/plugins/foundation.core.min.js +1 -1
  32. data/vendor/assets/js/plugins/foundation.core.min.js.map +1 -1
  33. data/vendor/assets/js/plugins/foundation.drilldown.js +29 -19
  34. data/vendor/assets/js/plugins/foundation.drilldown.js.map +1 -1
  35. data/vendor/assets/js/plugins/foundation.drilldown.min.js +1 -1
  36. data/vendor/assets/js/plugins/foundation.drilldown.min.js.map +1 -1
  37. data/vendor/assets/js/plugins/foundation.dropdown.js +30 -13
  38. data/vendor/assets/js/plugins/foundation.dropdown.js.map +1 -1
  39. data/vendor/assets/js/plugins/foundation.dropdown.min.js +1 -1
  40. data/vendor/assets/js/plugins/foundation.dropdown.min.js.map +1 -1
  41. data/vendor/assets/js/plugins/foundation.dropdownMenu.js +67 -38
  42. data/vendor/assets/js/plugins/foundation.dropdownMenu.js.map +1 -1
  43. data/vendor/assets/js/plugins/foundation.dropdownMenu.min.js +1 -1
  44. data/vendor/assets/js/plugins/foundation.dropdownMenu.min.js.map +1 -1
  45. data/vendor/assets/js/plugins/foundation.equalizer.js +1 -1
  46. data/vendor/assets/js/plugins/foundation.equalizer.min.js +1 -1
  47. data/vendor/assets/js/plugins/foundation.equalizer.min.js.map +1 -1
  48. data/vendor/assets/js/plugins/foundation.interchange.js +48 -13
  49. data/vendor/assets/js/plugins/foundation.interchange.js.map +1 -1
  50. data/vendor/assets/js/plugins/foundation.interchange.min.js +1 -1
  51. data/vendor/assets/js/plugins/foundation.interchange.min.js.map +1 -1
  52. data/vendor/assets/js/plugins/foundation.magellan.js +340 -12
  53. data/vendor/assets/js/plugins/foundation.magellan.js.map +1 -1
  54. data/vendor/assets/js/plugins/foundation.magellan.min.js +1 -1
  55. data/vendor/assets/js/plugins/foundation.magellan.min.js.map +1 -1
  56. data/vendor/assets/js/plugins/foundation.offcanvas.js +234 -56
  57. data/vendor/assets/js/plugins/foundation.offcanvas.js.map +1 -1
  58. data/vendor/assets/js/plugins/foundation.offcanvas.min.js +1 -1
  59. data/vendor/assets/js/plugins/foundation.offcanvas.min.js.map +1 -1
  60. data/vendor/assets/js/plugins/foundation.orbit.js +31 -4
  61. data/vendor/assets/js/plugins/foundation.orbit.js.map +1 -1
  62. data/vendor/assets/js/plugins/foundation.orbit.min.js +1 -1
  63. data/vendor/assets/js/plugins/foundation.orbit.min.js.map +1 -1
  64. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.js +91 -18
  65. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.js.map +1 -1
  66. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.min.js +1 -1
  67. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.min.js.map +1 -1
  68. data/vendor/assets/js/plugins/foundation.responsiveMenu.js +1 -1
  69. data/vendor/assets/js/plugins/foundation.responsiveMenu.min.js +1 -1
  70. data/vendor/assets/js/plugins/foundation.responsiveMenu.min.js.map +1 -1
  71. data/vendor/assets/js/plugins/foundation.responsiveToggle.js +1 -1
  72. data/vendor/assets/js/plugins/foundation.responsiveToggle.min.js +1 -1
  73. data/vendor/assets/js/plugins/foundation.responsiveToggle.min.js.map +1 -1
  74. data/vendor/assets/js/plugins/foundation.reveal.js +19 -12
  75. data/vendor/assets/js/plugins/foundation.reveal.js.map +1 -1
  76. data/vendor/assets/js/plugins/foundation.reveal.min.js +1 -1
  77. data/vendor/assets/js/plugins/foundation.reveal.min.js.map +1 -1
  78. data/vendor/assets/js/plugins/foundation.slider.js +20 -15
  79. data/vendor/assets/js/plugins/foundation.slider.js.map +1 -1
  80. data/vendor/assets/js/plugins/foundation.slider.min.js +1 -1
  81. data/vendor/assets/js/plugins/foundation.slider.min.js.map +1 -1
  82. data/vendor/assets/js/plugins/foundation.smoothScroll.js +2 -2
  83. data/vendor/assets/js/plugins/foundation.smoothScroll.js.map +1 -1
  84. data/vendor/assets/js/plugins/foundation.smoothScroll.min.js +1 -1
  85. data/vendor/assets/js/plugins/foundation.smoothScroll.min.js.map +1 -1
  86. data/vendor/assets/js/plugins/foundation.sticky.js +26 -18
  87. data/vendor/assets/js/plugins/foundation.sticky.js.map +1 -1
  88. data/vendor/assets/js/plugins/foundation.sticky.min.js +1 -1
  89. data/vendor/assets/js/plugins/foundation.sticky.min.js.map +1 -1
  90. data/vendor/assets/js/plugins/foundation.tabs.js +24 -21
  91. data/vendor/assets/js/plugins/foundation.tabs.js.map +1 -1
  92. data/vendor/assets/js/plugins/foundation.tabs.min.js +1 -1
  93. data/vendor/assets/js/plugins/foundation.tabs.min.js.map +1 -1
  94. data/vendor/assets/js/plugins/foundation.toggler.js +24 -9
  95. data/vendor/assets/js/plugins/foundation.toggler.js.map +1 -1
  96. data/vendor/assets/js/plugins/foundation.toggler.min.js +1 -1
  97. data/vendor/assets/js/plugins/foundation.toggler.min.js.map +1 -1
  98. data/vendor/assets/js/plugins/foundation.tooltip.js +31 -18
  99. data/vendor/assets/js/plugins/foundation.tooltip.js.map +1 -1
  100. data/vendor/assets/js/plugins/foundation.tooltip.min.js +1 -1
  101. data/vendor/assets/js/plugins/foundation.tooltip.min.js.map +1 -1
  102. data/vendor/assets/js/plugins/foundation.util.box.js +1 -59
  103. data/vendor/assets/js/plugins/foundation.util.box.js.map +1 -1
  104. data/vendor/assets/js/plugins/foundation.util.box.min.js +1 -1
  105. data/vendor/assets/js/plugins/foundation.util.box.min.js.map +1 -1
  106. data/vendor/assets/js/plugins/foundation.util.imageLoader.js +1 -1
  107. data/vendor/assets/js/plugins/foundation.util.imageLoader.min.js +1 -1
  108. data/vendor/assets/js/plugins/foundation.util.imageLoader.min.js.map +1 -1
  109. data/vendor/assets/js/plugins/foundation.util.keyboard.js +9 -8
  110. data/vendor/assets/js/plugins/foundation.util.keyboard.js.map +1 -1
  111. data/vendor/assets/js/plugins/foundation.util.keyboard.min.js +1 -1
  112. data/vendor/assets/js/plugins/foundation.util.keyboard.min.js.map +1 -1
  113. data/vendor/assets/js/plugins/foundation.util.mediaQuery.js +121 -17
  114. data/vendor/assets/js/plugins/foundation.util.mediaQuery.js.map +1 -1
  115. data/vendor/assets/js/plugins/foundation.util.mediaQuery.min.js +1 -1
  116. data/vendor/assets/js/plugins/foundation.util.mediaQuery.min.js.map +1 -1
  117. data/vendor/assets/js/plugins/foundation.util.motion.js +1 -2
  118. data/vendor/assets/js/plugins/foundation.util.motion.js.map +1 -1
  119. data/vendor/assets/js/plugins/foundation.util.motion.min.js +1 -1
  120. data/vendor/assets/js/plugins/foundation.util.motion.min.js.map +1 -1
  121. data/vendor/assets/js/plugins/foundation.util.nest.js +1 -1
  122. data/vendor/assets/js/plugins/foundation.util.nest.min.js +1 -1
  123. data/vendor/assets/js/plugins/foundation.util.nest.min.js.map +1 -1
  124. data/vendor/assets/js/plugins/foundation.util.timer.js +1 -1
  125. data/vendor/assets/js/plugins/foundation.util.timer.min.js +1 -1
  126. data/vendor/assets/js/plugins/foundation.util.timer.min.js.map +1 -1
  127. data/vendor/assets/js/plugins/foundation.util.touch.js +2 -2
  128. data/vendor/assets/js/plugins/foundation.util.touch.js.map +1 -1
  129. data/vendor/assets/js/plugins/foundation.util.touch.min.js +1 -1
  130. data/vendor/assets/js/plugins/foundation.util.touch.min.js.map +1 -1
  131. data/vendor/assets/js/plugins/foundation.util.triggers.js +3 -2
  132. data/vendor/assets/js/plugins/foundation.util.triggers.js.map +1 -1
  133. data/vendor/assets/js/plugins/foundation.util.triggers.min.js +1 -1
  134. data/vendor/assets/js/plugins/foundation.util.triggers.min.js.map +1 -1
  135. data/vendor/assets/scss/components/_accordion.scss +10 -2
  136. data/vendor/assets/scss/components/_button-group.scss +37 -10
  137. data/vendor/assets/scss/components/_button.scss +119 -104
  138. data/vendor/assets/scss/components/_callout.scss +12 -10
  139. data/vendor/assets/scss/components/_close-button.scss +28 -3
  140. data/vendor/assets/scss/components/_menu.scss +5 -1
  141. data/vendor/assets/scss/components/_off-canvas.scss +6 -1
  142. data/vendor/assets/scss/components/_pagination.scss +10 -2
  143. data/vendor/assets/scss/components/_switch.scss +14 -0
  144. data/vendor/assets/scss/components/_table.scss +1 -0
  145. data/vendor/assets/scss/forms/_select.scss +4 -0
  146. data/vendor/assets/scss/foundation.scss +8 -3
  147. data/vendor/assets/scss/grid/_classes.scss +25 -12
  148. data/vendor/assets/scss/grid/_column.scss +1 -31
  149. data/vendor/assets/scss/prototype/_rounded.scss +6 -2
  150. data/vendor/assets/scss/prototype/_spacing.scss +7 -5
  151. data/vendor/assets/scss/settings/_settings.scss +37 -11
  152. data/vendor/assets/scss/typography/_base.scss +16 -51
  153. data/vendor/assets/scss/typography/_helpers.scss +100 -0
  154. data/vendor/assets/scss/typography/_print.scss +8 -2
  155. data/vendor/assets/scss/util/_breakpoint.scss +172 -97
  156. data/vendor/assets/scss/util/_math.scss +75 -0
  157. data/vendor/assets/scss/util/_mixins.scss +81 -25
  158. data/vendor/assets/scss/util/_value.scss +40 -0
  159. data/vendor/assets/scss/xy-grid/_cell.scss +186 -99
  160. data/vendor/assets/scss/xy-grid/_classes.scss +26 -29
  161. data/vendor/assets/scss/xy-grid/_collapse.scss +2 -2
  162. data/vendor/assets/scss/xy-grid/_layout.scss +10 -8
  163. data/vendor/assets/scss/xy-grid/_position.scss +32 -9
  164. metadata +8 -9
@@ -119,6 +119,44 @@ function _get(target, property, receiver) {
119
119
  return _get(target, property, receiver || target);
120
120
  }
121
121
 
122
+ function _slicedToArray(arr, i) {
123
+ return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
124
+ }
125
+
126
+ function _arrayWithHoles(arr) {
127
+ if (Array.isArray(arr)) return arr;
128
+ }
129
+
130
+ function _iterableToArrayLimit(arr, i) {
131
+ var _arr = [];
132
+ var _n = true;
133
+ var _d = false;
134
+ var _e = undefined;
135
+
136
+ try {
137
+ for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
138
+ _arr.push(_s.value);
139
+
140
+ if (i && _arr.length === i) break;
141
+ }
142
+ } catch (err) {
143
+ _d = true;
144
+ _e = err;
145
+ } finally {
146
+ try {
147
+ if (!_n && _i["return"] != null) _i["return"]();
148
+ } finally {
149
+ if (_d) throw _e;
150
+ }
151
+ }
152
+
153
+ return _arr;
154
+ }
155
+
156
+ function _nonIterableRest() {
157
+ throw new TypeError("Invalid attempt to destructure non-iterable instance");
158
+ }
159
+
122
160
  /**
123
161
  * Returns a boolean for RTL support
124
162
  */
@@ -136,9 +174,18 @@ function rtl() {
136
174
  */
137
175
 
138
176
 
139
- function GetYoDigits(length, namespace) {
140
- length = length || 6;
141
- return Math.round(Math.pow(36, length + 1) - Math.random() * Math.pow(36, length)).toString(36).slice(1) + (namespace ? "-".concat(namespace) : '');
177
+ function GetYoDigits() {
178
+ var length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6;
179
+ var namespace = arguments.length > 1 ? arguments[1] : undefined;
180
+ var str = '';
181
+ var chars = '0123456789abcdefghijklmnopqrstuvwxyz';
182
+ var charsLength = chars.length;
183
+
184
+ for (var i = 0; i < length; i++) {
185
+ str += chars[Math.floor(Math.random() * charsLength)];
186
+ }
187
+
188
+ return namespace ? "".concat(str, "-").concat(namespace) : str;
142
189
  }
143
190
  /**
144
191
  * Escape a string so it can be used as a regexp pattern
@@ -277,7 +324,7 @@ var foundation_core_utils = /*#__PURE__*/Object.freeze({
277
324
  ignoreMousedisappear: ignoreMousedisappear
278
325
  });
279
326
 
280
- // Authors & copyright(c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. MIT license
327
+ // Authors & copyright © 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. MIT license
281
328
 
282
329
  /* eslint-disable */
283
330
 
@@ -335,6 +382,13 @@ var MediaQuery = {
335
382
  * @private
336
383
  */
337
384
  _init: function _init() {
385
+ // make sure the initialization is only done once when calling _init() several times
386
+ if (this.isInitialized === true) {
387
+ return;
388
+ } else {
389
+ this.isInitialized = true;
390
+ }
391
+
338
392
  var self = this;
339
393
  var $meta = $('meta.foundation-mq');
340
394
 
@@ -345,6 +399,7 @@ var MediaQuery = {
345
399
  var extractedStyles = $('.foundation-mq').css('font-family');
346
400
  var namedQueries;
347
401
  namedQueries = parseStyleToObject(extractedStyles);
402
+ self.queries = []; // reset
348
403
 
349
404
  for (var key in namedQueries) {
350
405
  if (namedQueries.hasOwnProperty(key)) {
@@ -360,6 +415,18 @@ var MediaQuery = {
360
415
  this._watcher();
361
416
  },
362
417
 
418
+ /**
419
+ * Reinitializes the media query helper.
420
+ * Useful if your CSS breakpoint configuration has just been loaded or has changed since the initialization.
421
+ * @function
422
+ * @private
423
+ */
424
+ _reInit: function _reInit() {
425
+ this.isInitialized = false;
426
+
427
+ this._init();
428
+ },
429
+
363
430
  /**
364
431
  * Checks if the screen is at least as wide as a breakpoint.
365
432
  * @function
@@ -376,6 +443,36 @@ var MediaQuery = {
376
443
  return false;
377
444
  },
378
445
 
446
+ /**
447
+ * Checks if the screen is within the given breakpoint.
448
+ * If smaller than the breakpoint of larger than its upper limit it returns false.
449
+ * @function
450
+ * @param {String} size - Name of the breakpoint to check.
451
+ * @returns {Boolean} `true` if the breakpoint matches, `false` otherwise.
452
+ */
453
+ only: function only(size) {
454
+ return size === this._getCurrentSize();
455
+ },
456
+
457
+ /**
458
+ * Checks if the screen is within a breakpoint or smaller.
459
+ * @function
460
+ * @param {String} size - Name of the breakpoint to check.
461
+ * @returns {Boolean} `true` if the breakpoint matches, `false` if it's larger.
462
+ */
463
+ upTo: function upTo(size) {
464
+ var nextSize = this.next(size); // If the next breakpoint does not match, the screen is smaller than
465
+ // the upper limit of this breakpoint.
466
+
467
+ if (nextSize) {
468
+ return !this.atLeast(nextSize);
469
+ } // If there is no next breakpoint, the "size" breakpoint does not have
470
+ // an upper limit and the screen will always be within it or smaller.
471
+
472
+
473
+ return true;
474
+ },
475
+
379
476
  /**
380
477
  * Checks if the screen matches to a breakpoint.
381
478
  * @function
@@ -383,15 +480,31 @@ var MediaQuery = {
383
480
  * @returns {Boolean} `true` if the breakpoint matches, `false` if it does not.
384
481
  */
385
482
  is: function is(size) {
386
- size = size.trim().split(' ');
483
+ var parts = size.trim().split(' ').filter(function (p) {
484
+ return !!p.length;
485
+ });
387
486
 
388
- if (size.length > 1 && size[1] === 'only') {
389
- if (size[0] === this._getCurrentSize()) return true;
390
- } else {
391
- return this.atLeast(size[0]);
487
+ var _parts = _slicedToArray(parts, 2),
488
+ bpSize = _parts[0],
489
+ _parts$ = _parts[1],
490
+ bpModifier = _parts$ === void 0 ? '' : _parts$; // Only the breakpont
491
+
492
+
493
+ if (bpModifier === 'only') {
494
+ return this.only(bpSize);
495
+ } // At least the breakpoint (included)
496
+
497
+
498
+ if (!bpModifier || bpModifier === 'up') {
499
+ return this.atLeast(bpSize);
500
+ } // Up to the breakpoint (included)
501
+
502
+
503
+ if (bpModifier === 'down') {
504
+ return this.upTo(bpSize);
392
505
  }
393
506
 
394
- return false;
507
+ throw new Error("\n Invalid breakpoint passed to MediaQuery.is().\n Expected a breakpoint name formatted like \"<size> <modifier>\", got \"".concat(size, "\".\n "));
395
508
  },
396
509
 
397
510
  /**
@@ -411,6 +524,40 @@ var MediaQuery = {
411
524
  return null;
412
525
  },
413
526
 
527
+ /**
528
+ * Get the breakpoint following the given breakpoint.
529
+ * @function
530
+ * @param {String} size - Name of the breakpoint.
531
+ * @returns {String|null} - The name of the following breakpoint, or `null` if the passed breakpoint was the last one.
532
+ */
533
+ next: function next(size) {
534
+ var _this = this;
535
+
536
+ var queryIndex = this.queries.findIndex(function (q) {
537
+ return _this._getQueryName(q) === size;
538
+ });
539
+
540
+ if (queryIndex === -1) {
541
+ throw new Error("\n Unknown breakpoint \"".concat(size, "\" passed to MediaQuery.next().\n Ensure it is present in your Sass \"$breakpoints\" setting.\n "));
542
+ }
543
+
544
+ var nextQuery = this.queries[queryIndex + 1];
545
+ return nextQuery ? nextQuery.name : null;
546
+ },
547
+
548
+ /**
549
+ * Returns the name of the breakpoint related to the given value.
550
+ * @function
551
+ * @private
552
+ * @param {String|Object} value - Breakpoint name or query object.
553
+ * @returns {String} Name of the breakpoint.
554
+ */
555
+ _getQueryName: function _getQueryName(value) {
556
+ if (typeof value === 'string') return value;
557
+ if (_typeof(value) === 'object') return value.name;
558
+ throw new TypeError("\n Invalid value passed to MediaQuery._getQueryName().\n Expected a breakpoint name (String) or a breakpoint query (Object), got \"".concat(value, "\" (").concat(_typeof(value), ")\n "));
559
+ },
560
+
414
561
  /**
415
562
  * Gets the current breakpoint name by testing every breakpoint and returning the last one to match (the biggest one).
416
563
  * @function
@@ -428,11 +575,7 @@ var MediaQuery = {
428
575
  }
429
576
  }
430
577
 
431
- if (_typeof(matched) === 'object') {
432
- return matched.name;
433
- } else {
434
- return matched;
435
- }
578
+ return matched && this._getQueryName(matched);
436
579
  },
437
580
 
438
581
  /**
@@ -441,15 +584,15 @@ var MediaQuery = {
441
584
  * @private
442
585
  */
443
586
  _watcher: function _watcher() {
444
- var _this = this;
587
+ var _this2 = this;
445
588
 
446
589
  $(window).off('resize.zf.mediaquery').on('resize.zf.mediaquery', function () {
447
- var newSize = _this._getCurrentSize(),
448
- currentSize = _this.current;
590
+ var newSize = _this2._getCurrentSize(),
591
+ currentSize = _this2.current;
449
592
 
450
593
  if (newSize !== currentSize) {
451
594
  // Change the current media query
452
- _this.current = newSize; // Broadcast the media query change on the window
595
+ _this2.current = newSize; // Broadcast the media query change on the window
453
596
 
454
597
  $(window).trigger('changed.zf.mediaquery', [newSize, currentSize]);
455
598
  }
@@ -492,7 +635,7 @@ function parseStyleToObject(str) {
492
635
  return styleObject;
493
636
  }
494
637
 
495
- var FOUNDATION_VERSION = '6.5.3'; // Global Foundation object
638
+ var FOUNDATION_VERSION = '6.6.1'; // Global Foundation object
496
639
  // This is attached to the window, or used as a module for AMD/Browserify
497
640
 
498
641
  var Foundation = {
@@ -611,7 +754,7 @@ var Foundation = {
611
754
  plugins = hyphenate(plugins);
612
755
  $('[data-' + plugins + ']').foundation('_init');
613
756
  },
614
- 'undefined': function undefined() {
757
+ 'undefined': function undefined$1() {
615
758
  this['object'](Object.keys(_this._plugins));
616
759
  }
617
760
  };
@@ -646,16 +789,15 @@ var Foundation = {
646
789
  // Get the current plugin
647
790
  var plugin = _this._plugins[name]; // Localize the search to all elements inside elem, as well as elem itself, unless elem === document
648
791
 
649
- var $elem = $(elem).find('[data-' + name + ']').addBack('[data-' + name + ']'); // For each plugin found, initialize it
792
+ var $elem = $(elem).find('[data-' + name + ']').addBack('[data-' + name + ']').filter(function () {
793
+ return typeof $(this).data("zfPlugin") === 'undefined';
794
+ }); // For each plugin found, initialize it
650
795
 
651
796
  $elem.each(function () {
652
797
  var $el = $(this),
653
- opts = {}; // Don't double-dip on plugins
654
-
655
- if ($el.data('zfPlugin')) {
656
- console.warn("Tried to initialize " + name + " on an element that already has a Foundation plugin.");
657
- return;
658
- }
798
+ opts = {
799
+ reflow: true
800
+ };
659
801
 
660
802
  if ($el.attr('data-options')) {
661
803
  var thing = $el.attr('data-options').split(';').forEach(function (e, i) {
@@ -677,7 +819,7 @@ var Foundation = {
677
819
  });
678
820
  },
679
821
  getFnName: functionName,
680
- addToJquery: function addToJquery($$$1) {
822
+ addToJquery: function addToJquery($) {
681
823
  // TODO: consider not making this a jQuery function
682
824
  // TODO: need way to reflow vs. re-initialize
683
825
 
@@ -687,7 +829,7 @@ var Foundation = {
687
829
  */
688
830
  var foundation = function foundation(method) {
689
831
  var type = _typeof(method),
690
- $noJS = $$$1('.no-js');
832
+ $noJS = $('.no-js');
691
833
 
692
834
  if ($noJS.length) {
693
835
  $noJS.removeClass('no-js');
@@ -712,7 +854,7 @@ var Foundation = {
712
854
  } else {
713
855
  this.each(function (i, el) {
714
856
  //otherwise loop through the jQuery collection and invoke the method on each
715
- plugClass[method].apply($$$1(el).data('zfPlugin'), args);
857
+ plugClass[method].apply($(el).data('zfPlugin'), args);
716
858
  });
717
859
  }
718
860
  } else {
@@ -727,8 +869,8 @@ var Foundation = {
727
869
  return this;
728
870
  };
729
871
 
730
- $$$1.fn.foundation = foundation;
731
- return $$$1;
872
+ $.fn.foundation = foundation;
873
+ return $;
732
874
  }
733
875
  };
734
876
  Foundation.util = {
@@ -849,7 +991,6 @@ var Box = {
849
991
  ImNotTouchingYou: ImNotTouchingYou,
850
992
  OverlapArea: OverlapArea,
851
993
  GetDimensions: GetDimensions,
852
- GetOffsets: GetOffsets,
853
994
  GetExplicitOffsets: GetExplicitOffsets
854
995
  /**
855
996
  * Compares the dimensions of an element to a container and determines collision events with container.
@@ -966,63 +1107,6 @@ function GetDimensions(elem) {
966
1107
  */
967
1108
 
968
1109
 
969
- function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) {
970
- console.log("NOTE: GetOffsets is deprecated in favor of GetExplicitOffsets and will be removed in 6.5");
971
-
972
- switch (position) {
973
- case 'top':
974
- return rtl() ? GetExplicitOffsets(element, anchor, 'top', 'left', vOffset, hOffset, isOverflow) : GetExplicitOffsets(element, anchor, 'top', 'right', vOffset, hOffset, isOverflow);
975
-
976
- case 'bottom':
977
- return rtl() ? GetExplicitOffsets(element, anchor, 'bottom', 'left', vOffset, hOffset, isOverflow) : GetExplicitOffsets(element, anchor, 'bottom', 'right', vOffset, hOffset, isOverflow);
978
-
979
- case 'center top':
980
- return GetExplicitOffsets(element, anchor, 'top', 'center', vOffset, hOffset, isOverflow);
981
-
982
- case 'center bottom':
983
- return GetExplicitOffsets(element, anchor, 'bottom', 'center', vOffset, hOffset, isOverflow);
984
-
985
- case 'center left':
986
- return GetExplicitOffsets(element, anchor, 'left', 'center', vOffset, hOffset, isOverflow);
987
-
988
- case 'center right':
989
- return GetExplicitOffsets(element, anchor, 'right', 'center', vOffset, hOffset, isOverflow);
990
-
991
- case 'left bottom':
992
- return GetExplicitOffsets(element, anchor, 'bottom', 'left', vOffset, hOffset, isOverflow);
993
-
994
- case 'right bottom':
995
- return GetExplicitOffsets(element, anchor, 'bottom', 'right', vOffset, hOffset, isOverflow);
996
- // Backwards compatibility... this along with the reveal and reveal full
997
- // classes are the only ones that didn't reference anchor
998
-
999
- case 'center':
1000
- return {
1001
- left: $eleDims.windowDims.offset.left + $eleDims.windowDims.width / 2 - $eleDims.width / 2 + hOffset,
1002
- top: $eleDims.windowDims.offset.top + $eleDims.windowDims.height / 2 - ($eleDims.height / 2 + vOffset)
1003
- };
1004
-
1005
- case 'reveal':
1006
- return {
1007
- left: ($eleDims.windowDims.width - $eleDims.width) / 2 + hOffset,
1008
- top: $eleDims.windowDims.offset.top + vOffset
1009
- };
1010
-
1011
- case 'reveal full':
1012
- return {
1013
- left: $eleDims.windowDims.offset.left,
1014
- top: $eleDims.windowDims.offset.top
1015
- };
1016
- break;
1017
-
1018
- default:
1019
- return {
1020
- left: rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width - hOffset : $anchorDims.offset.left + hOffset,
1021
- top: $anchorDims.offset.top + $anchorDims.height + vOffset
1022
- };
1023
- }
1024
- }
1025
-
1026
1110
  function GetExplicitOffsets(element, anchor, position, alignment, vOffset, hOffset, isOverflow) {
1027
1111
  var $eleDims = GetDimensions(element),
1028
1112
  $anchorDims = anchor ? GetDimensions(anchor) : null;
@@ -1202,10 +1286,11 @@ var Keyboard = {
1202
1286
  cmds,
1203
1287
  command,
1204
1288
  fn;
1205
- if (!commandList) return console.warn('Component not defined!');
1289
+ if (!commandList) return console.warn('Component not defined!'); // Ignore the event if it was already handled
1290
+
1291
+ if (event.zfIsKeyHandled === true) return; // This component does not differentiate between ltr and rtl
1206
1292
 
1207
1293
  if (typeof commandList.ltr === 'undefined') {
1208
- // this component does not differentiate between ltr and rtl
1209
1294
  cmds = commandList; // use plain list
1210
1295
  } else {
1211
1296
  // merge ltr and rtl: if document is rtl, rtl overwrites ltr and vice versa
@@ -1213,19 +1298,19 @@ var Keyboard = {
1213
1298
  }
1214
1299
 
1215
1300
  command = cmds[keyCode];
1216
- fn = functions[command];
1301
+ fn = functions[command]; // Execute the handler if found
1217
1302
 
1218
1303
  if (fn && typeof fn === 'function') {
1219
- // execute function if exists
1220
- var returnValue = fn.apply();
1304
+ var returnValue = fn.apply(); // Mark the event as "handled" to prevent future handlings
1305
+
1306
+ event.zfIsKeyHandled = true; // Execute function when event was handled
1221
1307
 
1222
1308
  if (functions.handled || typeof functions.handled === 'function') {
1223
- // execute function when event was handled
1224
1309
  functions.handled(returnValue);
1225
1310
  }
1226
1311
  } else {
1312
+ // Execute function when event was not handled
1227
1313
  if (functions.unhandled || typeof functions.unhandled === 'function') {
1228
- // execute function when event was not handled
1229
1314
  functions.unhandled();
1230
1315
  }
1231
1316
  }
@@ -1359,7 +1444,6 @@ function animate(isIn, element, animation, cb) {
1359
1444
  }); // Start the animation
1360
1445
 
1361
1446
  requestAnimationFrame(function () {
1362
- element[0].offsetWidth;
1363
1447
  element.css('transition', '').addClass(activeClass);
1364
1448
  }); // Clean up the animation when it finishes
1365
1449
 
@@ -1533,7 +1617,7 @@ function onTouchMove(e) {
1533
1617
  if (dir) {
1534
1618
  e.preventDefault();
1535
1619
  onTouchEnd.apply(this, arguments);
1536
- $(this).trigger($.Event('swipe', e), dir).trigger($.Event("swipe".concat(dir), e));
1620
+ $(this).trigger($.Event('swipe', Object.assign({}, e)), dir).trigger($.Event("swipe".concat(dir), Object.assign({}, e)));
1537
1621
  }
1538
1622
  }
1539
1623
  }
@@ -1558,7 +1642,7 @@ function init() {
1558
1642
  var SpotSwipe =
1559
1643
  /*#__PURE__*/
1560
1644
  function () {
1561
- function SpotSwipe($$$1) {
1645
+ function SpotSwipe($) {
1562
1646
  _classCallCheck(this, SpotSwipe);
1563
1647
 
1564
1648
  this.version = '1.0.0';
@@ -1566,7 +1650,7 @@ function () {
1566
1650
  this.preventDefault = false;
1567
1651
  this.moveThreshold = 75;
1568
1652
  this.timeThreshold = 200;
1569
- this.$ = $$$1;
1653
+ this.$ = $;
1570
1654
 
1571
1655
  this._init();
1572
1656
  }
@@ -1574,17 +1658,17 @@ function () {
1574
1658
  _createClass(SpotSwipe, [{
1575
1659
  key: "_init",
1576
1660
  value: function _init() {
1577
- var $$$1 = this.$;
1578
- $$$1.event.special.swipe = {
1661
+ var $ = this.$;
1662
+ $.event.special.swipe = {
1579
1663
  setup: init
1580
1664
  };
1581
- $$$1.event.special.tap = {
1665
+ $.event.special.tap = {
1582
1666
  setup: init
1583
1667
  };
1584
- $$$1.each(['left', 'up', 'down', 'right'], function () {
1585
- $$$1.event.special["swipe".concat(this)] = {
1668
+ $.each(['left', 'up', 'down', 'right'], function () {
1669
+ $.event.special["swipe".concat(this)] = {
1586
1670
  setup: function setup() {
1587
- $$$1(this).on('swipe', $$$1.noop);
1671
+ $(this).on('swipe', $.noop);
1588
1672
  }
1589
1673
  };
1590
1674
  });
@@ -1601,18 +1685,18 @@ function () {
1601
1685
  ****************************************************/
1602
1686
 
1603
1687
 
1604
- Touch.setupSpotSwipe = function ($$$1) {
1605
- $$$1.spotSwipe = new SpotSwipe($$$1);
1688
+ Touch.setupSpotSwipe = function ($) {
1689
+ $.spotSwipe = new SpotSwipe($);
1606
1690
  };
1607
1691
  /****************************************************
1608
1692
  * Method for adding pseudo drag events to elements *
1609
1693
  ***************************************************/
1610
1694
 
1611
1695
 
1612
- Touch.setupTouchHandler = function ($$$1) {
1613
- $$$1.fn.addTouch = function () {
1696
+ Touch.setupTouchHandler = function ($) {
1697
+ $.fn.addTouch = function () {
1614
1698
  this.each(function (i, el) {
1615
- $$$1(el).bind('touchstart touchmove touchend touchcancel', function (event) {
1699
+ $(el).bind('touchstart touchmove touchend touchcancel', function (event) {
1616
1700
  //we pass the original event object because the jQuery event
1617
1701
  //object is normalized to w3c specs and does not provide the TouchList
1618
1702
  handleTouch(event);
@@ -1651,10 +1735,10 @@ Touch.setupTouchHandler = function ($$$1) {
1651
1735
  };
1652
1736
  };
1653
1737
 
1654
- Touch.init = function ($$$1) {
1655
- if (typeof $$$1.spotSwipe === 'undefined') {
1656
- Touch.setupSpotSwipe($$$1);
1657
- Touch.setupTouchHandler($$$1);
1738
+ Touch.init = function ($) {
1739
+ if (typeof $.spotSwipe === 'undefined') {
1740
+ Touch.setupSpotSwipe($);
1741
+ Touch.setupTouchHandler($);
1658
1742
  }
1659
1743
  };
1660
1744
 
@@ -1706,8 +1790,9 @@ Triggers.Listeners.Basic = {
1706
1790
  }
1707
1791
  },
1708
1792
  closeableListener: function closeableListener(e) {
1793
+ var animation = $(this).data('closable'); // Only close the first closable element. See https://git.io/zf-7833
1794
+
1709
1795
  e.stopPropagation();
1710
- var animation = $(this).data('closable');
1711
1796
 
1712
1797
  if (animation !== '') {
1713
1798
  Motion.animateOut($(this), animation, function () {
@@ -1911,12 +1996,12 @@ Triggers.Initializers.addGlobalListeners = function () {
1911
1996
  Triggers.Initializers.addClosemeListener();
1912
1997
  };
1913
1998
 
1914
- Triggers.init = function ($$$1, Foundation) {
1915
- onLoad($$$1(window), function () {
1916
- if ($$$1.triggersInitialized !== true) {
1999
+ Triggers.init = function ($, Foundation) {
2000
+ onLoad($(window), function () {
2001
+ if ($.triggersInitialized !== true) {
1917
2002
  Triggers.Initializers.addSimpleListeners();
1918
2003
  Triggers.Initializers.addGlobalListeners();
1919
- $$$1.triggersInitialized = true;
2004
+ $.triggersInitialized = true;
1920
2005
  }
1921
2006
  });
1922
2007
 
@@ -2024,6 +2109,8 @@ function (_Plugin) {
2024
2109
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2025
2110
  this.$element = element;
2026
2111
  this.options = $.extend(true, {}, Abide.defaults, this.$element.data(), options);
2112
+ this.isEnabled = true;
2113
+ this.formnovalidate = null;
2027
2114
  this.className = 'Abide'; // ie9 back compat
2028
2115
 
2029
2116
  this._init();
@@ -2039,9 +2126,10 @@ function (_Plugin) {
2039
2126
  var _this2 = this;
2040
2127
 
2041
2128
  this.$inputs = $.merge( // Consider as input to validate:
2042
- this.$element.find('input').not('[type=submit]'), // * all input fields expect submit
2129
+ this.$element.find('input').not('[type="submit"]'), // * all input fields expect submit
2043
2130
  this.$element.find('textarea, select') // * all textareas and select fields
2044
2131
  );
2132
+ this.$submits = this.$element.find('[type="submit"]');
2045
2133
  var $globalErrors = this.$element.find('[data-abide-error]'); // Add a11y attributes to all fields
2046
2134
 
2047
2135
  if (this.options.a11yAttributes) {
@@ -2070,6 +2158,14 @@ function (_Plugin) {
2070
2158
  }).on('submit.zf.abide', function () {
2071
2159
  return _this3.validateForm();
2072
2160
  });
2161
+ this.$submits.off('click.zf.abide keydown.zf.abide').on('click.zf.abide keydown.zf.abide', function (e) {
2162
+ if (!e.key || e.key === ' ' || e.key === 'Enter') {
2163
+ e.preventDefault();
2164
+ _this3.formnovalidate = e.target.getAttribute('formnovalidate') !== null;
2165
+
2166
+ _this3.$element.submit();
2167
+ }
2168
+ });
2073
2169
 
2074
2170
  if (this.options.validateOn === 'fieldChange') {
2075
2171
  this.$inputs.off('change.zf.abide').on('change.zf.abide', function (e) {
@@ -2099,6 +2195,44 @@ function (_Plugin) {
2099
2195
  value: function _reflow() {
2100
2196
  this._init();
2101
2197
  }
2198
+ /**
2199
+ * Checks whether the submitted form should be validated or not, consodering formnovalidate and isEnabled
2200
+ * @returns {Boolean}
2201
+ * @private
2202
+ */
2203
+
2204
+ }, {
2205
+ key: "_validationIsDisabled",
2206
+ value: function _validationIsDisabled() {
2207
+ if (this.isEnabled === false) {
2208
+ // whole validation disabled
2209
+ return true;
2210
+ } else if (typeof this.formnovalidate === 'boolean') {
2211
+ // triggered by $submit
2212
+ return this.formnovalidate;
2213
+ } else {
2214
+ // triggered by Enter in non-submit input
2215
+ return this.$submits.length ? this.$submits[0].getAttribute('formnovalidate') !== null : false;
2216
+ }
2217
+ }
2218
+ /**
2219
+ * Enables the whole validation
2220
+ */
2221
+
2222
+ }, {
2223
+ key: "enableValidation",
2224
+ value: function enableValidation() {
2225
+ this.isEnabled = true;
2226
+ }
2227
+ /**
2228
+ * Disables the whole validation
2229
+ */
2230
+
2231
+ }, {
2232
+ key: "disableValidation",
2233
+ value: function disableValidation() {
2234
+ this.isEnabled = false;
2235
+ }
2102
2236
  /**
2103
2237
  * Checks whether or not a form element has the required attribute and if it's checked or not
2104
2238
  * @param {Object} element - jQuery object to check for required attribute
@@ -2145,7 +2279,7 @@ function (_Plugin) {
2145
2279
  }, {
2146
2280
  key: "findFormError",
2147
2281
  value: function findFormError($el) {
2148
- var id = $el[0].id;
2282
+ var id = $el.length ? $el[0].id : '';
2149
2283
  var $error = $el.siblings(this.options.formErrorSelector);
2150
2284
 
2151
2285
  if (!$error.length) {
@@ -2206,6 +2340,33 @@ function (_Plugin) {
2206
2340
  });
2207
2341
  return $(labels);
2208
2342
  }
2343
+ /**
2344
+ * Get the set of labels associated with a set of checkbox els in this order
2345
+ * 2. The <label> with the attribute `[for="someInputId"]`
2346
+ * 3. The `.closest()` <label>
2347
+ *
2348
+ * @param {Object} $el - jQuery object to check for required attribute
2349
+ * @returns {Boolean} Boolean value depends on whether or not attribute is checked or empty
2350
+ */
2351
+
2352
+ }, {
2353
+ key: "findCheckboxLabels",
2354
+ value: function findCheckboxLabels($els) {
2355
+ var _this5 = this;
2356
+
2357
+ var labels = $els.map(function (i, el) {
2358
+ var id = el.id;
2359
+
2360
+ var $label = _this5.$element.find("label[for=\"".concat(id, "\"]"));
2361
+
2362
+ if (!$label.length) {
2363
+ $label = $(el).closest('label');
2364
+ }
2365
+
2366
+ return $label[0];
2367
+ });
2368
+ return $(labels);
2369
+ }
2209
2370
  /**
2210
2371
  * Adds the CSS error class as specified by the Abide settings to the label, input, and the form
2211
2372
  * @param {Object} $el - jQuery object to add the class to
@@ -2312,6 +2473,32 @@ function (_Plugin) {
2312
2473
  'aria-invalid': null
2313
2474
  });
2314
2475
  }
2476
+ /**
2477
+ * Remove CSS error classes etc from an entire checkbox group
2478
+ * @param {String} groupName - A string that specifies the name of a checkbox group
2479
+ *
2480
+ */
2481
+
2482
+ }, {
2483
+ key: "removeCheckboxErrorClasses",
2484
+ value: function removeCheckboxErrorClasses(groupName) {
2485
+ var $els = this.$element.find(":checkbox[name=\"".concat(groupName, "\"]"));
2486
+ var $labels = this.findCheckboxLabels($els);
2487
+ var $formErrors = this.findFormError($els);
2488
+
2489
+ if ($labels.length) {
2490
+ $labels.removeClass(this.options.labelErrorClass);
2491
+ }
2492
+
2493
+ if ($formErrors.length) {
2494
+ $formErrors.removeClass(this.options.formErrorClass);
2495
+ }
2496
+
2497
+ $els.removeClass(this.options.inputErrorClass).attr({
2498
+ 'data-invalid': null,
2499
+ 'aria-invalid': null
2500
+ });
2501
+ }
2315
2502
  /**
2316
2503
  * Removes CSS error class as specified by the Abide settings from the label, input, and the form
2317
2504
  * @param {Object} $el - jQuery object to remove the class from
@@ -2323,7 +2510,10 @@ function (_Plugin) {
2323
2510
  // radios need to clear all of the els
2324
2511
  if ($el[0].type == 'radio') {
2325
2512
  return this.removeRadioErrorClasses($el.attr('name'));
2326
- }
2513
+ } // checkboxes need to clear all of the els
2514
+ else if ($el[0].type == 'checkbox') {
2515
+ return this.removeCheckboxErrorClasses($el.attr('name'));
2516
+ }
2327
2517
 
2328
2518
  var $label = this.findLabel($el);
2329
2519
  var $formError = this.findFormError($el);
@@ -2357,7 +2547,12 @@ function (_Plugin) {
2357
2547
  validated = false,
2358
2548
  customValidator = true,
2359
2549
  validator = $el.attr('data-validator'),
2360
- equalTo = true; // don't validate ignored inputs or hidden inputs or disabled inputs
2550
+ equalTo = true; // skip validation if disabled
2551
+
2552
+ if (this._validationIsDisabled()) {
2553
+ return true;
2554
+ } // don't validate ignored inputs or hidden inputs or disabled inputs
2555
+
2361
2556
 
2362
2557
  if ($el.is('[data-abide-ignore]') || $el.is('[type="hidden"]') || $el.is('[disabled]')) {
2363
2558
  return true;
@@ -2369,7 +2564,8 @@ function (_Plugin) {
2369
2564
  break;
2370
2565
 
2371
2566
  case 'checkbox':
2372
- validated = clearRequire;
2567
+ validated = this.validateCheckbox($el.attr('name'));
2568
+ clearRequire = true;
2373
2569
  break;
2374
2570
 
2375
2571
  case 'select':
@@ -2429,20 +2625,38 @@ function (_Plugin) {
2429
2625
  }, {
2430
2626
  key: "validateForm",
2431
2627
  value: function validateForm() {
2432
- var _this5 = this;
2628
+ var _this6 = this;
2433
2629
 
2434
2630
  var acc = [];
2435
2631
 
2436
2632
  var _this = this;
2437
2633
 
2634
+ var checkboxGroupName; // Remember first form submission to prevent specific checkbox validation (more than one required) until form got initially submitted
2635
+
2636
+ if (!this.initialized) {
2637
+ this.initialized = true;
2638
+ } // skip validation if disabled
2639
+
2640
+
2641
+ if (this._validationIsDisabled()) {
2642
+ this.formnovalidate = null;
2643
+ return true;
2644
+ }
2645
+
2438
2646
  this.$inputs.each(function () {
2647
+ // Only use one checkbox per group since validateCheckbox() iterates over all associated checkboxes
2648
+ if ($(this)[0].type === 'checkbox') {
2649
+ if ($(this).attr('name') === checkboxGroupName) return true;
2650
+ checkboxGroupName = $(this).attr('name');
2651
+ }
2652
+
2439
2653
  acc.push(_this.validateInput($(this)));
2440
2654
  });
2441
2655
  var noError = acc.indexOf(false) === -1;
2442
2656
  this.$element.find('[data-abide-error]').each(function (i, elem) {
2443
2657
  var $elem = $(elem); // Ensure a11y attributes are set
2444
2658
 
2445
- if (_this5.options.a11yAttributes) _this5.addGlobalErrorA11yAttributes($elem); // Show or hide the error
2659
+ if (_this6.options.a11yAttributes) _this6.addGlobalErrorA11yAttributes($elem); // Show or hide the error
2446
2660
 
2447
2661
  $elem.css('display', noError ? 'none' : 'block');
2448
2662
  });
@@ -2467,7 +2681,7 @@ function (_Plugin) {
2467
2681
  key: "validateText",
2468
2682
  value: function validateText($el, pattern) {
2469
2683
  // A pattern can be passed to this function, or it will be infered from the input's "pattern" attribute, or it's "type" attribute
2470
- pattern = pattern || $el.attr('pattern') || $el.attr('type');
2684
+ pattern = pattern || $el.attr('data-pattern') || $el.attr('pattern') || $el.attr('type');
2471
2685
  var inputText = $el.val();
2472
2686
  var valid = false;
2473
2687
 
@@ -2520,6 +2734,64 @@ function (_Plugin) {
2520
2734
  }
2521
2735
  return valid;
2522
2736
  }
2737
+ /**
2738
+ * Determines whether or a not a checkbox input is valid based on whether or not it is required and checked. Although the function targets a single `<input>`, it validates by checking the `required` and `checked` properties of all checkboxes in its group.
2739
+ * @param {String} groupName - A string that specifies the name of a checkbox group
2740
+ * @returns {Boolean} Boolean value depends on whether or not at least one checkbox input has been checked (if it's required)
2741
+ */
2742
+
2743
+ }, {
2744
+ key: "validateCheckbox",
2745
+ value: function validateCheckbox(groupName) {
2746
+ var _this7 = this;
2747
+
2748
+ // If at least one checkbox in the group has the `required` attribute, the group is considered required
2749
+ // Per W3C spec, all checkboxes in a group should have `required`, but we're being nice
2750
+ var $group = this.$element.find(":checkbox[name=\"".concat(groupName, "\"]"));
2751
+ var valid = false,
2752
+ required = false,
2753
+ minRequired = 1,
2754
+ checked = 0; // For the group to be required, at least one checkbox needs to be required
2755
+
2756
+ $group.each(function (i, e) {
2757
+ if ($(e).attr('required')) {
2758
+ required = true;
2759
+ }
2760
+ });
2761
+ if (!required) valid = true;
2762
+
2763
+ if (!valid) {
2764
+ // Count checked checkboxes within the group
2765
+ // Use data-min-required if available (default: 1)
2766
+ $group.each(function (i, e) {
2767
+ if ($(e).prop('checked')) {
2768
+ checked++;
2769
+ }
2770
+
2771
+ if (typeof $(e).attr('data-min-required') !== 'undefined') {
2772
+ minRequired = parseInt($(e).attr('data-min-required'));
2773
+ }
2774
+ }); // For the group to be valid, the minRequired amount of checkboxes have to be checked
2775
+
2776
+ if (checked >= minRequired) {
2777
+ valid = true;
2778
+ }
2779
+ }
2780
+
2781
+ if (this.initialized !== true && minRequired > 1) {
2782
+ return true;
2783
+ } // Refresh error class for all input
2784
+
2785
+
2786
+ $group.each(function (i, e) {
2787
+ if (!valid) {
2788
+ _this7.addErrorClasses($(e));
2789
+ } else {
2790
+ _this7.removeErrorClasses($(e));
2791
+ }
2792
+ });
2793
+ return valid;
2794
+ }
2523
2795
  /**
2524
2796
  * Determines if a selected input passes a custom validation function. Multiple validations can be used, if passed to the element with `data-validator="foo bar baz"` in a space separated listed.
2525
2797
  * @param {Object} $el - jQuery input element.
@@ -2531,11 +2803,11 @@ function (_Plugin) {
2531
2803
  }, {
2532
2804
  key: "matchValidation",
2533
2805
  value: function matchValidation($el, validators, required) {
2534
- var _this6 = this;
2806
+ var _this8 = this;
2535
2807
 
2536
2808
  required = required ? true : false;
2537
2809
  var clear = validators.split(' ').map(function (v) {
2538
- return _this6.options.validators[v]($el, required, $el.parent());
2810
+ return _this8.options.validators[v]($el, required, $el.parent());
2539
2811
  });
2540
2812
  return clear.indexOf(false) === -1;
2541
2813
  }
@@ -2586,6 +2858,7 @@ function (_Plugin) {
2586
2858
  this.$inputs.off('.abide').each(function () {
2587
2859
  _this.removeErrorClasses($(this));
2588
2860
  });
2861
+ this.$submits.off('.abide');
2589
2862
  }
2590
2863
  }]);
2591
2864
 
@@ -2780,6 +3053,9 @@ function (_Plugin) {
2780
3053
  this._isInitializing = true;
2781
3054
  this.$element.attr('role', 'tablist');
2782
3055
  this.$tabs = this.$element.children('[data-accordion-item]');
3056
+ this.$tabs.attr({
3057
+ 'role': 'presentation'
3058
+ });
2783
3059
  this.$tabs.each(function (idx, el) {
2784
3060
  var $el = $(el),
2785
3061
  $content = $el.children('[data-tab-content]'),
@@ -2823,19 +3099,20 @@ function (_Plugin) {
2823
3099
  var $link = anchor && _this2.$element.find("[href$=\"".concat(anchor, "\"]")); // Whether the anchor element that has been found is part of this element
2824
3100
 
2825
3101
 
2826
- var isOwnAnchor = !!($anchor.length && $link.length); // If there is an anchor for the hash, open it (if not already active)
2827
-
2828
- if ($anchor && $link && $link.length) {
2829
- if (!$link.parent('[data-accordion-item]').hasClass('is-active')) {
2830
- _this2._openSingleTab($anchor);
2831
- }
2832
- } // Otherwise, close everything
2833
- else {
2834
- _this2._closeAllTabs();
2835
- }
3102
+ var isOwnAnchor = !!($anchor.length && $link.length);
2836
3103
 
2837
3104
  if (isOwnAnchor) {
2838
- // Roll up a little to show the titles
3105
+ // If there is an anchor for the hash, open it (if not already active)
3106
+ if ($anchor && $link && $link.length) {
3107
+ if (!$link.parent('[data-accordion-item]').hasClass('is-active')) {
3108
+ _this2._openSingleTab($anchor);
3109
+ }
3110
+ } // Otherwise, close everything
3111
+ else {
3112
+ _this2._closeAllTabs();
3113
+ } // Roll up a little to show the titles
3114
+
3115
+
2839
3116
  if (_this2.options.deepLinkSmudge) {
2840
3117
  onLoad($(window), function () {
2841
3118
  var offset = _this2.$element.offset();
@@ -2904,7 +3181,6 @@ function (_Plugin) {
2904
3181
  },
2905
3182
  handled: function handled() {
2906
3183
  e.preventDefault();
2907
- e.stopPropagation();
2908
3184
  }
2909
3185
  });
2910
3186
  });
@@ -3299,7 +3575,7 @@ function (_Plugin) {
3299
3575
  });
3300
3576
  }
3301
3577
  }
3302
- }).on('keydown.zf.accordionmenu', function (e) {
3578
+ }).on('keydown.zf.accordionMenu', function (e) {
3303
3579
  var $element = $(this),
3304
3580
  $elements = $element.parent('ul').children('li'),
3305
3581
  $prevElement,
@@ -3376,8 +3652,6 @@ function (_Plugin) {
3376
3652
  if (preventDefault) {
3377
3653
  e.preventDefault();
3378
3654
  }
3379
-
3380
- e.stopImmediatePropagation();
3381
3655
  }
3382
3656
  });
3383
3657
  }); //.attr('tabindex', 0);
@@ -3732,7 +4006,6 @@ function (_Plugin) {
3732
4006
 
3733
4007
  $elem.off('click.zf.drilldown').on('click.zf.drilldown', function (e) {
3734
4008
  if ($(e.target).parentsUntil('ul', 'li').hasClass('is-drilldown-submenu-parent')) {
3735
- e.stopImmediatePropagation();
3736
4009
  e.preventDefault();
3737
4010
  } // if(e.target !== e.currentTarget.firstElementChild){
3738
4011
  // return false;
@@ -3768,7 +4041,7 @@ function (_Plugin) {
3768
4041
  value: function _registerEvents() {
3769
4042
  if (this.options.scrollTop) {
3770
4043
  this._bindHandler = this._scrollTop.bind(this);
3771
- this.$element.on('open.zf.drilldown hide.zf.drilldown closed.zf.drilldown', this._bindHandler);
4044
+ this.$element.on('open.zf.drilldown hide.zf.drilldown close.zf.drilldown closed.zf.drilldown', this._bindHandler);
3772
4045
  }
3773
4046
 
3774
4047
  this.$element.on('mutateme.zf.trigger', this._resize.bind(this));
@@ -3885,8 +4158,6 @@ function (_Plugin) {
3885
4158
  if (preventDefault) {
3886
4159
  e.preventDefault();
3887
4160
  }
3888
-
3889
- e.stopImmediatePropagation();
3890
4161
  }
3891
4162
  });
3892
4163
  }); // end keyboardAccess
@@ -3894,25 +4165,40 @@ function (_Plugin) {
3894
4165
  /**
3895
4166
  * Closes all open elements, and returns to root menu.
3896
4167
  * @function
4168
+ * @fires Drilldown#close
3897
4169
  * @fires Drilldown#closed
3898
4170
  */
3899
4171
 
3900
4172
  }, {
3901
4173
  key: "_hideAll",
3902
4174
  value: function _hideAll() {
3903
- var $elem = this.$element.find('.is-drilldown-submenu.is-active').addClass('is-closing');
3904
- if (this.options.autoHeight) this.$wrapper.css({
3905
- height: $elem.parent().closest('ul').data('calcHeight')
3906
- });
3907
- $elem.one(transitionend($elem), function (e) {
3908
- $elem.removeClass('is-active is-closing');
3909
- });
4175
+ var _this2 = this;
4176
+
4177
+ var $elem = this.$element.find('.is-drilldown-submenu.is-active');
4178
+ $elem.addClass('is-closing');
4179
+
4180
+ if (this.options.autoHeight) {
4181
+ var calcHeight = $elem.parent().closest('ul').data('calcHeight');
4182
+ this.$wrapper.css({
4183
+ height: calcHeight
4184
+ });
4185
+ }
3910
4186
  /**
3911
- * Fires when the menu is fully closed.
3912
- * @event Drilldown#closed
4187
+ * Fires when the menu is closing.
4188
+ * @event Drilldown#close
3913
4189
  */
3914
4190
 
3915
- this.$element.trigger('closed.zf.drilldown');
4191
+
4192
+ this.$element.trigger('close.zf.drilldown');
4193
+ $elem.one(transitionend($elem), function () {
4194
+ $elem.removeClass('is-active is-closing');
4195
+ /**
4196
+ * Fires when the menu is fully closed.
4197
+ * @event Drilldown#closed
4198
+ */
4199
+
4200
+ _this2.$element.trigger('closed.zf.drilldown');
4201
+ });
3916
4202
  }
3917
4203
  /**
3918
4204
  * Adds event listener for each `back` button, and closes open menus.
@@ -3928,8 +4214,7 @@ function (_Plugin) {
3928
4214
 
3929
4215
  $elem.off('click.zf.drilldown');
3930
4216
  $elem.children('.js-drilldown-back').on('click.zf.drilldown', function (e) {
3931
- e.stopImmediatePropagation(); // console.log('mouseup on back');
3932
-
4217
+ // console.log('mouseup on back');
3933
4218
  _this._hide($elem); // If there is a parent submenu, call show
3934
4219
 
3935
4220
 
@@ -3952,7 +4237,6 @@ function (_Plugin) {
3952
4237
  var _this = this;
3953
4238
 
3954
4239
  this.$menuItems.not('.is-drilldown-submenu-parent').off('click.zf.drilldown').on('click.zf.drilldown', function (e) {
3955
- // e.stopImmediatePropagation();
3956
4240
  setTimeout(function () {
3957
4241
  _this._hideAll();
3958
4242
  }, 0);
@@ -4169,7 +4453,7 @@ Drilldown.defaults = {
4169
4453
  * Drilldowns depend on styles in order to function properly; in the default build of Foundation these are
4170
4454
  * on the `drilldown` class. This option auto-applies this class to the drilldown upon initialization.
4171
4455
  * @option
4172
- * @type {boolian}
4456
+ * @type {boolean}
4173
4457
  * @default true
4174
4458
  */
4175
4459
  autoApplyClass: true,
@@ -4417,9 +4701,6 @@ function (_Plugin) {
4417
4701
  return false;
4418
4702
  }
4419
4703
 
4420
- var $eleDims = Box.GetDimensions($element),
4421
- $anchorDims = Box.GetDimensions($anchor);
4422
-
4423
4704
  if (!this.options.allowOverlap) {
4424
4705
  // restore original position & alignment before checking overlap
4425
4706
  this.position = this.originalPosition;
@@ -4527,6 +4808,7 @@ Positionable.defaults = {
4527
4808
  * @module foundation.dropdown
4528
4809
  * @requires foundation.util.keyboard
4529
4810
  * @requires foundation.util.box
4811
+ * @requires foundation.util.touch
4530
4812
  * @requires foundation.util.triggers
4531
4813
  */
4532
4814
 
@@ -4556,8 +4838,9 @@ function (_Positionable) {
4556
4838
  this.$element = element;
4557
4839
  this.options = $.extend({}, Dropdown.defaults, this.$element.data(), options);
4558
4840
  this.className = 'Dropdown'; // ie9 back compat
4559
- // Triggers init is idempotent, just need to make sure it is initialized
4841
+ // Touch and Triggers init are idempotent, just need to make sure they are initialized
4560
4842
 
4843
+ Touch.init($);
4561
4844
  Triggers.init($);
4562
4845
 
4563
4846
  this._init();
@@ -4676,7 +4959,8 @@ function (_Positionable) {
4676
4959
  }, {
4677
4960
  key: "_events",
4678
4961
  value: function _events() {
4679
- var _this = this;
4962
+ var _this = this,
4963
+ hasTouch = 'ontouchstart' in window || typeof window.ontouchstart !== 'undefined';
4680
4964
 
4681
4965
  this.$element.on({
4682
4966
  'open.zf.trigger': this.open.bind(this),
@@ -4684,8 +4968,17 @@ function (_Positionable) {
4684
4968
  'toggle.zf.trigger': this.toggle.bind(this),
4685
4969
  'resizeme.zf.trigger': this._setPosition.bind(this)
4686
4970
  });
4687
- this.$anchors.off('click.zf.trigger').on('click.zf.trigger', function () {
4971
+ this.$anchors.off('click.zf.trigger').on('click.zf.trigger', function (e) {
4688
4972
  _this._setCurrentAnchor(this);
4973
+
4974
+ if (_this.options.forceFollow === false) {
4975
+ // if forceFollow false, always prevent default action
4976
+ e.preventDefault();
4977
+ } else if (hasTouch && _this.options.hover && _this.$element.hasClass('is-open') === false) {
4978
+ // if forceFollow true and hover option true, only prevent default action on 1st click
4979
+ // on 2nd click (dropown opened) the default action (e.g. follow a href) gets executed
4980
+ e.preventDefault();
4981
+ }
4689
4982
  });
4690
4983
 
4691
4984
  if (this.options.hover) {
@@ -4758,7 +5051,7 @@ function (_Positionable) {
4758
5051
  var $body = $(document.body).not(this.$element),
4759
5052
  _this = this;
4760
5053
 
4761
- $body.off('click.zf.dropdown').on('click.zf.dropdown', function (e) {
5054
+ $body.off('click.zf.dropdown tap.zf.dropdown').on('click.zf.dropdown tap.zf.dropdown', function (e) {
4762
5055
  if (_this.$anchors.is(e.target) || _this.$anchors.find(e.target).length) {
4763
5056
  return;
4764
5057
  }
@@ -4769,7 +5062,7 @@ function (_Positionable) {
4769
5062
 
4770
5063
  _this.close();
4771
5064
 
4772
- $body.off('click.zf.dropdown');
5065
+ $body.off('click.zf.dropdown tap.zf.dropdown');
4773
5066
  });
4774
5067
  }
4775
5068
  /**
@@ -4877,7 +5170,7 @@ function (_Positionable) {
4877
5170
  value: function _destroy() {
4878
5171
  this.$element.off('.zf.trigger').hide();
4879
5172
  this.$anchors.off('.zf.dropdown');
4880
- $(document.body).off('click.zf.dropdown');
5173
+ $(document.body).off('click.zf.dropdown tap.zf.dropdown');
4881
5174
  }
4882
5175
  }]);
4883
5176
 
@@ -4989,15 +5282,24 @@ Dropdown.defaults = {
4989
5282
  * @type {boolean}
4990
5283
  * @default false
4991
5284
  */
4992
- closeOnClick: false
5285
+ closeOnClick: false,
5286
+
5287
+ /**
5288
+ * If true the default action of the toggle (e.g. follow a link with href) gets executed on click. If hover option is also true the default action gets prevented on first click for mobile / touch devices and executed on second click.
5289
+ * @option
5290
+ * @type {boolean}
5291
+ * @default true
5292
+ */
5293
+ forceFollow: true
4993
5294
  };
4994
5295
 
4995
5296
  /**
4996
5297
  * DropdownMenu module.
4997
- * @module foundation.dropdown-menu
5298
+ * @module foundation.dropdownMenu
4998
5299
  * @requires foundation.util.keyboard
4999
5300
  * @requires foundation.util.box
5000
5301
  * @requires foundation.util.nest
5302
+ * @requires foundation.util.touch
5001
5303
  */
5002
5304
 
5003
5305
  var DropdownMenu =
@@ -5027,6 +5329,8 @@ function (_Plugin) {
5027
5329
  this.options = $.extend({}, DropdownMenu.defaults, this.$element.data(), options);
5028
5330
  this.className = 'DropdownMenu'; // ie9 back compat
5029
5331
 
5332
+ Touch.init($); // Touch init is idempotent, we just need to make sure it's initialied.
5333
+
5030
5334
  this._init();
5031
5335
 
5032
5336
  Keyboard.register('DropdownMenu', {
@@ -5109,15 +5413,13 @@ function (_Plugin) {
5109
5413
  if (hasClicked) {
5110
5414
  if (!_this.options.closeOnClick || !_this.options.clickOpen && !hasTouch || _this.options.forceFollow && hasTouch) {
5111
5415
  return;
5112
- } else {
5113
- e.stopImmediatePropagation();
5114
- e.preventDefault();
5115
-
5116
- _this._hide($elem);
5117
5416
  }
5417
+
5418
+ e.preventDefault();
5419
+
5420
+ _this._hide($elem);
5118
5421
  } else {
5119
5422
  e.preventDefault();
5120
- e.stopImmediatePropagation();
5121
5423
 
5122
5424
  _this._show($sub);
5123
5425
 
@@ -5127,12 +5429,12 @@ function (_Plugin) {
5127
5429
  };
5128
5430
 
5129
5431
  if (this.options.clickOpen || hasTouch) {
5130
- this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', handleClickFn);
5432
+ this.$menuItems.on('click.zf.dropdownMenu touchstart.zf.dropdownMenu', handleClickFn);
5131
5433
  } // Handle Leaf element Clicks
5132
5434
 
5133
5435
 
5134
5436
  if (_this.options.closeOnClickInside) {
5135
- this.$menuItems.on('click.zf.dropdownmenu', function (e) {
5437
+ this.$menuItems.on('click.zf.dropdownMenu', function (e) {
5136
5438
  var $elem = $(this),
5137
5439
  hasSub = $elem.hasClass(parClass);
5138
5440
 
@@ -5143,7 +5445,7 @@ function (_Plugin) {
5143
5445
  }
5144
5446
 
5145
5447
  if (!this.options.disableHover) {
5146
- this.$menuItems.on('mouseenter.zf.dropdownmenu', function (e) {
5448
+ this.$menuItems.on('mouseenter.zf.dropdownMenu', function (e) {
5147
5449
  var $elem = $(this),
5148
5450
  hasSub = $elem.hasClass(parClass);
5149
5451
 
@@ -5153,7 +5455,7 @@ function (_Plugin) {
5153
5455
  _this._show($elem.children('.is-dropdown-submenu'));
5154
5456
  }, _this.options.hoverDelay));
5155
5457
  }
5156
- }).on('mouseleave.zf.dropdownMenu', ignoreMousedisappear(function (e) {
5458
+ }).on('mouseleave.zf.dropdownmenu', ignoreMousedisappear(function (e) {
5157
5459
  var $elem = $(this),
5158
5460
  hasSub = $elem.hasClass(parClass);
5159
5461
 
@@ -5170,7 +5472,7 @@ function (_Plugin) {
5170
5472
  }));
5171
5473
  }
5172
5474
 
5173
- this.$menuItems.on('keydown.zf.dropdownmenu', function (e) {
5475
+ this.$menuItems.on('keydown.zf.dropdownMenu', function (e) {
5174
5476
  var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'),
5175
5477
  isTab = _this.$tabs.index($element) > -1,
5176
5478
  $elements = isTab ? _this.$tabs : $element.siblings('li').add($element),
@@ -5223,9 +5525,6 @@ function (_Plugin) {
5223
5525
 
5224
5526
 
5225
5527
  e.preventDefault();
5226
- },
5227
- handled: function handled() {
5228
- e.stopImmediatePropagation();
5229
5528
  }
5230
5529
  };
5231
5530
 
@@ -5302,27 +5601,38 @@ function (_Plugin) {
5302
5601
  }, {
5303
5602
  key: "_addBodyHandler",
5304
5603
  value: function _addBodyHandler() {
5305
- var $body = $(document.body),
5306
- _this = this;
5604
+ var _this2 = this;
5307
5605
 
5308
- $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu').on('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu', function (e) {
5309
- var $link = _this.$element.find(e.target);
5606
+ var $body = $(document.body);
5310
5607
 
5311
- if ($link.length) {
5312
- return;
5313
- }
5608
+ this._removeBodyHandler();
5314
5609
 
5315
- _this._hide();
5610
+ $body.on('click.zf.dropdownMenu tap.zf.dropdownMenu', function (e) {
5611
+ var isItself = !!$(e.target).closest(_this2.$element).length;
5612
+ if (isItself) return;
5316
5613
 
5317
- $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu');
5614
+ _this2._hide();
5615
+
5616
+ _this2._removeBodyHandler();
5318
5617
  });
5319
5618
  }
5619
+ /**
5620
+ * Remove the body event handler. See `_addBodyHandler`.
5621
+ * @function
5622
+ * @private
5623
+ */
5624
+
5625
+ }, {
5626
+ key: "_removeBodyHandler",
5627
+ value: function _removeBodyHandler() {
5628
+ $(document.body).off('click.zf.dropdownMenu tap.zf.dropdownMenu');
5629
+ }
5320
5630
  /**
5321
5631
  * Opens a dropdown pane, and checks for collisions first.
5322
5632
  * @param {jQuery} $sub - ul element that is a submenu to show
5323
5633
  * @function
5324
5634
  * @private
5325
- * @fires Dropdownmenu#show
5635
+ * @fires DropdownMenu#show
5326
5636
  */
5327
5637
 
5328
5638
  }, {
@@ -5358,17 +5668,18 @@ function (_Plugin) {
5358
5668
  }
5359
5669
  /**
5360
5670
  * Fires when the new dropdown pane is visible.
5361
- * @event Dropdownmenu#show
5671
+ * @event DropdownMenu#show
5362
5672
  */
5363
5673
 
5364
5674
 
5365
- this.$element.trigger('show.zf.dropdownmenu', [$sub]);
5675
+ this.$element.trigger('show.zf.dropdownMenu', [$sub]);
5366
5676
  }
5367
5677
  /**
5368
5678
  * Hides a single, currently open dropdown pane, if passed a parameter, otherwise, hides everything.
5369
5679
  * @function
5370
5680
  * @param {jQuery} $elem - element with a submenu to hide
5371
5681
  * @param {Number} idx - index of the $tabs collection to hide
5682
+ * @fires DropdownMenu#hide
5372
5683
  * @private
5373
5684
  */
5374
5685
 
@@ -5390,7 +5701,8 @@ function (_Plugin) {
5390
5701
  var somethingToClose = $toClose.hasClass('is-active') || $toClose.find('.is-active').length > 0;
5391
5702
 
5392
5703
  if (somethingToClose) {
5393
- $toClose.find('li.is-active').add($toClose).attr({
5704
+ var $activeItem = $toClose.find('li.is-active');
5705
+ $activeItem.add($toClose).attr({
5394
5706
  'data-is-click': false
5395
5707
  }).removeClass('is-active');
5396
5708
  $toClose.find('ul.js-dropdown-active').removeClass('js-dropdown-active');
@@ -5400,13 +5712,17 @@ function (_Plugin) {
5400
5712
  $toClose.find('li.is-dropdown-submenu-parent').add($toClose).removeClass("opens-inner opens-".concat(this.options.alignment)).addClass("opens-".concat(oldClass));
5401
5713
  this.changed = false;
5402
5714
  }
5715
+
5716
+ clearTimeout($activeItem.data('_delay'));
5717
+
5718
+ this._removeBodyHandler();
5403
5719
  /**
5404
5720
  * Fires when the open menus are closed.
5405
- * @event Dropdownmenu#hide
5721
+ * @event DropdownMenu#hide
5406
5722
  */
5407
5723
 
5408
5724
 
5409
- this.$element.trigger('hide.zf.dropdownmenu', [$toClose]);
5725
+ this.$element.trigger('hide.zf.dropdownMenu', [$toClose]);
5410
5726
  }
5411
5727
  }
5412
5728
  /**
@@ -5417,8 +5733,8 @@ function (_Plugin) {
5417
5733
  }, {
5418
5734
  key: "_destroy",
5419
5735
  value: function _destroy() {
5420
- this.$menuItems.off('.zf.dropdownmenu').removeAttr('data-is-click').removeClass('is-right-arrow is-left-arrow is-down-arrow opens-right opens-left opens-inner');
5421
- $(document.body).off('.zf.dropdownmenu');
5736
+ this.$menuItems.off('.zf.dropdownMenu').removeAttr('data-is-click').removeClass('is-right-arrow is-left-arrow is-down-arrow opens-right opens-left opens-inner');
5737
+ $(document.body).off('.zf.dropdownMenu');
5422
5738
  Nest.Burn(this.$element, 'dropdown');
5423
5739
  }
5424
5740
  }]);
@@ -5937,7 +6253,7 @@ function (_Plugin) {
5937
6253
  */
5938
6254
  value: function _setup(element, options) {
5939
6255
  this.$element = element;
5940
- this.options = $.extend({}, Interchange.defaults, options);
6256
+ this.options = $.extend({}, Interchange.defaults, this.$element.data(), options);
5941
6257
  this.rules = [];
5942
6258
  this.currentPath = '';
5943
6259
  this.className = 'Interchange'; // ie9 back compat
@@ -5963,6 +6279,8 @@ function (_Plugin) {
5963
6279
  'id': id
5964
6280
  });
5965
6281
 
6282
+ this._parseOptions();
6283
+
5966
6284
  this._addBreakpoints();
5967
6285
 
5968
6286
  this._generateRules();
@@ -5978,10 +6296,10 @@ function (_Plugin) {
5978
6296
  }, {
5979
6297
  key: "_events",
5980
6298
  value: function _events() {
5981
- var _this2 = this;
6299
+ var _this = this;
5982
6300
 
5983
6301
  this.$element.off('resizeme.zf.trigger').on('resizeme.zf.trigger', function () {
5984
- return _this2._reflow();
6302
+ return _this._reflow();
5985
6303
  });
5986
6304
  }
5987
6305
  /**
@@ -6009,6 +6327,22 @@ function (_Plugin) {
6009
6327
  this.replace(match.path);
6010
6328
  }
6011
6329
  }
6330
+ /**
6331
+ * Check options valifity and set defaults for:
6332
+ * - `data-interchange-type`: if set, enforce the type of replacement (auto, src, background or html)
6333
+ * @function
6334
+ * @private
6335
+ */
6336
+
6337
+ }, {
6338
+ key: "_parseOptions",
6339
+ value: function _parseOptions() {
6340
+ var types = ['auto', 'src', 'background', 'html'];
6341
+ if (typeof this.options.type === 'undefined') this.options.type = 'auto';else if (types.indexOf(this.options.type) === -1) {
6342
+ console.log("Warning: invalid value \"".concat(this.options.type, "\" for Interchange option \"type\""));
6343
+ this.options.type = 'auto';
6344
+ }
6345
+ }
6012
6346
  /**
6013
6347
  * Gets the Foundation breakpoints and adds them to the Interchange.SPECIAL_QUERIES object.
6014
6348
  * @function
@@ -6076,29 +6410,34 @@ function (_Plugin) {
6076
6410
  }, {
6077
6411
  key: "replace",
6078
6412
  value: function replace(path) {
6413
+ var _this2 = this;
6414
+
6079
6415
  if (this.currentPath === path) return;
6416
+ var trigger = 'replaced.zf.interchange';
6417
+ var type = this.options.type;
6080
6418
 
6081
- var _this = this,
6082
- trigger = 'replaced.zf.interchange'; // Replacing images
6419
+ if (type === 'auto') {
6420
+ if (this.$element[0].nodeName === 'IMG') type = 'src';else if (path.match(/\.(gif|jpe?g|png|svg|tiff)([?#].*)?/i)) type = 'background';else type = 'html';
6421
+ } // Replacing images
6083
6422
 
6084
6423
 
6085
- if (this.$element[0].nodeName === 'IMG') {
6424
+ if (type === 'src') {
6086
6425
  this.$element.attr('src', path).on('load', function () {
6087
- _this.currentPath = path;
6426
+ _this2.currentPath = path;
6088
6427
  }).trigger(trigger);
6089
6428
  } // Replacing background images
6090
- else if (path.match(/\.(gif|jpg|jpeg|png|svg|tiff)([?#].*)?/i)) {
6429
+ else if (type === 'background') {
6091
6430
  path = path.replace(/\(/g, '%28').replace(/\)/g, '%29');
6092
6431
  this.$element.css({
6093
6432
  'background-image': 'url(' + path + ')'
6094
6433
  }).trigger(trigger);
6095
6434
  } // Replacing HTML
6096
- else {
6435
+ else if (type === 'html') {
6097
6436
  $.get(path, function (response) {
6098
- _this.$element.html(response).trigger(trigger);
6437
+ _this2.$element.html(response).trigger(trigger);
6099
6438
 
6100
6439
  $(response).foundation();
6101
- _this.currentPath = path;
6440
+ _this2.currentPath = path;
6102
6441
  });
6103
6442
  }
6104
6443
  /**
@@ -6134,7 +6473,19 @@ Interchange.defaults = {
6134
6473
  * @type {?array}
6135
6474
  * @default null
6136
6475
  */
6137
- rules: null
6476
+ rules: null,
6477
+
6478
+ /**
6479
+ * Type of the responsive ressource to replace. It can take the following options:
6480
+ * - `auto` (default): choose the type according to the element tag or the ressource extension,
6481
+ * - `src`: replace the `[src]` attribute, recommended for images `<img>`.
6482
+ * - `background`: replace the `background-image` CSS property.
6483
+ * - `html`: replace the element content.
6484
+ * @option
6485
+ * @type {string}
6486
+ * @default 'auto'
6487
+ */
6488
+ type: 'auto'
6138
6489
  };
6139
6490
  Interchange.SPECIAL_QUERIES = {
6140
6491
  'landscape': 'screen and (orientation: landscape)',
@@ -6144,7 +6495,7 @@ Interchange.SPECIAL_QUERIES = {
6144
6495
 
6145
6496
  /**
6146
6497
  * SmoothScroll module.
6147
- * @module foundation.smooth-scroll
6498
+ * @module foundation.smoothScroll
6148
6499
  */
6149
6500
 
6150
6501
  var SmoothScroll =
@@ -6309,6 +6660,7 @@ SmoothScroll.defaults = {
6309
6660
  * Magellan module.
6310
6661
  * @module foundation.magellan
6311
6662
  * @requires foundation.smoothScroll
6663
+ * @requires foundation.util.triggers
6312
6664
  */
6313
6665
 
6314
6666
  var Magellan =
@@ -6337,6 +6689,9 @@ function (_Plugin) {
6337
6689
  this.$element = element;
6338
6690
  this.options = $.extend({}, Magellan.defaults, this.$element.data(), options);
6339
6691
  this.className = 'Magellan'; // ie9 back compat
6692
+ // Triggers init is idempotent, just need to make sure it is initialized
6693
+
6694
+ Triggers.init($);
6340
6695
 
6341
6696
  this._init();
6342
6697
 
@@ -6526,7 +6881,12 @@ function (_Plugin) {
6526
6881
  if (window.history.pushState) {
6527
6882
  // Set or remove the hash (see: https://stackoverflow.com/a/5298684/4317384
6528
6883
  var url = activeHash ? activeHash : window.location.pathname + window.location.search;
6529
- window.history.pushState(null, null, url);
6884
+
6885
+ if (this.options.updateHistory) {
6886
+ window.history.pushState({}, '', url);
6887
+ } else {
6888
+ window.history.replaceState({}, '', url);
6889
+ }
6530
6890
  } else {
6531
6891
  window.location.hash = activeHash;
6532
6892
  }
@@ -6609,6 +6969,14 @@ Magellan.defaults = {
6609
6969
  */
6610
6970
  deepLinking: false,
6611
6971
 
6972
+ /**
6973
+ * Update the browser history with the active link, if deep linking is enabled.
6974
+ * @option
6975
+ * @type {boolean}
6976
+ * @default false
6977
+ */
6978
+ updateHistory: false,
6979
+
6612
6980
  /**
6613
6981
  * Number of pixels to offset the scroll of the page on item click if using a sticky nav bar.
6614
6982
  * @option
@@ -6620,7 +6988,7 @@ Magellan.defaults = {
6620
6988
 
6621
6989
  /**
6622
6990
  * OffCanvas module.
6623
- * @module foundation.offcanvas
6991
+ * @module foundation.offCanvas
6624
6992
  * @requires foundation.util.keyboard
6625
6993
  * @requires foundation.util.mediaQuery
6626
6994
  * @requires foundation.util.triggers
@@ -6663,7 +7031,9 @@ function (_Plugin) {
6663
7031
  this.$triggers = $();
6664
7032
  this.position = 'left';
6665
7033
  this.$content = $();
6666
- this.nested = !!this.options.nested; // Defines the CSS transition/position classes of the off-canvas content container.
7034
+ this.nested = !!this.options.nested;
7035
+ this.$sticky = $();
7036
+ this.isInCanvas = false; // Defines the CSS transition/position classes of the off-canvas content container.
6667
7037
 
6668
7038
  $(['push', 'overlap']).each(function (index, val) {
6669
7039
  _this2.contentClasses.base.push('has-transition-' + val);
@@ -6759,6 +7129,29 @@ function (_Plugin) {
6759
7129
 
6760
7130
  if (this.options.transitionTime) {
6761
7131
  this.$element.css('transition-duration', this.options.transitionTime);
7132
+ } // Find fixed elements that should stay fixed while off-canvas is opened
7133
+
7134
+
7135
+ this.$sticky = this.$content.find('[data-off-canvas-sticky]');
7136
+
7137
+ if (this.$sticky.length > 0 && this.options.transition === 'push') {
7138
+ // If there's at least one match force contentScroll:false because the absolute top value doesn't get recalculated on scroll
7139
+ // Limit to push transition since there's no transform scope for overlap
7140
+ this.options.contentScroll = false;
7141
+ }
7142
+
7143
+ var inCanvasFor = this.$element.attr('class').match(/\bin-canvas-for-(\w+)/);
7144
+
7145
+ if (inCanvasFor && inCanvasFor.length === 2) {
7146
+ // Set `inCanvasOn` option if found in-canvas-for-[BREAKPONT] CSS class
7147
+ this.options.inCanvasOn = inCanvasFor[1];
7148
+ } else if (this.options.inCanvasOn) {
7149
+ // Ensure the CSS class is set
7150
+ this.$element.addClass("in-canvas-for-".concat(this.options.inCanvasOn));
7151
+ }
7152
+
7153
+ if (this.options.inCanvasOn) {
7154
+ this._checkInCanvas();
6762
7155
  } // Initally remove all transition/position CSS classes from off-canvas content container.
6763
7156
 
6764
7157
 
@@ -6773,17 +7166,25 @@ function (_Plugin) {
6773
7166
  }, {
6774
7167
  key: "_events",
6775
7168
  value: function _events() {
6776
- this.$element.off('.zf.trigger .zf.offcanvas').on({
7169
+ var _this3 = this;
7170
+
7171
+ this.$element.off('.zf.trigger .zf.offCanvas').on({
6777
7172
  'open.zf.trigger': this.open.bind(this),
6778
7173
  'close.zf.trigger': this.close.bind(this),
6779
7174
  'toggle.zf.trigger': this.toggle.bind(this),
6780
- 'keydown.zf.offcanvas': this._handleKeyboard.bind(this)
7175
+ 'keydown.zf.offCanvas': this._handleKeyboard.bind(this)
6781
7176
  });
6782
7177
 
6783
7178
  if (this.options.closeOnClick === true) {
6784
7179
  var $target = this.options.contentOverlay ? this.$overlay : this.$content;
6785
7180
  $target.on({
6786
- 'click.zf.offcanvas': this.close.bind(this)
7181
+ 'click.zf.offCanvas': this.close.bind(this)
7182
+ });
7183
+ }
7184
+
7185
+ if (this.options.inCanvasOn) {
7186
+ $(window).on('changed.zf.mediaquery', function () {
7187
+ _this3._checkInCanvas();
6787
7188
  });
6788
7189
  }
6789
7190
  }
@@ -6810,6 +7211,20 @@ function (_Plugin) {
6810
7211
  }
6811
7212
  });
6812
7213
  }
7214
+ /**
7215
+ * Checks if InCanvas on current breakpoint and adjust off-canvas accordingly
7216
+ * @private
7217
+ */
7218
+
7219
+ }, {
7220
+ key: "_checkInCanvas",
7221
+ value: function _checkInCanvas() {
7222
+ this.isInCanvas = MediaQuery.atLeast(this.options.inCanvasOn);
7223
+
7224
+ if (this.isInCanvas === true) {
7225
+ this.close();
7226
+ }
7227
+ }
6813
7228
  /**
6814
7229
  * Removes the CSS transition/position classes of the off-canvas content container.
6815
7230
  * Removing the classes is important when another off-canvas gets opened that uses the same content container.
@@ -6844,6 +7259,57 @@ function (_Plugin) {
6844
7259
  this.$content.addClass("has-reveal-".concat(this.position));
6845
7260
  }
6846
7261
  }
7262
+ /**
7263
+ * Preserves the fixed behavior of sticky elements on opening an off-canvas with push transition.
7264
+ * Since the off-canvas container has got a transform scope in such a case, it is done by calculating position absolute values.
7265
+ * @private
7266
+ */
7267
+
7268
+ }, {
7269
+ key: "_fixStickyElements",
7270
+ value: function _fixStickyElements() {
7271
+ this.$sticky.each(function (_, el) {
7272
+ var $el = $(el); // If sticky element is currently fixed, adjust its top value to match absolute position due to transform scope
7273
+ // Limit to push transition because postion:fixed works without problems for overlap (no transform scope)
7274
+
7275
+ if ($el.css('position') === 'fixed') {
7276
+ // Save current inline styling to restore it if undoing the absolute fixing
7277
+ var topVal = parseInt($el.css('top'), 10);
7278
+ $el.data('offCanvasSticky', {
7279
+ top: topVal
7280
+ });
7281
+ var absoluteTopVal = $(document).scrollTop() + topVal;
7282
+ $el.css({
7283
+ top: "".concat(absoluteTopVal, "px"),
7284
+ width: '100%',
7285
+ transition: 'none'
7286
+ });
7287
+ }
7288
+ });
7289
+ }
7290
+ /**
7291
+ * Restores the original fixed styling of sticky elements after having closed an off-canvas that got pseudo fixed beforehand.
7292
+ * This reverts the changes of _fixStickyElements()
7293
+ * @private
7294
+ */
7295
+
7296
+ }, {
7297
+ key: "_unfixStickyElements",
7298
+ value: function _unfixStickyElements() {
7299
+ this.$sticky.each(function (_, el) {
7300
+ var $el = $(el);
7301
+ var stickyData = $el.data('offCanvasSticky'); // If sticky element has got data object with prior values (meaning it was originally fixed) restore these values once off-canvas is closed
7302
+
7303
+ if (_typeof(stickyData) === 'object') {
7304
+ $el.css({
7305
+ top: "".concat(stickyData.top, "px"),
7306
+ width: '',
7307
+ transition: ''
7308
+ });
7309
+ $el.data('offCanvasSticky', '');
7310
+ }
7311
+ });
7312
+ }
6847
7313
  /**
6848
7314
  * Handles the revealing/hiding the off-canvas at breakpoints, not the same as open.
6849
7315
  * @param {Boolean} isRevealed - true if element should be revealed.
@@ -6872,7 +7338,8 @@ function (_Plugin) {
6872
7338
  this._addContentClasses(isRevealed);
6873
7339
  }
6874
7340
  /**
6875
- * Stops scrolling of the body when offcanvas is open on mobile Safari and other troublesome browsers.
7341
+ * Stops scrolling of the body when OffCanvas is open on mobile Safari and other troublesome browsers.
7342
+ * @function
6876
7343
  * @private
6877
7344
  */
6878
7345
 
@@ -6880,8 +7347,17 @@ function (_Plugin) {
6880
7347
  key: "_stopScrolling",
6881
7348
  value: function _stopScrolling(event) {
6882
7349
  return false;
6883
- } // Taken and adapted from http://stackoverflow.com/questions/16889447/prevent-full-page-scrolling-ios
6884
- // Only really works for y, not sure how to extend to x or if we need to.
7350
+ }
7351
+ /**
7352
+ * Tag the element given as context whether it can be scrolled up and down.
7353
+ * Used to allow or prevent it to scroll. See `_stopScrollPropagation`.
7354
+ *
7355
+ * Taken and adapted from http://stackoverflow.com/questions/16889447/prevent-full-page-scrolling-ios
7356
+ * Only really works for y, not sure how to extend to x or if we need to.
7357
+ *
7358
+ * @function
7359
+ * @private
7360
+ */
6885
7361
 
6886
7362
  }, {
6887
7363
  key: "_recordScrollable",
@@ -6905,17 +7381,40 @@ function (_Plugin) {
6905
7381
  elem.allowDown = elem.scrollTop < elem.scrollHeight - elem.clientHeight;
6906
7382
  elem.lastY = event.originalEvent.pageY;
6907
7383
  }
7384
+ /**
7385
+ * Prevent the given event propagation if the element given as context can scroll.
7386
+ * Used to preserve the element scrolling on mobile (`touchmove`) when the document
7387
+ * scrolling is prevented. See https://git.io/zf-9707.
7388
+ * @function
7389
+ * @private
7390
+ */
7391
+
6908
7392
  }, {
6909
7393
  key: "_stopScrollPropagation",
6910
7394
  value: function _stopScrollPropagation(event) {
6911
7395
  var elem = this; // called from event handler context with this as elem
6912
7396
 
7397
+ var parent; // off-canvas elem if called from inner scrollbox
7398
+
6913
7399
  var up = event.pageY < elem.lastY;
6914
7400
  var down = !up;
6915
7401
  elem.lastY = event.pageY;
6916
7402
 
6917
7403
  if (up && elem.allowUp || down && elem.allowDown) {
6918
- event.stopPropagation();
7404
+ // It is not recommended to stop event propagation (the user cannot watch it),
7405
+ // but in this case this is the only solution we have.
7406
+ event.stopPropagation(); // If elem is inner scrollbox we are scrolling the outer off-canvas down/up once the box end has been reached
7407
+ // This lets the user continue to touch move the off-canvas without the need to place the finger outside the scrollbox
7408
+
7409
+ if (elem.hasAttribute('data-off-canvas-scrollbox')) {
7410
+ parent = elem.closest('[data-off-canvas], [data-off-canvas-scrollbox-outer]');
7411
+
7412
+ if (elem.scrollTop <= 1 && parent.scrollTop > 0) {
7413
+ parent.scrollTop--;
7414
+ } else if (elem.scrollTop >= elem.scrollHeight - elem.clientHeight - 1 && parent.scrollTop < parent.scrollHeight - parent.clientHeight) {
7415
+ parent.scrollTop++;
7416
+ }
7417
+ }
6919
7418
  } else {
6920
7419
  event.preventDefault();
6921
7420
  }
@@ -6925,14 +7424,16 @@ function (_Plugin) {
6925
7424
  * @function
6926
7425
  * @param {Object} event - Event object passed from listener.
6927
7426
  * @param {jQuery} trigger - element that triggered the off-canvas to open.
6928
- * @fires Offcanvas#opened
7427
+ * @fires OffCanvas#opened
6929
7428
  * @todo also trigger 'open' event?
6930
7429
  */
6931
7430
 
6932
7431
  }, {
6933
7432
  key: "open",
6934
7433
  value: function open(event, trigger) {
6935
- if (this.$element.hasClass('is-open') || this.isRevealed) {
7434
+ var _this4 = this;
7435
+
7436
+ if (this.$element.hasClass('is-open') || this.isRevealed || this.isInCanvas) {
6936
7437
  return;
6937
7438
  }
6938
7439
 
@@ -6963,6 +7464,8 @@ function (_Plugin) {
6963
7464
  $('body').addClass('is-off-canvas-open').on('touchmove', this._stopScrolling);
6964
7465
  this.$element.on('touchstart', this._recordScrollable);
6965
7466
  this.$element.on('touchmove', this._stopScrollPropagation);
7467
+ this.$element.on('touchstart', '[data-off-canvas-scrollbox]', this._recordScrollable);
7468
+ this.$element.on('touchmove', '[data-off-canvas-scrollbox]', this._stopScrollPropagation);
6966
7469
  }
6967
7470
 
6968
7471
  if (this.options.contentOverlay === true) {
@@ -6994,45 +7497,54 @@ function (_Plugin) {
6994
7497
  Keyboard.trapFocus(this.$element);
6995
7498
  }
6996
7499
 
7500
+ if (this.options.transition === 'push') {
7501
+ this._fixStickyElements();
7502
+ }
7503
+
6997
7504
  this._addContentClasses();
6998
7505
  /**
6999
7506
  * Fires when the off-canvas menu opens.
7000
- * @event Offcanvas#opened
7507
+ * @event OffCanvas#opened
7001
7508
  */
7002
7509
 
7003
7510
 
7004
- this.$element.trigger('opened.zf.offcanvas');
7511
+ this.$element.trigger('opened.zf.offCanvas');
7512
+ /**
7513
+ * Fires when the off-canvas menu open transition is done.
7514
+ * @event OffCanvas#openedEnd
7515
+ */
7516
+
7517
+ this.$element.one(transitionend(this.$element), function () {
7518
+ _this4.$element.trigger('openedEnd.zf.offCanvas');
7519
+ });
7005
7520
  }
7006
7521
  /**
7007
7522
  * Closes the off-canvas menu.
7008
7523
  * @function
7009
7524
  * @param {Function} cb - optional cb to fire after closure.
7010
- * @fires Offcanvas#closed
7525
+ * @fires OffCanvas#close
7526
+ * @fires OffCanvas#closed
7011
7527
  */
7012
7528
 
7013
7529
  }, {
7014
7530
  key: "close",
7015
7531
  value: function close(cb) {
7532
+ var _this5 = this;
7533
+
7016
7534
  if (!this.$element.hasClass('is-open') || this.isRevealed) {
7017
7535
  return;
7018
7536
  }
7019
-
7020
- var _this = this;
7021
-
7022
- this.$element.removeClass('is-open');
7023
- this.$element.attr('aria-hidden', 'true')
7024
7537
  /**
7025
- * Fires when the off-canvas menu opens.
7026
- * @event Offcanvas#closed
7538
+ * Fires when the off-canvas menu closes.
7539
+ * @event OffCanvas#close
7027
7540
  */
7028
- .trigger('closed.zf.offcanvas');
7029
- this.$content.removeClass('is-open-left is-open-top is-open-right is-open-bottom'); // If `contentScroll` is set to false, remove class and re-enable scrolling on touch devices.
7030
7541
 
7031
- if (this.options.contentScroll === false) {
7032
- $('body').removeClass('is-off-canvas-open').off('touchmove', this._stopScrolling);
7033
- this.$element.off('touchstart', this._recordScrollable);
7034
- this.$element.off('touchmove', this._stopScrollPropagation);
7035
- }
7542
+
7543
+ this.$element.trigger('close.zf.offCanvas');
7544
+
7545
+ this.$element.removeClass('is-open');
7546
+ this.$element.attr('aria-hidden', 'true');
7547
+ this.$content.removeClass('is-open-left is-open-top is-open-right is-open-bottom');
7036
7548
 
7037
7549
  if (this.options.contentOverlay === true) {
7038
7550
  this.$overlay.removeClass('is-visible');
@@ -7042,18 +7554,42 @@ function (_Plugin) {
7042
7554
  this.$overlay.removeClass('is-closable');
7043
7555
  }
7044
7556
 
7045
- this.$triggers.attr('aria-expanded', 'false');
7557
+ this.$triggers.attr('aria-expanded', 'false'); // Listen to transitionEnd: add class, re-enable scrolling and release focus when done.
7046
7558
 
7047
- if (this.options.trapFocus === true) {
7048
- this.$content.removeAttr('tabindex');
7049
- Keyboard.releaseFocus(this.$element);
7050
- } // Listen to transitionEnd and add class when done.
7559
+ this.$element.one(transitionend(this.$element), function (e) {
7560
+ _this5.$element.addClass('is-closed');
7051
7561
 
7562
+ _this5._removeContentClasses();
7052
7563
 
7053
- this.$element.one(transitionend(this.$element), function (e) {
7054
- _this.$element.addClass('is-closed');
7564
+ if (_this5.options.transition === 'push') {
7565
+ _this5._unfixStickyElements();
7566
+ } // If `contentScroll` is set to false, remove class and re-enable scrolling on touch devices.
7567
+
7568
+
7569
+ if (_this5.options.contentScroll === false) {
7570
+ $('body').removeClass('is-off-canvas-open').off('touchmove', _this5._stopScrolling);
7571
+
7572
+ _this5.$element.off('touchstart', _this5._recordScrollable);
7573
+
7574
+ _this5.$element.off('touchmove', _this5._stopScrollPropagation);
7575
+
7576
+ _this5.$element.off('touchstart', '[data-off-canvas-scrollbox]', _this5._recordScrollable);
7577
+
7578
+ _this5.$element.off('touchmove', '[data-off-canvas-scrollbox]', _this5._stopScrollPropagation);
7579
+ }
7580
+
7581
+ if (_this5.options.trapFocus === true) {
7582
+ _this5.$content.removeAttr('tabindex');
7583
+
7584
+ Keyboard.releaseFocus(_this5.$element);
7585
+ }
7586
+ /**
7587
+ * Fires when the off-canvas menu close transition is done.
7588
+ * @event OffCanvas#closed
7589
+ */
7055
7590
 
7056
- _this._removeContentClasses();
7591
+
7592
+ _this5.$element.trigger('closed.zf.offCanvas');
7057
7593
  });
7058
7594
  }
7059
7595
  /**
@@ -7081,24 +7617,23 @@ function (_Plugin) {
7081
7617
  }, {
7082
7618
  key: "_handleKeyboard",
7083
7619
  value: function _handleKeyboard(e) {
7084
- var _this3 = this;
7620
+ var _this6 = this;
7085
7621
 
7086
7622
  Keyboard.handleKey(e, 'OffCanvas', {
7087
7623
  close: function close() {
7088
- _this3.close();
7624
+ _this6.close();
7089
7625
 
7090
- _this3.$lastTrigger.focus();
7626
+ _this6.$lastTrigger.focus();
7091
7627
 
7092
7628
  return true;
7093
7629
  },
7094
7630
  handled: function handled() {
7095
- e.stopPropagation();
7096
7631
  e.preventDefault();
7097
7632
  }
7098
7633
  });
7099
7634
  }
7100
7635
  /**
7101
- * Destroys the offcanvas plugin.
7636
+ * Destroys the OffCanvas plugin.
7102
7637
  * @function
7103
7638
  */
7104
7639
 
@@ -7106,8 +7641,8 @@ function (_Plugin) {
7106
7641
  key: "_destroy",
7107
7642
  value: function _destroy() {
7108
7643
  this.close();
7109
- this.$element.off('.zf.trigger .zf.offcanvas');
7110
- this.$overlay.off('.zf.offcanvas');
7644
+ this.$element.off('.zf.trigger .zf.offCanvas');
7645
+ this.$overlay.off('.zf.offCanvas');
7111
7646
  if (this.onLoadListener) $(window).off(this.onLoadListener);
7112
7647
  }
7113
7648
  }]);
@@ -7157,15 +7692,15 @@ OffCanvas.defaults = {
7157
7692
  contentScroll: true,
7158
7693
 
7159
7694
  /**
7160
- * Amount of time in ms the open and close transition requires. If none selected, pulls from body style.
7695
+ * Amount of time the open and close transition requires, including the appropriate milliseconds (`ms`) or seconds (`s`) unit (e.g. `500ms`, `.75s`) If none selected, pulls from body style.
7161
7696
  * @option
7162
- * @type {number}
7697
+ * @type {string}
7163
7698
  * @default null
7164
7699
  */
7165
7700
  transitionTime: null,
7166
7701
 
7167
7702
  /**
7168
- * Type of transition for the offcanvas menu. Options are 'push', 'detached' or 'slide'.
7703
+ * Type of transition for the OffCanvas menu. Options are 'push', 'detached' or 'slide'.
7169
7704
  * @option
7170
7705
  * @type {string}
7171
7706
  * @default push
@@ -7181,7 +7716,7 @@ OffCanvas.defaults = {
7181
7716
  forceTo: null,
7182
7717
 
7183
7718
  /**
7184
- * Allow the offcanvas to remain open for certain breakpoints.
7719
+ * Allow the OffCanvas to remain open for certain breakpoints.
7185
7720
  * @option
7186
7721
  * @type {boolean}
7187
7722
  * @default false
@@ -7196,6 +7731,14 @@ OffCanvas.defaults = {
7196
7731
  */
7197
7732
  revealOn: null,
7198
7733
 
7734
+ /**
7735
+ * Breakpoint at which the off-canvas gets moved into canvas content and acts as regular page element.
7736
+ * @option
7737
+ * @type {?string}
7738
+ * @default null
7739
+ */
7740
+ inCanvasOn: null,
7741
+
7199
7742
  /**
7200
7743
  * Force focus to the offcanvas on open. If true, will focus the opening trigger on close.
7201
7744
  * @option
@@ -7205,7 +7748,7 @@ OffCanvas.defaults = {
7205
7748
  autoFocus: true,
7206
7749
 
7207
7750
  /**
7208
- * Class used to force an offcanvas to remain open. Foundation defaults for this are `reveal-for-large` & `reveal-for-medium`.
7751
+ * Class used to force an OffCanvas to remain open. Foundation defaults for this are `reveal-for-large` & `reveal-for-medium`.
7209
7752
  * @option
7210
7753
  * @type {string}
7211
7754
  * @default reveal-for-
@@ -7214,7 +7757,7 @@ OffCanvas.defaults = {
7214
7757
  revealClass: 'reveal-for-',
7215
7758
 
7216
7759
  /**
7217
- * Triggers optional focus trapping when opening an offcanvas. Sets tabindex of [data-off-canvas-content] to -1 for accessibility purposes.
7760
+ * Triggers optional focus trapping when opening an OffCanvas. Sets tabindex of [data-off-canvas-content] to -1 for accessibility purposes.
7218
7761
  * @option
7219
7762
  * @type {boolean}
7220
7763
  * @default false
@@ -7638,6 +8181,9 @@ function (_Plugin) {
7638
8181
  }
7639
8182
  /**
7640
8183
  * Updates the active state of the bullets, if displayed.
8184
+ * Move the descriptor of the current slide `[data-slide-active-label]` to the newly active bullet.
8185
+ * If no `[data-slide-active-label]` is set, will move the exceeding `span` element.
8186
+ *
7641
8187
  * @function
7642
8188
  * @private
7643
8189
  * @param {Number} idx - the index of the current slide.
@@ -7646,9 +8192,33 @@ function (_Plugin) {
7646
8192
  }, {
7647
8193
  key: "_updateBullets",
7648
8194
  value: function _updateBullets(idx) {
7649
- var $oldBullet = this.$element.find(".".concat(this.options.boxOfBullets)).find('.is-active').removeClass('is-active').blur(),
7650
- span = $oldBullet.find('span:last').detach(),
7651
- $newBullet = this.$bullets.eq(idx).addClass('is-active').append(span);
8195
+ var $oldBullet = this.$bullets.filter('.is-active');
8196
+ var $othersBullets = this.$bullets.not('.is-active');
8197
+ var $newBullet = this.$bullets.eq(idx);
8198
+ $oldBullet.removeClass('is-active').blur();
8199
+ $newBullet.addClass('is-active'); // Find the descriptor for the current slide to move it to the new slide button
8200
+
8201
+ var activeStateDescriptor = $oldBullet.children('[data-slide-active-label]').last(); // If not explicitely given, search for the last "exceeding" span element (compared to others bullets).
8202
+
8203
+ if (!activeStateDescriptor.length) {
8204
+ var spans = $oldBullet.children('span');
8205
+ var spanCountInOthersBullets = $othersBullets.toArray().map(function (b) {
8206
+ return $(b).children('span').length;
8207
+ }); // If there is an exceeding span element, use it as current slide descriptor
8208
+
8209
+ if (spanCountInOthersBullets.every(function (count) {
8210
+ return count < spans.length;
8211
+ })) {
8212
+ activeStateDescriptor = spans.last();
8213
+ activeStateDescriptor.attr('data-slide-active-label', '');
8214
+ }
8215
+ } // Move the current slide descriptor to the new slide button
8216
+
8217
+
8218
+ if (activeStateDescriptor.length) {
8219
+ activeStateDescriptor.detach();
8220
+ $newBullet.append(activeStateDescriptor);
8221
+ }
7652
8222
  }
7653
8223
  /**
7654
8224
  * Destroys the carousel and hides the element.
@@ -8143,6 +8713,7 @@ ResponsiveToggle.defaults = {
8143
8713
  * Reveal module.
8144
8714
  * @module foundation.reveal
8145
8715
  * @requires foundation.util.keyboard
8716
+ * @requires foundation.util.touch
8146
8717
  * @requires foundation.util.triggers
8147
8718
  * @requires foundation.util.mediaQuery
8148
8719
  * @requires foundation.util.motion if using animations
@@ -8174,9 +8745,10 @@ function (_Plugin) {
8174
8745
  this.options = $.extend({}, Reveal.defaults, this.$element.data(), options);
8175
8746
  this.className = 'Reveal'; // ie9 back compat
8176
8747
 
8177
- this._init(); // Triggers init is idempotent, just need to make sure it is initialized
8748
+ this._init(); // Touch and Triggers init are idempotent, just need to make sure they are initialized
8178
8749
 
8179
8750
 
8751
+ Touch.init($);
8180
8752
  Triggers.init($);
8181
8753
  Keyboard.register('Reveal', {
8182
8754
  'ESCAPE': 'close'
@@ -8329,7 +8901,7 @@ function (_Plugin) {
8329
8901
  });
8330
8902
 
8331
8903
  if (this.options.closeOnClick && this.options.overlay) {
8332
- this.$overlay.off('.zf.reveal').on('click.zf.reveal', function (e) {
8904
+ this.$overlay.off('.zf.reveal').on('click.zf.dropdown tap.zf.dropdown', function (e) {
8333
8905
  if (e.target === _this.$element[0] || $.contains(_this.$element[0], e.target) || !$.contains(document, e.target)) {
8334
8906
  return;
8335
8907
  }
@@ -8453,7 +9025,9 @@ function (_Plugin) {
8453
9025
  this.$element.trigger('closeme.zf.reveal', this.id);
8454
9026
  }
8455
9027
 
8456
- this._disableScroll();
9028
+ if ($('.reveal:visible').length === 0) {
9029
+ this._disableScroll();
9030
+ }
8457
9031
 
8458
9032
  var _this = this; // Motion UI method of reveal
8459
9033
 
@@ -8563,7 +9137,7 @@ function (_Plugin) {
8563
9137
  this.focusableElements = Keyboard.findFocusable(this.$element);
8564
9138
 
8565
9139
  if (!this.options.overlay && this.options.closeOnClick && !this.options.fullScreen) {
8566
- $('body').on('click.zf.reveal', function (e) {
9140
+ $('body').on('click.zf.dropdown tap.zf.dropdown', function (e) {
8567
9141
  if (e.target === _this.$element[0] || $.contains(_this.$element[0], e.target) || !$.contains(document, e.target)) {
8568
9142
  return;
8569
9143
  }
@@ -8623,7 +9197,7 @@ function (_Plugin) {
8623
9197
  }
8624
9198
 
8625
9199
  if (!this.options.overlay && this.options.closeOnClick) {
8626
- $('body').off('click.zf.reveal');
9200
+ $('body').off('click.zf.dropdown tap.zf.dropdown');
8627
9201
  }
8628
9202
 
8629
9203
  this.$element.off('keydown.zf.reveal');
@@ -8643,7 +9217,9 @@ function (_Plugin) {
8643
9217
 
8644
9218
  _this.$element.attr('aria-hidden', true);
8645
9219
 
8646
- _this._enableScroll(scrollTop);
9220
+ if ($('.reveal:visible').length === 0) {
9221
+ _this._enableScroll(scrollTop);
9222
+ }
8647
9223
  /**
8648
9224
  * Fires when the modal is done closing.
8649
9225
  * @event Reveal#closed
@@ -8966,11 +9542,11 @@ function (_Plugin) {
8966
9542
  var _this2 = this;
8967
9543
 
8968
9544
  if (this.handles[1]) {
8969
- this._setHandlePos(this.$handle, this.inputs.eq(0).val(), true, function () {
8970
- _this2._setHandlePos(_this2.$handle2, _this2.inputs.eq(1).val(), true);
9545
+ this._setHandlePos(this.$handle, this.inputs.eq(0).val(), function () {
9546
+ _this2._setHandlePos(_this2.$handle2, _this2.inputs.eq(1).val());
8971
9547
  });
8972
9548
  } else {
8973
- this._setHandlePos(this.$handle, this.inputs.eq(0).val(), true);
9549
+ this._setHandlePos(this.$handle, this.inputs.eq(0).val());
8974
9550
  }
8975
9551
  }
8976
9552
  }, {
@@ -9020,7 +9596,16 @@ function (_Plugin) {
9020
9596
  break;
9021
9597
  }
9022
9598
 
9023
- var value = (this.options.end - this.options.start) * pctOfBar + parseFloat(this.options.start);
9599
+ var value;
9600
+
9601
+ if (this.options.vertical) {
9602
+ // linear interpolation which is working with negative values for start
9603
+ // https://math.stackexchange.com/a/1019084
9604
+ value = parseFloat(this.options.end) + pctOfBar * (this.options.start - this.options.end);
9605
+ } else {
9606
+ value = (this.options.end - this.options.start) * pctOfBar + parseFloat(this.options.start);
9607
+ }
9608
+
9024
9609
  return value;
9025
9610
  }
9026
9611
  /**
@@ -9058,7 +9643,7 @@ function (_Plugin) {
9058
9643
 
9059
9644
  }, {
9060
9645
  key: "_setHandlePos",
9061
- value: function _setHandlePos($hndl, location, noInvert, cb) {
9646
+ value: function _setHandlePos($hndl, location, cb) {
9062
9647
  // don't move if the slider has been disabled since its initialization
9063
9648
  if (this.$element.hasClass(this.options.disabledClass)) {
9064
9649
  return;
@@ -9074,12 +9659,7 @@ function (_Plugin) {
9074
9659
  location = this.options.end;
9075
9660
  }
9076
9661
 
9077
- var isDbl = this.options.doubleSided; //this is for single-handled vertical sliders, it adjusts the value to account for the slider being "upside-down"
9078
- //for click and drag events, it's weird due to the scale(-1, 1) css property
9079
-
9080
- if (this.options.vertical && !noInvert) {
9081
- location = this.options.end - location;
9082
- }
9662
+ var isDbl = this.options.doubleSided;
9083
9663
 
9084
9664
  if (isDbl) {
9085
9665
  //this block is to prevent 2 handles from crossing eachother. Could/should be improved.
@@ -9239,7 +9819,7 @@ function (_Plugin) {
9239
9819
  }, {
9240
9820
  key: "_handleEvent",
9241
9821
  value: function _handleEvent(e, $handle, val) {
9242
- var value, hasVal;
9822
+ var value;
9243
9823
 
9244
9824
  if (!val) {
9245
9825
  //click or drag events
@@ -9281,8 +9861,6 @@ function (_Plugin) {
9281
9861
 
9282
9862
  value = _this._adjustValue(null, value); //boolean flag for the setHandlePos fn, specifically for vertical sliders
9283
9863
 
9284
- hasVal = false;
9285
-
9286
9864
  if (!$handle) {
9287
9865
  //figure out which handle it is, pass it to the next function.
9288
9866
  var firstHndlPos = absPosition(this.$handle, direction, barXY, param),
@@ -9292,10 +9870,9 @@ function (_Plugin) {
9292
9870
  } else {
9293
9871
  //change event on input
9294
9872
  value = this._adjustValue(null, val);
9295
- hasVal = true;
9296
9873
  }
9297
9874
 
9298
- this._setHandlePos($handle, value, hasVal);
9875
+ this._setHandlePos($handle, value);
9299
9876
  }
9300
9877
  /**
9301
9878
  * Adjustes value for handle in regard to step value. returns adjusted value
@@ -9458,7 +10035,7 @@ function (_Plugin) {
9458
10035
  // only set handle pos when event was handled specially
9459
10036
  e.preventDefault();
9460
10037
 
9461
- _this._setHandlePos(_$handle, newValue, true);
10038
+ _this._setHandlePos(_$handle, newValue);
9462
10039
  }
9463
10040
  });
9464
10041
  /*if (newValue) { // if pressed key has special function, update value
@@ -10021,18 +10598,17 @@ function (_Plugin) {
10021
10598
 
10022
10599
  this.$element.css({
10023
10600
  'max-width': "".concat(newElemWidth - pdngl - pdngr, "px")
10024
- });
10025
- var newContainerHeight = this.$element[0].getBoundingClientRect().height || this.containerHeight;
10601
+ }); // Recalculate the height only if it is "dynamic"
10026
10602
 
10027
- if (this.$element.css("display") == "none") {
10028
- newContainerHeight = 0;
10603
+ if (this.options.dynamicHeight || !this.containerHeight) {
10604
+ // Get the sticked element height and apply it to the container to "hold the place"
10605
+ var newContainerHeight = this.$element[0].getBoundingClientRect().height || this.containerHeight;
10606
+ newContainerHeight = this.$element.css("display") == "none" ? 0 : newContainerHeight;
10607
+ this.$container.css('height', newContainerHeight);
10608
+ this.containerHeight = newContainerHeight;
10029
10609
  }
10030
10610
 
10031
- this.containerHeight = newContainerHeight;
10032
- this.$container.css({
10033
- height: newContainerHeight
10034
- });
10035
- this.elemHeight = newContainerHeight;
10611
+ this.elemHeight = this.containerHeight;
10036
10612
 
10037
10613
  if (!this.isStuck) {
10038
10614
  if (this.$element.hasClass('is-at-bottom')) {
@@ -10041,7 +10617,7 @@ function (_Plugin) {
10041
10617
  }
10042
10618
  }
10043
10619
 
10044
- this._setBreakPoints(newContainerHeight, function () {
10620
+ this._setBreakPoints(this.containerHeight, function () {
10045
10621
  if (cb && typeof cb === 'function') {
10046
10622
  cb();
10047
10623
  }
@@ -10208,6 +10784,14 @@ Sticky.defaults = {
10208
10784
  */
10209
10785
  containerClass: 'sticky-container',
10210
10786
 
10787
+ /**
10788
+ * If true (by default), keep the sticky container the same height as the element. Otherwise, the container height is set once and does not change.
10789
+ * @option
10790
+ * @type {boolean}
10791
+ * @default true
10792
+ */
10793
+ dynamicHeight: true,
10794
+
10211
10795
  /**
10212
10796
  * Number of scroll events between the plugin's recalculating sticky points. Setting it to `0` will cause it to recalc every scroll event, setting it to `-1` will prevent recalc on scroll.
10213
10797
  * @option
@@ -10352,22 +10936,24 @@ function (_Plugin) {
10352
10936
  if (_this2._initialAnchor) anchor = _this2._initialAnchor;
10353
10937
  }
10354
10938
 
10355
- var $anchor = anchor && $(anchor);
10356
-
10357
- var $link = anchor && _this2.$element.find('[href$="' + anchor + '"]'); // Whether the anchor element that has been found is part of this element
10939
+ var anchorNoHash = anchor.indexOf('#') >= 0 ? anchor.slice(1) : anchor;
10940
+ var $anchor = anchorNoHash && $("#".concat(anchorNoHash));
10358
10941
 
10942
+ var $link = anchor && _this2.$element.find("[href$=\"".concat(anchor, "\"],[data-tabs-target=\"").concat(anchorNoHash, "\"]")).first(); // Whether the anchor element that has been found is part of this element
10359
10943
 
10360
- var isOwnAnchor = !!($anchor.length && $link.length); // If there is an anchor for the hash, select it
10361
10944
 
10362
- if ($anchor && $anchor.length && $link && $link.length) {
10363
- _this2.selectTab($anchor, true);
10364
- } // Otherwise, collapse everything
10365
- else {
10366
- _this2._collapse();
10367
- }
10945
+ var isOwnAnchor = !!($anchor.length && $link.length);
10368
10946
 
10369
10947
  if (isOwnAnchor) {
10370
- // Roll up a little to show the titles
10948
+ // If there is an anchor for the hash, select it
10949
+ if ($anchor && $anchor.length && $link && $link.length) {
10950
+ _this2.selectTab($anchor, true);
10951
+ } // Otherwise, collapse everything
10952
+ else {
10953
+ _this2._collapse();
10954
+ } // Roll up a little to show the titles
10955
+
10956
+
10371
10957
  if (_this2.options.deepLinkSmudge) {
10372
10958
  var offset = _this2.$element.offset();
10373
10959
 
@@ -10429,7 +11015,6 @@ function (_Plugin) {
10429
11015
 
10430
11016
  this.$element.off('click.zf.tabs').on('click.zf.tabs', ".".concat(this.options.linkClass), function (e) {
10431
11017
  e.preventDefault();
10432
- e.stopPropagation();
10433
11018
 
10434
11019
  _this._handleTabChange($(this));
10435
11020
  });
@@ -10481,7 +11066,6 @@ function (_Plugin) {
10481
11066
  _this._handleTabChange($nextElement);
10482
11067
  },
10483
11068
  handled: function handled() {
10484
- e.stopPropagation();
10485
11069
  e.preventDefault();
10486
11070
  }
10487
11071
  });
@@ -10604,7 +11188,7 @@ function (_Plugin) {
10604
11188
  }, {
10605
11189
  key: "selectTab",
10606
11190
  value: function selectTab(elem, historyHandled) {
10607
- var idStr;
11191
+ var idStr, hashIdStr;
10608
11192
 
10609
11193
  if (_typeof(elem) === 'object') {
10610
11194
  idStr = elem[0].id;
@@ -10613,10 +11197,13 @@ function (_Plugin) {
10613
11197
  }
10614
11198
 
10615
11199
  if (idStr.indexOf('#') < 0) {
10616
- idStr = "#".concat(idStr);
11200
+ hashIdStr = "#".concat(idStr);
11201
+ } else {
11202
+ hashIdStr = idStr;
11203
+ idStr = idStr.slice(1);
10617
11204
  }
10618
11205
 
10619
- var $target = this.$tabTitles.has("[href$=\"".concat(idStr, "\"]"));
11206
+ var $target = this.$tabTitles.has("[href$=\"".concat(hashIdStr, "\"],[data-tabs-target=\"").concat(idStr, "\"]")).first();
10620
11207
 
10621
11208
  this._handleTabChange($target, historyHandled);
10622
11209
  }
@@ -10839,24 +11426,31 @@ function (_Plugin) {
10839
11426
  }, {
10840
11427
  key: "_init",
10841
11428
  value: function _init() {
11429
+ // Collect triggers to set ARIA attributes to
11430
+ var id = this.$element[0].id,
11431
+ $triggers = $("[data-open~=\"".concat(id, "\"], [data-close~=\"").concat(id, "\"], [data-toggle~=\"").concat(id, "\"]"));
10842
11432
  var input; // Parse animation classes if they were set
10843
11433
 
10844
11434
  if (this.options.animate) {
10845
11435
  input = this.options.animate.split(' ');
10846
11436
  this.animationIn = input[0];
10847
- this.animationOut = input[1] || null;
11437
+ this.animationOut = input[1] || null; // - aria-expanded: according to the element visibility.
11438
+
11439
+ $triggers.attr('aria-expanded', !this.$element.is(':hidden'));
10848
11440
  } // Otherwise, parse toggle class
10849
11441
  else {
10850
- input = this.$element.data('toggler'); // Allow for a . at the beginning of the string
11442
+ input = this.options.toggler;
10851
11443
 
10852
- this.className = input[0] === '.' ? input.slice(1) : input;
10853
- } // Add ARIA attributes to triggers:
11444
+ if (typeof input !== 'string' || !input.length) {
11445
+ throw new Error("The 'toogler' option containing the target class is required, got \"".concat(input, "\""));
11446
+ } // Allow for a . at the beginning of the string
10854
11447
 
10855
11448
 
10856
- var id = this.$element[0].id,
10857
- $triggers = $("[data-open~=\"".concat(id, "\"], [data-close~=\"").concat(id, "\"], [data-toggle~=\"").concat(id, "\"]")); // - aria-expanded: according to the element visibility.
11449
+ this.className = input[0] === '.' ? input.slice(1) : input; // - aria-expanded: according to the elements class set.
11450
+
11451
+ $triggers.attr('aria-expanded', this.$element.hasClass(this.className));
11452
+ } // - aria-controls: adding the element id to it if not already in it.
10858
11453
 
10859
- $triggers.attr('aria-expanded', !this.$element.is(':hidden')); // - aria-controls: adding the element id to it if not already in it.
10860
11454
 
10861
11455
  $triggers.each(function (index, trigger) {
10862
11456
  var $trigger = $(trigger);
@@ -10957,6 +11551,13 @@ function (_Plugin) {
10957
11551
  }(Plugin);
10958
11552
 
10959
11553
  Toggler.defaults = {
11554
+ /**
11555
+ * Class of the element to toggle. It can be provided with or without "."
11556
+ * @option
11557
+ * @type {string}
11558
+ */
11559
+ toggler: undefined,
11560
+
10960
11561
  /**
10961
11562
  * Tells the plugin if the element should animated when toggled.
10962
11563
  * @option
@@ -11045,7 +11646,15 @@ function (_Positionable) {
11045
11646
  value: function _getDefaultPosition() {
11046
11647
  // handle legacy classnames
11047
11648
  var position = this.$element[0].className.match(/\b(top|left|right|bottom)\b/g);
11649
+ var elementClassName = this.$element[0].className;
11650
+
11651
+ if (this.$element[0] instanceof SVGElement) {
11652
+ elementClassName = elementClassName.baseVal;
11653
+ }
11654
+
11048
11655
  return position ? position[0] : 'top';
11656
+ var position = elementClassName.match(/\b(top|left|right)\b/g);
11657
+ position = position ? position[0] : 'tp';
11049
11658
  }
11050
11659
  }, {
11051
11660
  key: "_getDefaultAlignment",
@@ -11180,8 +11789,11 @@ function (_Positionable) {
11180
11789
  value: function _events() {
11181
11790
  var _this = this;
11182
11791
 
11792
+ var hasTouch = 'ontouchstart' in window || typeof window.ontouchstart !== 'undefined';
11183
11793
  var $template = this.template;
11184
- var isFocus = false;
11794
+ var isFocus = false; // `disableForTouch: Fully disable the tooltip on touch devices
11795
+
11796
+ if (hasTouch && this.options.disableForTouch) return;
11185
11797
 
11186
11798
  if (!this.options.disableHover) {
11187
11799
  this.$element.on('mouseenter.zf.tooltip', function (e) {
@@ -11199,10 +11811,14 @@ function (_Positionable) {
11199
11811
  }));
11200
11812
  }
11201
11813
 
11814
+ if (hasTouch) {
11815
+ this.$element.on('tap.zf.tooltip touchend.zf.tooltip', function (e) {
11816
+ _this.isActive ? _this.hide() : _this.show();
11817
+ });
11818
+ }
11819
+
11202
11820
  if (this.options.clickOpen) {
11203
11821
  this.$element.on('mousedown.zf.tooltip', function (e) {
11204
- e.stopImmediatePropagation();
11205
-
11206
11822
  if (_this.isClick) ; else {
11207
11823
  _this.isClick = true;
11208
11824
 
@@ -11213,17 +11829,10 @@ function (_Positionable) {
11213
11829
  });
11214
11830
  } else {
11215
11831
  this.$element.on('mousedown.zf.tooltip', function (e) {
11216
- e.stopImmediatePropagation();
11217
11832
  _this.isClick = true;
11218
11833
  });
11219
11834
  }
11220
11835
 
11221
- if (!this.options.disableForTouch) {
11222
- this.$element.on('tap.zf.tooltip touchend.zf.tooltip', function (e) {
11223
- _this.isActive ? _this.hide() : _this.show();
11224
- });
11225
- }
11226
-
11227
11836
  this.$element.on({
11228
11837
  // 'toggle.zf.trigger': this.toggle.bind(this),
11229
11838
  // 'close.zf.trigger': this.hide.bind(this)
@@ -11285,8 +11894,6 @@ function (_Positionable) {
11285
11894
  }(Positionable);
11286
11895
 
11287
11896
  Tooltip.defaults = {
11288
- disableForTouch: false,
11289
-
11290
11897
  /**
11291
11898
  * Time, in ms, before a tooltip should open on hover.
11292
11899
  * @option
@@ -11319,6 +11926,16 @@ Tooltip.defaults = {
11319
11926
  */
11320
11927
  disableHover: false,
11321
11928
 
11929
+ /**
11930
+ * Disable the tooltip for touch devices.
11931
+ * This can be useful to make elements with a tooltip on it trigger their
11932
+ * action on the first tap instead of displaying the tooltip.
11933
+ * @option
11934
+ * @type {booelan}
11935
+ * @default false
11936
+ */
11937
+ disableForTouch: false,
11938
+
11322
11939
  /**
11323
11940
  * Optional addtional classes to apply to the tooltip template on init.
11324
11941
  * @option
@@ -11457,11 +12074,29 @@ Tooltip.defaults = {
11457
12074
  var MenuPlugins$1 = {
11458
12075
  tabs: {
11459
12076
  cssClass: 'tabs',
11460
- plugin: Tabs
12077
+ plugin: Tabs,
12078
+ open: function open(plugin, target) {
12079
+ return plugin.selectTab(target);
12080
+ },
12081
+ close: null
12082
+ /* not supported */
12083
+ ,
12084
+ toggle: null
12085
+ /* not supported */
12086
+
11461
12087
  },
11462
12088
  accordion: {
11463
12089
  cssClass: 'accordion',
11464
- plugin: Accordion
12090
+ plugin: Accordion,
12091
+ open: function open(plugin, target) {
12092
+ return plugin.down($(target));
12093
+ },
12094
+ close: function close(plugin, target) {
12095
+ return plugin.up($(target));
12096
+ },
12097
+ toggle: function toggle(plugin, target) {
12098
+ return plugin.toggle($(target));
12099
+ }
11465
12100
  }
11466
12101
  };
11467
12102
  /**
@@ -11477,28 +12112,33 @@ var ResponsiveAccordionTabs =
11477
12112
  function (_Plugin) {
11478
12113
  _inherits(ResponsiveAccordionTabs, _Plugin);
11479
12114
 
11480
- function ResponsiveAccordionTabs() {
12115
+ function ResponsiveAccordionTabs(element, options) {
12116
+ var _this2;
12117
+
11481
12118
  _classCallCheck(this, ResponsiveAccordionTabs);
11482
12119
 
11483
- return _possibleConstructorReturn(this, _getPrototypeOf(ResponsiveAccordionTabs).apply(this, arguments));
12120
+ _this2 = _possibleConstructorReturn(this, _getPrototypeOf(ResponsiveAccordionTabs).call(this, element, options));
12121
+ return _possibleConstructorReturn(_this2, _this2.options.reflow && _this2.storezfData || _assertThisInitialized(_this2));
11484
12122
  }
12123
+ /**
12124
+ * Creates a new instance of a responsive accordion tabs.
12125
+ * @class
12126
+ * @name ResponsiveAccordionTabs
12127
+ * @fires ResponsiveAccordionTabs#init
12128
+ * @param {jQuery} element - jQuery object to make into Responsive Accordion Tabs.
12129
+ * @param {Object} options - Overrides to the default plugin settings.
12130
+ */
12131
+
11485
12132
 
11486
12133
  _createClass(ResponsiveAccordionTabs, [{
11487
12134
  key: "_setup",
11488
-
11489
- /**
11490
- * Creates a new instance of a responsive accordion tabs.
11491
- * @class
11492
- * @name ResponsiveAccordionTabs
11493
- * @fires ResponsiveAccordionTabs#init
11494
- * @param {jQuery} element - jQuery object to make into Responsive Accordion Tabs.
11495
- * @param {Object} options - Overrides to the default plugin settings.
11496
- */
11497
12135
  value: function _setup(element, options) {
11498
12136
  this.$element = $(element);
11499
- this.options = $.extend({}, this.$element.data(), options);
12137
+ this.$element.data('zfPluginBase', this);
12138
+ this.options = $.extend({}, ResponsiveAccordionTabs.defaults, this.$element.data(), options);
11500
12139
  this.rules = this.$element.data('responsive-accordion-tabs');
11501
12140
  this.currentMq = null;
12141
+ this.currentRule = null;
11502
12142
  this.currentPlugin = null;
11503
12143
  this.className = 'ResponsiveAccordionTabs'; // ie9 back compat
11504
12144
 
@@ -11623,7 +12263,8 @@ function (_Plugin) {
11623
12263
 
11624
12264
  this._handleMarkup(this.rules[matchedMq].cssClass);
11625
12265
 
11626
- this.currentPlugin = new this.rules[matchedMq].plugin(this.$element, {});
12266
+ this.currentRule = this.rules[matchedMq];
12267
+ this.currentPlugin = new this.currentRule.plugin(this.$element, this.options);
11627
12268
  this.storezfData = this.currentPlugin.$element.data('zfPlugin');
11628
12269
  }
11629
12270
  }, {
@@ -11701,6 +12342,55 @@ function (_Plugin) {
11701
12342
  $liHeads.addClass(tabsTitle);
11702
12343
  }
11703
12344
  }
12345
+ /**
12346
+ * Opens the plugin pane defined by `target`.
12347
+ * @param {jQuery | String} target - jQuery object or string of the id of the pane to open.
12348
+ * @see Accordion.down
12349
+ * @see Tabs.selectTab
12350
+ * @function
12351
+ */
12352
+
12353
+ }, {
12354
+ key: "open",
12355
+ value: function open(target) {
12356
+ if (this.currentRule && typeof this.currentRule.open === 'function') {
12357
+ var _this$currentRule;
12358
+
12359
+ return (_this$currentRule = this.currentRule).open.apply(_this$currentRule, [this.currentPlugin].concat(Array.prototype.slice.call(arguments)));
12360
+ }
12361
+ }
12362
+ /**
12363
+ * Closes the plugin pane defined by `target`. Not availaible for Tabs.
12364
+ * @param {jQuery | String} target - jQuery object or string of the id of the pane to close.
12365
+ * @see Accordion.up
12366
+ * @function
12367
+ */
12368
+
12369
+ }, {
12370
+ key: "close",
12371
+ value: function close(target) {
12372
+ if (this.currentRule && typeof this.currentRule.close === 'function') {
12373
+ var _this$currentRule2;
12374
+
12375
+ return (_this$currentRule2 = this.currentRule).close.apply(_this$currentRule2, [this.currentPlugin].concat(Array.prototype.slice.call(arguments)));
12376
+ }
12377
+ }
12378
+ /**
12379
+ * Toggles the plugin pane defined by `target`. Not availaible for Tabs.
12380
+ * @param {jQuery | String} target - jQuery object or string of the id of the pane to toggle.
12381
+ * @see Accordion.toggle
12382
+ * @function
12383
+ */
12384
+
12385
+ }, {
12386
+ key: "toggle",
12387
+ value: function toggle(target) {
12388
+ if (this.currentRule && typeof this.currentRule.toggle === 'function') {
12389
+ var _this$currentRule3;
12390
+
12391
+ return (_this$currentRule3 = this.currentRule).toggle.apply(_this$currentRule3, [this.currentPlugin].concat(Array.prototype.slice.call(arguments)));
12392
+ }
12393
+ }
11704
12394
  /**
11705
12395
  * Destroys the instance of the current plugin on this element, as well as the window resize handler that switches the plugins out.
11706
12396
  * @function
@@ -11764,30 +12454,27 @@ Foundation.plugin(Toggler, 'Toggler');
11764
12454
  Foundation.plugin(Tooltip, 'Tooltip');
11765
12455
  Foundation.plugin(ResponsiveAccordionTabs, 'ResponsiveAccordionTabs');
11766
12456
 
11767
- exports.CoreUtils = foundation_core_utils;
11768
- exports.Core = Foundation;
11769
- exports.Foundation = Foundation;
11770
- exports.Box = Box;
11771
- exports.onImagesLoaded = onImagesLoaded;
11772
- exports.Keyboard = Keyboard;
11773
- exports.MediaQuery = MediaQuery;
11774
- exports.Motion = Motion;
11775
- exports.Move = Move;
11776
- exports.Nest = Nest;
11777
- exports.Timer = Timer;
11778
- exports.Touch = Touch;
11779
- exports.Triggers = Triggers;
11780
12457
  exports.Abide = Abide;
11781
12458
  exports.Accordion = Accordion;
11782
12459
  exports.AccordionMenu = AccordionMenu;
12460
+ exports.Box = Box;
12461
+ exports.Core = Foundation;
12462
+ exports.CoreUtils = foundation_core_utils;
11783
12463
  exports.Drilldown = Drilldown;
11784
12464
  exports.Dropdown = Dropdown;
11785
12465
  exports.DropdownMenu = DropdownMenu;
11786
12466
  exports.Equalizer = Equalizer;
12467
+ exports.Foundation = Foundation;
11787
12468
  exports.Interchange = Interchange;
12469
+ exports.Keyboard = Keyboard;
11788
12470
  exports.Magellan = Magellan;
12471
+ exports.MediaQuery = MediaQuery;
12472
+ exports.Motion = Motion;
12473
+ exports.Move = Move;
12474
+ exports.Nest = Nest;
11789
12475
  exports.OffCanvas = OffCanvas;
11790
12476
  exports.Orbit = Orbit;
12477
+ exports.ResponsiveAccordionTabs = ResponsiveAccordionTabs;
11791
12478
  exports.ResponsiveMenu = ResponsiveMenu;
11792
12479
  exports.ResponsiveToggle = ResponsiveToggle;
11793
12480
  exports.Reveal = Reveal;
@@ -11795,8 +12482,11 @@ exports.Slider = Slider;
11795
12482
  exports.SmoothScroll = SmoothScroll;
11796
12483
  exports.Sticky = Sticky;
11797
12484
  exports.Tabs = Tabs;
12485
+ exports.Timer = Timer;
11798
12486
  exports.Toggler = Toggler;
11799
12487
  exports.Tooltip = Tooltip;
11800
- exports.ResponsiveAccordionTabs = ResponsiveAccordionTabs;
12488
+ exports.Touch = Touch;
12489
+ exports.Triggers = Triggers;
11801
12490
  exports.default = Foundation;
12491
+ exports.onImagesLoaded = onImagesLoaded;
11802
12492
  //# sourceMappingURL=foundation.cjs.js.map