1!function ($) { 2 3 "use strict"; 4 5 var FOUNDATION_VERSION = '6.2.1'; 6 7 // Global Foundation object 8 // This is attached to the window, or used as a module for AMD/Browserify 9 var Foundation = { 10 version: FOUNDATION_VERSION, 11 12 /** 13 * Stores initialized plugins. 14 */ 15 _plugins: {}, 16 17 /** 18 * Stores generated unique ids for plugin instances 19 */ 20 _uuids: [], 21 22 /** 23 * Returns a boolean for RTL support 24 */ 25 rtl: function () { 26 return $('html').attr('dir') === 'rtl'; 27 }, 28 /** 29 * Defines a Foundation plugin, adding it to the `Foundation` namespace and the list of plugins to initialize when reflowing. 30 * @param {Object} plugin - The constructor of the plugin. 31 */ 32 plugin: function (plugin, name) { 33 // Object key to use when adding to global Foundation object 34 // Examples: Foundation.Reveal, Foundation.OffCanvas 35 var className = name || functionName(plugin); 36 // Object key to use when storing the plugin, also used to create the identifying data attribute for the plugin 37 // Examples: data-reveal, data-off-canvas 38 var attrName = hyphenate(className); 39 40 // Add to the Foundation object and the plugins list (for reflowing) 41 this._plugins[attrName] = this[className] = plugin; 42 }, 43 /** 44 * @function 45 * Populates the _uuids array with pointers to each individual plugin instance. 46 * Adds the `zfPlugin` data-attribute to programmatically created plugins to allow use of $(selector).foundation(method) calls. 47 * Also fires the initialization event for each plugin, consolidating repeditive code. 48 * @param {Object} plugin - an instance of a plugin, usually `this` in context. 49 * @param {String} name - the name of the plugin, passed as a camelCased string. 50 * @fires Plugin#init 51 */ 52 registerPlugin: function (plugin, name) { 53 var pluginName = name ? hyphenate(name) : functionName(plugin.constructor).toLowerCase(); 54 plugin.uuid = this.GetYoDigits(6, pluginName); 55 56 if (!plugin.$element.attr('data-' + pluginName)) { 57 plugin.$element.attr('data-' + pluginName, plugin.uuid); 58 } 59 if (!plugin.$element.data('zfPlugin')) { 60 plugin.$element.data('zfPlugin', plugin); 61 } 62 /** 63 * Fires when the plugin has initialized. 64 * @event Plugin#init 65 */ 66 plugin.$element.trigger('init.zf.' + pluginName); 67 68 this._uuids.push(plugin.uuid); 69 70 return; 71 }, 72 /** 73 * @function 74 * Removes the plugins uuid from the _uuids array. 75 * Removes the zfPlugin data attribute, as well as the data-plugin-name attribute. 76 * Also fires the destroyed event for the plugin, consolidating repeditive code. 77 * @param {Object} plugin - an instance of a plugin, usually `this` in context. 78 * @fires Plugin#destroyed 79 */ 80 unregisterPlugin: function (plugin) { 81 var pluginName = hyphenate(functionName(plugin.$element.data('zfPlugin').constructor)); 82 83 this._uuids.splice(this._uuids.indexOf(plugin.uuid), 1); 84 plugin.$element.removeAttr('data-' + pluginName).removeData('zfPlugin') 85 /** 86 * Fires when the plugin has been destroyed. 87 * @event Plugin#destroyed 88 */ 89 .trigger('destroyed.zf.' + pluginName); 90 for (var prop in plugin) { 91 plugin[prop] = null; //clean up script to prep for garbage collection. 92 } 93 return; 94 }, 95 96 /** 97 * @function 98 * Causes one or more active plugins to re-initialize, resetting event listeners, recalculating positions, etc. 99 * @param {String} plugins - optional string of an individual plugin key, attained by calling `$(element).data('pluginName')`, or string of a plugin class i.e. `'dropdown'` 100 * @default If no argument is passed, reflow all currently active plugins. 101 */ 102 reInit: function (plugins) { 103 var isJQ = plugins instanceof $; 104 try { 105 if (isJQ) { 106 plugins.each(function () { 107 $(this).data('zfPlugin')._init(); 108 }); 109 } else { 110 var type = typeof plugins, 111 _this = this, 112 fns = { 113 'object': function (plgs) {
114 plgs.forEach(function (p) { 115 p = hyphenate(p); 116 $('[data-' + p + ']').foundation('_init'); 117 }); 118 }, 119 'string': function () { 120 plugins = hyphenate(plugins); 121 $('[data-' + plugins + ']').foundation('_init'); 122 }, 123 'undefined': function () { 124 this['object'](Object.keys(_this._plugins)); 125 } 126 }; 127 fns[type](plugins); 128 } 129 } catch (err) { 130 console.error(err); 131 } finally { 132 return plugins; 133 } 134 }, 135 136 /** 137 * returns a random base-36 uid with namespacing 138 * @function 139 * @param {Number} length - number of random base-36 digits desired. Increase for more random strings. 140 * @param {String} namespace - name of plugin to be incorporated in uid, optional. 141 * @default {String} '' - if no plugin name is provided, nothing is appended to the uid. 142 * @returns {String} - unique id 143 */ 144 GetYoDigits: function (length, namespace) { 145 length = length || 6; 146 return Math.round(Math.pow(36, length + 1) - Math.random() * Math.pow(36, length)).toString(36).slice(1) + (namespace ? '-' + namespace : ''); 147 }, 148 /** 149 * Initialize plugins on any elements within `elem` (and `elem` itself) that aren't already initialized. 150 * @param {Object} elem - jQuery object containing the element to check inside. Also checks the element itself, unless it's the `document` object. 151 * @param {String|Array} plugins - A list of plugins to initialize. Leave this out to initialize everything. 152 */ 153 reflow: function (elem, plugins) { 154 155 // If plugins is undefined, just grab everything 156 if (typeof plugins === 'undefined') { 157 plugins = Object.keys(this._plugins); 158 } 159 // If plugins is a string, convert it to an array with one item 160 else if (typeof plugins === 'string') { 161 plugins = [plugins]; 162 } 163 164 var _this = this; 165 166 // Iterate through each plugin 167 $.each(plugins, function (i, name) { 168 // Get the current plugin 169 var plugin = _this._plugins[name]; 170 171 // Localize the search to all elements inside elem, as well as elem itself, unless elem === document 172 var $elem = $(elem).find('[data-' + name + ']').addBack('[data-' + name + ']'); 173 174 // For each plugin found, initialize it 175 $elem.each(function () { 176 var $el = $(this), 177 opts = {}; 178 // Don't double-dip on plugins 179 if ($el.data('zfPlugin')) { 180 console.warn("Tried to initialize " + name + " on an element that already has a Foundation plugin."); 181 return; 182 } 183 184 if ($el.attr('data-options')) { 185 var thing = $el.attr('data-options').split(';').forEach(function (e, i) { 186 var opt = e.split(':').map(function (el) { 187 return el.trim(); 188 }); 189 if (opt[0]) opts[opt[0]] = parseValue(opt[1]); 190 }); 191 } 192 try { 193 $el.data('zfPlugin', new plugin($(this), opts)); 194 } catch (er) { 195 console.error(er); 196 } finally { 197 return; 198 } 199 }); 200 }); 201 }, 202 getFnName: functionName, 203 transitionend: function ($elem) { 204 var transitions = { 205 'transition': 'transitionend', 206 'WebkitTransition': 'webkitTransitionEnd', 207 'MozTransition': 'transitionend', 208 'OTransition': 'otransitionend' 209 }; 210 var elem = document.createElement('div'), 211 end; 212 213 for (var t in transitions) { 214 if (typeof elem.style[t] !== 'undefined') { 215 end = transitions[t]; 216 } 217 } 218 if (end) { 219 return end; 220 } else { 221 end = setTimeout(function () { 222 $elem.triggerHandler('transitionend', [$elem]); 223 }, 1); 224 return 'transitionend'; 225 } 226 } 227 }; 228 229 Foundation.util = { 230 /** 231 * Function for applying a debounce effect to a function call. 232 * @function 233 * @param {Function} func - Function to be called at end of timeout. 234 * @param {Number} delay - Time in ms to delay the call of `func`. 235 * @returns function 236 */ 237 throttle: function (func, delay) { 238 var timer = null; 239 240 return function () { 241 var context = this, 242 args = arguments; 243 244 if (timer === null) { 245 timer = setTimeout(function () {
246 func.apply(context, args); 247 timer = null; 248 }, delay); 249 } 250 }; 251 } 252 }; 253 254 // TODO: consider not making this a jQuery function 255 // TODO: need way to reflow vs. re-initialize 256 /** 257 * The Foundation jQuery method. 258 * @param {String|Array} method - An action to perform on the current jQuery object. 259 */ 260 var foundation = function (method) { 261 var type = typeof method, 262 $meta = $('meta.foundation-mq'), 263 $noJS = $('.no-js'); 264 265 if (!$meta.length) { 266 $('<meta class="foundation-mq">').appendTo(document.head); 267 } 268 if ($noJS.length) { 269 $noJS.removeClass('no-js'); 270 } 271 272 if (type === 'undefined') { 273 //needs to initialize the Foundation object, or an individual plugin. 274 Foundation.MediaQuery._init(); 275 Foundation.reflow(this); 276 } else if (type === 'string') { 277 //an individual method to invoke on a plugin or group of plugins 278 var args = Array.prototype.slice.call(arguments, 1); //collect all the arguments, if necessary 279 var plugClass = this.data('zfPlugin'); //determine the class of plugin 280 281 if (plugClass !== undefined && plugClass[method] !== undefined) { 282 //make sure both the class and method exist 283 if (this.length === 1) { 284 //if there's only one, call it directly. 285 plugClass[method].apply(plugClass, args); 286 } else { 287 this.each(function (i, el) { 288 //otherwise loop through the jQuery collection and invoke the method on each 289 plugClass[method].apply($(el).data('zfPlugin'), args); 290 }); 291 } 292 } else { 293 //error for no class or no method 294 throw new ReferenceError("We're sorry, '" + method + "' is not an available method for " + (plugClass ? functionName(plugClass) : 'this element') + '.'); 295 } 296 } else { 297 //error for invalid argument type 298 throw new TypeError('We\'re sorry, ' + type + ' is not a valid parameter. You must use a string representing the method you wish to invoke.'); 299 } 300 return this; 301 }; 302 303 window.Foundation = Foundation; 304 $.fn.foundation = foundation; 305 306 // Polyfill for requestAnimationFrame 307 (function () { 308 if (!Date.now || !window.Date.now) window.Date.now = Date.now = function () { 309 return new Date().getTime(); 310 }; 311 312 var vendors = ['webkit', 'moz']; 313 for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { 314 var vp = vendors[i]; 315 window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; 316 window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']; 317 } 318 if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { 319 var lastTime = 0; 320 window.requestAnimationFrame = function (callback) { 321 var now = Date.now(); 322 var nextTime = Math.max(lastTime + 16, now); 323 return setTimeout(function () { 324 callback(lastTime = nextTime); 325 }, nextTime - now); 326 }; 327 window.cancelAnimationFrame = clearTimeout; 328 } 329 /** 330 * Polyfill for performance.now, required by rAF 331 */ 332 if (!window.performance || !window.performance.now) { 333 window.performance = { 334 start: Date.now(), 335 now: function () { 336 return Date.now() - this.start; 337 } 338 }; 339 } 340 })(); 341 if (!Function.prototype.bind) { 342 Function.prototype.bind = function (oThis) { 343 if (typeof this !== 'function') { 344 // closest thing possible to the ECMAScript 5 345 // internal IsCallable function 346 throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); 347 } 348 349 var aArgs = Array.prototype.slice.call(arguments, 1), 350 fToBind = this, 351 fNOP = function () {}, 352 fBound = function () { 353 return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); 354 }; 355 356 if (this.prototype) { 357 // native functions don't have a prototype 358 fNOP.prototype = this.prototype; 359 } 360 fBound.prototype = new fNOP(); 361 362 return fBound; 363 }; 364 } 365 // Polyfill to get the name of a function in IE9 366 function functionName(fn) { 367 if (Function.prototype.name === undefined) { 368 var funcNameRegex = /function\s([^(]{1,})\(/; 369 var results = funcNameRegex.exec(fn.toString()); 370 return results && results.length > 1 ? results[1].trim() : ""; 371 } else if (fn.prototype === undefined) { 372 return fn.constructor.name; 373 } else { 374 return fn.prototype.constructor.name; 375 } 376 } 377 function parseValue(str) { 378 if (/true/.test(str)) return true;else if (/false/.test(str)) return false;else if (!isNaN(str * 1)) return parseFloat(str); 379 return str; 380 } 381 // Convert PascalCase to kebab-case 382 // Thank you: http://stackoverflow.com/a/8955580 383 function hyphenate(str) { 384 return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); 385 } 386}(jQuery); 387'use strict'; 388 389!function ($) { 390 391 // Default set of media queries 392 var defaultQueries = { 393 'default': 'only screen', 394 landscape: 'only screen and (orientation: landscape)', 395 portrait: 'only screen and (orientation: portrait)', 396 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)' 397 }; 398 399 var MediaQuery = { 400 queries: [], 401 402 current: '', 403 404 /** 405 * Initializes the media query helper, by extracting the breakpoint list from the CSS and activating the breakpoint watcher. 406 * @function 407 * @private 408 */ 409 _init: function () { 410 var self = this; 411 var extractedStyles = $('.foundation-mq').css('font-family'); 412 var namedQueries; 413 414 namedQueries = parseStyleToObject(extractedStyles); 415
416 for (var key in namedQueries) { 417 self.queries.push({ 418 name: key, 419 value: 'only screen and (min-width: ' + namedQueries[key] + ')' 420 }); 421 } 422 423 this.current = this._getCurrentSize(); 424 425 this._watcher(); 426 }, 427 428 429 /** 430 * Checks if the screen is at least as wide as a breakpoint. 431 * @function 432 * @param {String} size - Name of the breakpoint to check. 433 * @returns {Boolean} `true` if the breakpoint matches, `false` if it's smaller. 434 */ 435 atLeast: function (size) { 436 var query = this.get(size); 437 438 if (query) { 439 return window.matchMedia(query).matches; 440 } 441 442 return false; 443 }, 444 445 446 /** 447 * Gets the media query of a breakpoint. 448 * @function 449 * @param {String} size - Name of the breakpoint to get. 450 * @returns {String|null} - The media query of the breakpoint, or `null` if the breakpoint doesn't exist. 451 */ 452 get: function (size) { 453 for (var i in this.queries) { 454 var query = this.queries[i]; 455 if (size === query.name) return query.value; 456 } 457 458 return null; 459 }, 460 461 462 /** 463 * Gets the current breakpoint name by testing every breakpoint and returning the last one to match (the biggest one). 464 * @function 465 * @private 466 * @returns {String} Name of the current breakpoint. 467 */ 468 _getCurrentSize: function () { 469 var matched; 470 471 for (var i = 0; i < this.queries.length; i++) { 472 var query = this.queries[i]; 473 474 if (window.matchMedia(query.value).matches) { 475 matched = query; 476 } 477 } 478 479 if (typeof matched === 'object') { 480 return matched.name; 481 } else { 482 return matched; 483 } 484 }, 485 486 487 /** 488 * Activates the breakpoint watcher, which fires an event on the window whenever the breakpoint changes. 489 * @function 490 * @private 491 */ 492 _watcher: function () { 493 var _this = this; 494 495 $(window).on('resize.zf.mediaquery', function () { 496 var newSize = _this._getCurrentSize(); 497 498 if (newSize !== _this.current) { 499 // Broadcast the media query change on the window 500 $(window).trigger('changed.zf.mediaquery', [newSize, _this.current]); 501 502 // Change the current media query 503 _this.current = newSize; 504 } 505 }); 506 } 507 }; 508 509 Foundation.MediaQuery = MediaQuery; 510 511 // matchMedia() polyfill - Test a CSS media type/query in JS. 512 // Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license 513 window.matchMedia || (window.matchMedia = function () { 514 'use strict'; 515 516 // For browsers that support matchMedium api such as IE 9 and webkit 517 518 var styleMedia = window.styleMedia || window.media; 519 520 // For those that don't support matchMedium 521 if (!styleMedia) { 522 var style = document.createElement('style'), 523 script = document.getElementsByTagName('script')[0], 524 info = null; 525 526 style.type = 'text/css'; 527 style.id = 'matchmediajs-test'; 528 529 script.parentNode.insertBefore(style, script); 530 531 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers 532 info = 'getComputedStyle' in window && window.getComputedStyle(style, null) || style.currentStyle; 533 534 styleMedia = { 535 matchMedium: function (media) { 536 var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; 537 538 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers 539 if (style.styleSheet) { 540 style.styleSheet.cssText = text; 541 } else { 542 style.textContent = text; 543 } 544 545 // Test if media query is true or false 546 return info.width === '1px'; 547 } 548 }; 549 } 550 551 return function (media) { 552 return { 553 matches: styleMedia.matchMedium(media || 'all'), 554 media: media || 'all' 555 }; 556 }; 557 }()); 558 559 // Thank you: https://github.com/sindresorhus/query-string 560 function parseStyleToObject(str) { 561 var styleObject = {}; 562 563 if (typeof str !== 'string') { 564 return styleObject; 565 } 566 567 str = str.trim().slice(1, -1);
567 // browsers re-quote string style values 568 569 if (!str) { 570 return styleObject; 571 } 572 573 styleObject = str.split('&').reduce(function (ret, param) { 574 var parts = param.replace(/\+/g, ' ').split('='); 575 var key = parts[0]; 576 var val = parts[1]; 577 key = decodeURIComponent(key); 578 579 // missing `=` should be `null`: 580 // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters 581 val = val === undefined ? null : decodeURIComponent(val); 582 583 if (!ret.hasOwnProperty(key)) { 584 ret[key] = val; 585 } else if (Array.isArray(ret[key])) { 586 ret[key].push(val); 587 } else { 588 ret[key] = [ret[key], val]; 589 } 590 return ret; 591 }, {}); 592 593 return styleObject; 594 } 595 596 Foundation.MediaQuery = MediaQuery; 597}(jQuery); 598/******************************************* 599 * * 600 * This util was created by Marius Olbertz * 601 * Please thank Marius on GitHub /owlbertz * 602 * or the web http://www.mariusolbertz.de/ * 603 * * 604 ******************************************/ 605 606'use strict'; 607 608!function ($) { 609 610 var keyCodes = { 611 9: 'TAB', 612 13: 'ENTER', 613 27: 'ESCAPE', 614 32: 'SPACE', 615 37: 'ARROW_LEFT', 616 38: 'ARROW_UP', 617 39: 'ARROW_RIGHT', 618 40: 'ARROW_DOWN' 619 }; 620 621 var commands = {}; 622 623 var Keyboard = { 624 keys: getKeyCodes(keyCodes), 625 626 /** 627 * Parses the (keyboard) event and returns a String that represents its key 628 * Can be used like Foundation.parseKey(event) === Foundation.keys.SPACE 629 * @param {Event} event - the event generated by the event handler 630 * @return String key - String that represents the key pressed 631 */ 632 parseKey: function (event) { 633 var key = keyCodes[event.which || event.keyCode] || String.fromCharCode(event.which).toUpperCase(); 634 if (event.shiftKey) key = 'SHIFT_' + key; 635 if (event.ctrlKey) key = 'CTRL_' + key; 636 if (event.altKey) key = 'ALT_' + key; 637 return key; 638 }, 639 640 641 /** 642 * Handles the given (keyboard) event 643 * @param {Event} event - the event generated by the event handler 644 * @param {String} component - Foundation component's name, e.g. Slider or Reveal 645 * @param {Objects} functions - collection of functions that are to be executed 646 */ 647 handleKey: function (event, component, functions) { 648 var commandList = commands[component], 649 keyCode = this.parseKey(event), 650 cmds, 651 command, 652 fn; 653 654 if (!commandList) return console.warn('Component not defined!'); 655 656 if (typeof commandList.ltr === 'undefined') { 657 // this component does not differentiate between ltr and rtl 658 cmds = commandList; // use plain list 659 } else { 660 // merge ltr and rtl: if document is rtl, rtl overwrites ltr and vice versa 661 if (Foundation.rtl()) cmds = $.extend({}, commandList.ltr, commandList.rtl);else cmds = $.extend({}, commandList.rtl, commandList.ltr); 662 } 663 command = cmds[keyCode]; 664 665 fn = functions[command]; 666 if (fn && typeof fn === 'function') { 667 // execute function if exists 668 fn.apply(); 669 if (functions.handled || typeof functions.handled === 'function') { 670 // execute function when event was handled 671 functions.handled.apply(); 672 } 673 } else { 674 if (functions.unhandled || typeof functions.unhandled === 'function') { 675 // execute function when event was not handled 676 functions.unhandled.apply(); 677 } 678 } 679 }, 680 681 682 /** 683 * Finds all focusable elements within the given `$element` 684 * @param {jQuery} $element - jQuery object to search within 685 * @return {jQuery} $focusable - all focusable elements within `$element` 686 */ 687 findFocusable: function ($element) { 688 return $element.find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]').filter(function () { 689 if (!$(this).is(':visible') || $(this).attr('tabindex') < 0) { 690 return false;
691 } //only have visible elements and those that have a tabindex greater or equal 0 692 return true; 693 }); 694 }, 695 696 697 /** 698 * Returns the component name name 699 * @param {Object} component - Foundation component, e.g. Slider or Reveal 700 * @return String componentName 701 */ 702 703 register: function (componentName, cmds) { 704 commands[componentName] = cmds; 705 } 706 }; 707 708 /* 709 * Constants for easier comparing. 710 * Can be used like Foundation.parseKey(event) === Foundation.keys.SPACE 711 */ 712 function getKeyCodes(kcs) { 713 var k = {}; 714 for (var kc in kcs) { 715 k[kcs[kc]] = kcs[kc]; 716 }return k; 717 } 718 719 Foundation.Keyboard = Keyboard; 720}(jQuery); 721'use strict'; 722 723!function ($) { 724 725 /** 726 * Motion module. 727 * @module foundation.motion 728 */ 729 730 var initClasses = ['mui-enter', 'mui-leave']; 731 var activeClasses = ['mui-enter-active', 'mui-leave-active']; 732 733 var Motion = { 734 animateIn: function (element, animation, cb) { 735 animate(true, element, animation, cb); 736 }, 737 738 animateOut: function (element, animation, cb) { 739 animate(false, element, animation, cb); 740 } 741 }; 742 743 function Move(duration, elem, fn) { 744 var anim, 745 prog, 746 start = null; 747 // console.log('called'); 748 749 function move(ts) { 750 if (!start) start = window.performance.now(); 751 // console.log(start, ts); 752 prog = ts - start; 753 fn.apply(elem); 754 755 if (prog < duration) { 756 anim = window.requestAnimationFrame(move, elem); 757 } else { 758 window.cancelAnimationFrame(anim); 759 elem.trigger('finished.zf.animate', [elem]).triggerHandler('finished.zf.animate', [elem]); 760 } 761 } 762 anim = window.requestAnimationFrame(move); 763 } 764 765 /** 766 * Animates an element in or out using a CSS transition class. 767 * @function 768 * @private 769 * @param {Boolean} isIn - Defines if the animation is in or out. 770 * @param {Object} element - jQuery or HTML object to animate. 771 * @param {String} animation - CSS class to use. 772 * @param {Function} cb - Callback to run when animation is finished. 773 */ 774 function animate(isIn, element, animation, cb) { 775 element = $(element).eq(0); 776 777 if (!element.length) return; 778 779 var initClass = isIn ? initClasses[0] : initClasses[1]; 780 var activeClass = isIn ? activeClasses[0] : activeClasses[1]; 781 782 // Set up the animation 783 reset(); 784 785 element.addClass(animation).css('transition', 'none'); 786 787 requestAnimationFrame(function () { 788 element.addClass(initClass); 789 if (isIn) element.show(); 790 }); 791 792 // Start the animation 793 requestAnimationFrame(function () { 794 element[0].offsetWidth; 795 element.css('transition', '').addClass(activeClass); 796 }); 797 798 // Clean up the animation when it finishes 799 element.one(Foundation.transitionend(element), finish); 800 801 // Hides the element (for out animations), resets the element, and runs a callback 802 function finish() { 803 if (!isIn) element.hide(); 804 reset(); 805 if (cb) cb.apply(element); 806 } 807 808 // Resets transitions and removes motion-specific classes 809 function reset() { 810 element[0].style.transitionDuration = 0; 811 element.removeClass(initClass + ' ' + activeClass + ' ' + animation); 812 } 813 } 814 815 Foundation.Move = Move; 816 Foundation.Motion = Motion; 817}(jQuery); 818'use strict'; 819 820!function ($) { 821 822 var Nest = { 823 Feather: function (menu) { 824 var type = arguments.length <= 1 || arguments[1] === undefined ? 'zf' : arguments[1]; 825 826 menu.attr('role', 'menubar'); 827 828 var items = menu.find('li').attr({ 'role': 'menuitem' }), 829 subMenuClass = 'is-' + type + '-submenu', 830 subItemClass = subMenuClass + '-item', 831 hasSubClass = 'is-' + type + '-submenu-parent'; 832 833 menu.find('a:first').attr('tabindex', 0); 834 835 items.each(function () { 836 var $item = $(this), 837 $sub = $item.children('ul'); 838 839 if ($sub.length) { 840 $item.addClass(hasSubClass).attr({ 841 'aria-haspopup': true, 842 'aria-expanded': false, 843 'aria-label': $item.children('a:first').text() 844 }); 845 846 $sub.addClass('submenu ' + subMenuClass).attr({ 847 'data-submenu': '', 848 'aria-hidden': true, 849 'role': 'menu' 850 }); 851 } 852 853 if ($item.parent('[data-submenu]').length) { 854 $item.addClass('is-submenu-item ' + subItemClass); 855 } 856 }); 857 858 return; 859 }, 860 Burn: function (menu, type) { 861 var items = menu.find('li').removeAttr('tabindex'), 862 subMenuClass = 'is-' + type + '-submenu', 863 subItemClass = subMenuClass + '-item', 864 hasSubClass = 'is-' + type + '-submenu-parent'; 865 866 menu.find('*').removeClass(subMenuClass + ' ' + subItemClass + ' ' + hasSubClass + ' is-submenu-item submenu is-active').removeAttr('data-submenu').css('display', ''); 867 868 // console.log( menu.find('.' + subMenuClass + ', .' + subItemClass + ', .has-submenu, .is-submenu-item, .submenu, [data-submenu]') 869 // .removeClass(subMenuClass + ' ' + subItemClass + ' has-submenu is-submenu-item submenu') 870 // .removeAttr('data-submenu')); 871 // items.each(function(){ 872 // var $item = $(this), 873 // $sub = $item.children('ul'); 874 // if($item.parent('[data-submenu]').length){ 875 // $item.removeClass('is-submenu-item ' + subItemClass); 876 // } 877 // if($sub.length){ 878 // $item.removeClass('has-submenu'); 879 // $sub.removeClass('submenu ' + subMenuClass).removeAttr('data-submenu'); 880 // } 881 // }); 882 } 883 }; 884 885 Foundation.Nest = Nest; 886}(jQuery); 887'use strict'; 888 889!function ($) { 890 891 Foundation.Box = { 892 ImNotTouchingYou: ImNotTouchingYou, 893 GetDimensions: GetDimensions, 894 GetOffsets: GetOffsets 895 }; 896 897 /** 898 * Compares the dimensions of an element to a container and determines collision events with container. 899 * @function 900 * @param {jQuery} element - jQuery object to test for collisions. 901 * @param {jQuery}
901 parent - jQuery object to use as bounding container. 902 * @param {Boolean} lrOnly - set to true to check left and right values only. 903 * @param {Boolean} tbOnly - set to true to check top and bottom values only. 904 * @default if no parent object passed, detects collisions with `window`. 905 * @returns {Boolean} - true if collision free, false if a collision in any direction. 906 */ 907 function ImNotTouchingYou(element, parent, lrOnly, tbOnly) { 908 var eleDims = GetDimensions(element), 909 top, 910 bottom, 911 left, 912 right; 913 914 if (parent) { 915 var parDims = GetDimensions(parent); 916 917 bottom = eleDims.offset.top + eleDims.height <= parDims.height + parDims.offset.top; 918 top = eleDims.offset.top >= parDims.offset.top; 919 left = eleDims.offset.left >= parDims.offset.left; 920 right = eleDims.offset.left + eleDims.width <= parDims.width; 921 } else { 922 bottom = eleDims.offset.top + eleDims.height <= eleDims.windowDims.height + eleDims.windowDims.offset.top; 923 top = eleDims.offset.top >= eleDims.windowDims.offset.top; 924 left = eleDims.offset.left >= eleDims.windowDims.offset.left; 925 right = eleDims.offset.left + eleDims.width <= eleDims.windowDims.width; 926 } 927 928 var allDirs = [bottom, top, left, right]; 929 930 if (lrOnly) { 931 return left === right === true; 932 } 933 934 if (tbOnly) { 935 return top === bottom === true; 936 } 937 938 return allDirs.indexOf(false) === -1; 939 }; 940 941 /** 942 * Uses native methods to return an object of dimension values. 943 * @function 944 * @param {jQuery || HTML} element - jQuery object or DOM element for which to get the dimensions. Can be any element other that document or window. 945 * @returns {Object} - nested object of integer pixel values 946 * TODO - if element is window, return only those values. 947 */ 948 function GetDimensions(elem, test) { 949 elem = elem.length ? elem[0] : elem; 950 951 if (elem === window || elem === document) { 952 throw new Error("I'm sorry, Dave. I'm afraid I can't do that."); 953 } 954 955 var rect = elem.getBoundingClientRect(), 956 parRect = elem.parentNode.getBoundingClientRect(), 957 winRect = document.body.getBoundingClientRect(), 958 winY = window.pageYOffset, 959 winX = window.pageXOffset; 960 961 return { 962 width: rect.width, 963 height: rect.height, 964 offset: { 965 top: rect.top + winY, 966 left: rect.left + winX 967 }, 968 parentDims: { 969 width: parRect.width, 970 height: parRect.height, 971 offset: { 972 top: parRect.top + winY, 973 left: parRect.left + winX 974 } 975 }, 976 windowDims: { 977 width: winRect.width, 978 height: winRect.height, 979 offset: { 980 top: winY, 981 left: winX 982 } 983 } 984 }; 985 } 986 987 /** 988 * Returns an object of top and left integer pixel values for dynamically rendered elements, 989 * such as: Tooltip, Reveal, and Dropdown 990 * @function 991 * @param {jQuery} element - jQuery object for the element being positioned. 992 * @param {jQuery} anchor - jQuery object for the element's anchor point. 993 * @param {String} position - a string relating to the desired position of the element, relative to it's anchor 994 * @param {Number} vOffset - integer pixel value of desired vertical separation between anchor and element. 995 * @param {Number} hOffset - integer pixel value of desired horizontal separation between anchor and element. 996 * @param {Boolean} isOverflow - if a collision event is detected, sets to true to default the element to full width - any desired offset. 997 * TODO alter/rewrite to work with `em` values as well/instead of pixels 998 */ 999 function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) { 1000 var $eleDims = GetDimensions(element), 1001 $anchorDims = anchor ? GetDimensions(anchor) : null; 1002 1003 switch (position) { 1004 case 'top': 1005 return { 1006 left: Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left, 1007 top: $anchorDims.offset.top - ($eleDims.height + vOffset) 1008 }; 1009 break; 1010 case 'left': 1011 return { 1012 left: $anchorDims.offset.left - ($eleDims.width + hOffset), 1013 top: $anchorDims.offset.top 1014 }; 1015 break; 1016 case 'right': 1017 return { 1018 left: $anchorDims.offset.left + $anchorDims.width + hOffset, 1019 top: $anchorDims.offset.top 1020 }; 1021 break; 1022 case 'center top': 1023 return { 1024 left: $anchorDims.offset.left + $anchorDims.width / 2 - $eleDims.width / 2,
1025 top: $anchorDims.offset.top - ($eleDims.height + vOffset) 1026 }; 1027 break; 1028 case 'center bottom': 1029 return { 1030 left: isOverflow ? hOffset : $anchorDims.offset.left + $anchorDims.width / 2 - $eleDims.width / 2, 1031 top: $anchorDims.offset.top + $anchorDims.height + vOffset 1032 }; 1033 break; 1034 case 'center left': 1035 return { 1036 left: $anchorDims.offset.left - ($eleDims.width + hOffset), 1037 top: $anchorDims.offset.top + $anchorDims.height / 2 - $eleDims.height / 2 1038 }; 1039 break; 1040 case 'center right': 1041 return { 1042 left: $anchorDims.offset.left + $anchorDims.width + hOffset + 1, 1043 top: $anchorDims.offset.top + $anchorDims.height / 2 - $eleDims.height / 2 1044 }; 1045 break; 1046 case 'center': 1047 return { 1048 left: $eleDims.windowDims.offset.left + $eleDims.windowDims.width / 2 - $eleDims.width / 2, 1049 top: $eleDims.windowDims.offset.top + $eleDims.windowDims.height / 2 - $eleDims.height / 2 1050 }; 1051 break; 1052 case 'reveal': 1053 return { 1054 left: ($eleDims.windowDims.width - $eleDims.width) / 2, 1055 top: $eleDims.windowDims.offset.top + vOffset 1056 }; 1057 case 'reveal full': 1058 return { 1059 left: $eleDims.windowDims.offset.left, 1060 top: $eleDims.windowDims.offset.top 1061 }; 1062 break; 1063 case 'left bottom': 1064 return { 1065 left: $anchorDims.offset.left - ($eleDims.width + hOffset), 1066 top: $anchorDims.offset.top + $anchorDims.height 1067 }; 1068 break; 1069 case 'right bottom': 1070 return { 1071 left: $anchorDims.offset.left + $anchorDims.width + hOffset - $eleDims.width, 1072 top: $anchorDims.offset.top + $anchorDims.height 1073 }; 1074 break; 1075 default: 1076 return { 1077 left: Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left, 1078 top: $anchorDims.offset.top + $anchorDims.height + vOffset 1079 }; 1080 } 1081 } 1082}(jQuery); 1083'use strict'; 1084 1085!function ($) { 1086 1087 var MutationObserver = function () { 1088 var prefixes = ['WebKit', 'Moz', 'O', 'Ms', '']; 1089 for (var i = 0; i < prefixes.length; i++) { 1090 if (prefixes[i] + 'MutationObserver' in window) { 1091 return window[prefixes[i] + 'MutationObserver']; 1092 } 1093 } 1094 return false; 1095 }(); 1096 1097 var triggers = function (el, type) { 1098 el.data(type).split(' ').forEach(function (id) { 1099 $('#' + id)[type === 'close' ? 'trigger' : 'triggerHandler'](type + '.zf.trigger', [el]); 1100 }); 1101 }; 1102 // Elements with [data-open] will reveal a plugin that supports it when clicked. 1103 $(document).on('click.zf.trigger', '[data-open]', function () { 1104 triggers($(this), 'open'); 1105 }); 1106 1107 // Elements with [data-close] will close a plugin that supports it when clicked. 1108 // If used without a value on [data-close], the event will bubble, allowing it to close a parent component. 1109 $(document).on('click.zf.trigger', '[data-close]', function () { 1110 var id = $(this).data('close'); 1111 if (id) { 1112 triggers($(this), 'close'); 1113 } else { 1114 $(this).trigger('close.zf.trigger'); 1115 } 1116 }); 1117 1118 // Elements with [data-toggle] will toggle a plugin that supports it when clicked. 1119 $(document).on('click.zf.trigger', '[data-toggle]', function () { 1120 triggers($(this), 'toggle'); 1121 }); 1122 1123 // Elements with [data-closable] will respond to close.zf.trigger events. 1124 $(document).on('close.zf.trigger', '[data-closable]', function (e) { 1125 e.stopPropagation(); 1126 var animation = $(this).data('closable'); 1127 1128 if (animation !== '') { 1129 Foundation.Motion.animateOut($(this), animation, function () { 1130 $(this).trigger('closed.zf'); 1131 }); 1132 } else { 1133 $(this).fadeOut().trigger('closed.zf'); 1134 } 1135 }); 1136 1137 $(document).on('focus.zf.trigger blur.zf.trigger', '[data-toggle-focus]', function () { 1138 var id = $(this).data('toggle-focus'); 1139 $('#' + id).triggerHandler('toggle.zf.trigger', [$(this)]); 1140 }); 1141 1142 /** 1143 * Fires once after all other scripts have loaded 1144 * @function 1145 * @private 1146 */ 1147 $(window).load(function () { 1148 checkListeners(); 1149 }); 1150 1151 function checkListeners() { 1152 eventsListener(); 1153 resizeListener(); 1154 scrollListener(); 1155 closemeListener(); 1156 } 1157 1158 //******** only fires this function once on load, if there's something to watch ******** 1159 function closemeListener(pluginName) { 1160 var yetiBoxes = $('[data-yeti-box]'), 1161 plugNames = ['dropdown', 'tooltip', 'reveal']; 1162 1163 if (pluginName) { 1164 if (typeof pluginName === 'string') { 1165 plugNames.push(pluginName); 1166 } else if (typeof pluginName === 'object' && typeof pluginName[0] === 'string') { 1167 plugNames.concat(pluginName); 1168 } else { 1169 console.error('Plugin names must be strings'); 1170 } 1171 } 1172 if (yetiBoxes.length) { 1173 var listeners = plugNames.map(function (name) { 1174 return 'closeme.zf.' + name; 1175 }).join(' '); 1176 1177 $(window).off(listeners).on(listeners, function (e, pluginId) { 1178 var plugin = e.namespace.split('.')[0]; 1179 var plugins = $('[data-' + plugin + ']').not('[data-yeti-box="' + pluginId + '"]'); 1180 1181 plugins.each(function () { 1182 var _this = $(this); 1183 1184 _this.triggerHandler('close.zf.trigger', [_this]); 1185 }); 1186 }); 1187 } 1188 } 1189 1190 function resizeListener(debounce) { 1191 var timer = void 0, 1192 $nodes = $('[data-resize]'); 1193 if ($nodes.length) { 1194 $(window).off('resize.zf.trigger').on('resize.zf.trigger', function (e) { 1195 if (timer) { 1196 clearTimeout(timer); 1197 } 1198 1199 timer = setTimeout(function () { 1200 1201 if (!MutationObserver) { 1202 //fallback for IE 9 1203 $nodes.each(function () { 1204 $(this).triggerHandler('resizeme.zf.trigger'); 1205 }); 1206 } 1207 //trigger all listening elements and signal a resize event 1208 $nodes.attr('data-events', "resize"); 1209 }, debounce || 10); //default time to emit resize event 1210 }); 1211 } 1212 } 1213 1214 function scrollListener(debounce) { 1215 var timer = void 0, 1216 $nodes = $('[data-scroll]'); 1217 if ($nodes.length) { 1218 $(window).off('scroll.zf.trigger').on('scroll.zf.trigger', function (e) { 1219 if (timer) { 1220 clearTimeout(timer); 1221 } 1222 1223 timer = setTimeout(function () { 1224 1225 if (!MutationObserver) { 1226 //fallback for IE 9 1227 $nodes.each(function () { 1228 $(this).triggerHandler('scrollme.zf.trigger'); 1229 }); 1230 } 1231 //trigger all listening elements and signal a scroll event 1232 $nodes.attr('data-events', "scroll"); 1233 }, debounce || 10); //default time to emit scroll event 1234 }); 1235 } 1236 } 1237 1238 function eventsListener() { 1239 if (!MutationObserver) { 1240 return false;
1241 } 1242 var nodes = document.querySelectorAll('[data-resize], [data-scroll], [data-mutate]'); 1243 1244 //element callback 1245 var listeningElementsMutation = function (mutationRecordsList) { 1246 var $target = $(mutationRecordsList[0].target); 1247 //trigger the event handler for the element depending on type 1248 switch ($target.attr("data-events")) { 1249 1250 case "resize": 1251 $target.triggerHandler('resizeme.zf.trigger', [$target]); 1252 break; 1253 1254 case "scroll": 1255 $target.triggerHandler('scrollme.zf.trigger', [$target, window.pageYOffset]); 1256 break; 1257 1258 // case "mutate" : 1259 // console.log('mutate', $target); 1260 // $target.triggerHandler('mutate.zf.trigger'); 1261 // 1262 // //make sure we don't get stuck in an infinite loop from sloppy codeing 1263 // if ($target.index('[data-mutate]') == $("[data-mutate]").length-1) { 1264 // domMutationObserver(); 1265 // } 1266 // break; 1267 1268 default: 1269 return false; 1270 //nothing 1271 } 1272 }; 1273 1274 if (nodes.length) { 1275 //for each element that needs to listen for resizing, scrolling, (or coming soon mutation) add a single observer 1276 for (var i = 0; i <= nodes.length - 1; i++) { 1277 var elementObserver = new MutationObserver(listeningElementsMutation); 1278 elementObserver.observe(nodes[i], { attributes: true, childList: false, characterData: false, subtree: false, attributeFilter: ["data-events"] }); 1279 } 1280 } 1281 } 1282 1283 // ------------------------------------ 1284 1285 // [PH] 1286 // Foundation.CheckWatchers = checkWatchers; 1287 Foundation.IHearYou = checkListeners; 1288 // Foundation.ISeeYou = scrollListener; 1289 // Foundation.IFeelYou = closemeListener; 1290}(jQuery); 1291 1292// function domMutationObserver(debounce) { 1293// // !!! This is coming soon and needs more work; not active !!! // 1294// var timer, 1295// nodes = document.querySelectorAll('[data-mutate]'); 1296// // 1297// if (nodes.length) { 1298// // var MutationObserver = (function () { 1299// // var prefixes = ['WebKit', 'Moz', 'O', 'Ms', '']; 1300// // for (var i=0; i < prefixes.length; i++) { 1301// // if (prefixes[i] + 'MutationObserver' in window) { 1302// // return window[prefixes[i] + 'MutationObserver']; 1303// // } 1304// // } 1305// // return false; 1306// // }()); 1307// 1308// 1309// //for the body, we need to listen for all changes effecting the style and class attributes 1310// var bodyObserver = new MutationObserver(bodyMutation); 1311// bodyObserver.observe(document.body, { attributes: true, childList: true, characterData: false, subtree:true, attributeFilter:["style", "class"]}); 1312// 1313// 1314// //body callback 1315// function bodyMutation(mutate) { 1316// //trigger all listening elements and signal a mutation event 1317// if (timer) { clearTimeout(timer); } 1318// 1319// timer = setTimeout(function() { 1320// bodyObserver.disconnect(); 1321// $('[data-mutate]').attr('data-events',"mutate"); 1322// }, debounce || 150); 1323// } 1324// } 1325// } 1326'use strict'; 1327 1328var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 1329 1330function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1331 1332!function ($) { 1333 1334 /** 1335 * Drilldown module. 1336 * @module foundation.drilldown 1337 * @requires foundation.util.keyboard 1338 * @requires foundation.util.motion 1339 * @requires foundation.util.nest 1340 */ 1341 1342 var Drilldown = function () { 1343 /** 1344 * Creates a new instance of a drilldown menu. 1345 * @class 1346 * @param {jQuery} element - jQuery object to make into an accordion menu. 1347 * @param {Object} options - Overrides to the default plugin settings. 1348 */ 1349 1350 function Drilldown(element, options) { 1351 _classCallCheck(this, Drilldown); 1352 1353 this.$element = element; 1354 this.options = $.extend({}, Drilldown.defaults, this.$element.data(), options); 1355 1356 Foundation.Nest.Feather(this.$element, 'drilldown'); 1357 1358 this._init(); 1359 1360 Foundation.registerPlugin(this, 'Drilldown'); 1361 Foundation.Keyboard.register('Drilldown', { 1362 'ENTER': 'open', 1363 'SPACE': 'open',
1364 'ARROW_RIGHT': 'next', 1365 'ARROW_UP': 'up', 1366 'ARROW_DOWN': 'down', 1367 'ARROW_LEFT': 'previous', 1368 'ESCAPE': 'close', 1369 'TAB': 'down', 1370 'SHIFT_TAB': 'up' 1371 }); 1372 } 1373 1374 /** 1375 * Initializes the drilldown by creating jQuery collections of elements 1376 * @private 1377 */ 1378 1379 1380 _createClass(Drilldown, [{ 1381 key: '_init', 1382 value: function _init() { 1383 this.$submenuAnchors = this.$element.find('li.is-drilldown-submenu-parent').children('a'); 1384 this.$submenus = this.$submenuAnchors.parent('li').children('[data-submenu]'); 1385 this.$menuItems = this.$element.find('li').not('.js-drilldown-back').attr('role', 'menuitem').find('a'); 1386 1387 this._prepareMenu(); 1388 1389 this._keyboardEvents(); 1390 } 1391 1392 /** 1393 * prepares drilldown menu by setting attributes to links and elements 1394 * sets a min height to prevent content jumping 1395 * wraps the element if not already wrapped 1396 * @private 1397 * @function 1398 */ 1399 1400 }, { 1401 key: '_prepareMenu', 1402 value: function _prepareMenu() { 1403 var _this = this; 1404 // if(!this.options.holdOpen){ 1405 // this._menuLinkEvents(); 1406 // } 1407 this.$submenuAnchors.each(function () { 1408 var $sub = $(this); 1409 var $link = $sub.find('a:first'); 1410 if (_this.options.parentLink) { 1411 $link.clone().prependTo($sub.children('[data-submenu]')).wrap('<li class="is-submenu-parent-item is-submenu-item is-drilldown-submenu-item" role="menu-item"></li>'); 1412 } 1413 $link.data('savedHref', $link.attr('href')).removeAttr('href'); 1414 $sub.children('[data-submenu]').attr({ 1415 'aria-hidden': true, 1416 'tabindex': 0, 1417 'role': 'menu' 1418 }); 1419 _this._events($sub); 1420 }); 1421 this.$submenus.each(function () { 1422 var $menu = $(this), 1423 $back = $menu.find('.js-drilldown-back'); 1424 if (!$back.length) { 1425 $menu.prepend(_this.options.backButton); 1426 } 1427 _this._back($menu); 1428 }); 1429 if (!this.$element.parent().hasClass('is-drilldown')) { 1430 this.$wrapper = $(this.options.wrapper).addClass('is-drilldown').css(this._getMaxDims()); 1431 this.$element.wrap(this.$wrapper); 1432 } 1433 } 1434 1435 /** 1436 * Adds event handlers to elements in the menu. 1437 * @function 1438 * @private 1439 * @param {jQuery} $elem - the current menu item to add handlers to. 1440 */ 1441 1442 }, { 1443 key: '_events', 1444 value: function _events($elem) { 1445 var _this = this; 1446 1447 $elem.off('click.zf.drilldown').on('click.zf.drilldown', function (e) { 1448 if ($(e.target).parentsUntil('ul', 'li').hasClass('is-drilldown-submenu-parent')) { 1449 e.stopImmediatePropagation(); 1450 e.preventDefault(); 1451 } 1452 1453 // if(e.target !== e.currentTarget.firstElementChild){ 1454 // return false; 1455 // } 1456 _this._show($elem.parent('li')); 1457 1458 if (_this.options.closeOnClick) { 1459 var $body = $('body').not(_this.$wrapper); 1460 $body.off('.zf.drilldown').on('click.zf.drilldown', function (e) { 1461 e.preventDefault(); 1462 _this._hideAll(); 1463 $body.off('.zf.drilldown'); 1464 }); 1465 } 1466 }); 1467 } 1468 1469 /** 1470 * Adds keydown event listener to `li`'s in the menu. 1471 * @private 1472 */ 1473 1474 }, { 1475 key: '_keyboardEvents', 1476 value: function _keyboardEvents() { 1477 var _this = this; 1478 1479 this.$menuItems.add(this.$element.find('.js-drilldown-back > a')).on('keydown.zf.drilldown', function (e) { 1480 1481 var $element = $(this), 1482 $elements = $element.parent('li').parent('ul').children('li').children('a'), 1483 $prevElement, 1484 $nextElement; 1485 1486 $elements.each(function (i) { 1487 if ($(this).is($element)) { 1488 $prevElement = $elements.eq(Math.max(0, i - 1)); 1489 $nextElement = $elements.eq(Math.min(i + 1, $elements.length - 1)); 1490 return; 1491 } 1492 }); 1493 1494 Foundation.Keyboard.handleKey(e, 'Drilldown', { 1495 next: function () { 1496 if ($element.is(_this.$submenuAnchors)) { 1497 _this._show($element.parent('li')); 1498 $element.parent('li').one(Foundation.transitionend($element), function () { 1499 $element.parent('li').find('ul li a').filter(_this.$menuItems).first().focus(); 1500 }); 1501 e.preventDefault(); 1502 } 1503 }, 1504 previous: function () { 1505 _this._hide($element.parent('li').parent('ul')); 1506 $element.parent('li').parent('ul').one(Foundation.transitionend($element), function () { 1507 setTimeout(function () { 1508 $element.parent('li').parent('ul').parent('li').children('a').first().focus(); 1509 }, 1); 1510 }); 1511 e.preventDefault(); 1512 }, 1513 up: function () { 1514 $prevElement.focus(); 1515 e.preventDefault(); 1516 }, 1517 down: function () { 1518 $nextElement.focus(); 1519 e.preventDefault(); 1520 }, 1521 close: function () { 1522 _this._back(); 1523 //_this.$menuItems.first().focus(); // focus to first element 1524 }, 1525 open: function () { 1526 if (!$element.is(_this.$menuItems)) { 1527 // not menu item means back button 1528 _this._hide($element.parent('li').parent('ul')); 1529 $element.parent('li').parent('ul').one(Foundation.transitionend($element), function () { 1530 setTimeout(function () { 1531 $element.parent('li').parent('ul').parent('li').children('a').first().focus(); 1532 }, 1); 1533 }); 1534 e.preventDefault(); 1535 } else if ($element.is(_this.$submenuAnchors)) { 1536 _this._show($element.parent('li')); 1537 $element.parent('li').one(Foundation.transitionend($element), function () { 1538 $element.parent('li').find('ul li a').filter(_this.$menuItems).first().focus(); 1539 }); 1540 e.preventDefault(); 1541 } 1542 }, 1543 handled: function () { 1544 e.stopImmediatePropagation(); 1545 } 1546 }); 1547 }); // end keyboardAccess 1548 } 1549 1550 /** 1551 * Closes all open elements, and returns to root menu. 1552 * @function 1553 * @fires Drilldown#closed 1554 */ 1555 1556 }, {
1557 key: '_hideAll', 1558 value: function _hideAll() { 1559 var $elem = this.$element.find('.is-drilldown-submenu.is-active').addClass('is-closing'); 1560 $elem.one(Foundation.transitionend($elem), function (e) { 1561 $elem.removeClass('is-active is-closing'); 1562 }); 1563 /** 1564 * Fires when the menu is fully closed. 1565 * @event Drilldown#closed 1566 */ 1567 this.$element.trigger('closed.zf.drilldown'); 1568 } 1569 1570 /** 1571 * Adds event listener for each `back` button, and closes open menus. 1572 * @function 1573 * @fires Drilldown#back 1574 * @param {jQuery} $elem - the current sub-menu to add `back` event. 1575 */ 1576 1577 }, { 1578 key: '_back', 1579 value: function _back($elem) { 1580 var _this = this; 1581 $elem.off('click.zf.drilldown'); 1582 $elem.children('.js-drilldown-back').on('click.zf.drilldown', function (e) { 1583 e.stopImmediatePropagation(); 1584 // console.log('mouseup on back'); 1585 _this._hide($elem); 1586 }); 1587 } 1588 1589 /** 1590 * Adds event listener to menu items w/o submenus to close open menus on click. 1591 * @function 1592 * @private 1593 */ 1594 1595 }, { 1596 key: '_menuLinkEvents', 1597 value: function _menuLinkEvents() { 1598 var _this = this; 1599 this.$menuItems.not('.is-drilldown-submenu-parent').off('click.zf.drilldown').on('click.zf.drilldown', function (e) { 1600 // e.stopImmediatePropagation(); 1601 setTimeout(function () { 1602 _this._hideAll(); 1603 }, 0); 1604 }); 1605 } 1606 1607 /** 1608 * Opens a submenu. 1609 * @function 1610 * @fires Drilldown#open 1611 * @param {jQuery} $elem - the current element with a submenu to open, i.e. the `li` tag. 1612 */ 1613 1614 }, { 1615 key: '_show', 1616 value: function _show($elem) { 1617 $elem.children('[data-submenu]').addClass('is-active'); 1618 1619 this.$element.trigger('open.zf.drilldown', [$elem]); 1620 } 1621 }, { 1622 key: '_hide', 1623 1624 1625 /** 1626 * Hides a submenu 1627 * @function 1628 * @fires Drilldown#hide 1629 * @param {jQuery} $elem - the current sub-menu to hide, i.e. the `ul` tag. 1630 */ 1631 value: function _hide($elem) { 1632 var _this = this; 1633 $elem.addClass('is-closing').one(Foundation.transitionend($elem), function () { 1634 $elem.removeClass('is-active is-closing'); 1635 $elem.blur(); 1636 }); 1637 /** 1638 * Fires when the submenu is has closed. 1639 * @event Drilldown#hide 1640 */ 1641 $elem.trigger('hide.zf.drilldown', [$elem]); 1642 } 1643 1644 /** 1645 * Iterates through the nested menus to calculate the min-height, and max-width for the menu. 1646 * Prevents content jumping. 1647 * @function 1648 * @private 1649 */ 1650 1651 }, { 1652 key: '_getMaxDims', 1653 value: function _getMaxDims() { 1654 var max = 0, 1655 result = {}; 1656 this.$submenus.add(this.$element).each(function () { 1657 var numOfElems = $(this).children('li').length; 1658 max = numOfElems > max ? numOfElems : max; 1659 }); 1660 1661 result['min-height'] = max * this.$menuItems[0].getBoundingClientRect().height + 'px'; 1662 result['max-width'] = this.$element[0].getBoundingClientRect().width + 'px'; 1663 1664 return result; 1665 } 1666 1667 /** 1668 * Destroys the Drilldown Menu 1669 * @function 1670 */ 1671 1672 }, { 1673 key: 'destroy', 1674 value: function destroy() { 1675 this._hideAll(); 1676 Foundation.Nest.Burn(this.$element, 'drilldown'); 1677 this.$element.unwrap().find('.js-drilldown-back, .is-submenu-parent-item').remove().end().find('.is-active, .is-closing, .is-drilldown-submenu').removeClass('is-active is-closing is-drilldown-submenu').end().find('[data-submenu]').removeAttr('aria-hidden tabindex role').off('.zf.drilldown').end().off('zf.drilldown'); 1678 this.$element.find('a').each(function () { 1679 var $link = $(this); 1680 if ($link.data('savedHref')) { 1681 $link.attr('href', $link.data('savedHref')).removeData('savedHref'); 1682 } else { 1683 return; 1684 } 1685 }); 1686 Foundation.unregisterPlugin(this); 1687 } 1688 }]); 1689 1690 return Drilldown; 1691 }(); 1692 1693 Drilldown.defaults = { 1694 /** 1695 * Markup used for JS generated back button. Prepended to submenu lists and deleted on `destroy` method, 'js-drilldown-back' class required. Remove the backslash (`\`) if copy and pasting. 1696 * @option 1697 * @example '<\li><\a>Back<\/a><\/li>' 1698 */ 1699 backButton: '<li class="js-drilldown-back"><a tabindex="0">Back</a></li>', 1700 /** 1701 * Markup used to wrap drilldown menu. Use a class name for independent styling; the JS applied class: `is-drilldown` is required. Remove the backslash (`\`) if copy and pasting. 1702 * @option 1703 * @example '<\div class="is-drilldown"><\/div>' 1704 */ 1705 wrapper: '<div></div>', 1706 /** 1707 * Adds the parent link to the submenu. 1708 * @option 1709 * @example false 1710 */ 1711 parentLink: false, 1712 /** 1713 * Allow the menu to return to root list on body click. 1714 * @option 1715 * @example false 1716 */ 1717 closeOnClick: false 1718 // holdOpen: false 1719 }; 1720 1721 // Window exports 1722 Foundation.plugin(Drilldown, 'Drilldown'); 1723}(jQuery); 1724'use strict'; 1725 1726var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 1727 1728function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1729 1730!function ($) { 1731 1732 /** 1733 * DropdownMenu module. 1734 * @module foundation.dropdown-menu 1735 * @requires foundation.util.keyboard 1736 * @requires foundation.util.box 1737 * @requires foundation.util.nest 1738 */ 1739 1740 var DropdownMenu = function () { 1741 /** 1742 * Creates a new instance of DropdownMenu. 1743 * @class 1744 * @fires DropdownMenu#init 1745 * @param {jQuery} element - jQuery object to make into a dropdown menu. 1746 * @param {Object} options - Overrides to the default plugin settings. 1747 */ 1748 1749 function DropdownMenu(element, options) { 1750 _classCallCheck(this, DropdownMenu); 1751 1752 this.$element = element; 1753 this.options = $.extend({}, DropdownMenu.defaults, this.$element.data(), options); 1754 1755 Foundation.Nest.Feather(this.$element, 'dropdown'); 1756 this._init(); 1757 1758 Foundation.registerPlugin(this, 'DropdownMenu'); 1759 Foundation.Keyboard.register('DropdownMenu', { 1760 'ENTER': 'open', 1761 'SPACE': 'open',
1762 'ARROW_RIGHT': 'next', 1763 'ARROW_UP': 'up', 1764 'ARROW_DOWN': 'down', 1765 'ARROW_LEFT': 'previous', 1766 'ESCAPE': 'close' 1767 }); 1768 } 1769 1770 /** 1771 * Initializes the plugin, and calls _prepareMenu 1772 * @private 1773 * @function 1774 */ 1775 1776 1777 _createClass(DropdownMenu, [{ 1778 key: '_init', 1779 value: function _init() { 1780 var subs = this.$element.find('li.is-dropdown-submenu-parent'); 1781 this.$element.children('.is-dropdown-submenu-parent').children('.is-dropdown-submenu').addClass('first-sub'); 1782 1783 this.$menuItems = this.$element.find('[role="menuitem"]'); 1784 this.$tabs = this.$element.children('[role="menuitem"]'); 1785 this.$tabs.find('ul.is-dropdown-submenu').addClass(this.options.verticalClass); 1786 1787 if (this.$element.hasClass(this.options.rightClass) || this.options.alignment === 'right' || Foundation.rtl() || this.$element.parents('.top-bar-right').is('*')) { 1788 this.options.alignment = 'right'; 1789 subs.addClass('opens-left'); 1790 } else { 1791 subs.addClass('opens-right'); 1792 } 1793 this.changed = false; 1794 this._events(); 1795 } 1796 }, { 1797 key: '_events', 1798 1799 /** 1800 * Adds event listeners to elements within the menu 1801 * @private 1802 * @function 1803 */ 1804 value: function _events() { 1805 var _this = this, 1806 hasTouch = 'ontouchstart' in window || typeof window.ontouchstart !== 'undefined', 1807 parClass = 'is-dropdown-submenu-parent'; 1808 1809 if (this.options.clickOpen || hasTouch) { 1810 this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', function (e) { 1811 var $elem = $(e.target).parentsUntil('ul', '.' + parClass), 1812 hasSub = $elem.hasClass(parClass), 1813 hasClicked = $elem.attr('data-is-click') === 'true', 1814 $sub = $elem.children('.is-dropdown-submenu'); 1815 1816 if (hasSub) { 1817 if (hasClicked) { 1818 if (!_this.options.closeOnClick || !_this.options.clickOpen && !hasTouch || _this.options.forceFollow && hasTouch) { 1819 return; 1820 } else { 1821 e.stopImmediatePropagation(); 1822 e.preventDefault(); 1823 _this._hide($elem); 1824 } 1825 } else { 1826 e.preventDefault(); 1827 e.stopImmediatePropagation(); 1828 _this._show($elem.children('.is-dropdown-submenu')); 1829 $elem.add($elem.parentsUntil(_this.$element, '.' + parClass)).attr('data-is-click', true); 1830 } 1831 } else { 1832 return; 1833 } 1834 }); 1835 } 1836 1837 if (!this.options.disableHover) { 1838 this.$menuItems.on('mouseenter.zf.dropdownmenu', function (e) { 1839 e.stopImmediatePropagation(); 1840 var $elem = $(this), 1841 hasSub = $elem.hasClass(parClass); 1842 1843 if (hasSub) { 1844 clearTimeout(_this.delay); 1845 _this.delay = setTimeout(function () { 1846 _this._show($elem.children('.is-dropdown-submenu')); 1847 }, _this.options.hoverDelay); 1848 } 1849 }).on('mouseleave.zf.dropdownmenu', function (e) { 1850 var $elem = $(this), 1851 hasSub = $elem.hasClass(parClass); 1852 if (hasSub && _this.options.autoclose) { 1853 if ($elem.attr('data-is-click') === 'true' && _this.options.clickOpen) { 1854 return false; 1855 } 1856 1857 clearTimeout(_this.delay); 1858 _this.delay = setTimeout(function () { 1859 _this._hide($elem); 1860 }, _this.options.closingTime); 1861 } 1862 }); 1863 } 1864 this.$menuItems.on('keydown.zf.dropdownmenu', function (e) { 1865 var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'), 1866 isTab = _this.$tabs.index($element) > -1, 1867 $elements = isTab ? _this.$tabs : $element.siblings('li').add($element), 1868 $prevElement, 1869 $nextElement; 1870 1871 $elements.each(function (i) { 1872 if ($(this).is($element)) { 1873 $prevElement = $elements.eq(i - 1); 1874 $nextElement = $elements.eq(i + 1); 1875 return; 1876 } 1877 }); 1878 1879 var nextSibling = function () { 1880 if (!$element.is(':last-child')) $nextElement.children('a:first').focus(); 1881 }, 1882 prevSibling = function () { 1883 $prevElement.children('a:first').focus(); 1884 }, 1885 openSub = function () {
1886 var $sub = $element.children('ul.is-dropdown-submenu'); 1887 if ($sub.length) { 1888 _this._show($sub); 1889 $element.find('li > a:first').focus(); 1890 } else { 1891 return; 1892 } 1893 }, 1894 closeSub = function () { 1895 //if ($element.is(':first-child')) { 1896 var close = $element.parent('ul').parent('li'); 1897 close.children('a:first').focus(); 1898 _this._hide(close); 1899 //} 1900 }; 1901 var functions = { 1902 open: openSub, 1903 close: function () { 1904 _this._hide(_this.$element); 1905 _this.$menuItems.find('a:first').focus(); // focus to first element 1906 }, 1907 handled: function () { 1908 e.preventDefault(); 1909 e.stopImmediatePropagation(); 1910 } 1911 }; 1912 1913 if (isTab) { 1914 if (_this.vertical) { 1915 // vertical menu 1916 if (_this.options.alignment === 'left') { 1917 // left aligned 1918 $.extend(functions, { 1919 down: nextSibling, 1920 up: prevSibling, 1921 next: openSub, 1922 previous: closeSub 1923 }); 1924 } else { 1925 // right aligned 1926 $.extend(functions, { 1927 down: nextSibling, 1928 up: prevSibling, 1929 next: closeSub, 1930 previous: openSub 1931 }); 1932 } 1933 } else { 1934 // horizontal menu 1935 $.extend(functions, { 1936 next: nextSibling, 1937 previous: prevSibling, 1938 down: openSub, 1939 up: closeSub 1940 }); 1941 } 1942 } else { 1943 // not tabs -> one sub 1944 if (_this.options.alignment === 'left') { 1945 // left aligned 1946 $.extend(functions, { 1947 next: openSub, 1948 previous: closeSub, 1949 down: nextSibling, 1950 up: prevSibling 1951 }); 1952 } else { 1953 // right aligned 1954 $.extend(functions, { 1955 next: closeSub, 1956 previous: openSub, 1957 down: nextSibling, 1958 up: prevSibling 1959 }); 1960 } 1961 } 1962 Foundation.Keyboard.handleKey(e, 'DropdownMenu', functions); 1963 }); 1964 } 1965 1966 /** 1967 * Adds an event handler to the body to close any dropdowns on a click. 1968 * @function 1969 * @private 1970 */ 1971 1972 }, { 1973 key: '_addBodyHandler', 1974 value: function _addBodyHandler() { 1975 var $body = $(document.body), 1976 _this = this; 1977 $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu').on('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu', function (e) { 1978 var $link = _this.$element.find(e.target); 1979 if ($link.length) { 1980 return; 1981 } 1982 1983 _this._hide(); 1984 $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu'); 1985 }); 1986 } 1987 1988 /** 1989 * Opens a dropdown pane, and checks for collisions first. 1990 * @param {jQuery} $sub - ul element that is a submenu to show 1991 * @function 1992 * @private 1993 * @fires DropdownMenu#show 1994 */ 1995 1996 }, { 1997 key: '_show', 1998 value: function _show($sub) { 1999 var idx = this.$tabs.index(this.$tabs.filter(function (i, el) { 2000 return $(el).find($sub).length > 0; 2001 })); 2002 var $sibs = $sub.parent('li.is-dropdown-submenu-parent').siblings('li.is-dropdown-submenu-parent'); 2003 this._hide($sibs, idx); 2004 $sub.css('visibility', 'hidden').addClass('js-dropdown-active').attr({ 'aria-hidden': false }).parent('li.is-dropdown-submenu-parent').addClass('is-active').attr({ 'aria-expanded': true }); 2005 var clear = Foundation.Box.ImNotTouchingYou($sub, null, true); 2006 if (!clear) { 2007 var oldClass = this.options.alignment === 'left' ? '-right' : '-left', 2008 $parentLi = $sub.parent('.is-dropdown-submenu-parent'); 2009 $parentLi.removeClass('opens' + oldClass).addClass('opens-' + this.options.alignment); 2010 clear = Foundation.Box.ImNotTouchingYou($sub, null, true); 2011 if (!clear) { 2012 $parentLi.removeClass('opens-' + this.options.alignment).addClass('opens-inner'); 2013 } 2014 this.changed = true; 2015 } 2016 $sub.css('visibility', ''); 2017 if (this.options.closeOnClick) { 2018 this._addBodyHandler(); 2019 } 2020 /** 2021 * Fires when the new dropdown pane is visible. 2022 * @event DropdownMenu#show 2023 */ 2024 this.$element.trigger('show.zf.dropdownmenu', [$sub]); 2025 } 2026 2027 /** 2028 * Hides a single, currently open dropdown pane, if passed a parameter, otherwise, hides everything. 2029 * @function 2030 * @param {jQuery} $elem - element with a submenu to hide 2031 * @param {Number} idx - index of the $tabs collection to hide 2032 * @private 2033 */ 2034 2035 }, {
2036 key: '_hide', 2037 value: function _hide($elem, idx) { 2038 var $toClose; 2039 if ($elem && $elem.length) { 2040 $toClose = $elem; 2041 } else if (idx !== undefined) { 2042 $toClose = this.$tabs.not(function (i, el) { 2043 return i === idx; 2044 }); 2045 } else { 2046 $toClose = this.$element; 2047 } 2048 var somethingToClose = $toClose.hasClass('is-active') || $toClose.find('.is-active').length > 0; 2049 2050 if (somethingToClose) { 2051 $toClose.find('li.is-active').add($toClose).attr({ 2052 'aria-expanded': false, 2053 'data-is-click': false 2054 }).removeClass('is-active'); 2055 2056 $toClose.find('ul.js-dropdown-active').attr({ 2057 'aria-hidden': true 2058 }).removeClass('js-dropdown-active'); 2059 2060 if (this.changed || $toClose.find('opens-inner').length) { 2061 var oldClass = this.options.alignment === 'left' ? 'right' : 'left'; 2062 $toClose.find('li.is-dropdown-submenu-parent').add($toClose).removeClass('opens-inner opens-' + this.options.alignment).addClass('opens-' + oldClass); 2063 this.changed = false; 2064 } 2065 /** 2066 * Fires when the open menus are closed. 2067 * @event DropdownMenu#hide 2068 */ 2069 2070 // TODO: this is a hack. 2071 // There is a bigger issue in that the correct trigger doees not work 2072 // correctly, and it is unclear as to why. 2073 // this.$element.trigger('hide.zf.dropdownmenu', [$toClose]); 2074 this.$element.trigger('notifications.hide', [$toClose]); 2075 } 2076 } 2077 2078 /** 2079 * Destroys the plugin. 2080 * @function 2081 */ 2082 2083 }, { 2084 key: 'destroy', 2085 value: function destroy() { 2086 this.$menuItems.off('.zf.dropdownmenu').removeAttr('data-is-click').removeClass('is-right-arrow is-left-arrow is-down-arrow opens-right opens-left opens-inner'); 2087 $(document.body).off('.zf.dropdownmenu'); 2088 Foundation.Nest.Burn(this.$element, 'dropdown'); 2089 Foundation.unregisterPlugin(this); 2090 } 2091 }]); 2092 2093 return DropdownMenu; 2094 }(); 2095 2096 /** 2097 * Default settings for plugin 2098 */ 2099 2100 2101 DropdownMenu.defaults = { 2102 /** 2103 * Disallows hover events from opening submenus 2104 * @option 2105 * @example false 2106 */ 2107 disableHover: false, 2108 /** 2109 * Allow a submenu to automatically close on a mouseleave event, if not clicked open. 2110 * @option 2111 * @example true 2112 */ 2113 autoclose: true, 2114 /** 2115 * Amount of time to delay opening a submenu on hover event. 2116 * @option 2117 * @example 50 2118 */ 2119 hoverDelay: 50, 2120 /** 2121 * Allow a submenu to open/remain open on parent click event. Allows cursor to move away from menu. 2122 * @option 2123 * @example true 2124 */ 2125 clickOpen: false, 2126 /** 2127 * Amount of time to delay closing a submenu on a mouseleave event. 2128 * @option 2129 * @example 500 2130 */ 2131 2132 closingTime: 500, 2133 /** 2134 * Position of the menu relative to what direction the submenus should open. Handled by JS. 2135 * @option 2136 * @example 'left' 2137 */ 2138 alignment: 'left', 2139 /** 2140 * Allow clicks on the body to close any open submenus. 2141 * @option 2142 * @example true 2143 */ 2144 closeOnClick: true, 2145 /** 2146 * Class applied to vertical oriented menus, Foundation default is `vertical`. Update this if using your own class. 2147 * @option 2148 * @example 'vertical' 2149 */ 2150 verticalClass: 'vertical', 2151 /** 2152 * Class applied to right-side oriented menus, Foundation default is `align-right`. Update this if using your own class. 2153 * @option 2154 * @example 'align-right' 2155 */ 2156 rightClass: 'align-right', 2157 /** 2158 * Boolean to force overide the clicking of links to perform default action, on second touch event for mobile. 2159 * @option 2160 * @example false 2161 */ 2162 forceFollow: true 2163 }; 2164 2165 // Window exports 2166 Foundation.plugin(DropdownMenu, 'DropdownMenu'); 2167}(jQuery); 2168'use strict'; 2169 2170var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 2171 2172function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 2173 2174!function ($) { 2175 2176 /** 2177 * ResponsiveMenu module. 2178 * @module foundation.responsiveMenu 2179 * @requires foundation.util.triggers 2180 * @requires foundation.util.mediaQuery 2181 * @requires foundation.util.accordionMenu 2182 * @requires foundation.util.drilldown 2183 * @requires foundation.util.dropdown-menu 2184 */ 2185 2186 var ResponsiveMenu = function () { 2187 /** 2188 * Creates a new instance of a responsive menu. 2189 * @class 2190 * @fires ResponsiveMenu#init 2191 * @param {jQuery} element - jQuery object to make into a dropdown menu. 2192 * @param {Object} options - Overrides to the default plugin settings. 2193 */ 2194 2195 function ResponsiveMenu(element, options) { 2196 _classCallCheck(this, ResponsiveMenu); 2197 2198 this.$element = $(element); 2199 this.rules = this.$element.data('responsive-menu'); 2200 this.currentMq = null; 2201 this.currentPlugin = null; 2202 2203 this._init(); 2204 this._events(); 2205 2206 Foundation.registerPlugin(this, 'ResponsiveMenu'); 2207 } 2208 2209 /** 2210 * Initializes the Menu by parsing the classes from the 'data-ResponsiveMenu' attribute on the element. 2211 * @function 2212 * @private 2213 */ 2214 2215 2216 _createClass(ResponsiveMenu, [{ 2217 key: '_init', 2218 value: function _init() { 2219 // The first time an Interchange plugin is initialized, this.rules is converted from a string of "classes" to an object of rules 2220 if (typeof this.rules === 'string') { 2221 var rulesTree = {}; 2222 2223 // Parse rules from "classes" pulled from data attribute 2224 var rules = this.rules.split(' '); 2225 2226 // Iterate through every rule found 2227 for (var i = 0; i < rules.length; i++) { 2228 var rule = rules[i].split('-'); 2229 var ruleSize = rule.length > 1 ? rule[0] : 'small'; 2230 var rulePlugin = rule.length > 1 ? rule[1] : rule[0]; 2231 2232 if (MenuPlugins[rulePlugin] !== null) { 2233 rulesTree[ruleSize] = MenuPlugins[rulePlugin]; 2234 } 2235 } 2236 2237 this.rules = rulesTree; 2238 } 2239 2240 if (!$.isEmptyObject(this.rules)) { 2241 this._checkMediaQueries(); 2242 } 2243 } 2244 2245 /** 2246 * Initializes events for the Menu. 2247 * @function 2248 * @private 2249 */ 2250 2251 }, {
2252 key: '_events', 2253 value: function _events() { 2254 var _this = this; 2255 2256 $(window).on('changed.zf.mediaquery', function () { 2257 _this._checkMediaQueries(); 2258 }); 2259 // $(window).on('resize.zf.ResponsiveMenu', function() { 2260 // _this._checkMediaQueries(); 2261 // }); 2262 } 2263 2264 /** 2265 * Checks the current screen width against available media queries. If the media query has changed, and the plugin needed has changed, the plugins will swap out. 2266 * @function 2267 * @private 2268 */ 2269 2270 }, { 2271 key: '_checkMediaQueries', 2272 value: function _checkMediaQueries() { 2273 var matchedMq, 2274 _this = this; 2275 // Iterate through each rule and find the last matching rule 2276 $.each(this.rules, function (key) { 2277 if (Foundation.MediaQuery.atLeast(key)) { 2278 matchedMq = key; 2279 } 2280 }); 2281 2282 // No match? No dice 2283 if (!matchedMq) return; 2284 2285 // Plugin already initialized? We good 2286 if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return; 2287 2288 // Remove existing plugin-specific CSS classes 2289 $.each(MenuPlugins, function (key, value) { 2290 _this.$element.removeClass(value.cssClass); 2291 }); 2292 2293 // Add the CSS class for the new plugin 2294 this.$element.addClass(this.rules[matchedMq].cssClass); 2295 2296 // Create an instance of the new plugin 2297 if (this.currentPlugin) this.currentPlugin.destroy(); 2298 this.currentPlugin = new this.rules[matchedMq].plugin(this.$element, {}); 2299 } 2300 2301 /** 2302 * Destroys the instance of the current plugin on this element, as well as the window resize handler that switches the plugins out. 2303 * @function 2304 */ 2305 2306 }, { 2307 key: 'destroy', 2308 value: function destroy() { 2309 this.currentPlugin.destroy(); 2310 $(window).off('.zf.ResponsiveMenu'); 2311 Foundation.unregisterPlugin(this); 2312 } 2313 }]); 2314 2315 return ResponsiveMenu; 2316 }(); 2317 2318 ResponsiveMenu.defaults = {}; 2319 2320 // The plugin matches the plugin classes with these plugin instances. 2321 var MenuPlugins = { 2322 dropdown: { 2323 cssClass: 'dropdown', 2324 plugin: Foundation._plugins['dropdown-menu'] || null 2325 }, 2326 drilldown: { 2327 cssClass: 'drilldown', 2328 plugin: Foundation._plugins['drilldown'] || null 2329 }, 2330 accordion: { 2331 cssClass: 'accordion-menu', 2332 plugin: Foundation._plugins['accordion-menu'] || null 2333 } 2334 }; 2335 2336 // Window exports 2337 Foundation.plugin(ResponsiveMenu, 'ResponsiveMenu'); 2338}(jQuery); 2339'use strict'; 2340 2341var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 2342 2343function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 2344 2345!function ($) { 2346 2347 /** 2348 * Dropdown module. 2349 * @module foundation.dropdown 2350 * @requires foundation.util.keyboard 2351 * @requires foundation.util.box 2352 * @requires foundation.util.triggers 2353 */ 2354 2355 var Dropdown = function () { 2356 /** 2357 * Creates a new instance of a dropdown. 2358 * @class 2359 * @param {jQuery} element - jQuery object to make into a dropdown. 2360 * Object should be of the dropdown panel, rather than its anchor. 2361 * @param {Object} options - Overrides to the default plugin settings. 2362 */ 2363 2364 function Dropdown(element, options) { 2365 _classCallCheck(this, Dropdown); 2366 2367 this.$element = element; 2368 this.options = $.extend({}, Dropdown.defaults, this.$element.data(), options); 2369 this._init(); 2370 2371 Foundation.registerPlugin(this, 'Dropdown'); 2372 Foundation.Keyboard.register('Dropdown', { 2373 'ENTER': 'open', 2374 'SPACE': 'open', 2375 'ESCAPE': 'close', 2376 'TAB': 'tab_forward', 2377 'SHIFT_TAB': 'tab_backward' 2378 }); 2379 } 2380 2381 /** 2382 * Initializes the plugin by setting/checking options and attributes, adding helper variables, and saving the anch
2382or. 2383 * @function 2384 * @private 2385 */ 2386 2387 2388 _createClass(Dropdown, [{ 2389 key: '_init', 2390 value: function _init() { 2391 var $id = this.$element.attr('id'); 2392 2393 this.$anchor = $('[data-toggle="' + $id + '"]') || $('[data-open="' + $id + '"]'); 2394 this.$anchor.attr({ 2395 'aria-controls': $id, 2396 'data-is-focus': false, 2397 'data-yeti-box': $id, 2398 'aria-haspopup': true, 2399 'aria-expanded': false 2400 2401 }); 2402 2403 this.options.positionClass = this.getPositionClass(); 2404 this.counter = 4; 2405 this.usedPositions = []; 2406 this.$element.attr({ 2407 'aria-hidden': 'true', 2408 'data-yeti-box': $id, 2409 'data-resize': $id, 2410 'aria-labelledby': this.$anchor[0].id || Foundation.GetYoDigits(6, 'dd-anchor') 2411 }); 2412 this._events(); 2413 } 2414 2415 /** 2416 * Helper function to determine current orientation of dropdown pane. 2417 * @function 2418 * @returns {String} position - string value of a position class. 2419 */ 2420 2421 }, { 2422 key: 'getPositionClass', 2423 value: function getPositionClass() { 2424 var verticalPosition = this.$element[0].className.match(/(top|left|right|bottom)/g); 2425 verticalPosition = verticalPosition ? verticalPosition[0] : ''; 2426 var horizontalPosition = /float-(.+)\s/.exec(this.$anchor[0].className); 2427 horizontalPosition = horizontalPosition ? horizontalPosition[1] : ''; 2428 var position = horizontalPosition ? horizontalPosition + ' ' + verticalPosition : verticalPosition; 2429 return position; 2430 } 2431 2432 /** 2433 * Adjusts the dropdown panes orientation by adding/removing positioning classes. 2434 * @function 2435 * @private 2436 * @param {String} position - position class to remove. 2437 */ 2438 2439 }, { 2440 key: '_reposition', 2441 value: function _reposition(position) { 2442 this.usedPositions.push(position ? position : 'bottom'); 2443 //default, try switching to opposite side 2444 if (!position && this.usedPositions.indexOf('top') < 0) { 2445 this.$element.addClass('top'); 2446 } else if (position === 'top' && this.usedPositions.indexOf('bottom') < 0) { 2447 this.$element.removeClass(position); 2448 } else if (position === 'left' && this.usedPositions.indexOf('right') < 0) { 2449 this.$element.removeClass(position).addClass('right'); 2450 } else if (position === 'right' && this.usedPositions.indexOf('left') < 0) { 2451 this.$element.removeClass(position).addClass('left'); 2452 } 2453 2454 //if default change didn't work, try bottom or left first 2455 else if (!position && this.usedPositions.indexOf('top') > -1 && this.usedPositions.indexOf('left') < 0) { 2456 this.$element.addClass('left'); 2457 } else if (position === 'top' && this.usedPositions.indexOf('bottom') > -1 && this.usedPositions.indexOf('left') < 0) { 2458 this.$element.removeClass(position).addClass('left'); 2459 } else if (position === 'left' && this.usedPositions.indexOf('right') > -1 && this.usedPositions.indexOf('bottom') < 0) { 2460 this.$element.removeClass(position); 2461 } else if (position === 'right' && this.usedPositions.indexOf('left') > -1 && this.usedPositions.indexOf('bottom') < 0) { 2462 this.$element.removeClass(position); 2463 } 2464 //if nothing cleared, set to bottom 2465 else { 2466 this.$element.removeClass(position); 2467 } 2468 this.classChanged = true; 2469 this.counter--; 2470 } 2471 2472 /** 2473 * Sets the position and orientation of the dropdown pane, checks for collisions. 2474 * Recursively calls itself if a collision is detected, with a new position class. 2475 * @function 2476 * @private 2477 */ 2478 2479 }, { 2480 key: '_setPosition', 2481 value: function _setPosition() { 2482 if (this.$anchor.attr('aria-expanded') === 'false') { 2483 return false; 2484 } 2485 var position = this.getPositionClass(), 2486 $eleDims = Foundation.Box.GetDimensions(this.$element), 2487 $anchorDims = Foundation.Box.GetDimensions(this.$anchor), 2488 _this = this, 2489 direction = position === 'left' ? 'left' : position === 'right' ? 'left' : 'top', 2490 param = direction === 'top' ? 'height' : 'width', 2491 offset = param === 'height' ? this.options.vOffset : this.options.hOffset; 2492 2493 if ($eleDims.width >= $eleDims.windowDims.width || !this.counter && !Foundation.Box.ImNotTouchingYou(this.$element)) { 2494 this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, 'center bottom', this.options.vOffset, this.options.hOffset, true)).css({ 2495 'width': $eleDims.windowDims.width - this.options.hOffset * 2, 2496 'height': 'auto' 2497 }); 2498 this.classChanged = true; 2499 return false;
2500 } 2501 2502 this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, position, this.options.vOffset, this.options.hOffset)); 2503 2504 while (!Foundation.Box.ImNotTouchingYou(this.$element, false, true) && this.counter) { 2505 this._reposition(position); 2506 this._setPosition(); 2507 } 2508 } 2509 2510 /** 2511 * Adds event listeners to the element utilizing the triggers utility library. 2512 * @function 2513 * @private 2514 */ 2515 2516 }, { 2517 key: '_events', 2518 value: function _events() { 2519 var _this = this; 2520 this.$element.on({ 2521 'open.zf.trigger': this.open.bind(this), 2522 'close.zf.trigger': this.close.bind(this), 2523 'toggle.zf.trigger': this.toggle.bind(this), 2524 'resizeme.zf.trigger': this._setPosition.bind(this) 2525 }); 2526 2527 if (this.options.hover) { 2528 this.$anchor.off('mouseenter.zf.dropdown mouseleave.zf.dropdown').on('mouseenter.zf.dropdown', function () { 2529 clearTimeout(_this.timeout); 2530 _this.timeout = setTimeout(function () { 2531 _this.open(); 2532 _this.$anchor.data('hover', true); 2533 }, _this.options.hoverDelay); 2534 }).on('mouseleave.zf.dropdown', function () { 2535 clearTimeout(_this.timeout); 2536 _this.timeout = setTimeout(function () { 2537 _this.close(); 2538 _this.$anchor.data('hover', false); 2539 }, _this.options.hoverDelay); 2540 }); 2541 if (this.options.hoverPane) { 2542 this.$element.off('mouseenter.zf.dropdown mouseleave.zf.dropdown').on('mouseenter.zf.dropdown', function () { 2543 clearTimeout(_this.timeout); 2544 }).on('mouseleave.zf.dropdown', function () { 2545 clearTimeout(_this.timeout); 2546 _this.timeout = setTimeout(function () { 2547 _this.close(); 2548 _this.$anchor.data('hover', false); 2549 }, _this.options.hoverDelay); 2550 }); 2551 } 2552 } 2553 this.$anchor.add(this.$element).on('keydown.zf.dropdown', function (e) { 2554 2555 var $target = $(this), 2556 visibleFocusableElements = Foundation.Keyboard.findFocusable(_this.$element); 2557 2558 Foundation.Keyboard.handleKey(e, 'Dropdown', { 2559 tab_forward: function () { 2560 if (_this.$element.find(':focus').is(visibleFocusableElements.eq(-1))) { 2561 // left modal downwards, setting focus to first element 2562 if (_this.options.trapFocus) { 2563 // if focus shall be trapped 2564 visibleFocusableElements.eq(0).focus(); 2565 e.preventDefault(); 2566 } else { 2567 // if focus is not trapped, close dropdown on focus out 2568 _this.close(); 2569 } 2570 } 2571 }, 2572 tab_backward: function () { 2573 if (_this.$element.find(':focus').is(visibleFocusableElements.eq(0)) || _this.$element.is(':focus')) { 2574 // left modal upwards, setting focus to last element 2575 if (_this.options.trapFocus) { 2576 // if focus shall be trapped 2577 visibleFocusableElements.eq(-1).focus(); 2578 e.preventDefault(); 2579 } else { 2580 // if focus is not trapped, close dropdown on focus out 2581 _this.close(); 2582 } 2583 } 2584 }, 2585 open: function () { 2586 if ($target.is(_this.$anchor)) { 2587 _this.open(); 2588 _this.$element.attr('tabindex', -1).focus(); 2589 e.preventDefault(); 2590 } 2591 }, 2592 close: function () { 2593 _this.close(); 2594 _this.$anchor.focus(); 2595 } 2596 }); 2597 }); 2598 } 2599 2600 /** 2601 * Adds an event handler to the body to close any dropdowns on a click. 2602 * @function 2603 * @private 2604 */ 2605 2606 }, { 2607 key: '_addBodyHandler', 2608 value: function _addBodyHandler() { 2609 var $body = $(document.body).not(this.$element), 2610 _this = this; 2611 $body.off('click.zf.dropdown').on('click.zf.dropdown', function (e) { 2612 if (_this.$anchor.is(e.target) || _this.$anchor.find(e.target).length) { 2613 return; 2614 } 2615 if (_this.$element.find(e.target).length) { 2616 return; 2617 } 2618 _this.close(); 2619 $body.off('click.zf.dropdown'); 2620 }); 2621 } 2622 2623 /** 2624 * Opens the dropdown pane, and fires a bubbling event to close other dropdowns. 2625 * @function 2626 * @fires Dropdown#closeme 2627 * @fires Dropdown#show 2628 */ 2629 2630 }, {
2631 key: 'open', 2632 value: function open() { 2633 // var _this = this; 2634 /** 2635 * Fires to close other open dropdowns 2636 * @event Dropdown#closeme 2637 */ 2638 this.$element.trigger('closeme.zf.dropdown', this.$element.attr('id')); 2639 this.$anchor.addClass('hover').attr({ 'aria-expanded': true }); 2640 // this.$element/*.show()*/; 2641 this._setPosition(); 2642 this.$element.addClass('is-open').attr({ 'aria-hidden': false }); 2643 2644 if (this.options.autoFocus) { 2645 var $focusable = Foundation.Keyboard.findFocusable(this.$element); 2646 if ($focusable.length) { 2647 $focusable.eq(0).focus(); 2648 } 2649 } 2650 2651 if (this.options.closeOnClick) { 2652 this._addBodyHandler(); 2653 } 2654 2655 /** 2656 * Fires once the dropdown is visible. 2657 * @event Dropdown#show 2658 */ 2659 this.$element.trigger('show.zf.dropdown', [this.$element]); 2660 } 2661 2662 /** 2663 * Closes the open dropdown pane. 2664 * @function 2665 * @fires Dropdown#hide 2666 */ 2667 2668 }, { 2669 key: 'close', 2670 value: function close() { 2671 if (!this.$element.hasClass('is-open')) { 2672 return false; 2673 } 2674 this.$element.removeClass('is-open').attr({ 'aria-hidden': true }); 2675 2676 this.$anchor.removeClass('hover').attr('aria-expanded', false); 2677 2678 if (this.classChanged) { 2679 var curPositionClass = this.getPositionClass(); 2680 if (curPositionClass) { 2681 this.$element.removeClass(curPositionClass); 2682 } 2683 this.$element.addClass(this.options.positionClass) 2684 /*.hide()*/.css({ height: '', width: '' }); 2685 this.classChanged = false; 2686 this.counter = 4; 2687 this.usedPositions.length = 0; 2688 } 2689 this.$element.trigger('hide.zf.dropdown', [this.$element]); 2690 } 2691 2692 /** 2693 * Toggles the dropdown pane's visibility. 2694 * @function 2695 */ 2696 2697 }, { 2698 key: 'toggle', 2699 value: function toggle() { 2700 if (this.$element.hasClass('is-open')) { 2701 if (this.$anchor.data('hover')) return; 2702 this.close(); 2703 } else { 2704 this.open(); 2705 } 2706 } 2707 2708 /** 2709 * Destroys the dropdown. 2710 * @function 2711 */ 2712 2713 }, { 2714 key: 'destroy', 2715 value: function destroy() { 2716 this.$element.off('.zf.trigger').hide(); 2717 this.$anchor.off('.zf.dropdown'); 2718 2719 Foundation.unregisterPlugin(this); 2720 } 2721 }]); 2722 2723 return Dropdown; 2724 }(); 2725 2726 Dropdown.defaults = { 2727 /** 2728 * Amount of time to delay opening a submenu on hover event. 2729 * @option 2730 * @example 250 2731 */ 2732 hoverDelay: 250, 2733 /** 2734 * Allow submenus to open on hover events 2735 * @option 2736 * @example false 2737 */ 2738 hover: false, 2739 /** 2740 * Don't close dropdown when hovering over dropdown pane 2741 * @option 2742 * @example true 2743 */ 2744 hoverPane: false, 2745 /** 2746 * Number of pixels between the dropdown pane and the triggering element on open. 2747 * @option 2748 * @example 1 2749 */ 2750 vOffset: 1, 2751 /** 2752 * Number of pixels between the dropdown pane and the triggering element on open. 2753 * @option 2754 * @example 1 2755 */ 2756 hOffset: 1, 2757 /** 2758 * Class applied to adjust open position. JS will test and fill this in. 2759 * @option 2760 * @example 'top' 2761 */ 2762 positionClass: '', 2763 /** 2764 * Allow the plugin to trap focus to the dropdown pane if opened with keyboard commands. 2765 * @option 2766 * @example false 2767 */ 2768 trapFocus: false, 2769 /** 2770 * Allow the plugin to set focus to the first focusable element within the pane, regardless of method of opening. 2771 * @option 2772 * @example true 2773 */ 2774 autoFocus: false, 2775 /** 2776 * Allows a click on the body to close the dropdown. 2777 * @option 2778 * @example false 2779 */ 2780 closeOnClick: false 2781 }; 2782 2783 // Window exports 2784 Foundation.plugin(Dropdown, 'Dropdown'); 2785}(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.