foundation-rails 6.2.4.0 → 6.3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  */