foundation-rails 5.5.3.2 → 6.1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -8
  4. data/Rakefile +23 -0
  5. data/app/views/foundation/rails/styleguide/show.html.erb +2 -5
  6. data/bower.json +2 -2
  7. data/lib/foundation/rails/version.rb +1 -1
  8. data/lib/generators/foundation/install_generator.rb +6 -3
  9. data/lib/generators/foundation/templates/_settings.scss +546 -0
  10. data/lib/generators/foundation/templates/application.html.erb +0 -1
  11. data/lib/generators/foundation/templates/application.html.haml +0 -2
  12. data/lib/generators/foundation/templates/application.html.slim +0 -2
  13. data/lib/generators/foundation/templates/foundation_and_overrides.scss +51 -0
  14. data/vendor/assets/js/foundation.abide.js +418 -0
  15. data/vendor/assets/js/foundation.accordion.js +229 -0
  16. data/vendor/assets/js/foundation.accordionMenu.js +262 -0
  17. data/vendor/assets/js/foundation.core.js +378 -0
  18. data/vendor/assets/js/foundation.drilldown.js +321 -0
  19. data/vendor/assets/js/foundation.dropdown.js +390 -0
  20. data/vendor/assets/js/foundation.dropdownMenu.js +391 -0
  21. data/vendor/assets/js/foundation.equalizer.js +274 -0
  22. data/vendor/assets/js/foundation.interchange.js +184 -0
  23. data/vendor/assets/js/foundation.js +28 -0
  24. data/vendor/assets/js/foundation.magellan.js +212 -0
  25. data/vendor/assets/js/foundation.offcanvas.js +371 -0
  26. data/vendor/assets/js/foundation.orbit.js +419 -0
  27. data/vendor/assets/js/foundation.responsiveMenu.js +145 -0
  28. data/vendor/assets/js/foundation.responsiveToggle.js +106 -0
  29. data/vendor/assets/js/foundation.reveal.js +478 -0
  30. data/vendor/assets/js/foundation.slider.js +484 -0
  31. data/vendor/assets/js/foundation.sticky.js +436 -0
  32. data/vendor/assets/js/foundation.tabs.js +306 -0
  33. data/vendor/assets/js/foundation.toggler.js +147 -0
  34. data/vendor/assets/js/foundation.tooltip.js +429 -0
  35. data/vendor/assets/js/foundation.util.box.js +169 -0
  36. data/vendor/assets/js/foundation.util.keyboard.js +115 -0
  37. data/vendor/assets/js/foundation.util.mediaQuery.js +210 -0
  38. data/vendor/assets/js/foundation.util.motion.js +89 -0
  39. data/vendor/assets/js/foundation.util.nest.js +64 -0
  40. data/vendor/assets/js/foundation.util.timerAndImageLoader.js +78 -0
  41. data/vendor/assets/js/foundation.util.touch.js +339 -0
  42. data/vendor/assets/js/foundation.util.triggers.js +222 -0
  43. data/vendor/assets/scss/_global.scss +626 -0
  44. data/vendor/assets/scss/components/_accordion-menu.scss +32 -0
  45. data/vendor/assets/scss/components/_accordion.scss +113 -0
  46. data/vendor/assets/scss/components/_badge.scss +55 -0
  47. data/vendor/assets/scss/components/_breadcrumbs.scss +94 -0
  48. data/vendor/assets/scss/components/_button-group.scss +130 -0
  49. data/vendor/assets/scss/components/_button.scss +265 -0
  50. data/vendor/assets/scss/components/_callout.scss +105 -0
  51. data/vendor/assets/scss/components/_close-button.scss +61 -0
  52. data/vendor/assets/scss/components/_drilldown.scss +75 -0
  53. data/vendor/assets/scss/components/_dropdown-menu.scss +148 -0
  54. data/vendor/assets/scss/components/_dropdown.scss +64 -0
  55. data/vendor/assets/scss/components/_flex-video.scss +63 -0
  56. data/vendor/assets/scss/components/_float.scss +27 -0
  57. data/vendor/assets/scss/components/_label.scss +56 -0
  58. data/vendor/assets/scss/components/_media-object.scss +74 -0
  59. data/vendor/assets/scss/components/_menu.scss +209 -0
  60. data/vendor/assets/scss/components/_off-canvas.scss +180 -0
  61. data/vendor/assets/scss/components/_orbit.scss +193 -0
  62. data/vendor/assets/scss/components/_pagination.scss +158 -0
  63. data/vendor/assets/scss/components/_progress-bar.scss +83 -0
  64. data/vendor/assets/scss/components/_reveal.scss +156 -0
  65. data/vendor/assets/scss/components/_slider.scss +158 -0
  66. data/vendor/assets/scss/components/_sticky.scss +38 -0
  67. data/vendor/assets/scss/components/_switch.scss +232 -0
  68. data/vendor/assets/scss/components/_table.scss +213 -0
  69. data/vendor/assets/scss/components/_tabs.scss +170 -0
  70. data/vendor/assets/scss/components/_thumbnail.scss +54 -0
  71. data/vendor/assets/scss/components/_title-bar.scss +68 -0
  72. data/vendor/assets/scss/components/_tooltip.scss +100 -0
  73. data/vendor/assets/scss/components/_top-bar.scss +89 -0
  74. data/vendor/assets/scss/components/_visibility.scss +131 -0
  75. data/vendor/assets/scss/forms/_checkbox.scss +36 -0
  76. data/vendor/assets/scss/forms/_error.scss +82 -0
  77. data/vendor/assets/scss/forms/_fieldset.scss +53 -0
  78. data/vendor/assets/scss/forms/_forms.scss +32 -0
  79. data/vendor/assets/scss/forms/_help-text.scss +30 -0
  80. data/vendor/assets/scss/forms/_input-group.scss +91 -0
  81. data/vendor/assets/scss/forms/_label.scss +48 -0
  82. data/vendor/assets/scss/forms/_select.scss +63 -0
  83. data/vendor/assets/scss/forms/_text.scss +154 -0
  84. data/vendor/assets/scss/foundation.scss +91 -0
  85. data/vendor/assets/scss/grid/_classes.scss +153 -0
  86. data/vendor/assets/scss/grid/_column.scss +124 -0
  87. data/vendor/assets/scss/grid/_flex-grid.scss +281 -0
  88. data/vendor/assets/scss/grid/_grid.scss +48 -0
  89. data/vendor/assets/scss/grid/_gutter.scss +34 -0
  90. data/vendor/assets/scss/grid/_layout.scss +33 -0
  91. data/vendor/assets/scss/grid/_position.scss +72 -0
  92. data/vendor/assets/scss/grid/_row.scss +97 -0
  93. data/vendor/assets/scss/grid/_size.scss +24 -0
  94. data/vendor/assets/scss/settings/_settings.scss +547 -0
  95. data/vendor/assets/scss/typography/_alignment.scss +22 -0
  96. data/vendor/assets/scss/typography/_base.scss +439 -0
  97. data/vendor/assets/scss/typography/_helpers.scss +77 -0
  98. data/vendor/assets/scss/typography/_print.scss +73 -0
  99. data/vendor/assets/scss/typography/_typography.scss +28 -0
  100. data/vendor/assets/scss/util/_breakpoint.scss +266 -0
  101. data/vendor/assets/scss/util/_color.scss +41 -0
  102. data/vendor/assets/scss/util/_mixins.scss +223 -0
  103. data/vendor/assets/scss/util/_selector.scss +40 -0
  104. data/vendor/assets/scss/util/_unit.scss +90 -0
  105. data/vendor/assets/scss/util/_util.scss +15 -0
  106. data/vendor/assets/scss/util/_value.scss +126 -0
  107. metadata +97 -64
  108. data/update-gem.sh +0 -20
  109. data/vendor/assets/javascripts/foundation.js +0 -17
  110. data/vendor/assets/javascripts/foundation/foundation.abide.js +0 -426
  111. data/vendor/assets/javascripts/foundation/foundation.accordion.js +0 -125
  112. data/vendor/assets/javascripts/foundation/foundation.alert.js +0 -43
  113. data/vendor/assets/javascripts/foundation/foundation.clearing.js +0 -586
  114. data/vendor/assets/javascripts/foundation/foundation.dropdown.js +0 -468
  115. data/vendor/assets/javascripts/foundation/foundation.equalizer.js +0 -104
  116. data/vendor/assets/javascripts/foundation/foundation.interchange.js +0 -360
  117. data/vendor/assets/javascripts/foundation/foundation.joyride.js +0 -935
  118. data/vendor/assets/javascripts/foundation/foundation.js +0 -732
  119. data/vendor/assets/javascripts/foundation/foundation.magellan.js +0 -214
  120. data/vendor/assets/javascripts/foundation/foundation.offcanvas.js +0 -225
  121. data/vendor/assets/javascripts/foundation/foundation.orbit.js +0 -476
  122. data/vendor/assets/javascripts/foundation/foundation.reveal.js +0 -522
  123. data/vendor/assets/javascripts/foundation/foundation.slider.js +0 -296
  124. data/vendor/assets/javascripts/foundation/foundation.tab.js +0 -247
  125. data/vendor/assets/javascripts/foundation/foundation.tooltip.js +0 -348
  126. data/vendor/assets/javascripts/foundation/foundation.topbar.js +0 -458
  127. data/vendor/assets/javascripts/vendor/modernizr.js +0 -1406
  128. data/vendor/assets/stylesheets/foundation.scss +0 -42
  129. data/vendor/assets/stylesheets/foundation/_functions.scss +0 -156
  130. data/vendor/assets/stylesheets/foundation/_settings.scss +0 -1489
  131. data/vendor/assets/stylesheets/foundation/components/_accordion.scss +0 -161
  132. data/vendor/assets/stylesheets/foundation/components/_alert-boxes.scss +0 -128
  133. data/vendor/assets/stylesheets/foundation/components/_block-grid.scss +0 -133
  134. data/vendor/assets/stylesheets/foundation/components/_breadcrumbs.scss +0 -132
  135. data/vendor/assets/stylesheets/foundation/components/_button-groups.scss +0 -208
  136. data/vendor/assets/stylesheets/foundation/components/_buttons.scss +0 -261
  137. data/vendor/assets/stylesheets/foundation/components/_clearing.scss +0 -260
  138. data/vendor/assets/stylesheets/foundation/components/_dropdown-buttons.scss +0 -130
  139. data/vendor/assets/stylesheets/foundation/components/_dropdown.scss +0 -269
  140. data/vendor/assets/stylesheets/foundation/components/_flex-video.scss +0 -51
  141. data/vendor/assets/stylesheets/foundation/components/_forms.scss +0 -607
  142. data/vendor/assets/stylesheets/foundation/components/_global.scss +0 -566
  143. data/vendor/assets/stylesheets/foundation/components/_grid.scss +0 -292
  144. data/vendor/assets/stylesheets/foundation/components/_icon-bar.scss +0 -460
  145. data/vendor/assets/stylesheets/foundation/components/_inline-lists.scss +0 -58
  146. data/vendor/assets/stylesheets/foundation/components/_joyride.scss +0 -220
  147. data/vendor/assets/stylesheets/foundation/components/_keystrokes.scss +0 -60
  148. data/vendor/assets/stylesheets/foundation/components/_labels.scss +0 -106
  149. data/vendor/assets/stylesheets/foundation/components/_magellan.scss +0 -34
  150. data/vendor/assets/stylesheets/foundation/components/_offcanvas.scss +0 -606
  151. data/vendor/assets/stylesheets/foundation/components/_orbit.scss +0 -388
  152. data/vendor/assets/stylesheets/foundation/components/_pagination.scss +0 -163
  153. data/vendor/assets/stylesheets/foundation/components/_panels.scss +0 -107
  154. data/vendor/assets/stylesheets/foundation/components/_pricing-tables.scss +0 -150
  155. data/vendor/assets/stylesheets/foundation/components/_progress-bars.scss +0 -85
  156. data/vendor/assets/stylesheets/foundation/components/_range-slider.scss +0 -177
  157. data/vendor/assets/stylesheets/foundation/components/_reveal.scss +0 -212
  158. data/vendor/assets/stylesheets/foundation/components/_side-nav.scss +0 -120
  159. data/vendor/assets/stylesheets/foundation/components/_split-buttons.scss +0 -203
  160. data/vendor/assets/stylesheets/foundation/components/_sub-nav.scss +0 -125
  161. data/vendor/assets/stylesheets/foundation/components/_switches.scss +0 -241
  162. data/vendor/assets/stylesheets/foundation/components/_tables.scss +0 -135
  163. data/vendor/assets/stylesheets/foundation/components/_tabs.scss +0 -142
  164. data/vendor/assets/stylesheets/foundation/components/_thumbs.scss +0 -66
  165. data/vendor/assets/stylesheets/foundation/components/_tooltips.scss +0 -142
  166. data/vendor/assets/stylesheets/foundation/components/_top-bar.scss +0 -745
  167. data/vendor/assets/stylesheets/foundation/components/_type.scss +0 -525
  168. data/vendor/assets/stylesheets/foundation/components/_visibility.scss +0 -425
  169. data/vendor/assets/stylesheets/normalize.scss +0 -424
@@ -0,0 +1,390 @@
1
+ /**
2
+ * Dropdown module.
3
+ * @module foundation.dropdown
4
+ * @requires foundation.util.keyboard
5
+ * @requires foundation.util.box
6
+ */
7
+ !function($, Foundation){
8
+ 'use strict';
9
+ /**
10
+ * Creates a new instance of a dropdown.
11
+ * @class
12
+ * @param {jQuery} element - jQuery object to make into an accordion menu.
13
+ * @param {Object} options - Overrides to the default plugin settings.
14
+ */
15
+ function Dropdown(element, options){
16
+ this.$element = element;
17
+ this.options = $.extend({}, Dropdown.defaults, this.$element.data(), options);
18
+ this._init();
19
+
20
+ Foundation.registerPlugin(this, 'Dropdown');
21
+ Foundation.Keyboard.register('Dropdown', {
22
+ 'ENTER': 'open',
23
+ 'SPACE': 'open',
24
+ 'ESCAPE': 'close',
25
+ 'TAB': 'tab_forward',
26
+ 'SHIFT_TAB': 'tab_backward'
27
+ });
28
+ }
29
+
30
+ Dropdown.defaults = {
31
+ /**
32
+ * Amount of time to delay opening a submenu on hover event.
33
+ * @option
34
+ * @example 250
35
+ */
36
+ hoverDelay: 250,
37
+ /**
38
+ * Allow submenus to open on hover events
39
+ * @option
40
+ * @example false
41
+ */
42
+ hover: false,
43
+ /**
44
+ * Don't close dropdown when hovering over dropdown pane
45
+ * @option
46
+ * @example true
47
+ */
48
+ hoverPane: false,
49
+ /**
50
+ * Number of pixels between the dropdown pane and the triggering element on open.
51
+ * @option
52
+ * @example 1
53
+ */
54
+ vOffset: 1,
55
+ /**
56
+ * Number of pixels between the dropdown pane and the triggering element on open.
57
+ * @option
58
+ * @example 1
59
+ */
60
+ hOffset: 1,
61
+ /**
62
+ * Class applied to adjust open position. JS will test and fill this in.
63
+ * @option
64
+ * @example 'top'
65
+ */
66
+ positionClass: '',
67
+ /**
68
+ * Allow the plugin to trap focus to the dropdown pane if opened with keyboard commands.
69
+ * @option
70
+ * @example false
71
+ */
72
+ trapFocus: false,
73
+ /**
74
+ * Allow the plugin to set focus to the first focusable element within the pane, regardless of method of opening.
75
+ * @option
76
+ * @example true
77
+ */
78
+ autoFocus: false,
79
+ /**
80
+ * Allows a click on the body to close the dropdown.
81
+ * @option
82
+ * @example true
83
+ */
84
+ closeOnClick: false
85
+ };
86
+ /**
87
+ * Initializes the plugin by setting/checking options and attributes, adding helper variables, and saving the anchor.
88
+ * @function
89
+ * @private
90
+ */
91
+ Dropdown.prototype._init = function(){
92
+ var $id = this.$element.attr('id');
93
+
94
+ this.$anchor = $('[data-toggle="' + $id + '"]') || $('[data-open="' + $id + '"]');
95
+ this.$anchor.attr({
96
+ 'aria-controls': $id,
97
+ 'data-is-focus': false,
98
+ 'data-yeti-box': $id,
99
+ 'aria-haspopup': true,
100
+ 'aria-expanded': false
101
+ // 'data-resize': $id
102
+ });
103
+
104
+ this.options.positionClass = this.getPositionClass();
105
+ this.counter = 4;
106
+ this.usedPositions = [];
107
+ this.$element.attr({
108
+ 'aria-hidden': 'true',
109
+ 'data-yeti-box': $id,
110
+ 'data-resize': $id,
111
+ 'aria-labelledby': this.$anchor[0].id || Foundation.GetYoDigits(6, 'dd-anchor')
112
+ });
113
+ this._events();
114
+ };
115
+ /**
116
+ * Helper function to determine current orientation of dropdown pane.
117
+ * @function
118
+ * @returns {String} position - string value of a position class.
119
+ */
120
+ Dropdown.prototype.getPositionClass = function(){
121
+ var position = this.$element[0].className.match(/(top|left|right)/g);
122
+ position = position ? position[0] : '';
123
+ return position;
124
+ };
125
+ /**
126
+ * Adjusts the dropdown panes orientation by adding/removing positioning classes.
127
+ * @function
128
+ * @private
129
+ * @param {String} position - position class to remove.
130
+ */
131
+ Dropdown.prototype._reposition = function(position){
132
+ this.usedPositions.push(position ? position : 'bottom');
133
+ //default, try switching to opposite side
134
+ if(!position && (this.usedPositions.indexOf('top') < 0)){
135
+ this.$element.addClass('top');
136
+ }else if(position === 'top' && (this.usedPositions.indexOf('bottom') < 0)){
137
+ this.$element.removeClass(position);
138
+ }else if(position === 'left' && (this.usedPositions.indexOf('right') < 0)){
139
+ this.$element.removeClass(position)
140
+ .addClass('right');
141
+ }else if(position === 'right' && (this.usedPositions.indexOf('left') < 0)){
142
+ this.$element.removeClass(position)
143
+ .addClass('left');
144
+ }
145
+
146
+ //if default change didn't work, try bottom or left first
147
+ else if(!position && (this.usedPositions.indexOf('top') > -1) && (this.usedPositions.indexOf('left') < 0)){
148
+ this.$element.addClass('left');
149
+ }else if(position === 'top' && (this.usedPositions.indexOf('bottom') > -1) && (this.usedPositions.indexOf('left') < 0)){
150
+ this.$element.removeClass(position)
151
+ .addClass('left');
152
+ }else if(position === 'left' && (this.usedPositions.indexOf('right') > -1) && (this.usedPositions.indexOf('bottom') < 0)){
153
+ this.$element.removeClass(position);
154
+ }else if(position === 'right' && (this.usedPositions.indexOf('left') > -1) && (this.usedPositions.indexOf('bottom') < 0)){
155
+ this.$element.removeClass(position);
156
+ }
157
+ //if nothing cleared, set to bottom
158
+ else{
159
+ this.$element.removeClass(position);
160
+ }
161
+ this.classChanged = true;
162
+ this.counter--;
163
+ };
164
+ /**
165
+ * Sets the position and orientation of the dropdown pane, checks for collisions.
166
+ * Recursively calls itself if a collision is detected, with a new position class.
167
+ * @function
168
+ * @private
169
+ */
170
+ Dropdown.prototype._setPosition = function(){
171
+ if(this.$anchor.attr('aria-expanded') === 'false'){ return false; }
172
+ var position = this.getPositionClass(),
173
+ $eleDims = Foundation.Box.GetDimensions(this.$element),
174
+ $anchorDims = Foundation.Box.GetDimensions(this.$anchor),
175
+ _this = this,
176
+ direction = (position === 'left' ? 'left' : ((position === 'right') ? 'left' : 'top')),
177
+ param = (direction === 'top') ? 'height' : 'width',
178
+ offset = (param === 'height') ? this.options.vOffset : this.options.hOffset;
179
+
180
+ if(($eleDims.width >= $eleDims.windowDims.width) || (!this.counter && !Foundation.Box.ImNotTouchingYou(this.$element))){
181
+ this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, 'center bottom', this.options.vOffset, this.options.hOffset, true)).css({
182
+ 'width': $eleDims.windowDims.width - (this.options.hOffset * 2),
183
+ 'height': 'auto'
184
+ });
185
+ this.classChanged = true;
186
+ return false;
187
+ }
188
+
189
+ this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, position, this.options.vOffset, this.options.hOffset));
190
+
191
+ while(!Foundation.Box.ImNotTouchingYou(this.$element) && this.counter){
192
+ this._reposition(position);
193
+ this._setPosition();
194
+ }
195
+ };
196
+ /**
197
+ * Adds event listeners to the element utilizing the triggers utility library.
198
+ * @function
199
+ * @private
200
+ */
201
+ Dropdown.prototype._events = function(){
202
+ var _this = this;
203
+ this.$element.on({
204
+ 'open.zf.trigger': this.open.bind(this),
205
+ 'close.zf.trigger': this.close.bind(this),
206
+ 'toggle.zf.trigger': this.toggle.bind(this),
207
+ 'resizeme.zf.trigger': this._setPosition.bind(this)
208
+ });
209
+
210
+ if(this.options.hover){
211
+ this.$anchor.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
212
+ .on('mouseenter.zf.dropdown', function(){
213
+ clearTimeout(_this.timeout);
214
+ _this.timeout = setTimeout(function(){
215
+ _this.open();
216
+ _this.$anchor.data('hover', true);
217
+ }, _this.options.hoverDelay);
218
+ }).on('mouseleave.zf.dropdown', function(){
219
+ clearTimeout(_this.timeout);
220
+ _this.timeout = setTimeout(function(){
221
+ _this.close();
222
+ _this.$anchor.data('hover', false);
223
+ }, _this.options.hoverDelay);
224
+ });
225
+ if(this.options.hoverPane){
226
+ this.$element.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
227
+ .on('mouseenter.zf.dropdown', function(){
228
+ clearTimeout(_this.timeout);
229
+ }).on('mouseleave.zf.dropdown', function(){
230
+ clearTimeout(_this.timeout);
231
+ _this.timeout = setTimeout(function(){
232
+ _this.close();
233
+ _this.$anchor.data('hover', false);
234
+ }, _this.options.hoverDelay);
235
+ });
236
+ }
237
+ }
238
+ this.$anchor.add(this.$element).on('keydown.zf.dropdown', function(e) {
239
+
240
+ var $target = $(this),
241
+ visibleFocusableElements = Foundation.Keyboard.findFocusable(_this.$element);
242
+
243
+ Foundation.Keyboard.handleKey(e, 'Dropdown', {
244
+ tab_forward: function() {
245
+ if (_this.$element.find(':focus').is(visibleFocusableElements.eq(-1))) { // left modal downwards, setting focus to first element
246
+ if (_this.options.trapFocus) { // if focus shall be trapped
247
+ visibleFocusableElements.eq(0).focus();
248
+ e.preventDefault();
249
+ } else { // if focus is not trapped, close dropdown on focus out
250
+ _this.close();
251
+ }
252
+ }
253
+ },
254
+ tab_backward: function() {
255
+ if (_this.$element.find(':focus').is(visibleFocusableElements.eq(0)) || _this.$element.is(':focus')) { // left modal upwards, setting focus to last element
256
+ if (_this.options.trapFocus) { // if focus shall be trapped
257
+ visibleFocusableElements.eq(-1).focus();
258
+ e.preventDefault();
259
+ } else { // if focus is not trapped, close dropdown on focus out
260
+ _this.close();
261
+ }
262
+ }
263
+ },
264
+ open: function() {
265
+ if ($target.is(_this.$anchor)) {
266
+ _this.open();
267
+ _this.$element.attr('tabindex', -1).focus();
268
+ e.preventDefault();
269
+ }
270
+ },
271
+ close: function() {
272
+ _this.close();
273
+ _this.$anchor.focus();
274
+ }
275
+ });
276
+ });
277
+ };
278
+ /**
279
+ * Adds an event handler to the body to close any dropdowns on a click.
280
+ * @function
281
+ * @private
282
+ */
283
+ Dropdown.prototype._addBodyHandler = function(){
284
+ var $body = $(document.body).not(this.$element),
285
+ _this = this;
286
+ $body.off('click.zf.dropdown')
287
+ .on('click.zf.dropdown', function(e){
288
+ if(_this.$anchor.is(e.target) || _this.$anchor.find(e.target).length) {
289
+ return;
290
+ }
291
+ if(_this.$element.find(e.target).length) {
292
+ return;
293
+ }
294
+ _this.close();
295
+ $body.off('click.zf.dropdown');
296
+ });
297
+ };
298
+ /**
299
+ * Opens the dropdown pane, and fires a bubbling event to close other dropdowns.
300
+ * @function
301
+ * @fires Dropdown#closeme
302
+ * @fires Dropdown#show
303
+ */
304
+ Dropdown.prototype.open = function(){
305
+ // var _this = this;
306
+ /**
307
+ * Fires to close other open dropdowns
308
+ * @event Dropdown#closeme
309
+ */
310
+ this.$element.trigger('closeme.zf.dropdown', this.$element.attr('id'));
311
+ this.$anchor.addClass('hover')
312
+ .attr({'aria-expanded': true});
313
+ // this.$element/*.show()*/;
314
+ this._setPosition();
315
+ this.$element.addClass('is-open')
316
+ .attr({'aria-hidden': false});
317
+
318
+ if(this.options.autoFocus){
319
+ var $focusable = Foundation.Keyboard.findFocusable(this.$element);
320
+ if($focusable.length){
321
+ $focusable.eq(0).focus();
322
+ }
323
+ }
324
+
325
+ if(this.options.closeOnClick){ this._addBodyHandler(); }
326
+
327
+ /**
328
+ * Fires once the dropdown is visible.
329
+ * @event Dropdown#show
330
+ */
331
+ this.$element.trigger('show.zf.dropdown', [this.$element]);
332
+ //why does this not work correctly for this plugin?
333
+ // Foundation.reflow(this.$element, 'dropdown');
334
+ // Foundation._reflow(this.$element.attr('data-dropdown'));
335
+ };
336
+
337
+ /**
338
+ * Closes the open dropdown pane.
339
+ * @function
340
+ * @fires Dropdown#hide
341
+ */
342
+ Dropdown.prototype.close = function(){
343
+ if(!this.$element.hasClass('is-open')){
344
+ return false;
345
+ }
346
+ this.$element.removeClass('is-open')
347
+ .attr({'aria-hidden': true});
348
+
349
+ this.$anchor.removeClass('hover')
350
+ .attr('aria-expanded', false);
351
+
352
+ if(this.classChanged){
353
+ var curPositionClass = this.getPositionClass();
354
+ if(curPositionClass){
355
+ this.$element.removeClass(curPositionClass);
356
+ }
357
+ this.$element.addClass(this.options.positionClass)
358
+ /*.hide()*/.css({height: '', width: ''});
359
+ this.classChanged = false;
360
+ this.counter = 4;
361
+ this.usedPositions.length = 0;
362
+ }
363
+ this.$element.trigger('hide.zf.dropdown', [this.$element]);
364
+ // Foundation.reflow(this.$element, 'dropdown');
365
+ };
366
+ /**
367
+ * Toggles the dropdown pane's visibility.
368
+ * @function
369
+ */
370
+ Dropdown.prototype.toggle = function(){
371
+ if(this.$element.hasClass('is-open')){
372
+ if(this.$anchor.data('hover')) return;
373
+ this.close();
374
+ }else{
375
+ this.open();
376
+ }
377
+ };
378
+ /**
379
+ * Destroys the dropdown.
380
+ * @function
381
+ */
382
+ Dropdown.prototype.destroy = function(){
383
+ this.$element.off('.zf.trigger').hide();
384
+ this.$anchor.off('.zf.dropdown');
385
+
386
+ Foundation.unregisterPlugin(this);
387
+ };
388
+
389
+ Foundation.plugin(Dropdown, 'Dropdown');
390
+ }(jQuery, window.Foundation);
@@ -0,0 +1,391 @@
1
+ /**
2
+ * DropdownMenu module.
3
+ * @module foundation.dropdown-menu
4
+ * @requires foundation.util.keyboard
5
+ * @requires foundation.util.box
6
+ * @requires foundation.util.nest
7
+ */
8
+ !function($, Foundation){
9
+ 'use strict';
10
+
11
+ /**
12
+ * Creates a new instance of DropdownMenu.
13
+ * @class
14
+ * @fires DropdownMenu#init
15
+ * @param {jQuery} element - jQuery object to make into a dropdown menu.
16
+ * @param {Object} options - Overrides to the default plugin settings.
17
+ */
18
+ function DropdownMenu(element, options){
19
+ this.$element = element;
20
+ this.options = $.extend({}, DropdownMenu.defaults, this.$element.data(), options);
21
+
22
+ Foundation.Nest.Feather(this.$element, 'dropdown');
23
+ this._init();
24
+
25
+ Foundation.registerPlugin(this, 'DropdownMenu');
26
+ Foundation.Keyboard.register('DropdownMenu', {
27
+ 'ENTER': 'open',
28
+ 'SPACE': 'open',
29
+ 'ARROW_RIGHT': 'next',
30
+ 'ARROW_UP': 'up',
31
+ 'ARROW_DOWN': 'down',
32
+ 'ARROW_LEFT': 'previous',
33
+ 'ESCAPE': 'close'
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Default settings for plugin
39
+ */
40
+ DropdownMenu.defaults = {
41
+ /**
42
+ * Disallows hover events from opening submenus
43
+ * @option
44
+ * @example false
45
+ */
46
+ disableHover: false,
47
+ /**
48
+ * Allow a submenu to automatically close on a mouseleave event, if not clicked open.
49
+ * @option
50
+ * @example true
51
+ */
52
+ autoclose: true,
53
+ /**
54
+ * Amount of time to delay opening a submenu on hover event.
55
+ * @option
56
+ * @example 50
57
+ */
58
+ hoverDelay: 50,
59
+ /**
60
+ * Allow a submenu to open/remain open on parent click event. Allows cursor to move away from menu.
61
+ * @option
62
+ * @example true
63
+ */
64
+ clickOpen: false,
65
+ /**
66
+ * Amount of time to delay closing a submenu on a mouseleave event.
67
+ * @option
68
+ * @example 500
69
+ */
70
+
71
+ closingTime: 500,
72
+ /**
73
+ * Position of the menu relative to what direction the submenus should open. Handled by JS.
74
+ * @option
75
+ * @example 'left'
76
+ */
77
+ alignment: 'left',
78
+ /**
79
+ * Allow clicks on the body to close any open submenus.
80
+ * @option
81
+ * @example true
82
+ */
83
+ closeOnClick: true,
84
+ /**
85
+ * Class applied to vertical oriented menus, Foundation default is `vertical`. Update this if using your own class.
86
+ * @option
87
+ * @example 'vertical'
88
+ */
89
+ verticalClass: 'vertical',
90
+ /**
91
+ * Class applied to right-side oriented menus, Foundation default is `align-right`. Update this if using your own class.
92
+ * @option
93
+ * @example 'align-right'
94
+ */
95
+ rightClass: 'align-right',
96
+ /**
97
+ * Boolean to force overide the clicking of links to perform default action, on second touch event for mobile.
98
+ * @option
99
+ * @example false
100
+ */
101
+ forceFollow: true
102
+ };
103
+ /**
104
+ * Initializes the plugin, and calls _prepareMenu
105
+ * @private
106
+ * @function
107
+ */
108
+ DropdownMenu.prototype._init = function(){
109
+ var subs = this.$element.find('li.is-dropdown-submenu-parent');
110
+ this.$element.children('.is-dropdown-submenu-parent').children('.is-dropdown-submenu').addClass('first-sub');
111
+
112
+ this.$menuItems = this.$element.find('[role="menuitem"]');
113
+ this.$tabs = this.$element.children('[role="menuitem"]');
114
+ this.isVert = this.$element.hasClass(this.options.verticalClass);
115
+ this.$tabs.find('ul.is-dropdown-submenu').addClass(this.options.verticalClass);
116
+
117
+ if(this.$element.hasClass(this.options.rightClass) || this.options.alignment === 'right'){
118
+ this.options.alignment = 'right';
119
+ subs.addClass('is-left-arrow opens-left');
120
+ }else{
121
+ subs.addClass('is-right-arrow opens-right');
122
+ }
123
+ if(!this.isVert){
124
+ this.$tabs.filter('.is-dropdown-submenu-parent').removeClass('is-right-arrow is-left-arrow opens-right opens-left')
125
+ .addClass('is-down-arrow');
126
+ }
127
+ this.changed = false;
128
+ this._events();
129
+ };
130
+ /**
131
+ * Adds event listeners to elements within the menu
132
+ * @private
133
+ * @function
134
+ */
135
+ DropdownMenu.prototype._events = function(){
136
+ var _this = this,
137
+ hasTouch = 'ontouchstart' in window || (typeof window.ontouchstart !== 'undefined'),
138
+ parClass = 'is-dropdown-submenu-parent',
139
+ delay;
140
+
141
+ if(this.options.clickOpen || hasTouch){
142
+ this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', function(e){
143
+ var $elem = $(e.target).parentsUntil('ul', '.' + parClass),
144
+ hasSub = $elem.hasClass(parClass),
145
+ hasClicked = $elem.attr('data-is-click') === 'true',
146
+ $sub = $elem.children('.is-dropdown-submenu');
147
+
148
+ if(hasSub){
149
+ if(hasClicked){
150
+ if(!_this.options.closeOnClick || (!_this.options.clickOpen && !hasTouch) || (_this.options.forceFollow && hasTouch)){ return; }
151
+ else{
152
+ e.stopImmediatePropagation();
153
+ e.preventDefault();
154
+ _this._hide($elem);
155
+ }
156
+ }else{
157
+ e.preventDefault();
158
+ e.stopImmediatePropagation();
159
+ _this._show($elem.children('.is-dropdown-submenu'));
160
+ $elem.add($elem.parentsUntil(_this.$element, '.' + parClass)).attr('data-is-click', true);
161
+ }
162
+ }else{ return; }
163
+ });
164
+ }
165
+
166
+ if(!this.options.disableHover){
167
+ this.$menuItems.on('mouseenter.zf.dropdownmenu', function(e){
168
+ e.stopImmediatePropagation();
169
+ var $elem = $(this),
170
+ hasSub = $elem.hasClass(parClass);
171
+
172
+ if(hasSub){
173
+ clearTimeout(delay);
174
+ delay = setTimeout(function(){
175
+ _this._show($elem.children('.is-dropdown-submenu'));
176
+ }, _this.options.hoverDelay);
177
+ }
178
+ }).on('mouseleave.zf.dropdownmenu', function(e){
179
+ var $elem = $(this),
180
+ hasSub = $elem.hasClass(parClass);
181
+ if(hasSub && _this.options.autoclose){
182
+ if($elem.attr('data-is-click') === 'true' && _this.options.clickOpen){ return false; }
183
+
184
+ // clearTimeout(delay);
185
+ delay = setTimeout(function(){
186
+ _this._hide($elem);
187
+ }, _this.options.closingTime);
188
+ }
189
+ });
190
+ }
191
+ this.$menuItems.on('keydown.zf.dropdownmenu', function(e){
192
+ var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'),
193
+ isTab = _this.$tabs.index($element) > -1,
194
+ $elements = isTab ? _this.$tabs : $element.siblings('li').add($element),
195
+ $prevElement,
196
+ $nextElement;
197
+
198
+ $elements.each(function(i) {
199
+ if ($(this).is($element)) {
200
+ $prevElement = $elements.eq(i-1);
201
+ $nextElement = $elements.eq(i+1);
202
+ return;
203
+ }
204
+ });
205
+
206
+ var nextSibling = function() {
207
+ if (!$element.is(':last-child')) $nextElement.children('a:first').focus();
208
+ }, prevSibling = function() {
209
+ $prevElement.children('a:first').focus();
210
+ }, openSub = function() {
211
+ var $sub = $element.children('ul.is-dropdown-submenu');
212
+ if($sub.length){
213
+ _this._show($sub);
214
+ $element.find('li > a:first').focus();
215
+ }else{ return; }
216
+ }, closeSub = function() {
217
+ //if ($element.is(':first-child')) {
218
+ var close = $element.parent('ul').parent('li');
219
+ close.children('a:first').focus();
220
+ _this._hide(close);
221
+ //}
222
+ };
223
+ var functions = {
224
+ open: openSub,
225
+ close: function() {
226
+ _this._hide(_this.$element);
227
+ _this.$menuItems.find('a:first').focus(); // focus to first element
228
+ },
229
+ handled: function() {
230
+ e.preventDefault();
231
+ e.stopImmediatePropagation();
232
+ }
233
+ };
234
+
235
+ if (isTab) {
236
+ if (_this.vertical) { // vertical menu
237
+ if (_this.options.alignment === 'left') { // left aligned
238
+ $.extend(functions, {
239
+ down: nextSibling,
240
+ up: prevSibling,
241
+ next: openSub,
242
+ previous: closeSub
243
+ });
244
+ } else { // right aligned
245
+ $.extend(functions, {
246
+ down: nextSibling,
247
+ up: prevSibling,
248
+ next: closeSub,
249
+ previous: openSub
250
+ });
251
+ }
252
+ } else { // horizontal menu
253
+ $.extend(functions, {
254
+ next: nextSibling,
255
+ previous: prevSibling,
256
+ down: openSub,
257
+ up: closeSub
258
+ });
259
+ }
260
+ } else { // not tabs -> one sub
261
+ if (_this.options.alignment === 'left') { // left aligned
262
+ $.extend(functions, {
263
+ next: openSub,
264
+ previous: closeSub,
265
+ down: nextSibling,
266
+ up: prevSibling
267
+ });
268
+ } else { // right aligned
269
+ $.extend(functions, {
270
+ next: closeSub,
271
+ previous: openSub,
272
+ down: nextSibling,
273
+ up: prevSibling
274
+ });
275
+ }
276
+ }
277
+ Foundation.Keyboard.handleKey(e, 'DropdownMenu', functions);
278
+
279
+ });
280
+ };
281
+ /**
282
+ * Adds an event handler to the body to close any dropdowns on a click.
283
+ * @function
284
+ * @private
285
+ */
286
+ DropdownMenu.prototype._addBodyHandler = function(){
287
+ var $body = $(document.body),
288
+ _this = this;
289
+ $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu')
290
+ .on('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu', function(e){
291
+ var $link = _this.$element.find(e.target);
292
+ if($link.length){ return; }
293
+
294
+ _this._hide();
295
+ $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu');
296
+ });
297
+ };
298
+ /**
299
+ * Opens a dropdown pane, and checks for collisions first.
300
+ * @param {jQuery} $sub - ul element that is a submenu to show
301
+ * @function
302
+ * @private
303
+ * @fires DropdownMenu#show
304
+ */
305
+ DropdownMenu.prototype._show = function($sub){
306
+ var idx = this.$tabs.index(this.$tabs.filter(function(i, el){
307
+ return $(el).find($sub).length > 0;
308
+ }));
309
+ var $sibs = $sub.parent('li.is-dropdown-submenu-parent').siblings('li.is-dropdown-submenu-parent');
310
+ this._hide($sibs, idx);
311
+ $sub.css('visibility', 'hidden').addClass('js-dropdown-active').attr({'aria-hidden': false})
312
+ .parent('li.is-dropdown-submenu-parent').addClass('is-active')
313
+ .attr({'aria-selected': true, 'aria-expanded': true});
314
+ var clear = Foundation.Box.ImNotTouchingYou($sub, null, true);
315
+ if(!clear){
316
+ var oldClass = this.options.alignment === 'left' ? '-right' : '-left',
317
+ $parentLi = $sub.parent('.is-dropdown-submenu-parent');
318
+ $parentLi.removeClass('opens' + oldClass).addClass('opens-' + this.options.alignment);
319
+ clear = Foundation.Box.ImNotTouchingYou($sub, null, true);
320
+ if(!clear){
321
+ $parentLi.removeClass('opens-' + this.options.alignment).addClass('opens-inner');
322
+ }
323
+ this.changed = true;
324
+ }
325
+ $sub.css('visibility', '');
326
+ if(this.options.closeOnClick){ this._addBodyHandler(); }
327
+ /**
328
+ * Fires when the new dropdown pane is visible.
329
+ * @event DropdownMenu#show
330
+ */
331
+ this.$element.trigger('show.zf.dropdownmenu', [$sub]);
332
+ };
333
+ /**
334
+ * Hides a single, currently open dropdown pane, if passed a parameter, otherwise, hides everything.
335
+ * @function
336
+ * @param {jQuery} $elem - element with a submenu to hide
337
+ * @param {Number} idx - index of the $tabs collection to hide
338
+ * @private
339
+ */
340
+ DropdownMenu.prototype._hide = function($elem, idx){
341
+ var $toClose;
342
+ if($elem && $elem.length){
343
+ $toClose = $elem;
344
+ }else if(idx !== undefined){
345
+ $toClose = this.$tabs.not(function(i, el){
346
+ return i === idx;
347
+ });
348
+ }
349
+ else{
350
+ $toClose = this.$element;
351
+ }
352
+ var somethingToClose = $toClose.hasClass('is-active') || $toClose.find('.is-active').length > 0;
353
+
354
+ if(somethingToClose){
355
+ $toClose.find('li.is-active').add($toClose).attr({
356
+ 'aria-selected': false,
357
+ 'aria-expanded': false,
358
+ 'data-is-click': false
359
+ }).removeClass('is-active');
360
+
361
+ $toClose.find('ul.js-dropdown-active').attr({
362
+ 'aria-hidden': true
363
+ }).removeClass('js-dropdown-active');
364
+
365
+ if(this.changed || $toClose.find('opens-inner').length){
366
+ var oldClass = this.options.alignment === 'left' ? 'right' : 'left';
367
+ $toClose.find('li.is-dropdown-submenu-parent').add($toClose)
368
+ .removeClass('opens-inner opens-' + this.options.alignment)
369
+ .addClass('opens-' + oldClass);
370
+ this.changed = false;
371
+ }
372
+ /**
373
+ * Fires when the open menus are closed.
374
+ * @event DropdownMenu#hide
375
+ */
376
+ this.$element.trigger('hide.zf.dropdownmenu', [$toClose]);
377
+ }
378
+ };
379
+ /**
380
+ * Destroys the plugin.
381
+ * @function
382
+ */
383
+ DropdownMenu.prototype.destroy = function(){
384
+ this.$menuItems.off('.zf.dropdownmenu').removeAttr('data-is-click')
385
+ .removeClass('is-right-arrow is-left-arrow is-down-arrow opens-right opens-left opens-inner');
386
+ Foundation.Nest.Burn(this.$element, 'dropdown');
387
+ Foundation.unregisterPlugin(this);
388
+ };
389
+
390
+ Foundation.plugin(DropdownMenu, 'DropdownMenu');
391
+ }(jQuery, window.Foundation);