foundation-rails 6.2.4.0 → 6.3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/Rakefile +2 -0
  4. data/bower.json +2 -2
  5. data/lib/foundation/rails/version.rb +1 -1
  6. data/lib/generators/foundation/templates/_settings.scss +117 -70
  7. data/lib/generators/foundation/templates/foundation_and_overrides.scss +2 -1
  8. data/vendor/assets/_vendor/normalize-scss/sass/_normalize.scss +3 -0
  9. data/vendor/assets/_vendor/normalize-scss/sass/normalize/_import-now.scss +11 -0
  10. data/vendor/assets/_vendor/normalize-scss/sass/normalize/_normalize-mixin.scss +676 -0
  11. data/vendor/assets/_vendor/normalize-scss/sass/normalize/_variables.scss +36 -0
  12. data/vendor/assets/_vendor/normalize-scss/sass/normalize/_vertical-rhythm.scss +61 -0
  13. data/vendor/assets/_vendor/sassy-lists/stylesheets/functions/_purge.scss +38 -0
  14. data/vendor/assets/_vendor/sassy-lists/stylesheets/functions/_remove.scss +31 -0
  15. data/vendor/assets/_vendor/sassy-lists/stylesheets/functions/_replace.scss +46 -0
  16. data/vendor/assets/_vendor/sassy-lists/stylesheets/functions/_to-list.scss +27 -0
  17. data/vendor/assets/_vendor/sassy-lists/stylesheets/helpers/_missing-dependencies.scss +25 -0
  18. data/vendor/assets/_vendor/sassy-lists/stylesheets/helpers/_true.scss +13 -0
  19. data/vendor/assets/js/foundation.abide.js.es6 +28 -0
  20. data/vendor/assets/js/foundation.accordion.js.es6 +1 -1
  21. data/vendor/assets/js/foundation.accordionMenu.js.es6 +9 -1
  22. data/vendor/assets/js/foundation.core.js.es6 +4 -4
  23. data/vendor/assets/js/foundation.drilldown.js.es6 +128 -14
  24. data/vendor/assets/js/foundation.dropdown.js.es6 +48 -42
  25. data/vendor/assets/js/foundation.dropdownMenu.js.es6 +20 -18
  26. data/vendor/assets/js/foundation.equalizer.js.es6 +12 -6
  27. data/vendor/assets/js/foundation.interchange.js.es6 +3 -2
  28. data/vendor/assets/js/foundation.js.es6 +2 -1
  29. data/vendor/assets/js/foundation.magellan.js.es6 +28 -9
  30. data/vendor/assets/js/foundation.offcanvas.js.es6 +90 -123
  31. data/vendor/assets/js/foundation.orbit.js.es6 +61 -10
  32. data/vendor/assets/js/foundation.responsiveMenu.js.es6 +2 -0
  33. data/vendor/assets/js/foundation.responsiveToggle.js.es6 +52 -12
  34. data/vendor/assets/js/foundation.reveal.js.es6 +48 -48
  35. data/vendor/assets/js/foundation.slider.js.es6 +124 -42
  36. data/vendor/assets/js/foundation.sticky.js.es6 +11 -9
  37. data/vendor/assets/js/foundation.tabs.js.es6 +164 -35
  38. data/vendor/assets/js/foundation.toggler.js.es6 +3 -0
  39. data/vendor/assets/js/foundation.tooltip.js.es6 +20 -10
  40. data/vendor/assets/js/foundation.util.box.js.es6 +2 -2
  41. data/vendor/assets/js/foundation.util.keyboard.js.es6 +37 -0
  42. data/vendor/assets/js/foundation.util.mediaQuery.js.es6 +16 -0
  43. data/vendor/assets/js/foundation.util.motion.js.es6 +7 -1
  44. data/vendor/assets/js/foundation.util.nest.js.es6 +10 -5
  45. data/vendor/assets/js/foundation.util.timerAndImageLoader.js.es6 +6 -4
  46. data/vendor/assets/js/foundation.util.triggers.js.es6 +54 -36
  47. data/vendor/assets/js/foundation.zf.responsiveAccordionTabs.js.es6 +240 -0
  48. data/vendor/assets/scss/_global.scss +25 -450
  49. data/vendor/assets/scss/components/_accordion-menu.scss +8 -4
  50. data/vendor/assets/scss/components/_accordion.scss +43 -22
  51. data/vendor/assets/scss/components/_badge.scss +17 -9
  52. data/vendor/assets/scss/components/_breadcrumbs.scss +7 -5
  53. data/vendor/assets/scss/components/_button-group.scss +54 -6
  54. data/vendor/assets/scss/components/_button.scss +27 -16
  55. data/vendor/assets/scss/components/_callout.scss +3 -2
  56. data/vendor/assets/scss/components/_card.scss +121 -0
  57. data/vendor/assets/scss/components/_close-button.scss +54 -13
  58. data/vendor/assets/scss/components/_drilldown.scss +19 -5
  59. data/vendor/assets/scss/components/_dropdown-menu.scss +23 -18
  60. data/vendor/assets/scss/components/_dropdown.scss +14 -7
  61. data/vendor/assets/scss/components/_flex-video.scss +1 -63
  62. data/vendor/assets/scss/components/_float.scss +1 -1
  63. data/vendor/assets/scss/components/_label.scss +16 -8
  64. data/vendor/assets/scss/components/_media-object.scss +2 -3
  65. data/vendor/assets/scss/components/_menu.scss +68 -33
  66. data/vendor/assets/scss/components/_off-canvas.scss +231 -80
  67. data/vendor/assets/scss/components/_orbit.scss +8 -6
  68. data/vendor/assets/scss/components/_pagination.scss +42 -22
  69. data/vendor/assets/scss/components/_progress-bar.scss +1 -1
  70. data/vendor/assets/scss/components/_responsive-embed.scss +66 -0
  71. data/vendor/assets/scss/components/_reveal.scss +17 -11
  72. data/vendor/assets/scss/components/_slider.scss +6 -1
  73. data/vendor/assets/scss/components/_sticky.scss +3 -3
  74. data/vendor/assets/scss/components/_switch.scss +47 -36
  75. data/vendor/assets/scss/components/_table.scss +83 -23
  76. data/vendor/assets/scss/components/_tabs.scss +54 -23
  77. data/vendor/assets/scss/components/_thumbnail.scss +17 -4
  78. data/vendor/assets/scss/components/_title-bar.scss +5 -6
  79. data/vendor/assets/scss/components/_tooltip.scss +15 -12
  80. data/vendor/assets/scss/components/_top-bar.scss +11 -8
  81. data/vendor/assets/scss/forms/_checkbox.scss +2 -1
  82. data/vendor/assets/scss/forms/_error.scss +10 -6
  83. data/vendor/assets/scss/forms/_fieldset.scss +7 -7
  84. data/vendor/assets/scss/forms/_input-group.scss +17 -11
  85. data/vendor/assets/scss/forms/_label.scss +2 -0
  86. data/vendor/assets/scss/forms/_meter.scss +9 -10
  87. data/vendor/assets/scss/forms/_progress.scss +9 -9
  88. data/vendor/assets/scss/forms/_range.scss +20 -15
  89. data/vendor/assets/scss/forms/_select.scss +26 -8
  90. data/vendor/assets/scss/forms/_text.scss +19 -16
  91. data/vendor/assets/scss/foundation.scss +19 -3
  92. data/vendor/assets/scss/grid/_classes.scss +31 -14
  93. data/vendor/assets/scss/grid/_column.scss +10 -24
  94. data/vendor/assets/scss/grid/_flex-grid.scss +84 -76
  95. data/vendor/assets/scss/grid/_grid.scss +0 -16
  96. data/vendor/assets/scss/grid/_gutter.scss +53 -5
  97. data/vendor/assets/scss/grid/_layout.scss +3 -3
  98. data/vendor/assets/scss/grid/_position.scss +3 -3
  99. data/vendor/assets/scss/grid/_row.scss +24 -19
  100. data/vendor/assets/scss/settings/_settings.scss +117 -70
  101. data/vendor/assets/scss/typography/_base.scss +110 -44
  102. data/vendor/assets/scss/typography/_helpers.scss +1 -0
  103. data/vendor/assets/scss/typography/_print.scss +7 -3
  104. data/vendor/assets/scss/typography/_typography.scss +0 -2
  105. data/vendor/assets/scss/util/_breakpoint.scss +28 -19
  106. data/vendor/assets/scss/util/_color.scss +69 -16
  107. data/vendor/assets/scss/util/_flex.scss +20 -3
  108. data/vendor/assets/scss/util/_math.scss +72 -0
  109. data/vendor/assets/scss/util/_mixins.scss +63 -26
  110. data/vendor/assets/scss/util/_selector.scss +3 -2
  111. data/vendor/assets/scss/util/_unit.scss +61 -4
  112. data/vendor/assets/scss/util/_util.scss +1 -0
  113. data/vendor/assets/scss/util/_value.scss +33 -0
  114. metadata +17 -2
@@ -27,9 +27,7 @@ class Dropdown {
27
27
  Foundation.Keyboard.register('Dropdown', {
28
28
  'ENTER': 'open',
29
29
  'SPACE': 'open',
30
- 'ESCAPE': 'close',
31
- 'TAB': 'tab_forward',
32
- 'SHIFT_TAB': 'tab_backward'
30
+ 'ESCAPE': 'close'
33
31
  });
34
32
  }
35
33
 
@@ -51,6 +49,11 @@ class Dropdown {
51
49
 
52
50
  });
53
51
 
52
+ if(this.options.parentClass){
53
+ this.$parent = this.$element.parents('.' + this.options.parentClass);
54
+ }else{
55
+ this.$parent = null;
56
+ }
54
57
  this.options.positionClass = this.getPositionClass();
55
58
  this.counter = 4;
56
59
  this.usedPositions = [];
@@ -134,11 +137,19 @@ class Dropdown {
134
137
  param = (direction === 'top') ? 'height' : 'width',
135
138
  offset = (param === 'height') ? this.options.vOffset : this.options.hOffset;
136
139
 
140
+ if(($eleDims.width >= $eleDims.windowDims.width) || (!this.counter && !Foundation.Box.ImNotTouchingYou(this.$element, this.$parent))){
141
+ var newWidth = $eleDims.windowDims.width,
142
+ parentHOffset = 0;
143
+ if(this.$parent){
144
+ var $parentDims = Foundation.Box.GetDimensions(this.$parent),
145
+ parentHOffset = $parentDims.offset.left;
146
+ if ($parentDims.width < newWidth){
147
+ newWidth = $parentDims.width;
148
+ }
149
+ }
137
150
 
138
-
139
- if(($eleDims.width >= $eleDims.windowDims.width) || (!this.counter && !Foundation.Box.ImNotTouchingYou(this.$element))){
140
- this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, 'center bottom', this.options.vOffset, this.options.hOffset, true)).css({
141
- 'width': $eleDims.windowDims.width - (this.options.hOffset * 2),
151
+ this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, 'center bottom', this.options.vOffset, this.options.hOffset + parentHOffset, true)).css({
152
+ 'width': newWidth - (this.options.hOffset * 2),
142
153
  'height': 'auto'
143
154
  });
144
155
  this.classChanged = true;
@@ -147,7 +158,7 @@ class Dropdown {
147
158
 
148
159
  this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, position, this.options.vOffset, this.options.hOffset));
149
160
 
150
- while(!Foundation.Box.ImNotTouchingYou(this.$element, false, true) && this.counter){
161
+ while(!Foundation.Box.ImNotTouchingYou(this.$element, this.$parent, true) && this.counter){
151
162
  this._reposition(position);
152
163
  this._setPosition();
153
164
  }
@@ -170,20 +181,21 @@ class Dropdown {
170
181
  if(this.options.hover){
171
182
  this.$anchor.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
172
183
  .on('mouseenter.zf.dropdown', function(){
173
- if($('body[data-whatinput="mouse"]').is('*')) {
174
- clearTimeout(_this.timeout);
175
- _this.timeout = setTimeout(function(){
176
- _this.open();
177
- _this.$anchor.data('hover', true);
178
- }, _this.options.hoverDelay);
179
- }
180
- }).on('mouseleave.zf.dropdown', function(){
181
- clearTimeout(_this.timeout);
182
- _this.timeout = setTimeout(function(){
183
- _this.close();
184
- _this.$anchor.data('hover', false);
185
- }, _this.options.hoverDelay);
186
- });
184
+ var bodyData = $('body').data();
185
+ if(typeof(bodyData.whatinput) === 'undefined' || bodyData.whatinput === 'mouse') {
186
+ clearTimeout(_this.timeout);
187
+ _this.timeout = setTimeout(function(){
188
+ _this.open();
189
+ _this.$anchor.data('hover', true);
190
+ }, _this.options.hoverDelay);
191
+ }
192
+ }).on('mouseleave.zf.dropdown', function(){
193
+ clearTimeout(_this.timeout);
194
+ _this.timeout = setTimeout(function(){
195
+ _this.close();
196
+ _this.$anchor.data('hover', false);
197
+ }, _this.options.hoverDelay);
198
+ });
187
199
  if(this.options.hoverPane){
188
200
  this.$element.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
189
201
  .on('mouseenter.zf.dropdown', function(){
@@ -203,26 +215,6 @@ class Dropdown {
203
215
  visibleFocusableElements = Foundation.Keyboard.findFocusable(_this.$element);
204
216
 
205
217
  Foundation.Keyboard.handleKey(e, 'Dropdown', {
206
- tab_forward: function() {
207
- if (_this.$element.find(':focus').is(visibleFocusableElements.eq(-1))) { // left modal downwards, setting focus to first element
208
- if (_this.options.trapFocus) { // if focus shall be trapped
209
- visibleFocusableElements.eq(0).focus();
210
- e.preventDefault();
211
- } else { // if focus is not trapped, close dropdown on focus out
212
- _this.close();
213
- }
214
- }
215
- },
216
- tab_backward: function() {
217
- if (_this.$element.find(':focus').is(visibleFocusableElements.eq(0)) || _this.$element.is(':focus')) { // left modal upwards, setting focus to last element
218
- if (_this.options.trapFocus) { // if focus shall be trapped
219
- visibleFocusableElements.eq(-1).focus();
220
- e.preventDefault();
221
- } else { // if focus is not trapped, close dropdown on focus out
222
- _this.close();
223
- }
224
- }
225
- },
226
218
  open: function() {
227
219
  if ($target.is(_this.$anchor)) {
228
220
  _this.open();
@@ -288,6 +280,10 @@ class Dropdown {
288
280
 
289
281
  if(this.options.closeOnClick){ this._addBodyHandler(); }
290
282
 
283
+ if (this.options.trapFocus) {
284
+ Foundation.Keyboard.trapFocus(this.$element);
285
+ }
286
+
291
287
  /**
292
288
  * Fires once the dropdown is visible.
293
289
  * @event Dropdown#show
@@ -322,6 +318,10 @@ class Dropdown {
322
318
  this.usedPositions.length = 0;
323
319
  }
324
320
  this.$element.trigger('hide.zf.dropdown', [this.$element]);
321
+
322
+ if (this.options.trapFocus) {
323
+ Foundation.Keyboard.releaseFocus(this.$element);
324
+ }
325
325
  }
326
326
 
327
327
  /**
@@ -350,6 +350,12 @@ class Dropdown {
350
350
  }
351
351
 
352
352
  Dropdown.defaults = {
353
+ /**
354
+ * Class that designates bounding container of Dropdown (Default: window)
355
+ * @option
356
+ * @example 'dropdown-parent'
357
+ */
358
+ parentClass: null,
353
359
  /**
354
360
  * Amount of time to delay opening a submenu on hover event.
355
361
  * @option
@@ -95,11 +95,6 @@ class DropdownMenu {
95
95
  _this._show($sub);
96
96
  $elem.add($elem.parentsUntil(_this.$element, `.${parClass}`)).attr('data-is-click', true);
97
97
  }
98
- } else {
99
- if(_this.options.closeOnClickInside){
100
- _this._hide($elem);
101
- }
102
- return;
103
98
  }
104
99
  };
105
100
 
@@ -107,16 +102,27 @@ class DropdownMenu {
107
102
  this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', handleClickFn);
108
103
  }
109
104
 
105
+ // Handle Leaf element Clicks
106
+ if(_this.options.closeOnClickInside){
107
+ this.$menuItems.on('click.zf.dropdownmenu touchend.zf.dropdownmenu', function(e) {
108
+ var $elem = $(this),
109
+ hasSub = $elem.hasClass(parClass);
110
+ if(!hasSub){
111
+ _this._hide();
112
+ }
113
+ });
114
+ }
115
+
110
116
  if (!this.options.disableHover) {
111
117
  this.$menuItems.on('mouseenter.zf.dropdownmenu', function(e) {
112
118
  var $elem = $(this),
113
119
  hasSub = $elem.hasClass(parClass);
114
120
 
115
121
  if (hasSub) {
116
- clearTimeout(_this.delay);
117
- _this.delay = setTimeout(function() {
122
+ clearTimeout($elem.data('_delay'));
123
+ $elem.data('_delay', setTimeout(function() {
118
124
  _this._show($elem.children('.is-dropdown-submenu'));
119
- }, _this.options.hoverDelay);
125
+ }, _this.options.hoverDelay));
120
126
  }
121
127
  }).on('mouseleave.zf.dropdownmenu', function(e) {
122
128
  var $elem = $(this),
@@ -124,10 +130,10 @@ class DropdownMenu {
124
130
  if (hasSub && _this.options.autoclose) {
125
131
  if ($elem.attr('data-is-click') === 'true' && _this.options.clickOpen) { return false; }
126
132
 
127
- clearTimeout(_this.delay);
128
- _this.delay = setTimeout(function() {
133
+ clearTimeout($elem.data('_delay'));
134
+ $elem.data('_delay', setTimeout(function() {
129
135
  _this._hide($elem);
130
- }, _this.options.closingTime);
136
+ }, _this.options.closingTime));
131
137
  }
132
138
  });
133
139
  }
@@ -268,9 +274,8 @@ class DropdownMenu {
268
274
  }));
269
275
  var $sibs = $sub.parent('li.is-dropdown-submenu-parent').siblings('li.is-dropdown-submenu-parent');
270
276
  this._hide($sibs, idx);
271
- $sub.css('visibility', 'hidden').addClass('js-dropdown-active').attr({'aria-hidden': false})
272
- .parent('li.is-dropdown-submenu-parent').addClass('is-active')
273
- .attr({'aria-expanded': true});
277
+ $sub.css('visibility', 'hidden').addClass('js-dropdown-active')
278
+ .parent('li.is-dropdown-submenu-parent').addClass('is-active');
274
279
  var clear = Foundation.Box.ImNotTouchingYou($sub, null, true);
275
280
  if (!clear) {
276
281
  var oldClass = this.options.alignment === 'left' ? '-right' : '-left',
@@ -314,13 +319,10 @@ class DropdownMenu {
314
319
 
315
320
  if (somethingToClose) {
316
321
  $toClose.find('li.is-active').add($toClose).attr({
317
- 'aria-expanded': false,
318
322
  'data-is-click': false
319
323
  }).removeClass('is-active');
320
324
 
321
- $toClose.find('ul.js-dropdown-active').attr({
322
- 'aria-hidden': true
323
- }).removeClass('js-dropdown-active');
325
+ $toClose.find('ul.js-dropdown-active').removeClass('js-dropdown-active');
324
326
 
325
327
  if (this.changed || $toClose.find('opens-inner').length) {
326
328
  var oldClass = this.options.alignment === 'left' ? 'right' : 'left';
@@ -36,6 +36,7 @@ class Equalizer {
36
36
 
37
37
  this.$watched = $watched.length ? $watched : this.$element.find('[data-equalizer-watch]');
38
38
  this.$element.attr('data-resize', (eqId || Foundation.GetYoDigits(6, 'eq')));
39
+ this.$element.attr('data-mutate', (eqId || Foundation.GetYoDigits(6, 'eq')));
39
40
 
40
41
  this.hasNested = this.$element.find('[data-equalizer]').length > 0;
41
42
  this.isNested = this.$element.parentsUntil(document.body, '[data-equalizer]').length > 0;
@@ -70,7 +71,8 @@ class Equalizer {
70
71
  this.isOn = false;
71
72
  this.$element.off({
72
73
  '.zf.equalizer': this._bindHandler.onPostEqualizedBound,
73
- 'resizeme.zf.trigger': this._bindHandler.onResizeMeBound
74
+ 'resizeme.zf.trigger': this._bindHandler.onResizeMeBound,
75
+ 'mutateme.zf.trigger': this._bindHandler.onResizeMeBound
74
76
  });
75
77
  }
76
78
 
@@ -101,6 +103,7 @@ class Equalizer {
101
103
  this.$element.on('postequalized.zf.equalizer', this._bindHandler.onPostEqualizedBound);
102
104
  }else{
103
105
  this.$element.on('resizeme.zf.trigger', this._bindHandler.onResizeMeBound);
106
+ this.$element.on('mutateme.zf.trigger', this._bindHandler.onResizeMeBound);
104
107
  }
105
108
  this.isOn = true;
106
109
  }
@@ -110,7 +113,7 @@ class Equalizer {
110
113
  * @private
111
114
  */
112
115
  _checkMQ() {
113
- var tooSmall = !Foundation.MediaQuery.atLeast(this.options.equalizeOn);
116
+ var tooSmall = !Foundation.MediaQuery.is(this.options.equalizeOn);
114
117
  if(tooSmall){
115
118
  if(this.isOn){
116
119
  this._pauseEvents();
@@ -155,6 +158,9 @@ class Equalizer {
155
158
  * @private
156
159
  */
157
160
  _isStacked() {
161
+ if (!this.$watched[0] || !this.$watched[1]) {
162
+ return true;
163
+ }
158
164
  return this.$watched[0].getBoundingClientRect().top !== this.$watched[1].getBoundingClientRect().top;
159
165
  }
160
166
 
@@ -230,8 +236,8 @@ class Equalizer {
230
236
  * Changes the CSS height property of each child in an Equalizer parent to match the tallest by row
231
237
  * @param {array} groups - An array of heights of children within Equalizer container grouped by row with element,height and max as last child
232
238
  * @fires Equalizer#preequalized
233
- * @fires Equalizer#preequalizedRow
234
- * @fires Equalizer#postequalizedRow
239
+ * @fires Equalizer#preequalizedrow
240
+ * @fires Equalizer#postequalizedrow
235
241
  * @fires Equalizer#postequalized
236
242
  */
237
243
  applyHeightByRow(groups) {
@@ -248,7 +254,7 @@ class Equalizer {
248
254
  }
249
255
  /**
250
256
  * Fires before the heights per row are applied
251
- * @event Equalizer#preequalizedRow
257
+ * @event Equalizer#preequalizedrow
252
258
  */
253
259
  this.$element.trigger('preequalizedrow.zf.equalizer');
254
260
  for (var j = 0, lenJ = (groupsILength-1); j < lenJ ; j++) {
@@ -256,7 +262,7 @@ class Equalizer {
256
262
  }
257
263
  /**
258
264
  * Fires when the heights per row have been applied
259
- * @event Equalizer#postequalizedRow
265
+ * @event Equalizer#postequalizedrow
260
266
  */
261
267
  this.$element.trigger('postequalizedrow.zf.equalizer');
262
268
  }
@@ -46,7 +46,9 @@ class Interchange {
46
46
  * @private
47
47
  */
48
48
  _events() {
49
- $(window).on('resize.zf.interchange', Foundation.util.throttle(this._reflow.bind(this), 50));
49
+ $(window).on('resize.zf.interchange', Foundation.util.throttle(() => {
50
+ this._reflow();
51
+ }, 50));
50
52
  }
51
53
 
52
54
  /**
@@ -61,7 +63,6 @@ class Interchange {
61
63
  for (var i in this.rules) {
62
64
  if(this.rules.hasOwnProperty(i)) {
63
65
  var rule = this.rules[i];
64
-
65
66
  if (window.matchMedia(rule.query).matches) {
66
67
  match = rule;
67
68
  }
@@ -25,4 +25,5 @@
25
25
  //= require foundation.util.nest.js
26
26
  //= require foundation.util.timerAndImageLoader.js
27
27
  //= require foundation.util.touch.js
28
- //= require foundation.util.triggers.js
28
+ //= require foundation.util.triggers.js
29
+ //= require foundation.zf.responsiveAccordionTabs.js
@@ -20,6 +20,7 @@ class Magellan {
20
20
  this.options = $.extend({}, Magellan.defaults, this.$element.data(), options);
21
21
 
22
22
  this._init();
23
+ this.calcPoints();
23
24
 
24
25
  Foundation.registerPlugin(this, 'Magellan');
25
26
  }
@@ -94,6 +95,11 @@ class Magellan {
94
95
  e.preventDefault();
95
96
  var arrival = this.getAttribute('href');
96
97
  _this.scrollToLoc(arrival);
98
+ });
99
+ $(window).on('popstate', function(e) {
100
+ if(_this.options.deepLinking) {
101
+ _this.scrollToLoc(window.location.hash);
102
+ }
97
103
  });
98
104
  }
99
105
 
@@ -105,9 +111,16 @@ class Magellan {
105
111
  scrollToLoc(loc) {
106
112
  // Do nothing if target does not exist to prevent errors
107
113
  if (!$(loc).length) {return false;}
108
- var scrollPos = Math.round($(loc).offset().top - this.options.threshold / 2 - this.options.barOffset);
109
-
110
- $('html, body').stop(true).animate({ scrollTop: scrollPos }, this.options.animationDuration, this.options.animationEasing);
114
+ this._inTransition = true;
115
+ var _this = this,
116
+ scrollPos = Math.round($(loc).offset().top - this.options.threshold / 2 - this.options.barOffset);
117
+
118
+ $('html, body').stop(true).animate(
119
+ { scrollTop: scrollPos },
120
+ this.options.animationDuration,
121
+ this.options.animationEasing,
122
+ function() {_this._inTransition = false; _this._updateActive()}
123
+ );
111
124
  }
112
125
 
113
126
  /**
@@ -126,11 +139,12 @@ class Magellan {
126
139
  * @fires Magellan#update
127
140
  */
128
141
  _updateActive(/*evt, elem, scrollPos*/) {
142
+ if(this._inTransition) {return;}
129
143
  var winPos = /*scrollPos ||*/ parseInt(window.pageYOffset, 10),
130
144
  curIdx;
131
145
 
132
146
  if(winPos + this.winHeight === this.docHeight){ curIdx = this.points.length - 1; }
133
- else if(winPos < this.points[0]){ curIdx = 0; }
147
+ else if(winPos < this.points[0]){ curIdx = undefined; }
134
148
  else{
135
149
  var isDown = this.scrollPos < winPos,
136
150
  _this = this,
@@ -144,11 +158,16 @@ class Magellan {
144
158
  this.$active = this.$links.filter('[href="#' + this.$targets.eq(curIdx).data('magellan-target') + '"]').addClass(this.options.activeClass);
145
159
 
146
160
  if(this.options.deepLinking){
147
- var hash = this.$active[0].getAttribute('href');
148
- if(window.history.pushState){
149
- window.history.pushState(null, null, hash);
150
- }else{
151
- window.location.hash = hash;
161
+ var hash = "";
162
+ if(curIdx != undefined){
163
+ hash = this.$active[0].getAttribute('href');
164
+ }
165
+ if(hash !== window.location.hash) {
166
+ if(window.history.pushState){
167
+ window.history.pushState(null, null, hash);
168
+ }else{
169
+ window.location.hash = hash;
170
+ }
152
171
  }
153
172
  }
154
173
 
@@ -44,33 +44,35 @@ class OffCanvas {
44
44
 
45
45
  this.$element.attr('aria-hidden', 'true');
46
46
 
47
+ this.$element.addClass(`is-transition-${this.options.transition}`);
48
+
47
49
  // Find triggers that affect this element and add aria-expanded to them
48
50
  this.$triggers = $(document)
49
51
  .find('[data-open="'+id+'"], [data-close="'+id+'"], [data-toggle="'+id+'"]')
50
52
  .attr('aria-expanded', 'false')
51
53
  .attr('aria-controls', id);
52
54
 
53
- // Add a close trigger over the body if necessary
54
- if (this.options.closeOnClick) {
55
- if ($('.js-off-canvas-exit').length) {
56
- this.$exiter = $('.js-off-canvas-exit');
55
+ // Add an overlay over the content if necessary
56
+ if (this.options.contentOverlay === true) {
57
+ var overlay = document.createElement('div');
58
+ var overlayPosition = $(this.$element).css("position") === 'fixed' ? 'is-overlay-fixed' : 'is-overlay-absolute';
59
+ overlay.setAttribute('class', 'js-off-canvas-overlay ' + overlayPosition);
60
+ this.$overlay = $(overlay);
61
+ if(overlayPosition === 'is-overlay-fixed') {
62
+ $('body').append(this.$overlay);
57
63
  } else {
58
- var exiter = document.createElement('div');
59
- exiter.setAttribute('class', 'js-off-canvas-exit');
60
- $('[data-off-canvas-content]').append(exiter);
61
-
62
- this.$exiter = $(exiter);
64
+ this.$element.siblings('[data-off-canvas-content]').append(this.$overlay);
63
65
  }
64
66
  }
65
67
 
66
68
  this.options.isRevealed = this.options.isRevealed || new RegExp(this.options.revealClass, 'g').test(this.$element[0].className);
67
69
 
68
- if (this.options.isRevealed) {
70
+ if (this.options.isRevealed === true) {
69
71
  this.options.revealOn = this.options.revealOn || this.$element[0].className.match(/(reveal-for-medium|reveal-for-large)/g)[0].split('-')[2];
70
72
  this._setMQChecker();
71
73
  }
72
- if (!this.options.transitionTime) {
73
- this.options.transitionTime = parseFloat(window.getComputedStyle($('[data-off-canvas-wrapper]')[0]).transitionDuration) * 1000;
74
+ if (!this.options.transitionTime === true) {
75
+ this.options.transitionTime = parseFloat(window.getComputedStyle($('[data-off-canvas]')[0]).transitionDuration) * 1000;
74
76
  }
75
77
  }
76
78
 
@@ -87,8 +89,9 @@ class OffCanvas {
87
89
  'keydown.zf.offcanvas': this._handleKeyboard.bind(this)
88
90
  });
89
91
 
90
- if (this.options.closeOnClick && this.$exiter.length) {
91
- this.$exiter.on({'click.zf.offcanvas': this.close.bind(this)});
92
+ if (this.options.closeOnClick === true) {
93
+ var $target = this.options.contentOverlay ? this.$overlay : $('[data-off-canvas-content]');
94
+ $target.on({'click.zf.offcanvas': this.close.bind(this)});
92
95
  }
93
96
  }
94
97
 
@@ -122,19 +125,12 @@ class OffCanvas {
122
125
  if (isRevealed) {
123
126
  this.close();
124
127
  this.isRevealed = true;
125
- // if (!this.options.forceTop) {
126
- // var scrollPos = parseInt(window.pageYOffset);
127
- // this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
128
- // }
129
- // if (this.options.isSticky) { this._stick(); }
128
+ this.$element.attr('aria-hidden', 'false');
130
129
  this.$element.off('open.zf.trigger toggle.zf.trigger');
131
130
  if ($closer.length) { $closer.hide(); }
132
131
  } else {
133
132
  this.isRevealed = false;
134
- // if (this.options.isSticky || !this.options.forceTop) {
135
- // this.$element[0].style.transform = '';
136
- // $(window).off('scroll.zf.offcanvas');
137
- // }
133
+ this.$element.attr('aria-hidden', 'true');
138
134
  this.$element.on({
139
135
  'open.zf.trigger': this.open.bind(this),
140
136
  'toggle.zf.trigger': this.toggle.bind(this)
@@ -145,6 +141,14 @@ class OffCanvas {
145
141
  }
146
142
  }
147
143
 
144
+ /**
145
+ * Stops scrolling of the body when offcanvas is open on mobile Safari and other troublesome browsers.
146
+ * @private
147
+ */
148
+ _stopScrolling(event) {
149
+ return false;
150
+ }
151
+
148
152
  /**
149
153
  * Opens the off-canvas menu.
150
154
  * @function
@@ -154,107 +158,53 @@ class OffCanvas {
154
158
  */
155
159
  open(event, trigger) {
156
160
  if (this.$element.hasClass('is-open') || this.isRevealed) { return; }
157
- var _this = this,
158
- $body = $(document.body);
161
+ var _this = this;
162
+
163
+ if (trigger) {
164
+ this.$lastTrigger = trigger;
165
+ }
159
166
 
160
- if (this.options.forceTop) {
161
- $('body').scrollTop(0);
167
+ if (this.options.forceTo === 'top') {
168
+ window.scrollTo(0, 0);
169
+ } else if (this.options.forceTo === 'bottom') {
170
+ window.scrollTo(0,document.body.scrollHeight);
162
171
  }
163
- // window.pageYOffset = 0;
164
-
165
- // if (!this.options.forceTop) {
166
- // var scrollPos = parseInt(window.pageYOffset);
167
- // this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
168
- // if (this.$exiter.length) {
169
- // this.$exiter[0].style.transform = 'translate(0,' + scrollPos + 'px)';
170
- // }
171
- // }
172
+
172
173
  /**
173
174
  * Fires when the off-canvas menu opens.
174
175
  * @event OffCanvas#opened
175
176
  */
176
-
177
- var $wrapper = $('[data-off-canvas-wrapper]');
178
- $wrapper.addClass('is-off-canvas-open is-open-'+ _this.options.position);
179
-
180
177
  _this.$element.addClass('is-open')
181
178
 
182
- // if (_this.options.isSticky) {
183
- // _this._stick();
184
- // }
185
-
186
179
  this.$triggers.attr('aria-expanded', 'true');
187
180
  this.$element.attr('aria-hidden', 'false')
188
181
  .trigger('opened.zf.offcanvas');
189
182
 
190
- if (this.options.closeOnClick) {
191
- this.$exiter.addClass('is-visible');
183
+ // If `contentScroll` is set to false, add class and disable scrolling on touch devices.
184
+ if (this.options.contentScroll === false) {
185
+ $('body').addClass('is-off-canvas-open').on('touchmove', this._stopScrolling);
192
186
  }
193
187
 
194
- if (trigger) {
195
- this.$lastTrigger = trigger;
188
+ if (this.options.contentOverlay === true) {
189
+ this.$overlay.addClass('is-visible');
196
190
  }
197
191
 
198
- if (this.options.autoFocus) {
199
- $wrapper.one(Foundation.transitionend($wrapper), function() {
200
- if(_this.$element.hasClass('is-open')) { // handle double clicks
201
- _this.$element.attr('tabindex', '-1');
202
- _this.$element.focus();
203
- }
204
- });
192
+ if (this.options.closeOnClick === true && this.options.contentOverlay === true) {
193
+ this.$overlay.addClass('is-closable');
205
194
  }
206
195
 
207
- if (this.options.trapFocus) {
208
- $wrapper.one(Foundation.transitionend($wrapper), function() {
209
- if(_this.$element.hasClass('is-open')) { // handle double clicks
210
- _this.$element.attr('tabindex', '-1');
211
- _this.trapFocus();
212
- }
196
+ if (this.options.autoFocus === true) {
197
+ this.$element.one(Foundation.transitionend(this.$element), function() {
198
+ _this.$element.find('a, button').eq(0).focus();
213
199
  });
214
200
  }
215
- }
216
201
 
217
- /**
218
- * Traps focus within the offcanvas on open.
219
- * @private
220
- */
221
- _trapFocus() {
222
- var focusable = Foundation.Keyboard.findFocusable(this.$element),
223
- first = focusable.eq(0),
224
- last = focusable.eq(-1);
225
-
226
- focusable.off('.zf.offcanvas').on('keydown.zf.offcanvas', function(e) {
227
- var key = Foundation.Keyboard.parseKey(e);
228
- if (key === 'TAB' && e.target === last[0]) {
229
- e.preventDefault();
230
- first.focus();
231
- }
232
- if (key === 'SHIFT_TAB' && e.target === first[0]) {
233
- e.preventDefault();
234
- last.focus();
235
- }
236
- });
202
+ if (this.options.trapFocus === true) {
203
+ this.$element.siblings('[data-off-canvas-content]').attr('tabindex', '-1');
204
+ Foundation.Keyboard.trapFocus(this.$element);
205
+ }
237
206
  }
238
207
 
239
- /**
240
- * Allows the offcanvas to appear sticky utilizing translate properties.
241
- * @private
242
- */
243
- // OffCanvas.prototype._stick = function() {
244
- // var elStyle = this.$element[0].style;
245
- //
246
- // if (this.options.closeOnClick) {
247
- // var exitStyle = this.$exiter[0].style;
248
- // }
249
- //
250
- // $(window).on('scroll.zf.offcanvas', function(e) {
251
- // console.log(e);
252
- // var pageY = window.pageYOffset;
253
- // elStyle.transform = 'translate(0,' + pageY + 'px)';
254
- // if (exitStyle !== undefined) { exitStyle.transform = 'translate(0,' + pageY + 'px)'; }
255
- // });
256
- // // this.$element.trigger('stuck.zf.offcanvas');
257
- // };
258
208
  /**
259
209
  * Closes the off-canvas menu.
260
210
  * @function
@@ -266,30 +216,33 @@ class OffCanvas {
266
216
 
267
217
  var _this = this;
268
218
 
269
- // Foundation.Move(this.options.transitionTime, this.$element, function() {
270
- $('[data-off-canvas-wrapper]').removeClass(`is-off-canvas-open is-open-${_this.options.position}`);
271
219
  _this.$element.removeClass('is-open');
272
- // Foundation._reflow();
273
- // });
220
+
274
221
  this.$element.attr('aria-hidden', 'true')
275
222
  /**
276
223
  * Fires when the off-canvas menu opens.
277
224
  * @event OffCanvas#closed
278
225
  */
279
226
  .trigger('closed.zf.offcanvas');
280
- // if (_this.options.isSticky || !_this.options.forceTop) {
281
- // setTimeout(function() {
282
- // _this.$element[0].style.transform = '';
283
- // $(window).off('scroll.zf.offcanvas');
284
- // }, this.options.transitionTime);
285
- // }
286
- if (this.options.closeOnClick) {
287
- this.$exiter.removeClass('is-visible');
227
+
228
+ // If `contentScroll` is set to false, remove class and re-enable scrolling on touch devices.
229
+ if (this.options.contentScroll === false) {
230
+ $('body').removeClass('is-off-canvas-open').off('touchmove', this._stopScrolling);
231
+ }
232
+
233
+ if (this.options.contentOverlay === true) {
234
+ this.$overlay.removeClass('is-visible');
235
+ }
236
+
237
+ if (this.options.closeOnClick === true && this.options.contentOverlay === true) {
238
+ this.$overlay.removeClass('is-closable');
288
239
  }
289
240
 
290
241
  this.$triggers.attr('aria-expanded', 'false');
291
- if (this.options.trapFocus) {
292
- $('[data-off-canvas-content]').removeAttr('tabindex');
242
+
243
+ if (this.options.trapFocus === true) {
244
+ this.$element.siblings('[data-off-canvas-content]').removeAttr('tabindex');
245
+ Foundation.Keyboard.releaseFocus(this.$element);
293
246
  }
294
247
  }
295
248
 
@@ -334,7 +287,7 @@ class OffCanvas {
334
287
  destroy() {
335
288
  this.close();
336
289
  this.$element.off('.zf.trigger .zf.offcanvas');
337
- this.$exiter.off('.zf.offcanvas');
290
+ this.$overlay.off('.zf.offcanvas');
338
291
 
339
292
  Foundation.unregisterPlugin(this);
340
293
  }
@@ -348,6 +301,20 @@ OffCanvas.defaults = {
348
301
  */
349
302
  closeOnClick: true,
350
303
 
304
+ /**
305
+ * Adds an overlay on top of `[data-off-canvas-content]`.
306
+ * @option
307
+ * @example true
308
+ */
309
+ contentOverlay: true,
310
+
311
+ /**
312
+ * Enable/disable scrolling of the main content when an off canvas panel is open.
313
+ * @option
314
+ * @example true
315
+ */
316
+ contentScroll: true,
317
+
351
318
  /**
352
319
  * Amount of time in ms the open and close transition requires. If none selected, pulls from body style.
353
320
  * @option
@@ -356,18 +323,18 @@ OffCanvas.defaults = {
356
323
  transitionTime: 0,
357
324
 
358
325
  /**
359
- * Direction the offcanvas opens from. Determines class applied to body.
326
+ * Type of transition for the offcanvas menu. Options are 'push', 'detached' or 'slide'.
360
327
  * @option
361
- * @example left
328
+ * @example push
362
329
  */
363
- position: 'left',
330
+ transition: 'push',
364
331
 
365
332
  /**
366
- * Force the page to scroll to top on open.
333
+ * Force the page to scroll to top or bottom on open.
367
334
  * @option
368
- * @example true
335
+ * @example top
369
336
  */
370
- forceTop: true,
337
+ forceTo: null,
371
338
 
372
339
  /**
373
340
  * Allow the offcanvas to remain open for certain breakpoints.
@@ -384,7 +351,7 @@ OffCanvas.defaults = {
384
351
  revealOn: null,
385
352
 
386
353
  /**
387
- * Force focus to the offcanvas on open. If true, will focus the opening trigger on close. Sets tabindex of [data-off-canvas-content] to -1 for accessibility purposes.
354
+ * Force focus to the offcanvas on open. If true, will focus the opening trigger on close.
388
355
  * @option
389
356
  * @example true
390
357
  */