1/* 2 * Foundation Responsive Library 3 * http://foundation.zurb.com 4 * Copyright 2014, ZURB 5 * Free to use under the MIT license. 6 * http://www.opensource.org/licenses/mit-license.php 7*/ 8 9(function ($, window, document, undefined) { 10 'use strict'; 11 12 var header_helpers = function (class_array) { 13 var i = class_array.length; 14 var head = $('head'); 15 16 while (i--) { 17 if (head.has('.' + class_array[i]).length === 0) { 18 head.append('<meta class="' + class_array[i] + '" />'); 19 } 20 } 21 }; 22 23 header_helpers([ 24 'foundation-mq-small', 25 'foundation-mq-small-only', 26 'foundation-mq-medium', 27 'foundation-mq-medium-only', 28 'foundation-mq-large', 29 'foundation-mq-large-only', 30 'foundation-mq-xlarge', 31 'foundation-mq-xlarge-only', 32 'foundation-mq-xxlarge', 33 'foundation-data-attribute-namespace']); 34 35 // Enable FastClick if present 36 37 $(function () { 38 if (typeof FastClick !== 'undefined') { 39 // Don't attach to body if undefined 40 if (typeof document.body !== 'undefined') { 41 FastClick.attach(document.body); 42 } 43 } 44 }); 45 46 // private Fast Selector wrapper, 47 // returns jQuery object. Only use where 48 // getElementById is not available. 49 var S = function (selector, context) { 50 if (typeof selector === 'string') { 51 if (context) { 52 var cont; 53 if (context.jquery) { 54 cont = context[0]; 55 if (!cont) { 56 return context; 57 } 58 } else { 59 cont = context; 60 } 61 return $(cont.querySelectorAll(selector)); 62 } 63 64 return $(document.querySelectorAll(selector)); 65 } 66 67 return $(selector, context); 68 }; 69 70 // Namespace functions. 71 72 var attr_name = function (init) { 73 var arr = []; 74 if (!init) { 75 arr.push('data'); 76 } 77 if (this.namespace.length > 0) { 78 arr.push(this.namespace); 79 } 80 arr.push(this.name); 81 82 return arr.join('-'); 83 }; 84 85 var add_namespace = function (str) { 86 var parts = str.split('-'), 87 i = parts.length, 88 arr = []; 89 90 while (i--) { 91 if (i !== 0) { 92 arr.push(parts[i]); 93 } else { 94 if (this.namespace.length > 0) { 95 arr.push(this.namespace, parts[i]); 96 } else { 97 arr.push(parts[i]); 98 } 99 } 100 } 101 102 return arr.reverse().join('-'); 103 }; 104 105 // Event binding and data-options updating. 106 107 var bindings = function (method, options) { 108 var self = this, 109 bind = function(){ 110 var $this = S(this), 111 should_bind_events = !$this.data(self.attr_name(true) + '-init'); 112 $this.data(self.attr_name(true) + '-init', $.extend({}, self.settings, (options || method), self.data_options($this))); 113 114 if (should_bind_events) { 115 self.events(this); 116 } 117 }; 118 119 if (S(this.scope).is('[' + this.attr_name() +']')) { 120 bind.call(this.scope); 121 } else { 122 S('[' + this.attr_name() +']', this.scope).each(bind); 123 } 124 // # Patch to fix #5043 to move this *after* the if/else clause in order for Backbone and similar frameworks to have improved control over event binding and data-options updating. 125 if (typeof method === 'string') { 126 return this[method].call(this, options); 127 } 128 129 }; 130 131 var single_image_loaded = function (image, callback) { 132 function loaded () { 133 callback(image[0]); 134 } 135 136 function bindLoad () { 137 this.one('load', loaded); 138 139 if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { 140 var src = this.attr( 'src' ), 141 param = src.match( /\?/ ) ? '&' : '?'; 142 143 param += 'random=' + (new Date()).getTime(); 144 this.attr('src', src + param); 145 } 146 } 147 148 if (!image.attr('src')) { 149 loaded(); 150 return; 151 } 152 153 if (image[0].complete || image[0].readyState === 4) { 154 loaded(); 155 } else { 156 bindLoad.call(image); 157 } 158 }; 159 160 /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ 161 162 window.matchMedia || (window.matchMedia = function() { 163 "use strict"; 164 165 // For browsers that support matchMedium api such as IE 9 and webkit 166 var styleMedia = (window.styleMedia || window.media); 167 168 // For those that don't support matchMedium 169 if (!styleMedia) { 170 var style = document.createElement('style'), 171 script = document.getElementsByTagName('script')[0], 172 info = null; 173 174 style.type = 'text/css'; 175 style.id = 'matchmediajs-test'; 176 177 script.parentNode.insertBefore(style, script); 178 179 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers 180 info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; 181 182 styleMedia = { 183 matchMedium: function(media) { 184 var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; 185 186 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers 187 if (style.styleSheet) { 188 style.styleSheet.cssText = text; 189 } else { 190 style.textContent = text; 191 } 192 193 // Test if media query is true or false 194 return info.width === '1px'; 195 } 196 }; 197 } 198 199 return function(media) { 200 return { 201 matches: styleMedia.matchMedium(media || 'all'), 202 media: media || 'all' 203 }; 204 }; 205 }()); 206 207 /* 208 * jquery.requestAnimationFrame 209 * https://github.com/gnarf37/jquery-requestAnimationFrame 210 * Requires jQuery 1.8+ 211 * 212 * Copyright (c) 2012 Corey Frang 213 * Licensed under the MIT license. 214 */ 215 216 (function(jQuery) { 217 218 219 // requestAnimationFrame polyfill adapted from Erik Möller 220 // fixes from Paul Irish and Tino Zijdel 221 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 222 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 223 224 var animating, 225 lastTime = 0, 226 vendors = ['webkit', 'moz'], 227 requestAnimationFrame = window.requestAnimationFrame, 228 cancelAnimationFrame = window.cancelAnimationFrame, 229 jqueryFxAvailable = 'undefined' !== typeof jQuery.fx; 230 231 for (;
231 lastTime < vendors.length && !requestAnimationFrame; lastTime++) { 232 requestAnimationFrame = window[ vendors[lastTime] + 'RequestAnimationFrame' ]; 233 cancelAnimationFrame = cancelAnimationFrame || 234 window[ vendors[lastTime] + 'CancelAnimationFrame' ] || 235 window[ vendors[lastTime] + 'CancelRequestAnimationFrame' ]; 236 } 237 238 function raf() { 239 if (animating) { 240 requestAnimationFrame(raf); 241 242 if (jqueryFxAvailable) { 243 jQuery.fx.tick(); 244 } 245 } 246 } 247 248 if (requestAnimationFrame) { 249 // use rAF 250 window.requestAnimationFrame = requestAnimationFrame; 251 window.cancelAnimationFrame = cancelAnimationFrame; 252 253 if (jqueryFxAvailable) { 254 jQuery.fx.timer = function (timer) { 255 if (timer() && jQuery.timers.push(timer) && !animating) { 256 animating = true; 257 raf(); 258 } 259 }; 260 261 jQuery.fx.stop = function () { 262 animating = false; 263 }; 264 } 265 } else { 266 // polyfill 267 window.requestAnimationFrame = function (callback) { 268 var currTime = new Date().getTime(), 269 timeToCall = Math.max(0, 16 - (currTime - lastTime)), 270 id = window.setTimeout(function () { 271 callback(currTime + timeToCall); 272 }, timeToCall); 273 lastTime = currTime + timeToCall; 274 return id; 275 }; 276 277 window.cancelAnimationFrame = function (id) { 278 clearTimeout(id); 279 }; 280 281 } 282 283 }( $ )); 284 285 function removeQuotes (string) { 286 if (typeof string === 'string' || string instanceof String) { 287 string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, ''); 288 } 289 290 return string; 291 } 292 293 window.Foundation = { 294 name : 'Foundation', 295 296 version : '5.5.2', 297 298 media_queries : { 299 'small' : S('.foundation-mq-small').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 300 'small-only' : S('.foundation-mq-small-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 301 'medium' : S('.foundation-mq-medium').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 302 'medium-only' : S('.foundation-mq-medium-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
303 'large' : S('.foundation-mq-large').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 304 'large-only' : S('.foundation-mq-large-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 305 'xlarge' : S('.foundation-mq-xlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 306 'xlarge-only' : S('.foundation-mq-xlarge-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 307 'xxlarge' : S('.foundation-mq-xxlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, '') 308 }, 309 310 stylesheet : $('<style></style>').appendTo('head')[0].sheet, 311 312 global : { 313 namespace : undefined 314 }, 315 316 init : function (scope, libraries, method, options, response) { 317 var args = [scope, method, options, response], 318 responses = []; 319 320 // check RTL 321 this.rtl = /rtl/i.test(S('html').attr('dir')); 322 323 // set foundation global scope 324 this.scope = scope || this.scope; 325 326 this.set_namespace(); 327 328 if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) { 329 if (this.libs.hasOwnProperty(libraries)) { 330 responses.push(this.init_lib(libraries, args)); 331 } 332 } else { 333 for (var lib in this.libs) { 334 responses.push(this.init_lib(lib, libraries)); 335 } 336 } 337 338 S(window).load(function () { 339 S(window) 340 .trigger('resize.fndtn.clearing') 341 .trigger('resize.fndtn.dropdown') 342 .trigger('resize.fndtn.equalizer') 343 .trigger('resize.fndtn.interchange') 344 .trigger('resize.fndtn.joyride') 345 .trigger('resize.fndtn.magellan') 346 .trigger('resize.fndtn.topbar') 347 .trigger('resize.fndtn.slider'); 348 }); 349 350 return scope; 351 }, 352 353 init_lib : function (lib, args) { 354 if (this.libs.hasOwnProperty(lib)) { 355 this.patch(this.libs[lib]); 356 357 if (args && args.hasOwnProperty(lib)) { 358 if (typeof this.libs[lib].settings !== 'undefined') { 359 $.extend(true, this.libs[lib].settings, args[lib]); 360 } else if (typeof this.libs[lib].defaults !== 'undefined') { 361 $.extend(true, this.libs[lib].defaults, args[lib]); 362 } 363 return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]); 364 } 365 366 args = args instanceof Array ? args : new Array(args); 367 return this.libs[lib].init.apply(this.libs[lib], args); 368 } 369 370 return function () {}; 371 }, 372 373 patch : function (lib) { 374 lib.scope = this.scope; 375 lib.namespace = this.global.namespace; 376 lib.rtl = this.rtl; 377 lib['data_options'] = this.utils.data_options; 378 lib['attr_name'] = attr_name; 379 lib['add_namespace'] = add_namespace; 380 lib['bindings'] = bindings; 381 lib['S'] = this.utils.S; 382 }, 383 384 inherit : function (scope, methods) { 385 var methods_arr = methods.split(' '), 386 i = methods_arr.length; 387 388 while (i--) { 389 if (this.utils.hasOwnProperty(methods_arr[i])) { 390 scope[methods_arr[i]] = this.utils[methods_arr[i]]; 391 } 392 } 393 }, 394 395 set_namespace : function () { 396 397 // Description: 398 // Don't bother reading the namespace out of the meta tag 399 // if the namespace has been set globally in javascript 400 // 401 // Example: 402 // Foundation.global.namespace = 'my-namespace'; 403 // or make it an empty string: 404 // Foundation.global.namespace = ''; 405 // 406 // 407 408 // If the namespace has not been set (is undefined), try to read it out of the meta element. 409 // Otherwise use the globally defined namespace, even if it's empty ('') 410 var namespace = ( this.global.namespace === undefined ) ? $('.foundation-data-attribute-namespace').css('font-family') : this.global.namespace; 411 412 // Finally, if the namsepace is either undefined or false, set it to an empty string. 413 // Otherwise use the namespace value. 414 this.global.namespace = ( namespace === undefined || /false/i.test(namespace) ) ? '' : namespace; 415 }, 416 417 libs : {}, 418 419 // methods that can be inherited in libraries 420 utils : { 421 422 // Description: 423 // Fast Selector wrapper returns jQuery object. Only use where getElementById 424 // is not available. 425 // 426 // Arguments:
427 // Selector (String): CSS selector describing the element(s) to be 428 // returned as a jQuery object. 429 // 430 // Scope (String): CSS selector describing the area to be searched. Default 431 // is document. 432 // 433 // Returns: 434 // Element (jQuery Object): jQuery object containing elements matching the 435 // selector within the scope. 436 S : S, 437 438 // Description: 439 // Executes a function a max of once every n milliseconds 440 // 441 // Arguments: 442 // Func (Function): Function to be throttled. 443 // 444 // Delay (Integer): Function execution threshold in milliseconds. 445 // 446 // Returns: 447 // Lazy_function (Function): Function with throttling applied. 448 throttle : function (func, delay) { 449 var timer = null; 450 451 return function () { 452 var context = this, args = arguments; 453 454 if (timer == null) { 455 timer = setTimeout(function () { 456 func.apply(context, args); 457 timer = null; 458 }, delay); 459 } 460 }; 461 }, 462 463 // Description: 464 // Executes a function when it stops being invoked for n seconds 465 // Modified version of _.debounce() http://underscorejs.org 466 // 467 // Arguments: 468 // Func (Function): Function to be debounced. 469 // 470 // Delay (Integer): Function execution threshold in milliseconds. 471 // 472 // Immediate (Bool): Whether the function should be called at the beginning 473 // of the delay instead of the end. Default is false. 474 // 475 // Returns: 476 // Lazy_function (Function): Function with debouncing applied. 477 debounce : function (func, delay, immediate) { 478 var timeout, result; 479 return function () { 480 var context = this, args = arguments; 481 var later = function () { 482 timeout = null; 483 if (!immediate) { 484 result = func.apply(context, args); 485 } 486 }; 487 var callNow = immediate && !timeout; 488 clearTimeout(timeout); 489 timeout = setTimeout(later, delay); 490 if (callNow) { 491 result = func.apply(context, args); 492 } 493 return result; 494 }; 495 }, 496 497 // Description: 498 // Parses data-options attribute 499 // 500 // Arguments: 501 // El (jQuery Object): Element to be parsed. 502 // 503 // Returns: 504 // Options (Javascript Object): Contents of the element's data-options 505 // attribute. 506 data_options : function (el, data_attr_name) { 507 data_attr_name = data_attr_name || 'options'; 508 var opts = {}, ii, p, opts_arr, 509 data_options = function (el) { 510 var namespace = Foundation.global.namespace; 511 512 if (namespace.length > 0) { 513 return el.data(namespace + '-' + data_attr_name); 514 } 515 516 return el.data(data_attr_name); 517 }; 518 519 var cached_options = data_options(el); 520 521 if (typeof cached_options === 'object') { 522 return cached_options; 523 } 524 525 opts_arr = (cached_options || ':').split(';'); 526 ii = opts_arr.length; 527 528 function isNumber (o) { 529 return !isNaN (o - 0) && o !== null && o !== '' && o !== false && o !== true; 530 } 531 532 function trim (str) { 533 if (typeof str === 'string') { 534 return $.trim(str); 535 } 536 return str; 537 } 538 539 while (ii--) { 540 p = opts_arr[ii].split(':'); 541 p = [p[0], p.slice(1).join(':')]; 542 543 if (/true/i.test(p[1])) { 544 p[1] = true; 545 } 546 if (/false/i.test(p[1])) { 547 p[1] = false; 548 } 549 if (isNumber(p[1])) { 550 if (p[1].indexOf('.') === -1) { 551 p[1] = parseInt(p[1], 10); 552 } else { 553 p[1] = parseFloat(p[1]); 554 } 555 } 556 557 if (p.length === 2 && p[0].length > 0) { 558 opts[trim(p[0])] = trim(p[1]); 559 } 560 } 561 562 return opts; 563 }, 564 565 // Description: 566 // Adds JS-recognizable media queries 567 // 568 // Arguments: 569 // Media (String): Key string for the media query to be stored as in 570 // Foundation.media_queries 571 //
572 // Class (String): Class name for the generated <meta> tag 573 register_media : function (media, media_class) { 574 if (Foundation.media_queries[media] === undefined) { 575 $('head').append('<meta class="' + media_class + '"/>'); 576 Foundation.media_queries[media] = removeQuotes($('.' + media_class).css('font-family')); 577 } 578 }, 579 580 // Description: 581 // Add custom CSS within a JS-defined media query 582 // 583 // Arguments: 584 // Rule (String): CSS rule to be appended to the document. 585 // 586 // Media (String): Optional media query string for the CSS rule to be 587 // nested under. 588 add_custom_rule : function (rule, media) { 589 if (media === undefined && Foundation.stylesheet) { 590 Foundation.stylesheet.insertRule(rule, Foundation.stylesheet.cssRules.length); 591 } else { 592 var query = Foundation.media_queries[media]; 593 594 if (query !== undefined) { 595 Foundation.stylesheet.insertRule('@media ' + 596 Foundation.media_queries[media] + '{ ' + rule + ' }', Foundation.stylesheet.cssRules.length); 597 } 598 } 599 }, 600 601 // Description: 602 // Performs a callback function when an image is fully loaded 603 // 604 // Arguments: 605 // Image (jQuery Object): Image(s) to check if loaded. 606 // 607 // Callback (Function): Function to execute when image is fully loaded. 608 image_loaded : function (images, callback) { 609 var self = this, 610 unloaded = images.length; 611 612 function pictures_has_height(images) { 613 var pictures_number = images.length; 614 615 for (var i = pictures_number - 1; i >= 0; i--) { 616 if(images.attr('height') === undefined) { 617 return false; 618 }; 619 }; 620 621 return true; 622 } 623 624 if (unloaded === 0 || pictures_has_height(images)) { 625 callback(images); 626 } 627 628 images.each(function () { 629 single_image_loaded(self.S(this), function () { 630 unloaded -= 1; 631 if (unloaded === 0) { 632 callback(images); 633 } 634 }); 635 }); 636 }, 637 638 // Description: 639 // Returns a random, alphanumeric string 640 // 641 // Arguments: 642 // Length (Integer): Length of string to be generated. Defaults to random 643 // integer. 644 // 645 // Returns: 646 // Rand (String): Pseudo-random, alphanumeric string. 647 random_str : function () { 648 if (!this.fidx) { 649 this.fidx = 0; 650 } 651 this.prefix = this.prefix || [(this.name || 'F'), (+new Date).toString(36)].join('-'); 652 653 return this.prefix + (this.fidx++).toString(36); 654 }, 655 656 // Description: 657 // Helper for window.matchMedia 658 // 659 // Arguments: 660 // mq (String): Media query 661 // 662 // Returns: 663 // (Boolean): Whether the media query passes or not 664 match : function (mq) { 665 return window.matchMedia(mq).matches; 666 }, 667 668 // Description: 669 // Helpers for checking Foundation default media queries with JS 670 // 671 // Returns: 672 // (Boolean): Whether the media query passes or not 673 674 is_small_up : function () { 675 return this.match(Foundation.media_queries.small); 676 }, 677 678 is_medium_up : function () { 679 return this.match(Foundation.media_queries.medium); 680 }, 681 682 is_large_up : function () { 683 return this.match(Foundation.media_queries.large); 684 }, 685 686 is_xlarge_up : function () { 687 return this.match(Foundation.media_queries.xlarge); 688 }, 689 690 is_xxlarge_up : function () { 691 return this.match(Foundation.media_queries.xxlarge); 692 }, 693 694 is_small_only : function () { 695 return !this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up(); 696 }, 697 698 is_medium_only : function () { 699 return this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up(); 700 }, 701 702 is_large_only : function () { 703 return this.is_medium_up() && this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up(); 704 }, 705 706 is_xlarge_only : function () { 707 return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && !this.is_xxlarge_up(); 708 }, 709 710 is_xxlarge_only : function () { 711 return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && this.is_xxlarge_up(); 712 } 713 } 714 }; 715 716 $.fn.foundation = function () { 717 var args = Array.prototype.slice.call(arguments, 0); 718 719 return this.each(function () {
720 Foundation.init.apply(Foundation, [this].concat(args)); 721 return this; 722 }); 723 }; 724 725}(jQuery, window, window.document)); 726;(function ($, window, document, undefined) { 727 'use strict'; 728 729 Foundation.libs.abide = { 730 name : 'abide', 731 732 version : '5.5.2', 733 734 settings : { 735 live_validate : true, 736 validate_on_blur : true, 737 // validate_on: 'tab', // tab (when user tabs between fields), change (input changes), manual (call custom events) 738 focus_on_invalid : true, 739 error_labels : true, // labels with a for="inputId" will recieve an `error` class 740 error_class : 'error', 741 timeout : 1000, 742 patterns : { 743 alpha : /^[a-zA-Z]+$/, 744 alpha_numeric : /^[a-zA-Z0-9]+$/, 745 integer : /^[-+]?\d+$/, 746 number : /^[-+]?\d*(?:[\.\,]\d+)?$/, 747 748 // amex, visa, diners 749 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})$/, 750 cvv : /^([0-9]){3,4}$/, 751 752 // http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address 753 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])?)+$/,
754 755 // http://blogs.lse.ac.uk/lti/2008/04/23/a-regular-expression-to-match-any-url/ 756 url: /^(https?|ftp|file|ssh):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+~%\/\.\w]+)?\??([-\+=&;%@\.\w]+)?#?([\w]+)?)?/, 757 // abc.de 758 domain : /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,8}$/, 759 760 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))$/, 761 // YYYY-MM-DD 762 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))$/, 763 // HH:MM:SS 764 time : /^(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}$/, 765 dateISO : /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/, 766 // MM/DD/YYYY 767 month_day_year : /^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]\d{4}$/, 768 // DD/MM/YYYY 769 day_month_year : /^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]\d{4}$/, 770 771 // #FFF or #FFFFFF 772 color : /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/ 773 }, 774 validators : { 775 equalTo : function (el, required, parent) { 776 var from = document.getElementById(el.getAttribute(this.add_namespace('data-equalto'))).value, 777 to = el.value, 778 valid = (from === to); 779 780 return valid; 781 } 782 } 783 }, 784 785 timer : null, 786 787 init : function (scope, method, options) { 788 this.bindings(method, options); 789 }, 790 791 events : function (scope) { 792 var self = this, 793 form = self.S(scope).attr('novalidate', 'novalidate'), 794 settings = form.data(this.attr_name(true) + '-init') || {}; 795 796 this.invalid_attr = this.add_namespace('data-invalid'); 797 798 function validate(originalSelf, e) { 799 clearTimeout(self.timer); 800 self.timer = setTimeout(function () { 801 self.validate([originalSelf], e); 802 }.bind(originalSelf), settings.timeout); 803 } 804 805 806 form 807 .off('.abide') 808 .on('submit.fndtn.abide', function (e) { 809 var is_ajax = /ajax/i.test(self.S(this).attr(self.attr_name())); 810 return self.validate(self.S(this).find('input, textarea, select').not(":hidden, [data-abide-ignore]").get(), e, is_ajax); 811 }) 812 .on('validate.fndtn.abide', function (e) { 813 if (settings.validate_on === 'manual') { 814 self.validate([e.target], e); 815 } 816 }) 817 .on('reset', function (e) { 818 return self.reset($(this), e); 819 }) 820 .find('input, textarea, select').not(":hidden, [data-abide-ignore]") 821 .off('.abide') 822 .on('blur.fndtn.abide change.fndtn.abide', function (e) { 823 // old settings fallback 824 // will be deprecated with F6 release 825 if (settings.validate_on_blur && settings.validate_on_blur === true) { 826 validate(this, e); 827 } 828 // new settings combining validate options into one setting 829 if (settings.validate_on === 'change') { 830 validate(this, e); 831 } 832 }) 833 .on('keydown.fndtn.abide', function (e) { 834 // old settings fallback 835 // will be deprecated with F6 release 836 if (settings.live_validate && settings.live_validate === true && e.which != 9) { 837 validate(this, e); 838 } 839 // new settings combining validate options into one setting 840 if (settings.validate_on === 'tab' && e.which === 9) { 841 validate(this, e); 842 } 843 else if (settings.validate_on === 'change') { 844 validate(this, e); 845 } 846 }) 847 .on('focus', function (e) { 848 if (navigator.userAgent.match(/iPad|iPhone|Android|BlackBerry|Windows Phone|webOS/i)) { 849 $('html, body').animate({ 850 scrollTop: $(e.target).offset().top 851 }, 100); 852 } 853 }); 854 }, 855 856 reset : function (form, e) { 857 var self = this; 858 form.removeAttr(self.invalid_attr); 859 860 $('[' + self.invalid_attr + ']', form).removeAttr(self.invalid_attr); 861 $('.' + self.settings.error_class, form).not('small').removeClass(self.settings.error_class); 862 $(':input', form).not(':button, :submit, :reset, :hidden, [data-abide-ignore]').val('').removeAttr(self.invalid_attr); 863 }, 864 865 validate : function (els, e, is_ajax) {
866 var validations = this.parse_patterns(els), 867 validation_count = validations.length, 868 form = this.S(els[0]).closest('form'), 869 submit_event = /submit/.test(e.type); 870 871 // Has to count up to make sure the focus gets applied to the top error 872 for (var i = 0; i < validation_count; i++) { 873 if (!validations[i] && (submit_event || is_ajax)) { 874 if (this.settings.focus_on_invalid) { 875 els[i].focus(); 876 } 877 form.trigger('invalid.fndtn.abide'); 878 this.S(els[i]).closest('form').attr(this.invalid_attr, ''); 879 return false; 880 } 881 } 882 883 if (submit_event || is_ajax) { 884 form.trigger('valid.fndtn.abide'); 885 } 886 887 form.removeAttr(this.invalid_attr); 888 889 if (is_ajax) { 890 return false; 891 } 892 893 return true; 894 }, 895 896 parse_patterns : function (els) { 897 var i = els.length, 898 el_patterns = []; 899 900 while (i--) { 901 el_patterns.push(this.pattern(els[i])); 902 } 903 904 return this.check_validation_and_apply_styles(el_patterns); 905 }, 906 907 pattern : function (el) { 908 var type = el.getAttribute('type'), 909 required = typeof el.getAttribute('required') === 'string'; 910 911 var pattern = el.getAttribute('pattern') || ''; 912 913 if (this.settings.patterns.hasOwnProperty(pattern) && pattern.length > 0) { 914 return [el, this.settings.patterns[pattern], required]; 915 } else if (pattern.length > 0) { 916 return [el, new RegExp(pattern), required]; 917 } 918 919 if (this.settings.patterns.hasOwnProperty(type)) { 920 return [el, this.settings.patterns[type], required]; 921 } 922 923 pattern = /.*/; 924 925 return [el, pattern, required]; 926 }, 927 928 // TODO: Break this up into smaller methods, getting hard to read. 929 check_validation_and_apply_styles : function (el_patterns) { 930 var i = el_patterns.length, 931 validations = [], 932 form = this.S(el_patterns[0][0]).closest('[data-' + this.attr_name(true) + ']'), 933 settings = form.data(this.attr_name(true) + '-init') || {}; 934 while (i--) { 935 var el = el_patterns[i][0], 936 required = el_patterns[i][2], 937 value = el.value.trim(), 938 direct_parent = this.S(el).parent(), 939 validator = el.getAttribute(this.add_namespace('data-abide-validator')), 940 is_radio = el.type === 'radio', 941 is_checkbox = el.type === 'checkbox', 942 label = this.S('label[for="' + el.getAttribute('id') + '"]'), 943 valid_length = (required) ? (el.value.length > 0) : true, 944 el_validations = []; 945 946 var parent, valid; 947 948 // support old way to do equalTo validations 949 if (el.getAttribute(this.add_namespace('data-equalto'))) { validator = 'equalTo' } 950 951 if (!direct_parent.is('label')) { 952 parent = direct_parent; 953 } else { 954 parent = direct_parent.parent(); 955 } 956 957 if (is_radio && required) { 958 el_validations.push(this.valid_radio(el, required)); 959 } else if (is_checkbox && required) { 960 el_validations.push(this.valid_checkbox(el, required)); 961 962 } else if (validator) { 963 // Validate using each of the specified (space-delimited) validators. 964 var validators = validator.split(' '); 965 var last_valid = true, all_valid = true; 966 for (var iv = 0; iv < validators.length; iv++) { 967 valid = this.settings.validators[validators[iv]].apply(this, [el, required, parent]) 968 el_validations.push(valid); 969 all_valid = valid && last_valid; 970 last_valid = valid; 971 } 972 if (all_valid) { 973 this.S(el).removeAttr(this.invalid_attr); 974 parent.removeClass('error'); 975 if (label.length > 0 && this.settings.error_labels) { 976 label.removeClass(this.settings.error_class).removeAttr('role'); 977 } 978 $(el).triggerHandler('valid'); 979 } else { 980 this.S(el).attr(this.invalid_attr, ''); 981 parent.addClass('error'); 982 if (label.length > 0 && this.settings.error_labels) { 983 label.addClass(this.settings.error_class).attr('role', 'alert'); 984 } 985 $(el).triggerHandler('invalid'); 986 } 987 } else { 988 989 if (el_patterns[i][1].test(value) && valid_length || 990 !required && el.value.length < 1 || $(el).attr('disabled')) { 991 el_validations.push(true); 992 } else { 993 el_validations.push(false); 994 } 995 996 el_validations = [el_validations.every(function (valid) {return valid;})]; 997 if (el_validations[0]) { 998 this.S(el).removeAttr(this.invalid_attr); 999 el.setAttribute('aria-invalid', 'false'); 1000 el.removeAttribute('aria-describedby'); 1001 parent.removeClass(this.settings.error_class); 1002 if (label.length > 0 && this.settings.error_labels) { 1003 label.removeClass(this.settings.error_class).removeAttr('role'); 1004 } 1005 $(el).triggerHandler('valid'); 1006 } else { 1007 this.S(el).attr(this.invalid_attr, ''); 1008 el.setAttribute('aria-invalid', 'true'); 1009 1010 // Try to find the error associated with the input 1011 var errorElem = parent.find('small.' + this.settings.error_class, 'span.' + this.settings.error_class); 1012 var errorID = errorElem.length > 0 ? errorElem[0].id : ''; 1013 if (errorID.length > 0) { 1014 el.setAttribute('aria-describedby', errorID); 1015 } 1016 1017 // el.setAttribute('aria-describedby', $(el).find('.error')[0].id); 1018 parent.addClass(this.settings.error_class); 1019 if (label.length > 0 && this.settings.error_labels) { 1020 label.addClass(this.settings.error_class).attr('role', 'alert'); 1021 } 1022 $(el).triggerHandler('invalid'); 1023 } 1024 } 1025 validations = validations.concat(el_validations); 1026 } 1027 return validations; 1028 }, 1029 1030 valid_checkbox : function (el, required) { 1031 var el = this.S(el), 1032 valid = (el.is(':checked') || !required || el.get(0).getAttribute('disabled')); 1033 1034 if (valid) { 1035 el.removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class); 1036 $(el).triggerHandler('valid'); 1037 } else { 1038 el.attr(this.invalid_attr, '').parent().addClass(this.settings.error_class); 1039 $(el).triggerHandler('invalid'); 1040 } 1041 1042 return valid; 1043 }, 1044 1045 valid_radio : function (el, required) { 1046 var name = el.getAttribute('name'), 1047 group = this.S(el).closest('[data-' + this.attr_name(true) + ']').find("[name='" + name + "']"), 1048 count = group.length, 1049 valid = false, 1050 disabled = false;
1051 1052 // Has to count up to make sure the focus gets applied to the top error 1053 for (var i=0; i < count; i++) { 1054 if( group[i].getAttribute('disabled') ){ 1055 disabled=true; 1056 valid=true; 1057 } else { 1058 if (group[i].checked){ 1059 valid = true; 1060 } else { 1061 if( disabled ){ 1062 valid = false; 1063 } 1064 } 1065 } 1066 } 1067 1068 // Has to count up to make sure the focus gets applied to the top error 1069 for (var i = 0; i < count; i++) { 1070 if (valid) { 1071 this.S(group[i]).removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class); 1072 $(group[i]).triggerHandler('valid'); 1073 } else { 1074 this.S(group[i]).attr(this.invalid_attr, '').parent().addClass(this.settings.error_class); 1075 $(group[i]).triggerHandler('invalid'); 1076 } 1077 } 1078 1079 return valid; 1080 }, 1081 1082 valid_equal : function (el, required, parent) { 1083 var from = document.getElementById(el.getAttribute(this.add_namespace('data-equalto'))).value, 1084 to = el.value, 1085 valid = (from === to); 1086 1087 if (valid) { 1088 this.S(el).removeAttr(this.invalid_attr); 1089 parent.removeClass(this.settings.error_class); 1090 if (label.length > 0 && settings.error_labels) { 1091 label.removeClass(this.settings.error_class); 1092 } 1093 } else { 1094 this.S(el).attr(this.invalid_attr, ''); 1095 parent.addClass(this.settings.error_class); 1096 if (label.length > 0 && settings.error_labels) { 1097 label.addClass(this.settings.error_class); 1098 } 1099 } 1100 1101 return valid; 1102 }, 1103 1104 valid_oneof : function (el, required, parent, doNotValidateOthers) { 1105 var el = this.S(el), 1106 others = this.S('[' + this.add_namespace('data-oneof') + ']'), 1107 valid = others.filter(':checked').length > 0; 1108 1109 if (valid) { 1110 el.removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class); 1111 } else { 1112 el.attr(this.invalid_attr, '').parent().addClass(this.settings.error_class); 1113 } 1114 1115 if (!doNotValidateOthers) { 1116 var _this = this; 1117 others.each(function () { 1118 _this.valid_oneof.call(_this, this, null, null, true); 1119 }); 1120 } 1121 1122 return valid; 1123 }, 1124 1125 reflow : function(scope, options) { 1126 var self = this, 1127 form = self.S('[' + this.attr_name() + ']').attr('novalidate', 'novalidate'); 1128 self.S(form).each(function (idx, el) { 1129 self.events(el); 1130 }); 1131 } 1132 }; 1133}(jQuery, window, window.document)); 1134;(function ($, window, document, undefined) { 1135 'use strict'; 1136 1137 Foundation.libs.dropdown = { 1138 name : 'dropdown', 1139 1140 version : '5.5.2', 1141 1142 settings : { 1143 active_class : 'open', 1144 disabled_class : 'disabled', 1145 mega_class : 'mega', 1146 align : 'bottom', 1147 is_hover : false, 1148 hover_timeout : 150, 1149 opened : function () {}, 1150 closed : function () {} 1151 }, 1152 1153 init : function (scope, method, options) { 1154 Foundation.inherit(this, 'throttle'); 1155 1156 $.extend(true, this.settings, method, options); 1157 this.bindings(method, options); 1158 }, 1159 1160 events : function (scope) { 1161 var self = this, 1162 S = self.S; 1163 1164 S(this.scope) 1165 .off('.dropdown') 1166 .on('click.fndtn.dropdown', '[' + this.attr_name() + ']', function (e) { 1167 var settings = S(this).data(self.attr_name(true) + '-init') || self.settings; 1168 if (!settings.is_hover || Modernizr.touch) { 1169 e.preventDefault(); 1170 if (S(this).parent('[data-reveal-id]').length) { 1171 e.stopPropagation(); 1172 } 1173 self.toggle($(this)); 1174 } 1175 }) 1176 .on('mouseenter.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) { 1177 var $this = S(this), 1178 dropdown, 1179 target; 1180 1181 clearTimeout(self.timeout); 1182 1183 if ($this.data(self.data_attr())) { 1184 dropdown = S('#' + $this.data(self.data_attr())); 1185 target = $this; 1186 } else { 1187 dropdown = $this; 1188 target = S('[' + self.attr_name() + '="' + dropdown.attr('id') + '"]'); 1189 } 1190 1191 var settings = target.data(self.attr_name(true) + '-init') || self.settings; 1192 1193 if (S(e.currentTarget).data(self.data_attr()) && settings.is_hover) { 1194 self.closeall.call(self); 1195 } 1196 1197 if (settings.is_hover) { 1198 self.open.apply(self, [dropdown, target]); 1199 } 1200 }) 1201 .on('mouseleave.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) { 1202 var $this = S(this); 1203 var settings; 1204 1205 if ($this.data(self.data_attr())) { 1206 settings = $this.data(self.data_attr(true) + '-init') || self.settings; 1207 } else { 1208 var target = S('[' + self.attr_name() + '="' + S(this).attr('id') + '"]'), 1209 settings = target.data(self.attr_name(true) + '-init') || self.settings; 1210 } 1211 1212 self.timeout = setTimeout(function () { 1213 if ($this.data(self.data_attr())) { 1214 if (settings.is_hover) { 1215 self.close.call(self, S('#' + $this.data(self.data_attr()))); 1216 } 1217 } else { 1218 if (settings.is_hover) { 1219 self.close.call(self, $this); 1220 } 1221 } 1222 }.bind(this), settings.hover_timeout); 1223 }) 1224 .on('click.fndtn.dropdown', function (e) { 1225 var parent = S(e.target).closest('[' + self.attr_name() + '-content]'); 1226 var links = parent.find('a'); 1227 1228 if (links.length > 0 && parent.attr('aria-autoclose') !== 'false') { 1229 self.close.call(self, S('[' + self.attr_name() + '-content]')); 1230 } 1231 1232 if (e.target !== document && !$.contains(document.documentElement, e.target)) { 1233 return; 1234 } 1235 1236 if (S(e.target).closest('[' + self.attr_name() + ']').length > 0) { 1237 return; 1238 } 1239 1240 if (!(S(e.target).data('revealId')) && 1241 (parent.length > 0 && (S(e.target).is('[' + self.attr_name() + '-content]') || 1242 $.contains(parent.first()[0], e.target)))) { 1243 e.stopPropagation(); 1244 return; 1245 } 1246 1247 self.close.call(self, S('[' + self.attr_name() + '-content]')); 1248 }) 1249 .on('opened.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () {
1250 self.settings.opened.call(this); 1251 }) 1252 .on('closed.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () { 1253 self.settings.closed.call(this); 1254 }); 1255 1256 S(window) 1257 .off('.dropdown') 1258 .on('resize.fndtn.dropdown', self.throttle(function () { 1259 self.resize.call(self); 1260 }, 50)); 1261 1262 this.resize(); 1263 }, 1264 1265 close : function (dropdown) { 1266 var self = this; 1267 dropdown.each(function (idx) { 1268 var original_target = $('[' + self.attr_name() + '=' + dropdown[idx].id + ']') || $('aria-controls=' + dropdown[idx].id + ']'); 1269 original_target.attr('aria-expanded', 'false'); 1270 if (self.S(this).hasClass(self.settings.active_class)) { 1271 self.S(this) 1272 .css(Foundation.rtl ? 'right' : 'left', '-99999px') 1273 .attr('aria-hidden', 'true') 1274 .removeClass(self.settings.active_class) 1275 .prev('[' + self.attr_name() + ']') 1276 .removeClass(self.settings.active_class) 1277 .removeData('target'); 1278 1279 self.S(this).trigger('closed.fndtn.dropdown', [dropdown]); 1280 } 1281 }); 1282 dropdown.removeClass('f-open-' + this.attr_name(true)); 1283 }, 1284 1285 closeall : function () { 1286 var self = this; 1287 $.each(self.S('.f-open-' + this.attr_name(true)), function () { 1288 self.close.call(self, self.S(this)); 1289 }); 1290 }, 1291 1292 open : function (dropdown, target) { 1293 this 1294 .css(dropdown 1295 .addClass(this.settings.active_class), target); 1296 dropdown.prev('[' + this.attr_name() + ']').addClass(this.settings.active_class); 1297 dropdown.data('target', target.get(0)).trigger('opened.fndtn.dropdown', [dropdown, target]); 1298 dropdown.attr('aria-hidden', 'false'); 1299 target.attr('aria-expanded', 'true'); 1300 dropdown.focus(); 1301 dropdown.addClass('f-open-' + this.attr_name(true)); 1302 }, 1303 1304 data_attr : function () { 1305 if (this.namespace.length > 0) { 1306 return this.namespace + '-' + this.name; 1307 } 1308 1309 return this.name; 1310 }, 1311 1312 toggle : function (target) { 1313 if (target.hasClass(this.settings.disabled_class)) { 1314 return; 1315 } 1316 var dropdown = this.S('#' + target.data(this.data_attr())); 1317 if (dropdown.length === 0) { 1318 // No dropdown found, not continuing 1319 return; 1320 } 1321 1322 this.close.call(this, this.S('[' + this.attr_name() + '-content]').not(dropdown)); 1323 1324 if (dropdown.hasClass(this.settings.active_class)) { 1325 this.close.call(this, dropdown); 1326 if (dropdown.data('target') !== target.get(0)) { 1327 this.open.call(this, dropdown, target); 1328 } 1329 } else { 1330 this.open.call(this, dropdown, target); 1331 } 1332 }, 1333 1334 resize : function () { 1335 var dropdown = this.S('[' + this.attr_name() + '-content].open'); 1336 var target = $(dropdown.data("target")); 1337 1338 if (dropdown.length && target.length) { 1339 this.css(dropdown, target); 1340 } 1341 }, 1342 1343 css : function (dropdown, target) { 1344 var left_offset = Math.max((target.width() - dropdown.width()) / 2, 8), 1345 settings = target.data(this.attr_name(true) + '-init') || this.settings, 1346 parentOverflow = dropdown.parent().css('overflow-y') || dropdown.parent().css('overflow'); 1347 1348 this.clear_idx(); 1349 1350 1351 1352 if (this.small()) { 1353 var p = this.dirs.bottom.call(dropdown, target, settings); 1354 1355 dropdown.attr('style', '').removeClass('drop-left drop-right drop-top').css({ 1356 position : 'absolute', 1357 width : '95%', 1358 'max-width' : 'none', 1359 top : p.top 1360 }); 1361 1362 dropdown.css(Foundation.rtl ? 'right' : 'left', left_offset); 1363 } 1364 // detect if dropdown is in an overflow container 1365 else if (parentOverflow !== 'visible') { 1366 var offset = target[0].offsetTop + target[0].offsetHeight; 1367 1368 dropdown.attr('style', '').css({ 1369 position : 'absolute', 1370 top : offset 1371 }); 1372 1373 dropdown.css(Foundation.rtl ? 'right' : 'left', left_offset); 1374 } 1375 else { 1376 1377 this.style(dropdown, target, settings); 1378 } 1379 1380 return dropdown; 1381 }, 1382 1383 style : function (dropdown, target, settings) { 1384 var css = $.extend({position : 'absolute'}, 1385 this.dirs[settings.align].call(dropdown, target, settings)); 1386 1387 dropdown.attr('style', '').css(css); 1388 }, 1389 1390 // return CSS property object 1391 // `this` is the dropdown 1392 dirs : { 1393 // Calculate target offset 1394 _base : function (t) { 1395 var o_p = this.offsetParent(), 1396 o = o_p.offset(), 1397 p = t.offset(); 1398 1399 p.top -= o.top; 1400 p.left -= o.left; 1401 1402 //set some flags on the p object to pass along 1403 p.missRight = false;
1404 p.missTop = false; 1405 p.missLeft = false; 1406 p.leftRightFlag = false; 1407 1408 //lets see if the panel will be off the screen 1409 //get the actual width of the page and store it 1410 var actualBodyWidth; 1411 if (document.getElementsByClassName('row')[0]) { 1412 actualBodyWidth = document.getElementsByClassName('row')[0].clientWidth; 1413 } else { 1414 actualBodyWidth = window.innerWidth; 1415 } 1416 1417 var actualMarginWidth = (window.innerWidth - actualBodyWidth) / 2; 1418 var actualBoundary = actualBodyWidth; 1419 1420 if (!this.hasClass('mega')) { 1421 //miss top 1422 if (t.offset().top <= this.outerHeight()) { 1423 p.missTop = true; 1424 actualBoundary = window.innerWidth - actualMarginWidth; 1425 p.leftRightFlag = true; 1426 } 1427 1428 //miss right 1429 if (t.offset().left + this.outerWidth() > t.offset().left + actualMarginWidth && t.offset().left - actualMarginWidth > this.outerWidth()) { 1430 p.missRight = true; 1431 p.missLeft = false; 1432 } 1433 1434 //miss left 1435 if (t.offset().left - this.outerWidth() <= 0) { 1436 p.missLeft = true; 1437 p.missRight = false; 1438 } 1439 } 1440 1441 return p; 1442 }, 1443 1444 top : function (t, s) { 1445 var self = Foundation.libs.dropdown, 1446 p = self.dirs._base.call(this, t); 1447 1448 this.addClass('drop-top'); 1449 1450 if (p.missTop == true) { 1451 p.top = p.top + t.outerHeight() + this.outerHeight(); 1452 this.removeClass('drop-top'); 1453 } 1454 1455 if (p.missRight == true) { 1456 p.left = p.left - this.outerWidth() + t.outerWidth(); 1457 } 1458 1459 if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) { 1460 self.adjust_pip(this, t, s, p); 1461 } 1462 1463 if (Foundation.rtl) { 1464 return {left : p.left - this.outerWidth() + t.outerWidth(), 1465 top : p.top - this.outerHeight()}; 1466 } 1467 1468 return {left : p.left, top : p.top - this.outerHeight()}; 1469 }, 1470 1471 bottom : function (t, s) { 1472 var self = Foundation.libs.dropdown, 1473 p = self.dirs._base.call(this, t); 1474 1475 if (p.missRight == true) { 1476 p.left = p.left - this.outerWidth() + t.outerWidth(); 1477 } 1478 1479 if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) { 1480 self.adjust_pip(this, t, s, p); 1481 } 1482 1483 if (self.rtl) { 1484 return {left : p.left - this.outerWidth() + t.outerWidth(), top : p.top + t.outerHeight()}; 1485 } 1486 1487 return {left : p.left, top : p.top + t.outerHeight()}; 1488 }, 1489 1490 left : function (t, s) { 1491 var p = Foundation.libs.dropdown.dirs._base.call(this, t); 1492 1493 this.addClass('drop-left'); 1494 1495 if (p.missLeft == true) { 1496 p.left = p.left + this.outerWidth(); 1497 p.top = p.top + t.outerHeight(); 1498 this.removeClass('drop-left'); 1499 } 1500 1501 return {left : p.left - this.outerWidth(), top : p.top}; 1502 }, 1503 1504 right : function (t, s) { 1505 var p = Foundation.libs.dropdown.dirs._base.call(this, t); 1506 1507 this.addClass('drop-right'); 1508 1509 if (p.missRight == true) { 1510 p.left = p.left - this.outerWidth(); 1511 p.top = p.top + t.outerHeight(); 1512 this.removeClass('drop-right'); 1513 } else { 1514 p.triggeredRight = true; 1515 } 1516 1517 var self = Foundation.libs.dropdown; 1518 1519 if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) { 1520 self.adjust_pip(this, t, s, p); 1521 } 1522 1523 return {left : p.left + t.outerWidth(), top : p.top}; 1524 } 1525 }, 1526 1527 // Insert rule to style psuedo elements 1528 adjust_pip : function (dropdown, target, settings, position) { 1529 var sheet = Foundation.stylesheet, 1530 pip_offset_base = 8; 1531 1532 if (dropdown.hasClass(settings.mega_class)) { 1533 pip_offset_base = position.left + (target.outerWidth() / 2) - 8; 1534 } else if (this.small()) { 1535 pip_offset_base += position.left - 8; 1536 } 1537 1538 this.rule_idx = sheet.cssRules.length; 1539 1540 //default 1541 var sel_before = '.f-dropdown.open:before', 1542 sel_after = '.f-dropdown.open:after', 1543 css_before = 'left: ' + pip_offset_base + 'px;', 1544 css_after = 'left: ' + (pip_offset_base - 1) + 'px;'; 1545 1546 if (position.missRight == true) { 1547 pip_offset_base = dropdown.outerWidth() - 23; 1548 sel_before = '.f-dropdown.open:before', 1549 sel_after = '.f-dropdown.open:after', 1550 css_before = 'left: ' + pip_offset_base + 'px;', 1551 css_after = 'left: ' + (pip_offset_base - 1) + 'px;'; 1552 } 1553 1554 //just a case where right is fired, but its not missing right 1555 if (position.triggeredRight == true) { 1556 sel_before = '.f-dropdown.open:before', 1557 sel_after = '.f-dropdown.open:after', 1558 css_before = 'left:-12px;', 1559 css_after = 'left:-14px;'; 1560 } 1561 1562 if (sheet.insertRule) { 1563 sheet.insertRule([sel_before, '{', css_before, '}'].join(' '), this.rule_idx); 1564 sheet.insertRule([sel_after, '{', css_after, '}'].join(' '), this.rule_idx + 1); 1565 } else { 1566 sheet.addRule(sel_before, css_before, this.rule_idx); 1567 sheet.addRule(sel_after, css_after, this.rule_idx + 1); 1568 } 1569 }, 1570 1571 // Remove old dropdown rule index 1572 clear_idx : function () { 1573 var sheet = Foundation.stylesheet; 1574 1575 if (typeof this.rule_idx !== 'undefined') { 1576 sheet.deleteRule(this.rule_idx); 1577 sheet.deleteRule(this.rule_idx); 1578 delete this.rule_idx; 1579 } 1580 }, 1581 1582 small : function () { 1583 return matchMedia(Foundation.media_queries.small).matches && 1584 !matchMedia(Foundation.media_queries.medium).matches; 1585 }, 1586 1587 off : function () { 1588 this.S(this.scope).off('.fndtn.dropdown'); 1589 this.S('html, body').off('.fndtn.dropdown'); 1590 this.S(window).off('.fndtn.dropdown'); 1591 this.S('[data-dropdown-content]').off('.fndtn.dropdown'); 1592 }, 1593 1594 reflow : function () {} 1595 }; 1596}(jQuery, window, window.document)); 1597;(function ($, window, document, undefined) { 1598 'use strict'; 1599 1600 Foundation.libs.alert = { 1601 name : 'alert', 1602 1603 version : '5.5.2', 1604 1605 settings : { 1606 callback : function () {} 1607 }, 1608 1609 init : function (scope, method, options) { 1610 this.bindings(method, options); 1611 }, 1612 1613 events : function () { 1614 var self = this, 1615 S = this.S; 1616 1617 $(this.scope).off('.alert').on('click.fndtn.alert', '[' + this.attr_name() + '] .close', function (e) { 1618 var alertBox = S(this).closest('[' + self.attr_name() + ']'), 1619 settings = alertBox.data(self.attr_name(true) + '-init') || self.settings; 1620 1621 e.preventDefault(); 1622 if (Modernizr.csstransitions) { 1623 alertBox.addClass('alert-close'); 1624 alertBox.on('transitionend webkitTransitionEnd oTransitionEnd', function (e) { 1625 S(this).trigger('close.fndtn.alert').remove(); 1626 settings.callback(); 1627 }); 1628 } else { 1629 alertBox.fadeOut(300, function () { 1630 S(this).trigger('close.fndtn.alert').remove(); 1631 settings.callback(); 1632 }); 1633 } 1634 }); 1635 }, 1636 1637 reflow : function () {} 1638 }; 1639}(jQuery, window, window.document)); 1640;(function ($, window, document, undefined) { 1641 'use strict'; 1642 1643 Foundation.libs.clearing = { 1644 name : 'clearing', 1645 1646 version : '5.5.2', 1647 1648 settings : { 1649 templates : { 1650 viewing : '<a href="#" class="clearing-close">×</a>' + 1651 '<div class="visible-img" style="display: none"><div class="clearing-touch-label"></div><img src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" />' + 1652 '<p class="clearing-caption"></p><a href="#" class="clearing-main-prev"><span></span></a>' + 1653 '<a href="#" class="clearing-main-next"><span></span></a></div>' + 1654 '<img class="clearing-preload-next" style="display: none" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" />' + 1655 '<img class="clearing-preload-prev" style="display: none" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" />' 1656 }, 1657 1658 // comma delimited list of selectors that, on click, will close clearing, 1659 // add 'div.clearing-blackout, div.visible-img' to close on background click 1660 close_selectors : '.clearing-close, div.clearing-blackout', 1661 1662 // Default to the entire li element. 1663 open_selectors : '', 1664 1665 // Image will be skipped in carousel. 1666 skip_selector : '', 1667 1668 touch_label : '', 1669
1670 // event initializers and locks 1671 init : false, 1672 locked : false 1673 }, 1674 1675 init : function (scope, method, options) { 1676 var self = this; 1677 Foundation.inherit(this, 'throttle image_loaded'); 1678 1679 this.bindings(method, options); 1680 1681 if (self.S(this.scope).is('[' + this.attr_name() + ']')) { 1682 this.assemble(self.S('li', this.scope)); 1683 } else { 1684 self.S('[' + this.attr_name() + ']', this.scope).each(function () { 1685 self.assemble(self.S('li', this)); 1686 }); 1687 } 1688 }, 1689 1690 events : function (scope) { 1691 var self = this, 1692 S = self.S, 1693 $scroll_container = $('.scroll-container'); 1694 1695 if ($scroll_container.length > 0) { 1696 this.scope = $scroll_container; 1697 } 1698 1699 S(this.scope) 1700 .off('.clearing') 1701 .on('click.fndtn.clearing', 'ul[' + this.attr_name() + '] li ' + this.settings.open_selectors, 1702 function (e, current, target) { 1703 var current = current || S(this), 1704 target = target || current, 1705 next = current.next('li'), 1706 settings = current.closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'), 1707 image = S(e.target); 1708 1709 e.preventDefault(); 1710 1711 if (!settings) { 1712 self.init(); 1713 settings = current.closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'); 1714 } 1715 1716 // if clearing is open and the current image is 1717 // clicked, go to the next image in sequence 1718 if (target.hasClass('visible') && 1719 current[0] === target[0] && 1720 next.length > 0 && self.is_open(current)) { 1721 target = next; 1722 image = S('img', target); 1723 } 1724 1725 // set current and target to the clicked li if not otherwise defined. 1726 self.open(image, current, target); 1727 self.update_paddles(target); 1728 }) 1729 1730 .on('click.fndtn.clearing', '.clearing-main-next', 1731 function (e) { self.nav(e, 'next') }) 1732 .on('click.fndtn.clearing', '.clearing-main-prev', 1733 function (e) { self.nav(e, 'prev') }) 1734 .on('click.fndtn.clearing', this.settings.close_selectors, 1735 function (e) { Foundation.libs.clearing.close(e, this) }); 1736 1737 $(document).on('keydown.fndtn.clearing', 1738 function (e) { self.keydown(e) }); 1739 1740 S(window).off('.clearing').on('resize.fndtn.clearing', 1741 function () { self.resize() }); 1742 1743 this.swipe_events(scope); 1744 }, 1745 1746 swipe_events : function (scope) { 1747 var self = this, 1748 S = self.S; 1749 1750 S(this.scope) 1751 .on('touchstart.fndtn.clearing', '.visible-img', function (e) { 1752 if (!e.touches) { e = e.originalEvent; } 1753 var data = { 1754 start_page_x : e.touches[0].pageX, 1755 start_page_y : e.touches[0].pageY, 1756 start_time : (new Date()).getTime(), 1757 delta_x : 0, 1758 is_scrolling : undefined 1759 }; 1760 1761 S(this).data('swipe-transition', data); 1762 e.stopPropagation(); 1763 }) 1764 .on('touchmove.fndtn.clearing', '.visible-img', function (e) { 1765 if (!e.touches) { 1766 e = e.originalEvent; 1767 } 1768 // Ignore pinch/zoom events 1769 if (e.touches.length > 1 || e.scale && e.scale !== 1) { 1770 return; 1771 } 1772 1773 var data = S(this).data('swipe-transition'); 1774 1775 if (typeof data === 'undefined') { 1776 data = {}; 1777 } 1778 1779 data.delta_x = e.touches[0].pageX - data.start_page_x; 1780 1781 if (Foundation.rtl) { 1782 data.delta_x = -data.delta_x; 1783 } 1784 1785 if (typeof data.is_scrolling === 'undefined') { 1786 data.is_scrolling = !!( data.is_scrolling || Math.abs(data.delta_x) < Math.abs(e.touches[0].pageY - data.start_page_y) ); 1787 } 1788 1789 if (!data.is_scrolling && !data.active) { 1790 e.preventDefault(); 1791 var direction = (data.delta_x < 0) ? 'next' : 'prev'; 1792 data.active = true; 1793 self.nav(e, direction); 1794 } 1795 }) 1796 .on('touchend.fndtn.clearing', '.visible-img', function (e) { 1797 S(this).data('swipe-transition', {}); 1798 e.stopPropagation(); 1799 }); 1800 }, 1801 1802 assemble : function ($li) { 1803 var $el = $li.parent(); 1804 1805 if ($el.parent().hasClass('carousel')) { 1806 return; 1807 } 1808 1809 $el.after('<div id="foundationClearingHolder"></div>'); 1810 1811 var grid = $el.detach(), 1812 grid_outerHTML = ''; 1813 1814 if (grid[0] == null) { 1815 return; 1816 } else {
1817 grid_outerHTML = grid[0].outerHTML; 1818 } 1819 1820 var holder = this.S('#foundationClearingHolder'), 1821 settings = $el.data(this.attr_name(true) + '-init'), 1822 data = { 1823 grid : '<div class="carousel">' + grid_outerHTML + '</div>', 1824 viewing : settings.templates.viewing 1825 }, 1826 wrapper = '<div class="clearing-assembled"><div>' + data.viewing + 1827 data.grid + '</div></div>', 1828 touch_label = this.settings.touch_label; 1829 1830 if (Modernizr.touch) { 1831 wrapper = $(wrapper).find('.clearing-touch-label').html(touch_label).end(); 1832 } 1833 1834 holder.after(wrapper).remove(); 1835 }, 1836 1837 open : function ($image, current, target) { 1838 var self = this, 1839 body = $(document.body), 1840 root = target.closest('.clearing-assembled'), 1841 container = self.S('div', root).first(), 1842 visible_image = self.S('.visible-img', container), 1843 image = self.S('img', visible_image).not($image), 1844 label = self.S('.clearing-touch-label', container), 1845 error = false, 1846 loaded = {}; 1847 1848 // Event to disable scrolling on touch devices when Clearing is activated 1849 $('body').on('touchmove', function (e) { 1850 e.preventDefault(); 1851 }); 1852 1853 image.error(function () { 1854 error = true; 1855 }); 1856 1857 function startLoad() { 1858 setTimeout(function () { 1859 this.image_loaded(image, function () { 1860 if (image.outerWidth() === 1 && !error) { 1861 startLoad.call(this); 1862 } else { 1863 cb.call(this, image); 1864 } 1865 }.bind(this)); 1866 }.bind(this), 100); 1867 } 1868 1869 function cb (image) { 1870 var $image = $(image); 1871 $image.css('visibility', 'visible'); 1872 $image.trigger('imageVisible'); 1873 // toggle the gallery 1874 body.css('overflow', 'hidden'); 1875 root.addClass('clearing-blackout'); 1876 container.addClass('clearing-container'); 1877 visible_image.show(); 1878 this.fix_height(target) 1879 .caption(self.S('.clearing-caption', visible_image), self.S('img', target)) 1880 .center_and_label(image, label) 1881 .shift(current, target, function () { 1882 target.closest('li').siblings().removeClass('visible'); 1883 target.closest('li').addClass('visible'); 1884 }); 1885 visible_image.trigger('opened.fndtn.clearing') 1886 } 1887 1888 if (!this.locked()) { 1889 visible_image.trigger('open.fndtn.clearing'); 1890 // set the image to the selected thumbnail 1891 loaded = this.load($image); 1892 if (loaded.interchange) { 1893 image 1894 .attr('data-interchange', loaded.interchange) 1895 .foundation('interchange', 'reflow'); 1896 } else { 1897 image 1898 .attr('src', loaded.src) 1899 .attr('data-interchange', ''); 1900 } 1901 image.css('visibility', 'hidden'); 1902 1903 startLoad.call(this); 1904 } 1905 }, 1906 1907 close : function (e, el) { 1908 e.preventDefault(); 1909 1910 var root = (function (target) { 1911 if (/blackout/.test(target.selector)) { 1912 return target; 1913 } else { 1914 return target.closest('.clearing-blackout'); 1915 } 1916 }($(el))), 1917 body = $(document.body), container, visible_image; 1918 1919 if (el === e.target && root) { 1920 body.css('overflow', ''); 1921 container = $('div', root).first(); 1922 visible_image = $('.visible-img', container); 1923 visible_image.trigger('close.fndtn.clearing'); 1924 this.settings.prev_index = 0; 1925 $('ul[' + this.attr_name() + ']', root) 1926 .attr('style', '').closest('.clearing-blackout') 1927 .removeClass('clearing-blackout'); 1928 container.removeClass('clearing-container'); 1929 visible_image.hide(); 1930 visible_image.trigger('closed.fndtn.clearing'); 1931 } 1932 1933 // Event to re-enable scrolling on touch devices 1934 $('body').off('touchmove'); 1935 1936 return false; 1937 }, 1938 1939 is_open : function (current) { 1940 return current.parent().prop('style').length > 0; 1941 }, 1942 1943 keydown : function (e) { 1944 var clearing = $('.clearing-blackout ul[' + this.attr_name() + ']'), 1945 NEXT_KEY = this.rtl ? 37 : 39, 1946 PREV_KEY = this.rtl ? 39 : 37, 1947 ESC_KEY = 27; 1948 1949 if (e.which === NEXT_KEY) { 1950 this.go(clearing, 'next'); 1951 } 1952 if (e.which === PREV_KEY) { 1953 this.go(clearing, 'prev'); 1954 } 1955 if (e.which === ESC_KEY) { 1956 this.S('a.clearing-close').trigger('click.fndtn.clearing'); 1957 } 1958 }, 1959 1960 nav : function (e, direction) { 1961 var clearing = $('ul[' + this.attr_name() + ']', '.clearing-blackout'); 1962 1963 e.preventDefault(); 1964 this.go(clearing, direction); 1965 }, 1966 1967 resize : function () { 1968 var image = $('img', '.clearing-blackout .visible-img'), 1969 label = $('.clearing-touch-label', '.clearing-blackout'); 1970 1971 if (image.length) { 1972 this.center_and_label(image, label); 1973 image.trigger('resized.fndtn.clearing') 1974 } 1975 }, 1976 1977 // visual adjustments 1978 fix_height : function (target) { 1979 var lis = target.parent().children(), 1980 self = this; 1981 1982 lis.each(function () { 1983 var li = self.S(this), 1984 image = li.find('img'); 1985 1986 if (li.height() > image.outerHeight()) { 1987 li.addClass('fix-height'); 1988 } 1989 }) 1990 .closest('ul') 1991 .width(lis.length * 100 + '%'); 1992 1993 return this; 1994 }, 1995 1996 update_paddles : function (target) { 1997 target = target.closest('li'); 1998 var visible_image = target 1999 .closest('.carousel') 2000 .siblings('.visible-img'); 2001 2002 if (target.next().length > 0) { 2003 this.S('.clearing-main-next', visible_image).removeClass('disabled'); 2004 } else { 2005 this.S('.clearing-main-next', visible_image).addClass('disabled'); 2006 } 2007 2008 if (target.prev().length > 0) { 2009 this.S('.clearing-main-prev', visible_image).removeClass('disabled'); 2010 } else { 2011 this.S('.clearing-main-prev', visible_image).addClass('disabled'); 2012 } 2013 }, 2014 2015 center_and_label : function (target, label) { 2016 if (!this.rtl && label.length > 0) { 2017 label.css({ 2018 marginLeft : -(label.outerWidth() / 2), 2019 marginTop : -(target.outerHeight() / 2)-label.outerHeight()-10 2020 }); 2021 } else { 2022 label.css({ 2023 marginRight : -(label.outerWidth() / 2), 2024 marginTop : -(target.outerHeight() / 2)-label.outerHeight()-10, 2025 left: 'auto', 2026 right: '50%' 2027 }); 2028 } 2029 return this; 2030 }, 2031 2032 // image loading and preloading 2033 2034 load : function ($image) { 2035 var href, 2036 interchange, 2037 closest_a; 2038 2039 if ($image[0].nodeName === 'A') { 2040 href = $image.attr('href'); 2041 interchange = $image.data('clearing-interchange'); 2042 } else { 2043 closest_a = $image.closest('a'); 2044 href = closest_a.attr('href'); 2045 interchange = closest_a.data('clearing-interchange'); 2046 } 2047 2048 this.preload($image); 2049 2050 return { 2051 'src': href ? href : $image.attr('src'), 2052 'interchange': href ? interchange : $image.data('clearing-interchange') 2053 } 2054 }, 2055 2056 preload : function ($image) { 2057 this 2058 .img($image.closest('li').next(), 'next') 2059 .img($image.closest('li').prev(), 'prev'); 2060 }, 2061 2062 img : function (img, sibling_type) { 2063 if (img.length) { 2064 var preload_img = $('.clearing-preload-' + sibling_type), 2065 new_a = this.S('a', img), 2066 src, 2067 interchange, 2068 image; 2069 2070 if (new_a.length) { 2071 src = new_a.attr('href'); 2072 interchange = new_a.data('clearing-interchange'); 2073 } else { 2074 image = this.S('img', img); 2075 src = image.attr('src'); 2076 interchange = image.data('clearing-interchange'); 2077 } 2078 2079 if (interchange) { 2080 preload_img.attr('data-interchange', interchange); 2081 } else { 2082 preload_img.attr('src', src); 2083 preload_img.attr('data-interchange', ''); 2084 } 2085 } 2086 return this; 2087 }, 2088 2089 // image caption 2090 2091 caption : function (container, $image) { 2092 var caption = $image.attr('data-caption'); 2093 2094 if (caption) { 2095 container 2096 .html(caption) 2097 .show(); 2098 } else { 2099 container 2100 .text('') 2101 .hide(); 2102 } 2103 return this; 2104 }, 2105 2106 // directional methods 2107 2108 go : function ($ul, direction) { 2109 var current = this.S('.visible', $ul), 2110 target = current[direction](); 2111 2112 // Check for skip selector. 2113 if (this.settings.skip_selector && target.find(this.settings.skip_selector).length != 0) { 2114 target = target[direction](); 2115 } 2116 2117 if (target.length) { 2118 this.S('img', target) 2119 .trigger('click.fndtn.clearing', [current, target]) 2120 .trigger('change.fndtn.clearing'); 2121 } 2122 }, 2123 2124 shift : function (current, target, callback) { 2125 var clearing = target.parent(), 2126 old_index = this.settings.prev_index || target.index(), 2127 direction = this.direction(clearing, current, target), 2128 dir = this.rtl ? 'right' : 'left', 2129 left = parseInt(clearing.css('left'), 10), 2130 width = target.outerWidth(), 2131 skip_shift; 2132 2133 var dir_obj = {}; 2134 2135 // we use jQuery animate instead of CSS transitions because we 2136 // need a callback to unlock the next animation
2137 // needs support for RTL ** 2138 if (target.index() !== old_index && !/skip/.test(direction)) { 2139 if (/left/.test(direction)) { 2140 this.lock(); 2141 dir_obj[dir] = left + width; 2142 clearing.animate(dir_obj, 300, this.unlock()); 2143 } else if (/right/.test(direction)) { 2144 this.lock(); 2145 dir_obj[dir] = left - width; 2146 clearing.animate(dir_obj, 300, this.unlock()); 2147 } 2148 } else if (/skip/.test(direction)) { 2149 // the target image is not adjacent to the current image, so 2150 // do we scroll right or not 2151 skip_shift = target.index() - this.settings.up_count; 2152 this.lock(); 2153 2154 if (skip_shift > 0) { 2155 dir_obj[dir] = -(skip_shift * width); 2156 clearing.animate(dir_obj, 300, this.unlock()); 2157 } else { 2158 dir_obj[dir] = 0; 2159 clearing.animate(dir_obj, 300, this.unlock()); 2160 } 2161 } 2162 2163 callback(); 2164 }, 2165 2166 direction : function ($el, current, target) { 2167 var lis = this.S('li', $el), 2168 li_width = lis.outerWidth() + (lis.outerWidth() / 4), 2169 up_count = Math.floor(this.S('.clearing-container').outerWidth() / li_width) - 1, 2170 target_index = lis.index(target), 2171 response; 2172 2173 this.settings.up_count = up_count; 2174 2175 if (this.adjacent(this.settings.prev_index, target_index)) { 2176 if ((target_index > up_count) && target_index > this.settings.prev_index) { 2177 response = 'right'; 2178 } else if ((target_index > up_count - 1) && target_index <= this.settings.prev_index) { 2179 response = 'left'; 2180 } else { 2181 response = false; 2182 } 2183 } else { 2184 response = 'skip'; 2185 } 2186 2187 this.settings.prev_index = target_index; 2188 2189 return response; 2190 }, 2191 2192 adjacent : function (current_index, target_index) { 2193 for (var i = target_index + 1; i >= target_index - 1; i--) { 2194 if (i === current_index) { 2195 return true; 2196 } 2197 } 2198 return false; 2199 }, 2200 2201 // lock management 2202 2203 lock : function () { 2204 this.settings.locked = true; 2205 }, 2206 2207 unlock : function () { 2208 this.settings.locked = false; 2209 }, 2210 2211 locked : function () { 2212 return this.settings.locked; 2213 }, 2214 2215 off : function () { 2216 this.S(this.scope).off('.fndtn.clearing'); 2217 this.S(window).off('.fndtn.clearing'); 2218 }, 2219 2220 reflow : function () { 2221 this.init(); 2222 } 2223 }; 2224 2225}(jQuery, window, window.document)); 2226;(function ($, window, document, undefined) { 2227 'use strict'; 2228 2229 Foundation.libs.tab = { 2230 name : 'tab', 2231 2232 version : '5.5.2', 2233 2234 settings : { 2235 active_class : 'active', 2236 callback : function () {}, 2237 deep_linking : false, 2238 scroll_to_content : true, 2239 is_hover : false 2240 }, 2241 2242 default_tab_hashes : [], 2243 2244 init : function (scope, method, options) { 2245 var self = this, 2246 S = this.S; 2247 2248 // Store the default active tabs which will be referenced when the 2249 // location hash is absent, as in the case of navigating the tabs and 2250 // returning to the first viewing via the browser Back button. 2251 S('[' + this.attr_name() + '] > .active > a', this.scope).each(function () { 2252 self.default_tab_hashes.push(this.hash); 2253 }); 2254 2255 // store the initial href, which is used to allow correct behaviour of the 2256 // browser back button when deep linking is turned on. 2257 self.entry_location = window.location.href; 2258 2259 this.bindings(method, options); 2260 this.handle_location_hash_change(); 2261 }, 2262 2263 events : function () { 2264 var self = this, 2265 S = this.S; 2266 2267 var usual_tab_behavior = function (e, target) { 2268 var settings = S(target).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'); 2269 if (!settings.is_hover || Modernizr.touch) { 2270 e.preventDefault(); 2271 e.stopPropagation(); 2272 self.toggle_active_tab(S(target).parent()); 2273 } 2274 }; 2275 2276 S(this.scope) 2277 .off('.tab') 2278 // Key event: focus/tab key 2279 .on('keydown.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) { 2280 var el = this; 2281 var keyCode = e.keyCode || e.which; 2282 // if user pressed tab key 2283 if (keyCode == 9) { 2284 e.preventDefault(); 2285 // TODO: Change usual_tab_behavior into accessibility function? 2286 usual_tab_behavior(e, el); 2287 } 2288 }) 2289 // Click event: tab title 2290 .on('click.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) { 2291 var el = this; 2292 usual_tab_behavior(e, el); 2293 }) 2294 // Hover event: tab title 2295 .on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > * > a', function (e) { 2296 var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'); 2297 if (settings.is_hover) { 2298 self.toggle_active_tab(S(this).parent()); 2299 } 2300 }); 2301 2302 // Location hash change event 2303 S(window).on('hashchange.fndtn.tab', function (e) { 2304 e.preventDefault(); 2305 self.handle_location_hash_change(); 2306 }); 2307 }, 2308 2309 handle_location_hash_change : function () { 2310 2311 var self = this, 2312 S = this.S; 2313 2314 S('[' + this.attr_name() + ']', this.scope).each(function () { 2315 var settings = S(this).data(self.attr_name(true) + '-init'); 2316 if (settings.deep_linking) { 2317 // Match the location hash to a label 2318 var hash; 2319 if (settings.scroll_to_content) { 2320 hash = self.scope.location.hash; 2321 } else { 2322 // prefix the hash to prevent anchor scrolling 2323 hash = self.scope.location.hash.replace('fndtn-', ''); 2324 } 2325 if (hash != '') { 2326 // Check whether the location hash references a tab content div or 2327 // another element on the page (inside or outside the tab content div) 2328 var hash_element = S(hash); 2329 if (hash_element.hasClass('content') && hash_element.parent().hasClass('tabs-content')) { 2330 // Tab content div 2331 self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + hash + ']').parent()); 2332 } else { 2333 // Not the tab content div. If inside the tab content, find the 2334 // containing tab and toggle it as active. 2335 var hash_tab_container_id = hash_element.closest('.content').attr('id'); 2336 if (hash_tab_container_id != undefined) { 2337 self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=#' + hash_tab_container_id + ']').parent(), hash); 2338 } 2339 } 2340 } else { 2341 // Reference the default tab hashes which were initialized in the init function 2342 for (var ind = 0; ind < self.default_tab_hashes.length; ind++) { 2343 self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + self.default_tab_hashes[ind] + ']').parent()); 2344 } 2345 } 2346 } 2347 }); 2348 }, 2349 2350 toggle_active_tab : function (tab, location_hash) { 2351 var self = this, 2352 S = self.S, 2353 tabs = tab.closest('[' + this.attr_name() + ']'), 2354 tab_link = tab.find('a'), 2355 anchor = tab.children('a').first(), 2356 target_hash = '#' + anchor.attr('href').split('#')[1], 2357 target = S(target_hash), 2358 siblings = tab.siblings(), 2359 settings = tabs.data(this.attr_name(true) + '-init'), 2360 interpret_keyup_action = function (e) { 2361 // Light modification of Heydon Pickering's Practical ARIA Examples: http://heydonworks.com/practical_aria_examples/js/a11y.js 2362 2363 // define current, previous and next (possible) tabs 2364 2365 var $original = $(this); 2366 var $prev = $(this).parents('li').prev().children('[role="tab"]'); 2367 var $next = $(this).parents('li').next().children('[role="tab"]'); 2368 var $target; 2369 2370 // find the direction (prev or next) 2371 2372 switch (e.keyCode) { 2373 case 37: 2374 $target = $prev; 2375 break; 2376 case 39: 2377 $target = $next; 2378 break; 2379 default: 2380 $target = false 2381 break; 2382 } 2383 2384 if ($target.length) { 2385 $original.attr({ 2386 'tabindex' : '-1', 2387 'aria-selected' : null 2388 }); 2389 $target.attr({ 2390 'tabindex' : '0', 2391 'aria-selected' : true 2392 }).focus(); 2393 } 2394 2395 // Hide panels 2396 2397 $('[role="tabpanel"]') 2398 .attr('aria-hidden', 'true'); 2399 2400 // Show panel which corresponds to target 2401 2402 $('#' + $(document.activeElement).attr('href').substring(1)) 2403 .attr('aria-hidden', null); 2404 2405 }, 2406 go_to_hash = function(hash) { 2407 // This function allows correct behaviour of the browser's back button when deep linking is enabled. Without it 2408 // the user would get continually redirected to the default hash. 2409 var is_entry_location = window.location.href === self.entry_location, 2410 default_hash = settings.scroll_to_content ? self.default_tab_hashes[0] : is_entry_location ? window.location.hash :'fndtn-' + self.default_tab_hashes[0].replace('#', '') 2411 2412 if (!(is_entry_location && hash === default_hash)) { 2413 window.location.hash = hash; 2414 } 2415 }; 2416 2417 // allow usage of data-tab-content attribute instead of href 2418 if (anchor.data('tab-content')) { 2419 target_hash = '#' + anchor.data('tab-content').split('#')[1]; 2420 target = S(target_hash); 2421 } 2422 2423 if (settings.deep_linking) { 2424 2425 if (settings.scroll_to_content) { 2426 2427 // retain current hash to scroll to content 2428 go_to_hash(location_hash || target_hash); 2429 2430 if (location_hash == undefined || location_hash == target_hash) { 2431 tab.parent()[0].scrollIntoView(); 2432 } else { 2433 S(target_hash)[0].scrollIntoView(); 2434 } 2435 } else { 2436 // prefix the hashes so that the browser doesn't scroll down 2437 if (location_hash != undefined) { 2438 go_to_hash('fndtn-' + location_hash.replace('#', '')); 2439 } else { 2440 go_to_hash('fndtn-' + target_hash.replace('#', '')); 2441 } 2442 } 2443 } 2444 2445 // WARNING: The activation and deactivation of the tab content must 2446 // occur after the deep linking in order to properly refresh the browser 2447 // window (notably in Chrome). 2448 // Clean up multiple attr instances to done once 2449 tab.addClass(settings.active_class).triggerHandler('opened'); 2450 tab_link.attr({'aria-selected' : 'true', tabindex : 0}); 2451 siblings.removeClass(settings.active_class) 2452 siblings.find('a').attr({'aria-selected' : 'false', tabindex : -1}); 2453 target.siblings().removeClass(settings.active_class).attr({'aria-hidden' : 'true', tabindex : -1}); 2454 target.addClass(settings.active_class).attr('aria-hidden', 'false').removeAttr('tabindex'); 2455 settings.callback(tab); 2456 target.triggerHandler('toggled', [target]); 2457 tabs.triggerHandler('toggled', [tab]); 2458 2459 tab_link.off('keydown').on('keydown', interpret_keyup_action ); 2460 }, 2461 2462 data_attr : function (str) { 2463 if (this.namespace.length > 0) { 2464 return this.namespace + '-' + str; 2465 } 2466 2467 return str; 2468 }, 2469 2470 off : function () {}, 2471 2472 reflow : function () {} 2473 }; 2474}(jQuery, window, window.document));
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.