foundation-rails 6.6.1.0 → 6.9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (253) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +2 -0
  4. data/Appraisals +4 -0
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +199 -146
  7. data/bower.json +3 -3
  8. data/foundation-rails.gemspec +4 -4
  9. data/gemfiles/rails_7.1.gemfile +10 -0
  10. data/gemfiles/rails_7.1.gemfile.lock +261 -0
  11. data/lib/foundation/rails/version.rb +1 -1
  12. data/lib/generators/foundation/templates/_settings.scss +32 -28
  13. data/vendor/assets/js/foundation.cjs.js +2101 -3230
  14. data/vendor/assets/js/foundation.cjs.js.map +1 -1
  15. data/vendor/assets/js/foundation.es6.js +505 -379
  16. data/vendor/assets/js/foundation.es6.js.map +1 -1
  17. data/vendor/assets/js/foundation.esm.js +1779 -2911
  18. data/vendor/assets/js/foundation.esm.js.map +1 -1
  19. data/vendor/assets/js/foundation.js +2544 -3970
  20. data/vendor/assets/js/foundation.js.map +1 -1
  21. data/vendor/assets/js/foundation.min.js +1 -1
  22. data/vendor/assets/js/foundation.min.js.map +1 -1
  23. data/vendor/assets/js/plugins/foundation.abide.js +277 -367
  24. data/vendor/assets/js/plugins/foundation.abide.js.map +1 -1
  25. data/vendor/assets/js/plugins/foundation.abide.min.js +1 -1
  26. data/vendor/assets/js/plugins/foundation.abide.min.js.map +1 -1
  27. data/vendor/assets/js/plugins/foundation.accordion.js +205 -277
  28. data/vendor/assets/js/plugins/foundation.accordion.js.map +1 -1
  29. data/vendor/assets/js/plugins/foundation.accordion.min.js +1 -1
  30. data/vendor/assets/js/plugins/foundation.accordion.min.js.map +1 -1
  31. data/vendor/assets/js/plugins/foundation.accordionMenu.js +174 -262
  32. data/vendor/assets/js/plugins/foundation.accordionMenu.js.map +1 -1
  33. data/vendor/assets/js/plugins/foundation.accordionMenu.min.js +1 -1
  34. data/vendor/assets/js/plugins/foundation.accordionMenu.min.js.map +1 -1
  35. data/vendor/assets/js/plugins/foundation.core.js +314 -457
  36. data/vendor/assets/js/plugins/foundation.core.js.map +1 -1
  37. data/vendor/assets/js/plugins/foundation.core.min.js +1 -1
  38. data/vendor/assets/js/plugins/foundation.core.min.js.map +1 -1
  39. data/vendor/assets/js/plugins/foundation.drilldown.js +259 -359
  40. data/vendor/assets/js/plugins/foundation.drilldown.js.map +1 -1
  41. data/vendor/assets/js/plugins/foundation.drilldown.min.js +1 -1
  42. data/vendor/assets/js/plugins/foundation.drilldown.min.js.map +1 -1
  43. data/vendor/assets/js/plugins/foundation.dropdown.js +291 -462
  44. data/vendor/assets/js/plugins/foundation.dropdown.js.map +1 -1
  45. data/vendor/assets/js/plugins/foundation.dropdown.min.js +1 -1
  46. data/vendor/assets/js/plugins/foundation.dropdown.min.js.map +1 -1
  47. data/vendor/assets/js/plugins/foundation.dropdownMenu.js +251 -349
  48. data/vendor/assets/js/plugins/foundation.dropdownMenu.js.map +1 -1
  49. data/vendor/assets/js/plugins/foundation.dropdownMenu.min.js +1 -1
  50. data/vendor/assets/js/plugins/foundation.dropdownMenu.min.js.map +1 -1
  51. data/vendor/assets/js/plugins/foundation.equalizer.js +178 -261
  52. data/vendor/assets/js/plugins/foundation.equalizer.js.map +1 -1
  53. data/vendor/assets/js/plugins/foundation.equalizer.min.js +1 -1
  54. data/vendor/assets/js/plugins/foundation.equalizer.min.js.map +1 -1
  55. data/vendor/assets/js/plugins/foundation.interchange.js +455 -240
  56. data/vendor/assets/js/plugins/foundation.interchange.js.map +1 -1
  57. data/vendor/assets/js/plugins/foundation.interchange.min.js +1 -1
  58. data/vendor/assets/js/plugins/foundation.interchange.min.js.map +1 -1
  59. data/vendor/assets/js/plugins/foundation.magellan.js +226 -342
  60. data/vendor/assets/js/plugins/foundation.magellan.js.map +1 -1
  61. data/vendor/assets/js/plugins/foundation.magellan.min.js +1 -1
  62. data/vendor/assets/js/plugins/foundation.magellan.min.js.map +1 -1
  63. data/vendor/assets/js/plugins/foundation.offcanvas.js +326 -471
  64. data/vendor/assets/js/plugins/foundation.offcanvas.js.map +1 -1
  65. data/vendor/assets/js/plugins/foundation.offcanvas.min.js +1 -1
  66. data/vendor/assets/js/plugins/foundation.offcanvas.min.js.map +1 -1
  67. data/vendor/assets/js/plugins/foundation.orbit.js +244 -347
  68. data/vendor/assets/js/plugins/foundation.orbit.js.map +1 -1
  69. data/vendor/assets/js/plugins/foundation.orbit.min.js +1 -1
  70. data/vendor/assets/js/plugins/foundation.orbit.min.js.map +1 -1
  71. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.js +203 -288
  72. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.js.map +1 -1
  73. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.min.js +1 -1
  74. data/vendor/assets/js/plugins/foundation.responsiveAccordionTabs.min.js.map +1 -1
  75. data/vendor/assets/js/plugins/foundation.responsiveMenu.js +205 -255
  76. data/vendor/assets/js/plugins/foundation.responsiveMenu.js.map +1 -1
  77. data/vendor/assets/js/plugins/foundation.responsiveMenu.min.js +1 -1
  78. data/vendor/assets/js/plugins/foundation.responsiveMenu.min.js.map +1 -1
  79. data/vendor/assets/js/plugins/foundation.responsiveToggle.js +170 -226
  80. data/vendor/assets/js/plugins/foundation.responsiveToggle.js.map +1 -1
  81. data/vendor/assets/js/plugins/foundation.responsiveToggle.min.js +1 -1
  82. data/vendor/assets/js/plugins/foundation.responsiveToggle.min.js.map +1 -1
  83. data/vendor/assets/js/plugins/foundation.reveal.js +285 -445
  84. data/vendor/assets/js/plugins/foundation.reveal.js.map +1 -1
  85. data/vendor/assets/js/plugins/foundation.reveal.min.js +1 -1
  86. data/vendor/assets/js/plugins/foundation.reveal.min.js.map +1 -1
  87. data/vendor/assets/js/plugins/foundation.slider.js +321 -486
  88. data/vendor/assets/js/plugins/foundation.slider.js.map +1 -1
  89. data/vendor/assets/js/plugins/foundation.slider.min.js +1 -1
  90. data/vendor/assets/js/plugins/foundation.slider.min.js.map +1 -1
  91. data/vendor/assets/js/plugins/foundation.smoothScroll.js +138 -188
  92. data/vendor/assets/js/plugins/foundation.smoothScroll.js.map +1 -1
  93. data/vendor/assets/js/plugins/foundation.smoothScroll.min.js +1 -1
  94. data/vendor/assets/js/plugins/foundation.smoothScroll.min.js.map +1 -1
  95. data/vendor/assets/js/plugins/foundation.sticky.js +253 -395
  96. data/vendor/assets/js/plugins/foundation.sticky.js.map +1 -1
  97. data/vendor/assets/js/plugins/foundation.sticky.min.js +1 -1
  98. data/vendor/assets/js/plugins/foundation.sticky.min.js.map +1 -1
  99. data/vendor/assets/js/plugins/foundation.tabs.js +228 -317
  100. data/vendor/assets/js/plugins/foundation.tabs.js.map +1 -1
  101. data/vendor/assets/js/plugins/foundation.tabs.min.js +1 -1
  102. data/vendor/assets/js/plugins/foundation.tabs.min.js.map +1 -1
  103. data/vendor/assets/js/plugins/foundation.toggler.js +207 -294
  104. data/vendor/assets/js/plugins/foundation.toggler.js.map +1 -1
  105. data/vendor/assets/js/plugins/foundation.toggler.min.js +1 -1
  106. data/vendor/assets/js/plugins/foundation.toggler.min.js.map +1 -1
  107. data/vendor/assets/js/plugins/foundation.tooltip.js +276 -437
  108. data/vendor/assets/js/plugins/foundation.tooltip.js.map +1 -1
  109. data/vendor/assets/js/plugins/foundation.tooltip.min.js +1 -1
  110. data/vendor/assets/js/plugins/foundation.tooltip.min.js.map +1 -1
  111. data/vendor/assets/js/plugins/foundation.util.box.js +176 -234
  112. data/vendor/assets/js/plugins/foundation.util.box.js.map +1 -1
  113. data/vendor/assets/js/plugins/foundation.util.box.min.js +1 -1
  114. data/vendor/assets/js/plugins/foundation.util.box.min.js.map +1 -1
  115. data/vendor/assets/js/plugins/foundation.util.imageLoader.js +110 -150
  116. data/vendor/assets/js/plugins/foundation.util.imageLoader.js.map +1 -1
  117. data/vendor/assets/js/plugins/foundation.util.imageLoader.min.js +1 -1
  118. data/vendor/assets/js/plugins/foundation.util.imageLoader.min.js.map +1 -1
  119. data/vendor/assets/js/plugins/foundation.util.keyboard.js +157 -172
  120. data/vendor/assets/js/plugins/foundation.util.keyboard.js.map +1 -1
  121. data/vendor/assets/js/plugins/foundation.util.keyboard.min.js +1 -1
  122. data/vendor/assets/js/plugins/foundation.util.keyboard.min.js.map +1 -1
  123. data/vendor/assets/js/plugins/foundation.util.mediaQuery.js +167 -233
  124. data/vendor/assets/js/plugins/foundation.util.mediaQuery.js.map +1 -1
  125. data/vendor/assets/js/plugins/foundation.util.mediaQuery.min.js +1 -1
  126. data/vendor/assets/js/plugins/foundation.util.mediaQuery.min.js.map +1 -1
  127. data/vendor/assets/js/plugins/foundation.util.motion.js +127 -161
  128. data/vendor/assets/js/plugins/foundation.util.motion.js.map +1 -1
  129. data/vendor/assets/js/plugins/foundation.util.motion.min.js +1 -1
  130. data/vendor/assets/js/plugins/foundation.util.motion.min.js.map +1 -1
  131. data/vendor/assets/js/plugins/foundation.util.nest.js +126 -160
  132. data/vendor/assets/js/plugins/foundation.util.nest.js.map +1 -1
  133. data/vendor/assets/js/plugins/foundation.util.nest.min.js +1 -1
  134. data/vendor/assets/js/plugins/foundation.util.nest.min.js.map +1 -1
  135. data/vendor/assets/js/plugins/foundation.util.timer.js +116 -171
  136. data/vendor/assets/js/plugins/foundation.util.timer.js.map +1 -1
  137. data/vendor/assets/js/plugins/foundation.util.timer.min.js +1 -1
  138. data/vendor/assets/js/plugins/foundation.util.timer.min.js.map +1 -1
  139. data/vendor/assets/js/plugins/foundation.util.touch.js +172 -228
  140. data/vendor/assets/js/plugins/foundation.util.touch.js.map +1 -1
  141. data/vendor/assets/js/plugins/foundation.util.touch.min.js +1 -1
  142. data/vendor/assets/js/plugins/foundation.util.touch.min.js.map +1 -1
  143. data/vendor/assets/js/plugins/foundation.util.triggers.js +158 -222
  144. data/vendor/assets/js/plugins/foundation.util.triggers.js.map +1 -1
  145. data/vendor/assets/js/plugins/foundation.util.triggers.min.js +1 -1
  146. data/vendor/assets/js/plugins/foundation.util.triggers.min.js.map +1 -1
  147. data/vendor/assets/scss/_global.scss +20 -7
  148. data/vendor/assets/scss/components/_accordion-menu.scss +2 -2
  149. data/vendor/assets/scss/components/_accordion.scss +2 -2
  150. data/vendor/assets/scss/components/_badge.scss +3 -3
  151. data/vendor/assets/scss/components/_breadcrumbs.scss +4 -3
  152. data/vendor/assets/scss/components/_button-group.scss +23 -13
  153. data/vendor/assets/scss/components/_button.scss +15 -15
  154. data/vendor/assets/scss/components/_callout.scss +4 -4
  155. data/vendor/assets/scss/components/_card.scss +2 -2
  156. data/vendor/assets/scss/components/_close-button.scss +7 -6
  157. data/vendor/assets/scss/components/_drilldown.scss +2 -2
  158. data/vendor/assets/scss/components/_dropdown-menu.scss +3 -3
  159. data/vendor/assets/scss/components/_dropdown.scss +2 -2
  160. data/vendor/assets/scss/components/_flex.scss +2 -2
  161. data/vendor/assets/scss/components/_float.scss +2 -2
  162. data/vendor/assets/scss/components/_label.scss +3 -3
  163. data/vendor/assets/scss/components/_media-object.scss +2 -2
  164. data/vendor/assets/scss/components/_menu.scss +56 -21
  165. data/vendor/assets/scss/components/_off-canvas.scss +20 -18
  166. data/vendor/assets/scss/components/_orbit.scss +5 -5
  167. data/vendor/assets/scss/components/_pagination.scss +3 -3
  168. data/vendor/assets/scss/components/_progress-bar.scss +3 -3
  169. data/vendor/assets/scss/components/_responsive-embed.scss +3 -3
  170. data/vendor/assets/scss/components/_reveal.scss +10 -5
  171. data/vendor/assets/scss/components/_slider.scss +7 -4
  172. data/vendor/assets/scss/components/_sticky.scss +2 -2
  173. data/vendor/assets/scss/components/_switch.scss +27 -4
  174. data/vendor/assets/scss/components/_table.scss +10 -9
  175. data/vendor/assets/scss/components/_tabs.scss +4 -4
  176. data/vendor/assets/scss/components/_thumbnail.scss +2 -2
  177. data/vendor/assets/scss/components/_title-bar.scss +2 -2
  178. data/vendor/assets/scss/components/_tooltip.scss +2 -2
  179. data/vendor/assets/scss/components/_top-bar.scss +9 -7
  180. data/vendor/assets/scss/components/_visibility.scss +48 -5
  181. data/vendor/assets/scss/forms/_checkbox.scss +2 -2
  182. data/vendor/assets/scss/forms/_error.scss +2 -2
  183. data/vendor/assets/scss/forms/_fieldset.scss +2 -2
  184. data/vendor/assets/scss/forms/_forms.scss +2 -2
  185. data/vendor/assets/scss/forms/_help-text.scss +2 -2
  186. data/vendor/assets/scss/forms/_input-group.scss +2 -2
  187. data/vendor/assets/scss/forms/_label.scss +4 -3
  188. data/vendor/assets/scss/forms/_meter.scss +2 -2
  189. data/vendor/assets/scss/forms/_progress.scss +3 -3
  190. data/vendor/assets/scss/forms/_range.scss +3 -3
  191. data/vendor/assets/scss/forms/_select.scss +7 -6
  192. data/vendor/assets/scss/forms/_text.scss +4 -4
  193. data/vendor/assets/scss/foundation.scss +3 -3
  194. data/vendor/assets/scss/grid/_classes.scss +3 -3
  195. data/vendor/assets/scss/grid/_column.scss +5 -4
  196. data/vendor/assets/scss/grid/_flex-grid.scss +9 -8
  197. data/vendor/assets/scss/grid/_grid.scss +2 -2
  198. data/vendor/assets/scss/grid/_gutter.scss +3 -3
  199. data/vendor/assets/scss/grid/_layout.scss +7 -7
  200. data/vendor/assets/scss/grid/_position.scss +6 -6
  201. data/vendor/assets/scss/grid/_row.scss +3 -3
  202. data/vendor/assets/scss/grid/_size.scss +2 -2
  203. data/vendor/assets/scss/motion-ui/util/_animation.scss +1 -1
  204. data/vendor/assets/scss/motion-ui/util/_series.scss +1 -1
  205. data/vendor/assets/scss/motion-ui/util/_unit.scss +54 -1
  206. data/vendor/assets/scss/prototype/_arrow.scss +2 -2
  207. data/vendor/assets/scss/prototype/_border-box.scss +2 -2
  208. data/vendor/assets/scss/prototype/_border-none.scss +3 -3
  209. data/vendor/assets/scss/prototype/_bordered.scss +2 -2
  210. data/vendor/assets/scss/prototype/_box.scss +2 -2
  211. data/vendor/assets/scss/prototype/_display.scss +2 -2
  212. data/vendor/assets/scss/prototype/_font-styling.scss +4 -4
  213. data/vendor/assets/scss/prototype/_list-style-type.scss +2 -2
  214. data/vendor/assets/scss/prototype/_overflow.scss +11 -2
  215. data/vendor/assets/scss/prototype/_position.scss +2 -2
  216. data/vendor/assets/scss/prototype/_prototype.scss +2 -2
  217. data/vendor/assets/scss/prototype/_rotate.scss +9 -7
  218. data/vendor/assets/scss/prototype/_rounded.scss +2 -2
  219. data/vendor/assets/scss/prototype/_separator.scss +7 -7
  220. data/vendor/assets/scss/prototype/_shadow.scss +3 -4
  221. data/vendor/assets/scss/prototype/_sizing.scss +2 -2
  222. data/vendor/assets/scss/prototype/_spacing.scss +35 -35
  223. data/vendor/assets/scss/prototype/_text-decoration.scss +2 -2
  224. data/vendor/assets/scss/prototype/_text-transformation.scss +5 -5
  225. data/vendor/assets/scss/prototype/_text-utilities.scss +2 -2
  226. data/vendor/assets/scss/settings/_settings.scss +32 -28
  227. data/vendor/assets/scss/typography/_alignment.scss +2 -2
  228. data/vendor/assets/scss/typography/_base.scss +8 -8
  229. data/vendor/assets/scss/typography/_helpers.scss +12 -4
  230. data/vendor/assets/scss/typography/_print.scss +4 -4
  231. data/vendor/assets/scss/typography/_typography.scss +2 -2
  232. data/vendor/assets/scss/util/_breakpoint.scss +24 -21
  233. data/vendor/assets/scss/util/_color.scss +22 -10
  234. data/vendor/assets/scss/util/_direction.scss +3 -3
  235. data/vendor/assets/scss/util/_flex.scss +1 -1
  236. data/vendor/assets/scss/util/_math.scss +63 -11
  237. data/vendor/assets/scss/util/_mixins.scss +20 -16
  238. data/vendor/assets/scss/util/_selector.scss +3 -17
  239. data/vendor/assets/scss/util/_typography.scss +8 -8
  240. data/vendor/assets/scss/util/_unit.scss +16 -10
  241. data/vendor/assets/scss/util/_util.scss +2 -2
  242. data/vendor/assets/scss/util/_value.scss +5 -20
  243. data/vendor/assets/scss/vendor/normalize.scss +19 -2
  244. data/vendor/assets/scss/xy-grid/_cell.scss +18 -7
  245. data/vendor/assets/scss/xy-grid/_classes.scss +16 -16
  246. data/vendor/assets/scss/xy-grid/_collapse.scss +2 -2
  247. data/vendor/assets/scss/xy-grid/_frame.scss +12 -0
  248. data/vendor/assets/scss/xy-grid/_grid.scss +4 -4
  249. data/vendor/assets/scss/xy-grid/_gutters.scss +4 -4
  250. data/vendor/assets/scss/xy-grid/_layout.scss +3 -3
  251. data/vendor/assets/scss/xy-grid/_position.scss +14 -9
  252. data/vendor/assets/scss/xy-grid/_xy-grid.scss +4 -4
  253. metadata +21 -19
@@ -49,15 +49,15 @@ function transitionend($elem){
49
49
  var elem = document.createElement('div'),
50
50
  end;
51
51
 
52
- for (var t in transitions){
53
- if (typeof elem.style[t] !== 'undefined'){
54
- end = transitions[t];
52
+ for (let transition in transitions){
53
+ if (typeof elem.style[transition] !== 'undefined'){
54
+ end = transitions[transition];
55
55
  }
56
56
  }
57
- if(end){
57
+ if (end) {
58
58
  return end;
59
- }else{
60
- end = setTimeout(function(){
59
+ } else {
60
+ setTimeout(function(){
61
61
  $elem.triggerHandler('transitionend', [$elem]);
62
62
  }, 1);
63
63
  return 'transitionend';
@@ -144,6 +144,7 @@ function ignoreMousedisappear(handler, { ignoreLeaveWindow = false, ignoreReappe
144
144
  }
145
145
 
146
146
  var foundation_core_utils = /*#__PURE__*/Object.freeze({
147
+ __proto__: null,
147
148
  rtl: rtl,
148
149
  GetYoDigits: GetYoDigits,
149
150
  RegExpEscape: RegExpEscape,
@@ -152,6 +153,20 @@ var foundation_core_utils = /*#__PURE__*/Object.freeze({
152
153
  ignoreMousedisappear: ignoreMousedisappear
153
154
  });
154
155
 
156
+ // Default set of media queries
157
+ // const defaultQueries = {
158
+ // 'default' : 'only screen',
159
+ // landscape : 'only screen and (orientation: landscape)',
160
+ // portrait : 'only screen and (orientation: portrait)',
161
+ // retina : 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
162
+ // 'only screen and (min--moz-device-pixel-ratio: 2),' +
163
+ // 'only screen and (-o-min-device-pixel-ratio: 2/1),' +
164
+ // 'only screen and (min-device-pixel-ratio: 2),' +
165
+ // 'only screen and (min-resolution: 192dpi),' +
166
+ // 'only screen and (min-resolution: 2dppx)'
167
+ // };
168
+
169
+
155
170
  // matchMedia() polyfill - Test a CSS media type/query in JS.
156
171
  // Authors & copyright © 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. MIT license
157
172
  /* eslint-disable */
@@ -218,7 +233,7 @@ var MediaQuery = {
218
233
 
219
234
  // make sure the initialization is only done once when calling _init() several times
220
235
  if (this.isInitialized === true) {
221
- return;
236
+ return this;
222
237
  } else {
223
238
  this.isInitialized = true;
224
239
  }
@@ -226,7 +241,7 @@ var MediaQuery = {
226
241
  var self = this;
227
242
  var $meta = $('meta.foundation-mq');
228
243
  if(!$meta.length){
229
- $('<meta class="foundation-mq">').appendTo(document.head);
244
+ $('<meta class="foundation-mq" name="foundation-mq" content>').appendTo(document.head);
230
245
  }
231
246
 
232
247
  var extractedStyles = $('.foundation-mq').css('font-family');
@@ -417,7 +432,7 @@ var MediaQuery = {
417
432
  * @private
418
433
  */
419
434
  _watcher() {
420
- $(window).off('resize.zf.mediaquery').on('resize.zf.mediaquery', () => {
435
+ $(window).on('resize.zf.trigger', () => {
421
436
  var newSize = this._getCurrentSize(), currentSize = this.current;
422
437
 
423
438
  if (newSize !== currentSize) {
@@ -470,7 +485,7 @@ function parseStyleToObject(str) {
470
485
  return styleObject;
471
486
  }
472
487
 
473
- var FOUNDATION_VERSION = '6.6.1';
488
+ var FOUNDATION_VERSION = '6.9.0';
474
489
 
475
490
  // Global Foundation object
476
491
  // This is attached to the window, or used as a module for AMD/Browserify
@@ -497,7 +512,7 @@ var Foundation = {
497
512
  var className = (name || functionName(plugin));
498
513
  // Object key to use when storing the plugin, also used to create the identifying data attribute for the plugin
499
514
  // Examples: data-reveal, data-off-canvas
500
- var attrName = hyphenate(className);
515
+ var attrName = hyphenate$1(className);
501
516
 
502
517
  // Add to the Foundation object and the plugins list (for reflowing)
503
518
  this._plugins[attrName] = this[className] = plugin;
@@ -512,7 +527,7 @@ var Foundation = {
512
527
  * @fires Plugin#init
513
528
  */
514
529
  registerPlugin: function(plugin, name){
515
- var pluginName = name ? hyphenate(name) : functionName(plugin.constructor).toLowerCase();
530
+ var pluginName = name ? hyphenate$1(name) : functionName(plugin.constructor).toLowerCase();
516
531
  plugin.uuid = GetYoDigits(6, pluginName);
517
532
 
518
533
  if(!plugin.$element.attr(`data-${pluginName}`)){ plugin.$element.attr(`data-${pluginName}`, plugin.uuid); }
@@ -536,7 +551,7 @@ var Foundation = {
536
551
  * @fires Plugin#destroyed
537
552
  */
538
553
  unregisterPlugin: function(plugin){
539
- var pluginName = hyphenate(functionName(plugin.$element.data('zfPlugin').constructor));
554
+ var pluginName = hyphenate$1(functionName(plugin.$element.data('zfPlugin').constructor));
540
555
 
541
556
  this._uuids.splice(this._uuids.indexOf(plugin.uuid), 1);
542
557
  plugin.$element.removeAttr(`data-${pluginName}`).removeData('zfPlugin')
@@ -546,7 +561,9 @@ var Foundation = {
546
561
  */
547
562
  .trigger(`destroyed.zf.${pluginName}`);
548
563
  for(var prop in plugin){
549
- plugin[prop] = null;//clean up script to prep for garbage collection.
564
+ if(typeof plugin[prop] === 'function'){
565
+ plugin[prop] = null; //clean up script to prep for garbage collection.
566
+ }
550
567
  }
551
568
  return;
552
569
  },
@@ -564,22 +581,22 @@ var Foundation = {
564
581
  plugins.each(function(){
565
582
  $(this).data('zfPlugin')._init();
566
583
  });
567
- }else{
584
+ }else {
568
585
  var type = typeof plugins,
569
586
  _this = this,
570
587
  fns = {
571
588
  'object': function(plgs){
572
589
  plgs.forEach(function(p){
573
- p = hyphenate(p);
590
+ p = hyphenate$1(p);
574
591
  $('[data-'+ p +']').foundation('_init');
575
592
  });
576
593
  },
577
594
  'string': function(){
578
- plugins = hyphenate(plugins);
595
+ plugins = hyphenate$1(plugins);
579
596
  $('[data-'+ plugins +']').foundation('_init');
580
597
  },
581
598
  'undefined': function(){
582
- this['object'](Object.keys(_this._plugins));
599
+ this.object(Object.keys(_this._plugins));
583
600
  }
584
601
  };
585
602
  fns[type](plugins);
@@ -625,8 +642,8 @@ var Foundation = {
625
642
  opts = { reflow: true };
626
643
 
627
644
  if($el.attr('data-options')){
628
- var thing = $el.attr('data-options').split(';').forEach(function(e, i){
629
- var opt = e.split(':').map(function(el){ return el.trim(); });
645
+ $el.attr('data-options').split(';').forEach(function(option){
646
+ var opt = option.split(':').map(function(el){ return el.trim(); });
630
647
  if(opt[0]) opts[opt[0]] = parseValue(opt[1]);
631
648
  });
632
649
  }
@@ -642,7 +659,7 @@ var Foundation = {
642
659
  },
643
660
  getFnName: functionName,
644
661
 
645
- addToJquery: function($) {
662
+ addToJquery: function() {
646
663
  // TODO: consider not making this a jQuery function
647
664
  // TODO: need way to reflow vs. re-initialize
648
665
  /**
@@ -667,15 +684,15 @@ var Foundation = {
667
684
  if(typeof plugClass !== 'undefined' && typeof plugClass[method] !== 'undefined'){//make sure both the class and method exist
668
685
  if(this.length === 1){//if there's only one, call it directly.
669
686
  plugClass[method].apply(plugClass, args);
670
- }else{
687
+ }else {
671
688
  this.each(function(i, el){//otherwise loop through the jQuery collection and invoke the method on each
672
689
  plugClass[method].apply($(el).data('zfPlugin'), args);
673
690
  });
674
691
  }
675
- }else{//error for no class or no method
692
+ }else {//error for no class or no method
676
693
  throw new ReferenceError("We're sorry, '" + method + "' is not an available method for " + (plugClass ? functionName(plugClass) : 'this element') + '.');
677
694
  }
678
- }else{//error for invalid argument type
695
+ }else {//error for invalid argument type
679
696
  throw new TypeError(`We're sorry, ${type} is not a valid parameter. You must use a string representing the method you wish to invoke.`);
680
697
  }
681
698
  return this;
@@ -745,6 +762,7 @@ window.Foundation = Foundation;
745
762
  }
746
763
  })();
747
764
  if (!Function.prototype.bind) {
765
+ /* eslint-disable no-extend-native */
748
766
  Function.prototype.bind = function(oThis) {
749
767
  if (typeof this !== 'function') {
750
768
  // closest thing possible to the ECMAScript 5
@@ -793,7 +811,7 @@ function parseValue(str){
793
811
  }
794
812
  // Convert PascalCase to kebab-case
795
813
  // Thank you: http://stackoverflow.com/a/8955580
796
- function hyphenate(str) {
814
+ function hyphenate$1(str) {
797
815
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
798
816
  }
799
817
 
@@ -817,6 +835,7 @@ var Box = {
817
835
  function ImNotTouchingYou(element, parent, lrOnly, tbOnly, ignoreBottom) {
818
836
  return OverlapArea(element, parent, lrOnly, tbOnly, ignoreBottom) === 0;
819
837
  }
838
+
820
839
  function OverlapArea(element, parent, lrOnly, tbOnly, ignoreBottom) {
821
840
  var eleDims = GetDimensions(element),
822
841
  topOver, bottomOver, leftOver, rightOver;
@@ -917,8 +936,8 @@ function GetExplicitOffsets(element, anchor, position, alignment, vOffset, hOffs
917
936
 
918
937
  var topVal, leftVal;
919
938
 
939
+ if ($anchorDims !== null) {
920
940
  // set position related attribute
921
-
922
941
  switch (position) {
923
942
  case 'top':
924
943
  topVal = $anchorDims.offset.top - ($eleDims.height + vOffset);
@@ -934,7 +953,6 @@ function GetExplicitOffsets(element, anchor, position, alignment, vOffset, hOffs
934
953
  break;
935
954
  }
936
955
 
937
-
938
956
  // set alignment related attribute
939
957
  switch (position) {
940
958
  case 'top':
@@ -966,6 +984,8 @@ function GetExplicitOffsets(element, anchor, position, alignment, vOffset, hOffs
966
984
  }
967
985
  break;
968
986
  }
987
+ }
988
+
969
989
  return {top: topVal, left: leftVal};
970
990
  }
971
991
 
@@ -991,7 +1011,7 @@ function onImagesLoaded(images, callback){
991
1011
  var image = new Image();
992
1012
  // Still count image as loaded if it finalizes with an error.
993
1013
  var events = "load.zf.images error.zf.images";
994
- $(image).one(events, function me(event){
1014
+ $(image).one(events, function me(){
995
1015
  // Unbind the event listeners. We're using 'one' but only one of the two events will have fired.
996
1016
  $(this).off(events, me);
997
1017
  singleImageLoaded();
@@ -1037,6 +1057,32 @@ function findFocusable($element) {
1037
1057
  return $element.find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]').filter(function() {
1038
1058
  if (!$(this).is(':visible') || $(this).attr('tabindex') < 0) { return false; } //only have visible elements and those that have a tabindex greater or equal 0
1039
1059
  return true;
1060
+ })
1061
+ .sort( function( a, b ) {
1062
+ if ($(a).attr('tabindex') === $(b).attr('tabindex')) {
1063
+ return 0;
1064
+ }
1065
+ let aTabIndex = parseInt($(a).attr('tabindex'), 10),
1066
+ bTabIndex = parseInt($(b).attr('tabindex'), 10);
1067
+ // Undefined is treated the same as 0
1068
+ if (typeof $(a).attr('tabindex') === 'undefined' && bTabIndex > 0) {
1069
+ return 1;
1070
+ }
1071
+ if (typeof $(b).attr('tabindex') === 'undefined' && aTabIndex > 0) {
1072
+ return -1;
1073
+ }
1074
+ if (aTabIndex === 0 && bTabIndex > 0) {
1075
+ return 1;
1076
+ }
1077
+ if (bTabIndex === 0 && aTabIndex > 0) {
1078
+ return -1;
1079
+ }
1080
+ if (aTabIndex < bTabIndex) {
1081
+ return -1;
1082
+ }
1083
+ if (aTabIndex > bTabIndex) {
1084
+ return 1;
1085
+ }
1040
1086
  });
1041
1087
  }
1042
1088
 
@@ -1171,7 +1217,9 @@ var Keyboard = {
1171
1217
  */
1172
1218
  function getKeyCodes(kcs) {
1173
1219
  var k = {};
1174
- for (var kc in kcs) k[kcs[kc]] = kcs[kc];
1220
+ for (var kc in kcs) {
1221
+ if (kcs.hasOwnProperty(kc)) k[kcs[kc]] = kcs[kc];
1222
+ }
1175
1223
  return k;
1176
1224
  }
1177
1225
 
@@ -1195,7 +1243,6 @@ const Motion = {
1195
1243
 
1196
1244
  function Move(duration, elem, fn){
1197
1245
  var anim, prog, start = null;
1198
- // console.log('called');
1199
1246
 
1200
1247
  if (duration === 0) {
1201
1248
  fn.apply(elem);
@@ -1205,12 +1252,11 @@ function Move(duration, elem, fn){
1205
1252
 
1206
1253
  function move(ts){
1207
1254
  if(!start) start = ts;
1208
- // console.log(start, ts);
1209
1255
  prog = ts - start;
1210
1256
  fn.apply(elem);
1211
1257
 
1212
1258
  if(prog < duration){ anim = window.requestAnimationFrame(move, elem); }
1213
- else{
1259
+ else {
1214
1260
  window.cancelAnimationFrame(anim);
1215
1261
  elem.trigger('finished.zf.animate', [elem]).triggerHandler('finished.zf.animate', [elem]);
1216
1262
  }
@@ -1249,6 +1295,10 @@ function animate(isIn, element, animation, cb) {
1249
1295
 
1250
1296
  // Start the animation
1251
1297
  requestAnimationFrame(() => {
1298
+ // will trigger the browser to synchronously calculate the style and layout
1299
+ // also called reflow or layout thrashing
1300
+ // see https://gist.github.com/paulirish/5d52fb081b3570c81e3a
1301
+ element[0].offsetWidth;
1252
1302
  element
1253
1303
  .css('transition', '')
1254
1304
  .addClass(activeClass);
@@ -1274,8 +1324,9 @@ function animate(isIn, element, animation, cb) {
1274
1324
  const Nest = {
1275
1325
  Feather(menu, type = 'zf') {
1276
1326
  menu.attr('role', 'menubar');
1327
+ menu.find('a').attr({'role': 'menuitem'});
1277
1328
 
1278
- var items = menu.find('li').attr({'role': 'menuitem'}),
1329
+ var items = menu.find('li').attr({'role': 'none'}),
1279
1330
  subMenuClass = `is-${type}-submenu`,
1280
1331
  subItemClass = `${subMenuClass}-item`,
1281
1332
  hasSubClass = `is-${type}-submenu-parent`,
@@ -1288,9 +1339,10 @@ const Nest = {
1288
1339
  if ($sub.length) {
1289
1340
  $item.addClass(hasSubClass);
1290
1341
  if(applyAria) {
1291
- $item.attr({
1342
+ const firstItem = $item.children('a:first');
1343
+ firstItem.attr({
1292
1344
  'aria-haspopup': true,
1293
- 'aria-label': $item.children('a:first').text()
1345
+ 'aria-label': firstItem.attr('aria-label') || firstItem.text()
1294
1346
  });
1295
1347
  // Note: Drilldowns behave differently in how they hide, and so need
1296
1348
  // additional attributes. We should look if this possibly over-generalized
@@ -1380,7 +1432,6 @@ function Timer(elem, options, cb) {
1380
1432
  var Touch = {};
1381
1433
 
1382
1434
  var startPosX,
1383
- startPosY,
1384
1435
  startTime,
1385
1436
  elapsedTime,
1386
1437
  startEvent,
@@ -1403,12 +1454,13 @@ function onTouchEnd(e) {
1403
1454
  }
1404
1455
 
1405
1456
  function onTouchMove(e) {
1406
- if ($.spotSwipe.preventDefault) { e.preventDefault(); }
1457
+ if (true === $.spotSwipe.preventDefault) { e.preventDefault(); }
1407
1458
 
1408
1459
  if(isMoving) {
1409
1460
  var x = e.touches[0].pageX;
1410
- var y = e.touches[0].pageY;
1461
+ // var y = e.touches[0].pageY;
1411
1462
  var dx = startPosX - x;
1463
+ // var dy = startPosY - y;
1412
1464
  var dir;
1413
1465
  didMoved = true;
1414
1466
  elapsedTime = new Date().getTime() - startTime;
@@ -1431,35 +1483,36 @@ function onTouchMove(e) {
1431
1483
 
1432
1484
  function onTouchStart(e) {
1433
1485
 
1434
- if (e.touches.length == 1) {
1486
+ if (e.touches.length === 1) {
1435
1487
  startPosX = e.touches[0].pageX;
1436
- startPosY = e.touches[0].pageY;
1437
1488
  startEvent = e;
1438
1489
  isMoving = true;
1439
1490
  didMoved = false;
1440
1491
  startTime = new Date().getTime();
1441
- this.addEventListener('touchmove', onTouchMove, false);
1492
+ this.addEventListener('touchmove', onTouchMove, { passive : true === $.spotSwipe.preventDefault });
1442
1493
  this.addEventListener('touchend', onTouchEnd, false);
1443
1494
  }
1444
1495
  }
1445
1496
 
1446
1497
  function init() {
1447
- this.addEventListener && this.addEventListener('touchstart', onTouchStart, false);
1498
+ this.addEventListener && this.addEventListener('touchstart', onTouchStart, { passive : true });
1448
1499
  }
1449
1500
 
1501
+ // function teardown() {
1502
+ // this.removeEventListener('touchstart', onTouchStart);
1503
+ // }
1504
+
1450
1505
  class SpotSwipe {
1451
- constructor($) {
1506
+ constructor() {
1452
1507
  this.version = '1.0.0';
1453
1508
  this.enabled = 'ontouchstart' in document.documentElement;
1454
1509
  this.preventDefault = false;
1455
1510
  this.moveThreshold = 75;
1456
1511
  this.timeThreshold = 200;
1457
- this.$ = $;
1458
1512
  this._init();
1459
1513
  }
1460
1514
 
1461
1515
  _init() {
1462
- var $ = this.$;
1463
1516
  $.event.special.swipe = { setup: init };
1464
1517
  $.event.special.tap = { setup: init };
1465
1518
 
@@ -1478,16 +1531,16 @@ class SpotSwipe {
1478
1531
  * values, and do not add event handlers directly. *
1479
1532
  ****************************************************/
1480
1533
 
1481
- Touch.setupSpotSwipe = function($) {
1534
+ Touch.setupSpotSwipe = function() {
1482
1535
  $.spotSwipe = new SpotSwipe($);
1483
1536
  };
1484
1537
 
1485
1538
  /****************************************************
1486
1539
  * Method for adding pseudo drag events to elements *
1487
1540
  ***************************************************/
1488
- Touch.setupTouchHandler = function($) {
1541
+ Touch.setupTouchHandler = function() {
1489
1542
  $.fn.addTouch = function(){
1490
- this.each(function(i,el){
1543
+ this.each(function(i, el){
1491
1544
  $(el).bind('touchstart touchmove touchend touchcancel', function(event) {
1492
1545
  //we pass the original event object because the jQuery event
1493
1546
  //object is normalized to w3c specs and does not provide the TouchList
@@ -1495,7 +1548,7 @@ Touch.setupTouchHandler = function($) {
1495
1548
  });
1496
1549
  });
1497
1550
 
1498
- var handleTouch = function(event){
1551
+ var handleTouch = function(event) {
1499
1552
  var touches = event.changedTouches,
1500
1553
  first = touches[0],
1501
1554
  eventTypes = {
@@ -1525,8 +1578,7 @@ Touch.setupTouchHandler = function($) {
1525
1578
  };
1526
1579
  };
1527
1580
 
1528
- Touch.init = function ($) {
1529
-
1581
+ Touch.init = function () {
1530
1582
  if(typeof($.spotSwipe) === 'undefined') {
1531
1583
  Touch.setupSpotSwipe($);
1532
1584
  Touch.setupTouchHandler($);
@@ -1541,7 +1593,7 @@ const MutationObserver = (function () {
1541
1593
  }
1542
1594
  }
1543
1595
  return false;
1544
- }());
1596
+ })();
1545
1597
 
1546
1598
  const triggers = (el, type) => {
1547
1599
  el.data(type).split(' ').forEach(id => {
@@ -1588,7 +1640,7 @@ Triggers.Listeners.Basic = {
1588
1640
  Motion.animateOut($(this), animation, function() {
1589
1641
  $(this).trigger('closed.zf');
1590
1642
  });
1591
- }else{
1643
+ }else {
1592
1644
  $(this).fadeOut().trigger('closed.zf');
1593
1645
  }
1594
1646
  },
@@ -1672,7 +1724,7 @@ Triggers.Initializers.addClosemeListener = function(pluginName) {
1672
1724
  plugNames.push(pluginName);
1673
1725
  }else if(typeof pluginName === 'object' && typeof pluginName[0] === 'string'){
1674
1726
  plugNames = plugNames.concat(pluginName);
1675
- }else{
1727
+ }else {
1676
1728
  console.error('Plugin names must be strings');
1677
1729
  }
1678
1730
  }
@@ -1687,11 +1739,11 @@ Triggers.Initializers.addClosemeListener = function(pluginName) {
1687
1739
 
1688
1740
  function debounceGlobalListener(debounce, trigger, listener) {
1689
1741
  let timer, args = Array.prototype.slice.call(arguments, 3);
1690
- $(window).off(trigger).on(trigger, function(e) {
1742
+ $(window).on(trigger, function() {
1691
1743
  if (timer) { clearTimeout(timer); }
1692
1744
  timer = setTimeout(function(){
1693
1745
  listener.apply(null, args);
1694
- }, debounce || 10);//default time to emit scroll event
1746
+ }, debounce || 10); //default time to emit scroll event
1695
1747
  });
1696
1748
  }
1697
1749
 
@@ -1766,13 +1818,13 @@ Triggers.Initializers.addSimpleListeners = function() {
1766
1818
  Triggers.Initializers.addGlobalListeners = function() {
1767
1819
  let $document = $(document);
1768
1820
  Triggers.Initializers.addMutationEventsListener($document);
1769
- Triggers.Initializers.addResizeListener();
1821
+ Triggers.Initializers.addResizeListener(250);
1770
1822
  Triggers.Initializers.addScrollListener();
1771
1823
  Triggers.Initializers.addClosemeListener();
1772
1824
  };
1773
1825
 
1774
1826
 
1775
- Triggers.init = function ($, Foundation) {
1827
+ Triggers.init = function (__, Foundation) {
1776
1828
  onLoad($(window), function () {
1777
1829
  if ($.triggersInitialized !== true) {
1778
1830
  Triggers.Initializers.addSimpleListeners();
@@ -1817,23 +1869,21 @@ class Plugin {
1817
1869
  */
1818
1870
  .trigger(`destroyed.zf.${pluginName}`);
1819
1871
  for(var prop in this){
1820
- this[prop] = null;//clean up script to prep for garbage collection.
1872
+ if (this.hasOwnProperty(prop)) {
1873
+ this[prop] = null; //clean up script to prep for garbage collection.
1874
+ }
1821
1875
  }
1822
1876
  }
1823
1877
  }
1824
1878
 
1825
1879
  // Convert PascalCase to kebab-case
1826
1880
  // Thank you: http://stackoverflow.com/a/8955580
1827
- function hyphenate$1(str) {
1881
+ function hyphenate(str) {
1828
1882
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
1829
1883
  }
1830
1884
 
1831
1885
  function getPluginName(obj) {
1832
- if(typeof(obj.constructor.name) !== 'undefined') {
1833
- return hyphenate$1(obj.constructor.name);
1834
- } else {
1835
- return hyphenate$1(obj.className);
1836
- }
1886
+ return hyphenate(obj.className);
1837
1887
  }
1838
1888
 
1839
1889
  /**
@@ -1947,15 +1997,15 @@ class Abide extends Plugin {
1947
1997
  return true;
1948
1998
  } else if (typeof this.formnovalidate === 'boolean') { // triggered by $submit
1949
1999
  return this.formnovalidate;
1950
- } else { // triggered by Enter in non-submit input
1951
- return this.$submits.length ? this.$submits[0].getAttribute('formnovalidate') !== null : false;
1952
2000
  }
2001
+ // triggered by Enter in non-submit input
2002
+ return this.$submits.length ? this.$submits[0].getAttribute('formnovalidate') !== null : false;
1953
2003
  }
1954
2004
 
1955
2005
  /**
1956
2006
  * Enables the whole validation
1957
2007
  */
1958
- enableValidation(){
2008
+ enableValidation() {
1959
2009
  this.isEnabled = true;
1960
2010
  }
1961
2011
 
@@ -1989,7 +2039,7 @@ class Abide extends Plugin {
1989
2039
  break;
1990
2040
 
1991
2041
  default:
1992
- if(!$el.val() || !$el.val().length) isGood = false;
2042
+ if (!$el.val() || !$el.val().length) isGood = false;
1993
2043
  }
1994
2044
 
1995
2045
  return isGood;
@@ -2005,9 +2055,10 @@ class Abide extends Plugin {
2005
2055
  * This allows for multiple form errors per input, though if none are found, no form errors will be shown.
2006
2056
  *
2007
2057
  * @param {Object} $el - jQuery object to use as reference to find the form error selector.
2058
+ * @param {String[]} [failedValidators] - List of failed validators.
2008
2059
  * @returns {Object} jQuery object with the selector.
2009
2060
  */
2010
- findFormError($el) {
2061
+ findFormError($el, failedValidators) {
2011
2062
  var id = $el.length ? $el[0].id : '';
2012
2063
  var $error = $el.siblings(this.options.formErrorSelector);
2013
2064
 
@@ -2019,6 +2070,15 @@ class Abide extends Plugin {
2019
2070
  $error = $error.add(this.$element.find(`[data-form-error-for="${id}"]`));
2020
2071
  }
2021
2072
 
2073
+ if (!!failedValidators) {
2074
+ $error = $error.not('[data-form-error-on]');
2075
+
2076
+ failedValidators.forEach((v) => {
2077
+ $error = $error.add($el.siblings(`[data-form-error-on="${v}"]`));
2078
+ $error = $error.add(this.$element.find(`[data-form-error-for="${id}"][data-form-error-on="${v}"]`));
2079
+ });
2080
+ }
2081
+
2022
2082
  return $error;
2023
2083
  }
2024
2084
 
@@ -2088,10 +2148,11 @@ class Abide extends Plugin {
2088
2148
  /**
2089
2149
  * Adds the CSS error class as specified by the Abide settings to the label, input, and the form
2090
2150
  * @param {Object} $el - jQuery object to add the class to
2151
+ * @param {String[]} [failedValidators] - List of failed validators.
2091
2152
  */
2092
- addErrorClasses($el) {
2153
+ addErrorClasses($el, failedValidators) {
2093
2154
  var $label = this.findLabel($el);
2094
- var $formError = this.findFormError($el);
2155
+ var $formError = this.findFormError($el, failedValidators);
2095
2156
 
2096
2157
  if ($label.length) {
2097
2158
  $label.addClass(this.options.labelErrorClass);
@@ -2105,6 +2166,10 @@ class Abide extends Plugin {
2105
2166
  'data-invalid': '',
2106
2167
  'aria-invalid': true
2107
2168
  });
2169
+
2170
+ if ($formError.filter(':visible').length) {
2171
+ this.addA11yErrorDescribe($el, $formError);
2172
+ }
2108
2173
  }
2109
2174
 
2110
2175
  /**
@@ -2115,18 +2180,11 @@ class Abide extends Plugin {
2115
2180
  addA11yAttributes($el) {
2116
2181
  let $errors = this.findFormError($el);
2117
2182
  let $labels = $errors.filter('label');
2118
- let $error = $errors.first();
2119
2183
  if (!$errors.length) return;
2120
2184
 
2121
- // Set [aria-describedby] on the input toward the first form error if it is not set
2122
- if (typeof $el.attr('aria-describedby') === 'undefined') {
2123
- // Get the first error ID or create one
2124
- let errorId = $error.attr('id');
2125
- if (typeof errorId === 'undefined') {
2126
- errorId = GetYoDigits(6, 'abide-error');
2127
- $error.attr('id', errorId);
2128
- }
2129
- $el.attr('aria-describedby', errorId);
2185
+ let $error = $errors.filter(':visible').first();
2186
+ if ($error.length) {
2187
+ this.addA11yErrorDescribe($el, $error);
2130
2188
  }
2131
2189
 
2132
2190
  if ($labels.filter('[for]').length < $labels.length) {
@@ -2136,6 +2194,7 @@ class Abide extends Plugin {
2136
2194
  elemId = GetYoDigits(6, 'abide-input');
2137
2195
  $el.attr('id', elemId);
2138
2196
  }
2197
+
2139
2198
  // For each label targeting $el, set [for] if it is not set.
2140
2199
  $labels.each((i, label) => {
2141
2200
  const $label = $(label);
@@ -2152,6 +2211,21 @@ class Abide extends Plugin {
2152
2211
  }).end();
2153
2212
  }
2154
2213
 
2214
+ addA11yErrorDescribe($el, $error) {
2215
+ if ($el.attr('type') === 'hidden') return;
2216
+ if (typeof $el.attr('aria-describedby') !== 'undefined') return;
2217
+
2218
+ // Set [aria-describedby] on the input toward the first form error if it is not set
2219
+ // Get the first error ID or create one
2220
+ let errorId = $error.attr('id');
2221
+ if (typeof errorId === 'undefined') {
2222
+ errorId = GetYoDigits(6, 'abide-error');
2223
+ $error.attr('id', errorId);
2224
+ }
2225
+
2226
+ $el.attr('aria-describedby', errorId).data('abide-describedby', true);
2227
+ }
2228
+
2155
2229
  /**
2156
2230
  * Adds [aria-live] attribute to the given global form error $el.
2157
2231
  * @param {Object} $el - jQuery object to add the attribute to
@@ -2217,11 +2291,11 @@ class Abide extends Plugin {
2217
2291
  */
2218
2292
  removeErrorClasses($el) {
2219
2293
  // radios need to clear all of the els
2220
- if($el[0].type == 'radio') {
2294
+ if ($el[0].type === 'radio') {
2221
2295
  return this.removeRadioErrorClasses($el.attr('name'));
2222
2296
  }
2223
2297
  // checkboxes need to clear all of the els
2224
- else if($el[0].type == 'checkbox') {
2298
+ else if ($el[0].type === 'checkbox') {
2225
2299
  return this.removeCheckboxErrorClasses($el.attr('name'));
2226
2300
  }
2227
2301
 
@@ -2240,6 +2314,10 @@ class Abide extends Plugin {
2240
2314
  'data-invalid': null,
2241
2315
  'aria-invalid': null
2242
2316
  });
2317
+
2318
+ if ($el.data('abide-describedby')) {
2319
+ $el.removeAttr('aria-describedby').removeData('abide-describedby');
2320
+ }
2243
2321
  }
2244
2322
 
2245
2323
  /**
@@ -2252,10 +2330,9 @@ class Abide extends Plugin {
2252
2330
  */
2253
2331
  validateInput($el) {
2254
2332
  var clearRequire = this.requiredCheck($el),
2255
- validated = false,
2256
- customValidator = true,
2257
2333
  validator = $el.attr('data-validator'),
2258
- equalTo = true;
2334
+ failedValidators = [],
2335
+ manageErrorClasses = true;
2259
2336
 
2260
2337
  // skip validation if disabled
2261
2338
  if (this._validationIsDisabled()) {
@@ -2269,34 +2346,39 @@ class Abide extends Plugin {
2269
2346
 
2270
2347
  switch ($el[0].type) {
2271
2348
  case 'radio':
2272
- validated = this.validateRadio($el.attr('name'));
2349
+ this.validateRadio($el.attr('name')) || failedValidators.push('required');
2273
2350
  break;
2274
2351
 
2275
2352
  case 'checkbox':
2276
- validated = this.validateCheckbox($el.attr('name'));
2277
- clearRequire = true;
2353
+ this.validateCheckbox($el.attr('name')) || failedValidators.push('required');
2354
+ // validateCheckbox() adds/removes error classes
2355
+ manageErrorClasses = false;
2278
2356
  break;
2279
2357
 
2280
2358
  case 'select':
2281
2359
  case 'select-one':
2282
2360
  case 'select-multiple':
2283
- validated = clearRequire;
2361
+ clearRequire || failedValidators.push('required');
2284
2362
  break;
2285
2363
 
2286
2364
  default:
2287
- validated = this.validateText($el);
2365
+ clearRequire || failedValidators.push('required');
2366
+ this.validateText($el) || failedValidators.push('pattern');
2288
2367
  }
2289
2368
 
2290
2369
  if (validator) {
2291
- customValidator = this.matchValidation($el, validator, $el.attr('required'));
2370
+ const required = $el.attr('required') ? true : false;
2371
+
2372
+ validator.split(' ').forEach((v) => {
2373
+ this.options.validators[v]($el, required, $el.parent()) || failedValidators.push(v);
2374
+ });
2292
2375
  }
2293
2376
 
2294
2377
  if ($el.attr('data-equalto')) {
2295
- equalTo = this.options.validators.equalTo($el);
2378
+ this.options.validators.equalTo($el) || failedValidators.push('equalTo');
2296
2379
  }
2297
2380
 
2298
-
2299
- var goodToGo = [clearRequire, validated, customValidator, equalTo].indexOf(false) === -1;
2381
+ var goodToGo = failedValidators.length === 0;
2300
2382
  var message = (goodToGo ? 'valid' : 'invalid') + '.zf.abide';
2301
2383
 
2302
2384
  if (goodToGo) {
@@ -2312,7 +2394,12 @@ class Abide extends Plugin {
2312
2394
  }
2313
2395
  }
2314
2396
 
2315
- this[goodToGo ? 'removeErrorClasses' : 'addErrorClasses']($el);
2397
+ if (manageErrorClasses) {
2398
+ this.removeErrorClasses($el);
2399
+ if (!goodToGo) {
2400
+ this.addErrorClasses($el, failedValidators);
2401
+ }
2402
+ }
2316
2403
 
2317
2404
  /**
2318
2405
  * Fires when the input is done checking for validation. Event trigger is either `valid.zf.abide` or `invalid.zf.abide`
@@ -2389,7 +2476,7 @@ class Abide extends Plugin {
2389
2476
  // A pattern can be passed to this function, or it will be infered from the input's "pattern" attribute, or it's "type" attribute
2390
2477
  pattern = (pattern || $el.attr('data-pattern') || $el.attr('pattern') || $el.attr('type'));
2391
2478
  var inputText = $el.val();
2392
- var valid = false;
2479
+ var valid = true;
2393
2480
 
2394
2481
  if (inputText.length) {
2395
2482
  // If the pattern attribute on the element is in Abide's list of patterns, then test that regexp
@@ -2400,13 +2487,6 @@ class Abide extends Plugin {
2400
2487
  else if (pattern !== $el.attr('type')) {
2401
2488
  valid = new RegExp(pattern).test(inputText);
2402
2489
  }
2403
- else {
2404
- valid = true;
2405
- }
2406
- }
2407
- // An empty field is valid if it's not required
2408
- else if (!$el.prop('required')) {
2409
- valid = true;
2410
2490
  }
2411
2491
 
2412
2492
  return valid;
@@ -2429,7 +2509,7 @@ class Abide extends Plugin {
2429
2509
  required = true;
2430
2510
  }
2431
2511
  });
2432
- if(!required) valid=true;
2512
+ if (!required) valid=true;
2433
2513
 
2434
2514
  if (!valid) {
2435
2515
  // For the group to be valid, at least one radio needs to be checked
@@ -2439,6 +2519,7 @@ class Abide extends Plugin {
2439
2519
  }
2440
2520
  });
2441
2521
  }
2522
+
2442
2523
  return valid;
2443
2524
  }
2444
2525
 
@@ -2459,7 +2540,7 @@ class Abide extends Plugin {
2459
2540
  required = true;
2460
2541
  }
2461
2542
  });
2462
- if(!required) valid=true;
2543
+ if (!required) valid=true;
2463
2544
 
2464
2545
  if (!valid) {
2465
2546
  // Count checked checkboxes within the group
@@ -2469,7 +2550,7 @@ class Abide extends Plugin {
2469
2550
  checked++;
2470
2551
  }
2471
2552
  if (typeof $(e).attr('data-min-required') !== 'undefined') {
2472
- minRequired = parseInt($(e).attr('data-min-required'));
2553
+ minRequired = parseInt($(e).attr('data-min-required'), 10);
2473
2554
  }
2474
2555
  });
2475
2556
 
@@ -2478,6 +2559,7 @@ class Abide extends Plugin {
2478
2559
  valid = true;
2479
2560
  }
2480
2561
  }
2562
+
2481
2563
  // Skip validation if more than 1 checkbox have to be checked AND if the form hasn't got submitted yet (otherwise it will already show an error during the first fill in)
2482
2564
  if (this.initialized !== true && minRequired > 1) {
2483
2565
  return true;
@@ -2486,7 +2568,7 @@ class Abide extends Plugin {
2486
2568
  // Refresh error class for all input
2487
2569
  $group.each((i, e) => {
2488
2570
  if (!valid) {
2489
- this.addErrorClasses($(e));
2571
+ this.addErrorClasses($(e), ['required']);
2490
2572
  } else {
2491
2573
  this.removeErrorClasses($(e));
2492
2574
  }
@@ -2648,6 +2730,7 @@ Abide.defaults = {
2648
2730
 
2649
2731
  patterns: {
2650
2732
  alpha : /^[a-zA-Z]+$/,
2733
+ // eslint-disable-next-line camelcase
2651
2734
  alpha_numeric : /^[a-zA-Z0-9]+$/,
2652
2735
  integer : /^[-+]?\d+$/,
2653
2736
  number : /^[-+]?\d*(?:[\.\,]\d+)?$/,
@@ -2674,8 +2757,10 @@ Abide.defaults = {
2674
2757
  time : /^(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}$/,
2675
2758
  dateISO : /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
2676
2759
  // MM/DD/YYYY
2760
+ // eslint-disable-next-line camelcase
2677
2761
  month_day_year : /^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]\d{4}$/,
2678
2762
  // DD/MM/YYYY
2763
+ // eslint-disable-next-line camelcase
2679
2764
  day_month_year : /^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]\d{4}$/,
2680
2765
 
2681
2766
  // #FFF or #FFFFFF
@@ -2684,7 +2769,7 @@ Abide.defaults = {
2684
2769
  // Domain || URL
2685
2770
  website: {
2686
2771
  test: (text) => {
2687
- return Abide.defaults.patterns['domain'].test(text) || Abide.defaults.patterns['url'].test(text);
2772
+ return Abide.defaults.patterns.domain.test(text) || Abide.defaults.patterns.url.test(text);
2688
2773
  }
2689
2774
  }
2690
2775
  },
@@ -2693,12 +2778,10 @@ Abide.defaults = {
2693
2778
  * Optional validation functions to be used. `equalTo` being the only default included function.
2694
2779
  * Functions should return only a boolean if the input is valid or not. Functions are given the following arguments:
2695
2780
  * el : The jQuery element to validate.
2696
- * required : Boolean value of the required attribute be present or not.
2697
- * parent : The direct parent of the input.
2698
2781
  * @option
2699
2782
  */
2700
2783
  validators: {
2701
- equalTo: function (el, required, parent) {
2784
+ equalTo: function (el) {
2702
2785
  return $(`#${el.attr('data-equalto')}`).val() === el.val();
2703
2786
  }
2704
2787
  }
@@ -2730,7 +2813,9 @@ class Accordion extends Plugin {
2730
2813
  'ENTER': 'toggle',
2731
2814
  'SPACE': 'toggle',
2732
2815
  'ARROW_DOWN': 'next',
2733
- 'ARROW_UP': 'previous'
2816
+ 'ARROW_UP': 'previous',
2817
+ 'HOME': 'first',
2818
+ 'END': 'last',
2734
2819
  });
2735
2820
  }
2736
2821
 
@@ -2741,10 +2826,8 @@ class Accordion extends Plugin {
2741
2826
  _init() {
2742
2827
  this._isInitializing = true;
2743
2828
 
2744
- this.$element.attr('role', 'tablist');
2745
2829
  this.$tabs = this.$element.children('[data-accordion-item]');
2746
-
2747
- this.$tabs.attr({'role': 'presentation'});
2830
+
2748
2831
 
2749
2832
  this.$tabs.each(function(idx, el) {
2750
2833
  var $el = $(el),
@@ -2754,13 +2837,11 @@ class Accordion extends Plugin {
2754
2837
 
2755
2838
  $el.find('a:first').attr({
2756
2839
  'aria-controls': id,
2757
- 'role': 'tab',
2758
2840
  'id': linkId,
2759
- 'aria-expanded': false,
2760
- 'aria-selected': false
2841
+ 'aria-expanded': false
2761
2842
  });
2762
2843
 
2763
- $content.attr({'role': 'tabpanel', 'aria-labelledby': linkId, 'aria-hidden': true, 'id': id});
2844
+ $content.attr({'role': 'region', 'aria-labelledby': linkId, 'aria-hidden': true, 'id': id});
2764
2845
  });
2765
2846
 
2766
2847
  var $initActive = this.$element.find('.is-active').children('[data-tab-content]');
@@ -2790,7 +2871,8 @@ class Accordion extends Plugin {
2790
2871
  if ($anchor && $link && $link.length) {
2791
2872
  if (!$link.parent('[data-accordion-item]').hasClass('is-active')) {
2792
2873
  this._openSingleTab($anchor);
2793
- } }
2874
+ }
2875
+ }
2794
2876
  // Otherwise, close everything
2795
2877
  else {
2796
2878
  this._closeAllTabs();
@@ -2800,7 +2882,7 @@ class Accordion extends Plugin {
2800
2882
  if (this.options.deepLinkSmudge) {
2801
2883
  onLoad($(window), () => {
2802
2884
  var offset = this.$element.offset();
2803
- $('html, body').animate({ scrollTop: offset.top }, this.options.deepLinkSmudgeDelay);
2885
+ $('html, body').animate({ scrollTop: offset.top - this.options.deepLinkSmudgeOffset }, this.options.deepLinkSmudgeDelay);
2804
2886
  });
2805
2887
  }
2806
2888
 
@@ -2837,7 +2919,7 @@ class Accordion extends Plugin {
2837
2919
  .on('click.zf.accordion', function(e) {
2838
2920
  e.preventDefault();
2839
2921
  _this.toggle($tabContent);
2840
- }).on('keydown.zf.accordion', function(e){
2922
+ }).on('keydown.zf.accordion', function(e) {
2841
2923
  Keyboard.handleKey(e, 'Accordion', {
2842
2924
  toggle: function() {
2843
2925
  _this.toggle($tabContent);
@@ -2854,6 +2936,18 @@ class Accordion extends Plugin {
2854
2936
  $a.trigger('click.zf.accordion');
2855
2937
  }
2856
2938
  },
2939
+ first: function() {
2940
+ var $a = _this.$tabs.first().find('.accordion-title').focus();
2941
+ if (!_this.options.multiExpand) {
2942
+ $a.trigger('click.zf.accordion');
2943
+ }
2944
+ },
2945
+ last: function() {
2946
+ var $a = _this.$tabs.last().find('.accordion-title').focus();
2947
+ if (!_this.options.multiExpand) {
2948
+ $a.trigger('click.zf.accordion');
2949
+ }
2950
+ },
2857
2951
  handled: function() {
2858
2952
  e.preventDefault();
2859
2953
  }
@@ -2861,7 +2955,7 @@ class Accordion extends Plugin {
2861
2955
  });
2862
2956
  }
2863
2957
  });
2864
- if(this.options.deepLink) {
2958
+ if (this.options.deepLink) {
2865
2959
  $(window).on('hashchange', this._checkDeepLink);
2866
2960
  }
2867
2961
  }
@@ -2876,7 +2970,7 @@ class Accordion extends Plugin {
2876
2970
  console.info('Cannot toggle an accordion that is disabled.');
2877
2971
  return;
2878
2972
  }
2879
- if($target.parent().hasClass('is-active')) {
2973
+ if ($target.parent().hasClass('is-active')) {
2880
2974
  this.up($target);
2881
2975
  } else {
2882
2976
  this.down($target);
@@ -2968,11 +3062,10 @@ class Accordion extends Plugin {
2968
3062
  $targetItem.addClass('is-active');
2969
3063
 
2970
3064
  $(`#${targetContentId}`).attr({
2971
- 'aria-expanded': true,
2972
- 'aria-selected': true
3065
+ 'aria-expanded': true
2973
3066
  });
2974
3067
 
2975
- $target.slideDown(this.options.slideSpeed, () => {
3068
+ $target.finish().slideDown(this.options.slideSpeed, () => {
2976
3069
  /**
2977
3070
  * Fires when the tab is done opening.
2978
3071
  * @event Accordion#down
@@ -2996,11 +3089,10 @@ class Accordion extends Plugin {
2996
3089
  $targetItem.removeClass('is-active');
2997
3090
 
2998
3091
  $(`#${targetContentId}`).attr({
2999
- 'aria-expanded': false,
3000
- 'aria-selected': false
3092
+ 'aria-expanded': false
3001
3093
  });
3002
3094
 
3003
- $target.slideUp(this.options.slideSpeed, () => {
3095
+ $target.finish().slideUp(this.options.slideSpeed, () => {
3004
3096
  /**
3005
3097
  * Fires when the tab is done collapsing up.
3006
3098
  * @event Accordion#up
@@ -3030,7 +3122,7 @@ class Accordion extends Plugin {
3030
3122
  _destroy() {
3031
3123
  this.$element.find('[data-tab-content]').stop(true).slideUp(0).css('display', '');
3032
3124
  this.$element.find('a').off('.zf.accordion');
3033
- if(this.options.deepLink) {
3125
+ if (this.options.deepLink) {
3034
3126
  $(window).off('hashchange', this._checkDeepLink);
3035
3127
  }
3036
3128
 
@@ -3081,6 +3173,13 @@ Accordion.defaults = {
3081
3173
  * @default 300
3082
3174
  */
3083
3175
  deepLinkSmudgeDelay: 300,
3176
+ /**
3177
+ * If `deepLinkSmudge` is enabled, the offset for scrollToTtop to prevent overlap by a sticky element at the top of the page
3178
+ * @option
3179
+ * @type {number}
3180
+ * @default 0
3181
+ */
3182
+ deepLinkSmudgeOffset: 0,
3084
3183
  /**
3085
3184
  * If `deepLink` is enabled, update the browser history with the open accordion
3086
3185
  * @option
@@ -3137,24 +3236,23 @@ class AccordionMenu extends Plugin {
3137
3236
 
3138
3237
  this.$element.find('[data-submenu]').not('.is-active').slideUp(0);//.find('a').css('padding-left', '1rem');
3139
3238
  this.$element.attr({
3140
- 'role': 'tree',
3141
3239
  'aria-multiselectable': this.options.multiOpen
3142
3240
  });
3143
3241
 
3144
3242
  this.$menuLinks = this.$element.find('.is-accordion-submenu-parent');
3145
- this.$menuLinks.each(function(){
3243
+ this.$menuLinks.each(function() {
3146
3244
  var linkId = this.id || GetYoDigits(6, 'acc-menu-link'),
3147
3245
  $elem = $(this),
3148
3246
  $sub = $elem.children('[data-submenu]'),
3149
3247
  subId = $sub[0].id || GetYoDigits(6, 'acc-menu'),
3150
3248
  isActive = $sub.hasClass('is-active');
3151
3249
 
3152
- if(_this.options.parentLink) {
3250
+ if (_this.options.parentLink) {
3153
3251
  let $anchor = $elem.children('a');
3154
3252
  $anchor.clone().prependTo($sub).wrap('<li data-is-parent-link class="is-submenu-parent-item is-submenu-item is-accordion-submenu-item"></li>');
3155
3253
  }
3156
3254
 
3157
- if(_this.options.submenuToggle) {
3255
+ if (_this.options.submenuToggle) {
3158
3256
  $elem.addClass('has-submenu-toggle');
3159
3257
  $elem.children('a').after('<button id="' + linkId + '" class="submenu-toggle" aria-controls="' + subId + '" aria-expanded="' + isActive + '" title="' + _this.options.submenuToggleText + '"><span class="submenu-toggle-text">' + _this.options.submenuToggleText + '</span></button>');
3160
3258
  } else {
@@ -3171,13 +3269,9 @@ class AccordionMenu extends Plugin {
3171
3269
  'id': subId
3172
3270
  });
3173
3271
  });
3174
- this.$element.find('li').attr({
3175
- 'role': 'treeitem'
3176
- });
3177
3272
  var initPanes = this.$element.find('.is-active');
3178
- if(initPanes.length){
3179
- var _this = this;
3180
- initPanes.each(function(){
3273
+ if (initPanes.length) {
3274
+ initPanes.each(function() {
3181
3275
  _this.down($(this));
3182
3276
  });
3183
3277
  }
@@ -3195,8 +3289,8 @@ class AccordionMenu extends Plugin {
3195
3289
  var $submenu = $(this).children('[data-submenu]');
3196
3290
 
3197
3291
  if ($submenu.length) {
3198
- if(_this.options.submenuToggle) {
3199
- $(this).children('.submenu-toggle').off('click.zf.accordionMenu').on('click.zf.accordionMenu', function(e) {
3292
+ if (_this.options.submenuToggle) {
3293
+ $(this).children('.submenu-toggle').off('click.zf.accordionMenu').on('click.zf.accordionMenu', function() {
3200
3294
  _this.toggle($submenu);
3201
3295
  });
3202
3296
  } else {
@@ -3206,7 +3300,7 @@ class AccordionMenu extends Plugin {
3206
3300
  });
3207
3301
  }
3208
3302
  }
3209
- }).on('keydown.zf.accordionMenu', function(e){
3303
+ }).on('keydown.zf.accordionMenu', function(e) {
3210
3304
  var $element = $(this),
3211
3305
  $elements = $element.parent('ul').children('li'),
3212
3306
  $prevElement,
@@ -3299,8 +3393,8 @@ class AccordionMenu extends Plugin {
3299
3393
  * @function
3300
3394
  * @param {jQuery} $target - the submenu to toggle
3301
3395
  */
3302
- toggle($target){
3303
- if(!$target.is(':animated')) {
3396
+ toggle($target) {
3397
+ if (!$target.is(':animated')) {
3304
3398
  if (!$target.is(':hidden')) {
3305
3399
  this.up($target);
3306
3400
  }
@@ -3334,7 +3428,7 @@ class AccordionMenu extends Plugin {
3334
3428
  .addClass('is-active')
3335
3429
  .attr({ 'aria-hidden': false });
3336
3430
 
3337
- if(this.options.submenuToggle) {
3431
+ if (this.options.submenuToggle) {
3338
3432
  $target.prev('.submenu-toggle').attr({'aria-expanded': true});
3339
3433
  }
3340
3434
  else {
@@ -3364,7 +3458,7 @@ class AccordionMenu extends Plugin {
3364
3458
  .removeClass('is-active')
3365
3459
  .attr('aria-hidden', true);
3366
3460
 
3367
- if(this.options.submenuToggle) {
3461
+ if (this.options.submenuToggle) {
3368
3462
  $allmenus.prev('.submenu-toggle').attr('aria-expanded', false);
3369
3463
  }
3370
3464
  else {
@@ -3389,7 +3483,7 @@ class AccordionMenu extends Plugin {
3389
3483
  this.$element.find('a').off('click.zf.accordionMenu');
3390
3484
  this.$element.find('[data-is-parent-link]').detach();
3391
3485
 
3392
- if(this.options.submenuToggle) {
3486
+ if (this.options.submenuToggle) {
3393
3487
  this.$element.find('.has-submenu-toggle').removeClass('has-submenu-toggle');
3394
3488
  this.$element.find('.submenu-toggle').remove();
3395
3489
  }
@@ -3465,8 +3559,6 @@ class Drilldown extends Plugin {
3465
3559
  'ARROW_DOWN': 'down',
3466
3560
  'ARROW_LEFT': 'previous',
3467
3561
  'ESCAPE': 'close',
3468
- 'TAB': 'down',
3469
- 'SHIFT_TAB': 'up'
3470
3562
  });
3471
3563
  }
3472
3564
 
@@ -3482,12 +3574,11 @@ class Drilldown extends Plugin {
3482
3574
  }
3483
3575
 
3484
3576
  this.$element.attr({
3485
- 'role': 'tree',
3486
3577
  'aria-multiselectable': false
3487
3578
  });
3488
3579
  this.$submenuAnchors = this.$element.find('li.is-drilldown-submenu-parent').children('a');
3489
3580
  this.$submenus = this.$submenuAnchors.parent('li').children('[data-submenu]').attr('role', 'group');
3490
- this.$menuItems = this.$element.find('li').not('.js-drilldown-back').attr('role', 'treeitem').find('a');
3581
+ this.$menuItems = this.$element.find('li').not('.js-drilldown-back').find('a');
3491
3582
 
3492
3583
  // Set the main menu as current by default (unless a submenu is selected)
3493
3584
  // Used to set the wrapper height when the drilldown is closed/reopened from any (sub)menu
@@ -3517,7 +3608,7 @@ class Drilldown extends Plugin {
3517
3608
  var $link = $(this);
3518
3609
  var $sub = $link.parent();
3519
3610
  if(_this.options.parentLink){
3520
- $link.clone().prependTo($sub.children('[data-submenu]')).wrap('<li data-is-parent-link class="is-submenu-parent-item is-submenu-item is-drilldown-submenu-item" role="menuitem"></li>');
3611
+ $link.clone().prependTo($sub.children('[data-submenu]')).wrap('<li data-is-parent-link class="is-submenu-parent-item is-submenu-item is-drilldown-submenu-item" role="none"></li>');
3521
3612
  }
3522
3613
  $link.data('savedHref', $link.attr('href')).removeAttr('href').attr('tabindex', 0);
3523
3614
  $link.children('[data-submenu]')
@@ -3531,7 +3622,7 @@ class Drilldown extends Plugin {
3531
3622
  this.$submenus.each(function(){
3532
3623
  var $menu = $(this),
3533
3624
  $back = $menu.find('.js-drilldown-back');
3534
- if(!$back.length){
3625
+ if(!$back.length) {
3535
3626
  switch (_this.options.backButtonPosition) {
3536
3627
  case "bottom":
3537
3628
  $menu.append(_this.options.backButton);
@@ -3578,7 +3669,7 @@ class Drilldown extends Plugin {
3578
3669
  var _this = this;
3579
3670
 
3580
3671
  $elem.off('click.zf.drilldown')
3581
- .on('click.zf.drilldown', function(e){
3672
+ .on('click.zf.drilldown', function(e) {
3582
3673
  if($(e.target).parentsUntil('ul', 'li').hasClass('is-drilldown-submenu-parent')){
3583
3674
  e.preventDefault();
3584
3675
  }
@@ -3590,9 +3681,9 @@ class Drilldown extends Plugin {
3590
3681
 
3591
3682
  if(_this.options.closeOnClick){
3592
3683
  var $body = $('body');
3593
- $body.off('.zf.drilldown').on('click.zf.drilldown', function(e){
3594
- if (e.target === _this.$element[0] || $.contains(_this.$element[0], e.target)) { return; }
3595
- e.preventDefault();
3684
+ $body.off('.zf.drilldown').on('click.zf.drilldown', function(ev) {
3685
+ if (ev.target === _this.$element[0] || $.contains(_this.$element[0], ev.target)) { return; }
3686
+ ev.preventDefault();
3596
3687
  _this._hideAll();
3597
3688
  $body.off('.zf.drilldown');
3598
3689
  });
@@ -3620,7 +3711,7 @@ class Drilldown extends Plugin {
3620
3711
  */
3621
3712
  _scrollTop() {
3622
3713
  var _this = this;
3623
- var $scrollTopElement = _this.options.scrollTopElement!=''?$(_this.options.scrollTopElement):_this.$element,
3714
+ var $scrollTopElement = _this.options.scrollTopElement !== ''?$(_this.options.scrollTopElement):_this.$element,
3624
3715
  scrollPos = parseInt($scrollTopElement.offset().top+_this.options.scrollTopOffset, 10);
3625
3716
  $('html, body').stop(true).animate({ scrollTop: scrollPos }, _this.options.animationDuration, _this.options.animationEasing,function(){
3626
3717
  /**
@@ -3725,6 +3816,7 @@ class Drilldown extends Plugin {
3725
3816
  _hideAll() {
3726
3817
  var $elem = this.$element.find('.is-drilldown-submenu.is-active');
3727
3818
  $elem.addClass('is-closing');
3819
+ $elem.parent().closest('ul').removeClass('invisible');
3728
3820
 
3729
3821
  if (this.options.autoHeight) {
3730
3822
  const calcHeight = $elem.parent().closest('ul').data('calcHeight');
@@ -3758,8 +3850,7 @@ class Drilldown extends Plugin {
3758
3850
  var _this = this;
3759
3851
  $elem.off('click.zf.drilldown');
3760
3852
  $elem.children('.js-drilldown-back')
3761
- .on('click.zf.drilldown', function(e){
3762
- // console.log('mouseup on back');
3853
+ .on('click.zf.drilldown', function() {
3763
3854
  _this._hide($elem);
3764
3855
 
3765
3856
  // If there is a parent submenu, call show
@@ -3767,6 +3858,9 @@ class Drilldown extends Plugin {
3767
3858
  if (parentSubMenu.length) {
3768
3859
  _this._show(parentSubMenu);
3769
3860
  }
3861
+ else {
3862
+ _this.$currentMenu = _this.$element;
3863
+ }
3770
3864
  });
3771
3865
  }
3772
3866
 
@@ -3779,8 +3873,8 @@ class Drilldown extends Plugin {
3779
3873
  var _this = this;
3780
3874
  this.$menuItems.not('.is-drilldown-submenu-parent')
3781
3875
  .off('click.zf.drilldown')
3782
- .on('click.zf.drilldown', function(e){
3783
- setTimeout(function(){
3876
+ .on('click.zf.drilldown', function() {
3877
+ setTimeout(function() {
3784
3878
  _this._hideAll();
3785
3879
  }, 0);
3786
3880
  });
@@ -3830,7 +3924,7 @@ class Drilldown extends Plugin {
3830
3924
 
3831
3925
  // Reset drilldown
3832
3926
  var $expandedSubmenus = this.$element.find('li[aria-expanded="true"] > ul[data-submenu]');
3833
- $expandedSubmenus.each(function(index) {
3927
+ $expandedSubmenus.each(function() {
3834
3928
  _this._setHideSubMenuClasses($(this));
3835
3929
  });
3836
3930
 
@@ -3839,7 +3933,7 @@ class Drilldown extends Plugin {
3839
3933
 
3840
3934
  // If target menu is root, focus first link & exit
3841
3935
  if ($elem.is('[data-drilldown]')) {
3842
- if (autoFocus === true) $elem.find('li[role="treeitem"] > a').first().focus();
3936
+ if (autoFocus === true) $elem.find('li > a').first().focus();
3843
3937
  if (this.options.autoHeight) this.$wrapper.css('height', $elem.data('calcHeight'));
3844
3938
  return;
3845
3939
  }
@@ -3855,14 +3949,14 @@ class Drilldown extends Plugin {
3855
3949
  _this.$wrapper.css('height', $(this).data('calcHeight'));
3856
3950
  }
3857
3951
 
3858
- var isLastChild = index == $submenus.length - 1;
3952
+ var isLastChild = index === $submenus.length - 1;
3859
3953
 
3860
3954
  // Add transitionsend listener to last child (root due to reverse order) to open target menu's first link
3861
3955
  // Last child makes sure the event gets always triggered even if going through several menus
3862
3956
  if (isLastChild === true) {
3863
3957
  $(this).one(transitionend($(this)), () => {
3864
3958
  if (autoFocus === true) {
3865
- $elem.find('li[role="treeitem"] > a').first().focus();
3959
+ $elem.find('li > a').first().focus();
3866
3960
  }
3867
3961
  });
3868
3962
  }
@@ -3883,7 +3977,14 @@ class Drilldown extends Plugin {
3883
3977
  $elem.attr('aria-expanded', true);
3884
3978
 
3885
3979
  this.$currentMenu = $submenu;
3886
- $submenu.addClass('is-active').removeClass('invisible').attr('aria-hidden', false);
3980
+
3981
+ //hide drilldown parent menu when submenu is open
3982
+ // this removes it from the dom so that the tab key will take the user to the next visible element
3983
+ $elem.parent().closest('ul').addClass('invisible');
3984
+
3985
+ // add visible class to submenu to override invisible class above
3986
+ $submenu.addClass('is-active visible').removeClass('invisible').attr('aria-hidden', false);
3987
+
3887
3988
  if (this.options.autoHeight) {
3888
3989
  this.$wrapper.css({ height: $submenu.data('calcHeight') });
3889
3990
  }
@@ -3903,11 +4004,12 @@ class Drilldown extends Plugin {
3903
4004
  */
3904
4005
  _hide($elem) {
3905
4006
  if(this.options.autoHeight) this.$wrapper.css({height:$elem.parent().closest('ul').data('calcHeight')});
4007
+ $elem.parent().closest('ul').removeClass('invisible');
3906
4008
  $elem.parent('li').attr('aria-expanded', false);
3907
4009
  $elem.attr('aria-hidden', true);
3908
4010
  $elem.addClass('is-closing')
3909
4011
  .one(transitionend($elem), function(){
3910
- $elem.removeClass('is-active is-closing');
4012
+ $elem.removeClass('is-active is-closing visible');
3911
4013
  $elem.blur().addClass('invisible');
3912
4014
  });
3913
4015
  /**
@@ -3928,7 +4030,6 @@ class Drilldown extends Plugin {
3928
4030
 
3929
4031
  // Recalculate menu heights and total max height
3930
4032
  this.$submenus.add(this.$element).each(function(){
3931
- var numOfElems = $(this).children('li').length;
3932
4033
  var height = Box.GetDimensions(this).height;
3933
4034
 
3934
4035
  maxHeight = height > maxHeight ? height : maxHeight;
@@ -3939,7 +4040,7 @@ class Drilldown extends Plugin {
3939
4040
  });
3940
4041
 
3941
4042
  if (this.options.autoHeight)
3942
- result['height'] = this.$currentMenu.data('calcHeight');
4043
+ result.height = this.$currentMenu.data('calcHeight');
3943
4044
  else
3944
4045
  result['min-height'] = `${maxHeight}px`;
3945
4046
 
@@ -3953,13 +4054,14 @@ class Drilldown extends Plugin {
3953
4054
  * @function
3954
4055
  */
3955
4056
  _destroy() {
4057
+ $('body').off('.zf.drilldown');
3956
4058
  if(this.options.scrollTop) this.$element.off('.zf.drilldown',this._bindHandler);
3957
4059
  this._hideAll();
3958
4060
  this.$element.off('mutateme.zf.trigger');
3959
4061
  Nest.Burn(this.$element, 'drilldown');
3960
4062
  this.$element.unwrap()
3961
4063
  .find('.js-drilldown-back, .is-submenu-parent-item').remove()
3962
- .end().find('.is-active, .is-closing, .is-drilldown-submenu').removeClass('is-active is-closing is-drilldown-submenu')
4064
+ .end().find('.is-active, .is-closing, .is-drilldown-submenu').removeClass('is-active is-closing is-drilldown-submenu').off('transitionend otransitionend webkitTransitionEnd')
3963
4065
  .end().find('[data-submenu]').removeAttr('aria-hidden tabindex role');
3964
4066
  this.$submenuAnchors.each(function() {
3965
4067
  $(this).off('.zf.drilldown');
@@ -3973,7 +4075,7 @@ class Drilldown extends Plugin {
3973
4075
  $link.removeAttr('tabindex');
3974
4076
  if($link.data('savedHref')){
3975
4077
  $link.attr('href', $link.data('savedHref')).removeData('savedHref');
3976
- }else{ return; }
4078
+ }else { return; }
3977
4079
  });
3978
4080
  };
3979
4081
  }
@@ -4170,7 +4272,7 @@ class Positionable extends Plugin {
4170
4272
  }
4171
4273
 
4172
4274
  _alignmentsExhausted(position) {
4173
- return this.triedPositions[position] && this.triedPositions[position].length == ALIGNMENTS[position].length;
4275
+ return this.triedPositions[position] && this.triedPositions[position].length === ALIGNMENTS[position].length;
4174
4276
  }
4175
4277
 
4176
4278
 
@@ -4333,7 +4435,7 @@ class Dropdown extends Positionable {
4333
4435
 
4334
4436
  if(this.options.parentClass){
4335
4437
  this.$parent = this.$element.parents('.' + this.options.parentClass);
4336
- }else{
4438
+ }else {
4337
4439
  this.$parent = null;
4338
4440
  }
4339
4441
 
@@ -4343,6 +4445,7 @@ class Dropdown extends Positionable {
4343
4445
  if (typeof this.$currentAnchor.attr('id') === 'undefined') {
4344
4446
  this.$currentAnchor.attr('id', GetYoDigits(6, 'dd-anchor'));
4345
4447
  }
4448
+
4346
4449
  this.$element.attr('aria-labelledby', this.$currentAnchor.attr('id'));
4347
4450
  }
4348
4451
 
@@ -4421,12 +4524,13 @@ class Dropdown extends Positionable {
4421
4524
  .on('click.zf.trigger', function(e) {
4422
4525
  _this._setCurrentAnchor(this);
4423
4526
 
4424
- if (_this.options.forceFollow === false) {
4527
+ if (
4425
4528
  // if forceFollow false, always prevent default action
4426
- e.preventDefault();
4427
- } else if (hasTouch && _this.options.hover && _this.$element.hasClass('is-open') === false) {
4529
+ (_this.options.forceFollow === false) ||
4428
4530
  // if forceFollow true and hover option true, only prevent default action on 1st click
4429
4531
  // on 2nd click (dropown opened) the default action (e.g. follow a href) gets executed
4532
+ (hasTouch && _this.options.hover && _this.$element.hasClass('is-open') === false)
4533
+ ) {
4430
4534
  e.preventDefault();
4431
4535
  }
4432
4536
  });
@@ -4466,8 +4570,7 @@ class Dropdown extends Positionable {
4466
4570
  }
4467
4571
  this.$anchors.add(this.$element).on('keydown.zf.dropdown', function(e) {
4468
4572
 
4469
- var $target = $(this),
4470
- visibleFocusableElements = Keyboard.findFocusable(_this.$element);
4573
+ var $target = $(this);
4471
4574
 
4472
4575
  Keyboard.handleKey(e, 'Dropdown', {
4473
4576
  open: function() {
@@ -4582,7 +4685,7 @@ class Dropdown extends Positionable {
4582
4685
  if(this.$element.hasClass('is-open')){
4583
4686
  if(this.$anchors.data('hover')) return;
4584
4687
  this.close();
4585
- }else{
4688
+ }else {
4586
4689
  this.open();
4587
4690
  }
4588
4691
  }
@@ -4751,8 +4854,8 @@ class DropdownMenu extends Plugin {
4751
4854
  var subs = this.$element.find('li.is-dropdown-submenu-parent');
4752
4855
  this.$element.children('.is-dropdown-submenu-parent').children('.is-dropdown-submenu').addClass('first-sub');
4753
4856
 
4754
- this.$menuItems = this.$element.find('[role="menuitem"]');
4755
- this.$tabs = this.$element.children('[role="menuitem"]');
4857
+ this.$menuItems = this.$element.find('li[role="none"]');
4858
+ this.$tabs = this.$element.children('li[role="none"]');
4756
4859
  this.$tabs.find('ul.is-dropdown-submenu').addClass(this.options.verticalClass);
4757
4860
 
4758
4861
  if (this.options.alignment === 'auto') {
@@ -4806,10 +4909,12 @@ class DropdownMenu extends Plugin {
4806
4909
  || (_this.options.forceFollow && hasTouch)) {
4807
4910
  return;
4808
4911
  }
4912
+ e.stopImmediatePropagation();
4809
4913
  e.preventDefault();
4810
4914
  _this._hide($elem);
4811
4915
  }
4812
4916
  else {
4917
+ e.stopImmediatePropagation();
4813
4918
  e.preventDefault();
4814
4919
  _this._show($sub);
4815
4920
  $elem.add($elem.parentsUntil(_this.$element, `.${parClass}`)).attr('data-is-click', true);
@@ -4823,7 +4928,7 @@ class DropdownMenu extends Plugin {
4823
4928
 
4824
4929
  // Handle Leaf element Clicks
4825
4930
  if(_this.options.closeOnClickInside){
4826
- this.$menuItems.on('click.zf.dropdownMenu', function(e) {
4931
+ this.$menuItems.on('click.zf.dropdownMenu', function() {
4827
4932
  var $elem = $(this),
4828
4933
  hasSub = $elem.hasClass(parClass);
4829
4934
  if(!hasSub){
@@ -4832,8 +4937,10 @@ class DropdownMenu extends Plugin {
4832
4937
  });
4833
4938
  }
4834
4939
 
4940
+ if (hasTouch && this.options.disableHoverOnTouch) this.options.disableHover = true;
4941
+
4835
4942
  if (!this.options.disableHover) {
4836
- this.$menuItems.on('mouseenter.zf.dropdownMenu', function (e) {
4943
+ this.$menuItems.on('mouseenter.zf.dropdownMenu', function () {
4837
4944
  var $elem = $(this),
4838
4945
  hasSub = $elem.hasClass(parClass);
4839
4946
 
@@ -4843,7 +4950,7 @@ class DropdownMenu extends Plugin {
4843
4950
  _this._show($elem.children('.is-dropdown-submenu'));
4844
4951
  }, _this.options.hoverDelay));
4845
4952
  }
4846
- }).on('mouseleave.zf.dropdownmenu', ignoreMousedisappear(function (e) {
4953
+ }).on('mouseleave.zf.dropdownMenu', ignoreMousedisappear(function () {
4847
4954
  var $elem = $(this),
4848
4955
  hasSub = $elem.hasClass(parClass);
4849
4956
  if (hasSub && _this.options.autoclose) {
@@ -4857,7 +4964,7 @@ class DropdownMenu extends Plugin {
4857
4964
  }));
4858
4965
  }
4859
4966
  this.$menuItems.on('keydown.zf.dropdownMenu', function(e) {
4860
- var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'),
4967
+ var $element = $(e.target).parentsUntil('ul', '[role="none"]'),
4861
4968
  isTab = _this.$tabs.index($element) > -1,
4862
4969
  $elements = isTab ? _this.$tabs : $element.siblings('li').add($element),
4863
4970
  $prevElement,
@@ -5031,7 +5138,7 @@ class DropdownMenu extends Plugin {
5031
5138
  if ($elem && $elem.length) {
5032
5139
  $toClose = $elem;
5033
5140
  } else if (typeof idx !== 'undefined') {
5034
- $toClose = this.$tabs.not(function(i, el) {
5141
+ $toClose = this.$tabs.not(function(i) {
5035
5142
  return i === idx;
5036
5143
  });
5037
5144
  }
@@ -5090,6 +5197,13 @@ DropdownMenu.defaults = {
5090
5197
  * @default false
5091
5198
  */
5092
5199
  disableHover: false,
5200
+ /**
5201
+ * Disallows hover on touch devices
5202
+ * @option
5203
+ * @type {boolean}
5204
+ * @default true
5205
+ */
5206
+ disableHoverOnTouch: true,
5093
5207
  /**
5094
5208
  * Allow a submenu to automatically close on a mouseleave event, if not clicked open.
5095
5209
  * @option
@@ -5214,13 +5328,13 @@ class Equalizer extends Plugin {
5214
5328
  if(this.options.equalizeOn){
5215
5329
  tooSmall = this._checkMQ();
5216
5330
  $(window).on('changed.zf.mediaquery', this._checkMQ.bind(this));
5217
- }else{
5331
+ }else {
5218
5332
  this._events();
5219
5333
  }
5220
5334
  if((typeof tooSmall !== 'undefined' && tooSmall === false) || typeof tooSmall === 'undefined'){
5221
5335
  if(imgs.length){
5222
5336
  onImagesLoaded(imgs, this._reflow.bind(this));
5223
- }else{
5337
+ }else {
5224
5338
  this._reflow();
5225
5339
  }
5226
5340
  }
@@ -5243,7 +5357,7 @@ class Equalizer extends Plugin {
5243
5357
  * function to handle $elements resizeme.zf.trigger, with bound this on _bindHandler.onResizeMeBound
5244
5358
  * @private
5245
5359
  */
5246
- _onResizeMe(e) {
5360
+ _onResizeMe() {
5247
5361
  this._reflow();
5248
5362
  }
5249
5363
 
@@ -5263,7 +5377,7 @@ class Equalizer extends Plugin {
5263
5377
  this._pauseEvents();
5264
5378
  if(this.hasNested){
5265
5379
  this.$element.on('postequalized.zf.equalizer', this._bindHandler.onPostEqualizedBound);
5266
- }else{
5380
+ }else {
5267
5381
  this.$element.on('resizeme.zf.trigger', this._bindHandler.onResizeMeBound);
5268
5382
  this.$element.on('mutateme.zf.trigger', this._bindHandler.onResizeMeBound);
5269
5383
  }
@@ -5281,7 +5395,7 @@ class Equalizer extends Plugin {
5281
5395
  this._pauseEvents();
5282
5396
  this.$watched.css('height', 'auto');
5283
5397
  }
5284
- }else{
5398
+ }else {
5285
5399
  if(!this.isOn){
5286
5400
  this._events();
5287
5401
  }
@@ -5310,7 +5424,7 @@ class Equalizer extends Plugin {
5310
5424
  }
5311
5425
  if (this.options.equalizeByRow) {
5312
5426
  this.getHeightsByRow(this.applyHeightByRow.bind(this));
5313
- }else{
5427
+ }else {
5314
5428
  this.getHeights(this.applyHeight.bind(this));
5315
5429
  }
5316
5430
  }
@@ -5355,7 +5469,7 @@ class Equalizer extends Plugin {
5355
5469
  this.$watched[i].style.height = 'auto';
5356
5470
  //maybe could use this.$watched[i].offsetTop
5357
5471
  var elOffsetTop = $(this.$watched[i]).offset().top;
5358
- if (elOffsetTop!=lastElTopOffset) {
5472
+ if (elOffsetTop !== lastElTopOffset) {
5359
5473
  group++;
5360
5474
  groups[group] = [];
5361
5475
  lastElTopOffset=elOffsetTop;
@@ -5493,6 +5607,9 @@ class Interchange extends Plugin {
5493
5607
  this.currentPath = '';
5494
5608
  this.className = 'Interchange'; // ie9 back compat
5495
5609
 
5610
+ // Triggers init is idempotent, just need to make sure it is initialized
5611
+ Triggers.init($);
5612
+
5496
5613
  this._init();
5497
5614
  this._events();
5498
5615
  }
@@ -5560,7 +5677,7 @@ class Interchange extends Plugin {
5560
5677
  if (typeof this.options.type === 'undefined')
5561
5678
  this.options.type = 'auto';
5562
5679
  else if (types.indexOf(this.options.type) === -1) {
5563
- console.log(`Warning: invalid value "${this.options.type}" for Interchange option "type"`);
5680
+ console.warn(`Warning: invalid value "${this.options.type}" for Interchange option "type"`);
5564
5681
  this.options.type = 'auto';
5565
5682
  }
5566
5683
  }
@@ -5583,10 +5700,9 @@ class Interchange extends Plugin {
5583
5700
  * Checks the Interchange element for the provided media query + content pairings
5584
5701
  * @function
5585
5702
  * @private
5586
- * @param {Object} element - jQuery object that is an Interchange instance
5587
5703
  * @returns {Array} scenarios - Array of objects that have 'mq' and 'path' keys with corresponding keys
5588
5704
  */
5589
- _generateRules(element) {
5705
+ _generateRules() {
5590
5706
  var rulesList = [];
5591
5707
  var rules;
5592
5708
 
@@ -5921,12 +6037,7 @@ class Magellan extends Plugin {
5921
6037
  * @private
5922
6038
  */
5923
6039
  _events() {
5924
- var _this = this,
5925
- $body = $('html, body'),
5926
- opts = {
5927
- duration: _this.options.animationDuration,
5928
- easing: _this.options.animationEasing
5929
- };
6040
+ var _this = this;
5930
6041
 
5931
6042
  $(window).one('load', function(){
5932
6043
  if(_this.options.deepLinking){
@@ -5951,7 +6062,7 @@ class Magellan extends Plugin {
5951
6062
  });
5952
6063
  });
5953
6064
 
5954
- this._deepLinkScroll = function(e) {
6065
+ this._deepLinkScroll = function() {
5955
6066
  if(_this.options.deepLinking) {
5956
6067
  _this.scrollToLoc(window.location.hash);
5957
6068
  }
@@ -6005,12 +6116,12 @@ class Magellan extends Plugin {
6005
6116
 
6006
6117
  let activeIdx;
6007
6118
  // Before the first point: no link
6008
- if(newScrollPos < this.points[0]);
6119
+ if(newScrollPos < this.points[0] - this.options.offset - (isScrollingUp ? this.options.threshold : 0));
6009
6120
  // At the bottom of the page: last link
6010
6121
  else if(newScrollPos + this.winHeight === this.docHeight){ activeIdx = this.points.length - 1; }
6011
6122
  // Otherwhise, use the last visible link
6012
- else{
6013
- const visibleLinks = this.points.filter((p, i) => {
6123
+ else {
6124
+ const visibleLinks = this.points.filter((p) => {
6014
6125
  return (p - this.options.offset - (isScrollingUp ? this.options.threshold : 0)) <= newScrollPos;
6015
6126
  });
6016
6127
  activeIdx = visibleLinks.length ? visibleLinks.length - 1 : 0;
@@ -6022,7 +6133,7 @@ class Magellan extends Plugin {
6022
6133
  if(typeof activeIdx !== 'undefined'){
6023
6134
  this.$active = this.$links.filter('[href="#' + this.$targets.eq(activeIdx).data('magellan-target') + '"]');
6024
6135
  if (this.$active.length) activeHash = this.$active[0].getAttribute('href');
6025
- }else{
6136
+ }else {
6026
6137
  this.$active = $();
6027
6138
  }
6028
6139
  const isNewActive = !(!this.$active.length && !$oldActive.length) && !this.$active.is($oldActive);
@@ -6041,10 +6152,10 @@ class Magellan extends Plugin {
6041
6152
  const url = activeHash ? activeHash : window.location.pathname + window.location.search;
6042
6153
  if(this.options.updateHistory){
6043
6154
  window.history.pushState({}, '', url);
6044
- }else{
6155
+ }else {
6045
6156
  window.history.replaceState({}, '', url);
6046
6157
  }
6047
- }else{
6158
+ }else {
6048
6159
  window.location.hash = activeHash;
6049
6160
  }
6050
6161
  }
@@ -6445,74 +6556,75 @@ class OffCanvas extends Plugin {
6445
6556
  * @function
6446
6557
  * @private
6447
6558
  */
6448
- _stopScrolling(event) {
6559
+ _stopScrolling() {
6449
6560
  return false;
6450
6561
  }
6451
6562
 
6452
6563
  /**
6453
- * Tag the element given as context whether it can be scrolled up and down.
6454
- * Used to allow or prevent it to scroll. See `_stopScrollPropagation`.
6455
- *
6456
- * Taken and adapted from http://stackoverflow.com/questions/16889447/prevent-full-page-scrolling-ios
6457
- * Only really works for y, not sure how to extend to x or if we need to.
6458
- *
6459
- * @function
6564
+ * Save current finger y-position
6565
+ * @param event
6460
6566
  * @private
6461
6567
  */
6462
6568
  _recordScrollable(event) {
6463
- let elem = this; // called from event handler context with this as elem
6569
+ const elem = this;
6570
+ elem.lastY = event.touches[0].pageY;
6571
+ }
6464
6572
 
6465
- // If the element is scrollable (content overflows), then...
6466
- if (elem.scrollHeight !== elem.clientHeight) {
6467
- // If we're at the top, scroll down one pixel to allow scrolling up
6468
- if (elem.scrollTop === 0) {
6469
- elem.scrollTop = 1;
6470
- }
6471
- // If we're at the bottom, scroll up one pixel to allow scrolling down
6472
- if (elem.scrollTop === elem.scrollHeight - elem.clientHeight) {
6473
- elem.scrollTop = elem.scrollHeight - elem.clientHeight - 1;
6474
- }
6573
+ /**
6574
+ * Prevent further scrolling when it hits the edges
6575
+ * @param event
6576
+ * @private
6577
+ */
6578
+ _preventDefaultAtEdges(event) {
6579
+ const elem = this;
6580
+ const _this = event.data;
6581
+ const delta = elem.lastY - event.touches[0].pageY;
6582
+ elem.lastY = event.touches[0].pageY;
6583
+
6584
+ if (!_this._canScroll(delta, elem)) {
6585
+ event.preventDefault();
6475
6586
  }
6476
- elem.allowUp = elem.scrollTop > 0;
6477
- elem.allowDown = elem.scrollTop < (elem.scrollHeight - elem.clientHeight);
6478
- elem.lastY = event.originalEvent.pageY;
6479
6587
  }
6480
6588
 
6481
6589
  /**
6482
- * Prevent the given event propagation if the element given as context can scroll.
6483
- * Used to preserve the element scrolling on mobile (`touchmove`) when the document
6484
- * scrolling is prevented. See https://git.io/zf-9707.
6485
- * @function
6590
+ * Handle continuous scrolling of scrollbox
6591
+ * Don't bubble up to _preventDefaultAtEdges
6592
+ * @param event
6486
6593
  * @private
6487
6594
  */
6488
- _stopScrollPropagation(event) {
6489
- let elem = this; // called from event handler context with this as elem
6490
- let parent; // off-canvas elem if called from inner scrollbox
6491
- let up = event.pageY < elem.lastY;
6492
- let down = !up;
6493
- elem.lastY = event.pageY;
6494
-
6495
- if((up && elem.allowUp) || (down && elem.allowDown)) {
6496
- // It is not recommended to stop event propagation (the user cannot watch it),
6497
- // but in this case this is the only solution we have.
6498
- event.stopPropagation();
6499
-
6500
- // If elem is inner scrollbox we are scrolling the outer off-canvas down/up once the box end has been reached
6501
- // This lets the user continue to touch move the off-canvas without the need to place the finger outside the scrollbox
6502
- if (elem.hasAttribute('data-off-canvas-scrollbox')) {
6503
- parent = elem.closest('[data-off-canvas], [data-off-canvas-scrollbox-outer]');
6504
- if (elem.scrollTop <= 1 && parent.scrollTop > 0) {
6505
- parent.scrollTop--;
6506
- } else if (elem.scrollTop >= elem.scrollHeight - elem.clientHeight - 1 && parent.scrollTop < parent.scrollHeight - parent.clientHeight) {
6507
- parent.scrollTop++;
6508
- }
6509
- }
6595
+ _scrollboxTouchMoved(event) {
6596
+ const elem = this;
6597
+ const _this = event.data;
6598
+ const parent = elem.closest('[data-off-canvas], [data-off-canvas-scrollbox-outer]');
6599
+ const delta = elem.lastY - event.touches[0].pageY;
6600
+ parent.lastY = elem.lastY = event.touches[0].pageY;
6510
6601
 
6511
- } else {
6512
- event.preventDefault();
6602
+ event.stopPropagation();
6603
+
6604
+ if (!_this._canScroll(delta, elem)) {
6605
+ if (!_this._canScroll(delta, parent)) {
6606
+ event.preventDefault();
6607
+ } else {
6608
+ parent.scrollTop += delta;
6609
+ }
6513
6610
  }
6514
6611
  }
6515
6612
 
6613
+ /**
6614
+ * Detect possibility of scrolling
6615
+ * @param delta
6616
+ * @param elem
6617
+ * @returns boolean
6618
+ * @private
6619
+ */
6620
+ _canScroll(delta, elem) {
6621
+ const up = delta < 0;
6622
+ const down = delta > 0;
6623
+ const allowUp = elem.scrollTop > 0;
6624
+ const allowDown = elem.scrollTop < elem.scrollHeight - elem.clientHeight;
6625
+ return up && allowUp || down && allowDown;
6626
+ }
6627
+
6516
6628
  /**
6517
6629
  * Opens the off-canvas menu.
6518
6630
  * @function
@@ -6552,9 +6664,9 @@ class OffCanvas extends Plugin {
6552
6664
  if (this.options.contentScroll === false) {
6553
6665
  $('body').addClass('is-off-canvas-open').on('touchmove', this._stopScrolling);
6554
6666
  this.$element.on('touchstart', this._recordScrollable);
6555
- this.$element.on('touchmove', this._stopScrollPropagation);
6667
+ this.$element.on('touchmove', this, this._preventDefaultAtEdges);
6556
6668
  this.$element.on('touchstart', '[data-off-canvas-scrollbox]', this._recordScrollable);
6557
- this.$element.on('touchmove', '[data-off-canvas-scrollbox]', this._stopScrollPropagation);
6669
+ this.$element.on('touchmove', '[data-off-canvas-scrollbox]', this, this._scrollboxTouchMoved);
6558
6670
  }
6559
6671
 
6560
6672
  if (this.options.contentOverlay === true) {
@@ -6612,7 +6724,7 @@ class OffCanvas extends Plugin {
6612
6724
  * @fires OffCanvas#close
6613
6725
  * @fires OffCanvas#closed
6614
6726
  */
6615
- close(cb) {
6727
+ close() {
6616
6728
  if (!this.$element.hasClass('is-open') || this.isRevealed) { return; }
6617
6729
 
6618
6730
  /**
@@ -6639,7 +6751,7 @@ class OffCanvas extends Plugin {
6639
6751
 
6640
6752
 
6641
6753
  // Listen to transitionEnd: add class, re-enable scrolling and release focus when done.
6642
- this.$element.one(transitionend(this.$element), (e) => {
6754
+ this.$element.one(transitionend(this.$element), () => {
6643
6755
 
6644
6756
  this.$element.addClass('is-closed');
6645
6757
  this._removeContentClasses();
@@ -6652,9 +6764,9 @@ class OffCanvas extends Plugin {
6652
6764
  if (this.options.contentScroll === false) {
6653
6765
  $('body').removeClass('is-off-canvas-open').off('touchmove', this._stopScrolling);
6654
6766
  this.$element.off('touchstart', this._recordScrollable);
6655
- this.$element.off('touchmove', this._stopScrollPropagation);
6767
+ this.$element.off('touchmove', this._preventDefaultAtEdges);
6656
6768
  this.$element.off('touchstart', '[data-off-canvas-scrollbox]', this._recordScrollable);
6657
- this.$element.off('touchmove', '[data-off-canvas-scrollbox]', this._stopScrollPropagation);
6769
+ this.$element.off('touchmove', '[data-off-canvas-scrollbox]', this._scrollboxTouchMoved);
6658
6770
  }
6659
6771
 
6660
6772
  if (this.options.trapFocus === true) {
@@ -7087,7 +7199,7 @@ class Orbit extends Plugin {
7087
7199
  */
7088
7200
  _reset() {
7089
7201
  // Don't do anything if there are no slides (first run)
7090
- if (typeof this.$slides == 'undefined') {
7202
+ if (typeof this.$slides === 'undefined') {
7091
7203
  return;
7092
7204
  }
7093
7205
 
@@ -7373,7 +7485,7 @@ Orbit.defaults = {
7373
7485
  useMUI: true
7374
7486
  };
7375
7487
 
7376
- let MenuPlugins = {
7488
+ let MenuPlugins$1 = {
7377
7489
  dropdown: {
7378
7490
  cssClass: 'dropdown',
7379
7491
  plugin: DropdownMenu
@@ -7407,7 +7519,7 @@ class ResponsiveMenu extends Plugin {
7407
7519
  * @param {jQuery} element - jQuery object to make into a dropdown menu.
7408
7520
  * @param {Object} options - Overrides to the default plugin settings.
7409
7521
  */
7410
- _setup(element, options) {
7522
+ _setup(element) {
7411
7523
  this.$element = $(element);
7412
7524
  this.rules = this.$element.data('responsive-menu');
7413
7525
  this.currentMq = null;
@@ -7439,8 +7551,8 @@ class ResponsiveMenu extends Plugin {
7439
7551
  let ruleSize = rule.length > 1 ? rule[0] : 'small';
7440
7552
  let rulePlugin = rule.length > 1 ? rule[1] : rule[0];
7441
7553
 
7442
- if (MenuPlugins[rulePlugin] !== null) {
7443
- rulesTree[ruleSize] = MenuPlugins[rulePlugin];
7554
+ if (MenuPlugins$1[rulePlugin] !== null) {
7555
+ rulesTree[ruleSize] = MenuPlugins$1[rulePlugin];
7444
7556
  }
7445
7557
  }
7446
7558
 
@@ -7491,7 +7603,7 @@ class ResponsiveMenu extends Plugin {
7491
7603
  if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return;
7492
7604
 
7493
7605
  // Remove existing plugin-specific CSS classes
7494
- $.each(MenuPlugins, function(key, value) {
7606
+ $.each(MenuPlugins$1, function(key, value) {
7495
7607
  _this.$element.removeClass(value.cssClass);
7496
7608
  });
7497
7609
 
@@ -7576,7 +7688,6 @@ class ResponsiveToggle extends Plugin {
7576
7688
  * @private
7577
7689
  */
7578
7690
  _events() {
7579
-
7580
7691
  this._updateMqHandler = this._update.bind(this);
7581
7692
 
7582
7693
  $(window).on('changed.zf.mediaquery', this._updateMqHandler);
@@ -7707,7 +7818,7 @@ class Reveal extends Plugin {
7707
7818
  this.$anchor = $(`[data-open="${this.id}"]`).length ? $(`[data-open="${this.id}"]`) : $(`[data-toggle="${this.id}"]`);
7708
7819
  this.$anchor.attr({
7709
7820
  'aria-controls': this.id,
7710
- 'aria-haspopup': true,
7821
+ 'aria-haspopup': 'dialog',
7711
7822
  'tabindex': 0
7712
7823
  });
7713
7824
 
@@ -7833,9 +7944,9 @@ class Reveal extends Plugin {
7833
7944
  * Handles modal methods on back/forward button clicks or any other event that triggers hashchange.
7834
7945
  * @private
7835
7946
  */
7836
- _handleState(e) {
7947
+ _handleState() {
7837
7948
  if(window.location.hash === ( '#' + this.id) && !this.isActive){ this.open(); }
7838
- else{ this.close(); }
7949
+ else { this.close(); }
7839
7950
  }
7840
7951
 
7841
7952
  /**
@@ -7855,7 +7966,7 @@ class Reveal extends Plugin {
7855
7966
  * @param {number} scrollTop - Scroll to restore, html "top" property by default (as set by `_disableScroll`)
7856
7967
  */
7857
7968
  _enableScroll(scrollTop) {
7858
- scrollTop = scrollTop || parseInt($("html").css("top"));
7969
+ scrollTop = scrollTop || parseInt($("html").css("top"), 10);
7859
7970
  if ($(document).height() > $(window).height()) {
7860
7971
  $("html")
7861
7972
  .css("top", "");
@@ -8089,8 +8200,8 @@ class Reveal extends Plugin {
8089
8200
 
8090
8201
  // Get the current top before the modal is closed and restore the scroll after.
8091
8202
  // TODO: use component properties instead of HTML properties
8092
- // See https://github.com/zurb/foundation-sites/pull/10786
8093
- var scrollTop = parseInt($("html").css("top"));
8203
+ // See https://github.com/foundation/foundation-sites/pull/10786
8204
+ var scrollTop = parseInt($("html").css("top"), 10);
8094
8205
 
8095
8206
  if ($('.reveal:visible').length === 0) {
8096
8207
  _this._removeGlobalClasses(); // also remove .is-reveal-open from the html element when there is no opened reveal
@@ -8306,6 +8417,7 @@ class Slider extends Plugin {
8306
8417
  this.$element = element;
8307
8418
  this.options = $.extend({}, Slider.defaults, this.$element.data(), options);
8308
8419
  this.className = 'Slider'; // ie9 back compat
8420
+ this.initialized = false;
8309
8421
 
8310
8422
  // Touch and Triggers inits are idempotent, we just need to make sure it's initialied.
8311
8423
  Touch.init($);
@@ -8319,18 +8431,18 @@ class Slider extends Plugin {
8319
8431
  'ARROW_UP': 'increase',
8320
8432
  'ARROW_DOWN': 'decrease',
8321
8433
  'ARROW_LEFT': 'decrease',
8322
- 'SHIFT_ARROW_RIGHT': 'increase_fast',
8323
- 'SHIFT_ARROW_UP': 'increase_fast',
8324
- 'SHIFT_ARROW_DOWN': 'decrease_fast',
8325
- 'SHIFT_ARROW_LEFT': 'decrease_fast',
8434
+ 'SHIFT_ARROW_RIGHT': 'increaseFast',
8435
+ 'SHIFT_ARROW_UP': 'increaseFast',
8436
+ 'SHIFT_ARROW_DOWN': 'decreaseFast',
8437
+ 'SHIFT_ARROW_LEFT': 'decreaseFast',
8326
8438
  'HOME': 'min',
8327
8439
  'END': 'max'
8328
8440
  },
8329
8441
  'rtl': {
8330
8442
  'ARROW_LEFT': 'increase',
8331
8443
  'ARROW_RIGHT': 'decrease',
8332
- 'SHIFT_ARROW_LEFT': 'increase_fast',
8333
- 'SHIFT_ARROW_RIGHT': 'decrease_fast'
8444
+ 'SHIFT_ARROW_LEFT': 'increaseFast',
8445
+ 'SHIFT_ARROW_RIGHT': 'decreaseFast'
8334
8446
  }
8335
8447
  });
8336
8448
  }
@@ -8347,6 +8459,7 @@ class Slider extends Plugin {
8347
8459
  this.$handle = this.handles.eq(0);
8348
8460
  this.$input = this.inputs.length ? this.inputs.eq(0) : $(`#${this.$handle.attr('aria-controls')}`);
8349
8461
  this.$fill = this.$element.find('[data-slider-fill]').css(this.options.vertical ? 'height' : 'width', 0);
8462
+
8350
8463
  if (this.options.disabled || this.$element.hasClass(this.options.disabledClass)) {
8351
8464
  this.options.disabled = true;
8352
8465
  this.$element.addClass(this.options.disabledClass);
@@ -8375,6 +8488,7 @@ class Slider extends Plugin {
8375
8488
  this.setHandles();
8376
8489
 
8377
8490
  this._events();
8491
+ this.initialized = true;
8378
8492
  }
8379
8493
 
8380
8494
  setHandles() {
@@ -8514,7 +8628,7 @@ class Slider extends Plugin {
8514
8628
  //empty variable, will be used for min-height/width for fill bar
8515
8629
  dim,
8516
8630
  //percentage w/h of the handle compared to the slider bar
8517
- handlePct = ~~(percent(handleDim, elemDim) * 100);
8631
+ handlePct = Math.floor(percent(handleDim, elemDim) * 100);
8518
8632
  //if left handle, the math is slightly different than if it's the right handle, and the left/top property needs to be changed for the fill bar
8519
8633
  if (isLeftHndl) {
8520
8634
  //left or top percentage value to apply to the fill bar.
@@ -8535,14 +8649,6 @@ class Slider extends Plugin {
8535
8649
  css[`min-${hOrW}`] = `${dim}%`;
8536
8650
  }
8537
8651
 
8538
- this.$element.one('finished.zf.animate', function() {
8539
- /**
8540
- * Fires when the handle is done moving.
8541
- * @event Slider#moved
8542
- */
8543
- _this.$element.trigger('moved.zf.slider', [$hndl]);
8544
- });
8545
-
8546
8652
  //because we don't know exactly how the handle will be moved, check the amount of time it should take to move.
8547
8653
  var moveTime = this.$element.data('dragging') ? 1000/60 : this.options.moveTime;
8548
8654
 
@@ -8566,15 +8672,23 @@ class Slider extends Plugin {
8566
8672
  }
8567
8673
  });
8568
8674
 
8569
-
8570
- /**
8571
- * Fires when the value has not been change for a given time.
8572
- * @event Slider#changed
8573
- */
8574
- clearTimeout(_this.timeout);
8575
- _this.timeout = setTimeout(function(){
8576
- _this.$element.trigger('changed.zf.slider', [$hndl]);
8577
- }, _this.options.changedDelay);
8675
+ if (this.initialized) {
8676
+ this.$element.one('finished.zf.animate', function() {
8677
+ /**
8678
+ * Fires when the handle is done moving.
8679
+ * @event Slider#moved
8680
+ */
8681
+ _this.$element.trigger('moved.zf.slider', [$hndl]);
8682
+ });
8683
+ /**
8684
+ * Fires when the value has not been change for a given time.
8685
+ * @event Slider#changed
8686
+ */
8687
+ clearTimeout(_this.timeout);
8688
+ _this.timeout = setTimeout(function(){
8689
+ _this.$element.trigger('changed.zf.slider', [$hndl]);
8690
+ }, _this.options.changedDelay);
8691
+ }
8578
8692
  }
8579
8693
 
8580
8694
  /**
@@ -8637,11 +8751,9 @@ class Slider extends Plugin {
8637
8751
  param = vertical ? 'height' : 'width',
8638
8752
  direction = vertical ? 'top' : 'left',
8639
8753
  eventOffset = vertical ? e.pageY : e.pageX,
8640
- halfOfHandle = this.$handle[0].getBoundingClientRect()[param] / 2,
8641
8754
  barDim = this.$element[0].getBoundingClientRect()[param],
8642
8755
  windowScroll = vertical ? $(window).scrollTop() : $(window).scrollLeft();
8643
8756
 
8644
-
8645
8757
  var elemOffset = this.$element.offset()[direction];
8646
8758
 
8647
8759
  // touch events emulated by the touch util give position relative to screen, add window.scroll to event coordinates...
@@ -8689,7 +8801,7 @@ class Slider extends Plugin {
8689
8801
  var val,
8690
8802
  step = this.options.step,
8691
8803
  div = parseFloat(step/2),
8692
- left, prev_val, next_val;
8804
+ left, previousVal, nextVal;
8693
8805
  if (!!$handle) {
8694
8806
  val = parseFloat($handle.attr('aria-valuenow'));
8695
8807
  }
@@ -8701,12 +8813,12 @@ class Slider extends Plugin {
8701
8813
  } else {
8702
8814
  left = step + (val % step);
8703
8815
  }
8704
- prev_val = val - left;
8705
- next_val = prev_val + step;
8816
+ previousVal = val - left;
8817
+ nextVal = previousVal + step;
8706
8818
  if (left === 0) {
8707
8819
  return val;
8708
8820
  }
8709
- val = val >= prev_val + div ? next_val : prev_val;
8821
+ val = val >= previousVal + div ? nextVal : previousVal;
8710
8822
  return val;
8711
8823
  }
8712
8824
 
@@ -8742,7 +8854,7 @@ class Slider extends Plugin {
8742
8854
  // listen for the enter key and trigger a change
8743
8855
  // @see https://html.spec.whatwg.org/multipage/input.html#common-input-element-events
8744
8856
  this.inputs.off('keyup.zf.slider').on('keyup.zf.slider', function (e) {
8745
- if(e.keyCode == 13) handleChangeEvent.call(this, e);
8857
+ if(e.keyCode === 13) handleChangeEvent.call(this, e);
8746
8858
  });
8747
8859
 
8748
8860
  this.inputs.off('change.zf.slider').on('change.zf.slider', handleChangeEvent);
@@ -8774,12 +8886,12 @@ class Slider extends Plugin {
8774
8886
 
8775
8887
  curHandle = $(e.currentTarget);
8776
8888
 
8777
- $body.on('mousemove.zf.slider', function(e) {
8778
- e.preventDefault();
8779
- _this._handleEvent(e, curHandle);
8889
+ $body.on('mousemove.zf.slider', function(ev) {
8890
+ ev.preventDefault();
8891
+ _this._handleEvent(ev, curHandle);
8780
8892
 
8781
- }).on('mouseup.zf.slider', function(e) {
8782
- _this._handleEvent(e, curHandle);
8893
+ }).on('mouseup.zf.slider', function(ev) {
8894
+ _this._handleEvent(ev, curHandle);
8783
8895
 
8784
8896
  $handle.removeClass('is-dragging');
8785
8897
  _this.$fill.removeClass('is-dragging');
@@ -8795,9 +8907,9 @@ class Slider extends Plugin {
8795
8907
  }
8796
8908
 
8797
8909
  $handle.off('keydown.zf.slider').on('keydown.zf.slider', function(e) {
8798
- var _$handle = $(this),
8799
- idx = _this.options.doubleSided ? _this.handles.index(_$handle) : 0,
8800
- oldValue = parseFloat(_this.inputs.eq(idx).val()),
8910
+ var _$handle = $(this);
8911
+ _this.options.doubleSided ? _this.handles.index(_$handle) : 0;
8912
+ var oldValue = parseFloat($handle.attr('aria-valuenow')),
8801
8913
  newValue;
8802
8914
 
8803
8915
  // handle keyboard event with keyboard util
@@ -8808,10 +8920,10 @@ class Slider extends Plugin {
8808
8920
  increase: function() {
8809
8921
  newValue = oldValue + _this.options.step;
8810
8922
  },
8811
- decrease_fast: function() {
8923
+ decreaseFast: function() {
8812
8924
  newValue = oldValue - _this.options.step * 10;
8813
8925
  },
8814
- increase_fast: function() {
8926
+ increaseFast: function() {
8815
8927
  newValue = oldValue + _this.options.step * 10;
8816
8928
  },
8817
8929
  min: function() {
@@ -9047,7 +9159,7 @@ class Sticky extends Plugin {
9047
9159
  this.isStuck = false;
9048
9160
  this.onLoadListener = onLoad($(window), function () {
9049
9161
  //We calculate the container height to have correct values for anchor points offset calculation.
9050
- _this.containerHeight = _this.$element.css("display") == "none" ? 0 : _this.$element[0].getBoundingClientRect().height;
9162
+ _this.containerHeight = _this.$element.css("display") === "none" ? 0 : _this.$element[0].getBoundingClientRect().height;
9051
9163
  _this.$container.css('height', _this.containerHeight);
9052
9164
  _this.elemHeight = _this.containerHeight;
9053
9165
  if (_this.options.anchor !== '') {
@@ -9074,8 +9186,8 @@ class Sticky extends Plugin {
9074
9186
  * @private
9075
9187
  */
9076
9188
  _parsePoints() {
9077
- var top = this.options.topAnchor == "" ? 1 : this.options.topAnchor,
9078
- btm = this.options.btmAnchor== "" ? document.documentElement.scrollHeight : this.options.btmAnchor,
9189
+ var top = this.options.topAnchor === "" ? 1 : this.options.topAnchor,
9190
+ btm = this.options.btmAnchor === "" ? document.documentElement.scrollHeight : this.options.btmAnchor,
9079
9191
  pts = [top, btm],
9080
9192
  breaks = {};
9081
9193
  for (var i = 0, len = pts.length; i < len && pts[i]; i++) {
@@ -9111,7 +9223,7 @@ class Sticky extends Plugin {
9111
9223
  if (this.canStick) {
9112
9224
  this.isOn = true;
9113
9225
  $(window).off(scrollListener)
9114
- .on(scrollListener, function(e) {
9226
+ .on(scrollListener, function() {
9115
9227
  if (_this.scrollCount === 0) {
9116
9228
  _this.scrollCount = _this.options.checkEvery;
9117
9229
  _this._setSizes(function() {
@@ -9125,16 +9237,16 @@ class Sticky extends Plugin {
9125
9237
  }
9126
9238
 
9127
9239
  this.$element.off('resizeme.zf.trigger')
9128
- .on('resizeme.zf.trigger', function(e, el) {
9240
+ .on('resizeme.zf.trigger', function() {
9129
9241
  _this._eventsHandler(id);
9130
9242
  });
9131
9243
 
9132
- this.$element.on('mutateme.zf.trigger', function (e, el) {
9244
+ this.$element.on('mutateme.zf.trigger', function () {
9133
9245
  _this._eventsHandler(id);
9134
9246
  });
9135
9247
 
9136
9248
  if(this.$anchor) {
9137
- this.$anchor.on('mutateme.zf.trigger', function (e, el) {
9249
+ this.$anchor.on('mutateme.zf.trigger', function () {
9138
9250
  _this._eventsHandler(id);
9139
9251
  });
9140
9252
  }
@@ -9263,11 +9375,11 @@ class Sticky extends Plugin {
9263
9375
 
9264
9376
  css[mrgn] = 0;
9265
9377
 
9266
- css['bottom'] = 'auto';
9378
+ css.bottom = 'auto';
9267
9379
  if(isTop) {
9268
- css['top'] = 0;
9380
+ css.top = 0;
9269
9381
  } else {
9270
- css['top'] = anchorPt;
9382
+ css.top = anchorPt;
9271
9383
  }
9272
9384
 
9273
9385
  this.isStuck = false;
@@ -9295,9 +9407,9 @@ class Sticky extends Plugin {
9295
9407
  }
9296
9408
 
9297
9409
  var newElemWidth = this.$container[0].getBoundingClientRect().width,
9298
- comp = window.getComputedStyle(this.$container[0]),
9299
- pdngl = parseInt(comp['padding-left'], 10),
9300
- pdngr = parseInt(comp['padding-right'], 10);
9410
+ comp = window.getComputedStyle(this.$container[0]),
9411
+ pdngl = parseInt(comp['padding-left'], 10),
9412
+ pdngr = parseInt(comp['padding-right'], 10);
9301
9413
 
9302
9414
  if (this.$anchor && this.$anchor.length) {
9303
9415
  this.anchorHeight = this.$anchor[0].getBoundingClientRect().height;
@@ -9313,7 +9425,7 @@ class Sticky extends Plugin {
9313
9425
  if (this.options.dynamicHeight || !this.containerHeight) {
9314
9426
  // Get the sticked element height and apply it to the container to "hold the place"
9315
9427
  var newContainerHeight = this.$element[0].getBoundingClientRect().height || this.containerHeight;
9316
- newContainerHeight = this.$element.css("display") == "none" ? 0 : newContainerHeight;
9428
+ newContainerHeight = this.$element.css("display") === "none" ? 0 : newContainerHeight;
9317
9429
  this.$container.css('height', newContainerHeight);
9318
9430
  this.containerHeight = newContainerHeight;
9319
9431
  }
@@ -9356,7 +9468,7 @@ class Sticky extends Plugin {
9356
9468
  } else if (this.options.stickTo === 'bottom') {
9357
9469
  topPoint -= (winHeight - (elemHeight + mBtm));
9358
9470
  bottomPoint -= (winHeight - mBtm);
9359
- }
9471
+ } else ;
9360
9472
 
9361
9473
  this.topPoint = topPoint;
9362
9474
  this.bottomPoint = bottomPoint;
@@ -9621,7 +9733,7 @@ class Tabs extends Plugin {
9621
9733
  // Roll up a little to show the titles
9622
9734
  if (this.options.deepLinkSmudge) {
9623
9735
  var offset = this.$element.offset();
9624
- $('html, body').animate({ scrollTop: offset.top }, this.options.deepLinkSmudgeDelay);
9736
+ $('html, body').animate({ scrollTop: offset.top - this.options.deepLinkSmudgeOffset}, this.options.deepLinkSmudgeDelay);
9625
9737
  }
9626
9738
 
9627
9739
  /**
@@ -9760,9 +9872,9 @@ class Tabs extends Plugin {
9760
9872
  //either replace or update browser history
9761
9873
  if (this.options.deepLink && !historyHandled) {
9762
9874
  if (this.options.updateHistory) {
9763
- history.pushState({}, '', anchor);
9875
+ history.pushState({}, '', location.pathname + location.search + anchor);
9764
9876
  } else {
9765
- history.replaceState({}, '', anchor);
9877
+ history.replaceState({}, '', location.pathname + location.search + anchor);
9766
9878
  }
9767
9879
  }
9768
9880
 
@@ -9803,7 +9915,7 @@ class Tabs extends Plugin {
9803
9915
  * @function
9804
9916
  */
9805
9917
  _collapseTab($target) {
9806
- var $target_anchor = $target
9918
+ var $targetAnchor = $target
9807
9919
  .removeClass(`${this.options.linkActiveClass}`)
9808
9920
  .find('[role="tab"]')
9809
9921
  .attr({
@@ -9811,7 +9923,7 @@ class Tabs extends Plugin {
9811
9923
  'tabindex': -1
9812
9924
  });
9813
9925
 
9814
- $(`#${$target_anchor.attr('aria-controls')}`)
9926
+ $(`#${$targetAnchor.attr('aria-controls')}`)
9815
9927
  .removeClass(`${this.options.panelActiveClass}`)
9816
9928
  .attr({ 'aria-hidden': 'true' });
9817
9929
  }
@@ -9874,9 +9986,13 @@ class Tabs extends Plugin {
9874
9986
  var max = 0,
9875
9987
  _this = this; // Lock down the `this` value for the root tabs object
9876
9988
 
9989
+ if (!this.$tabContent) {
9990
+ return;
9991
+ }
9992
+
9877
9993
  this.$tabContent
9878
9994
  .find(`.${this.options.panelClass}`)
9879
- .css('height', '')
9995
+ .css('min-height', '')
9880
9996
  .each(function() {
9881
9997
 
9882
9998
  var panel = $(this),
@@ -9897,7 +10013,7 @@ class Tabs extends Plugin {
9897
10013
 
9898
10014
  max = temp > max ? temp : max;
9899
10015
  })
9900
- .css('height', `${max}px`);
10016
+ .css('min-height', `${max}px`);
9901
10017
  }
9902
10018
 
9903
10019
  /**
@@ -9953,6 +10069,14 @@ Tabs.defaults = {
9953
10069
  */
9954
10070
  deepLinkSmudgeDelay: 300,
9955
10071
 
10072
+ /**
10073
+ * If `deepLinkSmudge` is enabled, animation offset from the top for the deep link adjustment
10074
+ * @option
10075
+ * @type {number}
10076
+ * @default 0
10077
+ */
10078
+ deepLinkSmudgeOffset: 0,
10079
+
9956
10080
  /**
9957
10081
  * If `deepLink` is enabled, update the browser history with the open tab
9958
10082
  * @option
@@ -10081,7 +10205,7 @@ class Toggler extends Plugin {
10081
10205
  else {
10082
10206
  input = this.options.toggler;
10083
10207
  if (typeof input !== 'string' || !input.length) {
10084
- throw new Error(`The 'toogler' option containing the target class is required, got "${input}"`);
10208
+ throw new Error(`The 'toggler' option containing the target class is required, got "${input}"`);
10085
10209
  }
10086
10210
  // Allow for a . at the beginning of the string
10087
10211
  this.className = input[0] === '.' ? input.slice(1) : input;
@@ -10260,14 +10384,12 @@ class Tooltip extends Positionable {
10260
10384
 
10261
10385
  _getDefaultPosition() {
10262
10386
  // handle legacy classnames
10263
- var position = this.$element[0].className.match(/\b(top|left|right|bottom)\b/g);
10264
10387
  var elementClassName = this.$element[0].className;
10265
10388
  if (this.$element[0] instanceof SVGElement) {
10266
10389
  elementClassName = elementClassName.baseVal;
10267
10390
  }
10391
+ var position = elementClassName.match(/\b(top|left|right|bottom)\b/g);
10268
10392
  return position ? position[0] : 'top';
10269
- var position = elementClassName.match(/\b(top|left|right)\b/g);
10270
- position = position ? position[0] : 'tp';
10271
10393
  }
10272
10394
 
10273
10395
  _getDefaultAlignment() {
@@ -10345,7 +10467,6 @@ class Tooltip extends Positionable {
10345
10467
  'aria-hidden': false
10346
10468
  });
10347
10469
  _this.isActive = true;
10348
- // console.log(this.template);
10349
10470
  this.template.stop().hide().css('visibility', '').fadeIn(this.options.fadeInDuration, function() {
10350
10471
  //maybe do stuff?
10351
10472
  });
@@ -10362,7 +10483,6 @@ class Tooltip extends Positionable {
10362
10483
  * @function
10363
10484
  */
10364
10485
  hide() {
10365
- // console.log('hiding', this.$element.data('yeti-box'));
10366
10486
  var _this = this;
10367
10487
  this.template.stop().attr({
10368
10488
  'aria-hidden': true,
@@ -10386,7 +10506,6 @@ class Tooltip extends Positionable {
10386
10506
  _events() {
10387
10507
  const _this = this;
10388
10508
  const hasTouch = 'ontouchstart' in window || (typeof window.ontouchstart !== 'undefined');
10389
- const $template = this.template;
10390
10509
  var isFocus = false;
10391
10510
 
10392
10511
  // `disableForTouch: Fully disable the tooltip on touch devices
@@ -10394,14 +10513,14 @@ class Tooltip extends Positionable {
10394
10513
 
10395
10514
  if (!this.options.disableHover) {
10396
10515
  this.$element
10397
- .on('mouseenter.zf.tooltip', function(e) {
10516
+ .on('mouseenter.zf.tooltip', function() {
10398
10517
  if (!_this.isActive) {
10399
10518
  _this.timeout = setTimeout(function() {
10400
10519
  _this.show();
10401
10520
  }, _this.options.hoverDelay);
10402
10521
  }
10403
10522
  })
10404
- .on('mouseleave.zf.tooltip', ignoreMousedisappear(function(e) {
10523
+ .on('mouseleave.zf.tooltip', ignoreMousedisappear(function() {
10405
10524
  clearTimeout(_this.timeout);
10406
10525
  if (!isFocus || (_this.isClick && !_this.options.clickOpen)) {
10407
10526
  _this.hide();
@@ -10411,13 +10530,13 @@ class Tooltip extends Positionable {
10411
10530
 
10412
10531
  if (hasTouch) {
10413
10532
  this.$element
10414
- .on('tap.zf.tooltip touchend.zf.tooltip', function (e) {
10533
+ .on('tap.zf.tooltip touchend.zf.tooltip', function () {
10415
10534
  _this.isActive ? _this.hide() : _this.show();
10416
10535
  });
10417
10536
  }
10418
10537
 
10419
10538
  if (this.options.clickOpen) {
10420
- this.$element.on('mousedown.zf.tooltip', function(e) {
10539
+ this.$element.on('mousedown.zf.tooltip', function() {
10421
10540
  if (_this.isClick) ; else {
10422
10541
  _this.isClick = true;
10423
10542
  if ((_this.options.disableHover || !_this.$element.attr('tabindex')) && !_this.isActive) {
@@ -10426,7 +10545,7 @@ class Tooltip extends Positionable {
10426
10545
  }
10427
10546
  });
10428
10547
  } else {
10429
- this.$element.on('mousedown.zf.tooltip', function(e) {
10548
+ this.$element.on('mousedown.zf.tooltip', function() {
10430
10549
  _this.isClick = true;
10431
10550
  });
10432
10551
  }
@@ -10438,7 +10557,7 @@ class Tooltip extends Positionable {
10438
10557
  });
10439
10558
 
10440
10559
  this.$element
10441
- .on('focus.zf.tooltip', function(e) {
10560
+ .on('focus.zf.tooltip', function() {
10442
10561
  isFocus = true;
10443
10562
  if (_this.isClick) {
10444
10563
  // If we're not showing open on clicks, we need to pretend a click-launched focus isn't
@@ -10450,7 +10569,7 @@ class Tooltip extends Positionable {
10450
10569
  }
10451
10570
  })
10452
10571
 
10453
- .on('focusout.zf.tooltip', function(e) {
10572
+ .on('focusout.zf.tooltip', function() {
10454
10573
  isFocus = false;
10455
10574
  _this.isClick = false;
10456
10575
  _this.hide();
@@ -10649,7 +10768,7 @@ Tooltip.defaults = {
10649
10768
  };
10650
10769
 
10651
10770
  // The plugin matches the plugin classes with these plugin instances.
10652
- var MenuPlugins$1 = {
10771
+ var MenuPlugins = {
10653
10772
  tabs: {
10654
10773
  cssClass: 'tabs',
10655
10774
  plugin: Tabs,
@@ -10702,6 +10821,7 @@ class ResponsiveAccordionTabs extends Plugin{
10702
10821
  if (!this.$element.attr('id')) {
10703
10822
  this.$element.attr('id',GetYoDigits(6, 'responsiveaccordiontabs'));
10704
10823
  }
10824
+
10705
10825
  this._init();
10706
10826
  this._events();
10707
10827
  }
@@ -10727,8 +10847,8 @@ class ResponsiveAccordionTabs extends Plugin{
10727
10847
  let ruleSize = rule.length > 1 ? rule[0] : 'small';
10728
10848
  let rulePlugin = rule.length > 1 ? rule[1] : rule[0];
10729
10849
 
10730
- if (MenuPlugins$1[rulePlugin] !== null) {
10731
- rulesTree[ruleSize] = MenuPlugins$1[rulePlugin];
10850
+ if (MenuPlugins[rulePlugin] !== null) {
10851
+ rulesTree[ruleSize] = MenuPlugins[rulePlugin];
10732
10852
  }
10733
10853
  }
10734
10854
 
@@ -10746,9 +10866,9 @@ class ResponsiveAccordionTabs extends Plugin{
10746
10866
  //get all defaults and options
10747
10867
  var _this = this;
10748
10868
  _this.allOptions = {};
10749
- for (var key in MenuPlugins$1) {
10750
- if (MenuPlugins$1.hasOwnProperty(key)) {
10751
- var obj = MenuPlugins$1[key];
10869
+ for (var key in MenuPlugins) {
10870
+ if (MenuPlugins.hasOwnProperty(key)) {
10871
+ var obj = MenuPlugins[key];
10752
10872
  try {
10753
10873
  var dummyPlugin = $('<ul></ul>');
10754
10874
  var tmpPlugin = new obj.plugin(dummyPlugin,_this.options);
@@ -10761,6 +10881,7 @@ class ResponsiveAccordionTabs extends Plugin{
10761
10881
  tmpPlugin.destroy();
10762
10882
  }
10763
10883
  catch(e) {
10884
+ console.warn(`Warning: Problems getting Accordion/Tab options: ${e}`);
10764
10885
  }
10765
10886
  }
10766
10887
  }
@@ -10797,7 +10918,7 @@ class ResponsiveAccordionTabs extends Plugin{
10797
10918
  if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return;
10798
10919
 
10799
10920
  // Remove existing plugin-specific CSS classes
10800
- $.each(MenuPlugins$1, function(key, value) {
10921
+ $.each(MenuPlugins, function(key, value) {
10801
10922
  _this.$element.removeClass(value.cssClass);
10802
10923
  });
10803
10924
 
@@ -10824,6 +10945,7 @@ class ResponsiveAccordionTabs extends Plugin{
10824
10945
  if (fromString === toSet) {
10825
10946
  return;
10826
10947
  }
10948
+
10827
10949
  var tabsTitle = _this.allOptions.linkClass?_this.allOptions.linkClass:'tabs-title';
10828
10950
  var tabsPanel = _this.allOptions.panelClass?_this.allOptions.panelClass:'tabs-panel';
10829
10951
 
@@ -10834,9 +10956,10 @@ class ResponsiveAccordionTabs extends Plugin{
10834
10956
  if (fromString === 'tabs') {
10835
10957
  $panels = $panels.children('.'+tabsPanel).removeClass(tabsPanel).removeAttr('role').removeAttr('aria-hidden').removeAttr('aria-labelledby');
10836
10958
  $panels.children('a').removeAttr('role').removeAttr('aria-controls').removeAttr('aria-selected');
10837
- }else{
10959
+ } else {
10838
10960
  $panels = $liHeads.children('[data-tab-content]').removeClass('accordion-content');
10839
10961
  }
10962
+
10840
10963
  $panels.css({display:'',visibility:''});
10841
10964
  $liHeads.css({display:'',visibility:''});
10842
10965
  if (toSet === 'accordion') {
@@ -10846,29 +10969,33 @@ class ResponsiveAccordionTabs extends Plugin{
10846
10969
  $liHeads.addClass('accordion-item').attr('data-accordion-item','');
10847
10970
  $liHeadsA.addClass('accordion-title');
10848
10971
  });
10849
- }else if (toSet === 'tabs'){
10972
+ } else if (toSet === 'tabs') {
10850
10973
  var $tabsContent = $('[data-tabs-content='+_this.$element.attr('id')+']');
10851
10974
  var $placeholder = $('#tabs-placeholder-'+_this.$element.attr('id'));
10852
10975
  if ($placeholder.length) {
10853
10976
  $tabsContent = $('<div class="tabs-content"></div>').insertAfter($placeholder).attr('data-tabs-content',_this.$element.attr('id'));
10854
10977
  $placeholder.remove();
10855
- }else{
10978
+ } else {
10856
10979
  $tabsContent = $('<div class="tabs-content"></div>').insertAfter(_this.$element).attr('data-tabs-content',_this.$element.attr('id'));
10857
- } $panels.each(function(key,value){
10980
+ }
10981
+ $panels.each(function(key,value){
10858
10982
  var tempValue = $(value).appendTo($tabsContent).addClass(tabsPanel);
10859
10983
  var hash = $liHeadsA.get(key).hash.slice(1);
10860
10984
  var id = $(value).attr('id') || GetYoDigits(6, 'accordion');
10861
10985
  if (hash !== id) {
10862
10986
  if (hash !== '') {
10863
10987
  $(value).attr('id',hash);
10864
- }else{
10988
+ } else {
10865
10989
  hash = id;
10866
10990
  $(value).attr('id',hash);
10867
10991
  $($liHeadsA.get(key)).attr('href',$($liHeadsA.get(key)).attr('href').replace('#','')+'#'+hash);
10868
- } } var isActive = $($liHeads.get(key)).hasClass('is-active');
10992
+ }
10993
+ }
10994
+ var isActive = $($liHeads.get(key)).hasClass('is-active');
10869
10995
  if (isActive) {
10870
10996
  tempValue.addClass('is-active');
10871
- } });
10997
+ }
10998
+ });
10872
10999
  $liHeads.addClass(tabsTitle);
10873
11000
  } }
10874
11001
 
@@ -10879,7 +11006,7 @@ class ResponsiveAccordionTabs extends Plugin{
10879
11006
  * @see Tabs.selectTab
10880
11007
  * @function
10881
11008
  */
10882
- open(target) {
11009
+ open() {
10883
11010
  if (this.currentRule && typeof this.currentRule.open === 'function') {
10884
11011
  return this.currentRule.open(this.currentPlugin, ...arguments);
10885
11012
  }
@@ -10891,7 +11018,7 @@ class ResponsiveAccordionTabs extends Plugin{
10891
11018
  * @see Accordion.up
10892
11019
  * @function
10893
11020
  */
10894
- close(target) {
11021
+ close() {
10895
11022
  if (this.currentRule && typeof this.currentRule.close === 'function') {
10896
11023
  return this.currentRule.close(this.currentPlugin, ...arguments);
10897
11024
  }
@@ -10903,7 +11030,7 @@ class ResponsiveAccordionTabs extends Plugin{
10903
11030
  * @see Accordion.toggle
10904
11031
  * @function
10905
11032
  */
10906
- toggle(target) {
11033
+ toggle() {
10907
11034
  if (this.currentRule && typeof this.currentRule.toggle === 'function') {
10908
11035
  return this.currentRule.toggle(this.currentPlugin, ...arguments);
10909
11036
  }
@@ -10968,6 +11095,5 @@ Foundation.plugin(Toggler, 'Toggler');
10968
11095
  Foundation.plugin(Tooltip, 'Tooltip');
10969
11096
  Foundation.plugin(ResponsiveAccordionTabs, 'ResponsiveAccordionTabs');
10970
11097
 
10971
- export default Foundation;
10972
- export { Abide, Accordion, AccordionMenu, Box, Foundation as Core, foundation_core_utils as CoreUtils, Drilldown, Dropdown, DropdownMenu, Equalizer, Foundation, Interchange, Keyboard, Magellan, MediaQuery, Motion, Move, Nest, OffCanvas, Orbit, ResponsiveAccordionTabs, ResponsiveMenu, ResponsiveToggle, Reveal, Slider, SmoothScroll, Sticky, Tabs, Timer, Toggler, Tooltip, Touch, Triggers, onImagesLoaded };
11098
+ export { Abide, Accordion, AccordionMenu, Box, Foundation as Core, foundation_core_utils as CoreUtils, Drilldown, Dropdown, DropdownMenu, Equalizer, Foundation, Interchange, Keyboard, Magellan, MediaQuery, Motion, Move, Nest, OffCanvas, Orbit, ResponsiveAccordionTabs, ResponsiveMenu, ResponsiveToggle, Reveal, Slider, SmoothScroll, Sticky, Tabs, Timer, Toggler, Tooltip, Touch, Triggers, Foundation as default, onImagesLoaded };
10973
11099
  //# sourceMappingURL=foundation.es6.js.map