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