1!function ($) { 2 3 "use strict"; 4 5 var FOUNDATION_VERSION = '6.2.2'; 6 7 // Global Foundation object 8 // This is attached to the window, or used as a module for AMD/Browserify 9 var Foundation = { 10 version: FOUNDATION_VERSION, 11 12 /** 13 * Stores initialized plugins. 14 */ 15 _plugins: {}, 16 17 /** 18 * Stores generated unique ids for plugin instances 19 */ 20 _uuids: [], 21 22 /** 23 * Returns a boolean for RTL support 24 */ 25 rtl: function () { 26 return $('html').attr('dir') === 'rtl'; 27 }, 28 /** 29 * Defines a Foundation plugin, adding it to the `Foundation` namespace and the list of plugins to initialize when reflowing. 30 * @param {Object} plugin - The constructor of the plugin. 31 */ 32 plugin: function (plugin, name) { 33 // Object key to use when adding to global Foundation object 34 // Examples: Foundation.Reveal, Foundation.OffCanvas 35 var className = name || functionName(plugin); 36 // Object key to use when storing the plugin, also used to create the identifying data attribute for the plugin 37 // Examples: data-reveal, data-off-canvas 38 var attrName = hyphenate(className); 39 40 // Add to the Foundation object and the plugins list (for reflowing) 41 this._plugins[attrName] = this[className] = plugin; 42 }, 43 /** 44 * @function 45 * Populates the _uuids array with pointers to each individual plugin instance. 46 * Adds the `zfPlugin` data-attribute to programmatically created plugins to allow use of $(selector).foundation(method) calls. 47 * Also fires the initialization event for each plugin, consolidating repetitive code. 48 * @param {Object} plugin - an instance of a plugin, usually `this` in context. 49 * @param {String} name - the name of the plugin, passed as a camelCased string. 50 * @fires Plugin#init 51 */ 52 registerPlugin: function (plugin, name) { 53 var pluginName = name ? hyphenate(name) : functionName(plugin.constructor).toLowerCase(); 54 plugin.uuid = this.GetYoDigits(6, pluginName); 55 56 if (!plugin.$element.attr('data-' + pluginName)) { 57 plugin.$element.attr('data-' + pluginName, plugin.uuid); 58 } 59 if (!plugin.$element.data('zfPlugin')) { 60 plugin.$element.data('zfPlugin', plugin); 61 } 62 /** 63 * Fires when the plugin has initialized. 64 * @event Plugin#init 65 */ 66 plugin.$element.trigger('init.zf.' + pluginName); 67 68 this._uuids.push(plugin.uuid); 69 70 return; 71 }, 72 /** 73 * @function 74 * Removes the plugins uuid from the _uuids array. 75 * Removes the zfPlugin data attribute, as well as the data-plugin-name attribute. 76 * Also fires the destroyed event for the plugin, consolidating repetitive code. 77 * @param {Object} plugin - an instance of a plugin, usually `this` in context. 78 * @fires Plugin#destroyed 79 */ 80 unregisterPlugin: function (plugin) { 81 var pluginName = hyphenate(functionName(plugin.$element.data('zfPlugin').constructor)); 82 83 this._uuids.splice(this._uuids.indexOf(plugin.uuid), 1); 84 plugin.$element.removeAttr('data-' + pluginName).removeData('zfPlugin') 85 /** 86 * Fires when the plugin has been destroyed. 87 * @event Plugin#destroyed 88 */ 89 .trigger('destroyed.zf.' + pluginName); 90 for (var prop in plugin) { 91 plugin[prop] = null; //clean up script to prep for garbage collection. 92 } 93 return; 94 }, 95 96 /** 97 * @function 98 * Causes one or more active plugins to re-initialize, resetting event listeners, recalculating positions, etc. 99 * @param {String} plugins - optional string of an individual plugin key, attained by calling `$(element).data('pluginName')`, or string of a plugin class i.e. `'dropdown'` 100 * @default If no argument is passed, reflow all currently active plugins. 101 */ 102 reInit: function (plugins) { 103 var isJQ = plugins instanceof $; 104 try { 105 if (isJQ) { 106 plugins.each(function () { 107 $(this).data('zfPlugin')._init(); 108 }); 109 } else { 110 var type = typeof plugins, 111 _this = this, 112 fns = { 113 'object': function (plgs) {
114 plgs.forEach(function (p) { 115 p = hyphenate(p); 116 $('[data-' + p + ']').foundation('_init'); 117 }); 118 }, 119 'string': function () { 120 plugins = hyphenate(plugins); 121 $('[data-' + plugins + ']').foundation('_init'); 122 }, 123 'undefined': function () { 124 this['object'](Object.keys(_this._plugins)); 125 } 126 }; 127 fns[type](plugins); 128 } 129 } catch (err) { 130 console.error(err); 131 } finally { 132 return plugins; 133 } 134 }, 135 136 /** 137 * returns a random base-36 uid with namespacing 138 * @function 139 * @param {Number} length - number of random base-36 digits desired. Increase for more random strings. 140 * @param {String} namespace - name of plugin to be incorporated in uid, optional. 141 * @default {String} '' - if no plugin name is provided, nothing is appended to the uid. 142 * @returns {String} - unique id 143 */ 144 GetYoDigits: function (length, namespace) { 145 length = length || 6; 146 return Math.round(Math.pow(36, length + 1) - Math.random() * Math.pow(36, length)).toString(36).slice(1) + (namespace ? '-' + namespace : ''); 147 }, 148 /** 149 * Initialize plugins on any elements within `elem` (and `elem` itself) that aren't already initialized. 150 * @param {Object} elem - jQuery object containing the element to check inside. Also checks the element itself, unless it's the `document` object. 151 * @param {String|Array} plugins - A list of plugins to initialize. Leave this out to initialize everything. 152 */ 153 reflow: function (elem, plugins) { 154 155 // If plugins is undefined, just grab everything 156 if (typeof plugins === 'undefined') { 157 plugins = Object.keys(this._plugins); 158 } 159 // If plugins is a string, convert it to an array with one item 160 else if (typeof plugins === 'string') { 161 plugins = [plugins]; 162 } 163 164 var _this = this; 165 166 // Iterate through each plugin 167 $.each(plugins, function (i, name) { 168 // Get the current plugin 169 var plugin = _this._plugins[name]; 170 171 // Localize the search to all elements inside elem, as well as elem itself, unless elem === document 172 var $elem = $(elem).find('[data-' + name + ']').addBack('[data-' + name + ']'); 173 174 // For each plugin found, initialize it 175 $elem.each(function () { 176 var $el = $(this), 177 opts = {}; 178 // Don't double-dip on plugins 179 if ($el.data('zfPlugin')) { 180 console.warn("Tried to initialize " + name + " on an element that already has a Foundation plugin."); 181 return; 182 } 183 184 if ($el.attr('data-options')) { 185 var thing = $el.attr('data-options').split(';').forEach(function (e, i) { 186 var opt = e.split(':').map(function (el) { 187 return el.trim(); 188 }); 189 if (opt[0]) opts[opt[0]] = parseValue(opt[1]); 190 }); 191 } 192 try { 193 $el.data('zfPlugin', new plugin($(this), opts)); 194 } catch (er) { 195 console.error(er); 196 } finally { 197 return; 198 } 199 }); 200 }); 201 }, 202 getFnName: functionName, 203 transitionend: function ($elem) { 204 var transitions = { 205 'transition': 'transitionend', 206 'WebkitTransition': 'webkitTransitionEnd', 207 'MozTransition': 'transitionend', 208 'OTransition': 'otransitionend' 209 }; 210 var elem = document.createElement('div'), 211 end; 212 213 for (var t in transitions) { 214 if (typeof elem.style[t] !== 'undefined') { 215 end = transitions[t]; 216 } 217 } 218 if (end) { 219 return end; 220 } else { 221 end = setTimeout(function () { 222 $elem.triggerHandler('transitionend', [$elem]); 223 }, 1); 224 return 'transitionend'; 225 } 226 } 227 }; 228 229 Foundation.util = { 230 /** 231 * Function for applying a debounce effect to a function call. 232 * @function 233 * @param {Function} func - Function to be called at end of timeout. 234 * @param {Number} delay - Time in ms to delay the call of `func`. 235 * @returns function 236 */ 237 throttle: function (func, delay) { 238 var timer = null; 239 240 return function () { 241 var context = this, 242 args = arguments; 243 244 if (timer === null) { 245 timer = setTimeout(function () {
246 func.apply(context, args); 247 timer = null; 248 }, delay); 249 } 250 }; 251 } 252 }; 253 254 // TODO: consider not making this a jQuery function 255 // TODO: need way to reflow vs. re-initialize 256 /** 257 * The Foundation jQuery method. 258 * @param {String|Array} method - An action to perform on the current jQuery object. 259 */ 260 var foundation = function (method) { 261 var type = typeof method, 262 $meta = $('meta.foundation-mq'), 263 $noJS = $('.no-js'); 264 265 if (!$meta.length) { 266 $('<meta class="foundation-mq">').appendTo(document.head); 267 } 268 if ($noJS.length) { 269 $noJS.removeClass('no-js'); 270 } 271 272 if (type === 'undefined') { 273 //needs to initialize the Foundation object, or an individual plugin. 274 Foundation.MediaQuery._init(); 275 Foundation.reflow(this); 276 } else if (type === 'string') { 277 //an individual method to invoke on a plugin or group of plugins 278 var args = Array.prototype.slice.call(arguments, 1); //collect all the arguments, if necessary 279 var plugClass = this.data('zfPlugin'); //determine the class of plugin 280 281 if (plugClass !== undefined && plugClass[method] !== undefined) { 282 //make sure both the class and method exist 283 if (this.length === 1) { 284 //if there's only one, call it directly. 285 plugClass[method].apply(plugClass, args); 286 } else { 287 this.each(function (i, el) { 288 //otherwise loop through the jQuery collection and invoke the method on each 289 plugClass[method].apply($(el).data('zfPlugin'), args); 290 }); 291 } 292 } else { 293 //error for no class or no method 294 throw new ReferenceError("We're sorry, '" + method + "' is not an available method for " + (plugClass ? functionName(plugClass) : 'this element') + '.'); 295 } 296 } else { 297 //error for invalid argument type 298 throw new TypeError('We\'re sorry, ' + type + ' is not a valid parameter. You must use a string representing the method you wish to invoke.'); 299 } 300 return this; 301 }; 302 303 window.Foundation = Foundation; 304 $.fn.foundation = foundation; 305 306 // Polyfill for requestAnimationFrame 307 (function () { 308 if (!Date.now || !window.Date.now) window.Date.now = Date.now = function () { 309 return new Date().getTime(); 310 }; 311 312 var vendors = ['webkit', 'moz']; 313 for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { 314 var vp = vendors[i]; 315 window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; 316 window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']; 317 } 318 if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { 319 var lastTime = 0; 320 window.requestAnimationFrame = function (callback) { 321 var now = Date.now(); 322 var nextTime = Math.max(lastTime + 16, now); 323 return setTimeout(function () { 324 callback(lastTime = nextTime); 325 }, nextTime - now); 326 }; 327 window.cancelAnimationFrame = clearTimeout; 328 } 329 /** 330 * Polyfill for performance.now, required by rAF 331 */ 332 if (!window.performance || !window.performance.now) { 333 window.performance = { 334 start: Date.now(), 335 now: function () { 336 return Date.now() - this.start; 337 } 338 }; 339 } 340 })(); 341 if (!Function.prototype.bind) { 342 Function.prototype.bind = function (oThis) { 343 if (typeof this !== 'function') { 344 // closest thing possible to the ECMAScript 5 345 // internal IsCallable function 346 throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); 347 } 348 349 var aArgs = Array.prototype.slice.call(arguments, 1), 350 fToBind = this, 351 fNOP = function () {}, 352 fBound = function () { 353 return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); 354 }; 355 356 if (this.prototype) { 357 // native functions don't have a prototype 358 fNOP.prototype = this.prototype; 359 } 360 fBound.prototype = new fNOP(); 361 362 return fBound; 363 }; 364 } 365 // Polyfill to get the name of a function in IE9 366 function functionName(fn) { 367 if (Function.prototype.name === undefined) { 368 var funcNameRegex = /function\s([^(]{1,})\(/; 369 var results = funcNameRegex.exec(fn.toString()); 370 return results && results.length > 1 ? results[1].trim() : ""; 371 } else if (fn.prototype === undefined) { 372 return fn.constructor.name; 373 } else { 374 return fn.prototype.constructor.name; 375 } 376 } 377 function parseValue(str) { 378 if (/true/.test(str)) return true;else if (/false/.test(str)) return false;else if (!isNaN(str * 1)) return parseFloat(str); 379 return str; 380 } 381 // Convert PascalCase to kebab-case 382 // Thank you: http://stackoverflow.com/a/8955580 383 function hyphenate(str) { 384 return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); 385 } 386}(jQuery); 387'use strict'; 388 389!function ($) { 390 391 // Default set of media queries 392 var defaultQueries = { 393 'default': 'only screen', 394 landscape: 'only screen and (orientation: landscape)', 395 portrait: 'only screen and (orientation: portrait)', 396 retina: 'only screen and (-webkit-min-device-pixel-ratio: 2),' + 'only screen and (min--moz-device-pixel-ratio: 2),' + 'only screen and (-o-min-device-pixel-ratio: 2/1),' + 'only screen and (min-device-pixel-ratio: 2),' + 'only screen and (min-resolution: 192dpi),' + 'only screen and (min-resolution: 2dppx)' 397 }; 398 399 var MediaQuery = { 400 queries: [], 401 402 current: '', 403 404 /** 405 * Initializes the media query helper, by extracting the breakpoint list from the CSS and activating the breakpoint watcher. 406 * @function 407 * @private 408 */ 409 _init: function () { 410 var self = this; 411 var extractedStyles = $('.foundation-mq').css('font-family'); 412 var namedQueries; 413 414 namedQueries = parseStyleToObject(extractedStyles); 415
416 for (var key in namedQueries) { 417 if (namedQueries.hasOwnProperty(key)) { 418 self.queries.push({ 419 name: key, 420 value: 'only screen and (min-width: ' + namedQueries[key] + ')' 421 }); 422 } 423 } 424 425 this.current = this._getCurrentSize(); 426 427 this._watcher(); 428 }, 429 430 431 /** 432 * Checks if the screen is at least as wide as a breakpoint. 433 * @function 434 * @param {String} size - Name of the breakpoint to check. 435 * @returns {Boolean} `true` if the breakpoint matches, `false` if it's smaller. 436 */ 437 atLeast: function (size) { 438 var query = this.get(size); 439 440 if (query) { 441 return window.matchMedia(query).matches; 442 } 443 444 return false; 445 }, 446 447 448 /** 449 * Gets the media query of a breakpoint. 450 * @function 451 * @param {String} size - Name of the breakpoint to get. 452 * @returns {String|null} - The media query of the breakpoint, or `null` if the breakpoint doesn't exist. 453 */ 454 get: function (size) { 455 for (var i in this.queries) { 456 if (this.queries.hasOwnProperty(i)) { 457 var query = this.queries[i]; 458 if (size === query.name) return query.value; 459 } 460 } 461 462 return null; 463 }, 464 465 466 /** 467 * Gets the current breakpoint name by testing every breakpoint and returning the last one to match (the biggest one). 468 * @function 469 * @private 470 * @returns {String} Name of the current breakpoint. 471 */ 472 _getCurrentSize: function () { 473 var matched; 474 475 for (var i = 0; i < this.queries.length; i++) { 476 var query = this.queries[i]; 477 478 if (window.matchMedia(query.value).matches) { 479 matched = query; 480 } 481 } 482 483 if (typeof matched === 'object') { 484 return matched.name; 485 } else { 486 return matched; 487 } 488 }, 489 490 491 /** 492 * Activates the breakpoint watcher, which fires an event on the window whenever the breakpoint changes. 493 * @function 494 * @private 495 */ 496 _watcher: function () { 497 var _this = this; 498 499 $(window).on('resize.zf.mediaquery', function () { 500 var newSize = _this._getCurrentSize(), 501 currentSize = _this.current; 502 503 if (newSize !== currentSize) { 504 // Change the current media query 505 _this.current = newSize; 506 507 // Broadcast the media query change on the window 508 $(window).trigger('changed.zf.mediaquery', [newSize, currentSize]); 509 } 510 }); 511 } 512 }; 513 514 Foundation.MediaQuery = MediaQuery; 515 516 // matchMedia() polyfill - Test a CSS media type/query in JS. 517 // Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license 518 window.matchMedia || (window.matchMedia = function () { 519 'use strict'; 520 521 // For browsers that support matchMedium api such as IE 9 and webkit 522 523 var styleMedia = window.styleMedia || window.media; 524 525 // For those that don't support matchMedium 526 if (!styleMedia) { 527 var style = document.createElement('style'), 528 script = document.getElementsByTagName('script')[0], 529 info = null; 530 531 style.type = 'text/css'; 532 style.id = 'matchmediajs-test'; 533 534 script.parentNode.insertBefore(style, script); 535 536 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers 537 info = 'getComputedStyle' in window && window.getComputedStyle(style, null) || style.currentStyle; 538 539 styleMedia = { 540 matchMedium: function (media) { 541 var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; 542 543 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers 544 if (style.styleSheet) { 545 style.styleSheet.cssText = text; 546 } else { 547 style.textContent = text; 548 } 549 550 // Test if media query is true or false 551 return info.width === '1px'; 552 } 553 }; 554 } 555 556 return function (media) { 557 return { 558 matches: styleMedia.matchMedium(media || 'all'), 559 media: media || 'all' 560 }; 561 }; 562 }()); 563 564 // Thank you: https://github.com/sindresorhus/query-string 565 function parseStyleToObject(str) { 566 var styleObject = {}; 567 568 if (typeof str !== 'string') { 569 return styleObject; 570 } 571 572 str = str.trim().slice(1, -1);
572 // browsers re-quote string style values 573 574 if (!str) { 575 return styleObject; 576 } 577 578 styleObject = str.split('&').reduce(function (ret, param) { 579 var parts = param.replace(/\+/g, ' ').split('='); 580 var key = parts[0]; 581 var val = parts[1]; 582 key = decodeURIComponent(key); 583 584 // missing `=` should be `null`: 585 // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters 586 val = val === undefined ? null : decodeURIComponent(val); 587 588 if (!ret.hasOwnProperty(key)) { 589 ret[key] = val; 590 } else if (Array.isArray(ret[key])) { 591 ret[key].push(val); 592 } else { 593 ret[key] = [ret[key], val]; 594 } 595 return ret; 596 }, {}); 597 598 return styleObject; 599 } 600 601 Foundation.MediaQuery = MediaQuery; 602}(jQuery); 603/******************************************* 604 * * 605 * This util was created by Marius Olbertz * 606 * Please thank Marius on GitHub /owlbertz * 607 * or the web http://www.mariusolbertz.de/ * 608 * * 609 ******************************************/ 610 611'use strict'; 612 613!function ($) { 614 615 var keyCodes = { 616 9: 'TAB', 617 13: 'ENTER', 618 27: 'ESCAPE', 619 32: 'SPACE', 620 37: 'ARROW_LEFT', 621 38: 'ARROW_UP', 622 39: 'ARROW_RIGHT', 623 40: 'ARROW_DOWN' 624 }; 625 626 var commands = {}; 627 628 var Keyboard = { 629 keys: getKeyCodes(keyCodes), 630 631 /** 632 * Parses the (keyboard) event and returns a String that represents its key 633 * Can be used like Foundation.parseKey(event) === Foundation.keys.SPACE 634 * @param {Event} event - the event generated by the event handler 635 * @return String key - String that represents the key pressed 636 */ 637 parseKey: function (event) { 638 var key = keyCodes[event.which || event.keyCode] || String.fromCharCode(event.which).toUpperCase(); 639 if (event.shiftKey) key = 'SHIFT_' + key; 640 if (event.ctrlKey) key = 'CTRL_' + key; 641 if (event.altKey) key = 'ALT_' + key; 642 return key; 643 }, 644 645 646 /** 647 * Handles the given (keyboard) event 648 * @param {Event} event - the event generated by the event handler 649 * @param {String} component - Foundation component's name, e.g. Slider or Reveal 650 * @param {Objects} functions - collection of functions that are to be executed 651 */ 652 handleKey: function (event, component, functions) { 653 var commandList = commands[component], 654 keyCode = this.parseKey(event), 655 cmds, 656 command, 657 fn; 658 659 if (!commandList) return console.warn('Component not defined!'); 660 661 if (typeof commandList.ltr === 'undefined') { 662 // this component does not differentiate between ltr and rtl 663 cmds = commandList; // use plain list 664 } else { 665 // merge ltr and rtl: if document is rtl, rtl overwrites ltr and vice versa 666 if (Foundation.rtl()) cmds = $.extend({}, commandList.ltr, commandList.rtl);else cmds = $.extend({}, commandList.rtl, commandList.ltr); 667 } 668 command = cmds[keyCode]; 669 670 fn = functions[command]; 671 if (fn && typeof fn === 'function') { 672 // execute function if exists 673 var returnValue = fn.apply(); 674 if (functions.handled || typeof functions.handled === 'function') { 675 // execute function when event was handled 676 functions.handled(returnValue); 677 } 678 } else { 679 if (functions.unhandled || typeof functions.unhandled === 'function') { 680 // execute function when event was not handled 681 functions.unhandled(); 682 } 683 } 684 }, 685 686 687 /** 688 * Finds all focusable elements within the given `$element` 689 * @param {jQuery} $element - jQuery object to search within 690 * @return {jQuery} $focusable - all focusable elements within `$element` 691 */ 692 findFocusable: function ($element) { 693 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 () { 694 if (!$(this).is(':visible') || $(this).attr('tabindex') < 0) { 695 return false;
696 } //only have visible elements and those that have a tabindex greater or equal 0 697 return true; 698 }); 699 }, 700 701 702 /** 703 * Returns the component name name 704 * @param {Object} component - Foundation component, e.g. Slider or Reveal 705 * @return String componentName 706 */ 707 708 register: function (componentName, cmds) { 709 commands[componentName] = cmds; 710 } 711 }; 712 713 /* 714 * Constants for easier comparing. 715 * Can be used like Foundation.parseKey(event) === Foundation.keys.SPACE 716 */ 717 function getKeyCodes(kcs) { 718 var k = {}; 719 for (var kc in kcs) { 720 k[kcs[kc]] = kcs[kc]; 721 }return k; 722 } 723 724 Foundation.Keyboard = Keyboard; 725}(jQuery); 726'use strict'; 727 728!function ($) { 729 730 /** 731 * Motion module. 732 * @module foundation.motion 733 */ 734 735 var initClasses = ['mui-enter', 'mui-leave']; 736 var activeClasses = ['mui-enter-active', 'mui-leave-active']; 737 738 var Motion = { 739 animateIn: function (element, animation, cb) { 740 animate(true, element, animation, cb); 741 }, 742 743 animateOut: function (element, animation, cb) { 744 animate(false, element, animation, cb); 745 } 746 }; 747 748 function Move(duration, elem, fn) { 749 var anim, 750 prog, 751 start = null; 752 // console.log('called'); 753 754 function move(ts) { 755 if (!start) start = window.performance.now(); 756 // console.log(start, ts); 757 prog = ts - start; 758 fn.apply(elem); 759 760 if (prog < duration) { 761 anim = window.requestAnimationFrame(move, elem); 762 } else { 763 window.cancelAnimationFrame(anim); 764 elem.trigger('finished.zf.animate', [elem]).triggerHandler('finished.zf.animate', [elem]); 765 } 766 } 767 anim = window.requestAnimationFrame(move); 768 } 769 770 /** 771 * Animates an element in or out using a CSS transition class. 772 * @function 773 * @private 774 * @param {Boolean} isIn - Defines if the animation is in or out. 775 * @param {Object} element - jQuery or HTML object to animate. 776 * @param {String} animation - CSS class to use. 777 * @param {Function} cb - Callback to run when animation is finished. 778 */ 779 function animate(isIn, element, animation, cb) { 780 element = $(element).eq(0); 781 782 if (!element.length) return; 783 784 var initClass = isIn ? initClasses[0] : initClasses[1]; 785 var activeClass = isIn ? activeClasses[0] : activeClasses[1]; 786 787 // Set up the animation 788 reset(); 789 790 element.addClass(animation).css('transition', 'none'); 791 792 requestAnimationFrame(function () { 793 element.addClass(initClass); 794 if (isIn) element.show(); 795 }); 796 797 // Start the animation 798 requestAnimationFrame(function () { 799 element[0].offsetWidth; 800 element.css('transition', '').addClass(activeClass); 801 }); 802 803 // Clean up the animation when it finishes 804 element.one(Foundation.transitionend(element), finish); 805 806 // Hides the element (for out animations), resets the element, and runs a callback 807 function finish() { 808 if (!isIn) element.hide(); 809 reset(); 810 if (cb) cb.apply(element); 811 } 812 813 // Resets transitions and removes motion-specific classes 814 function reset() { 815 element[0].style.transitionDuration = 0; 816 element.removeClass(initClass + ' ' + activeClass + ' ' + animation); 817 } 818 } 819 820 Foundation.Move = Move; 821 Foundation.Motion = Motion; 822}(jQuery); 823'use strict'; 824 825!function ($) { 826 827 var Nest = { 828 Feather: function (menu) { 829 var type = arguments.length <= 1 || arguments[1] === undefined ? 'zf' : arguments[1]; 830 831 menu.attr('role', 'menubar'); 832 833 var items = menu.find('li').attr({ 'role': 'menuitem' }), 834 subMenuClass = 'is-' + type + '-submenu', 835 subItemClass = subMenuClass + '-item', 836 hasSubClass = 'is-' + type + '-submenu-parent'; 837 838 menu.find('a:first').attr('tabindex', 0); 839 840 items.each(function () { 841 var $item = $(this), 842 $sub = $item.children('ul'); 843 844 if ($sub.length) { 845 $item.addClass(hasSubClass).attr({ 846 'aria-haspopup': true, 847 'aria-expanded': false, 848 'aria-label': $item.children('a:first').text() 849 }); 850 851 $sub.addClass('submenu ' + subMenuClass).attr({ 852 'data-submenu': '', 853 'aria-hidden': true, 854 'role': 'menu' 855 }); 856 } 857 858 if ($item.parent('[data-submenu]').length) { 859 $item.addClass('is-submenu-item ' + subItemClass); 860 } 861 }); 862 863 return; 864 }, 865 Burn: function (menu, type) { 866 var items = menu.find('li').removeAttr('tabindex'), 867 subMenuClass = 'is-' + type + '-submenu', 868 subItemClass = subMenuClass + '-item', 869 hasSubClass = 'is-' + type + '-submenu-parent'; 870 871 menu.find('*').removeClass(subMenuClass + ' ' + subItemClass + ' ' + hasSubClass + ' is-submenu-item submenu is-active').removeAttr('data-submenu').css('display', ''); 872 873 // console.log( menu.find('.' + subMenuClass + ', .' + subItemClass + ', .has-submenu, .is-submenu-item, .submenu, [data-submenu]') 874 // .removeClass(subMenuClass + ' ' + subItemClass + ' has-submenu is-submenu-item submenu') 875 // .removeAttr('data-submenu')); 876 // items.each(function(){ 877 // var $item = $(this), 878 // $sub = $item.children('ul'); 879 // if($item.parent('[data-submenu]').length){ 880 // $item.removeClass('is-submenu-item ' + subItemClass); 881 // } 882 // if($sub.length){ 883 // $item.removeClass('has-submenu'); 884 // $sub.removeClass('submenu ' + subMenuClass).removeAttr('data-submenu'); 885 // } 886 // }); 887 } 888 }; 889 890 Foundation.Nest = Nest; 891}(jQuery); 892'use strict'; 893 894!function ($) { 895 896 Foundation.Box = { 897 ImNotTouchingYou: ImNotTouchingYou, 898 GetDimensions: GetDimensions, 899 GetOffsets: GetOffsets 900 }; 901 902 /** 903 * Compares the dimensions of an element to a container and determines collision events with container. 904 * @function 905 * @param {jQuery} element - jQuery object to test for collisions. 906 * @param {jQuery}
906 parent - jQuery object to use as bounding container. 907 * @param {Boolean} lrOnly - set to true to check left and right values only. 908 * @param {Boolean} tbOnly - set to true to check top and bottom values only. 909 * @default if no parent object passed, detects collisions with `window`. 910 * @returns {Boolean} - true if collision free, false if a collision in any direction. 911 */ 912 function ImNotTouchingYou(element, parent, lrOnly, tbOnly) { 913 var eleDims = GetDimensions(element), 914 top, 915 bottom, 916 left, 917 right; 918 919 if (parent) { 920 var parDims = GetDimensions(parent); 921 922 bottom = eleDims.offset.top + eleDims.height <= parDims.height + parDims.offset.top; 923 top = eleDims.offset.top >= parDims.offset.top; 924 left = eleDims.offset.left >= parDims.offset.left; 925 right = eleDims.offset.left + eleDims.width <= parDims.width + parDims.offset.left; 926 } else { 927 bottom = eleDims.offset.top + eleDims.height <= eleDims.windowDims.height + eleDims.windowDims.offset.top; 928 top = eleDims.offset.top >= eleDims.windowDims.offset.top; 929 left = eleDims.offset.left >= eleDims.windowDims.offset.left; 930 right = eleDims.offset.left + eleDims.width <= eleDims.windowDims.width; 931 } 932 933 var allDirs = [bottom, top, left, right]; 934 935 if (lrOnly) { 936 return left === right === true; 937 } 938 939 if (tbOnly) { 940 return top === bottom === true; 941 } 942 943 return allDirs.indexOf(false) === -1; 944 }; 945 946 /** 947 * Uses native methods to return an object of dimension values. 948 * @function 949 * @param {jQuery || HTML} element - jQuery object or DOM element for which to get the dimensions. Can be any element other that document or window. 950 * @returns {Object} - nested object of integer pixel values 951 * TODO - if element is window, return only those values. 952 */ 953 function GetDimensions(elem, test) { 954 elem = elem.length ? elem[0] : elem; 955 956 if (elem === window || elem === document) { 957 throw new Error("I'm sorry, Dave. I'm afraid I can't do that."); 958 } 959 960 var rect = elem.getBoundingClientRect(), 961 parRect = elem.parentNode.getBoundingClientRect(), 962 winRect = document.body.getBoundingClientRect(), 963 winY = window.pageYOffset, 964 winX = window.pageXOffset; 965 966 return { 967 width: rect.width, 968 height: rect.height, 969 offset: { 970 top: rect.top + winY, 971 left: rect.left + winX 972 }, 973 parentDims: { 974 width: parRect.width, 975 height: parRect.height, 976 offset: { 977 top: parRect.top + winY, 978 left: parRect.left + winX 979 } 980 }, 981 windowDims: { 982 width: winRect.width, 983 height: winRect.height, 984 offset: { 985 top: winY, 986 left: winX 987 } 988 } 989 }; 990 } 991 992 /** 993 * Returns an object of top and left integer pixel values for dynamically rendered elements, 994 * such as: Tooltip, Reveal, and Dropdown 995 * @function 996 * @param {jQuery} element - jQuery object for the element being positioned. 997 * @param {jQuery} anchor - jQuery object for the element's anchor point. 998 * @param {String} position - a string relating to the desired position of the element, relative to it's anchor 999 * @param {Number} vOffset - integer pixel value of desired vertical separation between anchor and element. 1000 * @param {Number} hOffset - integer pixel value of desired horizontal separation between anchor and element. 1001 * @param {Boolean} isOverflow - if a collision event is detected, sets to true to default the element to full width - any desired offset. 1002 * TODO alter/rewrite to work with `em` values as well/instead of pixels 1003 */ 1004 function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) { 1005 var $eleDims = GetDimensions(element), 1006 $anchorDims = anchor ? GetDimensions(anchor) : null; 1007 1008 switch (position) { 1009 case 'top': 1010 return { 1011 left: Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left, 1012 top: $anchorDims.offset.top - ($eleDims.height + vOffset) 1013 }; 1014 break; 1015 case 'left': 1016 return { 1017 left: $anchorDims.offset.left - ($eleDims.width + hOffset), 1018 top: $anchorDims.offset.top 1019 }; 1020 break; 1021 case 'right': 1022 return { 1023 left: $anchorDims.offset.left + $anchorDims.width + hOffset, 1024 top: $anchorDims.offset.top 1025 }; 1026 break; 1027 case 'center top': 1028 return { 1029 left: $anchorDims.offset.left + $anchorDims.width / 2 - $eleDims.width / 2,
1030 top: $anchorDims.offset.top - ($eleDims.height + vOffset) 1031 }; 1032 break; 1033 case 'center bottom': 1034 return { 1035 left: isOverflow ? hOffset : $anchorDims.offset.left + $anchorDims.width / 2 - $eleDims.width / 2, 1036 top: $anchorDims.offset.top + $anchorDims.height + vOffset 1037 }; 1038 break; 1039 case 'center left': 1040 return { 1041 left: $anchorDims.offset.left - ($eleDims.width + hOffset), 1042 top: $anchorDims.offset.top + $anchorDims.height / 2 - $eleDims.height / 2 1043 }; 1044 break; 1045 case 'center right': 1046 return { 1047 left: $anchorDims.offset.left + $anchorDims.width + hOffset + 1, 1048 top: $anchorDims.offset.top + $anchorDims.height / 2 - $eleDims.height / 2 1049 }; 1050 break; 1051 case 'center': 1052 return { 1053 left: $eleDims.windowDims.offset.left + $eleDims.windowDims.width / 2 - $eleDims.width / 2, 1054 top: $eleDims.windowDims.offset.top + $eleDims.windowDims.height / 2 - $eleDims.height / 2 1055 }; 1056 break; 1057 case 'reveal': 1058 return { 1059 left: ($eleDims.windowDims.width - $eleDims.width) / 2, 1060 top: $eleDims.windowDims.offset.top + vOffset 1061 }; 1062 case 'reveal full': 1063 return { 1064 left: $eleDims.windowDims.offset.left, 1065 top: $eleDims.windowDims.offset.top 1066 }; 1067 break; 1068 case 'left bottom': 1069 return { 1070 left: $anchorDims.offset.left - ($eleDims.width + hOffset), 1071 top: $anchorDims.offset.top + $anchorDims.height 1072 }; 1073 break; 1074 case 'right bottom': 1075 return { 1076 left: $anchorDims.offset.left + $anchorDims.width + hOffset - $eleDims.width, 1077 top: $anchorDims.offset.top + $anchorDims.height 1078 }; 1079 break; 1080 default: 1081 return { 1082 left: Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left, 1083 top: $anchorDims.offset.top + $anchorDims.height + vOffset 1084 }; 1085 } 1086 } 1087}(jQuery); 1088'use strict'; 1089 1090!function ($) { 1091 1092 var MutationObserver = function () { 1093 var prefixes = ['WebKit', 'Moz', 'O', 'Ms', '']; 1094 for (var i = 0; i < prefixes.length; i++) { 1095 if (prefixes[i] + 'MutationObserver' in window) { 1096 return window[prefixes[i] + 'MutationObserver']; 1097 } 1098 } 1099 return false; 1100 }(); 1101 1102 var triggers = function (el, type) { 1103 el.data(type).split(' ').forEach(function (id) { 1104 $('#' + id)[type === 'close' ? 'trigger' : 'triggerHandler'](type + '.zf.trigger', [el]); 1105 }); 1106 }; 1107 // Elements with [data-open] will reveal a plugin that supports it when clicked. 1108 $(document).on('click.zf.trigger', '[data-open]', function () { 1109 triggers($(this), 'open'); 1110 }); 1111 1112 // Elements with [data-close] will close a plugin that supports it when clicked. 1113 // If used without a value on [data-close], the event will bubble, allowing it to close a parent component. 1114 $(document).on('click.zf.trigger', '[data-close]', function () { 1115 var id = $(this).data('close'); 1116 if (id) { 1117 triggers($(this), 'close'); 1118 } else { 1119 $(this).trigger('close.zf.trigger'); 1120 } 1121 }); 1122 1123 // Elements with [data-toggle] will toggle a plugin that supports it when clicked. 1124 $(document).on('click.zf.trigger', '[data-toggle]', function () { 1125 triggers($(this), 'toggle'); 1126 }); 1127 1128 // Elements with [data-closable] will respond to close.zf.trigger events. 1129 $(document).on('close.zf.trigger', '[data-closable]', function (e) { 1130 e.stopPropagation(); 1131 var animation = $(this).data('closable'); 1132 1133 if (animation !== '') { 1134 Foundation.Motion.animateOut($(this), animation, function () { 1135 $(this).trigger('closed.zf'); 1136 }); 1137 } else { 1138 $(this).fadeOut().trigger('closed.zf'); 1139 } 1140 }); 1141 1142 $(document).on('focus.zf.trigger blur.zf.trigger', '[data-toggle-focus]', function () { 1143 var id = $(this).data('toggle-focus'); 1144 $('#' + id).triggerHandler('toggle.zf.trigger', [$(this)]); 1145 }); 1146 1147 /** 1148 * Fires once after all other scripts have loaded 1149 * @function 1150 * @private 1151 */ 1152 $(window).load(function () { 1153 checkListeners(); 1154 }); 1155 1156 function checkListeners() { 1157 eventsListener(); 1158 resizeListener(); 1159 scrollListener(); 1160 closemeListener(); 1161 } 1162 1163 //******** only fires this function once on load, if there's something to watch ******** 1164 function closemeListener(pluginName) { 1165 var yetiBoxes = $('[data-yeti-box]'), 1166 plugNames = ['dropdown', 'tooltip', 'reveal']; 1167 1168 if (pluginName) { 1169 if (typeof pluginName === 'string') { 1170 plugNames.push(pluginName); 1171 } else if (typeof pluginName === 'object' && typeof pluginName[0] === 'string') { 1172 plugNames.concat(pluginName); 1173 } else { 1174 console.error('Plugin names must be strings'); 1175 } 1176 } 1177 if (yetiBoxes.length) { 1178 var listeners = plugNames.map(function (name) { 1179 return 'closeme.zf.' + name; 1180 }).join(' '); 1181 1182 $(window).off(listeners).on(listeners, function (e, pluginId) { 1183 var plugin = e.namespace.split('.')[0]; 1184 var plugins = $('[data-' + plugin + ']').not('[data-yeti-box="' + pluginId + '"]'); 1185 1186 plugins.each(function () { 1187 var _this = $(this); 1188 1189 _this.triggerHandler('close.zf.trigger', [_this]); 1190 }); 1191 }); 1192 } 1193 } 1194 1195 function resizeListener(debounce) { 1196 var timer = void 0, 1197 $nodes = $('[data-resize]'); 1198 if ($nodes.length) { 1199 $(window).off('resize.zf.trigger').on('resize.zf.trigger', function (e) { 1200 if (timer) { 1201 clearTimeout(timer); 1202 } 1203 1204 timer = setTimeout(function () { 1205 1206 if (!MutationObserver) { 1207 //fallback for IE 9 1208 $nodes.each(function () { 1209 $(this).triggerHandler('resizeme.zf.trigger'); 1210 }); 1211 } 1212 //trigger all listening elements and signal a resize event 1213 $nodes.attr('data-events', "resize"); 1214 }, debounce || 10); //default time to emit resize event 1215 }); 1216 } 1217 } 1218 1219 function scrollListener(debounce) { 1220 var timer = void 0, 1221 $nodes = $('[data-scroll]'); 1222 if ($nodes.length) { 1223 $(window).off('scroll.zf.trigger').on('scroll.zf.trigger', function (e) { 1224 if (timer) { 1225 clearTimeout(timer); 1226 } 1227 1228 timer = setTimeout(function () { 1229 1230 if (!MutationObserver) { 1231 //fallback for IE 9 1232 $nodes.each(function () { 1233 $(this).triggerHandler('scrollme.zf.trigger'); 1234 }); 1235 } 1236 //trigger all listening elements and signal a scroll event 1237 $nodes.attr('data-events', "scroll"); 1238 }, debounce || 10); //default time to emit scroll event 1239 }); 1240 } 1241 } 1242 1243 function eventsListener() { 1244 if (!MutationObserver) { 1245 return false;
1246 } 1247 var nodes = document.querySelectorAll('[data-resize], [data-scroll], [data-mutate]'); 1248 1249 //element callback 1250 var listeningElementsMutation = function (mutationRecordsList) { 1251 var $target = $(mutationRecordsList[0].target); 1252 //trigger the event handler for the element depending on type 1253 switch ($target.attr("data-events")) { 1254 1255 case "resize": 1256 $target.triggerHandler('resizeme.zf.trigger', [$target]); 1257 break; 1258 1259 case "scroll": 1260 $target.triggerHandler('scrollme.zf.trigger', [$target, window.pageYOffset]); 1261 break; 1262 1263 // case "mutate" : 1264 // console.log('mutate', $target); 1265 // $target.triggerHandler('mutate.zf.trigger'); 1266 // 1267 // //make sure we don't get stuck in an infinite loop from sloppy codeing 1268 // if ($target.index('[data-mutate]') == $("[data-mutate]").length-1) { 1269 // domMutationObserver(); 1270 // } 1271 // break; 1272 1273 default: 1274 return false; 1275 //nothing 1276 } 1277 }; 1278 1279 if (nodes.length) { 1280 //for each element that needs to listen for resizing, scrolling, (or coming soon mutation) add a single observer 1281 for (var i = 0; i <= nodes.length - 1; i++) { 1282 var elementObserver = new MutationObserver(listeningElementsMutation); 1283 elementObserver.observe(nodes[i], { attributes: true, childList: false, characterData: false, subtree: false, attributeFilter: ["data-events"] }); 1284 } 1285 } 1286 } 1287 1288 // ------------------------------------ 1289 1290 // [PH] 1291 // Foundation.CheckWatchers = checkWatchers; 1292 Foundation.IHearYou = checkListeners; 1293 // Foundation.ISeeYou = scrollListener; 1294 // Foundation.IFeelYou = closemeListener; 1295}(jQuery); 1296 1297// function domMutationObserver(debounce) { 1298// // !!! This is coming soon and needs more work; not active !!! // 1299// var timer, 1300// nodes = document.querySelectorAll('[data-mutate]'); 1301// // 1302// if (nodes.length) { 1303// // var MutationObserver = (function () { 1304// // var prefixes = ['WebKit', 'Moz', 'O', 'Ms', '']; 1305// // for (var i=0; i < prefixes.length; i++) { 1306// // if (prefixes[i] + 'MutationObserver' in window) { 1307// // return window[prefixes[i] + 'MutationObserver']; 1308// // } 1309// // } 1310// // return false; 1311// // }()); 1312// 1313// 1314// //for the body, we need to listen for all changes effecting the style and class attributes 1315// var bodyObserver = new MutationObserver(bodyMutation); 1316// bodyObserver.observe(document.body, { attributes: true, childList: true, characterData: false, subtree:true, attributeFilter:["style", "class"]}); 1317// 1318// 1319// //body callback 1320// function bodyMutation(mutate) { 1321// //trigger all listening elements and signal a mutation event 1322// if (timer) { clearTimeout(timer); } 1323// 1324// timer = setTimeout(function() { 1325// bodyObserver.disconnect(); 1326// $('[data-mutate]').attr('data-events',"mutate"); 1327// }, debounce || 150); 1328// } 1329// } 1330// } 1331'use strict'; 1332 1333!function ($) { 1334 1335 function Timer(elem, options, cb) { 1336 var _this = this, 1337 duration = options.duration, 1338 //options is an object for easily adding features later. 1339 nameSpace = Object.keys(elem.data())[0] || 'timer', 1340 remain = -1, 1341 start, 1342 timer; 1343 1344 this.isPaused = false; 1345 1346 this.restart = function () { 1347 remain = -1; 1348 clearTimeout(timer); 1349 this.start(); 1350 }; 1351 1352 this.start = function () { 1353 this.isPaused = false; 1354 // if(!elem.data('paused')){ return false; }//maybe implement this sanity check if used for other things. 1355 clearTimeout(timer); 1356 remain = remain <= 0 ? duration : remain; 1357 elem.data('paused', false); 1358 start = Date.now(); 1359 timer = setTimeout(function () { 1360 if (options.infinite) { 1361 _this.restart(); //rerun the timer. 1362 } 1363 cb(); 1364 }, remain); 1365 elem.trigger('timerstart.zf.' + nameSpace); 1366 }; 1367 1368 this.pause = function () { 1369 this.isPaused = true; 1370 //if(elem.data('paused')){ return false; }//maybe implement this sanity check if used for other things. 1371 clearTimeout(timer); 1372 elem.data('paused', true); 1373 var end = Date.now(); 1374 remain = remain - (end - start); 1375 elem.trigger('timerpaused.zf.' + nameSpace); 1376 }; 1377 } 1378 1379 /** 1380 * Runs a callback function when images are fully loaded. 1381 * @param {Object} images - Image(s) to check if loaded. 1382 * @param {Func} callback - Function to execute when image is fully loaded. 1383 */ 1384 function onImagesLoaded(images, callback) { 1385 var self = this, 1386 unloaded = images.length; 1387 1388 if (unloaded === 0) { 1389 callback(); 1390 } 1391 1392 images.each(function () { 1393 if (this.complete) { 1394 singleImageLoaded(); 1395 }
1395 else if (typeof this.naturalWidth !== 'undefined' && this.naturalWidth > 0) { 1396 singleImageLoaded(); 1397 } else { 1398 $(this).one('load', function () { 1399 singleImageLoaded(); 1400 }); 1401 } 1402 }); 1403 1404 function singleImageLoaded() { 1405 unloaded--; 1406 if (unloaded === 0) { 1407 callback(); 1408 } 1409 } 1410 } 1411 1412 Foundation.Timer = Timer; 1413 Foundation.onImagesLoaded = onImagesLoaded; 1414}(jQuery); 1415//************************************************** 1416//**Work inspired by multiple jquery swipe plugins** 1417//**Done by Yohai Ararat *************************** 1418//************************************************** 1419(function ($) { 1420 1421 $.spotSwipe = { 1422 version: '1.0.0', 1423 enabled: 'ontouchstart' in document.documentElement, 1424 preventDefault: false, 1425 moveThreshold: 75, 1426 timeThreshold: 200 1427 }; 1428 1429 var startPosX, 1430 startPosY, 1431 startTime, 1432 elapsedTime, 1433 isMoving = false; 1434 1435 function onTouchEnd() { 1436 // alert(this); 1437 this.removeEventListener('touchmove', onTouchMove); 1438 this.removeEventListener('touchend', onTouchEnd); 1439 isMoving = false; 1440 } 1441 1442 function onTouchMove(e) { 1443 if ($.spotSwipe.preventDefault) { 1444 e.preventDefault(); 1445 } 1446 if (isMoving) { 1447 var x = e.touches[0].pageX; 1448 var y = e.touches[0].pageY; 1449 var dx = startPosX - x; 1450 var dy = startPosY - y; 1451 var dir; 1452 elapsedTime = new Date().getTime() - startTime; 1453 if (Math.abs(dx) >= $.spotSwipe.moveThreshold && elapsedTime <= $.spotSwipe.timeThreshold) { 1454 dir = dx > 0 ? 'left' : 'right'; 1455 } 1456 // else if(Math.abs(dy) >= $.spotSwipe.moveThreshold && elapsedTime <= $.spotSwipe.timeThreshold) { 1457 // dir = dy > 0 ? 'down' : 'up'; 1458 // } 1459 if (dir) { 1460 e.preventDefault(); 1461 onTouchEnd.call(this); 1462 $(this).trigger('swipe', dir).trigger('swipe' + dir); 1463 } 1464 } 1465 } 1466 1467 function onTouchStart(e) { 1468 if (e.touches.length == 1) { 1469 startPosX = e.touches[0].pageX; 1470 startPosY = e.touches[0].pageY; 1471 isMoving = true; 1472 startTime = new Date().getTime(); 1473 this.addEventListener('touchmove', onTouchMove, false); 1474 this.addEventListener('touchend', onTouchEnd, false); 1475 } 1476 } 1477 1478 function init() { 1479 this.addEventListener && this.addEventListener('touchstart', onTouchStart, false); 1480 } 1481 1482 function teardown() { 1483 this.removeEventListener('touchstart', onTouchStart); 1484 } 1485 1486 $.event.special.swipe = { setup: init }; 1487 1488 $.each(['left', 'up', 'down', 'right'], function () { 1489 $.event.special['swipe' + this] = { setup: function () { 1490 $(this).on('swipe', $.noop); 1491 } }; 1492 }); 1493})(jQuery); 1494/**************************************************** 1495 * Method for adding psuedo drag events to elements * 1496 ***************************************************/ 1497!function ($) { 1498 $.fn.addTouch = function () { 1499 this.each(function (i, el) { 1500 $(el).bind('touchstart touchmove touchend touchcancel', function () { 1501 //we pass the original event object because the jQuery event 1502 //object is normalized to w3c specs and does not provide the TouchList 1503 handleTouch(event); 1504 }); 1505 }); 1506 1507 var handleTouch = function (event) { 1508 var touches = event.changedTouches, 1509 first = touches[0], 1510 eventTypes = { 1511 touchstart: 'mousedown', 1512 touchmove: 'mousemove', 1513 touchend: 'mouseup' 1514 }, 1515 type = eventTypes[event.type], 1516 simulatedEvent; 1517 1518 if ('MouseEvent' in window && typeof window.MouseEvent === 'function') { 1519 simulatedEvent = new window.MouseEvent(type, { 1520 'bubbles': true, 1521 'cancelable': true, 1522 'screenX': first.screenX, 1523 'screenY': first.screenY, 1524 'clientX': first.clientX, 1525 'clientY': first.clientY 1526 }); 1527 } else { 1528 simulatedEvent = document.createEvent('MouseEvent'); 1529 simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0 /*left*/, null); 1530 } 1531 first.target.dispatchEvent(simulatedEvent); 1532 }; 1533 }; 1534}(jQuery); 1535 1536//********************************** 1537//**From the jQuery Mobile Library** 1538//**need to recreate functionality** 1539//**and try to improve if possible** 1540//********************************** 1541 1542/* Removing the jQuery function **** 1543************************************ 1544 1545(function( $, window, undefined ) { 1546 1547 var $document = $( document ),
1548 // supportTouch = $.mobile.support.touch, 1549 touchStartEvent = 'touchstart'//supportTouch ? "touchstart" : "mousedown", 1550 touchStopEvent = 'touchend'//supportTouch ? "touchend" : "mouseup", 1551 touchMoveEvent = 'touchmove'//supportTouch ? "touchmove" : "mousemove"; 1552 1553 // setup new event shortcuts 1554 $.each( ( "touchstart touchmove touchend " + 1555 "swipe swipeleft swiperight" ).split( " " ), function( i, name ) { 1556 1557 $.fn[ name ] = function( fn ) { 1558 return fn ? this.bind( name, fn ) : this.trigger( name ); 1559 }; 1560 1561 // jQuery < 1.8 1562 if ( $.attrFn ) { 1563 $.attrFn[ name ] = true; 1564 } 1565 }); 1566 1567 function triggerCustomEvent( obj, eventType, event, bubble ) { 1568 var originalType = event.type; 1569 event.type = eventType; 1570 if ( bubble ) { 1571 $.event.trigger( event, undefined, obj ); 1572 } else { 1573 $.event.dispatch.call( obj, event ); 1574 } 1575 event.type = originalType; 1576 } 1577 1578 // also handles taphold 1579 1580 // Also handles swipeleft, swiperight 1581 $.event.special.swipe = { 1582 1583 // More than this horizontal displacement, and we will suppress scrolling. 1584 scrollSupressionThreshold: 30, 1585 1586 // More time than this, and it isn't a swipe. 1587 durationThreshold: 1000, 1588 1589 // Swipe horizontal displacement must be more than this. 1590 horizontalDistanceThreshold: window.devicePixelRatio >= 2 ? 15 : 30, 1591 1592 // Swipe vertical displacement must be less than this. 1593 verticalDistanceThreshold: window.devicePixelRatio >= 2 ? 15 : 30, 1594 1595 getLocation: function ( event ) { 1596 var winPageX = window.pageXOffset, 1597 winPageY = window.pageYOffset, 1598 x = event.clientX, 1599 y = event.clientY; 1600 1601 if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) || 1602 event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) { 1603 1604 // iOS4 clientX/clientY have the value that should have been 1605 // in pageX/pageY. While pageX/page/ have the value 0 1606 x = x - winPageX; 1607 y = y - winPageY; 1608 } else if ( y < ( event.pageY - winPageY) || x < ( event.pageX - winPageX ) ) { 1609 1610 // Some Android browsers have totally bogus values for clientX/Y 1611 // when scrolling/zooming a page. Detectable since clientX/clientY 1612 // should never be smaller than pageX/pageY minus page scroll 1613 x = event.pageX - winPageX; 1614 y = event.pageY - winPageY; 1615 } 1616 1617 return { 1618 x: x, 1619 y: y 1620 }; 1621 }, 1622 1623 start: function( event ) { 1624 var data = event.originalEvent.touches ? 1625 event.originalEvent.touches[ 0 ] : event, 1626 location = $.event.special.swipe.getLocation( data ); 1627 return { 1628 time: ( new Date() ).getTime(), 1629 coords: [ location.x, location.y ], 1630 origin: $( event.target ) 1631 }; 1632 }, 1633 1634 stop: function( event ) { 1635 var data = event.originalEvent.touches ? 1636 event.originalEvent.touches[ 0 ] : event, 1637 location = $.event.special.swipe.getLocation( data ); 1638 return { 1639 time: ( new Date() ).getTime(), 1640 coords: [ location.x, location.y ] 1641 }; 1642 }, 1643 1644 handleSwipe: function( start, stop, thisObject, origTarget ) { 1645 if ( stop.time - start.time < $.event.special.swipe.durationThreshold && 1646 Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold && 1647 Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) { 1648 var direction = start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight"; 1649 1650 triggerCustomEvent( thisObject, "swipe", $.Event( "swipe", { target: origTarget, swipestart: start, swipestop: stop }), true ); 1651 triggerCustomEvent( thisObject, direction,$.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true ); 1652 return true; 1653 } 1654 return false; 1655 1656 }, 1657 1658 // This serves as a flag to ensure that at most one swipe event event is 1659 // in work at any given time 1660 eventInProgress: false, 1661 1662 setup: function() { 1663 var events, 1664 thisObject = this, 1665 $this = $( thisObject ), 1666 context = {}; 1667 1668 // Retrieve the events data for this element and add the swipe context 1669 events = $.data( this, "mobile-events" ); 1670 if ( !events ) { 1671 events = { length: 0 }; 1672 $.data( this, "mobile-events", events ); 1673 } 1674 events.length++; 1675 events.swipe = context; 1676 1677 context.start = function( event ) { 1678 1679 // Bail if we're already working on a swipe event 1680 if ( $.event.special.swipe.eventInProgress ) { 1681 return; 1682 } 1683 $.event.special.swipe.eventInProgress = true; 1684 1685 var stop, 1686 start = $.event.special.swipe.start( event ), 1687 origTarget = event.target, 1688 emitted = false;
1689 1690 context.move = function( event ) { 1691 if ( !start || event.isDefaultPrevented() ) { 1692 return; 1693 } 1694 1695 stop = $.event.special.swipe.stop( event ); 1696 if ( !emitted ) { 1697 emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget ); 1698 if ( emitted ) { 1699 1700 // Reset the context to make way for the next swipe event 1701 $.event.special.swipe.eventInProgress = false; 1702 } 1703 } 1704 // prevent scrolling 1705 if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) { 1706 event.preventDefault(); 1707 } 1708 }; 1709 1710 context.stop = function() { 1711 emitted = true; 1712 1713 // Reset the context to make way for the next swipe event 1714 $.event.special.swipe.eventInProgress = false; 1715 $document.off( touchMoveEvent, context.move ); 1716 context.move = null; 1717 }; 1718 1719 $document.on( touchMoveEvent, context.move ) 1720 .one( touchStopEvent, context.stop ); 1721 }; 1722 $this.on( touchStartEvent, context.start ); 1723 }, 1724 1725 teardown: function() { 1726 var events, context; 1727 1728 events = $.data( this, "mobile-events" ); 1729 if ( events ) { 1730 context = events.swipe; 1731 delete events.swipe; 1732 events.length--; 1733 if ( events.length === 0 ) { 1734 $.removeData( this, "mobile-events" ); 1735 } 1736 } 1737 1738 if ( context ) { 1739 if ( context.start ) { 1740 $( this ).off( touchStartEvent, context.start ); 1741 } 1742 if ( context.move ) { 1743 $document.off( touchMoveEvent, context.move ); 1744 } 1745 if ( context.stop ) { 1746 $document.off( touchStopEvent, context.stop ); 1747 } 1748 } 1749 } 1750 }; 1751 $.each({ 1752 swipeleft: "swipe.left", 1753 swiperight: "swipe.right" 1754 }, function( event, sourceEvent ) { 1755 1756 $.event.special[ event ] = { 1757 setup: function() { 1758 $( this ).bind( sourceEvent, $.noop ); 1759 }, 1760 teardown: function() { 1761 $( this ).unbind( sourceEvent ); 1762 } 1763 }; 1764 }); 1765})( jQuery, this ); 1766*/ 1767'use strict'; 1768 1769var _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; }; }(); 1770 1771function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1772 1773!function ($) { 1774 1775 /** 1776 * Abide module. 1777 * @module foundation.abide 1778 */ 1779 1780 var Abide = function () { 1781 /** 1782 * Creates a new instance of Abide. 1783 * @class 1784 * @fires Abide#init 1785 * @param {Object} element - jQuery object to add the trigger to. 1786 * @param {Object} options - Overrides to the default plugin settings. 1787 */ 1788 1789 function Abide(element) { 1790 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 1791 1792 _classCallCheck(this, Abide); 1793 1794 this.$element = element; 1795 this.options = $.extend({}, Abide.defaults, this.$element.data(), options); 1796 1797 this._init(); 1798 1799 Foundation.registerPlugin(this, 'Abide'); 1800 } 1801 1802 /** 1803 * Initializes the Abide plugin and calls functions to get Abide functioning on load. 1804 * @private 1805 */ 1806 1807 1808 _createClass(Abide, [{ 1809 key: '_init', 1810 value: function _init() { 1811 this.$inputs = this.$element.find('input, textarea, select'); 1812 1813 this._events(); 1814 } 1815 1816 /** 1817 * Initializes events for Abide. 1818 * @private 1819 */ 1820 1821 }, { 1822 key: '_events', 1823 value: function _events() { 1824 var _this2 = this; 1825 1826 this.$element.off('.abide').on('reset.zf.abide', function () { 1827 _this2.resetForm(); 1828 }).on('submit.zf.abide', function () { 1829 return _this2.validateForm(); 1830 }); 1831 1832 if (this.options.validateOn === 'fieldChange') { 1833 this.$inputs.off('change.zf.abide').on('change.zf.abide', function (e) { 1834 _this2.validateInput($(e.target)); 1835 }); 1836 } 1837 1838 if (this.options.liveValidate) { 1839 this.$inputs.off('input.zf.abide').on('input.zf.abide', function (e) { 1840 _this2.validateInput($(e.target)); 1841 }); 1842 } 1843 } 1844 1845 /** 1846 * Calls necessary functions to update Abide upon DOM change 1847 * @private 1848 */ 1849 1850 }, {
vendor: 4,857 bytes, lines 1851-2011
1851 key: '_reflow', 1852 value: function _reflow() { 1853 this._init(); 1854 } 1855 1856 /** 1857 * Checks whether or not a form element has the required attribute and if it's checked or not 1858 * @param {Object} element - jQuery object to check for required attribute 1859 * @returns {Boolean} Boolean value depends on whether or not attribute is checked or empty 1860 */ 1861 1862 }, { 1863 key: 'requiredCheck', 1864 value: function requiredCheck($el) { 1865 if (!$el.attr('required')) return true; 1866 1867 var isGood = true; 1868 1869 switch ($el[0].type) { 1870 case 'checkbox': 1871 isGood = $el[0].checked; 1872 break; 1873 1874 case 'select': 1875 case 'select-one': 1876 case 'select-multiple': 1877 var opt = $el.find('option:selected'); 1878 if (!opt.length || !opt.val()) isGood = false; 1879 break; 1880 1881 default: 1882 if (!$el.val() || !$el.val().length) isGood = false; 1883 } 1884 1885 return isGood; 1886 } 1887 1888 /** 1889 * Based on $el, get the first element with selector in this order: 1890 * 1. The element's direct sibling('s). 1891 * 3. The element's parent's children. 1892 * 1893 * This allows for multiple form errors per input, though if none are found, no form errors will be shown. 1894 * 1895 * @param {Object} $el - jQuery object to use as reference to find the form error selector. 1896 * @returns {Object} jQuery object with the selector. 1897 */ 1898 1899 }, { 1900 key: 'findFormError', 1901 value: function findFormError($el) { 1902 var $error = $el.siblings(this.options.formErrorSelector); 1903 1904 if (!$error.length) { 1905 $error = $el.parent().find(this.options.formErrorSelector); 1906 } 1907 1908 return $error; 1909 } 1910 1911 /** 1912 * Get the first element in this order: 1913 * 2. The <label> with the attribute `[for="someInputId"]` 1914 * 3. The `.closest()` <label> 1915 * 1916 * @param {Object} $el - jQuery object to check for required attribute 1917 * @returns {Boolean} Boolean value depends on whether or not attribute is checked or empty 1918 */ 1919 1920 }, { 1921 key: 'findLabel', 1922 value: function findLabel($el) { 1923 var id = $el[0].id; 1924 var $label = this.$element.find('label[for="' + id + '"]'); 1925 1926 if (!$label.length) { 1927 return $el.closest('label'); 1928 } 1929 1930 return $label; 1931 } 1932 1933 /** 1934 * Get the set of labels associated with a set of radio els in this order 1935 * 2. The <label> with the attribute `[for="someInputId"]` 1936 * 3. The `.closest()` <label> 1937 * 1938 * @param {Object} $el - jQuery object to check for required attribute 1939 * @returns {Boolean} Boolean value depends on whether or not attribute is checked or empty 1940 */ 1941 1942 }, { 1943 key: 'findRadioLabels', 1944 value: function findRadioLabels($els) { 1945 var _this3 = this; 1946 1947 var labels = $els.map(function (i, el) { 1948 var id = el.id; 1949 var $label = _this3.$element.find('label[for="' + id + '"]'); 1950 1951 if (!$label.length) { 1952 $label = $(el).closest('label'); 1953 } 1954 return $label[0]; 1955 }); 1956 1957 return $(labels); 1958 } 1959 1960 /** 1961 * Adds the CSS error class as specified by the Abide settings to the label, input, and the form 1962 * @param {Object} $el - jQuery object to add the class to 1963 */ 1964 1965 }, { 1966 key: 'addErrorClasses', 1967 value: function addErrorClasses($el) { 1968 var $label = this.findLabel($el); 1969 var $formError = this.findFormError($el); 1970 1971 if ($label.length) { 1972 $label.addClass(this.options.labelErrorClass); 1973 } 1974 1975 if ($formError.length) { 1976 $formError.addClass(this.options.formErrorClass); 1977 } 1978 1979 $el.addClass(this.options.inputErrorClass).attr('data-invalid', ''); 1980 } 1981 1982 /** 1983 * Remove CSS error classes etc from an entire radio button group 1984 * @param {String} groupName - A string that specifies the name of a radio button group 1985 * 1986 */ 1987 1988 }, { 1989 key: 'removeRadioErrorClasses', 1990 value: function removeRadioErrorClasses(groupName) { 1991 var $els = this.$element.find(':radio[name="' + groupName + '"]'); 1992 var $labels = this.findRadioLabels($els); 1993 var $formErrors = this.findFormError($els); 1994 1995 if ($labels.length) { 1996 $labels.removeClass(this.options.labelErrorClass); 1997 } 1998 1999 if ($formErrors.length) { 2000 $formErrors.removeClass(this.options.formErrorClass); 2001 } 2002 2003 $els.removeClass(this.options.inputErrorClass).removeAttr('data-invalid'); 2004 } 2005 2006 /** 2007 * Removes CSS error class as specified by the Abide settings from the label, input, and the form 2008 * @param {Object} $el - jQuery object to remove the class from 2009 */ 2010 2011 }, {
2012 key: 'removeErrorClasses', 2013 value: function removeErrorClasses($el) { 2014 // radios need to clear all of the els 2015 if ($el[0].type == 'radio') { 2016 return this.removeRadioErrorClasses($el.attr('name')); 2017 } 2018 2019 var $label = this.findLabel($el); 2020 var $formError = this.findFormError($el); 2021 2022 if ($label.length) { 2023 $label.removeClass(this.options.labelErrorClass); 2024 } 2025 2026 if ($formError.length) { 2027 $formError.removeClass(this.options.formErrorClass); 2028 } 2029 2030 $el.removeClass(this.options.inputErrorClass).removeAttr('data-invalid'); 2031 } 2032 2033 /** 2034 * Goes through a form to find inputs and proceeds to validate them in ways specific to their type 2035 * @fires Abide#invalid 2036 * @fires Abide#valid 2037 * @param {Object} element - jQuery object to validate, should be an HTML input 2038 * @returns {Boolean} goodToGo - If the input is valid or not. 2039 */ 2040 2041 }, { 2042 key: 'validateInput', 2043 value: function validateInput($el) { 2044 var clearRequire = this.requiredCheck($el), 2045 validated = false, 2046 customValidator = true, 2047 validator = $el.attr('data-validator'), 2048 equalTo = true; 2049 2050 // don't validate ignored inputs or hidden inputs 2051 if ($el.is('[data-abide-ignore]') || $el.is('[type="hidden"]')) { 2052 return true; 2053 } 2054 2055 switch ($el[0].type) { 2056 case 'radio': 2057 validated = this.validateRadio($el.attr('name')); 2058 break; 2059 2060 case 'checkbox': 2061 validated = clearRequire; 2062 break; 2063 2064 case 'select': 2065 case 'select-one': 2066 case 'select-multiple': 2067 validated = clearRequire; 2068 break; 2069 2070 default: 2071 validated = this.validateText($el); 2072 } 2073 2074 if (validator) { 2075 customValidator = this.matchValidation($el, validator, $el.attr('required')); 2076 } 2077 2078 if ($el.attr('data-equalto')) { 2079 equalTo = this.options.validators.equalTo($el); 2080 } 2081 2082 var goodToGo = [clearRequire, validated, customValidator, equalTo].indexOf(false) === -1; 2083 var message = (goodToGo ? 'valid' : 'invalid') + '.zf.abide'; 2084 2085 this[goodToGo ? 'removeErrorClasses' : 'addErrorClasses']($el); 2086 2087 /** 2088 * Fires when the input is done checking for validation. Event trigger is either `valid.zf.abide` or `invalid.zf.abide` 2089 * Trigger includes the DOM element of the input. 2090 * @event Abide#valid 2091 * @event Abide#invalid 2092 */ 2093 $el.trigger(message, [$el]); 2094 2095 return goodToGo; 2096 } 2097 2098 /** 2099 * Goes through a form and if there are any invalid inputs, it will display the form error element 2100 * @returns {Boolean} noError - true if no errors were detected... 2101 * @fires Abide#formvalid 2102 * @fires Abide#forminvalid 2103 */ 2104 2105 }, { 2106 key: 'validateForm', 2107 value: function validateForm() { 2108 var acc = []; 2109 var _this = this; 2110 2111 this.$inputs.each(function () { 2112 acc.push(_this.validateInput($(this))); 2113 }); 2114 2115 var noError = acc.indexOf(false) === -1; 2116 2117 this.$element.find('[data-abide-error]').css('display', noError ? 'none' : 'block'); 2118 2119 /** 2120 * Fires when the form is finished validating. Event trigger is either `formvalid.zf.abide` or `forminvalid.zf.abide`. 2121 * Trigger includes the element of the form. 2122 * @event Abide#formvalid 2123 * @event Abide#forminvalid 2124 */ 2125 this.$element.trigger((noError ? 'formvalid' : 'forminvalid') + '.zf.abide', [this.$element]); 2126 2127 return noError; 2128 } 2129 2130 /** 2131 * Determines whether or a not a text input is valid based on the pattern specified in the attribute. If no matching pattern is found, returns true. 2132 * @param {Object} $el - jQuery object to validate, should be a text input HTML element 2133 * @param {String} pattern - string value of one of the RegEx patterns in Abide.options.patterns 2134 * @returns {Boolean} Boolean value depends on whether or not the input value matches the pattern specified 2135 */ 2136 2137 }, {
2138 key: 'validateText', 2139 value: function validateText($el, pattern) { 2140 // A pattern can be passed to this function, or it will be infered from the input's "pattern" attribute, or it's "type" attribute 2141 pattern = pattern || $el.attr('pattern') || $el.attr('type'); 2142 var inputText = $el.val(); 2143 var valid = false; 2144 2145 if (inputText.length) { 2146 // If the pattern attribute on the element is in Abide's list of patterns, then test that regexp 2147 if (this.options.patterns.hasOwnProperty(pattern)) { 2148 valid = this.options.patterns[pattern].test(inputText); 2149 } 2150 // If the pattern name isn't also the type attribute of the field, then test it as a regexp 2151 else if (pattern !== $el.attr('type')) { 2152 valid = new RegExp(pattern).test(inputText); 2153 } else { 2154 valid = true; 2155 } 2156 } 2157 // An empty field is valid if it's not required 2158 else if (!$el.prop('required')) { 2159 valid = true; 2160 } 2161 2162 return valid; 2163 } 2164 2165 /** 2166 * Determines whether or a not a radio input is valid based on whether or not it is required and selected. Although the function targets a single `<input>`, it validates by checking the `required` and `checked` properties of all radio buttons in its group. 2167 * @param {String} groupName - A string that specifies the name of a radio button group 2168 * @returns {Boolean} Boolean value depends on whether or not at least one radio input has been selected (if it's required) 2169 */ 2170 2171 }, { 2172 key: 'validateRadio', 2173 value: function validateRadio(groupName) { 2174 // If at least one radio in the group has the `required` attribute, the group is considered required 2175 // Per W3C spec, all radio buttons in a group should have `required`, but we're being nice 2176 var $group = this.$element.find(':radio[name="' + groupName + '"]'); 2177 var valid = false, 2178 required = false; 2179 2180 // For the group to be required, at least one radio needs to be required 2181 $group.each(function (i, e) { 2182 if ($(e).attr('required')) { 2183 required = true; 2184 } 2185 }); 2186 if (!required) valid = true; 2187 2188 if (!valid) { 2189 // For the group to be valid, at least one radio needs to be checked 2190 $group.each(function (i, e) { 2191 if ($(e).prop('checked')) { 2192 valid = true; 2193 } 2194 }); 2195 }; 2196 2197 return valid; 2198 } 2199 2200 /** 2201 * Determines if a selected input passes a custom validation function. Multiple validations can be used, if passed to the element with `data-validator="foo bar baz"` in a space separated listed. 2202 * @param {Object} $el - jQuery input element. 2203 * @param {String} validators - a string of function names matching functions in the Abide.options.validators object. 2204 * @param {Boolean} required - self explanatory? 2205 * @returns {Boolean} - true if validations passed. 2206 */ 2207 2208 }, { 2209 key: 'matchValidation', 2210 value: function matchValidation($el, validators, required) { 2211 var _this4 = this; 2212 2213 required = required ? true : false; 2214 2215 var clear = validators.split(' ').map(function (v) { 2216 return _this4.options.validators[v]($el, required, $el.parent()); 2217 }); 2218 return clear.indexOf(false) === -1; 2219 } 2220 2221 /** 2222 * Resets form inputs and styles 2223 * @fires Abide#formreset 2224 */ 2225 2226 }, { 2227 key: 'resetForm', 2228 value: function resetForm() { 2229 var $form = this.$element, 2230 opts = this.options; 2231 2232 $('.' + opts.labelErrorClass, $form).not('small').removeClass(opts.labelErrorClass); 2233 $('.' + opts.inputErrorClass, $form).not('small').removeClass(opts.inputErrorClass); 2234 $(opts.formErrorSelector + '.' + opts.formErrorClass).removeClass(opts.formErrorClass); 2235 $form.find('[data-abide-error]').css('display', 'none'); 2236 $(':input', $form).not(':button, :submit, :reset, :hidden, :radio, :checkbox, [data-abide-ignore]').val('').removeAttr('data-invalid'); 2237 $(':input:radio', $form).not('[data-abide-ignore]').prop('checked', false).removeAttr('data-invalid'); 2238 $(':input:checkbox', $form).not('[data-abide-ignore]').prop('checked', false).removeAttr('data-invalid'); 2239 /** 2240 * Fires when the form has been reset. 2241 * @event Abide#formreset 2242 */ 2243 $form.trigger('formreset.zf.abide', [$form]); 2244 } 2245 2246 /** 2247 * Destroys an instance of Abide. 2248 * Removes error styles and classes from elements, without resetting their values. 2249 */ 2250 2251 }, {
2252 key: 'destroy', 2253 value: function destroy() { 2254 var _this = this; 2255 this.$element.off('.abide').find('[data-abide-error]').css('display', 'none'); 2256 2257 this.$inputs.off('.abide').each(function () { 2258 _this.removeErrorClasses($(this)); 2259 }); 2260 2261 Foundation.unregisterPlugin(this); 2262 } 2263 }]); 2264 2265 return Abide; 2266 }(); 2267 2268 /** 2269 * Default settings for plugin 2270 */ 2271 2272 2273 Abide.defaults = { 2274 /** 2275 * The default event to validate inputs. Checkboxes and radios validate immediately. 2276 * Remove or change this value for manual validation. 2277 * @option 2278 * @example 'fieldChange' 2279 */ 2280 validateOn: 'fieldChange', 2281 2282 /** 2283 * Class to be applied to input labels on failed validation. 2284 * @option 2285 * @example 'is-invalid-label' 2286 */ 2287 labelErrorClass: 'is-invalid-label', 2288 2289 /** 2290 * Class to be applied to inputs on failed validation. 2291 * @option 2292 * @example 'is-invalid-input' 2293 */ 2294 inputErrorClass: 'is-invalid-input', 2295 2296 /** 2297 * Class selector to use to target Form Errors for show/hide. 2298 * @option 2299 * @example '.form-error' 2300 */ 2301 formErrorSelector: '.form-error', 2302 2303 /** 2304 * Class added to Form Errors on failed validation. 2305 * @option 2306 * @example 'is-visible' 2307 */ 2308 formErrorClass: 'is-visible', 2309 2310 /** 2311 * Set to true to validate text inputs on any value change. 2312 * @option 2313 * @example false 2314 */ 2315 liveValidate: false, 2316 2317 patterns: { 2318 alpha: /^[a-zA-Z]+$/, 2319 alpha_numeric: /^[a-zA-Z0-9]+$/, 2320 integer: /^[-+]?\d+$/, 2321 number: /^[-+]?\d*(?:[\.\,]\d+)?$/, 2322 2323 // amex, visa, diners 2324 card: /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/, 2325 cvv: /^([0-9]){3,4}$/, 2326 2327 // http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address 2328 email: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/,
2329 2330 url: /^(https?|ftp|file|ssh):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/, 2331 // abc.de 2332 domain: /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,8}$/, 2333 2334 datetime: /^([0-2][0-9]{3})\-([0-1][0-9])\-([0-3][0-9])T([0-5][0-9])\:([0-5][0-9])\:([0-5][0-9])(Z|([\-\+]([0-1][0-9])\:00))$/, 2335 // YYYY-MM-DD 2336 date: /(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))$/, 2337 // HH:MM:SS 2338 time: /^(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}$/, 2339 dateISO: /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/, 2340 // MM/DD/YYYY 2341 month_day_year: /^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]\d{4}$/, 2342 // DD/MM/YYYY 2343 day_month_year: /^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]\d{4}$/, 2344 2345 // #FFF or #FFFFFF 2346 color: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/ 2347 }, 2348 2349 /** 2350 * Optional validation functions to be used. `equalTo` being the only default included function. 2351 * Functions should return only a boolean if the input is valid or not. Functions are given the following arguments: 2352 * el : The jQuery element to validate. 2353 * required : Boolean value of the required attribute be present or not. 2354 * parent : The direct parent of the input. 2355 * @option 2356 */ 2357 validators: { 2358 equalTo: function (el, required, parent) { 2359 return $('#' + el.attr('data-equalto')).val() === el.val(); 2360 } 2361 } 2362 }; 2363 2364 // Window exports 2365 Foundation.plugin(Abide, 'Abide'); 2366}(jQuery); 2367'use strict'; 2368 2369var _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; }; }(); 2370 2371function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 2372 2373!function ($) { 2374 2375 /** 2376 * Accordion module. 2377 * @module foundation.accordion 2378 * @requires foundation.util.keyboard 2379 * @requires foundation.util.motion 2380 */ 2381 2382 var Accordion = function () { 2383 /** 2384 * Creates a new instance of an accordion. 2385 * @class 2386 * @fires Accordion#init 2387 * @param {jQuery} element - jQuery object to make into an accordion. 2388 * @param {Object} options - a plain object with settings to override the default options. 2389 */ 2390 2391 function Accordion(element, options) { 2392 _classCallCheck(this, Accordion); 2393 2394 this.$element = element; 2395 this.options = $.extend({}, Accordion.defaults, this.$element.data(), options); 2396 2397 this._init(); 2398 2399 Foundation.registerPlugin(this, 'Accordion'); 2400 Foundation.Keyboard.register('Accordion', { 2401 'ENTER': 'toggle', 2402 'SPACE': 'toggle', 2403 'ARROW_DOWN': 'next', 2404 'ARROW_UP': 'previous' 2405 }); 2406 } 2407 2408 /** 2409 * Initializes the accordion by animating the preset active pane(s). 2410 * @private 2411 */ 2412 2413 2414 _createClass(Accordion, [{ 2415 key: '_init', 2416 value: function _init() { 2417 this.$element.attr('role', 'tablist'); 2418 this.$tabs = this.$element.children('li, [data-accordion-item]'); 2419 2420 this.$tabs.each(function (idx, el) { 2421 var $el = $(el), 2422 $content = $el.children('[data-tab-content]'), 2423 id = $content[0].id || Foundation.GetYoDigits(6, 'accordion'), 2424 linkId = el.id || id + '-label'; 2425 2426 $el.find('a:first').attr({ 2427 'aria-controls': id, 2428 'role': 'tab', 2429 'id': linkId, 2430 'aria-expanded': false, 2431 'aria-selected': false 2432 }); 2433 2434 $content.attr({ 'role': 'tabpanel', 'aria-labelledby': linkId, 'aria-hidden': true, 'id': id }); 2435 }); 2436 var $initActive = this.$element.find('.is-active').children('[data-tab-content]'); 2437 if ($initActive.length) { 2438 this.down($initActive, true); 2439 } 2440 this._events(); 2441 } 2442 2443 /** 2444 * Adds event handlers for items within the accordion. 2445 * @private 2446 */ 2447 2448 }, {
2449 key: '_events', 2450 value: function _events() { 2451 var _this = this; 2452 2453 this.$tabs.each(function () { 2454 var $elem = $(this); 2455 var $tabContent = $elem.children('[data-tab-content]'); 2456 if ($tabContent.length) { 2457 $elem.children('a').off('click.zf.accordion keydown.zf.accordion').on('click.zf.accordion', function (e) { 2458 // $(this).children('a').on('click.zf.accordion', function(e) { 2459 e.preventDefault(); 2460 if ($elem.hasClass('is-active')) { 2461 if (_this.options.allowAllClosed || $elem.siblings().hasClass('is-active')) { 2462 _this.up($tabContent); 2463 } 2464 } else { 2465 _this.down($tabContent); 2466 } 2467 }).on('keydown.zf.accordion', function (e) { 2468 Foundation.Keyboard.handleKey(e, 'Accordion', { 2469 toggle: function () { 2470 _this.toggle($tabContent); 2471 }, 2472 next: function () { 2473 var $a = $elem.next().find('a').focus(); 2474 if (!_this.options.multiExpand) { 2475 $a.trigger('click.zf.accordion'); 2476 } 2477 }, 2478 previous: function () { 2479 var $a = $elem.prev().find('a').focus(); 2480 if (!_this.options.multiExpand) { 2481 $a.trigger('click.zf.accordion'); 2482 } 2483 }, 2484 handled: function () { 2485 e.preventDefault(); 2486 e.stopPropagation(); 2487 } 2488 }); 2489 }); 2490 } 2491 }); 2492 } 2493 2494 /** 2495 * Toggles the selected content pane's open/close state. 2496 * @param {jQuery} $target - jQuery object of the pane to toggle. 2497 * @function 2498 */ 2499 2500 }, { 2501 key: 'toggle', 2502 value: function toggle($target) { 2503 if ($target.parent().hasClass('is-active')) { 2504 if (this.options.allowAllClosed || $target.parent().siblings().hasClass('is-active')) { 2505 this.up($target); 2506 } else { 2507 return; 2508 } 2509 } else { 2510 this.down($target); 2511 } 2512 } 2513 2514 /** 2515 * Opens the accordion tab defined by `$target`. 2516 * @param {jQuery} $target - Accordion pane to open. 2517 * @param {Boolean} firstTime - flag to determine if reflow should happen. 2518 * @fires Accordion#down 2519 * @function 2520 */ 2521 2522 }, { 2523 key: 'down', 2524 value: function down($target, firstTime) { 2525 var _this2 = this; 2526 2527 if (!this.options.multiExpand && !firstTime) { 2528 var $currentActive = this.$element.children('.is-active').children('[data-tab-content]'); 2529 if ($currentActive.length) { 2530 this.up($currentActive); 2531 } 2532 } 2533 2534 $target.attr('aria-hidden', false).parent('[data-tab-content]').addBack().parent().addClass('is-active'); 2535 2536 $target.slideDown(this.options.slideSpeed, function () { 2537 /** 2538 * Fires when the tab is done opening. 2539 * @event Accordion#down 2540 */ 2541 _this2.$element.trigger('down.zf.accordion', [$target]); 2542 }); 2543 2544 $('#' + $target.attr('aria-labelledby')).attr({ 2545 'aria-expanded': true, 2546 'aria-selected': true 2547 }); 2548 } 2549 2550 /** 2551 * Closes the tab defined by `$target`. 2552 * @param {jQuery} $target - Accordion tab to close. 2553 * @fires Accordion#up 2554 * @function 2555 */ 2556 2557 }, { 2558 key: 'up', 2559 value: function up($target) { 2560 var $aunts = $target.parent().siblings(), 2561 _this = this; 2562 var canClose = this.options.multiExpand ? $aunts.hasClass('is-active') : $target.parent().hasClass('is-active'); 2563 2564 if (!this.options.allowAllClosed && !canClose) { 2565 return; 2566 } 2567 2568 // Foundation.Move(this.options.slideSpeed, $target, function(){ 2569 $target.slideUp(_this.options.slideSpeed, function () { 2570 /** 2571 * Fires when the tab is done collapsing up. 2572 * @event Accordion#up 2573 */ 2574 _this.$element.trigger('up.zf.accordion', [$target]); 2575 }); 2576 // }); 2577 2578 $target.attr('aria-hidden', true).parent().removeClass('is-active'); 2579 2580 $('#' + $target.attr('aria-labelledby')).attr({ 2581 'aria-expanded': false, 2582 'aria-selected': false 2583 }); 2584 } 2585 2586 /** 2587 * Destroys an instance of an accordion. 2588 * @fires Accordion#destroyed 2589 * @function 2590 */ 2591 2592 }, {
2593 key: 'destroy', 2594 value: function destroy() { 2595 this.$element.find('[data-tab-content]').stop(true).slideUp(0).css('display', ''); 2596 this.$element.find('a').off('.zf.accordion'); 2597 2598 Foundation.unregisterPlugin(this); 2599 } 2600 }]); 2601 2602 return Accordion; 2603 }(); 2604 2605 Accordion.defaults = { 2606 /** 2607 * Amount of time to animate the opening of an accordion pane. 2608 * @option 2609 * @example 250 2610 */ 2611 slideSpeed: 250, 2612 /** 2613 * Allow the accordion to have multiple open panes. 2614 * @option 2615 * @example false 2616 */ 2617 multiExpand: false, 2618 /** 2619 * Allow the accordion to close all panes. 2620 * @option 2621 * @example false 2622 */ 2623 allowAllClosed: false 2624 }; 2625 2626 // Window exports 2627 Foundation.plugin(Accordion, 'Accordion'); 2628}(jQuery); 2629'use strict'; 2630 2631var _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; }; }(); 2632 2633function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 2634 2635!function ($) { 2636 2637 /** 2638 * AccordionMenu module. 2639 * @module foundation.accordionMenu 2640 * @requires foundation.util.keyboard 2641 * @requires foundation.util.motion 2642 * @requires foundation.util.nest 2643 */ 2644 2645 var AccordionMenu = function () { 2646 /** 2647 * Creates a new instance of an accordion menu. 2648 * @class 2649 * @fires AccordionMenu#init 2650 * @param {jQuery} element - jQuery object to make into an accordion menu. 2651 * @param {Object} options - Overrides to the default plugin settings. 2652 */ 2653 2654 function AccordionMenu(element, options) { 2655 _classCallCheck(this, AccordionMenu); 2656 2657 this.$element = element; 2658 this.options = $.extend({}, AccordionMenu.defaults, this.$element.data(), options); 2659 2660 Foundation.Nest.Feather(this.$element, 'accordion'); 2661 2662 this._init(); 2663 2664 Foundation.registerPlugin(this, 'AccordionMenu'); 2665 Foundation.Keyboard.register('AccordionMenu', { 2666 'ENTER': 'toggle', 2667 'SPACE': 'toggle', 2668 'ARROW_RIGHT': 'open', 2669 'ARROW_UP': 'up', 2670 'ARROW_DOWN': 'down', 2671 'ARROW_LEFT': 'close', 2672 'ESCAPE': 'closeAll', 2673 'TAB': 'down', 2674 'SHIFT_TAB': 'up' 2675 }); 2676 } 2677 2678 /** 2679 * Initializes the accordion menu by hiding all nested menus. 2680 * @private 2681 */ 2682 2683 2684 _createClass(AccordionMenu, [{ 2685 key: '_init', 2686 value: function _init() { 2687 this.$element.find('[data-submenu]').not('.is-active').slideUp(0); //.find('a').css('padding-left', '1rem'); 2688 this.$element.attr({ 2689 'role': 'tablist', 2690 'aria-multiselectable': this.options.multiOpen 2691 }); 2692 2693 this.$menuLinks = this.$element.find('.is-accordion-submenu-parent'); 2694 this.$menuLinks.each(function () { 2695 var linkId = this.id || Foundation.GetYoDigits(6, 'acc-menu-link'), 2696 $elem = $(this), 2697 $sub = $elem.children('[data-submenu]'), 2698 subId = $sub[0].id || Foundation.GetYoDigits(6, 'acc-menu'), 2699 isActive = $sub.hasClass('is-active'); 2700 $elem.attr({ 2701 'aria-controls': subId, 2702 'aria-expanded': isActive, 2703 'role': 'tab', 2704 'id': linkId 2705 }); 2706 $sub.attr({ 2707 'aria-labelledby': linkId, 2708 'aria-hidden': !isActive, 2709 'role': 'tabpanel', 2710 'id': subId 2711 }); 2712 }); 2713 var initPanes = this.$element.find('.is-active'); 2714 if (initPanes.length) { 2715 var _this = this; 2716 initPanes.each(function () { 2717 _this.down($(this)); 2718 }); 2719 } 2720 this._events(); 2721 } 2722 2723 /** 2724 * Adds event handlers for items within the menu. 2725 * @private 2726 */ 2727 2728 }, {
2729 key: '_events', 2730 value: function _events() { 2731 var _this = this; 2732 2733 this.$element.find('li').each(function () { 2734 var $submenu = $(this).children('[data-submenu]'); 2735 2736 if ($submenu.length) { 2737 $(this).children('a').off('click.zf.accordionMenu').on('click.zf.accordionMenu', function (e) { 2738 e.preventDefault(); 2739 2740 _this.toggle($submenu); 2741 }); 2742 } 2743 }).on('keydown.zf.accordionmenu', function (e) { 2744 var $element = $(this), 2745 $elements = $element.parent('ul').children('li'), 2746 $prevElement, 2747 $nextElement, 2748 $target = $element.children('[data-submenu]'); 2749 2750 $elements.each(function (i) { 2751 if ($(this).is($element)) { 2752 $prevElement = $elements.eq(Math.max(0, i - 1)).find('a').first(); 2753 $nextElement = $elements.eq(Math.min(i + 1, $elements.length - 1)).find('a').first(); 2754 2755 if ($(this).children('[data-submenu]:visible').length) { 2756 // has open sub menu 2757 $nextElement = $element.find('li:first-child').find('a').first(); 2758 } 2759 if ($(this).is(':first-child')) { 2760 // is first element of sub menu 2761 $prevElement = $element.parents('li').first().find('a').first(); 2762 } else if ($prevElement.children('[data-submenu]:visible').length) { 2763 // if previous element has open sub menu 2764 $prevElement = $prevElement.find('li:last-child').find('a').first(); 2765 } 2766 if ($(this).is(':last-child')) { 2767 // is last element of sub menu 2768 $nextElement = $element.parents('li').first().next('li').find('a').first(); 2769 } 2770 2771 return; 2772 } 2773 }); 2774 Foundation.Keyboard.handleKey(e, 'AccordionMenu', { 2775 open: function () { 2776 if ($target.is(':hidden')) { 2777 _this.down($target); 2778 $target.find('li').first().find('a').first().focus(); 2779 } 2780 }, 2781 close: function () { 2782 if ($target.length && !$target.is(':hidden')) { 2783 // close active sub of this item 2784 _this.up($target); 2785 } else if ($element.parent('[data-submenu]').length) { 2786 // close currently open sub 2787 _this.up($element.parent('[data-submenu]')); 2788 $element.parents('li').first().find('a').first().focus(); 2789 } 2790 }, 2791 up: function () { 2792 $prevElement.attr('tabindex', -1).focus(); 2793 return true; 2794 }, 2795 down: function () { 2796 $nextElement.attr('tabindex', -1).focus(); 2797 return true; 2798 }, 2799 toggle: function () { 2800 if ($element.children('[data-submenu]').length) { 2801 _this.toggle($element.children('[data-submenu]')); 2802 } 2803 }, 2804 closeAll: function () { 2805 _this.hideAll(); 2806 }, 2807 handled: function (preventDefault) { 2808 if (preventDefault) { 2809 e.preventDefault(); 2810 } 2811 e.stopImmediatePropagation(); 2812 } 2813 }); 2814 }); //.attr('tabindex', 0); 2815 } 2816 2817 /** 2818 * Closes all panes of the menu. 2819 * @function 2820 */ 2821 2822 }, { 2823 key: 'hideAll', 2824 value: function hideAll() { 2825 this.$element.find('[data-submenu]').slideUp(this.options.slideSpeed); 2826 } 2827 2828 /** 2829 * Toggles the open/close state of a submenu. 2830 * @function 2831 * @param {jQuery} $target - the submenu to toggle 2832 */ 2833 2834 }, { 2835 key: 'toggle', 2836 value: function toggle($target) { 2837 if (!$target.is(':animated')) { 2838 if (!$target.is(':hidden')) { 2839 this.up($target); 2840 } else { 2841 this.down($target); 2842 } 2843 } 2844 } 2845 2846 /** 2847 * Opens the sub-menu defined by `$target`. 2848 * @param {jQuery} $target - Sub-menu to open. 2849 * @fires AccordionMenu#down 2850 */ 2851 2852 }, {
2853 key: 'down', 2854 value: function down($target) { 2855 var _this = this; 2856 2857 if (!this.options.multiOpen) { 2858 this.up(this.$element.find('.is-active').not($target.parentsUntil(this.$element).add($target))); 2859 } 2860 2861 $target.addClass('is-active').attr({ 'aria-hidden': false }).parent('.is-accordion-submenu-parent').attr({ 'aria-expanded': true }); 2862 2863 //Foundation.Move(this.options.slideSpeed, $target, function() { 2864 $target.slideDown(_this.options.slideSpeed, function () { 2865 /** 2866 * Fires when the menu is done opening. 2867 * @event AccordionMenu#down 2868 */ 2869 _this.$element.trigger('down.zf.accordionMenu', [$target]); 2870 }); 2871 //}); 2872 } 2873 2874 /** 2875 * Closes the sub-menu defined by `$target`. All sub-menus inside the target will be closed as well. 2876 * @param {jQuery} $target - Sub-menu to close. 2877 * @fires AccordionMenu#up 2878 */ 2879 2880 }, { 2881 key: 'up', 2882 value: function up($target) { 2883 var _this = this; 2884 //Foundation.Move(this.options.slideSpeed, $target, function(){ 2885 $target.slideUp(_this.options.slideSpeed, function () { 2886 /** 2887 * Fires when the menu is done collapsing up. 2888 * @event AccordionMenu#up 2889 */ 2890 _this.$element.trigger('up.zf.accordionMenu', [$target]); 2891 }); 2892 //}); 2893 2894 var $menus = $target.find('[data-submenu]').slideUp(0).addBack().attr('aria-hidden', true); 2895 2896 $menus.parent('.is-accordion-submenu-parent').attr('aria-expanded', false); 2897 } 2898 2899 /** 2900 * Destroys an instance of accordion menu. 2901 * @fires AccordionMenu#destroyed 2902 */ 2903 2904 }, { 2905 key: 'destroy', 2906 value: function destroy() { 2907 this.$element.find('[data-submenu]').slideDown(0).css('display', ''); 2908 this.$element.find('a').off('click.zf.accordionMenu'); 2909 2910 Foundation.Nest.Burn(this.$element, 'accordion'); 2911 Foundation.unregisterPlugin(this); 2912 } 2913 }]); 2914 2915 return AccordionMenu; 2916 }(); 2917 2918 AccordionMenu.defaults = { 2919 /** 2920 * Amount of time to animate the opening of a submenu in ms. 2921 * @option 2922 * @example 250 2923 */ 2924 slideSpeed: 250, 2925 /** 2926 * Allow the menu to have multiple open panes. 2927 * @option 2928 * @example true 2929 */ 2930 multiOpen: true 2931 }; 2932 2933 // Window exports 2934 Foundation.plugin(AccordionMenu, 'AccordionMenu'); 2935}(jQuery); 2936'use strict'; 2937 2938var _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; }; }(); 2939 2940function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 2941 2942!function ($) { 2943 2944 /** 2945 * Drilldown module. 2946 * @module foundation.drilldown 2947 * @requires foundation.util.keyboard 2948 * @requires foundation.util.motion 2949 * @requires foundation.util.nest 2950 */ 2951 2952 var Drilldown = function () { 2953 /** 2954 * Creates a new instance of a drilldown menu. 2955 * @class 2956 * @param {jQuery} element - jQuery object to make into an accordion menu. 2957 * @param {Object} options - Overrides to the default plugin settings. 2958 */ 2959 2960 function Drilldown(element, options) { 2961 _classCallCheck(this, Drilldown); 2962 2963 this.$element = element; 2964 this.options = $.extend({}, Drilldown.defaults, this.$element.data(), options); 2965 2966 Foundation.Nest.Feather(this.$element, 'drilldown'); 2967 2968 this._init(); 2969 2970 Foundation.registerPlugin(this, 'Drilldown'); 2971 Foundation.Keyboard.register('Drilldown', { 2972 'ENTER': 'open', 2973 'SPACE': 'open',
vendor: 6,806 bytes, lines 2974-3171
2974 'ARROW_RIGHT': 'next', 2975 'ARROW_UP': 'up', 2976 'ARROW_DOWN': 'down', 2977 'ARROW_LEFT': 'previous', 2978 'ESCAPE': 'close', 2979 'TAB': 'down', 2980 'SHIFT_TAB': 'up' 2981 }); 2982 } 2983 2984 /** 2985 * Initializes the drilldown by creating jQuery collections of elements 2986 * @private 2987 */ 2988 2989 2990 _createClass(Drilldown, [{ 2991 key: '_init', 2992 value: function _init() { 2993 this.$submenuAnchors = this.$element.find('li.is-drilldown-submenu-parent').children('a'); 2994 this.$submenus = this.$submenuAnchors.parent('li').children('[data-submenu]'); 2995 this.$menuItems = this.$element.find('li').not('.js-drilldown-back').attr('role', 'menuitem').find('a'); 2996 2997 this._prepareMenu(); 2998 2999 this._keyboardEvents(); 3000 } 3001 3002 /** 3003 * prepares drilldown menu by setting attributes to links and elements 3004 * sets a min height to prevent content jumping 3005 * wraps the element if not already wrapped 3006 * @private 3007 * @function 3008 */ 3009 3010 }, { 3011 key: '_prepareMenu', 3012 value: function _prepareMenu() { 3013 var _this = this; 3014 // if(!this.options.holdOpen){ 3015 // this._menuLinkEvents(); 3016 // } 3017 this.$submenuAnchors.each(function () { 3018 var $link = $(this); 3019 var $sub = $link.parent(); 3020 if (_this.options.parentLink) { 3021 $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>'); 3022 } 3023 $link.data('savedHref', $link.attr('href')).removeAttr('href'); 3024 $link.children('[data-submenu]').attr({ 3025 'aria-hidden': true, 3026 'tabindex': 0, 3027 'role': 'menu' 3028 }); 3029 _this._events($link); 3030 }); 3031 this.$submenus.each(function () { 3032 var $menu = $(this), 3033 $back = $menu.find('.js-drilldown-back'); 3034 if (!$back.length) { 3035 $menu.prepend(_this.options.backButton); 3036 } 3037 _this._back($menu); 3038 }); 3039 if (!this.$element.parent().hasClass('is-drilldown')) { 3040 this.$wrapper = $(this.options.wrapper).addClass('is-drilldown'); 3041 this.$wrapper = this.$element.wrap(this.$wrapper).parent().css(this._getMaxDims()); 3042 } 3043 } 3044 3045 /** 3046 * Adds event handlers to elements in the menu. 3047 * @function 3048 * @private 3049 * @param {jQuery} $elem - the current menu item to add handlers to. 3050 */ 3051 3052 }, { 3053 key: '_events', 3054 value: function _events($elem) { 3055 var _this = this; 3056 3057 $elem.off('click.zf.drilldown').on('click.zf.drilldown', function (e) { 3058 if ($(e.target).parentsUntil('ul', 'li').hasClass('is-drilldown-submenu-parent')) { 3059 e.stopImmediatePropagation(); 3060 e.preventDefault(); 3061 } 3062 3063 // if(e.target !== e.currentTarget.firstElementChild){ 3064 // return false; 3065 // } 3066 _this._show($elem.parent('li')); 3067 3068 if (_this.options.closeOnClick) { 3069 var $body = $('body'); 3070 $body.off('.zf.drilldown').on('click.zf.drilldown', function (e) { 3071 if (e.target === _this.$element[0] || $.contains(_this.$element[0], e.target)) { 3072 return; 3073 } 3074 e.preventDefault(); 3075 _this._hideAll(); 3076 $body.off('.zf.drilldown'); 3077 }); 3078 } 3079 }); 3080 } 3081 3082 /** 3083 * Adds keydown event listener to `li`'s in the menu. 3084 * @private 3085 */ 3086 3087 }, { 3088 key: '_keyboardEvents', 3089 value: function _keyboardEvents() { 3090 var _this = this; 3091 3092 this.$menuItems.add(this.$element.find('.js-drilldown-back > a')).on('keydown.zf.drilldown', function (e) { 3093 3094 var $element = $(this), 3095 $elements = $element.parent('li').parent('ul').children('li').children('a'), 3096 $prevElement, 3097 $nextElement; 3098 3099 $elements.each(function (i) { 3100 if ($(this).is($element)) { 3101 $prevElement = $elements.eq(Math.max(0, i - 1)); 3102 $nextElement = $elements.eq(Math.min(i + 1, $elements.length - 1)); 3103 return; 3104 } 3105 }); 3106 3107 Foundation.Keyboard.handleKey(e, 'Drilldown', { 3108 next: function () { 3109 if ($element.is(_this.$submenuAnchors)) { 3110 _this._show($element.parent('li')); 3111 $element.parent('li').one(Foundation.transitionend($element), function () { 3112 $element.parent('li').find('ul li a').filter(_this.$menuItems).first().focus(); 3113 }); 3114 return true; 3115 } 3116 }, 3117 previous: function () { 3118 _this._hide($element.parent('li').parent('ul')); 3119 $element.parent('li').parent('ul').one(Foundation.transitionend($element), function () { 3120 setTimeout(function () { 3121 $element.parent('li').parent('ul').parent('li').children('a').first().focus(); 3122 }, 1); 3123 }); 3124 return true; 3125 }, 3126 up: function () { 3127 $prevElement.focus(); 3128 return true; 3129 }, 3130 down: function () { 3131 $nextElement.focus(); 3132 return true; 3133 }, 3134 close: function () { 3135 _this._back(); 3136 //_this.$menuItems.first().focus(); // focus to first element 3137 }, 3138 open: function () { 3139 if (!$element.is(_this.$menuItems)) { 3140 // not menu item means back button 3141 _this._hide($element.parent('li').parent('ul')); 3142 $element.parent('li').parent('ul').one(Foundation.transitionend($element), function () { 3143 setTimeout(function () { 3144 $element.parent('li').parent('ul').parent('li').children('a').first().focus(); 3145 }, 1); 3146 }); 3147 } else if ($element.is(_this.$submenuAnchors)) { 3148 _this._show($element.parent('li')); 3149 $element.parent('li').one(Foundation.transitionend($element), function () { 3150 $element.parent('li').find('ul li a').filter(_this.$menuItems).first().focus(); 3151 }); 3152 } 3153 return true; 3154 }, 3155 handled: function (preventDefault) { 3156 if (preventDefault) { 3157 e.preventDefault(); 3158 } 3159 e.stopImmediatePropagation(); 3160 } 3161 }); 3162 }); // end keyboardAccess 3163 } 3164 3165 /** 3166 * Closes all open elements, and returns to root menu. 3167 * @function 3168 * @fires Drilldown#closed 3169 */ 3170 3171 }, {
3172 key: '_hideAll', 3173 value: function _hideAll() { 3174 var $elem = this.$element.find('.is-drilldown-submenu.is-active').addClass('is-closing'); 3175 $elem.one(Foundation.transitionend($elem), function (e) { 3176 $elem.removeClass('is-active is-closing'); 3177 }); 3178 /** 3179 * Fires when the menu is fully closed. 3180 * @event Drilldown#closed 3181 */ 3182 this.$element.trigger('closed.zf.drilldown'); 3183 } 3184 3185 /** 3186 * Adds event listener for each `back` button, and closes open menus. 3187 * @function 3188 * @fires Drilldown#back 3189 * @param {jQuery} $elem - the current sub-menu to add `back` event. 3190 */ 3191 3192 }, { 3193 key: '_back', 3194 value: function _back($elem) { 3195 var _this = this; 3196 $elem.off('click.zf.drilldown'); 3197 $elem.children('.js-drilldown-back').on('click.zf.drilldown', function (e) { 3198 e.stopImmediatePropagation(); 3199 // console.log('mouseup on back'); 3200 _this._hide($elem); 3201 }); 3202 } 3203 3204 /** 3205 * Adds event listener to menu items w/o submenus to close open menus on click. 3206 * @function 3207 * @private 3208 */ 3209 3210 }, { 3211 key: '_menuLinkEvents', 3212 value: function _menuLinkEvents() { 3213 var _this = this; 3214 this.$menuItems.not('.is-drilldown-submenu-parent').off('click.zf.drilldown').on('click.zf.drilldown', function (e) { 3215 // e.stopImmediatePropagation(); 3216 setTimeout(function () { 3217 _this._hideAll(); 3218 }, 0); 3219 }); 3220 } 3221 3222 /** 3223 * Opens a submenu. 3224 * @function 3225 * @fires Drilldown#open 3226 * @param {jQuery} $elem - the current element with a submenu to open, i.e. the `li` tag. 3227 */ 3228 3229 }, { 3230 key: '_show', 3231 value: function _show($elem) { 3232 $elem.children('[data-submenu]').addClass('is-active'); 3233 /** 3234 * Fires when the submenu has opened. 3235 * @event Drilldown#open 3236 */ 3237 this.$element.trigger('open.zf.drilldown', [$elem]); 3238 } 3239 }, { 3240 key: '_hide', 3241 3242 3243 /** 3244 * Hides a submenu 3245 * @function 3246 * @fires Drilldown#hide 3247 * @param {jQuery} $elem - the current sub-menu to hide, i.e. the `ul` tag. 3248 */ 3249 value: function _hide($elem) { 3250 var _this = this; 3251 $elem.addClass('is-closing').one(Foundation.transitionend($elem), function () { 3252 $elem.removeClass('is-active is-closing'); 3253 $elem.blur(); 3254 }); 3255 /** 3256 * Fires when the submenu has closed. 3257 * @event Drilldown#hide 3258 */ 3259 $elem.trigger('hide.zf.drilldown', [$elem]); 3260 } 3261 3262 /** 3263 * Iterates through the nested menus to calculate the min-height, and max-width for the menu. 3264 * Prevents content jumping. 3265 * @function 3266 * @private 3267 */ 3268 3269 }, { 3270 key: '_getMaxDims', 3271 value: function _getMaxDims() { 3272 var max = 0, 3273 result = {}; 3274 this.$submenus.add(this.$element).each(function () { 3275 var numOfElems = $(this).children('li').length; 3276 max = numOfElems > max ? numOfElems : max; 3277 }); 3278 3279 result['min-height'] = max * this.$menuItems[0].getBoundingClientRect().height + 'px'; 3280 result['max-width'] = this.$element[0].getBoundingClientRect().width + 'px'; 3281 3282 return result; 3283 } 3284 3285 /** 3286 * Destroys the Drilldown Menu 3287 * @function 3288 */ 3289 3290 }, { 3291 key: 'destroy', 3292 value: function destroy() { 3293 this._hideAll(); 3294 Foundation.Nest.Burn(this.$element, 'drilldown'); 3295 this.$element.unwrap().find('.js-drilldown-back, .is-submenu-parent-item').remove().end().find('.is-active, .is-closing, .is-drilldown-submenu').removeClass('is-active is-closing is-drilldown-submenu').end().find('[data-submenu]').removeAttr('aria-hidden tabindex role'); 3296 this.$submenuAnchors.each(function () { 3297 $(this).off('.zf.drilldown'); 3298 }); 3299 this.$element.find('a').each(function () { 3300 var $link = $(this); 3301 if ($link.data('savedHref')) { 3302 $link.attr('href', $link.data('savedHref')).removeData('savedHref'); 3303 } else { 3304 return; 3305 } 3306 }); 3307 Foundation.unregisterPlugin(this); 3308 } 3309 }]); 3310 3311 return Drilldown; 3312 }(); 3313 3314 Drilldown.defaults = { 3315 /** 3316 * 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. 3317 * @option 3318 * @example '<\li><\a>Back<\/a><\/li>' 3319 */ 3320 backButton: '<li class="js-drilldown-back"><a tabindex="0">Back</a></li>', 3321 /** 3322 * 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. 3323 * @option 3324 * @example '<\div class="is-drilldown"><\/div>' 3325 */ 3326 wrapper: '<div></div>', 3327 /** 3328 * Adds the parent link to the submenu. 3329 * @option 3330 * @example false 3331 */ 3332 parentLink: false, 3333 /** 3334 * Allow the menu to return to root list on body click. 3335 * @option 3336 * @example false 3337 */ 3338 closeOnClick: false 3339 // holdOpen: false 3340 }; 3341 3342 // Window exports 3343 Foundation.plugin(Drilldown, 'Drilldown'); 3344}(jQuery); 3345'use strict'; 3346 3347var _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; }; }(); 3348 3349function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 3350 3351!function ($) { 3352 3353 /** 3354 * Dropdown module. 3355 * @module foundation.dropdown 3356 * @requires foundation.util.keyboard 3357 * @requires foundation.util.box 3358 * @requires foundation.util.triggers 3359 */ 3360 3361 var Dropdown = function () { 3362 /** 3363 * Creates a new instance of a dropdown. 3364 * @class 3365 * @param {jQuery} element - jQuery object to make into a dropdown. 3366 * Object should be of the dropdown panel, rather than
3366its anchor. 3367 * @param {Object} options - Overrides to the default plugin settings. 3368 */ 3369 3370 function Dropdown(element, options) { 3371 _classCallCheck(this, Dropdown); 3372 3373 this.$element = element; 3374 this.options = $.extend({}, Dropdown.defaults, this.$element.data(), options); 3375 this._init(); 3376 3377 Foundation.registerPlugin(this, 'Dropdown'); 3378 Foundation.Keyboard.register('Dropdown', { 3379 'ENTER': 'open', 3380 'SPACE': 'open', 3381 'ESCAPE': 'close', 3382 'TAB': 'tab_forward', 3383 'SHIFT_TAB': 'tab_backward' 3384 }); 3385 } 3386 3387 /** 3388 * Initializes the plugin by setting/checking options and attributes, adding helper variables, and saving the anchor. 3389 * @function 3390 * @private 3391 */ 3392 3393 3394 _createClass(Dropdown, [{ 3395 key: '_init', 3396 value: function _init() { 3397 var $id = this.$element.attr('id'); 3398 3399 this.$anchor = $('[data-toggle="' + $id + '"]') || $('[data-open="' + $id + '"]'); 3400 this.$anchor.attr({ 3401 'aria-controls': $id, 3402 'data-is-focus': false, 3403 'data-yeti-box': $id, 3404 'aria-haspopup': true, 3405 'aria-expanded': false 3406 3407 }); 3408 3409 this.options.positionClass = this.getPositionClass(); 3410 this.counter = 4; 3411 this.usedPositions = []; 3412 this.$element.attr({ 3413 'aria-hidden': 'true', 3414 'data-yeti-box': $id, 3415 'data-resize': $id, 3416 'aria-labelledby': this.$anchor[0].id || Foundation.GetYoDigits(6, 'dd-anchor') 3417 }); 3418 this._events(); 3419 } 3420 3421 /** 3422 * Helper function to determine current orientation of dropdown pane. 3423 * @function 3424 * @returns {String} position - string value of a position class. 3425 */ 3426 3427 }, { 3428 key: 'getPositionClass', 3429 value: function getPositionClass() { 3430 var verticalPosition = this.$element[0].className.match(/(top|left|right|bottom)/g); 3431 verticalPosition = verticalPosition ? verticalPosition[0] : ''; 3432 var horizontalPosition = /float-(\S+)\s/.exec(this.$anchor[0].className); 3433 horizontalPosition = horizontalPosition ? horizontalPosition[1] : ''; 3434 var position = horizontalPosition ? horizontalPosition + ' ' + verticalPosition : verticalPosition; 3435 return position; 3436 } 3437 3438 /** 3439 * Adjusts the dropdown panes orientation by adding/removing positioning classes. 3440 * @function 3441 * @private 3442 * @param {String} position - position class to remove. 3443 */ 3444 3445 }, { 3446 key: '_reposition', 3447 value: function _reposition(position) { 3448 this.usedPositions.push(position ? position : 'bottom'); 3449 //default, try switching to opposite side 3450 if (!position && this.usedPositions.indexOf('top') < 0) { 3451 this.$element.addClass('top'); 3452 } else if (position === 'top' && this.usedPositions.indexOf('bottom') < 0) { 3453 this.$element.removeClass(position); 3454 } else if (position === 'left' && this.usedPositions.indexOf('right') < 0) { 3455 this.$element.removeClass(position).addClass('right'); 3456 } else if (position === 'right' && this.usedPositions.indexOf('left') < 0) { 3457 this.$element.removeClass(position).addClass('left'); 3458 } 3459 3460 //if default change didn't work, try bottom or left first 3461 else if (!position && this.usedPositions.indexOf('top') > -1 && this.usedPositions.indexOf('left') < 0) { 3462 this.$element.addClass('left'); 3463 } else if (position === 'top' && this.usedPositions.indexOf('bottom') > -1 && this.usedPositions.indexOf('left') < 0) { 3464 this.$element.removeClass(position).addClass('left'); 3465 } else if (position === 'left' && this.usedPositions.indexOf('right') > -1 && this.usedPositions.indexOf('bottom') < 0) { 3466 this.$element.removeClass(position); 3467 } else if (position === 'right' && this.usedPositions.indexOf('left') > -1 && this.usedPositions.indexOf('bottom') < 0) { 3468 this.$element.removeClass(position); 3469 } 3470 //if nothing cleared, set to bottom 3471 else { 3472 this.$element.removeClass(position); 3473 } 3474 this.classChanged = true; 3475 this.counter--; 3476 } 3477 3478 /** 3479 * Sets the position and orientation of the dropdown pane, checks for c
3479ollisions. 3480 * Recursively calls itself if a collision is detected, with a new position class. 3481 * @function 3482 * @private 3483 */ 3484 3485 }, { 3486 key: '_setPosition', 3487 value: function _setPosition() { 3488 if (this.$anchor.attr('aria-expanded') === 'false') { 3489 return false; 3490 } 3491 var position = this.getPositionClass(), 3492 $eleDims = Foundation.Box.GetDimensions(this.$element), 3493 $anchorDims = Foundation.Box.GetDimensions(this.$anchor), 3494 _this = this, 3495 direction = position === 'left' ? 'left' : position === 'right' ? 'left' : 'top', 3496 param = direction === 'top' ? 'height' : 'width', 3497 offset = param === 'height' ? this.options.vOffset : this.options.hOffset; 3498 3499 if ($eleDims.width >= $eleDims.windowDims.width || !this.counter && !Foundation.Box.ImNotTouchingYou(this.$element)) { 3500 this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, 'center bottom', this.options.vOffset, this.options.hOffset, true)).css({ 3501 'width': $eleDims.windowDims.width - this.options.hOffset * 2, 3502 'height': 'auto' 3503 }); 3504 this.classChanged = true; 3505 return false; 3506 } 3507 3508 this.$element.offset(Foundation.Box.GetOffsets(this.$element, this.$anchor, position, this.options.vOffset, this.options.hOffset)); 3509 3510 while (!Foundation.Box.ImNotTouchingYou(this.$element, false, true) && this.counter) { 3511 this._reposition(position); 3512 this._setPosition(); 3513 } 3514 } 3515 3516 /** 3517 * Adds event listeners to the element utilizing the triggers utility library. 3518 * @function 3519 * @private 3520 */ 3521 3522 }, { 3523 key: '_events', 3524 value: function _events() { 3525 var _this = this; 3526 this.$element.on({ 3527 'open.zf.trigger': this.open.bind(this), 3528 'close.zf.trigger': this.close.bind(this), 3529 'toggle.zf.trigger': this.toggle.bind(this), 3530 'resizeme.zf.trigger': this._setPosition.bind(this) 3531 }); 3532 3533 if (this.options.hover) { 3534 this.$anchor.off('mouseenter.zf.dropdown mouseleave.zf.dropdown').on('mouseenter.zf.dropdown', function () { 3535 clearTimeout(_this.timeout); 3536 _this.timeout = setTimeout(function () { 3537 _this.open(); 3538 _this.$anchor.data('hover', true); 3539 }, _this.options.hoverDelay); 3540 }).on('mouseleave.zf.dropdown', function () { 3541 clearTimeout(_this.timeout); 3542 _this.timeout = setTimeout(function () { 3543 _this.close(); 3544 _this.$anchor.data('hover', false); 3545 }, _this.options.hoverDelay); 3546 }); 3547 if (this.options.hoverPane) { 3548 this.$element.off('mouseenter.zf.dropdown mouseleave.zf.dropdown').on('mouseenter.zf.dropdown', function () { 3549 clearTimeout(_this.timeout); 3550 }).on('mouseleave.zf.dropdown', function () { 3551 clearTimeout(_this.timeout); 3552 _this.timeout = setTimeout(function () { 3553 _this.close(); 3554 _this.$anchor.data('hover', false); 3555 }, _this.options.hoverDelay); 3556 }); 3557 } 3558 } 3559 this.$anchor.add(this.$element).on('keydown.zf.dropdown', function (e) { 3560 3561 var $target = $(this), 3562 visibleFocusableElements = Foundation.Keyboard.findFocusable(_this.$element); 3563 3564 Foundation.Keyboard.handleKey(e, 'Dropdown', { 3565 tab_forward: function () { 3566 if (_this.$element.find(':focus').is(visibleFocusableElements.eq(-1))) { 3567 // left modal downwards, setting focus to first element 3568 if (_this.options.trapFocus) { 3569 // if focus shall be trapped 3570 visibleFocusableElements.eq(0).focus(); 3571 e.preventDefault(); 3572 } else { 3573 // if focus is not trapped, close dropdown on focus out 3574 _this.close(); 3575 } 3576 } 3577 }, 3578 tab_backward: function () { 3579 if (_this.$element.find(':focus').is(visibleFocusableElements.eq(0)) || _this.$element.is(':focus')) { 3580 // left modal upwards, setting focus to last element 3581 if (_this.options.trapFocus) { 3582 // if focus shall be trapped 3583 visibleFocusableElements.eq(-1).focus(); 3584 e.preventDefault(); 3585 } else { 3586 // if focus is not trapped, close dropdown on focus out 3587 _this.close(); 3588 } 3589 } 3590 }, 3591 open: function () { 3592 if ($target.is(_this.$anchor)) { 3593 _this.open(); 3594 _this.$element.attr('tabindex', -1).focus(); 3595 e.preventDefault(); 3596 } 3597 }, 3598 close: function () { 3599 _this.close(); 3600 _this.$anchor.focus(); 3601 } 3602 }); 3603 }); 3604 } 3605 3606 /** 3607 * Adds an event handler to the body to close any dropdowns on a click. 3608 * @function 3609 * @private 3610 */ 3611 3612 }, {
3613 key: '_addBodyHandler', 3614 value: function _addBodyHandler() { 3615 var $body = $(document.body).not(this.$element), 3616 _this = this; 3617 $body.off('click.zf.dropdown').on('click.zf.dropdown', function (e) { 3618 if (_this.$anchor.is(e.target) || _this.$anchor.find(e.target).length) { 3619 return; 3620 } 3621 if (_this.$element.find(e.target).length) { 3622 return; 3623 } 3624 _this.close(); 3625 $body.off('click.zf.dropdown'); 3626 }); 3627 } 3628 3629 /** 3630 * Opens the dropdown pane, and fires a bubbling event to close other dropdowns. 3631 * @function 3632 * @fires Dropdown#closeme 3633 * @fires Dropdown#show 3634 */ 3635 3636 }, { 3637 key: 'open', 3638 value: function open() { 3639 // var _this = this; 3640 /** 3641 * Fires to close other open dropdowns 3642 * @event Dropdown#closeme 3643 */ 3644 this.$element.trigger('closeme.zf.dropdown', this.$element.attr('id')); 3645 this.$anchor.addClass('hover').attr({ 'aria-expanded': true }); 3646 // this.$element/*.show()*/; 3647 this._setPosition(); 3648 this.$element.addClass('is-open').attr({ 'aria-hidden': false }); 3649 3650 if (this.options.autoFocus) { 3651 var $focusable = Foundation.Keyboard.findFocusable(this.$element); 3652 if ($focusable.length) { 3653 $focusable.eq(0).focus(); 3654 } 3655 } 3656 3657 if (this.options.closeOnClick) { 3658 this._addBodyHandler(); 3659 } 3660 3661 /** 3662 * Fires once the dropdown is visible. 3663 * @event Dropdown#show 3664 */ 3665 this.$element.trigger('show.zf.dropdown', [this.$element]); 3666 } 3667 3668 /** 3669 * Closes the open dropdown pane. 3670 * @function 3671 * @fires Dropdown#hide 3672 */ 3673 3674 }, { 3675 key: 'close', 3676 value: function close() { 3677 if (!this.$element.hasClass('is-open')) { 3678 return false; 3679 } 3680 this.$element.removeClass('is-open').attr({ 'aria-hidden': true }); 3681 3682 this.$anchor.removeClass('hover').attr('aria-expanded', false); 3683 3684 if (this.classChanged) { 3685 var curPositionClass = this.getPositionClass(); 3686 if (curPositionClass) { 3687 this.$element.removeClass(curPositionClass); 3688 } 3689 this.$element.addClass(this.options.positionClass) 3690 /*.hide()*/.css({ height: '', width: '' }); 3691 this.classChanged = false; 3692 this.counter = 4; 3693 this.usedPositions.length = 0; 3694 } 3695 this.$element.trigger('hide.zf.dropdown', [this.$element]); 3696 } 3697 3698 /** 3699 * Toggles the dropdown pane's visibility. 3700 * @function 3701 */ 3702 3703 }, { 3704 key: 'toggle', 3705 value: function toggle() { 3706 if (this.$element.hasClass('is-open')) { 3707 if (this.$anchor.data('hover')) return; 3708 this.close(); 3709 } else { 3710 this.open(); 3711 } 3712 } 3713 3714 /** 3715 * Destroys the dropdown. 3716 * @function 3717 */ 3718 3719 }, { 3720 key: 'destroy', 3721 value: function destroy() { 3722 this.$element.off('.zf.trigger').hide(); 3723 this.$anchor.off('.zf.dropdown'); 3724 3725 Foundation.unregisterPlugin(this); 3726 } 3727 }]); 3728 3729 return Dropdown; 3730 }(); 3731 3732 Dropdown.defaults = { 3733 /** 3734 * Amount of time to delay opening a submenu on hover event. 3735 * @option 3736 * @example 250 3737 */ 3738 hoverDelay: 250, 3739 /** 3740 * Allow submenus to open on hover events 3741 * @option 3742 * @example false 3743 */ 3744 hover: false, 3745 /** 3746 * Don't close dropdown when hovering over dropdown pane 3747 * @option 3748 * @example true 3749 */ 3750 hoverPane: false, 3751 /** 3752 * Number of pixels between the dropdown pane and the triggering element on open. 3753 * @option 3754 * @example 1 3755 */ 3756 vOffset: 1, 3757 /** 3758 * Number of pixels between the dropdown pane and the triggering element on open. 3759 * @option 3760 * @example 1 3761 */ 3762 hOffset: 1, 3763 /** 3764 * Class applied to adjust open position. JS will test and fill this in. 3765 * @option 3766 * @example 'top' 3767 */ 3768 positionClass: '', 3769 /** 3770 * Allow the plugin to trap focus to the dropdown pane if opened with keyboard commands. 3771 * @option 3772 * @example false 3773 */ 3774 trapFocus: false, 3775 /** 3776 * Allow the plugin to set focus to the first focusable element within the pane, regardless of method of opening. 3777 * @option 3778 * @example true 3779 */ 3780 autoFocus: false, 3781 /** 3782 * Allows a click on the body to close the dropdown. 3783 * @option 3784 * @example false 3785 */ 3786 closeOnClick: false 3787 }; 3788 3789 // Window exports 3790 Foundation.plugin(Dropdown, 'Dropdown'); 3791}(jQuery); 3792'use strict'; 3793 3794var _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; }; }(); 3795 3796function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 3797 3798!function ($) { 3799 3800 /** 3801 * DropdownMenu module. 3802 * @module foundation.dropdown-menu 3803 * @requires foundation.util.keyboard 3804 * @requires foundation.util.box 3805 * @requires foundation.util.nest 3806 */ 3807 3808 var DropdownMenu = function () { 3809 /** 3810 * Creates a new instance of DropdownMenu. 3811 * @class 3812 * @fires DropdownMenu#init 3813 * @param {jQuery} element - jQuery object to make into a dropdown menu. 3814 * @param {Object} options - Overrides to the default plugin settings. 3815 */ 3816 3817 function DropdownMenu(element, options) { 3818 _classCallCheck(this, DropdownMenu); 3819 3820 this.$element = element; 3821 this.options = $.extend({}, DropdownMenu.defaults, this.$element.data(), options); 3822 3823 Foundation.Nest.Feather(this.$element, 'dropdown'); 3824 this._init(); 3825 3826 Foundation.registerPlugin(this, 'DropdownMenu'); 3827 Foundation.Keyboard.register('DropdownMenu', { 3828 'ENTER': 'open', 3829 'SPACE': 'open',
3830 'ARROW_RIGHT': 'next', 3831 'ARROW_UP': 'up', 3832 'ARROW_DOWN': 'down', 3833 'ARROW_LEFT': 'previous', 3834 'ESCAPE': 'close' 3835 }); 3836 } 3837 3838 /** 3839 * Initializes the plugin, and calls _prepareMenu 3840 * @private 3841 * @function 3842 */ 3843 3844 3845 _createClass(DropdownMenu, [{ 3846 key: '_init', 3847 value: function _init() { 3848 var subs = this.$element.find('li.is-dropdown-submenu-parent'); 3849 this.$element.children('.is-dropdown-submenu-parent').children('.is-dropdown-submenu').addClass('first-sub'); 3850 3851 this.$menuItems = this.$element.find('[role="menuitem"]'); 3852 this.$tabs = this.$element.children('[role="menuitem"]'); 3853 this.$tabs.find('ul.is-dropdown-submenu').addClass(this.options.verticalClass); 3854 3855 if (this.$element.hasClass(this.options.rightClass) || this.options.alignment === 'right' || Foundation.rtl() || this.$element.parents('.top-bar-right').is('*')) { 3856 this.options.alignment = 'right'; 3857 subs.addClass('opens-left'); 3858 } else { 3859 subs.addClass('opens-right'); 3860 } 3861 this.changed = false; 3862 this._events(); 3863 } 3864 }, { 3865 key: '_events', 3866 3867 /** 3868 * Adds event listeners to elements within the menu 3869 * @private 3870 * @function 3871 */ 3872 value: function _events() { 3873 var _this = this, 3874 hasTouch = 'ontouchstart' in window || typeof window.ontouchstart !== 'undefined', 3875 parClass = 'is-dropdown-submenu-parent'; 3876 3877 // used for onClick and in the keyboard handlers 3878 var handleClickFn = function (e) { 3879 var $elem = $(e.target).parentsUntil('ul', '.' + parClass), 3880 hasSub = $elem.hasClass(parClass), 3881 hasClicked = $elem.attr('data-is-click') === 'true', 3882 $sub = $elem.children('.is-dropdown-submenu'); 3883 3884 if (hasSub) { 3885 if (hasClicked) { 3886 if (!_this.options.closeOnClick || !_this.options.clickOpen && !hasTouch || _this.options.forceFollow && hasTouch) { 3887 return; 3888 } else { 3889 e.stopImmediatePropagation(); 3890 e.preventDefault(); 3891 _this._hide($elem); 3892 } 3893 } else { 3894 e.preventDefault(); 3895 e.stopImmediatePropagation(); 3896 _this._show($elem.children('.is-dropdown-submenu')); 3897 $elem.add($elem.parentsUntil(_this.$element, '.' + parClass)).attr('data-is-click', true); 3898 } 3899 } else { 3900 return; 3901 } 3902 }; 3903 3904 if (this.options.clickOpen || hasTouch) { 3905 this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', handleClickFn); 3906 } 3907 3908 if (!this.options.disableHover) { 3909 this.$menuItems.on('mouseenter.zf.dropdownmenu', function (e) { 3910 var $elem = $(this), 3911 hasSub = $elem.hasClass(parClass); 3912 3913 if (hasSub) { 3914 clearTimeout(_this.delay); 3915 _this.delay = setTimeout(function () { 3916 _this._show($elem.children('.is-dropdown-submenu')); 3917 }, _this.options.hoverDelay); 3918 } 3919 }).on('mouseleave.zf.dropdownmenu', function (e) { 3920 var $elem = $(this), 3921 hasSub = $elem.hasClass(parClass); 3922 if (hasSub && _this.options.autoclose) { 3923 if ($elem.attr('data-is-click') === 'true' && _this.options.clickOpen) { 3924 return false; 3925 } 3926 3927 clearTimeout(_this.delay); 3928 _this.delay = setTimeout(function () { 3929 _this._hide($elem); 3930 }, _this.options.closingTime); 3931 } 3932 }); 3933 } 3934 this.$menuItems.on('keydown.zf.dropdownmenu', function (e) { 3935 var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'), 3936 isTab = _this.$tabs.index($element) > -1, 3937 $elements = isTab ? _this.$tabs : $element.siblings('li').add($element), 3938 $prevElement, 3939 $nextElement; 3940 3941 $elements.each(function (i) { 3942 if ($(this).is($element)) { 3943 $prevElement = $elements.eq(i - 1); 3944 $nextElement = $elements.eq(i + 1); 3945 return; 3946 } 3947 }); 3948 3949 var nextSibling = function () { 3950 if (!$element.is(':last-child')) { 3951 $nextElement.children('a:first').focus(); 3952 e.preventDefault(); 3953 } 3954 }, 3955 prevSibling = function () { 3956 $prevElement.children('a:first').focus(); 3957 e.preventDefault(); 3958 }, 3959 openSub = function () {
3960 var $sub = $element.children('ul.is-dropdown-submenu'); 3961 if ($sub.length) { 3962 _this._show($sub); 3963 $element.find('li > a:first').focus(); 3964 e.preventDefault(); 3965 } else { 3966 return; 3967 } 3968 }, 3969 closeSub = function () { 3970 //if ($element.is(':first-child')) { 3971 var close = $element.parent('ul').parent('li'); 3972 close.children('a:first').focus(); 3973 _this._hide(close); 3974 e.preventDefault(); 3975 //} 3976 }; 3977 var functions = { 3978 open: openSub, 3979 close: function () { 3980 _this._hide(_this.$element); 3981 _this.$menuItems.find('a:first').focus(); // focus to first element 3982 e.preventDefault(); 3983 }, 3984 handled: function () { 3985 e.stopImmediatePropagation(); 3986 } 3987 }; 3988 3989 if (isTab) { 3990 if (_this.$element.hasClass(_this.options.verticalClass)) { 3991 // vertical menu 3992 if (_this.options.alignment === 'left') { 3993 // left aligned 3994 $.extend(functions, { 3995 down: nextSibling, 3996 up: prevSibling, 3997 next: openSub, 3998 previous: closeSub 3999 }); 4000 } else { 4001 // right aligned 4002 $.extend(functions, { 4003 down: nextSibling, 4004 up: prevSibling, 4005 next: closeSub, 4006 previous: openSub 4007 }); 4008 } 4009 } else { 4010 // horizontal menu 4011 $.extend(functions, { 4012 next: nextSibling, 4013 previous: prevSibling, 4014 down: openSub, 4015 up: closeSub 4016 }); 4017 } 4018 } else { 4019 // not tabs -> one sub 4020 if (_this.options.alignment === 'left') { 4021 // left aligned 4022 $.extend(functions, { 4023 next: openSub, 4024 previous: closeSub, 4025 down: nextSibling, 4026 up: prevSibling 4027 }); 4028 } else { 4029 // right aligned 4030 $.extend(functions, { 4031 next: closeSub, 4032 previous: openSub, 4033 down: nextSibling, 4034 up: prevSibling 4035 }); 4036 } 4037 } 4038 Foundation.Keyboard.handleKey(e, 'DropdownMenu', functions); 4039 }); 4040 } 4041 4042 /** 4043 * Adds an event handler to the body to close any dropdowns on a click. 4044 * @function 4045 * @private 4046 */ 4047 4048 }, { 4049 key: '_addBodyHandler', 4050 value: function _addBodyHandler() { 4051 var $body = $(document.body), 4052 _this = this; 4053 $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu').on('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu', function (e) { 4054 var $link = _this.$element.find(e.target); 4055 if ($link.length) { 4056 return; 4057 } 4058 4059 _this._hide(); 4060 $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu'); 4061 }); 4062 } 4063 4064 /** 4065 * Opens a dropdown pane, and checks for collisions first. 4066 * @param {jQuery} $sub - ul element that is a submenu to show 4067 * @function 4068 * @private 4069 * @fires DropdownMenu#show 4070 */ 4071 4072 }, { 4073 key: '_show', 4074 value: function _show($sub) { 4075 var idx = this.$tabs.index(this.$tabs.filter(function (i, el) { 4076 return $(el).find($sub).length > 0; 4077 })); 4078 var $sibs = $sub.parent('li.is-dropdown-submenu-parent').siblings('li.is-dropdown-submenu-parent'); 4079 this._hide($sibs, idx); 4080 $sub.css('visibility', 'hidden').addClass('js-dropdown-active').attr({ 'aria-hidden': false }).parent('li.is-dropdown-submenu-parent').addClass('is-active').attr({ 'aria-expanded': true }); 4081 var clear = Foundation.Box.ImNotTouchingYou($sub, null, true); 4082 if (!clear) { 4083 var oldClass = this.options.alignment === 'left' ? '-right' : '-left', 4084 $parentLi = $sub.parent('.is-dropdown-submenu-parent'); 4085 $parentLi.removeClass('opens' + oldClass).addClass('opens-' + this.options.alignment); 4086 clear = Foundation.Box.ImNotTouchingYou($sub, null, true); 4087 if (!clear) { 4088 $parentLi.removeClass('opens-' + this.options.alignment).addClass('opens-inner'); 4089 } 4090 this.changed = true; 4091 } 4092 $sub.css('visibility', ''); 4093 if (this.options.closeOnClick) { 4094 this._addBodyHandler(); 4095 } 4096 /** 4097 * Fires when the new dropdown pane is visible. 4098 * @event DropdownMenu#show 4099 */ 4100 this.$element.trigger('show.zf.dropdownmenu', [$sub]); 4101 } 4102 4103 /** 4104 * Hides a single, currently open dropdown pane, if passed a parameter, otherwise, hides everything. 4105 * @function 4106 * @param {jQuery} $elem - element with a submenu to hide 4107 * @param {Number} idx - index of the $tabs collection to hide 4108 * @private 4109 */ 4110 4111 }, {
4112 key: '_hide', 4113 value: function _hide($elem, idx) { 4114 var $toClose; 4115 if ($elem && $elem.length) { 4116 $toClose = $elem; 4117 } else if (idx !== undefined) { 4118 $toClose = this.$tabs.not(function (i, el) { 4119 return i === idx; 4120 }); 4121 } else { 4122 $toClose = this.$element; 4123 } 4124 var somethingToClose = $toClose.hasClass('is-active') || $toClose.find('.is-active').length > 0; 4125 4126 if (somethingToClose) { 4127 $toClose.find('li.is-active').add($toClose).attr({ 4128 'aria-expanded': false, 4129 'data-is-click': false 4130 }).removeClass('is-active'); 4131 4132 $toClose.find('ul.js-dropdown-active').attr({ 4133 'aria-hidden': true 4134 }).removeClass('js-dropdown-active'); 4135 4136 if (this.changed || $toClose.find('opens-inner').length) { 4137 var oldClass = this.options.alignment === 'left' ? 'right' : 'left'; 4138 $toClose.find('li.is-dropdown-submenu-parent').add($toClose).removeClass('opens-inner opens-' + this.options.alignment).addClass('opens-' + oldClass); 4139 this.changed = false; 4140 } 4141 /** 4142 * Fires when the open menus are closed. 4143 * @event DropdownMenu#hide 4144 */ 4145 this.$element.trigger('hide.zf.dropdownmenu', [$toClose]); 4146 } 4147 } 4148 4149 /** 4150 * Destroys the plugin. 4151 * @function 4152 */ 4153 4154 }, { 4155 key: 'destroy', 4156 value: function destroy() { 4157 this.$menuItems.off('.zf.dropdownmenu').removeAttr('data-is-click').removeClass('is-right-arrow is-left-arrow is-down-arrow opens-right opens-left opens-inner'); 4158 $(document.body).off('.zf.dropdownmenu'); 4159 Foundation.Nest.Burn(this.$element, 'dropdown'); 4160 Foundation.unregisterPlugin(this); 4161 } 4162 }]); 4163 4164 return DropdownMenu; 4165 }(); 4166 4167 /** 4168 * Default settings for plugin 4169 */ 4170 4171 4172 DropdownMenu.defaults = { 4173 /** 4174 * Disallows hover events from opening submenus 4175 * @option 4176 * @example false 4177 */ 4178 disableHover: false, 4179 /** 4180 * Allow a submenu to automatically close on a mouseleave event, if not clicked open. 4181 * @option 4182 * @example true 4183 */ 4184 autoclose: true, 4185 /** 4186 * Amount of time to delay opening a submenu on hover event. 4187 * @option 4188 * @example 50 4189 */ 4190 hoverDelay: 50, 4191 /** 4192 * Allow a submenu to open/remain open on parent click event. Allows cursor to move away from menu. 4193 * @option 4194 * @example true 4195 */ 4196 clickOpen: false, 4197 /** 4198 * Amount of time to delay closing a submenu on a mouseleave event. 4199 * @option 4200 * @example 500 4201 */ 4202 4203 closingTime: 500, 4204 /** 4205 * Position of the menu relative to what direction the submenus should open. Handled by JS. 4206 * @option 4207 * @example 'left' 4208 */ 4209 alignment: 'left', 4210 /** 4211 * Allow clicks on the body to close any open submenus. 4212 * @option 4213 * @example true 4214 */ 4215 closeOnClick: true, 4216 /** 4217 * Class applied to vertical oriented menus, Foundation default is `vertical`. Update this if using your own class. 4218 * @option 4219 * @example 'vertical' 4220 */ 4221 verticalClass: 'vertical', 4222 /** 4223 * Class applied to right-side oriented menus, Foundation default is `align-right`. Update this if using your own class. 4224 * @option 4225 * @example 'align-right' 4226 */ 4227 rightClass: 'align-right', 4228 /** 4229 * Boolean to force overide the clicking of links to perform default action, on second touch event for mobile. 4230 * @option 4231 * @example false 4232 */ 4233 forceFollow: true 4234 }; 4235 4236 // Window exports 4237 Foundation.plugin(DropdownMenu, 'DropdownMenu'); 4238}(jQuery); 4239'use strict'; 4240 4241var _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; }; }(); 4242 4243function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 4244 4245!function ($) { 4246 4247 /** 4248 * Equalizer module. 4249 * @module foundation.equalizer 4250 */ 4251 4252 var Equalizer = function () { 4253 /** 4254 * Creates a new instance of Equalizer. 4255 * @class 4256 * @fires Equalizer#init 4257 * @param {Object} element - jQuery object to add the trigger to. 4258 * @param {Object} options - Overrides to the default plugin settings. 4259 */ 4260 4261 function Equalizer(element, options) { 4262 _classCallCheck(this, Equalizer); 4263 4264 this.$element = element; 4265 this.options = $.extend({}, Equalizer.defaults, this.$element.data(), options); 4266 4267 this._init(); 4268 4269 Foundation.registerPlugin(this, 'Equalizer'); 4270 } 4271 4272 /** 4273 * Initializes the Equalizer plugin and calls functions to get equalizer functioning on load. 4274 * @private 4275 */ 4276 4277 4278 _createClass(Equalizer, [{ 4279 key: '_init', 4280 value: function _init() { 4281 var eqId = this.$element.attr('data-equalizer') || ''; 4282 var $watched = this.$element.find('[data-equalizer-watch="' + eqId + '"]'); 4283 4284 this.$watched = $watched.length ? $watched : this.$element.find('[data-equalizer-watch]'); 4285 this.$element.attr('data-resize', eqId || Foundation.GetYoDigits(6, 'eq')); 4286 4287 this.hasNested = this.$element.find('[data-equalizer]').length > 0; 4288 this.isNested = this.$element.parentsUntil(document.body, '[data-equalizer]').length > 0; 4289 this.isOn = false;
vendor: 4,716 bytes, lines 4290-4457
4290 this._bindHandler = { 4291 onResizeMeBound: this._onResizeMe.bind(this), 4292 onPostEqualizedBound: this._onPostEqualized.bind(this) 4293 }; 4294 4295 var imgs = this.$element.find('img'); 4296 var tooSmall; 4297 if (this.options.equalizeOn) { 4298 tooSmall = this._checkMQ(); 4299 $(window).on('changed.zf.mediaquery', this._checkMQ.bind(this)); 4300 } else { 4301 this._events(); 4302 } 4303 if (tooSmall !== undefined && tooSmall === false || tooSmall === undefined) { 4304 if (imgs.length) { 4305 Foundation.onImagesLoaded(imgs, this._reflow.bind(this)); 4306 } else { 4307 this._reflow(); 4308 } 4309 } 4310 } 4311 4312 /** 4313 * Removes event listeners if the breakpoint is too small. 4314 * @private 4315 */ 4316 4317 }, { 4318 key: '_pauseEvents', 4319 value: function _pauseEvents() { 4320 this.isOn = false; 4321 this.$element.off({ 4322 '.zf.equalizer': this._bindHandler.onPostEqualizedBound, 4323 'resizeme.zf.trigger': this._bindHandler.onResizeMeBound 4324 }); 4325 } 4326 4327 /** 4328 * function to handle $elements resizeme.zf.trigger, with bound this on _bindHandler.onResizeMeBound 4329 * @private 4330 */ 4331 4332 }, { 4333 key: '_onResizeMe', 4334 value: function _onResizeMe(e) { 4335 this._reflow(); 4336 } 4337 4338 /** 4339 * function to handle $elements postequalized.zf.equalizer, with bound this on _bindHandler.onPostEqualizedBound 4340 * @private 4341 */ 4342 4343 }, { 4344 key: '_onPostEqualized', 4345 value: function _onPostEqualized(e) { 4346 if (e.target !== this.$element[0]) { 4347 this._reflow(); 4348 } 4349 } 4350 4351 /** 4352 * Initializes events for Equalizer. 4353 * @private 4354 */ 4355 4356 }, { 4357 key: '_events', 4358 value: function _events() { 4359 var _this = this; 4360 this._pauseEvents(); 4361 if (this.hasNested) { 4362 this.$element.on('postequalized.zf.equalizer', this._bindHandler.onPostEqualizedBound); 4363 } else { 4364 this.$element.on('resizeme.zf.trigger', this._bindHandler.onResizeMeBound); 4365 } 4366 this.isOn = true; 4367 } 4368 4369 /** 4370 * Checks the current breakpoint to the minimum required size. 4371 * @private 4372 */ 4373 4374 }, { 4375 key: '_checkMQ', 4376 value: function _checkMQ() { 4377 var tooSmall = !Foundation.MediaQuery.atLeast(this.options.equalizeOn); 4378 if (tooSmall) { 4379 if (this.isOn) { 4380 this._pauseEvents(); 4381 this.$watched.css('height', 'auto'); 4382 } 4383 } else { 4384 if (!this.isOn) { 4385 this._events(); 4386 } 4387 } 4388 return tooSmall; 4389 } 4390 4391 /** 4392 * A noop version for the plugin 4393 * @private 4394 */ 4395 4396 }, { 4397 key: '_killswitch', 4398 value: function _killswitch() { 4399 return; 4400 } 4401 4402 /** 4403 * Calls necessary functions to update Equalizer upon DOM change 4404 * @private 4405 */ 4406 4407 }, { 4408 key: '_reflow', 4409 value: function _reflow() { 4410 if (!this.options.equalizeOnStack) { 4411 if (this._isStacked()) { 4412 this.$watched.css('height', 'auto'); 4413 return false; 4414 } 4415 } 4416 if (this.options.equalizeByRow) { 4417 this.getHeightsByRow(this.applyHeightByRow.bind(this)); 4418 } else { 4419 this.getHeights(this.applyHeight.bind(this)); 4420 } 4421 } 4422 4423 /** 4424 * Manually determines if the first 2 elements are *NOT* stacked. 4425 * @private 4426 */ 4427 4428 }, { 4429 key: '_isStacked', 4430 value: function _isStacked() { 4431 return this.$watched[0].getBoundingClientRect().top !== this.$watched[1].getBoundingClientRect().top; 4432 } 4433 4434 /** 4435 * Finds the outer heights of children contained within an Equalizer parent and returns them in an array 4436 * @param {Function} cb - A non-optional callback to return the heights array to. 4437 * @returns {Array} heights - An array of heights of children within Equalizer container 4438 */ 4439 4440 }, { 4441 key: 'getHeights', 4442 value: function getHeights(cb) { 4443 var heights = []; 4444 for (var i = 0, len = this.$watched.length; i < len; i++) { 4445 this.$watched[i].style.height = 'auto'; 4446 heights.push(this.$watched[i].offsetHeight); 4447 } 4448 cb(heights); 4449 } 4450 4451 /** 4452 * Finds the outer heights of children contained within an Equalizer parent and returns them in an array 4453 * @param {Function} cb - A non-optional callback to return the heights array to. 4454 * @returns {Array} groups - An array of heights of children within Equalizer container grouped by row with element,height and max as last child 4455 */ 4456 4457 }, {
vendor: 6,408 bytes, lines 4458-4662
4458 key: 'getHeightsByRow', 4459 value: function getHeightsByRow(cb) { 4460 var lastElTopOffset = this.$watched.length ? this.$watched.first().offset().top : 0, 4461 groups = [], 4462 group = 0; 4463 //group by Row 4464 groups[group] = []; 4465 for (var i = 0, len = this.$watched.length; i < len; i++) { 4466 this.$watched[i].style.height = 'auto'; 4467 //maybe could use this.$watched[i].offsetTop 4468 var elOffsetTop = $(this.$watched[i]).offset().top; 4469 if (elOffsetTop != lastElTopOffset) { 4470 group++; 4471 groups[group] = []; 4472 lastElTopOffset = elOffsetTop; 4473 } 4474 groups[group].push([this.$watched[i], this.$watched[i].offsetHeight]); 4475 } 4476 4477 for (var j = 0, ln = groups.length; j < ln; j++) { 4478 var heights = $(groups[j]).map(function () { 4479 return this[1]; 4480 }).get(); 4481 var max = Math.max.apply(null, heights); 4482 groups[j].push(max); 4483 } 4484 cb(groups); 4485 } 4486 4487 /** 4488 * Changes the CSS height property of each child in an Equalizer parent to match the tallest 4489 * @param {array} heights - An array of heights of children within Equalizer container 4490 * @fires Equalizer#preequalized 4491 * @fires Equalizer#postequalized 4492 */ 4493 4494 }, { 4495 key: 'applyHeight', 4496 value: function applyHeight(heights) { 4497 var max = Math.max.apply(null, heights); 4498 /** 4499 * Fires before the heights are applied 4500 * @event Equalizer#preequalized 4501 */ 4502 this.$element.trigger('preequalized.zf.equalizer'); 4503 4504 this.$watched.css('height', max); 4505 4506 /** 4507 * Fires when the heights have been applied 4508 * @event Equalizer#postequalized 4509 */ 4510 this.$element.trigger('postequalized.zf.equalizer'); 4511 } 4512 4513 /** 4514 * Changes the CSS height property of each child in an Equalizer parent to match the tallest by row 4515 * @param {array} groups - An array of heights of children within Equalizer container grouped by row with element,height and max as last child 4516 * @fires Equalizer#preequalized 4517 * @fires Equalizer#preequalizedRow 4518 * @fires Equalizer#postequalizedRow 4519 * @fires Equalizer#postequalized 4520 */ 4521 4522 }, { 4523 key: 'applyHeightByRow', 4524 value: function applyHeightByRow(groups) { 4525 /** 4526 * Fires before the heights are applied 4527 */ 4528 this.$element.trigger('preequalized.zf.equalizer'); 4529 for (var i = 0, len = groups.length; i < len; i++) { 4530 var groupsILength = groups[i].length, 4531 max = groups[i][groupsILength - 1]; 4532 if (groupsILength <= 2) { 4533 $(groups[i][0][0]).css({ 'height': 'auto' }); 4534 continue; 4535 } 4536 /** 4537 * Fires before the heights per row are applied 4538 * @event Equalizer#preequalizedRow 4539 */ 4540 this.$element.trigger('preequalizedrow.zf.equalizer'); 4541 for (var j = 0, lenJ = groupsILength - 1; j < lenJ; j++) { 4542 $(groups[i][j][0]).css({ 'height': max }); 4543 } 4544 /** 4545 * Fires when the heights per row have been applied 4546 * @event Equalizer#postequalizedRow 4547 */ 4548 this.$element.trigger('postequalizedrow.zf.equalizer'); 4549 } 4550 /** 4551 * Fires when the heights have been applied 4552 */ 4553 this.$element.trigger('postequalized.zf.equalizer'); 4554 } 4555 4556 /** 4557 * Destroys an instance of Equalizer. 4558 * @function 4559 */ 4560 4561 }, { 4562 key: 'destroy', 4563 value: function destroy() { 4564 this._pauseEvents(); 4565 this.$watched.css('height', 'auto'); 4566 4567 Foundation.unregisterPlugin(this); 4568 } 4569 }]); 4570 4571 return Equalizer; 4572 }(); 4573 4574 /** 4575 * Default settings for plugin 4576 */ 4577 4578 4579 Equalizer.defaults = { 4580 /** 4581 * Enable height equalization when stacked on smaller screens. 4582 * @option 4583 * @example true 4584 */ 4585 equalizeOnStack: true, 4586 /** 4587 * Enable height equalization row by row. 4588 * @option 4589 * @example false 4590 */ 4591 equalizeByRow: false, 4592 /** 4593 * String representing the minimum breakpoint size the plugin should equalize heights on. 4594 * @option 4595 * @example 'medium' 4596 */ 4597 equalizeOn: '' 4598 }; 4599 4600 // Window exports 4601 Foundation.plugin(Equalizer, 'Equalizer'); 4602}(jQuery); 4603'use strict'; 4604 4605var _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; }; }(); 4606 4607function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 4608 4609!function ($) { 4610 4611 /** 4612 * Interchange module. 4613 * @module foundation.interchange 4614 * @requires foundation.util.mediaQuery 4615 * @requires foundation.util.timerAndImageLoader 4616 */ 4617 4618 var Interchange = function () { 4619 /** 4620 * Creates a new instance of Interchange. 4621 * @class 4622 * @fires Interchange#init 4623 * @param {Object} element - jQuery object to add the trigger to. 4624 * @param {Object} options - Overrides to the default plugin settings. 4625 */ 4626 4627 function Interchange(element, options) { 4628 _classCallCheck(this, Interchange); 4629 4630 this.$element = element; 4631 this.options = $.extend({}, Interchange.defaults, options); 4632 this.rules = []; 4633 this.currentPath = ''; 4634 4635 this._init(); 4636 this._events(); 4637 4638 Foundation.registerPlugin(this, 'Interchange'); 4639 } 4640 4641 /** 4642 * Initializes the Interchange plugin and calls functions to get interchange functioning on load. 4643 * @function 4644 * @private 4645 */ 4646 4647 4648 _createClass(Interchange, [{ 4649 key: '_init', 4650 value: function _init() { 4651 this._addBreakpoints(); 4652 this._generateRules(); 4653 this._reflow(); 4654 } 4655 4656 /** 4657 * Initializes events for Interchange. 4658 * @function 4659 * @private 4660 */ 4661 4662 }, {
4663 key: '_events', 4664 value: function _events() { 4665 $(window).on('resize.zf.interchange', Foundation.util.throttle(this._reflow.bind(this), 50)); 4666 } 4667 4668 /** 4669 * Calls necessary functions to update Interchange upon DOM change 4670 * @function 4671 * @private 4672 */ 4673 4674 }, { 4675 key: '_reflow', 4676 value: function _reflow() { 4677 var match; 4678 4679 // Iterate through each rule, but only save the last match 4680 for (var i in this.rules) { 4681 if (this.rules.hasOwnProperty(i)) { 4682 var rule = this.rules[i]; 4683 4684 if (window.matchMedia(rule.query).matches) { 4685 match = rule; 4686 } 4687 } 4688 } 4689 4690 if (match) { 4691 this.replace(match.path); 4692 } 4693 } 4694 4695 /** 4696 * Gets the Foundation breakpoints and adds them to the Interchange.SPECIAL_QUERIES object. 4697 * @function 4698 * @private 4699 */ 4700 4701 }, { 4702 key: '_addBreakpoints', 4703 value: function _addBreakpoints() { 4704 for (var i in Foundation.MediaQuery.queries) { 4705 if (Foundation.MediaQuery.queries.hasOwnProperty(i)) { 4706 var query = Foundation.MediaQuery.queries[i]; 4707 Interchange.SPECIAL_QUERIES[query.name] = query.value; 4708 } 4709 } 4710 } 4711 4712 /** 4713 * Checks the Interchange element for the provided media query + content pairings 4714 * @function 4715 * @private 4716 * @param {Object} element - jQuery object that is an Interchange instance 4717 * @returns {Array} scenarios - Array of objects that have 'mq' and 'path' keys with corresponding keys 4718 */ 4719 4720 }, { 4721 key: '_generateRules', 4722 value: function _generateRules(element) { 4723 var rulesList = []; 4724 var rules; 4725 4726 if (this.options.rules) { 4727 rules = this.options.rules; 4728 } else { 4729 rules = this.$element.data('interchange').match(/\[.*?\]/g); 4730 } 4731 4732 for (var i in rules) { 4733 if (rules.hasOwnProperty(i)) { 4734 var rule = rules[i].slice(1, -1).split(', '); 4735 var path = rule.slice(0, -1).join(''); 4736 var query = rule[rule.length - 1]; 4737 4738 if (Interchange.SPECIAL_QUERIES[query]) { 4739 query = Interchange.SPECIAL_QUERIES[query]; 4740 } 4741 4742 rulesList.push({ 4743 path: path, 4744 query: query 4745 }); 4746 } 4747 } 4748 4749 this.rules = rulesList; 4750 } 4751 4752 /** 4753 * Update the `src` property of an image, or change the HTML of a container, to the specified path. 4754 * @function 4755 * @param {String} path - Path to the image or HTML partial. 4756 * @fires Interchange#replaced 4757 */ 4758 4759 }, { 4760 key: 'replace', 4761 value: function replace(path) { 4762 if (this.currentPath === path) return; 4763 4764 var _this = this, 4765 trigger = 'replaced.zf.interchange'; 4766 4767 // Replacing images 4768 if (this.$element[0].nodeName === 'IMG') { 4769 this.$element.attr('src', path).load(function () { 4770 _this.currentPath = path; 4771 }).trigger(trigger); 4772 } 4773 // Replacing background images 4774 else if (path.match(/\.(gif|jpg|jpeg|png|svg|tiff)([?#].*)?/i)) { 4775 this.$element.css({ 'background-image': 'url(' + path + ')' }).trigger(trigger); 4776 } 4777 // Replacing HTML 4778 else { 4779 $.get(path, function (response) { 4780 _this.$element.html(response).trigger(trigger); 4781 $(response).foundation(); 4782 _this.currentPath = path; 4783 }); 4784 } 4785 4786 /** 4787 * Fires when content in an Interchange element is done being loaded. 4788 * @event Interchange#replaced 4789 */ 4790 // this.$element.trigger('replaced.zf.interchange'); 4791 } 4792 4793 /** 4794 * Destroys an instance of interchange. 4795 * @function 4796 */ 4797 4798 }, { 4799 key: 'destroy', 4800 value: function destroy() { 4801 //TODO this. 4802 } 4803 }]); 4804 4805 return Interchange; 4806 }(); 4807 4808 /** 4809 * Default settings for plugin 4810 */ 4811 4812 4813 Interchange.defaults = { 4814 /** 4815 * Rules to be applied to Interchange elements. Set with the `data-interchange` array notation. 4816 * @option 4817 */ 4818 rules: null 4819 }; 4820 4821 Interchange.SPECIAL_QUERIES = { 4822 'landscape': 'screen and (orientation: landscape)', 4823 'portrait': 'screen and (orientation: portrait)', 4824 '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)' 4825 }; 4826 4827 // Window exports 4828 Foundation.plugin(Interchange, 'Interchange'); 4829}(jQuery); 4830'use strict'; 4831 4832var _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; }; }(); 4833 4834function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 4835 4836!function ($) { 4837 4838 /** 4839 * Magellan module. 4840 * @module foundation.magellan 4841 */ 4842 4843 var Magellan = function () { 4844 /** 4845 * Creates a new instance of Magellan. 4846 * @class 4847 * @fires Magellan#init 4848 * @param {Object} element - jQuery object to add the trigger to. 4849 * @param {Object} options - Overrides to the default plugin settings. 4850 */ 4851 4852 function Magellan(element, options) { 4853 _classCallCheck(this, Magellan); 4854 4855 this.$element = element; 4856 this.options = $.extend({}, Magellan.defaults, this.$element.data(), options); 4857 4858 this._init(); 4859 4860 Foundation.registerPlugin(this, 'Magellan'); 4861 } 4862 4863 /** 4864 * Initializes the Magellan plugin and calls functions to get equalizer functioning on load. 4865 * @private 4866 */ 4867 4868 4869 _createClass(Magellan, [{ 4870 key: '_init', 4871 value: function _init() { 4872 var id = this.$element[0].id || Foundation.GetYoDigits(6, 'magellan'); 4873 var _this = this; 4874 this.$targets = $('[data-magellan-target]'); 4875 this.$links = this.$element.find('a'); 4876 this.$element.attr({ 4877 'data-resize': id, 4878 'data-scroll': id, 4879 'id': id 4880 }); 4881 this.$active = $(); 4882 this.scrollPos = parseInt(window.pageYOffset, 10); 4883 4884 this._events(); 4885 } 4886 4887 /** 4888 * Calculates an array of pixel values that are the demarcation lines between locations on the page. 4889 * Can be invoked if new elements are added or the size of a location changes. 4890 * @function 4891 */ 4892 4893 }, {
4894 key: 'calcPoints', 4895 value: function calcPoints() { 4896 var _this = this, 4897 body = document.body, 4898 html = document.documentElement; 4899 4900 this.points = []; 4901 this.winHeight = Math.round(Math.max(window.innerHeight, html.clientHeight)); 4902 this.docHeight = Math.round(Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)); 4903 4904 this.$targets.each(function () { 4905 var $tar = $(this), 4906 pt = Math.round($tar.offset().top - _this.options.threshold); 4907 $tar.targetPoint = pt; 4908 _this.points.push(pt); 4909 }); 4910 } 4911 4912 /** 4913 * Initializes events for Magellan. 4914 * @private 4915 */ 4916 4917 }, { 4918 key: '_events', 4919 value: function _events() { 4920 var _this = this, 4921 $body = $('html, body'), 4922 opts = { 4923 duration: _this.options.animationDuration, 4924 easing: _this.options.animationEasing 4925 }; 4926 $(window).one('load', function () { 4927 if (_this.options.deepLinking) { 4928 if (location.hash) { 4929 _this.scrollToLoc(location.hash); 4930 } 4931 } 4932 _this.calcPoints(); 4933 _this._updateActive(); 4934 }); 4935 4936 this.$element.on({ 4937 'resizeme.zf.trigger': this.reflow.bind(this), 4938 'scrollme.zf.trigger': this._updateActive.bind(this) 4939 }).on('click.zf.magellan', 'a[href^="#"]', function (e) { 4940 e.preventDefault(); 4941 var arrival = this.getAttribute('href'); 4942 _this.scrollToLoc(arrival); 4943 }); 4944 } 4945 4946 /** 4947 * Function to scroll to a given location on the page. 4948 * @param {String} loc - a properly formatted jQuery id selector. Example: '#foo' 4949 * @function 4950 */ 4951 4952 }, { 4953 key: 'scrollToLoc', 4954 value: function scrollToLoc(loc) { 4955 var scrollPos = Math.round($(loc).offset().top - this.options.threshold / 2 - this.options.barOffset); 4956 4957 $('html, body').stop(true).animate({ scrollTop: scrollPos }, this.options.animationDuration, this.options.animationEasing); 4958 } 4959 4960 /** 4961 * Calls necessary functions to update Magellan upon DOM change 4962 * @function 4963 */ 4964 4965 }, { 4966 key: 'reflow', 4967 value: function reflow() { 4968 this.calcPoints(); 4969 this._updateActive(); 4970 } 4971 4972 /** 4973 * Updates the visibility of an active location link, and updates the url hash for the page, if deepLinking enabled. 4974 * @private 4975 * @function 4976 * @fires Magellan#update 4977 */ 4978 4979 }, { 4980 key: '_updateActive', 4981 value: function _updateActive() /*evt, elem, scrollPos*/{ 4982 var winPos = /*scrollPos ||*/parseInt(window.pageYOffset, 10), 4983 curIdx; 4984 4985 if (winPos + this.winHeight === this.docHeight) { 4986 curIdx = this.points.length - 1; 4987 } else if (winPos < this.points[0]) { 4988 curIdx = 0; 4989 } else { 4990 var isDown = this.scrollPos < winPos, 4991 _this = this, 4992 curVisible = this.points.filter(function (p, i) { 4993 return isDown ? p - _this.options.barOffset <= winPos : p - _this.options.barOffset - _this.options.threshold <= winPos; 4994 }); 4995 curIdx = curVisible.length ? curVisible.length - 1 : 0; 4996 } 4997 4998 this.$active.removeClass(this.options.activeClass); 4999 this.$active = this.$links.eq(curIdx).addClass(this.options.activeClass); 5000 5001 if (this.options.deepLinking) { 5002 var hash = this.$active[0].getAttribute('href'); 5003 if (window.history.pushState) { 5004 window.history.pushState(null, null, hash); 5005 } else { 5006 window.location.hash = hash; 5007 } 5008 } 5009 5010 this.scrollPos = winPos; 5011 /** 5012 * Fires when magellan is finished updating to the new active element. 5013 * @event Magellan#update 5014 */ 5015 this.$element.trigger('update.zf.magellan', [this.$active]); 5016 } 5017 5018 /** 5019 * Destroys an instance of Magellan and resets the url of the window. 5020 * @function 5021 */ 5022 5023 }, {
5024 key: 'destroy', 5025 value: function destroy() { 5026 this.$element.off('.zf.trigger .zf.magellan').find('.' + this.options.activeClass).removeClass(this.options.activeClass); 5027 5028 if (this.options.deepLinking) { 5029 var hash = this.$active[0].getAttribute('href'); 5030 window.location.hash.replace(hash, ''); 5031 } 5032 5033 Foundation.unregisterPlugin(this); 5034 } 5035 }]); 5036 5037 return Magellan; 5038 }(); 5039 5040 /** 5041 * Default settings for plugin 5042 */ 5043 5044 5045 Magellan.defaults = { 5046 /** 5047 * Amount of time, in ms, the animated scrolling should take between locations. 5048 * @option 5049 * @example 500 5050 */ 5051 animationDuration: 500, 5052 /** 5053 * Animation style to use when scrolling between locations. 5054 * @option 5055 * @example 'ease-in-out' 5056 */ 5057 animationEasing: 'linear', 5058 /** 5059 * Number of pixels to use as a marker for location changes. 5060 * @option 5061 * @example 50 5062 */ 5063 threshold: 50, 5064 /** 5065 * Class applied to the active locations link on the magellan container. 5066 * @option 5067 * @example 'active' 5068 */ 5069 activeClass: 'active', 5070 /** 5071 * Allows the script to manipulate the url of the current page, and if supported, alter the history. 5072 * @option 5073 * @example true 5074 */ 5075 deepLinking: false, 5076 /** 5077 * Number of pixels to offset the scroll of the page on item click if using a sticky nav bar. 5078 * @option 5079 * @example 25 5080 */ 5081 barOffset: 0 5082 }; 5083 5084 // Window exports 5085 Foundation.plugin(Magellan, 'Magellan'); 5086}(jQuery); 5087'use strict'; 5088 5089var _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; }; }(); 5090 5091function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 5092 5093!function ($) { 5094 5095 /** 5096 * OffCanvas module. 5097 * @module foundation.offcanvas 5098 * @requires foundation.util.mediaQuery 5099 * @requires foundation.util.triggers 5100 * @requires foundation.util.motion 5101 */ 5102 5103 var OffCanvas = function () { 5104 /** 5105 * Creates a new instance of an off-canvas wrapper. 5106 * @class 5107 * @fires OffCanvas#init 5108 * @param {Object} element - jQuery object to initialize. 5109 * @param {Object} options - Overrides to the default plugin settings. 5110 */ 5111 5112 function OffCanvas(element, options) { 5113 _classCallCheck(this, OffCanvas); 5114 5115 this.$element = element; 5116 this.options = $.extend({}, OffCanvas.defaults, this.$element.data(), options); 5117 this.$lastTrigger = $(); 5118 this.$triggers = $(); 5119 5120 this._init(); 5121 this._events(); 5122 5123 Foundation.registerPlugin(this, 'OffCanvas'); 5124 } 5125 5126 /** 5127 * Initializes the off-canvas wrapper by adding the exit overlay (if needed). 5128 * @function 5129 * @private 5130 */ 5131 5132 5133 _createClass(OffCanvas, [{ 5134 key: '_init', 5135 value: function _init() { 5136 var id = this.$element.attr('id'); 5137 5138 this.$element.attr('aria-hidden', 'true'); 5139 5140 // Find triggers that affect this element and add aria-expanded to them 5141 this.$triggers = $(document).find('[data-open="' + id + '"], [data-close="' + id + '"], [data-toggle="' + id + '"]').attr('aria-expanded', 'false').attr('aria-controls', id); 5142 5143 // Add a close trigger over the body if necessary 5144 if (this.options.closeOnClick) { 5145 if ($('.js-off-canvas-exit').length) { 5146 this.$exiter = $('.js-off-canvas-exit'); 5147 } else { 5148 var exiter = document.createElement('div'); 5149 exiter.setAttribute('class', 'js-off-canvas-exit'); 5150 $('[data-off-canvas-content]').append(exiter); 5151 5152 this.$exiter = $(exiter); 5153 } 5154 } 5155 5156 this.options.isRevealed = this.options.isRevealed || new RegExp(this.options.revealClass, 'g').test(this.$element[0].className); 5157 5158 if (this.options.isRevealed) { 5159 this.options.revealOn = this.options.revealOn || this.$element[0].className.match(/(reveal-for-medium|reveal-for-large)/g)[0].split('-')[2]; 5160 this._setMQChecker(); 5161 } 5162 if (!this.options.transitionTime) { 5163 this.options.transitionTime = parseFloat(window.getComputedStyle($('[data-off-canvas-wrapper]')[0]).transitionDuration) * 1000; 5164 } 5165 } 5166 5167 /** 5168 * Adds event handlers to the off-canvas wrapper and the exit overlay. 5169 * @function 5170 * @private 5171 */ 5172 5173 }, {
5174 key: '_events', 5175 value: function _events() { 5176 this.$element.off('.zf.trigger .zf.offcanvas').on({ 5177 'open.zf.trigger': this.open.bind(this), 5178 'close.zf.trigger': this.close.bind(this), 5179 'toggle.zf.trigger': this.toggle.bind(this), 5180 'keydown.zf.offcanvas': this._handleKeyboard.bind(this) 5181 }); 5182 5183 if (this.options.closeOnClick && this.$exiter.length) { 5184 this.$exiter.on({ 'click.zf.offcanvas': this.close.bind(this) }); 5185 } 5186 } 5187 5188 /** 5189 * Applies event listener for elements that will reveal at certain breakpoints. 5190 * @private 5191 */ 5192 5193 }, { 5194 key: '_setMQChecker', 5195 value: function _setMQChecker() { 5196 var _this = this; 5197 5198 $(window).on('changed.zf.mediaquery', function () { 5199 if (Foundation.MediaQuery.atLeast(_this.options.revealOn)) { 5200 _this.reveal(true); 5201 } else { 5202 _this.reveal(false); 5203 } 5204 }).one('load.zf.offcanvas', function () { 5205 if (Foundation.MediaQuery.atLeast(_this.options.revealOn)) { 5206 _this.reveal(true); 5207 } 5208 }); 5209 } 5210 5211 /** 5212 * Handles the revealing/hiding the off-canvas at breakpoints, not the same as open. 5213 * @param {Boolean} isRevealed - true if element should be revealed. 5214 * @function 5215 */ 5216 5217 }, { 5218 key: 'reveal', 5219 value: function reveal(isRevealed) { 5220 var $closer = this.$element.find('[data-close]'); 5221 if (isRevealed) { 5222 this.close(); 5223 this.isRevealed = true; 5224 // if (!this.options.forceTop) { 5225 // var scrollPos = parseInt(window.pageYOffset); 5226 // this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)'; 5227 // } 5228 // if (this.options.isSticky) { this._stick(); } 5229 this.$element.off('open.zf.trigger toggle.zf.trigger'); 5230 if ($closer.length) { 5231 $closer.hide(); 5232 } 5233 } else { 5234 this.isRevealed = false; 5235 // if (this.options.isSticky || !this.options.forceTop) { 5236 // this.$element[0].style.transform = ''; 5237 // $(window).off('scroll.zf.offcanvas'); 5238 // } 5239 this.$element.on({ 5240 'open.zf.trigger': this.open.bind(this), 5241 'toggle.zf.trigger': this.toggle.bind(this) 5242 }); 5243 if ($closer.length) { 5244 $closer.show(); 5245 } 5246 } 5247 } 5248 5249 /** 5250 * Opens the off-canvas menu. 5251 * @function 5252 * @param {Object} event - Event object passed from listener. 5253 * @param {jQuery} trigger - element that triggered the off-canvas to open. 5254 * @fires OffCanvas#opened 5255 */ 5256 5257 }, { 5258 key: 'open', 5259 value: function open(event, trigger) { 5260 if (this.$element.hasClass('is-open') || this.isRevealed) { 5261 return; 5262 } 5263 var _this = this, 5264 $body = $(document.body); 5265 5266 if (this.options.forceTop) { 5267 $('body').scrollTop(0); 5268 } 5269 // window.pageYOffset = 0; 5270 5271 // if (!this.options.forceTop) { 5272 // var scrollPos = parseInt(window.pageYOffset); 5273 // this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)'; 5274 // if (this.$exiter.length) { 5275 // this.$exiter[0].style.transform = 'translate(0,' + scrollPos + 'px)'; 5276 // } 5277 // } 5278 /** 5279 * Fires when the off-canvas menu opens. 5280 * @event OffCanvas#opened 5281 */ 5282 Foundation.Move(this.options.transitionTime, this.$element, function () { 5283 $('[data-off-canvas-wrapper]').addClass('is-off-canvas-open is-open-' + _this.options.position); 5284 5285 _this.$element.addClass('is-open'); 5286 5287 // if (_this.options.isSticky) { 5288 // _this._stick(); 5289 // } 5290 }); 5291 5292 this.$triggers.attr('aria-expanded', 'true'); 5293 this.$element.attr('aria-hidden', 'false').trigger('opened.zf.offcanvas'); 5294 5295 if (this.options.closeOnClick) { 5296 this.$exiter.addClass('is-visible'); 5297 } 5298 5299 if (trigger) { 5300 this.$lastTrigger = trigger; 5301 } 5302 5303 if (this.options.autoFocus) { 5304 this.$element.one(Foundation.transitionend(this.$element), function () { 5305 _this.$element.find('a, button').eq(0).focus(); 5306 }); 5307 } 5308 5309 if (this.options.trapFocus) { 5310 $('[data-off-canvas-content]').attr('tabindex', '-1'); 5311 this._trapFocus(); 5312 } 5313 } 5314 5315 /** 5316 * Traps focus within the offcanvas on open. 5317 * @private 5318 */ 5319 5320 }, {
5321 key: '_trapFocus', 5322 value: function _trapFocus() { 5323 var focusable = Foundation.Keyboard.findFocusable(this.$element), 5324 first = focusable.eq(0), 5325 last = focusable.eq(-1); 5326 5327 focusable.off('.zf.offcanvas').on('keydown.zf.offcanvas', function (e) { 5328 if (e.which === 9 || e.keycode === 9) { 5329 if (e.target === last[0] && !e.shiftKey) { 5330 e.preventDefault(); 5331 first.focus(); 5332 } 5333 if (e.target === first[0] && e.shiftKey) { 5334 e.preventDefault(); 5335 last.focus(); 5336 } 5337 } 5338 }); 5339 } 5340 5341 /** 5342 * Allows the offcanvas to appear sticky utilizing translate properties. 5343 * @private 5344 */ 5345 // OffCanvas.prototype._stick = function() { 5346 // var elStyle = this.$element[0].style; 5347 // 5348 // if (this.options.closeOnClick) { 5349 // var exitStyle = this.$exiter[0].style; 5350 // } 5351 // 5352 // $(window).on('scroll.zf.offcanvas', function(e) { 5353 // console.log(e); 5354 // var pageY = window.pageYOffset; 5355 // elStyle.transform = 'translate(0,' + pageY + 'px)'; 5356 // if (exitStyle !== undefined) { exitStyle.transform = 'translate(0,' + pageY + 'px)'; } 5357 // }); 5358 // // this.$element.trigger('stuck.zf.offcanvas'); 5359 // }; 5360 /** 5361 * Closes the off-canvas menu. 5362 * @function 5363 * @param {Function} cb - optional cb to fire after closure. 5364 * @fires OffCanvas#closed 5365 */ 5366 5367 }, { 5368 key: 'close', 5369 value: function close(cb) { 5370 if (!this.$element.hasClass('is-open') || this.isRevealed) { 5371 return; 5372 } 5373 5374 var _this = this; 5375 5376 // Foundation.Move(this.options.transitionTime, this.$element, function() { 5377 $('[data-off-canvas-wrapper]').removeClass('is-off-canvas-open is-open-' + _this.options.position); 5378 _this.$element.removeClass('is-open'); 5379 // Foundation._reflow(); 5380 // }); 5381 this.$element.attr('aria-hidden', 'true') 5382 /** 5383 * Fires when the off-canvas menu opens. 5384 * @event OffCanvas#closed 5385 */ 5386 .trigger('closed.zf.offcanvas'); 5387 // if (_this.options.isSticky || !_this.options.forceTop) { 5388 // setTimeout(function() { 5389 // _this.$element[0].style.transform = ''; 5390 // $(window).off('scroll.zf.offcanvas'); 5391 // }, this.options.transitionTime); 5392 // } 5393 if (this.options.closeOnClick) { 5394 this.$exiter.removeClass('is-visible'); 5395 } 5396 5397 this.$triggers.attr('aria-expanded', 'false'); 5398 if (this.options.trapFocus) { 5399 $('[data-off-canvas-content]').removeAttr('tabindex'); 5400 } 5401 } 5402 5403 /** 5404 * Toggles the off-canvas menu open or closed. 5405 * @function 5406 * @param {Object} event - Event object passed from listener. 5407 * @param {jQuery} trigger - element that triggered the off-canvas to open. 5408 */ 5409 5410 }, { 5411 key: 'toggle', 5412 value: function toggle(event, trigger) { 5413 if (this.$element.hasClass('is-open')) { 5414 this.close(event, trigger); 5415 } else { 5416 this.open(event, trigger); 5417 } 5418 } 5419 5420 /** 5421 * 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. 5422 * @function 5423 * @private 5424 */ 5425 5426 }, { 5427 key: '_handleKeyboard', 5428 value: function _handleKeyboard(event) { 5429 if (event.which !== 27) return; 5430 5431 event.stopPropagation(); 5432 event.preventDefault(); 5433 this.close(); 5434 this.$lastTrigger.focus(); 5435 } 5436 5437 /** 5438 * Destroys the offcanvas plugin. 5439 * @function 5440 */ 5441 5442 }, { 5443 key: 'destroy', 5444 value: function destroy() { 5445 this.close(); 5446 this.$element.off('.zf.trigger .zf.offcanvas'); 5447 this.$exiter.off('.zf.offcanvas'); 5448 5449 Foundation.unregisterPlugin(this); 5450 } 5451 }]); 5452 5453 return OffCanvas; 5454 }(); 5455 5456 OffCanvas.defaults = { 5457 /** 5458 * Allow the user to click outside of the menu to close it. 5459 * @option 5460 * @example true 5461 */ 5462 closeOnClick: true, 5463 5464 /** 5465 * Amount of time in ms the open and close transition requires. If none selected, pulls from body style. 5466 * @option 5467 * @example 500 5468 */ 5469 transitionTime: 0, 5470 5471 /** 5472 * Direction the offcanvas opens from. Determines class applied to body. 5473 * @option 5474 * @example left 5475 */ 5476 position: 'left', 5477 5478 /** 5479 * Force the page to scroll to top on open. 5480 * @option 5481 * @example true 5482 */ 5483 forceTop: true, 5484 5485 /** 5486 * Allow the offcanvas to remain open for certain breakpoints. 5487 * @option 5488 * @example false 5489 */ 5490 isRevealed: false, 5491 5492 /** 5493 * Breakpoint at which to reveal. JS will use a RegExp to target standard classes, if changing classnames, pass your class with the `revealClass` option. 5494 * @option 5495 * @example reveal-for-large 5496 */ 5497 revealOn: null, 5498 5499 /** 5500 * Force focus to the offcanvas on open. If true, will focus the opening trigger on close. 5501 * @option 5502 * @example true 5503 */ 5504 autoFocus: true, 5505 5506 /** 5507 * Class used to force an offcanvas to remain open. Foundation defaults for this are `reveal-for-large` & `reveal-for-medium`. 5508 * @option 5509 * TODO improve the regex testing for this. 5510 * @example reveal-for-large 5511 */ 5512 revealClass: 'reveal-for-', 5513 5514 /** 5515 * Triggers optional focus trapping when opening an offcanvas. Sets tabindex of [data-off-canvas-content] to -1 for accessibility purposes. 5516 * @option 5517 * @example true 5518 */ 5519 trapFocus: false 5520 }; 5521 5522 // Window exports 5523 Foundation.plugin(OffCanvas, 'OffCanvas'); 5524}(jQuery); 5525'use strict'; 5526 5527var _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; }; }(); 5528 5529function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 5530 5531!function ($) { 5532 5533 /** 5534 * Orbit module. 5535 * @module foundation.orbit 5536 * @requires foundation.util.keyboard 5537 * @requires foundation.util.motion 5538 * @requires foundation.util.timerAndImageLoader 5539 * @requires foundation.util.touch 5540 */ 5541 5542 var Orbit = function () { 5543 /** 5544 * Creates a new instance of an orbit carousel. 5545 * @class 5546 * @param {jQuery} element - jQuery object to make into an Orbit Carousel. 5547 * @param {Object} options - Overrides to the default plugin settings. 5548 */ 5549 5550 function Orbit(element, options) { 5551 _classCallCheck(this, Orbit); 5552 5553 this.$element = element; 5554 this.options = $.extend({}, Orbit.defaults, this.$element.data(), options); 5555 5556 this._init(); 5557
5558 Foundation.registerPlugin(this, 'Orbit'); 5559 Foundation.Keyboard.register('Orbit', { 5560 'ltr': { 5561 'ARROW_RIGHT': 'next', 5562 'ARROW_LEFT': 'previous' 5563 }, 5564 'rtl': { 5565 'ARROW_LEFT': 'next', 5566 'ARROW_RIGHT': 'previous' 5567 } 5568 }); 5569 } 5570 5571 /** 5572 * Initializes the plugin by creating jQuery collections, setting attributes, and starting the animation. 5573 * @function 5574 * @private 5575 */ 5576 5577 5578 _createClass(Orbit, [{ 5579 key: '_init', 5580 value: function _init() { 5581 this.$wrapper = this.$element.find('.' + this.options.containerClass); 5582 this.$slides = this.$element.find('.' + this.options.slideClass); 5583 var $images = this.$element.find('img'), 5584 initActive = this.$slides.filter('.is-active'); 5585 5586 if (!initActive.length) { 5587 this.$slides.eq(0).addClass('is-active'); 5588 } 5589 5590 if (!this.options.useMUI) { 5591 this.$slides.addClass('no-motionui'); 5592 } 5593 5594 if ($images.length) { 5595 Foundation.onImagesLoaded($images, this._prepareForOrbit.bind(this)); 5596 } else { 5597 this._prepareForOrbit(); //hehe 5598 } 5599 5600 if (this.options.bullets) { 5601 this._loadBullets(); 5602 } 5603 5604 this._events(); 5605 5606 if (this.options.autoPlay && this.$slides.length > 1) { 5607 this.geoSync(); 5608 } 5609 5610 if (this.options.accessible) { 5611 // allow wrapper to be focusable to enable arrow navigation 5612 this.$wrapper.attr('tabindex', 0); 5613 } 5614 } 5615 5616 /** 5617 * Creates a jQuery collection of bullets, if they are being used. 5618 * @function 5619 * @private 5620 */ 5621 5622 }, { 5623 key: '_loadBullets', 5624 value: function _loadBullets() { 5625 this.$bullets = this.$element.find('.' + this.options.boxOfBullets).find('button'); 5626 } 5627 5628 /** 5629 * Sets a `timer` object on the orbit, and starts the counter for the next slide. 5630 * @function 5631 */ 5632 5633 }, { 5634 key: 'geoSync', 5635 value: function geoSync() { 5636 var _this = this; 5637 this.timer = new Foundation.Timer(this.$element, { 5638 duration: this.options.timerDelay, 5639 infinite: false 5640 }, function () { 5641 _this.changeSlide(true); 5642 }); 5643 this.timer.start(); 5644 } 5645 5646 /** 5647 * Sets wrapper and slide heights for the orbit. 5648 * @function 5649 * @private 5650 */ 5651 5652 }, { 5653 key: '_prepareForOrbit', 5654 value: function _prepareForOrbit() { 5655 var _this = this; 5656 this._setWrapperHeight(function (max) { 5657 _this._setSlideHeight(max); 5658 }); 5659 } 5660 5661 /** 5662 * Calulates the height of each slide in the collection, and uses the tallest one for the wrapper height. 5663 * @function 5664 * @private 5665 * @param {Function} cb - a callback function to fire when complete. 5666 */ 5667 5668 }, { 5669 key: '_setWrapperHeight', 5670 value: function _setWrapperHeight(cb) { 5671 //rewrite this to `for` loop 5672 var max = 0, 5673 temp, 5674 counter = 0; 5675 5676 this.$slides.each(function () { 5677 temp = this.getBoundingClientRect().height; 5678 $(this).attr('data-slide', counter); 5679 5680 if (counter) { 5681 //if not the first slide, set css position and display property 5682 $(this).css({ 'position': 'relative', 'display': 'none' }); 5683 } 5684 max = temp > max ? temp : max; 5685 counter++; 5686 }); 5687 5688 if (counter === this.$slides.length) { 5689 this.$wrapper.css({ 'height': max }); //only change the wrapper height property once. 5690 cb(max); //fire callback with max height dimension. 5691 } 5692 } 5693 5694 /** 5695 * Sets the max-height of each slide. 5696 * @function 5697 * @private 5698 */ 5699 5700 }, { 5701 key: '_setSlideHeight', 5702 value: function _setSlideHeight(height) { 5703 this.$slides.each(function () { 5704 $(this).css('max-height', height); 5705 }); 5706 } 5707 5708 /** 5709 * Adds event listeners to basically everything within the element. 5710 * @function 5711 * @private 5712 */ 5713 5714 }, {
vendor: 6,343 bytes, lines 5715-5858
5715 key: '_events', 5716 value: function _events() { 5717 var _this = this; 5718 5719 //*************************************** 5720 //**Now using custom event - thanks to:** 5721 //** Yohai Ararat of Toronto ** 5722 //*************************************** 5723 if (this.$slides.length > 1) { 5724 5725 if (this.options.swipe) { 5726 this.$slides.off('swipeleft.zf.orbit swiperight.zf.orbit').on('swipeleft.zf.orbit', function (e) { 5727 e.preventDefault(); 5728 _this.changeSlide(true); 5729 }).on('swiperight.zf.orbit', function (e) { 5730 e.preventDefault(); 5731 _this.changeSlide(false); 5732 }); 5733 } 5734 //*************************************** 5735 5736 if (this.options.autoPlay) { 5737 this.$slides.on('click.zf.orbit', function () { 5738 _this.$element.data('clickedOn', _this.$element.data('clickedOn') ? false : true); 5739 _this.timer[_this.$element.data('clickedOn') ? 'pause' : 'start'](); 5740 }); 5741 5742 if (this.options.pauseOnHover) { 5743 this.$element.on('mouseenter.zf.orbit', function () { 5744 _this.timer.pause(); 5745 }).on('mouseleave.zf.orbit', function () { 5746 if (!_this.$element.data('clickedOn')) { 5747 _this.timer.start(); 5748 } 5749 }); 5750 } 5751 } 5752 5753 if (this.options.navButtons) { 5754 var $controls = this.$element.find('.' + this.options.nextClass + ', .' + this.options.prevClass); 5755 $controls.attr('tabindex', 0) 5756 //also need to handle enter/return and spacebar key presses 5757 .on('click.zf.orbit touchend.zf.orbit', function (e) { 5758 e.preventDefault(); 5759 _this.changeSlide($(this).hasClass(_this.options.nextClass)); 5760 }); 5761 } 5762 5763 if (this.options.bullets) { 5764 this.$bullets.on('click.zf.orbit touchend.zf.orbit', function () { 5765 if (/is-active/g.test(this.className)) { 5766 return false; 5767 } //if this is active, kick out of function. 5768 var idx = $(this).data('slide'), 5769 ltr = idx > _this.$slides.filter('.is-active').data('slide'), 5770 $slide = _this.$slides.eq(idx); 5771 5772 _this.changeSlide(ltr, $slide, idx); 5773 }); 5774 } 5775 5776 this.$wrapper.add(this.$bullets).on('keydown.zf.orbit', function (e) { 5777 // handle keyboard event with keyboard util 5778 Foundation.Keyboard.handleKey(e, 'Orbit', { 5779 next: function () { 5780 _this.changeSlide(true); 5781 }, 5782 previous: function () { 5783 _this.changeSlide(false); 5784 }, 5785 handled: function () { 5786 // if bullet is focused, make sure focus moves 5787 if ($(e.target).is(_this.$bullets)) { 5788 _this.$bullets.filter('.is-active').focus(); 5789 } 5790 } 5791 }); 5792 }); 5793 } 5794 } 5795 5796 /** 5797 * Changes the current slide to a new one. 5798 * @function 5799 * @param {Boolean} isLTR - flag if the slide should move left to right. 5800 * @param {jQuery} chosenSlide - the jQuery element of the slide to show next, if one is selected. 5801 * @param {Number} idx - the index of the new slide in its collection, if one chosen. 5802 * @fires Orbit#slidechange 5803 */ 5804 5805 }, { 5806 key: 'changeSlide', 5807 value: function changeSlide(isLTR, chosenSlide, idx) { 5808 var $curSlide = this.$slides.filter('.is-active').eq(0); 5809 5810 if (/mui/g.test($curSlide[0].className)) { 5811 return false; 5812 } //if the slide is currently animating, kick out of the function 5813 5814 var $firstSlide = this.$slides.first(), 5815 $lastSlide = this.$slides.last(), 5816 dirIn = isLTR ? 'Right' : 'Left', 5817 dirOut = isLTR ? 'Left' : 'Right', 5818 _this = this, 5819 $newSlide; 5820 5821 if (!chosenSlide) { 5822 //most of the time, this will be auto played or clicked from the navButtons. 5823 $newSlide = isLTR ? //if wrapping enabled, check to see if there is a `next` or `prev` sibling, if not, select the first or last slide to fill in. if wrapping not enabled, attempt to select `next` or `prev`, if there's nothing there, the function will kick out on next step. CRAZY NESTED TERNARIES!!!!! 5824 this.options.infiniteWrap ? $curSlide.next('.' + this.options.slideClass).length ? $curSlide.next('.' + this.options.slideClass) : $firstSlide : $curSlide.next('.' + this.options.slideClass) : //pick next slide if moving left to right 5825 this.options.infiniteWrap ? $curSlide.prev('.' + this.options.slideClass).length ? $curSlide.prev('.' + this.options.slideClass) : $lastSlide : $curSlide.prev('.' + this.options.slideClass); //pick prev slide if moving right to left 5826 } else { 5827 $newSlide = chosenSlide; 5828 } 5829 5830 if ($newSlide.length) { 5831 if (this.options.bullets) { 5832 idx = idx || this.$slides.index($newSlide); //grab index to update bullets 5833 this._updateBullets(idx); 5834 } 5835 5836 if (this.options.useMUI) { 5837 Foundation.Motion.animateIn($newSlide.addClass('is-active').css({ 'position': 'absolute', 'top': 0 }), this.options['animInFrom' + dirIn], function () { 5838 $newSlide.css({ 'position': 'relative', 'display': 'block' }).attr('aria-live', 'polite'); 5839 }); 5840 5841 Foundation.Motion.animateOut($curSlide.removeClass('is-active'), this.options['animOutTo' + dirOut], function () { 5842 $curSlide.removeAttr('aria-live'); 5843 if (_this.options.autoPlay && !_this.timer.isPaused) { 5844 _this.timer.restart(); 5845 } 5846 //do stuff? 5847 }); 5848 } else { 5849 $curSlide.removeClass('is-active is-in').removeAttr('aria-live').hide(); 5850 $newSlide.addClass('is-active is-in').attr('aria-live', 'polite').show(); 5851 if (this.options.autoPlay && !this.timer.isPaused) { 5852 this.timer.restart(); 5853 } 5854 } 5855 /** 5856 * Triggers when the slide has finished animating in. 5857 * @event Orbit#slidechange 5858 */
5859 this.$element.trigger('slidechange.zf.orbit', [$newSlide]); 5860 } 5861 } 5862 5863 /** 5864 * Updates the active state of the bullets, if displayed. 5865 * @function 5866 * @private 5867 * @param {Number} idx - the index of the current slide. 5868 */ 5869 5870 }, { 5871 key: '_updateBullets', 5872 value: function _updateBullets(idx) { 5873 var $oldBullet = this.$element.find('.' + this.options.boxOfBullets).find('.is-active').removeClass('is-active').blur(), 5874 span = $oldBullet.find('span:last').detach(), 5875 $newBullet = this.$bullets.eq(idx).addClass('is-active').append(span); 5876 } 5877 5878 /** 5879 * Destroys the carousel and hides the element. 5880 * @function 5881 */ 5882 5883 }, { 5884 key: 'destroy', 5885 value: function destroy() { 5886 this.$element.off('.zf.orbit').find('*').off('.zf.orbit').end().hide(); 5887 Foundation.unregisterPlugin(this); 5888 } 5889 }]); 5890 5891 return Orbit; 5892 }(); 5893 5894 Orbit.defaults = { 5895 /** 5896 * Tells the JS to look for and loadBullets. 5897 * @option 5898 * @example true 5899 */ 5900 bullets: true, 5901 /** 5902 * Tells the JS to apply event listeners to nav buttons 5903 * @option 5904 * @example true 5905 */ 5906 navButtons: true, 5907 /** 5908 * motion-ui animation class to apply 5909 * @option 5910 * @example 'slide-in-right' 5911 */ 5912 animInFromRight: 'slide-in-right', 5913 /** 5914 * motion-ui animation class to apply 5915 * @option 5916 * @example 'slide-out-right' 5917 */ 5918 animOutToRight: 'slide-out-right', 5919 /** 5920 * motion-ui animation class to apply 5921 * @option 5922 * @example 'slide-in-left' 5923 * 5924 */ 5925 animInFromLeft: 'slide-in-left', 5926 /** 5927 * motion-ui animation class to apply 5928 * @option 5929 * @example 'slide-out-left' 5930 */ 5931 animOutToLeft: 'slide-out-left', 5932 /** 5933 * Allows Orbit to automatically animate on page load. 5934 * @option 5935 * @example true 5936 */ 5937 autoPlay: true, 5938 /** 5939 * Amount of time, in ms, between slide transitions 5940 * @option 5941 * @example 5000 5942 */ 5943 timerDelay: 5000, 5944 /** 5945 * Allows Orbit to infinitely loop through the slides 5946 * @option 5947 * @example true 5948 */ 5949 infiniteWrap: true, 5950 /** 5951 * Allows the Orbit slides to bind to swipe events for mobile, requires an additional util library 5952 * @option 5953 * @example true 5954 */ 5955 swipe: true, 5956 /** 5957 * Allows the timing function to pause animation on hover. 5958 * @option 5959 * @example true 5960 */ 5961 pauseOnHover: true, 5962 /** 5963 * Allows Orbit to bind keyboard events to the slider, to animate frames with arrow keys 5964 * @option 5965 * @example true 5966 */ 5967 accessible: true, 5968 /** 5969 * Class applied to the container of Orbit 5970 * @option 5971 * @example 'orbit-container' 5972 */ 5973 containerClass: 'orbit-container', 5974 /** 5975 * Class applied to individual slides. 5976 * @option 5977 * @example 'orbit-slide' 5978 */ 5979 slideClass: 'orbit-slide', 5980 /** 5981 * Class applied to the bullet container. You're welcome. 5982 * @option 5983 * @example 'orbit-bullets' 5984 */ 5985 boxOfBullets: 'orbit-bullets', 5986 /** 5987 * Class applied to the `next` navigation button. 5988 * @option 5989 * @example 'orbit-next' 5990 */ 5991 nextClass: 'orbit-next', 5992 /** 5993 * Class applied to the `previous` navigation button. 5994 * @option 5995 * @example 'orbit-previous' 5996 */ 5997 prevClass: 'orbit-previous', 5998 /** 5999 * Boolean to flag the js to use motion ui classes or not. Default to true for backwards compatability. 6000 * @option 6001 * @example true 6002 */ 6003 useMUI: true 6004 }; 6005 6006 // Window exports 6007 Foundation.plugin(Orbit, 'Orbit'); 6008}(jQuery); 6009'use strict'; 6010 6011var _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; }; }(); 6012 6013function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 6014 6015!function ($) { 6016 6017 /** 6018 * ResponsiveMenu module. 6019 * @module foundation.responsiveMenu 6020 * @requires foundation.util.triggers 6021 * @requires foundation.util.mediaQuery 6022 * @requires foundation.util.accordionMenu 6023 * @requires foundation.util.drilldown 6024 * @requires foundation.util.dropdown-menu 6025 */ 6026 6027 var ResponsiveMenu = function () { 6028 /** 6029 * Creates a new instance of a responsive menu. 6030 * @class 6031 * @fires ResponsiveMenu#init 6032 * @param {jQuery} element - jQuery object to make into a dropdown menu. 6033 * @param {Object} options - Overrides to the default plugin settings. 6034 */ 6035 6036 function ResponsiveMenu(element, options) { 6037 _classCallCheck(this, ResponsiveMenu); 6038 6039 this.$element = $(element); 6040 this.rules = this.$element.data('responsive-menu'); 6041 this.currentMq = null; 6042 this.currentPlugin = null; 6043 6044 this._init(); 6045 this._events(); 6046 6047 Foundation.registerPlugin(this, 'ResponsiveMenu'); 6048 } 6049 6050 /** 6051 * Initializes the Menu by parsing the classes from the 'data-ResponsiveMenu' attribute on the element. 6052 * @function 6053 * @private 6054 */ 6055 6056 6057 _createClass(ResponsiveMenu, [{ 6058 key: '_init', 6059 value: function _init() { 6060 // The first time an Interchange plugin is initialized, this.rules is converted from a string of "classes" to an object of rules 6061 if (typeof this.rules === 'string') { 6062 var rulesTree = {}; 6063 6064 // Parse rules from "classes" pulled from data attribute 6065 var rules = this.rules.split(' '); 6066 6067 // Iterate through every rule found 6068 for (var i = 0; i < rules.length; i++) { 6069 var rule = rules[i].split('-'); 6070 var ruleSize = rule.length > 1 ? rule[0] : 'small'; 6071 var rulePlugin = rule.length > 1 ? rule[1] : rule[0]; 6072 6073 if (MenuPlugins[rulePlugin] !== null) { 6074 rulesTree[ruleSize] = MenuPlugins[rulePlugin]; 6075 } 6076 } 6077 6078 this.rules = rulesTree; 6079 } 6080 6081 if (!$.isEmptyObject(this.rules)) { 6082 this._checkMediaQueries(); 6083 } 6084 } 6085 6086 /** 6087 * Initializes events for the Menu. 6088 * @function 6089 * @private 6090 */ 6091 6092 }, {
6093 key: '_events', 6094 value: function _events() { 6095 var _this = this; 6096 6097 $(window).on('changed.zf.mediaquery', function () { 6098 _this._checkMediaQueries(); 6099 }); 6100 // $(window).on('resize.zf.ResponsiveMenu', function() { 6101 // _this._checkMediaQueries(); 6102 // }); 6103 } 6104 6105 /** 6106 * Checks the current screen width against available media queries. If the media query has changed, and the plugin needed has changed, the plugins will swap out. 6107 * @function 6108 * @private 6109 */ 6110 6111 }, { 6112 key: '_checkMediaQueries', 6113 value: function _checkMediaQueries() { 6114 var matchedMq, 6115 _this = this; 6116 // Iterate through each rule and find the last matching rule 6117 $.each(this.rules, function (key) { 6118 if (Foundation.MediaQuery.atLeast(key)) { 6119 matchedMq = key; 6120 } 6121 }); 6122 6123 // No match? No dice 6124 if (!matchedMq) return; 6125 6126 // Plugin already initialized? We good 6127 if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return; 6128 6129 // Remove existing plugin-specific CSS classes 6130 $.each(MenuPlugins, function (key, value) { 6131 _this.$element.removeClass(value.cssClass); 6132 }); 6133 6134 // Add the CSS class for the new plugin 6135 this.$element.addClass(this.rules[matchedMq].cssClass); 6136 6137 // Create an instance of the new plugin 6138 if (this.currentPlugin) this.currentPlugin.destroy(); 6139 this.currentPlugin = new this.rules[matchedMq].plugin(this.$element, {}); 6140 } 6141 6142 /** 6143 * Destroys the instance of the current plugin on this element, as well as the window resize handler that switches the plugins out. 6144 * @function 6145 */ 6146 6147 }, { 6148 key: 'destroy', 6149 value: function destroy() { 6150 this.currentPlugin.destroy(); 6151 $(window).off('.zf.ResponsiveMenu'); 6152 Foundation.unregisterPlugin(this); 6153 } 6154 }]); 6155 6156 return ResponsiveMenu; 6157 }(); 6158 6159 ResponsiveMenu.defaults = {}; 6160 6161 // The plugin matches the plugin classes with these plugin instances. 6162 var MenuPlugins = { 6163 dropdown: { 6164 cssClass: 'dropdown', 6165 plugin: Foundation._plugins['dropdown-menu'] || null 6166 }, 6167 drilldown: { 6168 cssClass: 'drilldown', 6169 plugin: Foundation._plugins['drilldown'] || null 6170 }, 6171 accordion: { 6172 cssClass: 'accordion-menu', 6173 plugin: Foundation._plugins['accordion-menu'] || null 6174 } 6175 }; 6176 6177 // Window exports 6178 Foundation.plugin(ResponsiveMenu, 'ResponsiveMenu'); 6179}(jQuery); 6180'use strict'; 6181 6182var _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; }; }(); 6183 6184function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 6185 6186!function ($) { 6187 6188 /** 6189 * ResponsiveToggle module. 6190 * @module foundation.responsiveToggle 6191 * @requires foundation.util.mediaQuery 6192 */ 6193 6194 var ResponsiveToggle = function () { 6195 /** 6196 * Creates a new instance of Tab Bar. 6197 * @class 6198 * @fires ResponsiveToggle#init 6199 * @param {jQuery} element - jQuery object to attach tab bar functionality to. 6200 * @param {Object} options - Overrides to the default plugin settings. 6201 */ 6202 6203 function ResponsiveToggle(element, options) { 6204 _classCallCheck(this, ResponsiveToggle); 6205 6206 this.$element = $(element); 6207 this.options = $.extend({}, ResponsiveToggle.defaults, this.$element.data(), options); 6208 6209 this._init(); 6210 this._events(); 6211 6212 Foundation.registerPlugin(this, 'ResponsiveToggle'); 6213 } 6214 6215 /** 6216 * Initializes the tab bar by finding the target element, toggling element, and running update(). 6217 * @function 6218 * @private 6219 */ 6220 6221 6222 _createClass(ResponsiveToggle, [{ 6223 key: '_init', 6224 value: function _init() { 6225 var targetID = this.$element.data('responsive-toggle'); 6226 if (!targetID) { 6227 console.error('Your tab bar needs an ID of a Menu as the value of data-tab-bar.'); 6228 } 6229 6230 this.$targetMenu = $('#' + targetID); 6231 this.$toggler = this.$element.find('[data-toggle]'); 6232 6233 this._update(); 6234 } 6235 6236 /** 6237 * Adds necessary event handlers for the tab bar to work. 6238 * @function 6239 * @private 6240 */ 6241 6242 }, {
6243 key: '_events', 6244 value: function _events() { 6245 var _this = this; 6246 6247 this._updateMqHandler = this._update.bind(this); 6248 6249 $(window).on('changed.zf.mediaquery', this._updateMqHandler); 6250 6251 this.$toggler.on('click.zf.responsiveToggle', this.toggleMenu.bind(this)); 6252 } 6253 6254 /** 6255 * Checks the current media query to determine if the tab bar should be visible or hidden. 6256 * @function 6257 * @private 6258 */ 6259 6260 }, { 6261 key: '_update', 6262 value: function _update() { 6263 // Mobile 6264 if (!Foundation.MediaQuery.atLeast(this.options.hideFor)) { 6265 this.$element.show(); 6266 this.$targetMenu.hide(); 6267 } 6268 6269 // Desktop 6270 else { 6271 this.$element.hide(); 6272 this.$targetMenu.show(); 6273 } 6274 } 6275 6276 /** 6277 * Toggles the element attached to the tab bar. The toggle only happens if the screen is small enough to allow it. 6278 * @function 6279 * @fires ResponsiveToggle#toggled 6280 */ 6281 6282 }, { 6283 key: 'toggleMenu', 6284 value: function toggleMenu() { 6285 if (!Foundation.MediaQuery.atLeast(this.options.hideFor)) { 6286 this.$targetMenu.toggle(0); 6287 6288 /** 6289 * Fires when the element attached to the tab bar toggles. 6290 * @event ResponsiveToggle#toggled 6291 */ 6292 this.$element.trigger('toggled.zf.responsiveToggle'); 6293 } 6294 } 6295 }, { 6296 key: 'destroy', 6297 value: function destroy() { 6298 this.$element.off('.zf.responsiveToggle'); 6299 this.$toggler.off('.zf.responsiveToggle'); 6300 6301 $(window).off('changed.zf.mediaquery', this._updateMqHandler); 6302 6303 Foundation.unregisterPlugin(this); 6304 } 6305 }]); 6306 6307 return ResponsiveToggle; 6308 }(); 6309 6310 ResponsiveToggle.defaults = { 6311 /** 6312 * The breakpoint after which the menu is always shown, and the tab bar is hidden. 6313 * @option 6314 * @example 'medium' 6315 */ 6316 hideFor: 'medium' 6317 }; 6318 6319 // Window exports 6320 Foundation.plugin(ResponsiveToggle, 'ResponsiveToggle'); 6321}(jQuery); 6322'use strict'; 6323 6324var _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; }; }(); 6325 6326function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 6327 6328!function ($) { 6329 6330 /** 6331 * Reveal module. 6332 * @module foundation.reveal 6333 * @requires foundation.util.keyboard 6334 * @requires foundation.util.box 6335 * @requires foundation.util.triggers 6336 * @requires foundation.util.mediaQuery 6337 * @requires foundation.util.motion if using animations 6338 */ 6339 6340 var Reveal = function () { 6341 /** 6342 * Creates a new instance of Reveal. 6343 * @class 6344 * @param {jQuery} element - jQuery object to use for the modal. 6345 * @param {Object} options - optional parameters. 6346 */ 6347 6348 function Reveal(element, options) { 6349 _classCallCheck(this, Reveal); 6350 6351 this.$element = element; 6352 this.options = $.extend({}, Reveal.defaults, this.$element.data(), options); 6353 this._init(); 6354 6355 Foundation.registerPlugin(this, 'Reveal'); 6356 Foundation.Keyboard.register('Reveal', { 6357 'ENTER': 'open', 6358 'SPACE': 'open', 6359 'ESCAPE': 'close', 6360 'TAB': 'tab_forward', 6361 'SHIFT_TAB': 'tab_backward' 6362 }); 6363 } 6364 6365 /** 6366 * Initializes the modal by adding the overlay and close buttons, (if selected). 6367 * @private 6368 */ 6369 6370 6371 _createClass(Reveal, [{ 6372 key: '_init', 6373 value: function _init() { 6374 this.id = this.$element.attr('id'); 6375 this.isActive = false; 6376 this.cached = { mq: Foundation.MediaQuery.current }; 6377 this.isMobile = mobileSniff(); 6378 6379 this.$anchor = $('[data-open="' + this.id + '"]').length ? $('[data-open="' + this.id + '"]') : $('[data-toggle="' + this.id + '"]'); 6380 this.$anchor.attr({ 6381 'aria-controls': this.id, 6382 'aria-haspopup': true, 6383 'tabindex': 0 6384 }); 6385 6386 if (this.options.fullScreen || this.$element.hasClass('full')) { 6387 this.options.fullScreen = true;
vendor: 4,464 bytes, lines 6388-6533
6388 this.options.overlay = false; 6389 } 6390 if (this.options.overlay && !this.$overlay) { 6391 this.$overlay = this._makeOverlay(this.id); 6392 } 6393 6394 this.$element.attr({ 6395 'role': 'dialog', 6396 'aria-hidden': true, 6397 'data-yeti-box': this.id, 6398 'data-resize': this.id 6399 }); 6400 6401 if (this.$overlay) { 6402 this.$element.detach().appendTo(this.$overlay); 6403 } else { 6404 this.$element.detach().appendTo($('body')); 6405 this.$element.addClass('without-overlay'); 6406 } 6407 this._events(); 6408 if (this.options.deepLink && window.location.hash === '#' + this.id) { 6409 $(window).one('load.zf.reveal', this.open.bind(this)); 6410 } 6411 } 6412 6413 /** 6414 * Creates an overlay div to display behind the modal. 6415 * @private 6416 */ 6417 6418 }, { 6419 key: '_makeOverlay', 6420 value: function _makeOverlay(id) { 6421 var $overlay = $('<div></div>').addClass('reveal-overlay').appendTo('body'); 6422 return $overlay; 6423 } 6424 6425 /** 6426 * Updates position of modal 6427 * TODO: Figure out if we actually need to cache these values or if it doesn't matter 6428 * @private 6429 */ 6430 6431 }, { 6432 key: '_updatePosition', 6433 value: function _updatePosition() { 6434 var width = this.$element.outerWidth(); 6435 var outerWidth = $(window).width(); 6436 var height = this.$element.outerHeight(); 6437 var outerHeight = $(window).height(); 6438 var left, top; 6439 if (this.options.hOffset === 'auto') { 6440 left = parseInt((outerWidth - width) / 2, 10); 6441 } else { 6442 left = parseInt(this.options.hOffset, 10); 6443 } 6444 if (this.options.vOffset === 'auto') { 6445 if (height > outerHeight) { 6446 top = parseInt(Math.min(100, outerHeight / 10), 10); 6447 } else { 6448 top = parseInt((outerHeight - height) / 4, 10); 6449 } 6450 } else { 6451 top = parseInt(this.options.vOffset, 10); 6452 } 6453 this.$element.css({ top: top + 'px' }); 6454 // only worry about left if we don't have an overlay or we havea horizontal offset, 6455 // otherwise we're perfectly in the middle 6456 if (!this.$overlay || this.options.hOffset !== 'auto') { 6457 this.$element.css({ left: left + 'px' }); 6458 this.$element.css({ margin: '0px' }); 6459 } 6460 } 6461 6462 /** 6463 * Adds event handlers for the modal. 6464 * @private 6465 */ 6466 6467 }, { 6468 key: '_events', 6469 value: function _events() { 6470 var _this2 = this; 6471 6472 var _this = this; 6473 6474 this.$element.on({ 6475 'open.zf.trigger': this.open.bind(this), 6476 'close.zf.trigger': function (event, $element) { 6477 if (event.target === _this.$element[0] || $(event.target).parents('[data-closable]')[0] === $element) { 6478 // only close reveal when it's explicitly called 6479 return _this2.close.apply(_this2); 6480 } 6481 }, 6482 'toggle.zf.trigger': this.toggle.bind(this), 6483 'resizeme.zf.trigger': function () { 6484 _this._updatePosition(); 6485 } 6486 }); 6487 6488 if (this.$anchor.length) { 6489 this.$anchor.on('keydown.zf.reveal', function (e) { 6490 if (e.which === 13 || e.which === 32) { 6491 e.stopPropagation(); 6492 e.preventDefault(); 6493 _this.open(); 6494 } 6495 }); 6496 } 6497 6498 if (this.options.closeOnClick && this.options.overlay) { 6499 this.$overlay.off('.zf.reveal').on('click.zf.reveal', function (e) { 6500 if (e.target === _this.$element[0] || $.contains(_this.$element[0], e.target)) { 6501 return; 6502 } 6503 _this.close(); 6504 }); 6505 } 6506 if (this.options.deepLink) { 6507 $(window).on('popstate.zf.reveal:' + this.id, this._handleState.bind(this)); 6508 } 6509 } 6510 6511 /** 6512 * Handles modal methods on back/forward button clicks or any other event that triggers popstate. 6513 * @private 6514 */ 6515 6516 }, { 6517 key: '_handleState', 6518 value: function _handleState(e) { 6519 if (window.location.hash === '#' + this.id && !this.isActive) { 6520 this.open(); 6521 } else { 6522 this.close(); 6523 } 6524 } 6525 6526 /** 6527 * Opens the modal controlled by `this.$anchor`, and closes all others by default. 6528 * @function 6529 * @fires Reveal#closeme 6530 * @fires Reveal#open 6531 */ 6532 6533 }, {
6534 key: 'open', 6535 value: function open() { 6536 var _this3 = this; 6537 6538 if (this.options.deepLink) { 6539 var hash = '#' + this.id; 6540 6541 if (window.history.pushState) { 6542 window.history.pushState(null, null, hash); 6543 } else { 6544 window.location.hash = hash; 6545 } 6546 } 6547 6548 this.isActive = true; 6549 6550 // Make elements invisible, but remove display: none so we can get size and positioning 6551 this.$element.css({ 'visibility': 'hidden' }).show().scrollTop(0); 6552 if (this.options.overlay) { 6553 this.$overlay.css({ 'visibility': 'hidden' }).show(); 6554 } 6555 6556 this._updatePosition(); 6557 6558 this.$element.hide().css({ 'visibility': '' }); 6559 6560 if (this.$overlay) { 6561 this.$overlay.css({ 'visibility': '' }).hide(); 6562 if (this.$element.hasClass('fast')) { 6563 this.$overlay.addClass('fast'); 6564 } else if (this.$element.hasClass('slow')) { 6565 this.$overlay.addClass('slow'); 6566 } 6567 } 6568 6569 if (!this.options.multipleOpened) { 6570 /** 6571 * Fires immediately before the modal opens. 6572 * Closes any other modals that are currently open 6573 * @event Reveal#closeme 6574 */ 6575 this.$element.trigger('closeme.zf.reveal', this.id); 6576 } 6577 // Motion UI method of reveal 6578 if (this.options.animationIn) { 6579 var _this; 6580 6581 (function () { 6582 var afterAnimationFocus = function () { 6583 _this.$element.attr({ 6584 'aria-hidden': false, 6585 'tabindex': -1 6586 }).focus(); 6587 console.log('focus'); 6588 }; 6589 6590 _this = _this3; 6591 6592 if (_this3.options.overlay) { 6593 Foundation.Motion.animateIn(_this3.$overlay, 'fade-in'); 6594 } 6595 Foundation.Motion.animateIn(_this3.$element, _this3.options.animationIn, function () { 6596 _this3.focusableElements = Foundation.Keyboard.findFocusable(_this3.$element); 6597 afterAnimationFocus(); 6598 }); 6599 })(); 6600 } 6601 // jQuery method of reveal 6602 else { 6603 if (this.options.overlay) { 6604 this.$overlay.show(0); 6605 } 6606 this.$element.show(this.options.showDelay); 6607 } 6608 6609 // handle accessibility 6610 this.$element.attr({ 6611 'aria-hidden': false, 6612 'tabindex': -1 6613 }).focus(); 6614 6615 /** 6616 * Fires when the modal has successfully opened. 6617 * @event Reveal#open 6618 */ 6619 this.$element.trigger('open.zf.reveal'); 6620 6621 if (this.isMobile) { 6622 this.originalScrollPos = window.pageYOffset; 6623 $('html, body').addClass('is-reveal-open'); 6624 } else { 6625 $('body').addClass('is-reveal-open'); 6626 } 6627 6628 setTimeout(function () { 6629 _this3._extraHandlers(); 6630 }, 0); 6631 } 6632 6633 /** 6634 * Adds extra event handlers for the body and window if necessary. 6635 * @private 6636 */ 6637 6638 }, { 6639 key: '_extraHandlers', 6640 value: function _extraHandlers() { 6641 var _this = this; 6642 this.focusableElements = Foundation.Keyboard.findFocusable(this.$element); 6643 6644 if (!this.options.overlay && this.options.closeOnClick && !this.options.fullScreen) { 6645 $('body').on('click.zf.reveal', function (e) { 6646 if (e.target === _this.$element[0] || $.contains(_this.$element[0], e.target)) { 6647 return; 6648 } 6649 _this.close(); 6650 }); 6651 } 6652 6653 if (this.options.closeOnEsc) { 6654 $(window).on('keydown.zf.reveal', function (e) { 6655 Foundation.Keyboard.handleKey(e, 'Reveal', { 6656 close: function () { 6657 if (_this.options.closeOnEsc) { 6658 _this.close(); 6659 _this.$anchor.focus(); 6660 } 6661 } 6662 }); 6663 }); 6664 } 6665 6666 // lock focus within modal while tabbing 6667 this.$element.on('keydown.zf.reveal', function (e) { 6668 var $target = $(this); 6669 // handle keyboard event with keyboard util 6670 Foundation.Keyboard.handleKey(e, 'Reveal', { 6671 tab_forward: function () { 6672 if (_this.$element.find(':focus').is(_this.focusableElements.eq(-1))) { 6673 // left modal downwards, setting focus to first element 6674 _this.focusableElements.eq(0).focus(); 6675 return true; 6676 } 6677 if (_this.focusableElements.length === 0) { 6678 // no focusable elements inside the modal at all, prevent tabbing in general 6679 return true; 6680 } 6681 }, 6682 tab_backward: function () { 6683 if (_this.$element.find(':focus').is(_this.focusableElements.eq(0)) || _this.$element.is(':focus')) { 6684 // left modal upwards, setting focus to last element 6685 _this.focusableElements.eq(-1).focus(); 6686 return true; 6687 } 6688 if (_this.focusableElements.length === 0) { 6689 // no focusable elements inside the modal at all, prevent tabbing in general 6690 return true; 6691 } 6692 }, 6693 open: function () { 6694 if (_this.$element.find(':focus').is(_this.$element.find('[data-close]'))) { 6695 setTimeout(function () { 6696 // set focus back to anchor if close button has been activated 6697 _this.$anchor.focus(); 6698 }, 1); 6699 } else if ($target.is(_this.focusableElements)) { 6700 // dont't trigger if acual element has focus (i.e. inputs, links, ...) 6701 _this.open(); 6702 } 6703 }, 6704 close: function () { 6705 if (_this.options.closeOnEsc) { 6706 _this.close(); 6707 _this.$anchor.focus(); 6708 } 6709 }, 6710 handled: function (preventDefault) { 6711 if (preventDefault) { 6712 e.preventDefault(); 6713 } 6714 } 6715 }); 6716 }); 6717 } 6718 6719 /** 6720 * Closes the modal. 6721 * @function 6722 * @fires Reveal#closed 6723 */ 6724 6725 }, {
6726 key: 'close', 6727 value: function close() { 6728 if (!this.isActive || !this.$element.is(':visible')) { 6729 return false; 6730 } 6731 var _this = this; 6732 6733 // Motion UI method of hiding 6734 if (this.options.animationOut) { 6735 if (this.options.overlay) { 6736 Foundation.Motion.animateOut(this.$overlay, 'fade-out', finishUp); 6737 } else { 6738 finishUp(); 6739 } 6740 6741 Foundation.Motion.animateOut(this.$element, this.options.animationOut); 6742 } 6743 // jQuery method of hiding 6744 else { 6745 if (this.options.overlay) { 6746 this.$overlay.hide(0, finishUp); 6747 } else { 6748 finishUp(); 6749 } 6750 6751 this.$element.hide(this.options.hideDelay); 6752 } 6753 6754 // Conditionals to remove extra event listeners added on open 6755 if (this.options.closeOnEsc) { 6756 $(window).off('keydown.zf.reveal'); 6757 } 6758 6759 if (!this.options.overlay && this.options.closeOnClick) { 6760 $('body').off('click.zf.reveal'); 6761 } 6762 6763 this.$element.off('keydown.zf.reveal'); 6764 6765 function finishUp() { 6766 if (_this.isMobile) { 6767 $('html, body').removeClass('is-reveal-open'); 6768 if (_this.originalScrollPos) { 6769 $('body').scrollTop(_this.originalScrollPos); 6770 _this.originalScrollPos = null; 6771 } 6772 } else { 6773 $('body').removeClass('is-reveal-open'); 6774 } 6775 6776 _this.$element.attr('aria-hidden', true); 6777 6778 /** 6779 * Fires when the modal is done closing. 6780 * @event Reveal#closed 6781 */ 6782 _this.$element.trigger('closed.zf.reveal'); 6783 } 6784 6785 /** 6786 * Resets the modal content 6787 * This prevents a running video to keep going in the background 6788 */ 6789 if (this.options.resetOnClose) { 6790 this.$element.html(this.$element.html()); 6791 } 6792 6793 this.isActive = false; 6794 if (_this.options.deepLink) { 6795 if (window.history.replaceState) { 6796 window.history.replaceState("", document.title, window.location.pathname); 6797 } else { 6798 window.location.hash = ''; 6799 } 6800 } 6801 } 6802 6803 /** 6804 * Toggles the open/closed state of a modal. 6805 * @function 6806 */ 6807 6808 }, { 6809 key: 'toggle', 6810 value: function toggle() { 6811 if (this.isActive) { 6812 this.close(); 6813 } else { 6814 this.open(); 6815 } 6816 } 6817 }, { 6818 key: 'destroy', 6819 6820 6821 /** 6822 * Destroys an instance of a modal. 6823 * @function 6824 */ 6825 value: function destroy() { 6826 if (this.options.overlay) { 6827 this.$element.appendTo($('body')); // move $element outside of $overlay to prevent error unregisterPlugin() 6828 this.$overlay.hide().off().remove(); 6829 } 6830 this.$element.hide().off(); 6831 this.$anchor.off('.zf'); 6832 $(window).off('.zf.reveal:' + this.id); 6833 6834 Foundation.unregisterPlugin(this); 6835 } 6836 }]); 6837 6838 return Reveal; 6839 }(); 6840 6841 Reveal.defaults = { 6842 /** 6843 * Motion-UI class to use for animated elements. If none used, defaults to simple show/hide. 6844 * @option 6845 * @example 'slide-in-left' 6846 */ 6847 animationIn: '', 6848 /** 6849 * Motion-UI class to use for animated elements. If none used, defaults to simple show/hide. 6850 * @option 6851 * @example 'slide-out-right' 6852 */ 6853 animationOut: '', 6854 /** 6855 * Time, in ms, to delay the opening of a modal after a click if no animation used. 6856 * @option 6857 * @example 10 6858 */ 6859 showDelay: 0, 6860 /** 6861 * Time, in ms, to delay the closing of a modal after a click if no animation used. 6862 * @option 6863 * @example 10 6864 */ 6865 hideDelay: 0, 6866 /** 6867 * Allows a click on the body/overlay to close the modal. 6868 * @option 6869 * @example true 6870 */ 6871 closeOnClick: true, 6872 /** 6873 * Allows the modal to close if the user presses the `ESCAPE` key. 6874 * @option 6875 * @example true 6876 */ 6877 closeOnEsc: true, 6878 /** 6879 * If true, allows multiple modals to be displayed at once. 6880 * @option 6881 * @example false 6882 */ 6883 multipleOpened: false, 6884 /** 6885 * Distance, in pixels, the modal should push down from the top of the screen. 6886 * @option 6887 * @example auto 6888 */ 6889 vOffset: 'auto', 6890 /** 6891 * Distance, in pixels, the modal should push in from the side of the screen. 6892 * @option 6893 * @example auto 6894 */ 6895 hOffset: 'auto', 6896 /** 6897 * Allows the modal to be fullscreen, completely blocking out the rest of the view. JS checks for this as well. 6898 * @option 6899 * @example false 6900 */ 6901 fullScreen: false, 6902 /** 6903 * Percentage of screen height the modal should push up from the bottom of the view. 6904 * @option 6905 * @example 10 6906 */ 6907 btmOffsetPct: 10, 6908 /** 6909 * Allows the modal to generate an overlay div, which will cover the view when modal opens. 6910 * @option 6911 * @example true 6912 */ 6913 overlay: true, 6914 /** 6915 * Allows the modal to remove and reinject markup on close. Should be true if using video elements w/o using provider's api, otherwise, videos will continue to play in the background. 6916 * @option 6917 * @example false 6918 */ 6919 resetOnClose: false, 6920 /** 6921 * Allows the modal to alter the url on open/close, and allows the use of the `back` button to close modals. ALSO, allows a modal to auto-maniacally open on page load IF the hash === the modal'
6921s user-set id. 6922 * @option 6923 * @example false 6924 */ 6925 deepLink: false 6926 }; 6927 6928 // Window exports 6929 Foundation.plugin(Reveal, 'Reveal'); 6930 6931 function iPhoneSniff() { 6932 return (/iP(ad|hone|od).*OS/.test(window.navigator.userAgent) 6933 ); 6934 } 6935 6936 function androidSniff() { 6937 return (/Android/.test(window.navigator.userAgent) 6938 ); 6939 } 6940 6941 function mobileSniff() { 6942 return iPhoneSniff() || androidSniff(); 6943 } 6944}(jQuery); 6945'use strict'; 6946 6947var _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; }; }(); 6948 6949function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 6950 6951!function ($) { 6952 6953 /** 6954 * Slider module. 6955 * @module foundation.slider 6956 * @requires foundation.util.motion 6957 * @requires foundation.util.triggers 6958 * @requires foundation.util.keyboard 6959 * @requires foundation.util.touch 6960 */ 6961 6962 var Slider = function () { 6963 /** 6964 * Creates a new instance of a drilldown menu. 6965 * @class 6966 * @param {jQuery} element - jQuery object to make into an accordion menu. 6967 * @param {Object} options - Overrides to the default plugin settings. 6968 */ 6969 6970 function Slider(element, options) { 6971 _classCallCheck(this, Slider); 6972 6973 this.$element = element; 6974 this.options = $.extend({}, Slider.defaults, this.$element.data(), options); 6975 6976 this._init(); 6977 6978 Foundation.registerPlugin(this, 'Slider'); 6979 Foundation.Keyboard.register('Slider', { 6980 'ltr': { 6981 'ARROW_RIGHT': 'increase', 6982 'ARROW_UP': 'increase', 6983 'ARROW_DOWN': 'decrease', 6984 'ARROW_LEFT': 'decrease', 6985 'SHIFT_ARROW_RIGHT': 'increase_fast', 6986 'SHIFT_ARROW_UP': 'increase_fast', 6987 'SHIFT_ARROW_DOWN': 'decrease_fast', 6988 'SHIFT_ARROW_LEFT': 'decrease_fast' 6989 }, 6990 'rtl': { 6991 'ARROW_LEFT': 'increase', 6992 'ARROW_RIGHT': 'decrease', 6993 'SHIFT_ARROW_LEFT': 'increase_fast', 6994 'SHIFT_ARROW_RIGHT': 'decrease_fast' 6995 } 6996 }); 6997 } 6998 6999 /** 7000 * Initilizes the plugin by reading/setting attributes, creating collections and setting the initial position of the handle(s). 7001 * @function 7002 * @private 7003 */ 7004 7005 7006 _createClass(Slider, [{ 7007 key: '_init', 7008 value: function _init() { 7009 this.inputs = this.$element.find('input'); 7010 this.handles = this.$element.find('[data-slider-handle]'); 7011 7012 this.$handle = this.handles.eq(0); 7013 this.$input = this.inputs.length ? this.inputs.eq(0) : $('#' + this.$handle.attr('aria-controls')); 7014 this.$fill = this.$element.find('[data-slider-fill]').css(this.options.vertical ? 'height' : 'width', 0); 7015 7016 var isDbl = false, 7017 _this = this; 7018 if (this.options.disabled || this.$element.hasClass(this.options.disabledClass)) { 7019 this.options.disabled = true; 7020 this.$element.addClass(this.options.disabledClass); 7021 } 7022 if (!this.inputs.length) { 7023 this.inputs = $().add(this.$input); 7024 this.options.binding = true; 7025 } 7026 this._setInitAttr(0); 7027 this._events(this.$handle); 7028 7029 if (this.handles[1]) { 7030 this.options.doubleSided = true; 7031 this.$handle2 = this.handles.eq(1); 7032 this.$input2 = this.inputs.length > 1 ? this.inputs.eq(1) : $('#' + this.$handle2.attr('aria-controls')); 7033 7034 if (!this.inputs[1]) { 7035 this.inputs = this.inputs.add(this.$input2); 7036 } 7037 isDbl = true; 7038 7039 this._setHandlePos(this.$handle, this.options.initialStart, true, function () { 7040 7041 _this._setHandlePos(_this.$handle2, _this.options.initialEnd, true); 7042 }); 7043 // this.$handle.triggerHandler('click.zf.slider'); 7044 this._setInitAttr(1); 7045 this._events(this.$handle2); 7046 } 7047 7048 if (!isDbl) { 7049 this._setHandlePos(this.$handle, this.options.initialStart, true); 7050 } 7051 } 7052 7053 /** 7054 * Sets the position of the selected handle and fill bar. 7055 * @function 7056 * @private 7057 * @param {jQuery} $hndl - the selected handle to move. 7058 * @param {Number} location - floating point between the start and end values of the slider bar. 7059 * @param {Function} cb - callback function to fire on completion. 7060 * @fires Slider#moved 7061 * @fires Slider#changed 7062 */ 7063 7064 }, {
vendor: 5,311 bytes, lines 7065-7165
7065 key: '_setHandlePos', 7066 value: function _setHandlePos($hndl, location, noInvert, cb) { 7067 // don't move if the slider has been disabled since its initialization 7068 if (this.$element.hasClass(this.options.disabledClass)) { 7069 return; 7070 } 7071 //might need to alter that slightly for bars that will have odd number selections. 7072 location = parseFloat(location); //on input change events, convert string to number...grumble. 7073 7074 // prevent slider from running out of bounds, if value exceeds the limits set through options, override the value to min/max 7075 if (location < this.options.start) { 7076 location = this.options.start; 7077 } else if (location > this.options.end) { 7078 location = this.options.end; 7079 } 7080 7081 var isDbl = this.options.doubleSided; 7082 7083 if (isDbl) { 7084 //this block is to prevent 2 handles from crossing eachother. Could/should be improved. 7085 if (this.handles.index($hndl) === 0) { 7086 var h2Val = parseFloat(this.$handle2.attr('aria-valuenow')); 7087 location = location >= h2Val ? h2Val - this.options.step : location; 7088 } else { 7089 var h1Val = parseFloat(this.$handle.attr('aria-valuenow')); 7090 location = location <= h1Val ? h1Val + this.options.step : location; 7091 } 7092 } 7093 7094 //this is for single-handled vertical sliders, it adjusts the value to account for the slider being "upside-down" 7095 //for click and drag events, it's weird due to the scale(-1, 1) css property 7096 if (this.options.vertical && !noInvert) { 7097 location = this.options.end - location; 7098 } 7099 7100 var _this = this, 7101 vert = this.options.vertical, 7102 hOrW = vert ? 'height' : 'width', 7103 lOrT = vert ? 'top' : 'left', 7104 handleDim = $hndl[0].getBoundingClientRect()[hOrW], 7105 elemDim = this.$element[0].getBoundingClientRect()[hOrW], 7106 7107 //percentage of bar min/max value based on click or drag point 7108 pctOfBar = percent(location - this.options.start, this.options.end - this.options.start).toFixed(2), 7109 7110 //number of actual pixels to shift the handle, based on the percentage obtained above 7111 pxToMove = (elemDim - handleDim) * pctOfBar, 7112 7113 //percentage of bar to shift the handle 7114 movement = (percent(pxToMove, elemDim) * 100).toFixed(this.options.decimal); 7115 //fixing the decimal value for the location number, is passed to other methods as a fixed floating-point value 7116 location = parseFloat(location.toFixed(this.options.decimal)); 7117 // declare empty object for css adjustments, only used with 2 handled-sliders 7118 var css = {}; 7119 7120 this._setValues($hndl, location); 7121 7122 // TODO update to calculate based on values set to respective inputs?? 7123 if (isDbl) { 7124 var isLeftHndl = this.handles.index($hndl) === 0, 7125 7126 //empty variable, will be used for min-height/width for fill bar 7127 dim, 7128 7129 //percentage w/h of the handle compared to the slider bar 7130 handlePct = ~ ~(percent(handleDim, elemDim) * 100); 7131 //if left handle, the math is slightly different than if it's the right handle, and the left/top property needs to be changed for the fill bar 7132 if (isLeftHndl) { 7133 //left or top percentage value to apply to the fill bar. 7134 css[lOrT] = movement + '%'; 7135 //calculate the new min-height/width for the fill bar. 7136 dim = parseFloat(this.$handle2[0].style[lOrT]) - movement + handlePct; 7137 //this callback is necessary to prevent errors and allow the proper placement and initialization of a 2-handled slider 7138 //plus, it means we don't care if 'dim' isNaN on init, it won't be in the future. 7139 if (cb && typeof cb === 'function') { 7140 cb(); 7141 } //this is only needed for the initialization of 2 handled sliders 7142 } else { 7143 //just caching the value of the left/bottom handle's left/top property 7144 var handlePos = parseFloat(this.$handle[0].style[lOrT]); 7145 //calculate the new min-height/width for the fill bar. Use isNaN to prevent false positives for numbers <= 0 7146 //based on the percentage of movement of the handle being manipulated, less the opposing handle's left/top position, plus the percentage w/h of the handle itself 7147 dim = movement - (isNaN(handlePos) ? this.options.initialStart / ((this.options.end - this.options.start) / 100) : handlePos) + handlePct; 7148 } 7149 // assign the min-height/width to our css object 7150 css['min-' + hOrW] = dim + '%'; 7151 } 7152 7153 this.$element.one('finished.zf.animate', function () { 7154 /** 7155 * Fires when the handle is done moving. 7156 * @event Slider#moved 7157 */ 7158 _this.$element.trigger('moved.zf.slider', [$hndl]); 7159 }); 7160 7161 //because we don't know exactly how the handle will be moved, check the amount of time it should take to move. 7162 var moveTime = this.$element.data('dragging') ? 1000 / 60 : this.options.moveTime; 7163 7164 Foundation.Move(moveTime, $hndl, function () { 7165 //adjusting the left/top property of the handle, based on the percentage c
7165alculated above 7166 $hndl.css(lOrT, movement + '%'); 7167 7168 if (!_this.options.doubleSided) { 7169 //if single-handled, a simple method to expand the fill bar 7170 _this.$fill.css(hOrW, pctOfBar * 100 + '%'); 7171 } else { 7172 //otherwise, use the css object we created above 7173 _this.$fill.css(css); 7174 } 7175 }); 7176 7177 /** 7178 * Fires when the value has not been change for a given time. 7179 * @event Slider#changed 7180 */ 7181 clearTimeout(_this.timeout); 7182 _this.timeout = setTimeout(function () { 7183 _this.$element.trigger('changed.zf.slider', [$hndl]); 7184 }, _this.options.changedDelay); 7185 } 7186 7187 /** 7188 * Sets the initial attribute for the slider element. 7189 * @function 7190 * @private 7191 * @param {Number} idx - index of the current handle/input to use. 7192 */ 7193 7194 }, { 7195 key: '_setInitAttr', 7196 value: function _setInitAttr(idx) { 7197 var id = this.inputs.eq(idx).attr('id') || Foundation.GetYoDigits(6, 'slider'); 7198 this.inputs.eq(idx).attr({ 7199 'id': id, 7200 'max': this.options.end, 7201 'min': this.options.start, 7202 'step': this.options.step 7203 }); 7204 this.handles.eq(idx).attr({ 7205 'role': 'slider', 7206 'aria-controls': id, 7207 'aria-valuemax': this.options.end, 7208 'aria-valuemin': this.options.start, 7209 'aria-valuenow': idx === 0 ? this.options.initialStart : this.options.initialEnd, 7210 'aria-orientation': this.options.vertical ? 'vertical' : 'horizontal', 7211 'tabindex': 0 7212 }); 7213 } 7214 7215 /** 7216 * Sets the input and `aria-valuenow` values for the slider element. 7217 * @function 7218 * @private 7219 * @param {jQuery} $handle - the currently selected handle. 7220 * @param {Number} val - floating point of the new value. 7221 */ 7222 7223 }, { 7224 key: '_setValues', 7225 value: function _setValues($handle, val) { 7226 var idx = this.options.doubleSided ? this.handles.index($handle) : 0; 7227 this.inputs.eq(idx).val(val); 7228 $handle.attr('aria-valuenow', val); 7229 } 7230 7231 /** 7232 * Handles events on the slider element. 7233 * Calculates the new location of the current handle. 7234 * If there are two handles and the bar was clicked, it determines which handle to move. 7235 * @function 7236 * @private 7237 * @param {Object} e - the `event` object passed from the listener. 7238 * @param {jQuery} $handle - the current handle to calculate for, if selected. 7239 * @param {Number} val - floating point number for the new value of the slider. 7240 * TODO clean this up, there's a lot of repeated code between this and the _setHandlePos fn. 7241 */ 7242 7243 }, { 7244 key: '_handleEvent', 7245 value: function _handleEvent(e, $handle, val) { 7246 var value, hasVal; 7247 if (!val) { 7248 //click or drag events 7249 e.preventDefault(); 7250 var _this = this, 7251 vertical = this.options.vertical, 7252 param = vertical ? 'height' : 'width', 7253 direction = vertical ? 'top' : 'left', 7254 eventOffset = vertical ? e.pageY : e.pageX, 7255 halfOfHandle = this.$handle[0].getBoundingClientRect()[param] / 2, 7256 barDim = this.$element[0].getBoundingClientRect()[param], 7257 windowScroll = vertical ? $(window).scrollTop() : $(window).scrollLeft(); 7258 7259 var elemOffset = this.$element.offset()[direction]; 7260 7261 // touch events emulated by the touch util give position relative to screen, add window.scroll to event coordinates... 7262 // best way to guess this is simulated is if clientY == pageY 7263 if (e.clientY === e.pageY) { 7264 eventOffset = eventOffset + windowScroll; 7265 } 7266 var eventFromBar = eventOffset - elemOffset; 7267 var barXY; 7268 if (eventFromBar < 0) { 7269 barXY = 0; 7270 } else if (eventFromBar > barDim) { 7271 barXY = barDim; 7272 } else { 7273 barXY = eventFromBar; 7274 }
7275 offsetPct = percent(barXY, barDim); 7276 7277 value = (this.options.end - this.options.start) * offsetPct + this.options.start; 7278 7279 // turn everything around for RTL, yay math! 7280 if (Foundation.rtl() && !this.options.vertical) { 7281 value = this.options.end - value; 7282 } 7283 7284 value = _this._adjustValue(null, value); 7285 //boolean flag for the setHandlePos fn, specifically for vertical sliders 7286 hasVal = false; 7287 7288 if (!$handle) { 7289 //figure out which handle it is, pass it to the next function. 7290 var firstHndlPos = absPosition(this.$handle, direction, barXY, param), 7291 secndHndlPos = absPosition(this.$handle2, direction, barXY, param); 7292 $handle = firstHndlPos <= secndHndlPos ? this.$handle : this.$handle2; 7293 } 7294 } else { 7295 //change event on input 7296 value = this._adjustValue(null, val); 7297 hasVal = true; 7298 } 7299 7300 this._setHandlePos($handle, value, hasVal); 7301 } 7302 7303 /** 7304 * Adjustes value for handle in regard to step value. returns adjusted value 7305 * @function 7306 * @private 7307 * @param {jQuery} $handle - the selected handle. 7308 * @param {Number} value - value to adjust. used if $handle is falsy 7309 */ 7310 7311 }, { 7312 key: '_adjustValue', 7313 value: function _adjustValue($handle, value) { 7314 var val, 7315 step = this.options.step, 7316 div = parseFloat(step / 2), 7317 left, 7318 prev_val, 7319 next_val; 7320 if (!!$handle) { 7321 val = parseFloat($handle.attr('aria-valuenow')); 7322 } else { 7323 val = value; 7324 } 7325 left = val % step; 7326 prev_val = val - left; 7327 next_val = prev_val + step; 7328 if (left === 0) { 7329 return val; 7330 } 7331 val = val >= prev_val + div ? next_val : prev_val; 7332 return val; 7333 } 7334 7335 /** 7336 * Adds event listeners to the slider elements. 7337 * @function 7338 * @private 7339 * @param {jQuery} $handle - the current handle to apply listeners to. 7340 */ 7341 7342 }, { 7343 key: '_events', 7344 value: function _events($handle) { 7345 var _this = this, 7346 curHandle, 7347 timer; 7348 7349 this.inputs.off('change.zf.slider').on('change.zf.slider', function (e) { 7350 var idx = _this.inputs.index($(this)); 7351 _this._handleEvent(e, _this.handles.eq(idx), $(this).val()); 7352 }); 7353 7354 if (this.options.clickSelect) { 7355 this.$element.off('click.zf.slider').on('click.zf.slider', function (e) { 7356 if (_this.$element.data('dragging')) { 7357 return false; 7358 } 7359 7360 if (!$(e.target).is('[data-slider-handle]')) { 7361 if (_this.options.doubleSided) { 7362 _this._handleEvent(e); 7363 } else { 7364 _this._handleEvent(e, _this.$handle); 7365 } 7366 } 7367 }); 7368 } 7369 7370 if (this.options.draggable) { 7371 this.handles.addTouch(); 7372 7373 var $body = $('body'); 7374 $handle.off('mousedown.zf.slider').on('mousedown.zf.slider', function (e) { 7375 $handle.addClass('is-dragging'); 7376 _this.$fill.addClass('is-dragging'); // 7377 _this.$element.data('dragging', true); 7378 7379 curHandle = $(e.currentTarget); 7380 7381 $body.on('mousemove.zf.slider', function (e) { 7382 e.preventDefault(); 7383 _this._handleEvent(e, curHandle); 7384 }).on('mouseup.zf.slider', function (e) { 7385 _this._handleEvent(e, curHandle); 7386 7387 $handle.removeClass('is-dragging'); 7388 _this.$fill.removeClass('is-dragging'); 7389 _this.$element.data('dragging', false); 7390 7391 $body.off('mousemove.zf.slider mouseup.zf.slider'); 7392 }); 7393 }) 7394 // prevent events triggered by touch 7395 .on('selectstart.zf.slider touchmove.zf.slider', function (e) { 7396 e.preventDefault(); 7397 }); 7398 } 7399 7400 $handle.off('keydown.zf.slider').on('keydown.zf.slider', function (e) { 7401 var _$handle = $(this), 7402 idx = _this.options.doubleSided ? _this.handles.index(_$handle) : 0, 7403 oldValue = parseFloat(_this.inputs.eq(idx).val()), 7404 newValue; 7405 7406 // handle keyboard event with keyboard util 7407 Foundation.Keyboard.handleKey(e, 'Slider', { 7408 decrease: function () { 7409 newValue = oldValue - _this.options.step; 7410 }, 7411 increase: function () { 7412 newValue = oldValue + _this.options.step; 7413 }, 7414 decrease_fast: function () { 7415 newValue = oldValue - _this.options.step * 10; 7416 }, 7417 increase_fast: function () { 7418 newValue = oldValue + _this.options.step * 10; 7419 }, 7420 handled: function () { 7421 // only set handle pos when event was handled specially 7422 e.preventDefault(); 7423 _this._setHandlePos(_$handle, newValue, true); 7424 } 7425 }); 7426 /*if (newValue) { // if pressed key has special function, update value 7427 e.preventDefault(); 7428 _this._setHandlePos(_$handle, newValue); 7429 }*/ 7430 }); 7431 } 7432 7433 /** 7434 * Destroys the slider plugin. 7435 */ 7436 7437 }, {
7438 key: 'destroy', 7439 value: function destroy() { 7440 this.handles.off('.zf.slider'); 7441 this.inputs.off('.zf.slider'); 7442 this.$element.off('.zf.slider'); 7443 7444 Foundation.unregisterPlugin(this); 7445 } 7446 }]); 7447 7448 return Slider; 7449 }(); 7450 7451 Slider.defaults = { 7452 /** 7453 * Minimum value for the slider scale. 7454 * @option 7455 * @example 0 7456 */ 7457 start: 0, 7458 /** 7459 * Maximum value for the slider scale. 7460 * @option 7461 * @example 100 7462 */ 7463 end: 100, 7464 /** 7465 * Minimum value change per change event. 7466 * @option 7467 * @example 1 7468 */ 7469 step: 1, 7470 /** 7471 * Value at which the handle/input *(left handle/first input)* should be set to on initialization. 7472 * @option 7473 * @example 0 7474 */ 7475 initialStart: 0, 7476 /** 7477 * Value at which the right handle/second input should be set to on initialization. 7478 * @option 7479 * @example 100 7480 */ 7481 initialEnd: 100, 7482 /** 7483 * Allows the input to be located outside the container and visible. Set to by the JS 7484 * @option 7485 * @example false 7486 */ 7487 binding: false, 7488 /** 7489 * Allows the user to click/tap on the slider bar to select a value. 7490 * @option 7491 * @example true 7492 */ 7493 clickSelect: true, 7494 /** 7495 * Set to true and use the `vertical` class to change alignment to vertical. 7496 * @option 7497 * @example false 7498 */ 7499 vertical: false, 7500 /** 7501 * Allows the user to drag the slider handle(s) to select a value. 7502 * @option 7503 * @example true 7504 */ 7505 draggable: true, 7506 /** 7507 * Disables the slider and prevents event listeners from being applied. Double checked by JS with `disabledClass`. 7508 * @option 7509 * @example false 7510 */ 7511 disabled: false, 7512 /** 7513 * Allows the use of two handles. Double checked by the JS. Changes some logic handling. 7514 * @option 7515 * @example false 7516 */ 7517 doubleSided: false, 7518 /** 7519 * Potential future feature. 7520 */ 7521 // steps: 100, 7522 /** 7523 * Number of decimal places the plugin should go to for floating point precision. 7524 * @option 7525 * @example 2 7526 */ 7527 decimal: 2, 7528 /** 7529 * Time delay for dragged elements. 7530 */ 7531 // dragDelay: 0, 7532 /** 7533 * Time, in ms, to animate the movement of a slider handle if user clicks/taps on the bar. Needs to be manually set if updating the transition time in the Sass settings. 7534 * @option 7535 * @example 200 7536 */ 7537 moveTime: 200, //update this if changing the transition time in the sass 7538 /** 7539 * Class applied to disabled sliders. 7540 * @option 7541 * @example 'disabled' 7542 */ 7543 disabledClass: 'disabled', 7544 /** 7545 * Will invert the default layout for a vertical<span data-tooltip title="who would do this???"> </span>slider. 7546 * @option 7547 * @example false 7548 */ 7549 invertVertical: false, 7550 /** 7551 * Milliseconds before the `changed.zf-slider` event is triggered after value change. 7552 * @option 7553 * @example 500 7554 */ 7555 changedDelay: 500 7556 }; 7557 7558 function percent(frac, num) { 7559 return frac / num; 7560 } 7561 function absPosition($handle, dir, clickPos, param) { 7562 return Math.abs($handle.position()[dir] + $handle[param]() / 2 - clickPos); 7563 } 7564 7565 // Window exports 7566 Foundation.plugin(Slider, 'Slider'); 7567}(jQuery); 7568 7569//*********this is in case we go to static, absolute positions instead of dynamic positioning******** 7570// this.setSteps(function() { 7571// _this._events(); 7572// var initStart = _this.options.positions[_this.options.initialStart - 1] || null; 7573// var initEnd = _this.options.initialEnd ? _this.options.position[_this.options.initialEnd - 1] : null; 7574// if (initStart || initEnd) { 7575// _this._handleEvent(initStart, initEnd); 7576// } 7577// }); 7578 7579//***********the other part of absolute positions************* 7580// Slider.prototype.setSteps = function(cb) { 7581// var posChange = this.$element.outerWidth() / this.options.steps; 7582// var counter = 0 7583// while(counter < this.options.steps) { 7584// if (counter) { 7585// this.options.positions.push(this.options.positions[counter - 1] + posChange); 7586// } else { 7587// this.options.positions.push(posChange); 7588// } 7589// counter++; 7590// } 7591// cb(); 7592// }; 7593'use strict'; 7594 7595var _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; }; }(); 7596 7597function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 7598 7599!function ($) { 7600 7601 /** 7602 * Sticky module. 7603 * @module foundation.sticky 7604 * @requires foundation.util.triggers 7605 * @requires foundation.util.mediaQuery 7606 */ 7607 7608 var Sticky = function () { 7609 /** 7610 * Creates a new instance of a sticky thing. 7611 * @class 7612 * @param {jQuery} element - jQuery object to make sticky. 7613 * @param {Object} options - options object passed when creating the element programmatically. 7614 */ 7615 7616 function Sticky(element, options) { 7617 _classCallCheck(this, Sticky); 7618 7619 this.$element = element; 7620 this.options = $.extend({}, Sticky.defaults, this.$element.data(), options); 7621 7622 this._init(); 7623 7624 Foundation.registerPlugin(this, 'Sticky'); 7625 } 7626 7627 /** 7628 * Initializes the sticky element by adding classes, getting/setting dimensions, breakpoints and attributes 7629 * @function 7630 * @private 7631 */ 7632 7633 7634 _createClass(Sticky, [{ 7635 key: '_init', 7636 value: function _init() { 7637 var $parent = this.$element.parent('[data-sticky-container]'), 7638 id = this.$element[0].id || Foundation.GetYoDigits(6, 'sticky'), 7639 _this = this; 7640 7641 if (!$parent.length) { 7642 this.wasWrapped = true; 7643 } 7644 this.$container = $parent.length ? $parent : $(this.options.container).wrapInner(this.$element); 7645 this.$container.addClass(this.options.containerClass); 7646 7647 this.$element.addClass(this.options.stickyClass).attr({ 'data-resize': id }); 7648 7649 this.scrollCount = this.options.checkEvery; 7650 this.isStuck = false;
vendor: 4,703 bytes, lines 7651-7811
7651 $(window).one('load.zf.sticky', function () { 7652 if (_this.options.anchor !== '') { 7653 _this.$anchor = $('#' + _this.options.anchor); 7654 } else { 7655 _this._parsePoints(); 7656 } 7657 7658 _this._setSizes(function () { 7659 _this._calc(false); 7660 }); 7661 _this._events(id.split('-').reverse().join('-')); 7662 }); 7663 } 7664 7665 /** 7666 * If using multiple elements as anchors, calculates the top and bottom pixel values the sticky thing should stick and unstick on. 7667 * @function 7668 * @private 7669 */ 7670 7671 }, { 7672 key: '_parsePoints', 7673 value: function _parsePoints() { 7674 var top = this.options.topAnchor == "" ? 1 : this.options.topAnchor, 7675 btm = this.options.btmAnchor == "" ? document.documentElement.scrollHeight : this.options.btmAnchor, 7676 pts = [top, btm], 7677 breaks = {}; 7678 for (var i = 0, len = pts.length; i < len && pts[i]; i++) { 7679 var pt; 7680 if (typeof pts[i] === 'number') { 7681 pt = pts[i]; 7682 } else { 7683 var place = pts[i].split(':'), 7684 anchor = $('#' + place[0]); 7685 7686 pt = anchor.offset().top; 7687 if (place[1] && place[1].toLowerCase() === 'bottom') { 7688 pt += anchor[0].getBoundingClientRect().height; 7689 } 7690 } 7691 breaks[i] = pt; 7692 } 7693 7694 this.points = breaks; 7695 return; 7696 } 7697 7698 /** 7699 * Adds event handlers for the scrolling element. 7700 * @private 7701 * @param {String} id - psuedo-random id for unique scroll event listener. 7702 */ 7703 7704 }, { 7705 key: '_events', 7706 value: function _events(id) { 7707 var _this = this, 7708 scrollListener = this.scrollListener = 'scroll.zf.' + id; 7709 if (this.isOn) { 7710 return; 7711 } 7712 if (this.canStick) { 7713 this.isOn = true; 7714 $(window).off(scrollListener).on(scrollListener, function (e) { 7715 if (_this.scrollCount === 0) { 7716 _this.scrollCount = _this.options.checkEvery; 7717 _this._setSizes(function () { 7718 _this._calc(false, window.pageYOffset); 7719 }); 7720 } else { 7721 _this.scrollCount--; 7722 _this._calc(false, window.pageYOffset); 7723 } 7724 }); 7725 } 7726 7727 this.$element.off('resizeme.zf.trigger').on('resizeme.zf.trigger', function (e, el) { 7728 _this._setSizes(function () { 7729 _this._calc(false); 7730 if (_this.canStick) { 7731 if (!_this.isOn) { 7732 _this._events(id); 7733 } 7734 } else if (_this.isOn) { 7735 _this._pauseListeners(scrollListener); 7736 } 7737 }); 7738 }); 7739 } 7740 7741 /** 7742 * Removes event handlers for scroll and change events on anchor. 7743 * @fires Sticky#pause 7744 * @param {String} scrollListener - unique, namespaced scroll listener attached to `window` 7745 */ 7746 7747 }, { 7748 key: '_pauseListeners', 7749 value: function _pauseListeners(scrollListener) { 7750 this.isOn = false; 7751 $(window).off(scrollListener); 7752 7753 /** 7754 * Fires when the plugin is paused due to resize event shrinking the view. 7755 * @event Sticky#pause 7756 * @private 7757 */ 7758 this.$element.trigger('pause.zf.sticky'); 7759 } 7760 7761 /** 7762 * Called on every `scroll` event and on `_init` 7763 * fires functions based on booleans and cached values 7764 * @param {Boolean} checkSizes - true if plugin should recalculate sizes and breakpoints. 7765 * @param {Number} scroll - current scroll position passed from scroll event cb function. If not passed, defaults to `window.pageYOffset`. 7766 */ 7767 7768 }, { 7769 key: '_calc', 7770 value: function _calc(checkSizes, scroll) { 7771 if (checkSizes) { 7772 this._setSizes(); 7773 } 7774 7775 if (!this.canStick) { 7776 if (this.isStuck) { 7777 this._removeSticky(true); 7778 } 7779 return false; 7780 } 7781 7782 if (!scroll) { 7783 scroll = window.pageYOffset; 7784 } 7785 7786 if (scroll >= this.topPoint) { 7787 if (scroll <= this.bottomPoint) { 7788 if (!this.isStuck) { 7789 this._setSticky(); 7790 } 7791 } else { 7792 if (this.isStuck) { 7793 this._removeSticky(false); 7794 } 7795 } 7796 } else { 7797 if (this.isStuck) { 7798 this._removeSticky(true); 7799 } 7800 } 7801 } 7802 7803 /** 7804 * Causes the $element to become stuck. 7805 * Adds `position: fixed;`, and helper classes. 7806 * @fires Sticky#stuckto 7807 * @function 7808 * @private 7809 */ 7810 7811 }, {
7812 key: '_setSticky', 7813 value: function _setSticky() { 7814 var _this = this, 7815 stickTo = this.options.stickTo, 7816 mrgn = stickTo === 'top' ? 'marginTop' : 'marginBottom', 7817 notStuckTo = stickTo === 'top' ? 'bottom' : 'top', 7818 css = {}; 7819 7820 css[mrgn] = this.options[mrgn] + 'em'; 7821 css[stickTo] = 0; 7822 css[notStuckTo] = 'auto'; 7823 css['left'] = this.$container.offset().left + parseInt(window.getComputedStyle(this.$container[0])["padding-left"], 10); 7824 this.isStuck = true; 7825 this.$element.removeClass('is-anchored is-at-' + notStuckTo).addClass('is-stuck is-at-' + stickTo).css(css) 7826 /** 7827 * Fires when the $element has become `position: fixed;` 7828 * Namespaced to `top` or `bottom`, e.g. `sticky.zf.stuckto:top` 7829 * @event Sticky#stuckto 7830 */ 7831 .trigger('sticky.zf.stuckto:' + stickTo); 7832 this.$element.on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", function () { 7833 _this._setSizes(); 7834 }); 7835 } 7836 7837 /** 7838 * Causes the $element to become unstuck. 7839 * Removes `position: fixed;`, and helper classes. 7840 * Adds other helper classes. 7841 * @param {Boolean} isTop - tells the function if the $element should anchor to the top or bottom of its $anchor element. 7842 * @fires Sticky#unstuckfrom 7843 * @private 7844 */ 7845 7846 }, { 7847 key: '_removeSticky', 7848 value: function _removeSticky(isTop) { 7849 var stickTo = this.options.stickTo, 7850 stickToTop = stickTo === 'top', 7851 css = {}, 7852 anchorPt = (this.points ? this.points[1] - this.points[0] : this.anchorHeight) - this.elemHeight, 7853 mrgn = stickToTop ? 'marginTop' : 'marginBottom', 7854 notStuckTo = stickToTop ? 'bottom' : 'top', 7855 topOrBottom = isTop ? 'top' : 'bottom'; 7856 7857 css[mrgn] = 0; 7858 7859 css['bottom'] = 'auto'; 7860 if (isTop) { 7861 css['top'] = 0; 7862 } else { 7863 css['top'] = anchorPt; 7864 } 7865 7866 css['left'] = ''; 7867 this.isStuck = false; 7868 this.$element.removeClass('is-stuck is-at-' + stickTo).addClass('is-anchored is-at-' + topOrBottom).css(css) 7869 /** 7870 * Fires when the $element has become anchored. 7871 * Namespaced to `top` or `bottom`, e.g. `sticky.zf.unstuckfrom:bottom` 7872 * @event Sticky#unstuckfrom 7873 */ 7874 .trigger('sticky.zf.unstuckfrom:' + topOrBottom); 7875 } 7876 7877 /** 7878 * Sets the $element and $container sizes for plugin. 7879 * Calls `_setBreakPoints`. 7880 * @param {Function} cb - optional callback function to fire on completion of `_setBreakPoints`. 7881 * @private 7882 */ 7883 7884 }, { 7885 key: '_setSizes', 7886 value: function _setSizes(cb) { 7887 this.canStick = Foundation.MediaQuery.atLeast(this.options.stickyOn); 7888 if (!this.canStick) { 7889 cb(); 7890 } 7891 var _this = this, 7892 newElemWidth = this.$container[0].getBoundingClientRect().width, 7893 comp = window.getComputedStyle(this.$container[0]), 7894 pdng = parseInt(comp['padding-right'], 10); 7895 7896 if (this.$anchor && this.$anchor.length) { 7897 this.anchorHeight = this.$anchor[0].getBoundingClientRect().height; 7898 } else { 7899 this._parsePoints(); 7900 } 7901 7902 this.$element.css({ 7903 'max-width': newElemWidth - pdng + 'px' 7904 }); 7905 7906 var newContainerHeight = this.$element[0].getBoundingClientRect().height || this.containerHeight; 7907 if (this.$element.css("display") == "none") { 7908 newContainerHeight = 0; 7909 } 7910 this.containerHeight = newContainerHeight; 7911 this.$container.css({ 7912 height: newContainerHeight 7913 }); 7914 this.elemHeight = newContainerHeight; 7915 7916 if (this.isStuck) { 7917 this.$element.css({ "left": this.$container.offset().left + parseInt(comp['padding-left'], 10) }); 7918 } 7919 7920 this._setBreakPoints(newContainerHeight, function () { 7921 if (cb) { 7922 cb(); 7923 } 7924 }); 7925 } 7926 7927 /** 7928 * Sets the upper and lower breakpoints for the element to become sticky/unsticky. 7929 * @param {Number} elemHeight - px value for sticky.$element height, calculated by `_setSizes`. 7930 * @param {Function} cb - optional callback function to be called on completion. 7931 * @private 7932 */ 7933 7934 }, {
7935 key: '_setBreakPoints', 7936 value: function _setBreakPoints(elemHeight, cb) { 7937 if (!this.canStick) { 7938 if (cb) { 7939 cb(); 7940 } else { 7941 return false; 7942 } 7943 } 7944 var mTop = emCalc(this.options.marginTop), 7945 mBtm = emCalc(this.options.marginBottom), 7946 topPoint = this.points ? this.points[0] : this.$anchor.offset().top, 7947 bottomPoint = this.points ? this.points[1] : topPoint + this.anchorHeight, 7948 7949 // topPoint = this.$anchor.offset().top || this.points[0], 7950 // bottomPoint = topPoint + this.anchorHeight || this.points[1], 7951 winHeight = window.innerHeight; 7952 7953 if (this.options.stickTo === 'top') { 7954 topPoint -= mTop; 7955 bottomPoint -= elemHeight + mTop; 7956 } else if (this.options.stickTo === 'bottom') { 7957 topPoint -= winHeight - (elemHeight + mBtm); 7958 bottomPoint -= winHeight - mBtm; 7959 } else { 7960 //this would be the stickTo: both option... tricky 7961 } 7962 7963 this.topPoint = topPoint; 7964 this.bottomPoint = bottomPoint; 7965 7966 if (cb) { 7967 cb(); 7968 } 7969 } 7970 7971 /** 7972 * Destroys the current sticky element. 7973 * Resets the element to the top position first. 7974 * Removes event listeners, JS-added css properties and classes, and unwraps the $element if the JS added the $container. 7975 * @function 7976 */ 7977 7978 }, { 7979 key: 'destroy', 7980 value: function destroy() { 7981 this._removeSticky(true); 7982 7983 this.$element.removeClass(this.options.stickyClass + ' is-anchored is-at-top').css({ 7984 height: '', 7985 top: '', 7986 bottom: '', 7987 'max-width': '' 7988 }).off('resizeme.zf.trigger'); 7989 if (this.$anchor && this.$anchor.length) { 7990 this.$anchor.off('change.zf.sticky'); 7991 } 7992 $(window).off(this.scrollListener); 7993 7994 if (this.wasWrapped) { 7995 this.$element.unwrap(); 7996 } else { 7997 this.$container.removeClass(this.options.containerClass).css({ 7998 height: '' 7999 }); 8000 } 8001 Foundation.unregisterPlugin(this); 8002 } 8003 }]); 8004 8005 return Sticky; 8006 }(); 8007 8008 Sticky.defaults = { 8009 /** 8010 * Customizable container template. Add your own classes for styling and sizing. 8011 * @option 8012 * @example '<div data-sticky-container class="small-6 columns"></div>' 8013 */ 8014 container: '<div data-sticky-container></div>', 8015 /** 8016 * Location in the view the element sticks to. 8017 * @option 8018 * @example 'top' 8019 */ 8020 stickTo: 'top', 8021 /** 8022 * If anchored to a single element, the id of that element. 8023 * @option 8024 * @example 'exampleId' 8025 */ 8026 anchor: '', 8027 /** 8028 * If using more than one element as anchor points, the id of the top anchor. 8029 * @option 8030 * @example 'exampleId:top' 8031 */ 8032 topAnchor: '', 8033 /** 8034 * If using more than one element as anchor points, the id of the bottom anchor. 8035 * @option 8036 * @example 'exampleId:bottom' 8037 */ 8038 btmAnchor: '', 8039 /** 8040 * Margin, in `em`'s to apply to the top of the element when it becomes sticky. 8041 * @option 8042 * @example 1 8043 */ 8044 marginTop: 1, 8045 /** 8046 * Margin, in `em`'s to apply to the bottom of the element when it becomes sticky. 8047 * @option 8048 * @example 1 8049 */ 8050 marginBottom: 1, 8051 /** 8052 * Breakpoint string that is the minimum screen size an element should become sticky. 8053 * @option 8054 * @example 'medium' 8055 */ 8056 stickyOn: 'medium', 8057 /** 8058 * Class applied to sticky element, and removed on destruction. Foundation defaults to `sticky`. 8059 * @option 8060 * @example 'sticky' 8061 */ 8062 stickyClass: 'sticky', 8063 /** 8064 * Class applied to sticky container. Foundation defaults to `sticky-container`. 8065 * @option 8066 * @example 'sticky-container' 8067 */ 8068 containerClass: 'sticky-container', 8069 /** 8070 * 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. 8071 * @option 8072 * @example 50 8073 */ 8074 checkEvery: -1 8075 }; 8076 8077 /** 8078 * Helper function to calculate em values 8079 * @param Number {em} - number of em's to calculate into pixels 8080 */ 8081 function emCalc(em) { 8082 return parseInt(window.getComputedStyle(document.body, null).fontSize, 10) * em; 8083 } 8084 8085 // Window exports 8086 Foundation.plugin(Sticky, 'Sticky'); 8087}(jQuery); 8088'use strict'; 8089 8090var _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; }; }(); 8091 8092function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 8093 8094!function ($) { 8095 8096 /** 8097 * Tabs module. 8098 * @module foundation.tabs 8099 * @requires foundation.util.keyboard 8100 * @requires foundation.util.timerAndImageLoader if tabs contain images 8101 */ 8102 8103 var Tabs = function () { 8104 /** 8105 * Creates a new instance of tabs. 8106 * @class 8107 * @fires Tabs#init 8108 * @param {jQuery} element - jQuery object to make into tabs. 8109 * @param {Object} options - Overrides to the default plugin settings. 8110 */ 8111 8112 function Tabs(element, options) { 8113 _classCallCheck(this, Tabs); 8114 8115 this.$element = element; 8116 this.options = $.extend({}, Tabs.defaults, this.$element.data(), options); 8117 8118 this._init(); 8119 Foundation.registerPlugin(this, 'Tabs'); 8120 Foundation.Keyboard.register('Tabs', { 8121 'ENTER': 'open', 8122 'SPACE': 'open',
8123 'ARROW_RIGHT': 'next', 8124 'ARROW_UP': 'previous', 8125 'ARROW_DOWN': 'next', 8126 'ARROW_LEFT': 'previous' 8127 // 'TAB': 'next', 8128 // 'SHIFT_TAB': 'previous' 8129 }); 8130 } 8131 8132 /** 8133 * Initializes the tabs by showing and focusing (if autoFocus=true) the preset active tab. 8134 * @private 8135 */ 8136 8137 8138 _createClass(Tabs, [{ 8139 key: '_init', 8140 value: function _init() { 8141 var _this = this; 8142 8143 this.$tabTitles = this.$element.find('.' + this.options.linkClass); 8144 this.$tabContent = $('[data-tabs-content="' + this.$element[0].id + '"]'); 8145 8146 this.$tabTitles.each(function () { 8147 var $elem = $(this), 8148 $link = $elem.find('a'), 8149 isActive = $elem.hasClass('is-active'), 8150 hash = $link[0].hash.slice(1), 8151 linkId = $link[0].id ? $link[0].id : hash + '-label', 8152 $tabContent = $('#' + hash); 8153 8154 $elem.attr({ 'role': 'presentation' }); 8155 8156 $link.attr({ 8157 'role': 'tab', 8158 'aria-controls': hash, 8159 'aria-selected': isActive, 8160 'id': linkId 8161 }); 8162 8163 $tabContent.attr({ 8164 'role': 'tabpanel', 8165 'aria-hidden': !isActive, 8166 'aria-labelledby': linkId 8167 }); 8168 8169 if (isActive && _this.options.autoFocus) { 8170 $link.focus(); 8171 } 8172 }); 8173 8174 if (this.options.matchHeight) { 8175 var $images = this.$tabContent.find('img'); 8176 8177 if ($images.length) { 8178 Foundation.onImagesLoaded($images, this._setHeight.bind(this)); 8179 } else { 8180 this._setHeight(); 8181 } 8182 } 8183 8184 this._events(); 8185 } 8186 8187 /** 8188 * Adds event handlers for items within the tabs. 8189 * @private 8190 */ 8191 8192 }, { 8193 key: '_events', 8194 value: function _events() { 8195 this._addKeyHandler(); 8196 this._addClickHandler(); 8197 this._setHeightMqHandler = null; 8198 8199 if (this.options.matchHeight) { 8200 this._setHeightMqHandler = this._setHeight.bind(this); 8201 8202 $(window).on('changed.zf.mediaquery', this._setHeightMqHandler); 8203 } 8204 } 8205 8206 /** 8207 * Adds click handlers for items within the tabs. 8208 * @private 8209 */ 8210 8211 }, { 8212 key: '_addClickHandler', 8213 value: function _addClickHandler() { 8214 var _this = this; 8215 8216 this.$element.off('click.zf.tabs').on('click.zf.tabs', '.' + this.options.linkClass, function (e) { 8217 e.preventDefault(); 8218 e.stopPropagation(); 8219 if ($(this).hasClass('is-active')) { 8220 return; 8221 } 8222 _this._handleTabChange($(this)); 8223 }); 8224 } 8225 8226 /** 8227 * Adds keyboard event handlers for items within the tabs. 8228 * @private 8229 */ 8230 8231 }, { 8232 key: '_addKeyHandler', 8233 value: function _addKeyHandler() { 8234 var _this = this; 8235 var $firstTab = _this.$element.find('li:first-of-type'); 8236 var $lastTab = _this.$element.find('li:last-of-type'); 8237 8238 this.$tabTitles.off('keydown.zf.tabs').on('keydown.zf.tabs', function (e) { 8239 if (e.which === 9) return; 8240 8241 var $element = $(this), 8242 $elements = $element.parent('ul').children('li'), 8243 $prevElement, 8244 $nextElement; 8245 8246 $elements.each(function (i) { 8247 if ($(this).is($element)) { 8248 if (_this.options.wrapOnKeys) { 8249 $prevElement = i === 0 ? $elements.last() : $elements.eq(i - 1); 8250 $nextElement = i === $elements.length - 1 ? $elements.first() : $elements.eq(i + 1); 8251 } else { 8252 $prevElement = $elements.eq(Math.max(0, i - 1)); 8253 $nextElement = $elements.eq(Math.min(i + 1, $elements.length - 1)); 8254 } 8255 return; 8256 } 8257 }); 8258 8259 // handle keyboard event with keyboard util 8260 Foundation.Keyboard.handleKey(e, 'Tabs', { 8261 open: function () { 8262 $element.find('[role="tab"]').focus(); 8263 _this._handleTabChange($element); 8264 }, 8265 previous: function () { 8266 $prevElement.find('[role="tab"]').focus(); 8267 _this._handleTabChange($prevElement); 8268 }, 8269 next: function () { 8270 $nextElement.find('[role="tab"]').focus(); 8271 _this._handleTabChange($nextElement); 8272 }, 8273 handled: function () { 8274 e.stopPropagation(); 8275 e.preventDefault(); 8276 } 8277 }); 8278 }); 8279 } 8280 8281 /** 8282 * Opens the tab `$targetContent` defined by `$target`. 8283 * @param {jQuery} $target - Tab to open. 8284 * @fires Tabs#change 8285 * @function 8286 */ 8287 8288 }, {
8289 key: '_handleTabChange', 8290 value: function _handleTabChange($target) { 8291 var $tabLink = $target.find('[role="tab"]'), 8292 hash = $tabLink[0].hash, 8293 $targetContent = this.$tabContent.find(hash), 8294 $oldTab = this.$element.find('.' + this.options.linkClass + '.is-active').removeClass('is-active').find('[role="tab"]').attr({ 'aria-selected': 'false' }); 8295 8296 $('#' + $oldTab.attr('aria-controls')).removeClass('is-active').attr({ 'aria-hidden': 'true' }); 8297 8298 $target.addClass('is-active'); 8299 8300 $tabLink.attr({ 'aria-selected': 'true' }); 8301 8302 $targetContent.addClass('is-active').attr({ 'aria-hidden': 'false' }); 8303 8304 /** 8305 * Fires when the plugin has successfully changed tabs. 8306 * @event Tabs#change 8307 */ 8308 this.$element.trigger('change.zf.tabs', [$target]); 8309 } 8310 8311 /** 8312 * Public method for selecting a content pane to display. 8313 * @param {jQuery | String} elem - jQuery object or string of the id of the pane to display. 8314 * @function 8315 */ 8316 8317 }, { 8318 key: 'selectTab', 8319 value: function selectTab(elem) { 8320 var idStr; 8321 8322 if (typeof elem === 'object') { 8323 idStr = elem[0].id; 8324 } else { 8325 idStr = elem; 8326 } 8327 8328 if (idStr.indexOf('#') < 0) { 8329 idStr = '#' + idStr; 8330 } 8331 8332 var $target = this.$tabTitles.find('[href="' + idStr + '"]').parent('.' + this.options.linkClass); 8333 8334 this._handleTabChange($target); 8335 } 8336 }, { 8337 key: '_setHeight', 8338 8339 /** 8340 * Sets the height of each panel to the height of the tallest panel. 8341 * If enabled in options, gets called on media query change. 8342 * If loading content via external source, can be called directly or with _reflow. 8343 * @function 8344 * @private 8345 */ 8346 value: function _setHeight() { 8347 var max = 0; 8348 this.$tabContent.find('.' + this.options.panelClass).css('height', '').each(function () { 8349 var panel = $(this), 8350 isActive = panel.hasClass('is-active'); 8351 8352 if (!isActive) { 8353 panel.css({ 'visibility': 'hidden', 'display': 'block' }); 8354 } 8355 8356 var temp = this.getBoundingClientRect().height; 8357 8358 if (!isActive) { 8359 panel.css({ 8360 'visibility': '', 8361 'display': '' 8362 }); 8363 } 8364 8365 max = temp > max ? temp : max; 8366 }).css('height', max + 'px'); 8367 } 8368 8369 /** 8370 * Destroys an instance of an tabs. 8371 * @fires Tabs#destroyed 8372 */ 8373 8374 }, { 8375 key: 'destroy', 8376 value: function destroy() { 8377 this.$element.find('.' + this.options.linkClass).off('.zf.tabs').hide().end().find('.' + this.options.panelClass).hide(); 8378 8379 if (this.options.matchHeight) { 8380 if (this._setHeightMqHandler != null) { 8381 $(window).off('changed.zf.mediaquery', this._setHeightMqHandler); 8382 } 8383 } 8384 8385 Foundation.unregisterPlugin(this); 8386 } 8387 }]); 8388 8389 return Tabs; 8390 }(); 8391 8392 Tabs.defaults = { 8393 /** 8394 * Allows the window to scroll to content of active pane on load if set to true. 8395 * @option 8396 * @example false 8397 */ 8398 autoFocus: false, 8399 8400 /** 8401 * Allows keyboard input to 'wrap' around the tab links. 8402 * @option 8403 * @example true 8404 */ 8405 wrapOnKeys: true, 8406 8407 /** 8408 * Allows the tab content panes to match heights if set to true. 8409 * @option 8410 * @example false 8411 */ 8412 matchHeight: false, 8413 8414 /** 8415 * Class applied to `li`'s in tab link list. 8416 * @option 8417 * @example 'tabs-title' 8418 */ 8419 linkClass: 'tabs-title', 8420 8421 /** 8422 * Class applied to the content containers. 8423 * @option 8424 * @example 'tabs-panel' 8425 */ 8426 panelClass: 'tabs-panel' 8427 }; 8428 8429 function checkClass($elem) { 8430 return $elem.hasClass('is-active'); 8431 } 8432 8433 // Window exports 8434 Foundation.plugin(Tabs, 'Tabs'); 8435}(jQuery); 8436'use strict'; 8437 8438var _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; }; }(); 8439 8440function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 8441 8442!function ($) { 8443 8444 /** 8445 * Toggler module. 8446 * @module foundation.toggler 8447 * @requires foundation.util.motion 8448 * @requires foundation.util.triggers 8449 */ 8450 8451 var Toggler = function () { 8452 /** 8453 * Creates a new instance of Toggler. 8454 * @class 8455 * @fires Toggler#init 8456 * @param {Object} element - jQuery object to add the trigger to. 8457 * @param {Object} options - Overrides to the default plugin settings. 8458 */ 8459 8460 function Toggler(element, options) { 8461 _classCallCheck(this, Toggler); 8462 8463 this.$element = element; 8464 this.options = $.extend({}, Toggler.defaults, element.data(), options); 8465 this.className = ''; 8466 8467 this._init(); 8468 this._events(); 8469 8470 Foundation.registerPlugin(this, 'Toggler'); 8471 } 8472 8473 /** 8474 * Initializes the Toggler plugin by parsing the toggle class from data-toggler, or animation classes from data-animate. 8475 * @function 8476 * @private 8477 */ 8478 8479 8480 _createClass(Toggler, [{ 8481 key: '_init', 8482 value: function _init() { 8483 var input; 8484 // Parse animation classes if they were set 8485 if (this.options.animate) { 8486 input = this.options.animate.split(' '); 8487 8488 this.animationIn = input[0]; 8489 this.animationOut = input[1] || null; 8490 } 8491 // Otherwise, parse toggle class 8492 else { 8493 input = this.$element.data('toggler'); 8494 // Allow for a . at the beginning of the string 8495 this.className = input[0] === '.' ? input.slice(1) : input; 8496 } 8497 8498 // Add ARIA attributes to triggers 8499 var id = this.$element[0].id; 8500 $('[data-open="' + id + '"], [data-close="' + id + '"], [data-toggle="' + id + '"]').attr('aria-controls', id); 8501 // If the target is hidden, add aria-hidden 8502 this.$element.attr('aria-expanded', this.$element.is(':hidden') ? false : true); 8503 } 8504 8505 /** 8506 * Initializes events for the toggle trigger. 8507 * @function 8508 * @private 8509 */ 8510 8511 }, {
8512 key: '_events', 8513 value: function _events() { 8514 this.$element.off('toggle.zf.trigger').on('toggle.zf.trigger', this.toggle.bind(this)); 8515 } 8516 8517 /** 8518 * Toggles the target class on the target element. An event is fired from the original trigger depending on if the resultant state was "on" or "off". 8519 * @function 8520 * @fires Toggler#on 8521 * @fires Toggler#off 8522 */ 8523 8524 }, { 8525 key: 'toggle', 8526 value: function toggle() { 8527 this[this.options.animate ? '_toggleAnimate' : '_toggleClass'](); 8528 } 8529 }, { 8530 key: '_toggleClass', 8531 value: function _toggleClass() { 8532 this.$element.toggleClass(this.className); 8533 8534 var isOn = this.$element.hasClass(this.className); 8535 if (isOn) { 8536 /** 8537 * Fires if the target element has the class after a toggle. 8538 * @event Toggler#on 8539 */ 8540 this.$element.trigger('on.zf.toggler'); 8541 } else { 8542 /** 8543 * Fires if the target element does not have the class after a toggle. 8544 * @event Toggler#off 8545 */ 8546 this.$element.trigger('off.zf.toggler'); 8547 } 8548 8549 this._updateARIA(isOn); 8550 } 8551 }, { 8552 key: '_toggleAnimate', 8553 value: function _toggleAnimate() { 8554 var _this = this; 8555 8556 if (this.$element.is(':hidden')) { 8557 Foundation.Motion.animateIn(this.$element, this.animationIn, function () { 8558 _this._updateARIA(true); 8559 this.trigger('on.zf.toggler'); 8560 }); 8561 } else { 8562 Foundation.Motion.animateOut(this.$element, this.animationOut, function () { 8563 _this._updateARIA(false); 8564 this.trigger('off.zf.toggler'); 8565 }); 8566 } 8567 } 8568 }, { 8569 key: '_updateARIA', 8570 value: function _updateARIA(isOn) { 8571 this.$element.attr('aria-expanded', isOn ? true : false); 8572 } 8573 8574 /** 8575 * Destroys the instance of Toggler on the element. 8576 * @function 8577 */ 8578 8579 }, { 8580 key: 'destroy', 8581 value: function destroy() { 8582 this.$element.off('.zf.toggler'); 8583 Foundation.unregisterPlugin(this); 8584 } 8585 }]); 8586 8587 return Toggler; 8588 }(); 8589 8590 Toggler.defaults = { 8591 /** 8592 * Tells the plugin if the element should animated when toggled. 8593 * @option 8594 * @example false 8595 */ 8596 animate: false 8597 }; 8598 8599 // Window exports 8600 Foundation.plugin(Toggler, 'Toggler'); 8601}(jQuery); 8602'use strict'; 8603 8604var _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; }; }(); 8605 8606function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 8607 8608!function ($) { 8609 8610 /** 8611 * Tooltip module. 8612 * @module foundation.tooltip 8613 * @requires foundation.util.box 8614 * @requires foundation.util.triggers 8615 */ 8616 8617 var Tooltip = function () { 8618 /** 8619 * Creates a new instance of a Tooltip. 8620 * @class 8621 * @fires Tooltip#init 8622 * @param {jQuery} element - jQuery object to attach a tooltip to. 8623 * @param {Object} options - object to extend the default configuration. 8624 */ 8625 8626 function Tooltip(element, options) { 8627 _classCallCheck(this, Tooltip); 8628 8629 this.$element = element; 8630 this.options = $.extend({}, Tooltip.defaults, this.$element.data(), options); 8631 8632 this.isActive = false; 8633 this.isClick = false; 8634 this._init(); 8635 8636 Foundation.registerPlugin(this, 'Tooltip'); 8637 } 8638 8639 /** 8640 * Initializes the tooltip by setting the creating the tip element, adding it's text, setting private variables and setting attributes on the anch
8640or. 8641 * @private 8642 */ 8643 8644 8645 _createClass(Tooltip, [{ 8646 key: '_init', 8647 value: function _init() { 8648 var elemId = this.$element.attr('aria-describedby') || Foundation.GetYoDigits(6, 'tooltip'); 8649 8650 this.options.positionClass = this.options.positionClass || this._getPositionClass(this.$element); 8651 this.options.tipText = this.options.tipText || this.$element.attr('title'); 8652 this.template = this.options.template ? $(this.options.template) : this._buildTemplate(elemId); 8653 8654 this.template.appendTo(document.body).text(this.options.tipText).hide(); 8655 8656 this.$element.attr({ 8657 'title': '', 8658 'aria-describedby': elemId, 8659 'data-yeti-box': elemId, 8660 'data-toggle': elemId, 8661 'data-resize': elemId 8662 }).addClass(this.triggerClass); 8663 8664 //helper variables to track movement on collisions 8665 this.usedPositions = []; 8666 this.counter = 4; 8667 this.classChanged = false; 8668 8669 this._events(); 8670 } 8671 8672 /** 8673 * Grabs the current positioning class, if present, and returns the value or an empty string. 8674 * @private 8675 */ 8676 8677 }, { 8678 key: '_getPositionClass', 8679 value: function _getPositionClass(element) { 8680 if (!element) { 8681 return ''; 8682 } 8683 // var position = element.attr('class').match(/top|left|right/g); 8684 var position = element[0].className.match(/\b(top|left|right)\b/g); 8685 position = position ? position[0] : ''; 8686 return position; 8687 } 8688 }, { 8689 key: '_buildTemplate', 8690 8691 /** 8692 * builds the tooltip element, adds attributes, and returns the template. 8693 * @private 8694 */ 8695 value: function _buildTemplate(id) { 8696 var templateClasses = (this.options.tooltipClass + ' ' + this.options.positionClass + ' ' + this.options.templateClasses).trim(); 8697 var $template = $('<div></div>').addClass(templateClasses).attr({ 8698 'role': 'tooltip', 8699 'aria-hidden': true, 8700 'data-is-active': false, 8701 'data-is-focus': false, 8702 'id': id 8703 }); 8704 return $template; 8705 } 8706 8707 /** 8708 * Function that gets called if a collision event is detected. 8709 * @param {String} position - positioning class to try 8710 * @private 8711 */ 8712 8713 }, { 8714 key: '_reposition', 8715 value: function _reposition(position) { 8716 this.usedPositions.push(position ? position : 'bottom'); 8717 8718 //default, try switching to opposite side 8719 if (!position && this.usedPositions.indexOf('top') < 0) { 8720 this.template.addClass('top'); 8721 } else if (position === 'top' && this.usedPositions.indexOf('bottom') < 0) { 8722 this.template.removeClass(position); 8723 } else if (position === 'left' && this.usedPositions.indexOf('right') < 0) { 8724 this.template.removeClass(position).addClass('right'); 8725 } else if (position === 'right' && this.usedPositions.indexOf('left') < 0) { 8726 this.template.removeClass(position).addClass('left'); 8727 } 8728 8729 //if default change didn't work, try bottom or left first 8730 else if (!position && this.usedPositions.indexOf('top') > -1 && this.usedPositions.indexOf('left') < 0) { 8731 this.template.addClass('left'); 8732 } else if (position === 'top' && this.usedPositions.indexOf('bottom') > -1 && this.usedPositions.indexOf('left') < 0) { 8733 this.template.removeClass(position).addClass('left'); 8734 } else if (position === 'left' && this.usedPositions.indexOf('right') > -1 && this.usedPositions.indexOf('bottom') < 0) { 8735 this.template.removeClass(position); 8736 } else if (position === 'right' && this.usedPositions.indexOf('left') > -1 && this.usedPositions.indexOf('bottom') < 0) { 8737 this.template.removeClass(position); 8738 } 8739 //if nothing cleared, set to bottom 8740 else { 8741 this.template.removeClass(position); 8742 } 8743 this.classChanged = true; 8744 this.counter--; 8745 } 8746 8747 /** 8748 * sets the position class of an element and recursively calls itself until there are no more possible positions to attempt, or the tooltip element is no longer colliding. 8749 * if the tooltip is larger than the screen width, default to full width - any user selected margin 8750 * @private 8751 */ 8752 8753 }, {
8754 key: '_setPosition', 8755 value: function _setPosition() { 8756 var position = this._getPositionClass(this.template), 8757 $tipDims = Foundation.Box.GetDimensions(this.template), 8758 $anchorDims = Foundation.Box.GetDimensions(this.$element), 8759 direction = position === 'left' ? 'left' : position === 'right' ? 'left' : 'top', 8760 param = direction === 'top' ? 'height' : 'width', 8761 offset = param === 'height' ? this.options.vOffset : this.options.hOffset, 8762 _this = this; 8763 8764 if ($tipDims.width >= $tipDims.windowDims.width || !this.counter && !Foundation.Box.ImNotTouchingYou(this.template)) { 8765 this.template.offset(Foundation.Box.GetOffsets(this.template, this.$element, 'center bottom', this.options.vOffset, this.options.hOffset, true)).css({ 8766 // this.$element.offset(Foundation.GetOffsets(this.template, this.$element, 'center bottom', this.options.vOffset, this.options.hOffset, true)).css({ 8767 'width': $anchorDims.windowDims.width - this.options.hOffset * 2, 8768 'height': 'auto' 8769 }); 8770 return false; 8771 } 8772 8773 this.template.offset(Foundation.Box.GetOffsets(this.template, this.$element, 'center ' + (position || 'bottom'), this.options.vOffset, this.options.hOffset)); 8774 8775 while (!Foundation.Box.ImNotTouchingYou(this.template) && this.counter) { 8776 this._reposition(position); 8777 this._setPosition(); 8778 } 8779 } 8780 8781 /** 8782 * reveals the tooltip, and fires an event to close any other open tooltips on the page 8783 * @fires Tooltip#closeme 8784 * @fires Tooltip#show 8785 * @function 8786 */ 8787 8788 }, { 8789 key: 'show', 8790 value: function show() { 8791 if (this.options.showOn !== 'all' && !Foundation.MediaQuery.atLeast(this.options.showOn)) { 8792 // console.error('The screen is too small to display this tooltip'); 8793 return false; 8794 } 8795 8796 var _this = this; 8797 this.template.css('visibility', 'hidden').show(); 8798 this._setPosition(); 8799 8800 /** 8801 * Fires to close all other open tooltips on the page 8802 * @event Closeme#tooltip 8803 */ 8804 this.$element.trigger('closeme.zf.tooltip', this.template.attr('id')); 8805 8806 this.template.attr({ 8807 'data-is-active': true, 8808 'aria-hidden': false 8809 }); 8810 _this.isActive = true; 8811 // console.log(this.template); 8812 this.template.stop().hide().css('visibility', '').fadeIn(this.options.fadeInDuration, function () { 8813 //maybe do stuff? 8814 }); 8815 /** 8816 * Fires when the tooltip is shown 8817 * @event Tooltip#show 8818 */ 8819 this.$element.trigger('show.zf.tooltip'); 8820 } 8821 8822 /** 8823 * Hides the current tooltip, and resets the positioning class if it was changed due to collision 8824 * @fires Tooltip#hide 8825 * @function 8826 */ 8827 8828 }, { 8829 key: 'hide', 8830 value: function hide() { 8831 // console.log('hiding', this.$element.data('yeti-box')); 8832 var _this = this; 8833 this.template.stop().attr({ 8834 'aria-hidden': true, 8835 'data-is-active': false 8836 }).fadeOut(this.options.fadeOutDuration, function () { 8837 _this.isActive = false; 8838 _this.isClick = false; 8839 if (_this.classChanged) { 8840 _this.template.removeClass(_this._getPositionClass(_this.template)).addClass(_this.options.positionClass); 8841 8842 _this.usedPositions = []; 8843 _this.counter = 4; 8844 _this.classChanged = false; 8845 } 8846 }); 8847 /** 8848 * fires when the tooltip is hidden 8849 * @event Tooltip#hide 8850 */ 8851 this.$element.trigger('hide.zf.tooltip'); 8852 } 8853 8854 /** 8855 * adds event listeners for the tooltip and its anchor
8856 * TODO combine some of the listeners like focus and mouseenter, etc. 8857 * @private 8858 */ 8859 8860 }, { 8861 key: '_events', 8862 value: function _events() { 8863 var _this = this; 8864 var $template = this.template; 8865 var isFocus = false; 8866 8867 if (!this.options.disableHover) { 8868 8869 this.$element.on('mouseenter.zf.tooltip', function (e) { 8870 if (!_this.isActive) { 8871 _this.timeout = setTimeout(function () { 8872 _this.show(); 8873 }, _this.options.hoverDelay); 8874 } 8875 }).on('mouseleave.zf.tooltip', function (e) { 8876 clearTimeout(_this.timeout); 8877 if (!isFocus || _this.isClick && !_this.options.clickOpen) { 8878 _this.hide(); 8879 } 8880 }); 8881 } 8882 8883 if (this.options.clickOpen) { 8884 this.$element.on('mousedown.zf.tooltip', function (e) { 8885 e.stopImmediatePropagation(); 8886 if (_this.isClick) { 8887 //_this.hide(); 8888 // _this.isClick = false; 8889 } else { 8890 _this.isClick = true; 8891 if ((_this.options.disableHover || !_this.$element.attr('tabindex')) && !_this.isActive) { 8892 _this.show(); 8893 } 8894 } 8895 }); 8896 } else { 8897 this.$element.on('mousedown.zf.tooltip', function (e) { 8898 e.stopImmediatePropagation(); 8899 _this.isClick = true; 8900 }); 8901 } 8902 8903 if (!this.options.disableForTouch) { 8904 this.$element.on('tap.zf.tooltip touchend.zf.tooltip', function (e) { 8905 _this.isActive ? _this.hide() : _this.show(); 8906 }); 8907 } 8908 8909 this.$element.on({ 8910 // 'toggle.zf.trigger': this.toggle.bind(this), 8911 // 'close.zf.trigger': this.hide.bind(this) 8912 'close.zf.trigger': this.hide.bind(this) 8913 }); 8914 8915 this.$element.on('focus.zf.tooltip', function (e) { 8916 isFocus = true; 8917 if (_this.isClick) { 8918 // If we're not showing open on clicks, we need to pretend a click-launched focus isn't 8919 // a real focus, otherwise on hover and come back we get bad behavior 8920 if (!_this.options.clickOpen) { 8921 isFocus = false; 8922 } 8923 return false; 8924 } else { 8925 _this.show(); 8926 } 8927 }).on('focusout.zf.tooltip', function (e) { 8928 isFocus = false; 8929 _this.isClick = false; 8930 _this.hide(); 8931 }).on('resizeme.zf.trigger', function () { 8932 if (_this.isActive) { 8933 _this._setPosition(); 8934 } 8935 }); 8936 } 8937 8938 /** 8939 * adds a toggle method, in addition to the static show() & hide() functions 8940 * @function 8941 */ 8942 8943 }, { 8944 key: 'toggle', 8945 value: function toggle() { 8946 if (this.isActive) { 8947 this.hide(); 8948 } else { 8949 this.show(); 8950 } 8951 } 8952 8953 /** 8954 * Destroys an instance of tooltip, removes template element from the view. 8955 * @function 8956 */ 8957 8958 }, { 8959 key: 'destroy', 8960 value: function destroy() { 8961 this.$element.attr('title', this.template.text()).off('.zf.trigger .zf.tootip') 8962 // .removeClass('has-tip') 8963 .removeAttr('aria-describedby').removeAttr('data-yeti-box').removeAttr('data-toggle').removeAttr('data-resize'); 8964 8965 this.template.remove(); 8966 8967 Foundation.unregisterPlugin(this); 8968 } 8969 }]); 8970 8971 return Tooltip; 8972 }(); 8973 8974 Tooltip.defaults = { 8975 disableForTouch: false, 8976 /** 8977 * Time, in ms, before a tooltip should open on hover. 8978 * @option 8979 * @example 200 8980 */ 8981 hoverDelay: 200, 8982 /** 8983 * Time, in ms, a tooltip should take to fade into view. 8984 * @option 8985 * @example 150 8986 */ 8987 fadeInDuration: 150, 8988 /** 8989 * Time, in ms, a tooltip should take to fade out of view. 8990 * @option 8991 * @example 150 8992 */ 8993 fadeOutDuration: 150, 8994 /** 8995 * Disables hover events from opening the tooltip if set to true 8996 * @option 8997 * @example false 8998 */ 8999 disableHover: false, 9000 /** 9001 * Optional addtional classes to apply to the tooltip template on init. 9002 * @option
9003 * @example 'my-cool-tip-class' 9004 */ 9005 templateClasses: '', 9006 /** 9007 * Non-optional class added to tooltip templates. Foundation default is 'tooltip'. 9008 * @option 9009 * @example 'tooltip' 9010 */ 9011 tooltipClass: 'tooltip', 9012 /** 9013 * Class applied to the tooltip anchor element. 9014 * @option 9015 * @example 'has-tip' 9016 */ 9017 triggerClass: 'has-tip', 9018 /** 9019 * Minimum breakpoint size at which to open the tooltip. 9020 * @option 9021 * @example 'small' 9022 */ 9023 showOn: 'small', 9024 /** 9025 * Custom template to be used to generate markup for tooltip. 9026 * @option 9027 * @example '<div class="tooltip"></div>' 9028 */ 9029 template: '', 9030 /** 9031 * Text displayed in the tooltip template on open. 9032 * @option 9033 * @example 'Some cool space fact here.' 9034 */ 9035 tipText: '', 9036 touchCloseText: 'Tap to close.', 9037 /** 9038 * Allows the tooltip to remain open if triggered with a click or touch event. 9039 * @option 9040 * @example true 9041 */ 9042 clickOpen: true, 9043 /** 9044 * Additional positioning classes, set by the JS 9045 * @option 9046 * @example 'top' 9047 */ 9048 positionClass: '', 9049 /** 9050 * Distance, in pixels, the template should push away from the anch
9050or on the Y axis. 9051 * @option 9052 * @example 10 9053 */ 9054 vOffset: 10, 9055 /** 9056 * Distance, in pixels, the template should push away from the anchor on the X axis, if aligned to a side. 9057 * @option 9058 * @example 12 9059 */ 9060 hOffset: 12 9061 }; 9062 9063 /** 9064 * TODO utilize resize event trigger 9065 */ 9066 9067 // Window exports 9068 Foundation.plugin(Tooltip, 'Tooltip'); 9069}(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.