foundation-rails 6.1.2.0 → 6.2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -6
  3. data/README.md +1 -1
  4. data/Rakefile +5 -1
  5. data/bower.json +3 -3
  6. data/foundation-rails.gemspec +1 -0
  7. data/lib/foundation-rails.rb +1 -0
  8. data/lib/foundation/rails/version.rb +1 -1
  9. data/lib/generators/foundation/templates/foundation_and_overrides.scss +2 -2
  10. data/vendor/assets/js/foundation.abide.js.es6 +462 -0
  11. data/vendor/assets/js/{foundation.accordion.js → foundation.accordion.js.es6} +55 -47
  12. data/vendor/assets/js/{foundation.accordionMenu.js → foundation.accordionMenu.js.es6} +46 -35
  13. data/vendor/assets/js/{foundation.core.js → foundation.core.js.es6} +10 -8
  14. data/vendor/assets/js/{foundation.drilldown.js → foundation.drilldown.js.es6} +75 -49
  15. data/vendor/assets/js/{foundation.dropdown.js → foundation.dropdown.js.es6} +100 -88
  16. data/vendor/assets/js/{foundation.dropdownMenu.js → foundation.dropdownMenu.js.es6} +134 -128
  17. data/vendor/assets/js/{foundation.equalizer.js → foundation.equalizer.js.es6} +72 -61
  18. data/vendor/assets/js/{foundation.interchange.js → foundation.interchange.js.es6} +44 -45
  19. data/vendor/assets/js/{foundation.js → foundation.js.es6} +0 -0
  20. data/vendor/assets/js/{foundation.magellan.js → foundation.magellan.js.es6} +80 -83
  21. data/vendor/assets/js/foundation.offcanvas.js.es6 +395 -0
  22. data/vendor/assets/js/foundation.orbit.js.es6 +445 -0
  23. data/vendor/assets/js/{foundation.responsiveMenu.js → foundation.responsiveMenu.js.es6} +37 -31
  24. data/vendor/assets/js/foundation.responsiveToggle.js.es6 +112 -0
  25. data/vendor/assets/js/foundation.reveal.js.es6 +544 -0
  26. data/vendor/assets/js/{foundation.slider.js → foundation.slider.js.es6} +235 -184
  27. data/vendor/assets/js/{foundation.sticky.js → foundation.sticky.js.es6} +177 -166
  28. data/vendor/assets/js/{foundation.tabs.js → foundation.tabs.js.es6} +138 -118
  29. data/vendor/assets/js/{foundation.toggler.js → foundation.toggler.js.es6} +34 -37
  30. data/vendor/assets/js/{foundation.tooltip.js → foundation.tooltip.js.es6} +162 -153
  31. data/vendor/assets/js/foundation.util.box.js.es6 +183 -0
  32. data/vendor/assets/js/{foundation.util.keyboard.js → foundation.util.keyboard.js.es6} +54 -54
  33. data/vendor/assets/js/{foundation.util.mediaQuery.js → foundation.util.mediaQuery.js.es6} +46 -46
  34. data/vendor/assets/js/{foundation.util.motion.js → foundation.util.motion.js.es6} +58 -48
  35. data/vendor/assets/js/foundation.util.nest.js.es6 +76 -0
  36. data/vendor/assets/js/foundation.util.timerAndImageLoader.js.es6 +86 -0
  37. data/vendor/assets/js/{foundation.util.touch.js → foundation.util.touch.js.es6} +2 -2
  38. data/vendor/assets/js/foundation.util.triggers.js.es6 +239 -0
  39. data/vendor/assets/scss/_global.scss +28 -27
  40. data/vendor/assets/scss/components/_badge.scss +1 -1
  41. data/vendor/assets/scss/components/_button-group.scss +77 -26
  42. data/vendor/assets/scss/components/_button.scss +8 -8
  43. data/vendor/assets/scss/components/_callout.scss +2 -2
  44. data/vendor/assets/scss/components/_drilldown.scss +4 -0
  45. data/vendor/assets/scss/components/_dropdown-menu.scss +104 -54
  46. data/vendor/assets/scss/components/_flex.scss +28 -0
  47. data/vendor/assets/scss/components/_label.scss +1 -1
  48. data/vendor/assets/scss/components/_media-object.scss +37 -7
  49. data/vendor/assets/scss/components/_menu-icon.scss +9 -0
  50. data/vendor/assets/scss/components/_menu.scss +127 -29
  51. data/vendor/assets/scss/components/_off-canvas.scss +1 -0
  52. data/vendor/assets/scss/components/_pagination.scss +3 -3
  53. data/vendor/assets/scss/components/_progress-bar.scss +1 -25
  54. data/vendor/assets/scss/components/_reveal.scss +12 -6
  55. data/vendor/assets/scss/components/_slider.scss +3 -35
  56. data/vendor/assets/scss/components/_table.scss +8 -0
  57. data/vendor/assets/scss/components/_tabs.scss +5 -10
  58. data/vendor/assets/scss/components/_title-bar.scss +27 -10
  59. data/vendor/assets/scss/components/_tooltip.scss +0 -4
  60. data/vendor/assets/scss/components/_top-bar.scss +93 -21
  61. data/vendor/assets/scss/components/_visibility.scss +1 -1
  62. data/vendor/assets/scss/forms/_checkbox.scss +1 -1
  63. data/vendor/assets/scss/forms/_error.scss +7 -5
  64. data/vendor/assets/scss/forms/_forms.scss +3 -0
  65. data/vendor/assets/scss/forms/_help-text.scss +1 -1
  66. data/vendor/assets/scss/forms/_input-group.scss +44 -9
  67. data/vendor/assets/scss/forms/_meter.scss +109 -0
  68. data/vendor/assets/scss/forms/_progress.scss +85 -0
  69. data/vendor/assets/scss/forms/_range.scss +144 -0
  70. data/vendor/assets/scss/forms/_select.scss +1 -1
  71. data/vendor/assets/scss/forms/_text.scss +10 -1
  72. data/vendor/assets/scss/foundation.scss +16 -5
  73. data/vendor/assets/scss/grid/_classes.scss +5 -18
  74. data/vendor/assets/scss/grid/_column.scss +13 -11
  75. data/vendor/assets/scss/grid/_flex-grid.scss +54 -80
  76. data/vendor/assets/scss/grid/_grid.scss +22 -10
  77. data/vendor/assets/scss/grid/_layout.scss +18 -0
  78. data/vendor/assets/scss/grid/_row.scss +11 -15
  79. data/vendor/assets/scss/motion-ui/_classes.scss +10 -3
  80. data/vendor/assets/scss/motion-ui/effects/_fade.scss +4 -1
  81. data/vendor/assets/scss/motion-ui/effects/_zoom.scss +1 -1
  82. data/vendor/assets/scss/motion-ui/transitions/_slide.scss +1 -1
  83. data/vendor/assets/scss/motion-ui/util/_transition.scss +1 -1
  84. data/vendor/assets/scss/settings/_settings.scss +64 -47
  85. data/vendor/assets/scss/typography/_base.scss +4 -0
  86. data/vendor/assets/scss/typography/_print.scss +9 -5
  87. data/vendor/assets/scss/util/_breakpoint.scss +31 -25
  88. data/vendor/assets/scss/util/_color.scss +19 -0
  89. data/vendor/assets/scss/util/_flex.scss +68 -0
  90. data/vendor/assets/scss/util/_mixins.scss +13 -7
  91. data/vendor/assets/scss/util/_util.scss +1 -5
  92. data/vendor/assets/scss/util/_value.scss +9 -28
  93. metadata +51 -31
  94. data/vendor/assets/js/foundation.abide.js +0 -418
  95. data/vendor/assets/js/foundation.offcanvas.js +0 -376
  96. data/vendor/assets/js/foundation.orbit.js +0 -421
  97. data/vendor/assets/js/foundation.responsiveToggle.js +0 -106
  98. data/vendor/assets/js/foundation.reveal.js +0 -514
  99. data/vendor/assets/js/foundation.util.box.js +0 -169
  100. data/vendor/assets/js/foundation.util.nest.js +0 -63
  101. data/vendor/assets/js/foundation.util.timerAndImageLoader.js +0 -82
  102. data/vendor/assets/js/foundation.util.triggers.js +0 -224
@@ -1,12 +1,15 @@
1
+ 'use strict';
2
+
3
+ !function($) {
4
+
1
5
  /**
2
6
  * Interchange module.
3
7
  * @module foundation.interchange
4
8
  * @requires foundation.util.mediaQuery
5
9
  * @requires foundation.util.timerAndImageLoader
6
10
  */
7
- !function(Foundation, $) {
8
- 'use strict';
9
11
 
12
+ class Interchange {
10
13
  /**
11
14
  * Creates a new instance of Interchange.
12
15
  * @class
@@ -14,7 +17,7 @@
14
17
  * @param {Object} element - jQuery object to add the trigger to.
15
18
  * @param {Object} options - Overrides to the default plugin settings.
16
19
  */
17
- function Interchange(element, options) {
20
+ constructor(element, options) {
18
21
  this.$element = element;
19
22
  this.options = $.extend({}, Interchange.defaults, options);
20
23
  this.rules = [];
@@ -26,49 +29,32 @@
26
29
  Foundation.registerPlugin(this, 'Interchange');
27
30
  }
28
31
 
29
- /**
30
- * Default settings for plugin
31
- */
32
- Interchange.defaults = {
33
- /**
34
- * Rules to be applied to Interchange elements. Set with the `data-interchange` array notation.
35
- * @option
36
- */
37
- rules: null
38
- };
39
-
40
- Interchange.SPECIAL_QUERIES = {
41
- 'landscape': 'screen and (orientation: landscape)',
42
- 'portrait': 'screen and (orientation: portrait)',
43
- 'retina': 'only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx)'
44
- };
45
-
46
32
  /**
47
33
  * Initializes the Interchange plugin and calls functions to get interchange functioning on load.
48
34
  * @function
49
35
  * @private
50
36
  */
51
- Interchange.prototype._init = function() {
37
+ _init() {
52
38
  this._addBreakpoints();
53
39
  this._generateRules();
54
40
  this._reflow();
55
- };
41
+ }
56
42
 
57
43
  /**
58
44
  * Initializes events for Interchange.
59
45
  * @function
60
46
  * @private
61
47
  */
62
- Interchange.prototype._events = function() {
48
+ _events() {
63
49
  $(window).on('resize.zf.interchange', Foundation.util.throttle(this._reflow.bind(this), 50));
64
- };
50
+ }
65
51
 
66
52
  /**
67
53
  * Calls necessary functions to update Interchange upon DOM change
68
54
  * @function
69
55
  * @private
70
56
  */
71
- Interchange.prototype._reflow = function() {
57
+ _reflow() {
72
58
  var match;
73
59
 
74
60
  // Iterate through each rule, but only save the last match
@@ -83,19 +69,19 @@
83
69
  if (match) {
84
70
  this.replace(match.path);
85
71
  }
86
- };
72
+ }
87
73
 
88
74
  /**
89
75
  * Gets the Foundation breakpoints and adds them to the Interchange.SPECIAL_QUERIES object.
90
76
  * @function
91
77
  * @private
92
78
  */
93
- Interchange.prototype._addBreakpoints = function() {
79
+ _addBreakpoints() {
94
80
  for (var i in Foundation.MediaQuery.queries) {
95
81
  var query = Foundation.MediaQuery.queries[i];
96
82
  Interchange.SPECIAL_QUERIES[query.name] = query.value;
97
83
  }
98
- };
84
+ }
99
85
 
100
86
  /**
101
87
  * Checks the Interchange element for the provided media query + content pairings
@@ -104,7 +90,7 @@
104
90
  * @param {Object} element - jQuery object that is an Interchange instance
105
91
  * @returns {Array} scenarios - Array of objects that have 'mq' and 'path' keys with corresponding keys
106
92
  */
107
- Interchange.prototype._generateRules = function() {
93
+ _generateRules(element) {
108
94
  var rulesList = [];
109
95
  var rules;
110
96
 
@@ -131,7 +117,7 @@
131
117
  }
132
118
 
133
119
  this.rules = rulesList;
134
- };
120
+ }
135
121
 
136
122
  /**
137
123
  * Update the `src` property of an image, or change the HTML of a container, to the specified path.
@@ -139,7 +125,7 @@
139
125
  * @param {String} path - Path to the image or HTML partial.
140
126
  * @fires Interchange#replaced
141
127
  */
142
- Interchange.prototype.replace = function(path) {
128
+ replace(path) {
143
129
  if (this.currentPath === path) return;
144
130
 
145
131
  var _this = this,
@@ -172,22 +158,35 @@
172
158
  * @event Interchange#replaced
173
159
  */
174
160
  // this.$element.trigger('replaced.zf.interchange');
175
- };
161
+ }
162
+
176
163
  /**
177
164
  * Destroys an instance of interchange.
178
165
  * @function
179
166
  */
180
- Interchange.prototype.destroy = function(){
167
+ destroy() {
181
168
  //TODO this.
182
- };
183
- Foundation.plugin(Interchange, 'Interchange');
184
-
185
- // Exports for AMD/Browserify
186
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
187
- module.exports = Interchange;
188
- if (typeof define === 'function')
189
- define(['foundation'], function() {
190
- return Interchange;
191
- });
192
-
193
- }(Foundation, jQuery);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Default settings for plugin
174
+ */
175
+ Interchange.defaults = {
176
+ /**
177
+ * Rules to be applied to Interchange elements. Set with the `data-interchange` array notation.
178
+ * @option
179
+ */
180
+ rules: null
181
+ };
182
+
183
+ Interchange.SPECIAL_QUERIES = {
184
+ 'landscape': 'screen and (orientation: landscape)',
185
+ 'portrait': 'screen and (orientation: portrait)',
186
+ 'retina': 'only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx)'
187
+ };
188
+
189
+ // Window exports
190
+ Foundation.plugin(Interchange, 'Interchange');
191
+
192
+ }(jQuery);
@@ -1,10 +1,13 @@
1
+ 'use strict';
2
+
3
+ !function($) {
4
+
1
5
  /**
2
6
  * Magellan module.
3
7
  * @module foundation.magellan
4
8
  */
5
- !function(Foundation, $) {
6
- 'use strict';
7
9
 
10
+ class Magellan {
8
11
  /**
9
12
  * Creates a new instance of Magellan.
10
13
  * @class
@@ -12,7 +15,7 @@
12
15
  * @param {Object} element - jQuery object to add the trigger to.
13
16
  * @param {Object} options - Overrides to the default plugin settings.
14
17
  */
15
- function Magellan(element, options) {
18
+ constructor(element, options) {
16
19
  this.$element = element;
17
20
  this.options = $.extend({}, Magellan.defaults, this.$element.data(), options);
18
21
 
@@ -21,55 +24,13 @@
21
24
  Foundation.registerPlugin(this, 'Magellan');
22
25
  }
23
26
 
24
- /**
25
- * Default settings for plugin
26
- */
27
- Magellan.defaults = {
28
- /**
29
- * Amount of time, in ms, the animated scrolling should take between locations.
30
- * @option
31
- * @example 500
32
- */
33
- animationDuration: 500,
34
- /**
35
- * Animation style to use when scrolling between locations.
36
- * @option
37
- * @example 'ease-in-out'
38
- */
39
- animationEasing: 'linear',
40
- /**
41
- * Number of pixels to use as a marker for location changes.
42
- * @option
43
- * @example 50
44
- */
45
- threshold: 50,
46
- /**
47
- * Class applied to the active locations link on the magellan container.
48
- * @option
49
- * @example 'active'
50
- */
51
- activeClass: 'active',
52
- /**
53
- * Allows the script to manipulate the url of the current page, and if supported, alter the history.
54
- * @option
55
- * @example true
56
- */
57
- deepLinking: false,
58
- /**
59
- * Number of pixels to offset the scroll of the page on item click if using a sticky nav bar.
60
- * @option
61
- * @example 25
62
- */
63
- barOffset: 0
64
- };
65
-
66
27
  /**
67
28
  * Initializes the Magellan plugin and calls functions to get equalizer functioning on load.
68
29
  * @private
69
30
  */
70
- Magellan.prototype._init = function() {
71
- var id = this.$element[0].id || Foundation.GetYoDigits(6, 'magellan'),
72
- _this = this;
31
+ _init() {
32
+ var id = this.$element[0].id || Foundation.GetYoDigits(6, 'magellan');
33
+ var _this = this;
73
34
  this.$targets = $('[data-magellan-target]');
74
35
  this.$links = this.$element.find('a');
75
36
  this.$element.attr({
@@ -81,13 +42,14 @@
81
42
  this.scrollPos = parseInt(window.pageYOffset, 10);
82
43
 
83
44
  this._events();
84
- };
45
+ }
46
+
85
47
  /**
86
48
  * Calculates an array of pixel values that are the demarcation lines between locations on the page.
87
49
  * Can be invoked if new elements are added or the size of a location changes.
88
50
  * @function
89
51
  */
90
- Magellan.prototype.calcPoints = function(){
52
+ calcPoints() {
91
53
  var _this = this,
92
54
  body = document.body,
93
55
  html = document.documentElement;
@@ -102,12 +64,13 @@
102
64
  $tar.targetPoint = pt;
103
65
  _this.points.push(pt);
104
66
  });
105
- };
67
+ }
68
+
106
69
  /**
107
70
  * Initializes events for Magellan.
108
71
  * @private
109
72
  */
110
- Magellan.prototype._events = function() {
73
+ _events() {
111
74
  var _this = this,
112
75
  $body = $('html, body'),
113
76
  opts = {
@@ -132,39 +95,35 @@
132
95
  var arrival = this.getAttribute('href');
133
96
  _this.scrollToLoc(arrival);
134
97
  });
135
- };
98
+ }
99
+
136
100
  /**
137
101
  * Function to scroll to a given location on the page.
138
- * @param {String} loc - a properly formatted jQuery id selector.
139
- * @example '#foo'
102
+ * @param {String} loc - a properly formatted jQuery id selector. Example: '#foo'
140
103
  * @function
141
104
  */
142
- Magellan.prototype.scrollToLoc = function(loc){
143
- var scrollPos = $(loc).offset().top - this.options.threshold / 2 - this.options.barOffset;
144
-
145
- $(document.body).stop(true).animate({
146
- scrollTop: scrollPos
147
- },
148
- {
149
- duration: this.options.animationDuration,
150
- easiing: this.options.animationEasing
151
- });
152
- };
105
+ scrollToLoc(loc) {
106
+ var scrollPos = Math.round($(loc).offset().top - this.options.threshold / 2 - this.options.barOffset);
107
+
108
+ $('html, body').stop(true).animate({ scrollTop: scrollPos }, this.options.animationDuration, this.options.animationEasing);
109
+ }
110
+
153
111
  /**
154
112
  * Calls necessary functions to update Magellan upon DOM change
155
113
  * @function
156
114
  */
157
- Magellan.prototype.reflow = function(){
115
+ reflow() {
158
116
  this.calcPoints();
159
117
  this._updateActive();
160
- };
118
+ }
119
+
161
120
  /**
162
121
  * Updates the visibility of an active location link, and updates the url hash for the page, if deepLinking enabled.
163
122
  * @private
164
123
  * @function
165
124
  * @fires Magellan#update
166
125
  */
167
- Magellan.prototype._updateActive = function(/*evt, elem, scrollPos*/){
126
+ _updateActive(/*evt, elem, scrollPos*/) {
168
127
  var winPos = /*scrollPos ||*/ parseInt(window.pageYOffset, 10),
169
128
  curIdx;
170
129
 
@@ -197,14 +156,15 @@
197
156
  * @event Magellan#update
198
157
  */
199
158
  this.$element.trigger('update.zf.magellan', [this.$active]);
200
- };
159
+ }
160
+
201
161
  /**
202
162
  * Destroys an instance of Magellan and resets the url of the window.
203
163
  * @function
204
164
  */
205
- Magellan.prototype.destroy = function(){
165
+ destroy() {
206
166
  this.$element.off('.zf.trigger .zf.magellan')
207
- .find('.' + this.options.activeClass).removeClass(this.options.activeClass);
167
+ .find(`.${this.options.activeClass}`).removeClass(this.options.activeClass);
208
168
 
209
169
  if(this.options.deepLinking){
210
170
  var hash = this.$active[0].getAttribute('href');
@@ -212,15 +172,52 @@
212
172
  }
213
173
 
214
174
  Foundation.unregisterPlugin(this);
215
- };
216
- Foundation.plugin(Magellan, 'Magellan');
217
-
218
- // Exports for AMD/Browserify
219
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
220
- module.exports = Magellan;
221
- if (typeof define === 'function')
222
- define(['foundation'], function() {
223
- return Magellan;
224
- });
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Default settings for plugin
180
+ */
181
+ Magellan.defaults = {
182
+ /**
183
+ * Amount of time, in ms, the animated scrolling should take between locations.
184
+ * @option
185
+ * @example 500
186
+ */
187
+ animationDuration: 500,
188
+ /**
189
+ * Animation style to use when scrolling between locations.
190
+ * @option
191
+ * @example 'ease-in-out'
192
+ */
193
+ animationEasing: 'linear',
194
+ /**
195
+ * Number of pixels to use as a marker for location changes.
196
+ * @option
197
+ * @example 50
198
+ */
199
+ threshold: 50,
200
+ /**
201
+ * Class applied to the active locations link on the magellan container.
202
+ * @option
203
+ * @example 'active'
204
+ */
205
+ activeClass: 'active',
206
+ /**
207
+ * Allows the script to manipulate the url of the current page, and if supported, alter the history.
208
+ * @option
209
+ * @example true
210
+ */
211
+ deepLinking: false,
212
+ /**
213
+ * Number of pixels to offset the scroll of the page on item click if using a sticky nav bar.
214
+ * @option
215
+ * @example 25
216
+ */
217
+ barOffset: 0
218
+ }
219
+
220
+ // Window exports
221
+ Foundation.plugin(Magellan, 'Magellan');
225
222
 
226
- }(Foundation, jQuery);
223
+ }(jQuery);
@@ -0,0 +1,395 @@
1
+ 'use strict';
2
+
3
+ !function($) {
4
+
5
+ /**
6
+ * OffCanvas module.
7
+ * @module foundation.offcanvas
8
+ * @requires foundation.util.mediaQuery
9
+ * @requires foundation.util.triggers
10
+ * @requires foundation.util.motion
11
+ */
12
+
13
+ class OffCanvas {
14
+ /**
15
+ * Creates a new instance of an off-canvas wrapper.
16
+ * @class
17
+ * @fires OffCanvas#init
18
+ * @param {Object} element - jQuery object to initialize.
19
+ * @param {Object} options - Overrides to the default plugin settings.
20
+ */
21
+ constructor(element, options) {
22
+ this.$element = element;
23
+ this.options = $.extend({}, OffCanvas.defaults, this.$element.data(), options);
24
+ this.$lastTrigger = $();
25
+
26
+ this._init();
27
+ this._events();
28
+
29
+ Foundation.registerPlugin(this, 'OffCanvas');
30
+ }
31
+
32
+ /**
33
+ * Initializes the off-canvas wrapper by adding the exit overlay (if needed).
34
+ * @function
35
+ * @private
36
+ */
37
+ _init() {
38
+ var id = this.$element.attr('id');
39
+
40
+ this.$element.attr('aria-hidden', 'true');
41
+
42
+ // Find triggers that affect this element and add aria-expanded to them
43
+ $(document)
44
+ .find('[data-open="'+id+'"], [data-close="'+id+'"], [data-toggle="'+id+'"]')
45
+ .attr('aria-expanded', 'false')
46
+ .attr('aria-controls', id);
47
+
48
+ // Add a close trigger over the body if necessary
49
+ if (this.options.closeOnClick) {
50
+ if ($('.js-off-canvas-exit').length) {
51
+ this.$exiter = $('.js-off-canvas-exit');
52
+ } else {
53
+ var exiter = document.createElement('div');
54
+ exiter.setAttribute('class', 'js-off-canvas-exit');
55
+ $('[data-off-canvas-content]').append(exiter);
56
+
57
+ this.$exiter = $(exiter);
58
+ }
59
+ }
60
+
61
+ this.options.isRevealed = this.options.isRevealed || new RegExp(this.options.revealClass, 'g').test(this.$element[0].className);
62
+
63
+ if (this.options.isRevealed) {
64
+ this.options.revealOn = this.options.revealOn || this.$element[0].className.match(/(reveal-for-medium|reveal-for-large)/g)[0].split('-')[2];
65
+ this._setMQChecker();
66
+ }
67
+ if (!this.options.transitionTime) {
68
+ this.options.transitionTime = parseFloat(window.getComputedStyle($('[data-off-canvas-wrapper]')[0]).transitionDuration) * 1000;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Adds event handlers to the off-canvas wrapper and the exit overlay.
74
+ * @function
75
+ * @private
76
+ */
77
+ _events() {
78
+ this.$element.off('.zf.trigger .zf.offcanvas').on({
79
+ 'open.zf.trigger': this.open.bind(this),
80
+ 'close.zf.trigger': this.close.bind(this),
81
+ 'toggle.zf.trigger': this.toggle.bind(this),
82
+ 'keydown.zf.offcanvas': this._handleKeyboard.bind(this)
83
+ });
84
+
85
+ if (this.options.closeOnClick && this.$exiter.length) {
86
+ this.$exiter.on({'click.zf.offcanvas': this.close.bind(this)});
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Applies event listener for elements that will reveal at certain breakpoints.
92
+ * @private
93
+ */
94
+ _setMQChecker() {
95
+ var _this = this;
96
+
97
+ $(window).on('changed.zf.mediaquery', function() {
98
+ if (Foundation.MediaQuery.atLeast(_this.options.revealOn)) {
99
+ _this.reveal(true);
100
+ } else {
101
+ _this.reveal(false);
102
+ }
103
+ }).one('load.zf.offcanvas', function() {
104
+ if (Foundation.MediaQuery.atLeast(_this.options.revealOn)) {
105
+ _this.reveal(true);
106
+ }
107
+ });
108
+ }
109
+
110
+ /**
111
+ * Handles the revealing/hiding the off-canvas at breakpoints, not the same as open.
112
+ * @param {Boolean} isRevealed - true if element should be revealed.
113
+ * @function
114
+ */
115
+ reveal(isRevealed) {
116
+ var $closer = this.$element.find('[data-close]');
117
+ if (isRevealed) {
118
+ this.close();
119
+ this.isRevealed = true;
120
+ // if (!this.options.forceTop) {
121
+ // var scrollPos = parseInt(window.pageYOffset);
122
+ // this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
123
+ // }
124
+ // if (this.options.isSticky) { this._stick(); }
125
+ this.$element.off('open.zf.trigger toggle.zf.trigger');
126
+ if ($closer.length) { $closer.hide(); }
127
+ } else {
128
+ this.isRevealed = false;
129
+ // if (this.options.isSticky || !this.options.forceTop) {
130
+ // this.$element[0].style.transform = '';
131
+ // $(window).off('scroll.zf.offcanvas');
132
+ // }
133
+ this.$element.on({
134
+ 'open.zf.trigger': this.open.bind(this),
135
+ 'toggle.zf.trigger': this.toggle.bind(this)
136
+ });
137
+ if ($closer.length) {
138
+ $closer.show();
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Opens the off-canvas menu.
145
+ * @function
146
+ * @param {Object} event - Event object passed from listener.
147
+ * @param {jQuery} trigger - element that triggered the off-canvas to open.
148
+ * @fires OffCanvas#opened
149
+ */
150
+ open(event, trigger) {
151
+ if (this.$element.hasClass('is-open') || this.isRevealed) { return; }
152
+ var _this = this,
153
+ $body = $(document.body);
154
+
155
+ if (this.options.forceTop) {
156
+ $('body').scrollTop(0);
157
+ }
158
+ // window.pageYOffset = 0;
159
+
160
+ // if (!this.options.forceTop) {
161
+ // var scrollPos = parseInt(window.pageYOffset);
162
+ // this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
163
+ // if (this.$exiter.length) {
164
+ // this.$exiter[0].style.transform = 'translate(0,' + scrollPos + 'px)';
165
+ // }
166
+ // }
167
+ /**
168
+ * Fires when the off-canvas menu opens.
169
+ * @event OffCanvas#opened
170
+ */
171
+ Foundation.Move(this.options.transitionTime, this.$element, function() {
172
+ $('[data-off-canvas-wrapper]').addClass('is-off-canvas-open is-open-'+ _this.options.position);
173
+
174
+ _this.$element
175
+ .addClass('is-open')
176
+
177
+ // if (_this.options.isSticky) {
178
+ // _this._stick();
179
+ // }
180
+ });
181
+ this.$element.attr('aria-hidden', 'false')
182
+ .trigger('opened.zf.offcanvas');
183
+
184
+ if (this.options.closeOnClick) {
185
+ this.$exiter.addClass('is-visible');
186
+ }
187
+
188
+ if (trigger) {
189
+ this.$lastTrigger = trigger.attr('aria-expanded', 'true');
190
+ }
191
+
192
+ if (this.options.autoFocus) {
193
+ this.$element.one(Foundation.transitionend(this.$element), function() {
194
+ _this.$element.find('a, button').eq(0).focus();
195
+ });
196
+ }
197
+
198
+ if (this.options.trapFocus) {
199
+ $('[data-off-canvas-content]').attr('tabindex', '-1');
200
+ this._trapFocus();
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Traps focus within the offcanvas on open.
206
+ * @private
207
+ */
208
+ _trapFocus() {
209
+ var focusable = Foundation.Keyboard.findFocusable(this.$element),
210
+ first = focusable.eq(0),
211
+ last = focusable.eq(-1);
212
+
213
+ focusable.off('.zf.offcanvas').on('keydown.zf.offcanvas', function(e) {
214
+ if (e.which === 9 || e.keycode === 9) {
215
+ if (e.target === last[0] && !e.shiftKey) {
216
+ e.preventDefault();
217
+ first.focus();
218
+ }
219
+ if (e.target === first[0] && e.shiftKey) {
220
+ e.preventDefault();
221
+ last.focus();
222
+ }
223
+ }
224
+ });
225
+ }
226
+
227
+ /**
228
+ * Allows the offcanvas to appear sticky utilizing translate properties.
229
+ * @private
230
+ */
231
+ // OffCanvas.prototype._stick = function() {
232
+ // var elStyle = this.$element[0].style;
233
+ //
234
+ // if (this.options.closeOnClick) {
235
+ // var exitStyle = this.$exiter[0].style;
236
+ // }
237
+ //
238
+ // $(window).on('scroll.zf.offcanvas', function(e) {
239
+ // console.log(e);
240
+ // var pageY = window.pageYOffset;
241
+ // elStyle.transform = 'translate(0,' + pageY + 'px)';
242
+ // if (exitStyle !== undefined) { exitStyle.transform = 'translate(0,' + pageY + 'px)'; }
243
+ // });
244
+ // // this.$element.trigger('stuck.zf.offcanvas');
245
+ // };
246
+ /**
247
+ * Closes the off-canvas menu.
248
+ * @function
249
+ * @param {Function} cb - optional cb to fire after closure.
250
+ * @fires OffCanvas#closed
251
+ */
252
+ close(cb) {
253
+ if (!this.$element.hasClass('is-open') || this.isRevealed) { return; }
254
+
255
+ var _this = this;
256
+
257
+ // Foundation.Move(this.options.transitionTime, this.$element, function() {
258
+ $('[data-off-canvas-wrapper]').removeClass(`is-off-canvas-open is-open-${_this.options.position}`);
259
+ _this.$element.removeClass('is-open');
260
+ // Foundation._reflow();
261
+ // });
262
+ this.$element.attr('aria-hidden', 'true')
263
+ /**
264
+ * Fires when the off-canvas menu opens.
265
+ * @event OffCanvas#closed
266
+ */
267
+ .trigger('closed.zf.offcanvas');
268
+ // if (_this.options.isSticky || !_this.options.forceTop) {
269
+ // setTimeout(function() {
270
+ // _this.$element[0].style.transform = '';
271
+ // $(window).off('scroll.zf.offcanvas');
272
+ // }, this.options.transitionTime);
273
+ // }
274
+ if (this.options.closeOnClick) {
275
+ this.$exiter.removeClass('is-visible');
276
+ }
277
+
278
+ this.$lastTrigger.attr('aria-expanded', 'false');
279
+ if (this.options.trapFocus) {
280
+ $('[data-off-canvas-content]').removeAttr('tabindex');
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Toggles the off-canvas menu open or closed.
286
+ * @function
287
+ * @param {Object} event - Event object passed from listener.
288
+ * @param {jQuery} trigger - element that triggered the off-canvas to open.
289
+ */
290
+ toggle(event, trigger) {
291
+ if (this.$element.hasClass('is-open')) {
292
+ this.close(event, trigger);
293
+ }
294
+ else {
295
+ this.open(event, trigger);
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Handles keyboard input when detected. When the escape key is pressed, the off-canvas menu closes, and focus is restored to the element that opened the menu.
301
+ * @function
302
+ * @private
303
+ */
304
+ _handleKeyboard(event) {
305
+ if (event.which !== 27) return;
306
+
307
+ event.stopPropagation();
308
+ event.preventDefault();
309
+ this.close();
310
+ this.$lastTrigger.focus();
311
+ }
312
+
313
+ /**
314
+ * Destroys the offcanvas plugin.
315
+ * @function
316
+ */
317
+ destroy() {
318
+ this.close();
319
+ this.$element.off('.zf.trigger .zf.offcanvas');
320
+ this.$exiter.off('.zf.offcanvas');
321
+
322
+ Foundation.unregisterPlugin(this);
323
+ }
324
+ }
325
+
326
+ OffCanvas.defaults = {
327
+ /**
328
+ * Allow the user to click outside of the menu to close it.
329
+ * @option
330
+ * @example true
331
+ */
332
+ closeOnClick: true,
333
+
334
+ /**
335
+ * Amount of time in ms the open and close transition requires. If none selected, pulls from body style.
336
+ * @option
337
+ * @example 500
338
+ */
339
+ transitionTime: 0,
340
+
341
+ /**
342
+ * Direction the offcanvas opens from. Determines class applied to body.
343
+ * @option
344
+ * @example left
345
+ */
346
+ position: 'left',
347
+
348
+ /**
349
+ * Force the page to scroll to top on open.
350
+ * @option
351
+ * @example true
352
+ */
353
+ forceTop: true,
354
+
355
+ /**
356
+ * Allow the offcanvas to remain open for certain breakpoints.
357
+ * @option
358
+ * @example false
359
+ */
360
+ isRevealed: false,
361
+
362
+ /**
363
+ * Breakpoint at which to reveal. JS will use a RegExp to target standard classes, if changing classnames, pass your class with the `revealClass` option.
364
+ * @option
365
+ * @example reveal-for-large
366
+ */
367
+ revealOn: null,
368
+
369
+ /**
370
+ * Force focus to the offcanvas on open. If true, will focus the opening trigger on close.
371
+ * @option
372
+ * @example true
373
+ */
374
+ autoFocus: true,
375
+
376
+ /**
377
+ * Class used to force an offcanvas to remain open. Foundation defaults for this are `reveal-for-large` & `reveal-for-medium`.
378
+ * @option
379
+ * TODO improve the regex testing for this.
380
+ * @example reveal-for-large
381
+ */
382
+ revealClass: 'reveal-for-',
383
+
384
+ /**
385
+ * Triggers optional focus trapping when opening an offcanvas. Sets tabindex of [data-off-canvas-content] to -1 for accessibility purposes.
386
+ * @option
387
+ * @example true
388
+ */
389
+ trapFocus: false
390
+ }
391
+
392
+ // Window exports
393
+ Foundation.plugin(OffCanvas, 'OffCanvas');
394
+
395
+ }(jQuery);