]> de.git.xonotic.org Git - xonotic/xonstat.git/blob - xonstat/static/js/foundation.min.js
Get rid of joined_pretty_date in favor of the mixin.
[xonotic/xonstat.git] / xonstat / static / js / foundation.min.js
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   /*
161     https://github.com/paulirish/matchMedia.js
162   */
163
164   window.matchMedia = window.matchMedia || (function ( doc ) {
165
166     'use strict';
167
168     var bool,
169         docElem = doc.documentElement,
170         refNode = docElem.firstElementChild || docElem.firstChild,
171         // fakeBody required for <FF4 when executed in <head>
172         fakeBody = doc.createElement( 'body' ),
173         div = doc.createElement( 'div' );
174
175     div.id = 'mq-test-1';
176     div.style.cssText = 'position:absolute;top:-100em';
177     fakeBody.style.background = 'none';
178     fakeBody.appendChild(div);
179
180     return function (q) {
181
182       div.innerHTML = '&shy;<style media="' + q + '"> #mq-test-1 { width: 42px; }</style>';
183
184       docElem.insertBefore( fakeBody, refNode );
185       bool = div.offsetWidth === 42;
186       docElem.removeChild( fakeBody );
187
188       return {
189         matches : bool,
190         media : q
191       };
192
193     };
194
195   }( document ));
196
197   /*
198    * jquery.requestAnimationFrame
199    * https://github.com/gnarf37/jquery-requestAnimationFrame
200    * Requires jQuery 1.8+
201    *
202    * Copyright (c) 2012 Corey Frang
203    * Licensed under the MIT license.
204    */
205
206   (function(jQuery) {
207
208
209   // requestAnimationFrame polyfill adapted from Erik Möller
210   // fixes from Paul Irish and Tino Zijdel
211   // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
212   // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
213
214   var animating,
215       lastTime = 0,
216       vendors = ['webkit', 'moz'],
217       requestAnimationFrame = window.requestAnimationFrame,
218       cancelAnimationFrame = window.cancelAnimationFrame,
219       jqueryFxAvailable = 'undefined' !== typeof jQuery.fx;
220
221   for (; lastTime < vendors.length && !requestAnimationFrame; lastTime++) {
222     requestAnimationFrame = window[ vendors[lastTime] + 'RequestAnimationFrame' ];
223     cancelAnimationFrame = cancelAnimationFrame ||
224       window[ vendors[lastTime] + 'CancelAnimationFrame' ] ||
225       window[ vendors[lastTime] + 'CancelRequestAnimationFrame' ];
226   }
227
228   function raf() {
229     if (animating) {
230       requestAnimationFrame(raf);
231
232       if (jqueryFxAvailable) {
233         jQuery.fx.tick();
234       }
235     }
236   }
237
238   if (requestAnimationFrame) {
239     // use rAF
240     window.requestAnimationFrame = requestAnimationFrame;
241     window.cancelAnimationFrame = cancelAnimationFrame;
242
243     if (jqueryFxAvailable) {
244       jQuery.fx.timer = function (timer) {
245         if (timer() && jQuery.timers.push(timer) && !animating) {
246           animating = true;
247           raf();
248         }
249       };
250
251       jQuery.fx.stop = function () {
252         animating = false;
253       };
254     }
255   } else {
256     // polyfill
257     window.requestAnimationFrame = function (callback) {
258       var currTime = new Date().getTime(),
259         timeToCall = Math.max(0, 16 - (currTime - lastTime)),
260         id = window.setTimeout(function () {
261           callback(currTime + timeToCall);
262         }, timeToCall);
263       lastTime = currTime + timeToCall;
264       return id;
265     };
266
267     window.cancelAnimationFrame = function (id) {
268       clearTimeout(id);
269     };
270
271   }
272
273   }( $ ));
274
275   function removeQuotes (string) {
276     if (typeof string === 'string' || string instanceof String) {
277       string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, '');
278     }
279
280     return string;
281   }
282
283   window.Foundation = {
284     name : 'Foundation',
285
286     version : '5.5.1',
287
288     media_queries : {
289       'small'       : S('.foundation-mq-small').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
290       'small-only'  : S('.foundation-mq-small-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
291       'medium'      : S('.foundation-mq-medium').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
292       'medium-only' : S('.foundation-mq-medium-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
293       'large'       : S('.foundation-mq-large').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
294       'large-only'  : S('.foundation-mq-large-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
295       'xlarge'      : S('.foundation-mq-xlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
296       'xlarge-only' : S('.foundation-mq-xlarge-only').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
297       'xxlarge'     : S('.foundation-mq-xxlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, '')
298     },
299
300     stylesheet : $('<style></style>').appendTo('head')[0].sheet,
301
302     global : {
303       namespace : undefined
304     },
305
306     init : function (scope, libraries, method, options, response) {
307       var args = [scope, method, options, response],
308           responses = [];
309
310       // check RTL
311       this.rtl = /rtl/i.test(S('html').attr('dir'));
312
313       // set foundation global scope
314       this.scope = scope || this.scope;
315
316       this.set_namespace();
317
318       if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) {
319         if (this.libs.hasOwnProperty(libraries)) {
320           responses.push(this.init_lib(libraries, args));
321         }
322       } else {
323         for (var lib in this.libs) {
324           responses.push(this.init_lib(lib, libraries));
325         }
326       }
327
328       S(window).load(function () {
329         S(window)
330           .trigger('resize.fndtn.clearing')
331           .trigger('resize.fndtn.dropdown')
332           .trigger('resize.fndtn.equalizer')
333           .trigger('resize.fndtn.interchange')
334           .trigger('resize.fndtn.joyride')
335           .trigger('resize.fndtn.magellan')
336           .trigger('resize.fndtn.topbar')
337           .trigger('resize.fndtn.slider');
338       });
339
340       return scope;
341     },
342
343     init_lib : function (lib, args) {
344       if (this.libs.hasOwnProperty(lib)) {
345         this.patch(this.libs[lib]);
346
347         if (args && args.hasOwnProperty(lib)) {
348             if (typeof this.libs[lib].settings !== 'undefined') {
349               $.extend(true, this.libs[lib].settings, args[lib]);
350             } else if (typeof this.libs[lib].defaults !== 'undefined') {
351               $.extend(true, this.libs[lib].defaults, args[lib]);
352             }
353           return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]);
354         }
355
356         args = args instanceof Array ? args : new Array(args);
357         return this.libs[lib].init.apply(this.libs[lib], args);
358       }
359
360       return function () {};
361     },
362
363     patch : function (lib) {
364       lib.scope = this.scope;
365       lib.namespace = this.global.namespace;
366       lib.rtl = this.rtl;
367       lib['data_options'] = this.utils.data_options;
368       lib['attr_name'] = attr_name;
369       lib['add_namespace'] = add_namespace;
370       lib['bindings'] = bindings;
371       lib['S'] = this.utils.S;
372     },
373
374     inherit : function (scope, methods) {
375       var methods_arr = methods.split(' '),
376           i = methods_arr.length;
377
378       while (i--) {
379         if (this.utils.hasOwnProperty(methods_arr[i])) {
380           scope[methods_arr[i]] = this.utils[methods_arr[i]];
381         }
382       }
383     },
384
385     set_namespace : function () {
386
387       // Description:
388       //    Don't bother reading the namespace out of the meta tag
389       //    if the namespace has been set globally in javascript
390       //
391       // Example:
392       //    Foundation.global.namespace = 'my-namespace';
393       // or make it an empty string:
394       //    Foundation.global.namespace = '';
395       //
396       //
397
398       // If the namespace has not been set (is undefined), try to read it out of the meta element.
399       // Otherwise use the globally defined namespace, even if it's empty ('')
400       var namespace = ( this.global.namespace === undefined ) ? $('.foundation-data-attribute-namespace').css('font-family') : this.global.namespace;
401
402       // Finally, if the namsepace is either undefined or false, set it to an empty string.
403       // Otherwise use the namespace value.
404       this.global.namespace = ( namespace === undefined || /false/i.test(namespace) ) ? '' : namespace;
405     },
406
407     libs : {},
408
409     // methods that can be inherited in libraries
410     utils : {
411
412       // Description:
413       //    Fast Selector wrapper returns jQuery object. Only use where getElementById
414       //    is not available.
415       //
416       // Arguments:
417       //    Selector (String): CSS selector describing the element(s) to be
418       //    returned as a jQuery object.
419       //
420       //    Scope (String): CSS selector describing the area to be searched. Default
421       //    is document.
422       //
423       // Returns:
424       //    Element (jQuery Object): jQuery object containing elements matching the
425       //    selector within the scope.
426       S : S,
427
428       // Description:
429       //    Executes a function a max of once every n milliseconds
430       //
431       // Arguments:
432       //    Func (Function): Function to be throttled.
433       //
434       //    Delay (Integer): Function execution threshold in milliseconds.
435       //
436       // Returns:
437       //    Lazy_function (Function): Function with throttling applied.
438       throttle : function (func, delay) {
439         var timer = null;
440
441         return function () {
442           var context = this, args = arguments;
443
444           if (timer == null) {
445             timer = setTimeout(function () {
446               func.apply(context, args);
447               timer = null;
448             }, delay);
449           }
450         };
451       },
452
453       // Description:
454       //    Executes a function when it stops being invoked for n seconds
455       //    Modified version of _.debounce() http://underscorejs.org
456       //
457       // Arguments:
458       //    Func (Function): Function to be debounced.
459       //
460       //    Delay (Integer): Function execution threshold in milliseconds.
461       //
462       //    Immediate (Bool): Whether the function should be called at the beginning
463       //    of the delay instead of the end. Default is false.
464       //
465       // Returns:
466       //    Lazy_function (Function): Function with debouncing applied.
467       debounce : function (func, delay, immediate) {
468         var timeout, result;
469         return function () {
470           var context = this, args = arguments;
471           var later = function () {
472             timeout = null;
473             if (!immediate) {
474               result = func.apply(context, args);
475             }
476           };
477           var callNow = immediate && !timeout;
478           clearTimeout(timeout);
479           timeout = setTimeout(later, delay);
480           if (callNow) {
481             result = func.apply(context, args);
482           }
483           return result;
484         };
485       },
486
487       // Description:
488       //    Parses data-options attribute
489       //
490       // Arguments:
491       //    El (jQuery Object): Element to be parsed.
492       //
493       // Returns:
494       //    Options (Javascript Object): Contents of the element's data-options
495       //    attribute.
496       data_options : function (el, data_attr_name) {
497         data_attr_name = data_attr_name || 'options';
498         var opts = {}, ii, p, opts_arr,
499             data_options = function (el) {
500               var namespace = Foundation.global.namespace;
501
502               if (namespace.length > 0) {
503                 return el.data(namespace + '-' + data_attr_name);
504               }
505
506               return el.data(data_attr_name);
507             };
508
509         var cached_options = data_options(el);
510
511         if (typeof cached_options === 'object') {
512           return cached_options;
513         }
514
515         opts_arr = (cached_options || ':').split(';');
516         ii = opts_arr.length;
517
518         function isNumber (o) {
519           return !isNaN (o - 0) && o !== null && o !== '' && o !== false && o !== true;
520         }
521
522         function trim (str) {
523           if (typeof str === 'string') {
524             return $.trim(str);
525           }
526           return str;
527         }
528
529         while (ii--) {
530           p = opts_arr[ii].split(':');
531           p = [p[0], p.slice(1).join(':')];
532
533           if (/true/i.test(p[1])) {
534             p[1] = true;
535           }
536           if (/false/i.test(p[1])) {
537             p[1] = false;
538           }
539           if (isNumber(p[1])) {
540             if (p[1].indexOf('.') === -1) {
541               p[1] = parseInt(p[1], 10);
542             } else {
543               p[1] = parseFloat(p[1]);
544             }
545           }
546
547           if (p.length === 2 && p[0].length > 0) {
548             opts[trim(p[0])] = trim(p[1]);
549           }
550         }
551
552         return opts;
553       },
554
555       // Description:
556       //    Adds JS-recognizable media queries
557       //
558       // Arguments:
559       //    Media (String): Key string for the media query to be stored as in
560       //    Foundation.media_queries
561       //
562       //    Class (String): Class name for the generated <meta> tag
563       register_media : function (media, media_class) {
564         if (Foundation.media_queries[media] === undefined) {
565           $('head').append('<meta class="' + media_class + '"/>');
566           Foundation.media_queries[media] = removeQuotes($('.' + media_class).css('font-family'));
567         }
568       },
569
570       // Description:
571       //    Add custom CSS within a JS-defined media query
572       //
573       // Arguments:
574       //    Rule (String): CSS rule to be appended to the document.
575       //
576       //    Media (String): Optional media query string for the CSS rule to be
577       //    nested under.
578       add_custom_rule : function (rule, media) {
579         if (media === undefined && Foundation.stylesheet) {
580           Foundation.stylesheet.insertRule(rule, Foundation.stylesheet.cssRules.length);
581         } else {
582           var query = Foundation.media_queries[media];
583
584           if (query !== undefined) {
585             Foundation.stylesheet.insertRule('@media ' +
586               Foundation.media_queries[media] + '{ ' + rule + ' }');
587           }
588         }
589       },
590
591       // Description:
592       //    Performs a callback function when an image is fully loaded
593       //
594       // Arguments:
595       //    Image (jQuery Object): Image(s) to check if loaded.
596       //
597       //    Callback (Function): Function to execute when image is fully loaded.
598       image_loaded : function (images, callback) {
599         var self = this,
600             unloaded = images.length;
601
602         if (unloaded === 0) {
603           callback(images);
604         }
605
606         images.each(function () {
607           single_image_loaded(self.S(this), function () {
608             unloaded -= 1;
609             if (unloaded === 0) {
610               callback(images);
611             }
612           });
613         });
614       },
615
616       // Description:
617       //    Returns a random, alphanumeric string
618       //
619       // Arguments:
620       //    Length (Integer): Length of string to be generated. Defaults to random
621       //    integer.
622       //
623       // Returns:
624       //    Rand (String): Pseudo-random, alphanumeric string.
625       random_str : function () {
626         if (!this.fidx) {
627           this.fidx = 0;
628         }
629         this.prefix = this.prefix || [(this.name || 'F'), (+new Date).toString(36)].join('-');
630
631         return this.prefix + (this.fidx++).toString(36);
632       },
633
634       // Description:
635       //    Helper for window.matchMedia
636       //
637       // Arguments:
638       //    mq (String): Media query
639       //
640       // Returns:
641       //    (Boolean): Whether the media query passes or not
642       match : function (mq) {
643         return window.matchMedia(mq).matches;
644       },
645
646       // Description:
647       //    Helpers for checking Foundation default media queries with JS
648       //
649       // Returns:
650       //    (Boolean): Whether the media query passes or not
651
652       is_small_up : function () {
653         return this.match(Foundation.media_queries.small);
654       },
655
656       is_medium_up : function () {
657         return this.match(Foundation.media_queries.medium);
658       },
659
660       is_large_up : function () {
661         return this.match(Foundation.media_queries.large);
662       },
663
664       is_xlarge_up : function () {
665         return this.match(Foundation.media_queries.xlarge);
666       },
667
668       is_xxlarge_up : function () {
669         return this.match(Foundation.media_queries.xxlarge);
670       },
671
672       is_small_only : function () {
673         return !this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up();
674       },
675
676       is_medium_only : function () {
677         return this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up();
678       },
679
680       is_large_only : function () {
681         return this.is_medium_up() && this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up();
682       },
683
684       is_xlarge_only : function () {
685         return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && !this.is_xxlarge_up();
686       },
687
688       is_xxlarge_only : function () {
689         return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && this.is_xxlarge_up();
690       }
691     }
692   };
693
694   $.fn.foundation = function () {
695     var args = Array.prototype.slice.call(arguments, 0);
696
697     return this.each(function () {
698       Foundation.init.apply(Foundation, [this].concat(args));
699       return this;
700     });
701   };
702
703 }(jQuery, window, window.document));
704 ;(function ($, window, document, undefined) {
705   'use strict';
706
707   Foundation.libs.equalizer = {
708     name : 'equalizer',
709
710     version : '5.5.1',
711
712     settings : {
713       use_tallest : true,
714       before_height_change : $.noop,
715       after_height_change : $.noop,
716       equalize_on_stack : false
717     },
718
719     init : function (scope, method, options) {
720       Foundation.inherit(this, 'image_loaded');
721       this.bindings(method, options);
722       this.reflow();
723     },
724
725     events : function () {
726       this.S(window).off('.equalizer').on('resize.fndtn.equalizer', function (e) {
727         this.reflow();
728       }.bind(this));
729     },
730
731     equalize : function (equalizer) {
732       var isStacked = false,
733           vals = equalizer.find('[' + this.attr_name() + '-watch]:visible'),
734           settings = equalizer.data(this.attr_name(true) + '-init');
735
736       if (vals.length === 0) {
737         return;
738       }
739       var firstTopOffset = vals.first().offset().top;
740       settings.before_height_change();
741       equalizer.trigger('before-height-change').trigger('before-height-change.fndth.equalizer');
742       vals.height('inherit');
743       vals.each(function () {
744         var el = $(this);
745         if (el.offset().top !== firstTopOffset) {
746           isStacked = true;
747         }
748       });
749
750       if (settings.equalize_on_stack === false) {
751         if (isStacked) {
752           return;
753         }
754       };
755
756       var heights = vals.map(function () { return $(this).outerHeight(false) }).get();
757
758       if (settings.use_tallest) {
759         var max = Math.max.apply(null, heights);
760         vals.css('height', max);
761       } else {
762         var min = Math.min.apply(null, heights);
763         vals.css('height', min);
764       }
765       settings.after_height_change();
766       equalizer.trigger('after-height-change').trigger('after-height-change.fndtn.equalizer');
767     },
768
769     reflow : function () {
770       var self = this;
771
772       this.S('[' + this.attr_name() + ']', this.scope).each(function () {
773         var $eq_target = $(this);
774         self.image_loaded(self.S('img', this), function () {
775           self.equalize($eq_target)
776         });
777       });
778     }
779   };
780 })(jQuery, window, window.document);
781 ;(function ($, window, document, undefined) {
782   'use strict';
783
784   Foundation.libs.interchange = {
785     name : 'interchange',
786
787     version : '5.5.1',
788
789     cache : {},
790
791     images_loaded : false,
792     nodes_loaded : false,
793
794     settings : {
795       load_attr : 'interchange',
796
797       named_queries : {
798         'default'     : 'only screen',
799         'small'       : Foundation.media_queries['small'],
800         'small-only'  : Foundation.media_queries['small-only'],
801         'medium'      : Foundation.media_queries['medium'],
802         'medium-only' : Foundation.media_queries['medium-only'],
803         'large'       : Foundation.media_queries['large'],
804         'large-only'  : Foundation.media_queries['large-only'],
805         'xlarge'      : Foundation.media_queries['xlarge'],
806         'xlarge-only' : Foundation.media_queries['xlarge-only'],
807         'xxlarge'     : Foundation.media_queries['xxlarge'],
808         'landscape'   : 'only screen and (orientation: landscape)',
809         'portrait'    : 'only screen and (orientation: portrait)',
810         'retina'      : 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
811           'only screen and (min--moz-device-pixel-ratio: 2),' +
812           'only screen and (-o-min-device-pixel-ratio: 2/1),' +
813           'only screen and (min-device-pixel-ratio: 2),' +
814           'only screen and (min-resolution: 192dpi),' +
815           'only screen and (min-resolution: 2dppx)'
816       },
817
818       directives : {
819         replace : function (el, path, trigger) {
820           // The trigger argument, if called within the directive, fires
821           // an event named after the directive on the element, passing
822           // any parameters along to the event that you pass to trigger.
823           //
824           // ex. trigger(), trigger([a, b, c]), or trigger(a, b, c)
825           //
826           // This allows you to bind a callback like so:
827           // $('#interchangeContainer').on('replace', function (e, a, b, c) {
828           //   console.log($(this).html(), a, b, c);
829           // });
830
831           if (/IMG/.test(el[0].nodeName)) {
832             var orig_path = el[0].src;
833
834             if (new RegExp(path, 'i').test(orig_path)) {
835               return;
836             }
837
838             el[0].src = path;
839
840             return trigger(el[0].src);
841           }
842           var last_path = el.data(this.data_attr + '-last-path'),
843               self = this;
844
845           if (last_path == path) {
846             return;
847           }
848
849           if (/\.(gif|jpg|jpeg|tiff|png)([?#].*)?/i.test(path)) {
850             $(el).css('background-image', 'url(' + path + ')');
851             el.data('interchange-last-path', path);
852             return trigger(path);
853           }
854
855           return $.get(path, function (response) {
856             el.html(response);
857             el.data(self.data_attr + '-last-path', path);
858             trigger();
859           });
860
861         }
862       }
863     },
864
865     init : function (scope, method, options) {
866       Foundation.inherit(this, 'throttle random_str');
867
868       this.data_attr = this.set_data_attr();
869       $.extend(true, this.settings, method, options);
870       this.bindings(method, options);
871       this.load('images');
872       this.load('nodes');
873     },
874
875     get_media_hash : function () {
876         var mediaHash = '';
877         for (var queryName in this.settings.named_queries ) {
878             mediaHash += matchMedia(this.settings.named_queries[queryName]).matches.toString();
879         }
880         return mediaHash;
881     },
882
883     events : function () {
884       var self = this, prevMediaHash;
885
886       $(window)
887         .off('.interchange')
888         .on('resize.fndtn.interchange', self.throttle(function () {
889             var currMediaHash = self.get_media_hash();
890             if (currMediaHash !== prevMediaHash) {
891                 self.resize();
892             }
893             prevMediaHash = currMediaHash;
894         }, 50));
895
896       return this;
897     },
898
899     resize : function () {
900       var cache = this.cache;
901
902       if (!this.images_loaded || !this.nodes_loaded) {
903         setTimeout($.proxy(this.resize, this), 50);
904         return;
905       }
906
907       for (var uuid in cache) {
908         if (cache.hasOwnProperty(uuid)) {
909           var passed = this.results(uuid, cache[uuid]);
910
911           if (passed) {
912             this.settings.directives[passed
913               .scenario[1]].call(this, passed.el, passed.scenario[0], (function (passed) {
914                 if (arguments[0] instanceof Array) { 
915                   var args = arguments[0];
916                 } else {
917                   var args = Array.prototype.slice.call(arguments, 0);
918                 }
919
920                 return function() {
921                   passed.el.trigger(passed.scenario[1], args);
922                 }
923               }(passed)));
924           }
925         }
926       }
927
928     },
929
930     results : function (uuid, scenarios) {
931       var count = scenarios.length;
932
933       if (count > 0) {
934         var el = this.S('[' + this.add_namespace('data-uuid') + '="' + uuid + '"]');
935
936         while (count--) {
937           var mq, rule = scenarios[count][2];
938           if (this.settings.named_queries.hasOwnProperty(rule)) {
939             mq = matchMedia(this.settings.named_queries[rule]);
940           } else {
941             mq = matchMedia(rule);
942           }
943           if (mq.matches) {
944             return {el : el, scenario : scenarios[count]};
945           }
946         }
947       }
948
949       return false;
950     },
951
952     load : function (type, force_update) {
953       if (typeof this['cached_' + type] === 'undefined' || force_update) {
954         this['update_' + type]();
955       }
956
957       return this['cached_' + type];
958     },
959
960     update_images : function () {
961       var images = this.S('img[' + this.data_attr + ']'),
962           count = images.length,
963           i = count,
964           loaded_count = 0,
965           data_attr = this.data_attr;
966
967       this.cache = {};
968       this.cached_images = [];
969       this.images_loaded = (count === 0);
970
971       while (i--) {
972         loaded_count++;
973         if (images[i]) {
974           var str = images[i].getAttribute(data_attr) || '';
975
976           if (str.length > 0) {
977             this.cached_images.push(images[i]);
978           }
979         }
980
981         if (loaded_count === count) {
982           this.images_loaded = true;
983           this.enhance('images');
984         }
985       }
986
987       return this;
988     },
989
990     update_nodes : function () {
991       var nodes = this.S('[' + this.data_attr + ']').not('img'),
992           count = nodes.length,
993           i = count,
994           loaded_count = 0,
995           data_attr = this.data_attr;
996
997       this.cached_nodes = [];
998       this.nodes_loaded = (count === 0);
999
1000       while (i--) {
1001         loaded_count++;
1002         var str = nodes[i].getAttribute(data_attr) || '';
1003
1004         if (str.length > 0) {
1005           this.cached_nodes.push(nodes[i]);
1006         }
1007
1008         if (loaded_count === count) {
1009           this.nodes_loaded = true;
1010           this.enhance('nodes');
1011         }
1012       }
1013
1014       return this;
1015     },
1016
1017     enhance : function (type) {
1018       var i = this['cached_' + type].length;
1019
1020       while (i--) {
1021         this.object($(this['cached_' + type][i]));
1022       }
1023
1024       return $(window).trigger('resize').trigger('resize.fndtn.interchange');
1025     },
1026
1027     convert_directive : function (directive) {
1028
1029       var trimmed = this.trim(directive);
1030
1031       if (trimmed.length > 0) {
1032         return trimmed;
1033       }
1034
1035       return 'replace';
1036     },
1037
1038     parse_scenario : function (scenario) {
1039       // This logic had to be made more complex since some users were using commas in the url path
1040       // So we cannot simply just split on a comma
1041       var directive_match = scenario[0].match(/(.+),\s*(\w+)\s*$/),
1042       media_query         = scenario[1];
1043
1044       if (directive_match) {
1045         var path  = directive_match[1],
1046         directive = directive_match[2];
1047       } else {
1048         var cached_split = scenario[0].split(/,\s*$/),
1049         path             = cached_split[0],
1050         directive        = '';
1051       }
1052
1053       return [this.trim(path), this.convert_directive(directive), this.trim(media_query)];
1054     },
1055
1056     object : function (el) {
1057       var raw_arr = this.parse_data_attr(el),
1058           scenarios = [],
1059           i = raw_arr.length;
1060
1061       if (i > 0) {
1062         while (i--) {
1063           var split = raw_arr[i].split(/\(([^\)]*?)(\))$/);
1064
1065           if (split.length > 1) {
1066             var params = this.parse_scenario(split);
1067             scenarios.push(params);
1068           }
1069         }
1070       }
1071
1072       return this.store(el, scenarios);
1073     },
1074
1075     store : function (el, scenarios) {
1076       var uuid = this.random_str(),
1077           current_uuid = el.data(this.add_namespace('uuid', true));
1078
1079       if (this.cache[current_uuid]) {
1080         return this.cache[current_uuid];
1081       }
1082
1083       el.attr(this.add_namespace('data-uuid'), uuid);
1084
1085       return this.cache[uuid] = scenarios;
1086     },
1087
1088     trim : function (str) {
1089
1090       if (typeof str === 'string') {
1091         return $.trim(str);
1092       }
1093
1094       return str;
1095     },
1096
1097     set_data_attr : function (init) {
1098       if (init) {
1099         if (this.namespace.length > 0) {
1100           return this.namespace + '-' + this.settings.load_attr;
1101         }
1102
1103         return this.settings.load_attr;
1104       }
1105
1106       if (this.namespace.length > 0) {
1107         return 'data-' + this.namespace + '-' + this.settings.load_attr;
1108       }
1109
1110       return 'data-' + this.settings.load_attr;
1111     },
1112
1113     parse_data_attr : function (el) {
1114       var raw = el.attr(this.attr_name()).split(/\[(.*?)\]/),
1115           i = raw.length,
1116           output = [];
1117
1118       while (i--) {
1119         if (raw[i].replace(/[\W\d]+/, '').length > 4) {
1120           output.push(raw[i]);
1121         }
1122       }
1123
1124       return output;
1125     },
1126
1127     reflow : function () {
1128       this.load('images', true);
1129       this.load('nodes', true);
1130     }
1131
1132   };
1133
1134 }(jQuery, window, window.document));
1135 ;(function ($, window, document, undefined) {
1136   'use strict';
1137
1138   Foundation.libs.accordion = {
1139     name : 'accordion',
1140
1141     version : '5.5.1',
1142
1143     settings : {
1144       content_class : 'content',
1145       active_class : 'active',
1146       multi_expand : false,
1147       toggleable : true,
1148       callback : function () {}
1149     },
1150
1151     init : function (scope, method, options) {
1152       this.bindings(method, options);
1153     },
1154
1155     events : function () {
1156       var self = this;
1157       var S = this.S;
1158       S(this.scope)
1159       .off('.fndtn.accordion')
1160       .on('click.fndtn.accordion', '[' + this.attr_name() + '] > .accordion-navigation > a', function (e) {
1161         var accordion = S(this).closest('[' + self.attr_name() + ']'),
1162             groupSelector = self.attr_name() + '=' + accordion.attr(self.attr_name()),
1163             settings = accordion.data(self.attr_name(true) + '-init') || self.settings,
1164             target = S('#' + this.href.split('#')[1]),
1165             aunts = $('> .accordion-navigation', accordion),
1166             siblings = aunts.children('.' + settings.content_class),
1167             active_content = siblings.filter('.' + settings.active_class);
1168
1169         e.preventDefault();
1170
1171         if (accordion.attr(self.attr_name())) {
1172           siblings = siblings.add('[' + groupSelector + '] dd > ' + '.' + settings.content_class);
1173           aunts = aunts.add('[' + groupSelector + '] .accordion-navigation');
1174         }
1175
1176         if (settings.toggleable && target.is(active_content)) {
1177           target.parent('.accordion-navigation').toggleClass(settings.active_class, false);
1178           target.toggleClass(settings.active_class, false);
1179           settings.callback(target);
1180           target.triggerHandler('toggled', [accordion]);
1181           accordion.triggerHandler('toggled', [target]);
1182           return;
1183         }
1184
1185         if (!settings.multi_expand) {
1186           siblings.removeClass(settings.active_class);
1187           aunts.removeClass(settings.active_class);
1188         }
1189
1190         target.addClass(settings.active_class).parent().addClass(settings.active_class);
1191         settings.callback(target);
1192         target.triggerHandler('toggled', [accordion]);
1193         accordion.triggerHandler('toggled', [target]);
1194       });
1195     },
1196
1197     off : function () {},
1198
1199     reflow : function () {}
1200   };
1201 }(jQuery, window, window.document));
1202 ;(function ($, window, document, undefined) {
1203   'use strict';
1204
1205   Foundation.libs.dropdown = {
1206     name : 'dropdown',
1207
1208     version : '5.5.1',
1209
1210     settings : {
1211       active_class : 'open',
1212       disabled_class : 'disabled',
1213       mega_class : 'mega',
1214       align : 'bottom',
1215       is_hover : false,
1216       hover_timeout : 150,
1217       opened : function () {},
1218       closed : function () {}
1219     },
1220
1221     init : function (scope, method, options) {
1222       Foundation.inherit(this, 'throttle');
1223
1224       $.extend(true, this.settings, method, options);
1225       this.bindings(method, options);
1226     },
1227
1228     events : function (scope) {
1229       var self = this,
1230           S = self.S;
1231
1232       S(this.scope)
1233         .off('.dropdown')
1234         .on('click.fndtn.dropdown', '[' + this.attr_name() + ']', function (e) {
1235           var settings = S(this).data(self.attr_name(true) + '-init') || self.settings;
1236           if (!settings.is_hover || Modernizr.touch) {
1237             e.preventDefault();
1238             if (S(this).parent('[data-reveal-id]')) {
1239               e.stopPropagation();
1240             }
1241             self.toggle($(this));
1242           }
1243         })
1244         .on('mouseenter.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) {
1245           var $this = S(this),
1246               dropdown,
1247               target;
1248
1249           clearTimeout(self.timeout);
1250
1251           if ($this.data(self.data_attr())) {
1252             dropdown = S('#' + $this.data(self.data_attr()));
1253             target = $this;
1254           } else {
1255             dropdown = $this;
1256             target = S('[' + self.attr_name() + '="' + dropdown.attr('id') + '"]');
1257           }
1258
1259           var settings = target.data(self.attr_name(true) + '-init') || self.settings;
1260
1261           if (S(e.currentTarget).data(self.data_attr()) && settings.is_hover) {
1262             self.closeall.call(self);
1263           }
1264
1265           if (settings.is_hover) {
1266             self.open.apply(self, [dropdown, target]);
1267           }
1268         })
1269         .on('mouseleave.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) {
1270           var $this = S(this);
1271           var settings;
1272
1273           if ($this.data(self.data_attr())) {
1274               settings = $this.data(self.data_attr(true) + '-init') || self.settings;
1275           } else {
1276               var target   = S('[' + self.attr_name() + '="' + S(this).attr('id') + '"]'),
1277                   settings = target.data(self.attr_name(true) + '-init') || self.settings;
1278           }
1279
1280           self.timeout = setTimeout(function () {
1281             if ($this.data(self.data_attr())) {
1282               if (settings.is_hover) {
1283                 self.close.call(self, S('#' + $this.data(self.data_attr())));
1284               }
1285             } else {
1286               if (settings.is_hover) {
1287                 self.close.call(self, $this);
1288               }
1289             }
1290           }.bind(this), settings.hover_timeout);
1291         })
1292         .on('click.fndtn.dropdown', function (e) {
1293           var parent = S(e.target).closest('[' + self.attr_name() + '-content]');
1294           var links  = parent.find('a');
1295
1296           if (links.length > 0 && parent.attr('aria-autoclose') !== 'false') {
1297               self.close.call(self, S('[' + self.attr_name() + '-content]'));
1298           }
1299
1300           if (e.target !== document && !$.contains(document.documentElement, e.target)) {
1301             return;
1302           }
1303
1304           if (S(e.target).closest('[' + self.attr_name() + ']').length > 0) {
1305             return;
1306           }
1307
1308           if (!(S(e.target).data('revealId')) &&
1309             (parent.length > 0 && (S(e.target).is('[' + self.attr_name() + '-content]') ||
1310               $.contains(parent.first()[0], e.target)))) {
1311             e.stopPropagation();
1312             return;
1313           }
1314
1315           self.close.call(self, S('[' + self.attr_name() + '-content]'));
1316         })
1317         .on('opened.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () {
1318           self.settings.opened.call(this);
1319         })
1320         .on('closed.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () {
1321           self.settings.closed.call(this);
1322         });
1323
1324       S(window)
1325         .off('.dropdown')
1326         .on('resize.fndtn.dropdown', self.throttle(function () {
1327           self.resize.call(self);
1328         }, 50));
1329
1330       this.resize();
1331     },
1332
1333     close : function (dropdown) {
1334       var self = this;
1335       dropdown.each(function () {
1336         var original_target = $('[' + self.attr_name() + '=' + dropdown[0].id + ']') || $('aria-controls=' + dropdown[0].id + ']');
1337         original_target.attr('aria-expanded', 'false');
1338         if (self.S(this).hasClass(self.settings.active_class)) {
1339           self.S(this)
1340             .css(Foundation.rtl ? 'right' : 'left', '-99999px')
1341             .attr('aria-hidden', 'true')
1342             .removeClass(self.settings.active_class)
1343             .prev('[' + self.attr_name() + ']')
1344             .removeClass(self.settings.active_class)
1345             .removeData('target');
1346
1347           self.S(this).trigger('closed').trigger('closed.fndtn.dropdown', [dropdown]);
1348         }
1349       });
1350       dropdown.removeClass('f-open-' + this.attr_name(true));
1351     },
1352
1353     closeall : function () {
1354       var self = this;
1355       $.each(self.S('.f-open-' + this.attr_name(true)), function () {
1356         self.close.call(self, self.S(this));
1357       });
1358     },
1359
1360     open : function (dropdown, target) {
1361       this
1362         .css(dropdown
1363         .addClass(this.settings.active_class), target);
1364       dropdown.prev('[' + this.attr_name() + ']').addClass(this.settings.active_class);
1365       dropdown.data('target', target.get(0)).trigger('opened').trigger('opened.fndtn.dropdown', [dropdown, target]);
1366       dropdown.attr('aria-hidden', 'false');
1367       target.attr('aria-expanded', 'true');
1368       dropdown.focus();
1369       dropdown.addClass('f-open-' + this.attr_name(true));
1370     },
1371
1372     data_attr : function () {
1373       if (this.namespace.length > 0) {
1374         return this.namespace + '-' + this.name;
1375       }
1376
1377       return this.name;
1378     },
1379
1380     toggle : function (target) {
1381       if (target.hasClass(this.settings.disabled_class)) {
1382         return;
1383       }
1384       var dropdown = this.S('#' + target.data(this.data_attr()));
1385       if (dropdown.length === 0) {
1386         // No dropdown found, not continuing
1387         return;
1388       }
1389
1390       this.close.call(this, this.S('[' + this.attr_name() + '-content]').not(dropdown));
1391
1392       if (dropdown.hasClass(this.settings.active_class)) {
1393         this.close.call(this, dropdown);
1394         if (dropdown.data('target') !== target.get(0)) {
1395           this.open.call(this, dropdown, target);
1396         }
1397       } else {
1398         this.open.call(this, dropdown, target);
1399       }
1400     },
1401
1402     resize : function () {
1403       var dropdown = this.S('[' + this.attr_name() + '-content].open');
1404       var target = $(dropdown.data("target"));
1405
1406       if (dropdown.length && target.length) {
1407         this.css(dropdown, target);
1408       }
1409     },
1410
1411     css : function (dropdown, target) {
1412       var left_offset = Math.max((target.width() - dropdown.width()) / 2, 8),
1413           settings = target.data(this.attr_name(true) + '-init') || this.settings;
1414
1415       this.clear_idx();
1416
1417       if (this.small()) {
1418         var p = this.dirs.bottom.call(dropdown, target, settings);
1419
1420         dropdown.attr('style', '').removeClass('drop-left drop-right drop-top').css({
1421           position : 'absolute',
1422           width : '95%',
1423           'max-width' : 'none',
1424           top : p.top
1425         });
1426
1427         dropdown.css(Foundation.rtl ? 'right' : 'left', left_offset);
1428       } else {
1429
1430         this.style(dropdown, target, settings);
1431       }
1432
1433       return dropdown;
1434     },
1435
1436     style : function (dropdown, target, settings) {
1437       var css = $.extend({position : 'absolute'},
1438         this.dirs[settings.align].call(dropdown, target, settings));
1439
1440       dropdown.attr('style', '').css(css);
1441     },
1442
1443     // return CSS property object
1444     // `this` is the dropdown
1445     dirs : {
1446       // Calculate target offset
1447       _base : function (t) {
1448         var o_p = this.offsetParent(),
1449             o = o_p.offset(),
1450             p = t.offset();
1451
1452         p.top -= o.top;
1453         p.left -= o.left;
1454
1455         //set some flags on the p object to pass along
1456         p.missRight = false;
1457         p.missTop = false;
1458         p.missLeft = false;
1459         p.leftRightFlag = false;
1460
1461         //lets see if the panel will be off the screen
1462         //get the actual width of the page and store it
1463         var actualBodyWidth;
1464         if (document.getElementsByClassName('row')[0]) {
1465           actualBodyWidth = document.getElementsByClassName('row')[0].clientWidth;
1466         } else {
1467           actualBodyWidth = window.outerWidth;
1468         }
1469
1470         var actualMarginWidth = (window.outerWidth - actualBodyWidth) / 2;
1471         var actualBoundary = actualBodyWidth;
1472
1473         if (!this.hasClass('mega')) {
1474           //miss top
1475           if (t.offset().top <= this.outerHeight()) {
1476             p.missTop = true;
1477             actualBoundary = window.outerWidth - actualMarginWidth;
1478             p.leftRightFlag = true;
1479           }
1480
1481           //miss right
1482           if (t.offset().left + this.outerWidth() > t.offset().left + actualMarginWidth && t.offset().left - actualMarginWidth > this.outerWidth()) {
1483             p.missRight = true;
1484             p.missLeft = false;
1485           }
1486
1487           //miss left
1488           if (t.offset().left - this.outerWidth() <= 0) {
1489             p.missLeft = true;
1490             p.missRight = false;
1491           }
1492         }
1493
1494         return p;
1495       },
1496
1497       top : function (t, s) {
1498         var self = Foundation.libs.dropdown,
1499             p = self.dirs._base.call(this, t);
1500
1501         this.addClass('drop-top');
1502
1503         if (p.missTop == true) {
1504           p.top = p.top + t.outerHeight() + this.outerHeight();
1505           this.removeClass('drop-top');
1506         }
1507
1508         if (p.missRight == true) {
1509           p.left = p.left - this.outerWidth() + t.outerWidth();
1510         }
1511
1512         if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) {
1513           self.adjust_pip(this, t, s, p);
1514         }
1515
1516         if (Foundation.rtl) {
1517           return {left : p.left - this.outerWidth() + t.outerWidth(),
1518             top : p.top - this.outerHeight()};
1519         }
1520
1521         return {left : p.left, top : p.top - this.outerHeight()};
1522       },
1523
1524       bottom : function (t, s) {
1525         var self = Foundation.libs.dropdown,
1526             p = self.dirs._base.call(this, t);
1527
1528         if (p.missRight == true) {
1529           p.left = p.left - this.outerWidth() + t.outerWidth();
1530         }
1531
1532         if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) {
1533           self.adjust_pip(this, t, s, p);
1534         }
1535
1536         if (self.rtl) {
1537           return {left : p.left - this.outerWidth() + t.outerWidth(), top : p.top + t.outerHeight()};
1538         }
1539
1540         return {left : p.left, top : p.top + t.outerHeight()};
1541       },
1542
1543       left : function (t, s) {
1544         var p = Foundation.libs.dropdown.dirs._base.call(this, t);
1545
1546         this.addClass('drop-left');
1547
1548         if (p.missLeft == true) {
1549           p.left =  p.left + this.outerWidth();
1550           p.top = p.top + t.outerHeight();
1551           this.removeClass('drop-left');
1552         }
1553
1554         return {left : p.left - this.outerWidth(), top : p.top};
1555       },
1556
1557       right : function (t, s) {
1558         var p = Foundation.libs.dropdown.dirs._base.call(this, t);
1559
1560         this.addClass('drop-right');
1561
1562         if (p.missRight == true) {
1563           p.left = p.left - this.outerWidth();
1564           p.top = p.top + t.outerHeight();
1565           this.removeClass('drop-right');
1566         } else {
1567           p.triggeredRight = true;
1568         }
1569
1570         var self = Foundation.libs.dropdown;
1571
1572         if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) {
1573           self.adjust_pip(this, t, s, p);
1574         }
1575
1576         return {left : p.left + t.outerWidth(), top : p.top};
1577       }
1578     },
1579
1580     // Insert rule to style psuedo elements
1581     adjust_pip : function (dropdown, target, settings, position) {
1582       var sheet = Foundation.stylesheet,
1583           pip_offset_base = 8;
1584
1585       if (dropdown.hasClass(settings.mega_class)) {
1586         pip_offset_base = position.left + (target.outerWidth() / 2) - 8;
1587       } else if (this.small()) {
1588         pip_offset_base += position.left - 8;
1589       }
1590
1591       this.rule_idx = sheet.cssRules.length;
1592
1593       //default
1594       var sel_before = '.f-dropdown.open:before',
1595           sel_after  = '.f-dropdown.open:after',
1596           css_before = 'left: ' + pip_offset_base + 'px;',
1597           css_after  = 'left: ' + (pip_offset_base - 1) + 'px;';
1598
1599       if (position.missRight == true) {
1600         pip_offset_base = dropdown.outerWidth() - 23;
1601         sel_before = '.f-dropdown.open:before',
1602         sel_after  = '.f-dropdown.open:after',
1603         css_before = 'left: ' + pip_offset_base + 'px;',
1604         css_after  = 'left: ' + (pip_offset_base - 1) + 'px;';
1605       }
1606
1607       //just a case where right is fired, but its not missing right
1608       if (position.triggeredRight == true) {
1609         sel_before = '.f-dropdown.open:before',
1610         sel_after  = '.f-dropdown.open:after',
1611         css_before = 'left:-12px;',
1612         css_after  = 'left:-14px;';
1613       }
1614
1615       if (sheet.insertRule) {
1616         sheet.insertRule([sel_before, '{', css_before, '}'].join(' '), this.rule_idx);
1617         sheet.insertRule([sel_after, '{', css_after, '}'].join(' '), this.rule_idx + 1);
1618       } else {
1619         sheet.addRule(sel_before, css_before, this.rule_idx);
1620         sheet.addRule(sel_after, css_after, this.rule_idx + 1);
1621       }
1622     },
1623
1624     // Remove old dropdown rule index
1625     clear_idx : function () {
1626       var sheet = Foundation.stylesheet;
1627
1628       if (typeof this.rule_idx !== 'undefined') {
1629         sheet.deleteRule(this.rule_idx);
1630         sheet.deleteRule(this.rule_idx);
1631         delete this.rule_idx;
1632       }
1633     },
1634
1635     small : function () {
1636       return matchMedia(Foundation.media_queries.small).matches &&
1637         !matchMedia(Foundation.media_queries.medium).matches;
1638     },
1639
1640     off : function () {
1641       this.S(this.scope).off('.fndtn.dropdown');
1642       this.S('html, body').off('.fndtn.dropdown');
1643       this.S(window).off('.fndtn.dropdown');
1644       this.S('[data-dropdown-content]').off('.fndtn.dropdown');
1645     },
1646
1647     reflow : function () {}
1648   };
1649 }(jQuery, window, window.document));
1650 ;(function ($, window, document, undefined) {
1651   'use strict';
1652
1653   Foundation.libs.offcanvas = {
1654     name : 'offcanvas',
1655
1656     version : '5.5.1',
1657
1658     settings : {
1659       open_method : 'move',
1660       close_on_click : false
1661     },
1662
1663     init : function (scope, method, options) {
1664       this.bindings(method, options);
1665     },
1666
1667     events : function () {
1668       var self = this,
1669           S = self.S,
1670           move_class = '',
1671           right_postfix = '',
1672           left_postfix = '';
1673
1674       if (this.settings.open_method === 'move') {
1675         move_class = 'move-';
1676         right_postfix = 'right';
1677         left_postfix = 'left';
1678       } else if (this.settings.open_method === 'overlap_single') {
1679         move_class = 'offcanvas-overlap-';
1680         right_postfix = 'right';
1681         left_postfix = 'left';
1682       } else if (this.settings.open_method === 'overlap') {
1683         move_class = 'offcanvas-overlap';
1684       }
1685
1686       S(this.scope).off('.offcanvas')
1687         .on('click.fndtn.offcanvas', '.left-off-canvas-toggle', function (e) {
1688           self.click_toggle_class(e, move_class + right_postfix);
1689           if (self.settings.open_method !== 'overlap') {
1690             S('.left-submenu').removeClass(move_class + right_postfix);
1691           }
1692           $('.left-off-canvas-toggle').attr('aria-expanded', 'true');
1693         })
1694         .on('click.fndtn.offcanvas', '.left-off-canvas-menu a', function (e) {
1695           var settings = self.get_settings(e);
1696           var parent = S(this).parent();
1697
1698           if (settings.close_on_click && !parent.hasClass('has-submenu') && !parent.hasClass('back')) {
1699             self.hide.call(self, move_class + right_postfix, self.get_wrapper(e));
1700             parent.parent().removeClass(move_class + right_postfix);
1701           } else if (S(this).parent().hasClass('has-submenu')) {
1702             e.preventDefault();
1703             S(this).siblings('.left-submenu').toggleClass(move_class + right_postfix);
1704           } else if (parent.hasClass('back')) {
1705             e.preventDefault();
1706             parent.parent().removeClass(move_class + right_postfix);
1707           }
1708           $('.left-off-canvas-toggle').attr('aria-expanded', 'true');
1709         })
1710         .on('click.fndtn.offcanvas', '.right-off-canvas-toggle', function (e) {
1711           self.click_toggle_class(e, move_class + left_postfix);
1712           if (self.settings.open_method !== 'overlap') {
1713             S('.right-submenu').removeClass(move_class + left_postfix);
1714           }
1715           $('.right-off-canvas-toggle').attr('aria-expanded', 'true');
1716         })
1717         .on('click.fndtn.offcanvas', '.right-off-canvas-menu a', function (e) {
1718           var settings = self.get_settings(e);
1719           var parent = S(this).parent();
1720
1721           if (settings.close_on_click && !parent.hasClass('has-submenu') && !parent.hasClass('back')) {
1722             self.hide.call(self, move_class + left_postfix, self.get_wrapper(e));
1723             parent.parent().removeClass(move_class + left_postfix);
1724           } else if (S(this).parent().hasClass('has-submenu')) {
1725             e.preventDefault();
1726             S(this).siblings('.right-submenu').toggleClass(move_class + left_postfix);
1727           } else if (parent.hasClass('back')) {
1728             e.preventDefault();
1729             parent.parent().removeClass(move_class + left_postfix);
1730           }
1731           $('.right-off-canvas-toggle').attr('aria-expanded', 'true');
1732         })
1733         .on('click.fndtn.offcanvas', '.exit-off-canvas', function (e) {
1734           self.click_remove_class(e, move_class + left_postfix);
1735           S('.right-submenu').removeClass(move_class + left_postfix);
1736           if (right_postfix) {
1737             self.click_remove_class(e, move_class + right_postfix);
1738             S('.left-submenu').removeClass(move_class + left_postfix);
1739           }
1740           $('.right-off-canvas-toggle').attr('aria-expanded', 'true');
1741         })
1742         .on('click.fndtn.offcanvas', '.exit-off-canvas', function (e) {
1743           self.click_remove_class(e, move_class + left_postfix);
1744           $('.left-off-canvas-toggle').attr('aria-expanded', 'false');
1745           if (right_postfix) {
1746             self.click_remove_class(e, move_class + right_postfix);
1747             $('.right-off-canvas-toggle').attr('aria-expanded', 'false');
1748           }
1749         });
1750     },
1751
1752     toggle : function (class_name, $off_canvas) {
1753       $off_canvas = $off_canvas || this.get_wrapper();
1754       if ($off_canvas.is('.' + class_name)) {
1755         this.hide(class_name, $off_canvas);
1756       } else {
1757         this.show(class_name, $off_canvas);
1758       }
1759     },
1760
1761     show : function (class_name, $off_canvas) {
1762       $off_canvas = $off_canvas || this.get_wrapper();
1763       $off_canvas.trigger('open').trigger('open.fndtn.offcanvas');
1764       $off_canvas.addClass(class_name);
1765     },
1766
1767     hide : function (class_name, $off_canvas) {
1768       $off_canvas = $off_canvas || this.get_wrapper();
1769       $off_canvas.trigger('close').trigger('close.fndtn.offcanvas');
1770       $off_canvas.removeClass(class_name);
1771     },
1772
1773     click_toggle_class : function (e, class_name) {
1774       e.preventDefault();
1775       var $off_canvas = this.get_wrapper(e);
1776       this.toggle(class_name, $off_canvas);
1777     },
1778
1779     click_remove_class : function (e, class_name) {
1780       e.preventDefault();
1781       var $off_canvas = this.get_wrapper(e);
1782       this.hide(class_name, $off_canvas);
1783     },
1784
1785     get_settings : function (e) {
1786       var offcanvas  = this.S(e.target).closest('[' + this.attr_name() + ']');
1787       return offcanvas.data(this.attr_name(true) + '-init') || this.settings;
1788     },
1789
1790     get_wrapper : function (e) {
1791       var $off_canvas = this.S(e ? e.target : this.scope).closest('.off-canvas-wrap');
1792
1793       if ($off_canvas.length === 0) {
1794         $off_canvas = this.S('.off-canvas-wrap');
1795       }
1796       return $off_canvas;
1797     },
1798
1799     reflow : function () {}
1800   };
1801 }(jQuery, window, window.document));
1802 ;(function ($, window, document, undefined) {
1803   'use strict';
1804
1805   Foundation.libs.tab = {
1806     name : 'tab',
1807
1808     version : '5.5.1',
1809
1810     settings : {
1811       active_class : 'active',
1812       callback : function () {},
1813       deep_linking : false,
1814       scroll_to_content : true,
1815       is_hover : false
1816     },
1817
1818     default_tab_hashes : [],
1819
1820     init : function (scope, method, options) {
1821       var self = this,
1822           S = this.S;
1823
1824       this.bindings(method, options);
1825
1826       // store the initial href, which is used to allow correct behaviour of the
1827       // browser back button when deep linking is turned on.
1828       self.entry_location = window.location.href;
1829
1830       this.handle_location_hash_change();
1831
1832       // Store the default active tabs which will be referenced when the
1833       // location hash is absent, as in the case of navigating the tabs and
1834       // returning to the first viewing via the browser Back button.
1835       S('[' + this.attr_name() + '] > .active > a', this.scope).each(function () {
1836         self.default_tab_hashes.push(this.hash);
1837       });
1838     },
1839
1840     events : function () {
1841       var self = this,
1842           S = this.S;
1843
1844       var usual_tab_behavior =  function (e) {
1845           var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
1846           if (!settings.is_hover || Modernizr.touch) {
1847             e.preventDefault();
1848             e.stopPropagation();
1849             self.toggle_active_tab(S(this).parent());
1850           }
1851         };
1852
1853       S(this.scope)
1854         .off('.tab')
1855         // Click event: tab title
1856         .on('focus.fndtn.tab', '[' + this.attr_name() + '] > * > a', usual_tab_behavior )
1857         .on('click.fndtn.tab', '[' + this.attr_name() + '] > * > a', usual_tab_behavior )
1858         // Hover event: tab title
1859         .on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > * > a', function (e) {
1860           var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
1861           if (settings.is_hover) {
1862             self.toggle_active_tab(S(this).parent());
1863           }
1864         });
1865
1866       // Location hash change event
1867       S(window).on('hashchange.fndtn.tab', function (e) {
1868         e.preventDefault();
1869         self.handle_location_hash_change();
1870       });
1871     },
1872
1873     handle_location_hash_change : function () {
1874
1875       var self = this,
1876           S = this.S;
1877
1878       S('[' + this.attr_name() + ']', this.scope).each(function () {
1879         var settings = S(this).data(self.attr_name(true) + '-init');
1880         if (settings.deep_linking) {
1881           // Match the location hash to a label
1882           var hash;
1883           if (settings.scroll_to_content) {
1884             hash = self.scope.location.hash;
1885           } else {
1886             // prefix the hash to prevent anchor scrolling
1887             hash = self.scope.location.hash.replace('fndtn-', '');
1888           }
1889           if (hash != '') {
1890             // Check whether the location hash references a tab content div or
1891             // another element on the page (inside or outside the tab content div)
1892             var hash_element = S(hash);
1893             if (hash_element.hasClass('content') && hash_element.parent().hasClass('tabs-content')) {
1894               // Tab content div
1895               self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + hash + ']').parent());
1896             } else {
1897               // Not the tab content div. If inside the tab content, find the
1898               // containing tab and toggle it as active.
1899               var hash_tab_container_id = hash_element.closest('.content').attr('id');
1900               if (hash_tab_container_id != undefined) {
1901                 self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=#' + hash_tab_container_id + ']').parent(), hash);
1902               }
1903             }
1904           } else {
1905             // Reference the default tab hashes which were initialized in the init function
1906             for (var ind = 0; ind < self.default_tab_hashes.length; ind++) {
1907               self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + self.default_tab_hashes[ind] + ']').parent());
1908             }
1909           }
1910         }
1911        });
1912      },
1913
1914     toggle_active_tab : function (tab, location_hash) {
1915       var self = this,
1916           S = self.S,
1917           tabs = tab.closest('[' + this.attr_name() + ']'),
1918           tab_link = tab.find('a'),
1919           anchor = tab.children('a').first(),
1920           target_hash = '#' + anchor.attr('href').split('#')[1],
1921           target = S(target_hash),
1922           siblings = tab.siblings(),
1923           settings = tabs.data(this.attr_name(true) + '-init'),
1924           interpret_keyup_action = function (e) {
1925             // Light modification of Heydon Pickering's Practical ARIA Examples: http://heydonworks.com/practical_aria_examples/js/a11y.js
1926
1927             // define current, previous and next (possible) tabs
1928
1929             var $original = $(this);
1930             var $prev = $(this).parents('li').prev().children('[role="tab"]');
1931             var $next = $(this).parents('li').next().children('[role="tab"]');
1932             var $target;
1933
1934             // find the direction (prev or next)
1935
1936             switch (e.keyCode) {
1937               case 37:
1938                 $target = $prev;
1939                 break;
1940               case 39:
1941                 $target = $next;
1942                 break;
1943               default:
1944                 $target = false
1945                   break;
1946             }
1947
1948             if ($target.length) {
1949               $original.attr({
1950                 'tabindex' : '-1',
1951                 'aria-selected' : null
1952               });
1953               $target.attr({
1954                 'tabindex' : '0',
1955                 'aria-selected' : true
1956               }).focus();
1957             }
1958
1959             // Hide panels
1960
1961             $('[role="tabpanel"]')
1962               .attr('aria-hidden', 'true');
1963
1964             // Show panel which corresponds to target
1965
1966             $('#' + $(document.activeElement).attr('href').substring(1))
1967               .attr('aria-hidden', null);
1968
1969           },
1970           go_to_hash = function(hash) {
1971             // This function allows correct behaviour of the browser's back button when deep linking is enabled. Without it
1972             // the user would get continually redirected to the default hash.
1973             var is_entry_location = window.location.href === self.entry_location,
1974                 default_hash = settings.scroll_to_content ? self.default_tab_hashes[0] : is_entry_location ? window.location.hash :'fndtn-' + self.default_tab_hashes[0].replace('#', '')
1975
1976             if (!(is_entry_location && hash === default_hash)) {
1977               window.location.hash = hash;
1978             }
1979           };
1980
1981       // allow usage of data-tab-content attribute instead of href
1982       if (S(this).data(this.data_attr('tab-content'))) {
1983         target_hash = '#' + S(this).data(this.data_attr('tab-content')).split('#')[1];
1984         target = S(target_hash);
1985       }
1986
1987       if (settings.deep_linking) {
1988
1989         if (settings.scroll_to_content) {
1990
1991           // retain current hash to scroll to content
1992           go_to_hash(location_hash || target_hash);
1993
1994           if (location_hash == undefined || location_hash == target_hash) {
1995             tab.parent()[0].scrollIntoView();
1996           } else {
1997             S(target_hash)[0].scrollIntoView();
1998           }
1999         } else {
2000           // prefix the hashes so that the browser doesn't scroll down
2001           if (location_hash != undefined) {
2002             go_to_hash('fndtn-' + location_hash.replace('#', ''));
2003           } else {
2004             go_to_hash('fndtn-' + target_hash.replace('#', ''));
2005           }
2006         }
2007       }
2008
2009       // WARNING: The activation and deactivation of the tab content must
2010       // occur after the deep linking in order to properly refresh the browser
2011       // window (notably in Chrome).
2012       // Clean up multiple attr instances to done once
2013       tab.addClass(settings.active_class).triggerHandler('opened');
2014       tab_link.attr({'aria-selected' : 'true',  tabindex : 0});
2015       siblings.removeClass(settings.active_class)
2016       siblings.find('a').attr({'aria-selected' : 'false',  tabindex : -1});
2017       target.siblings().removeClass(settings.active_class).attr({'aria-hidden' : 'true',  tabindex : -1});
2018       target.addClass(settings.active_class).attr('aria-hidden', 'false').removeAttr('tabindex');
2019       settings.callback(tab);
2020       target.triggerHandler('toggled', [tab]);
2021       tabs.triggerHandler('toggled', [target]);
2022
2023       tab_link.off('keydown').on('keydown', interpret_keyup_action );
2024     },
2025
2026     data_attr : function (str) {
2027       if (this.namespace.length > 0) {
2028         return this.namespace + '-' + str;
2029       }
2030
2031       return str;
2032     },
2033
2034     off : function () {},
2035
2036     reflow : function () {}
2037   };
2038 }(jQuery, window, window.document));
2039 ;(function ($, window, document, undefined) {
2040   'use strict';
2041
2042   Foundation.libs.tooltip = {
2043     name : 'tooltip',
2044
2045     version : '5.5.1',
2046
2047     settings : {
2048       additional_inheritable_classes : [],
2049       tooltip_class : '.tooltip',
2050       append_to : 'body',
2051       touch_close_text : 'Tap To Close',
2052       disable_for_touch : false,
2053       hover_delay : 200,
2054       show_on : 'all',
2055       tip_template : function (selector, content) {
2056         return '<span data-selector="' + selector + '" id="' + selector + '" class="'
2057           + Foundation.libs.tooltip.settings.tooltip_class.substring(1)
2058           + '" role="tooltip">' + content + '<span class="nub"></span></span>';
2059       }
2060     },
2061
2062     cache : {},
2063
2064     init : function (scope, method, options) {
2065       Foundation.inherit(this, 'random_str');
2066       this.bindings(method, options);
2067     },
2068
2069     should_show : function (target, tip) {
2070       var settings = $.extend({}, this.settings, this.data_options(target));
2071
2072       if (settings.show_on === 'all') {
2073         return true;
2074       } else if (this.small() && settings.show_on === 'small') {
2075         return true;
2076       } else if (this.medium() && settings.show_on === 'medium') {
2077         return true;
2078       } else if (this.large() && settings.show_on === 'large') {
2079         return true;
2080       }
2081       return false;
2082     },
2083
2084     medium : function () {
2085       return matchMedia(Foundation.media_queries['medium']).matches;
2086     },
2087
2088     large : function () {
2089       return matchMedia(Foundation.media_queries['large']).matches;
2090     },
2091
2092     events : function (instance) {
2093       var self = this,
2094           S = self.S;
2095
2096       self.create(this.S(instance));
2097
2098       $(this.scope)
2099         .off('.tooltip')
2100         .on('mouseenter.fndtn.tooltip mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip',
2101           '[' + this.attr_name() + ']', function (e) {
2102           var $this = S(this),
2103               settings = $.extend({}, self.settings, self.data_options($this)),
2104               is_touch = false;
2105
2106           if (Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type) && S(e.target).is('a')) {
2107             return false;
2108           }
2109
2110           if (/mouse/i.test(e.type) && self.ie_touch(e)) {
2111             return false;
2112           }
2113
2114           if ($this.hasClass('open')) {
2115             if (Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) {
2116               e.preventDefault();
2117             }
2118             self.hide($this);
2119           } else {
2120             if (settings.disable_for_touch && Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) {
2121               return;
2122             } else if (!settings.disable_for_touch && Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) {
2123               e.preventDefault();
2124               S(settings.tooltip_class + '.open').hide();
2125               is_touch = true;
2126             }
2127
2128             if (/enter|over/i.test(e.type)) {
2129               this.timer = setTimeout(function () {
2130                 var tip = self.showTip($this);
2131               }.bind(this), self.settings.hover_delay);
2132             } else if (e.type === 'mouseout' || e.type === 'mouseleave') {
2133               clearTimeout(this.timer);
2134               self.hide($this);
2135             } else {
2136               self.showTip($this);
2137             }
2138           }
2139         })
2140         .on('mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', '[' + this.attr_name() + '].open', function (e) {
2141           if (/mouse/i.test(e.type) && self.ie_touch(e)) {
2142             return false;
2143           }
2144
2145           if ($(this).data('tooltip-open-event-type') == 'touch' && e.type == 'mouseleave') {
2146             return;
2147           } else if ($(this).data('tooltip-open-event-type') == 'mouse' && /MSPointerDown|touchstart/i.test(e.type)) {
2148             self.convert_to_touch($(this));
2149           } else {
2150             self.hide($(this));
2151           }
2152         })
2153         .on('DOMNodeRemoved DOMAttrModified', '[' + this.attr_name() + ']:not(a)', function (e) {
2154           self.hide(S(this));
2155         });
2156     },
2157
2158     ie_touch : function (e) {
2159       // How do I distinguish between IE11 and Windows Phone 8?????
2160       return false;
2161     },
2162
2163     showTip : function ($target) {
2164       var $tip = this.getTip($target);
2165       if (this.should_show($target, $tip)) {
2166         return this.show($target);
2167       }
2168       return;
2169     },
2170
2171     getTip : function ($target) {
2172       var selector = this.selector($target),
2173           settings = $.extend({}, this.settings, this.data_options($target)),
2174           tip = null;
2175
2176       if (selector) {
2177         tip = this.S('span[data-selector="' + selector + '"]' + settings.tooltip_class);
2178       }
2179
2180       return (typeof tip === 'object') ? tip : false;
2181     },
2182
2183     selector : function ($target) {
2184       var id = $target.attr('id'),
2185           dataSelector = $target.attr(this.attr_name()) || $target.attr('data-selector');
2186
2187       if ((id && id.length < 1 || !id) && typeof dataSelector != 'string') {
2188         dataSelector = this.random_str(6);
2189         $target
2190           .attr('data-selector', dataSelector)
2191           .attr('aria-describedby', dataSelector);
2192       }
2193
2194       return (id && id.length > 0) ? id : dataSelector;
2195     },
2196
2197     create : function ($target) {
2198       var self = this,
2199           settings = $.extend({}, this.settings, this.data_options($target)),
2200           tip_template = this.settings.tip_template;
2201
2202       if (typeof settings.tip_template === 'string' && window.hasOwnProperty(settings.tip_template)) {
2203         tip_template = window[settings.tip_template];
2204       }
2205
2206       var $tip = $(tip_template(this.selector($target), $('<div></div>').html($target.attr('title')).html())),
2207           classes = this.inheritable_classes($target);
2208
2209       $tip.addClass(classes).appendTo(settings.append_to);
2210
2211       if (Modernizr.touch) {
2212         $tip.append('<span class="tap-to-close">' + settings.touch_close_text + '</span>');
2213         $tip.on('touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', function (e) {
2214           self.hide($target);
2215         });
2216       }
2217
2218       $target.removeAttr('title').attr('title', '');
2219     },
2220
2221     reposition : function (target, tip, classes) {
2222       var width, nub, nubHeight, nubWidth, column, objPos;
2223
2224       tip.css('visibility', 'hidden').show();
2225
2226       width = target.data('width');
2227       nub = tip.children('.nub');
2228       nubHeight = nub.outerHeight();
2229       nubWidth = nub.outerHeight();
2230
2231       if (this.small()) {
2232         tip.css({'width' : '100%'});
2233       } else {
2234         tip.css({'width' : (width) ? width : 'auto'});
2235       }
2236
2237       objPos = function (obj, top, right, bottom, left, width) {
2238         return obj.css({
2239           'top' : (top) ? top : 'auto',
2240           'bottom' : (bottom) ? bottom : 'auto',
2241           'left' : (left) ? left : 'auto',
2242           'right' : (right) ? right : 'auto'
2243         }).end();
2244       };
2245
2246       objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', target.offset().left);
2247
2248       if (this.small()) {
2249         objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', 12.5, $(this.scope).width());
2250         tip.addClass('tip-override');
2251         objPos(nub, -nubHeight, 'auto', 'auto', target.offset().left);
2252       } else {
2253         var left = target.offset().left;
2254         if (Foundation.rtl) {
2255           nub.addClass('rtl');
2256           left = target.offset().left + target.outerWidth() - tip.outerWidth();
2257         }
2258         objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', left);
2259         tip.removeClass('tip-override');
2260         if (classes && classes.indexOf('tip-top') > -1) {
2261           if (Foundation.rtl) {
2262             nub.addClass('rtl');
2263           }
2264           objPos(tip, (target.offset().top - tip.outerHeight()), 'auto', 'auto', left)
2265             .removeClass('tip-override');
2266         } else if (classes && classes.indexOf('tip-left') > -1) {
2267           objPos(tip, (target.offset().top + (target.outerHeight() / 2) - (tip.outerHeight() / 2)), 'auto', 'auto', (target.offset().left - tip.outerWidth() - nubHeight))
2268             .removeClass('tip-override');
2269           nub.removeClass('rtl');
2270         } else if (classes && classes.indexOf('tip-right') > -1) {
2271           objPos(tip, (target.offset().top + (target.outerHeight() / 2) - (tip.outerHeight() / 2)), 'auto', 'auto', (target.offset().left + target.outerWidth() + nubHeight))
2272             .removeClass('tip-override');
2273           nub.removeClass('rtl');
2274         }
2275       }
2276
2277       tip.css('visibility', 'visible').hide();
2278     },
2279
2280     small : function () {
2281       return matchMedia(Foundation.media_queries.small).matches &&
2282         !matchMedia(Foundation.media_queries.medium).matches;
2283     },
2284
2285     inheritable_classes : function ($target) {
2286       var settings = $.extend({}, this.settings, this.data_options($target)),
2287           inheritables = ['tip-top', 'tip-left', 'tip-bottom', 'tip-right', 'radius', 'round'].concat(settings.additional_inheritable_classes),
2288           classes = $target.attr('class'),
2289           filtered = classes ? $.map(classes.split(' '), function (el, i) {
2290             if ($.inArray(el, inheritables) !== -1) {
2291               return el;
2292             }
2293           }).join(' ') : '';
2294
2295       return $.trim(filtered);
2296     },
2297
2298     convert_to_touch : function ($target) {
2299       var self = this,
2300           $tip = self.getTip($target),
2301           settings = $.extend({}, self.settings, self.data_options($target));
2302
2303       if ($tip.find('.tap-to-close').length === 0) {
2304         $tip.append('<span class="tap-to-close">' + settings.touch_close_text + '</span>');
2305         $tip.on('click.fndtn.tooltip.tapclose touchstart.fndtn.tooltip.tapclose MSPointerDown.fndtn.tooltip.tapclose', function (e) {
2306           self.hide($target);
2307         });
2308       }
2309
2310       $target.data('tooltip-open-event-type', 'touch');
2311     },
2312
2313     show : function ($target) {
2314       var $tip = this.getTip($target);
2315
2316       if ($target.data('tooltip-open-event-type') == 'touch') {
2317         this.convert_to_touch($target);
2318       }
2319
2320       this.reposition($target, $tip, $target.attr('class'));
2321       $target.addClass('open');
2322       $tip.fadeIn(150);
2323     },
2324
2325     hide : function ($target) {
2326       var $tip = this.getTip($target);
2327
2328       $tip.fadeOut(150, function () {
2329         $tip.find('.tap-to-close').remove();
2330         $tip.off('click.fndtn.tooltip.tapclose MSPointerDown.fndtn.tapclose');
2331         $target.removeClass('open');
2332       });
2333     },
2334
2335     off : function () {
2336       var self = this;
2337       this.S(this.scope).off('.fndtn.tooltip');
2338       this.S(this.settings.tooltip_class).each(function (i) {
2339         $('[' + self.attr_name() + ']').eq(i).attr('title', $(this).text());
2340       }).remove();
2341     },
2342
2343     reflow : function () {}
2344   };
2345 }(jQuery, window, window.document));
2346 ;(function ($, window, document, undefined) {
2347   'use strict';
2348
2349   Foundation.libs.topbar = {
2350     name : 'topbar',
2351
2352     version : '5.5.1',
2353
2354     settings : {
2355       index : 0,
2356       sticky_class : 'sticky',
2357       custom_back_text : true,
2358       back_text : 'Back',
2359       mobile_show_parent_link : true,
2360       is_hover : true,
2361       scrolltop : true, // jump to top when sticky nav menu toggle is clicked
2362       sticky_on : 'all'
2363     },
2364
2365     init : function (section, method, options) {
2366       Foundation.inherit(this, 'add_custom_rule register_media throttle');
2367       var self = this;
2368
2369       self.register_media('topbar', 'foundation-mq-topbar');
2370
2371       this.bindings(method, options);
2372
2373       self.S('[' + this.attr_name() + ']', this.scope).each(function () {
2374         var topbar = $(this),
2375             settings = topbar.data(self.attr_name(true) + '-init'),
2376             section = self.S('section, .top-bar-section', this);
2377         topbar.data('index', 0);
2378         var topbarContainer = topbar.parent();
2379         if (topbarContainer.hasClass('fixed') || self.is_sticky(topbar, topbarContainer, settings) ) {
2380           self.settings.sticky_class = settings.sticky_class;
2381           self.settings.sticky_topbar = topbar;
2382           topbar.data('height', topbarContainer.outerHeight());
2383           topbar.data('stickyoffset', topbarContainer.offset().top);
2384         } else {
2385           topbar.data('height', topbar.outerHeight());
2386         }
2387
2388         if (!settings.assembled) {
2389           self.assemble(topbar);
2390         }
2391
2392         if (settings.is_hover) {
2393           self.S('.has-dropdown', topbar).addClass('not-click');
2394         } else {
2395           self.S('.has-dropdown', topbar).removeClass('not-click');
2396         }
2397
2398         // Pad body when sticky (scrolled) or fixed.
2399         self.add_custom_rule('.f-topbar-fixed { padding-top: ' + topbar.data('height') + 'px }');
2400
2401         if (topbarContainer.hasClass('fixed')) {
2402           self.S('body').addClass('f-topbar-fixed');
2403         }
2404       });
2405
2406     },
2407
2408     is_sticky : function (topbar, topbarContainer, settings) {
2409       var sticky     = topbarContainer.hasClass(settings.sticky_class);
2410       var smallMatch = matchMedia(Foundation.media_queries.small).matches;
2411       var medMatch   = matchMedia(Foundation.media_queries.medium).matches;
2412       var lrgMatch   = matchMedia(Foundation.media_queries.large).matches;
2413       
2414        if (sticky && settings.sticky_on === 'all') {
2415           return true;
2416        }
2417        if (sticky && this.small() && settings.sticky_on.indexOf('small') !== -1) {
2418            if (smallMatch && !medMatch && !lrgMatch) { return true; }
2419        }
2420        if (sticky && this.medium() && settings.sticky_on.indexOf('medium') !== -1) {
2421            if (smallMatch && medMatch && !lrgMatch) { return true; }
2422        }
2423        if (sticky && this.large() && settings.sticky_on.indexOf('large') !== -1) {
2424            if (smallMatch && medMatch && lrgMatch) { return true; }
2425        }
2426
2427        // fix for iOS browsers
2428        if (sticky && navigator.userAgent.match(/(iPad|iPhone|iPod)/g)) {
2429         return true;
2430        }
2431        return false;
2432     },
2433
2434     toggle : function (toggleEl) {
2435       var self = this,
2436           topbar;
2437
2438       if (toggleEl) {
2439         topbar = self.S(toggleEl).closest('[' + this.attr_name() + ']');
2440       } else {
2441         topbar = self.S('[' + this.attr_name() + ']');
2442       }
2443
2444       var settings = topbar.data(this.attr_name(true) + '-init');
2445
2446       var section = self.S('section, .top-bar-section', topbar);
2447
2448       if (self.breakpoint()) {
2449         if (!self.rtl) {
2450           section.css({left : '0%'});
2451           $('>.name', section).css({left : '100%'});
2452         } else {
2453           section.css({right : '0%'});
2454           $('>.name', section).css({right : '100%'});
2455         }
2456
2457         self.S('li.moved', section).removeClass('moved');
2458         topbar.data('index', 0);
2459
2460         topbar
2461           .toggleClass('expanded')
2462           .css('height', '');
2463       }
2464
2465       if (settings.scrolltop) {
2466         if (!topbar.hasClass('expanded')) {
2467           if (topbar.hasClass('fixed')) {
2468             topbar.parent().addClass('fixed');
2469             topbar.removeClass('fixed');
2470             self.S('body').addClass('f-topbar-fixed');
2471           }
2472         } else if (topbar.parent().hasClass('fixed')) {
2473           if (settings.scrolltop) {
2474             topbar.parent().removeClass('fixed');
2475             topbar.addClass('fixed');
2476             self.S('body').removeClass('f-topbar-fixed');
2477
2478             window.scrollTo(0, 0);
2479           } else {
2480             topbar.parent().removeClass('expanded');
2481           }
2482         }
2483       } else {
2484         if (self.is_sticky(topbar, topbar.parent(), settings)) {
2485           topbar.parent().addClass('fixed');
2486         }
2487
2488         if (topbar.parent().hasClass('fixed')) {
2489           if (!topbar.hasClass('expanded')) {
2490             topbar.removeClass('fixed');
2491             topbar.parent().removeClass('expanded');
2492             self.update_sticky_positioning();
2493           } else {
2494             topbar.addClass('fixed');
2495             topbar.parent().addClass('expanded');
2496             self.S('body').addClass('f-topbar-fixed');
2497           }
2498         }
2499       }
2500     },
2501
2502     timer : null,
2503
2504     events : function (bar) {
2505       var self = this,
2506           S = this.S;
2507
2508       S(this.scope)
2509         .off('.topbar')
2510         .on('click.fndtn.topbar', '[' + this.attr_name() + '] .toggle-topbar', function (e) {
2511           e.preventDefault();
2512           self.toggle(this);
2513         })
2514         .on('click.fndtn.topbar', '.top-bar .top-bar-section li a[href^="#"],[' + this.attr_name() + '] .top-bar-section li a[href^="#"]', function (e) {
2515             var li = $(this).closest('li');
2516             if (self.breakpoint() && !li.hasClass('back') && !li.hasClass('has-dropdown')) {
2517               self.toggle();
2518             }
2519         })
2520         .on('click.fndtn.topbar', '[' + this.attr_name() + '] li.has-dropdown', function (e) {
2521           var li = S(this),
2522               target = S(e.target),
2523               topbar = li.closest('[' + self.attr_name() + ']'),
2524               settings = topbar.data(self.attr_name(true) + '-init');
2525
2526           if (target.data('revealId')) {
2527             self.toggle();
2528             return;
2529           }
2530
2531           if (self.breakpoint()) {
2532             return;
2533           }
2534
2535           if (settings.is_hover && !Modernizr.touch) {
2536             return;
2537           }
2538
2539           e.stopImmediatePropagation();
2540
2541           if (li.hasClass('hover')) {
2542             li
2543               .removeClass('hover')
2544               .find('li')
2545               .removeClass('hover');
2546
2547             li.parents('li.hover')
2548               .removeClass('hover');
2549           } else {
2550             li.addClass('hover');
2551
2552             $(li).siblings().removeClass('hover');
2553
2554             if (target[0].nodeName === 'A' && target.parent().hasClass('has-dropdown')) {
2555               e.preventDefault();
2556             }
2557           }
2558         })
2559         .on('click.fndtn.topbar', '[' + this.attr_name() + '] .has-dropdown>a', function (e) {
2560           if (self.breakpoint()) {
2561
2562             e.preventDefault();
2563
2564             var $this = S(this),
2565                 topbar = $this.closest('[' + self.attr_name() + ']'),
2566                 section = topbar.find('section, .top-bar-section'),
2567                 dropdownHeight = $this.next('.dropdown').outerHeight(),
2568                 $selectedLi = $this.closest('li');
2569
2570             topbar.data('index', topbar.data('index') + 1);
2571             $selectedLi.addClass('moved');
2572
2573             if (!self.rtl) {
2574               section.css({left : -(100 * topbar.data('index')) + '%'});
2575               section.find('>.name').css({left : 100 * topbar.data('index') + '%'});
2576             } else {
2577               section.css({right : -(100 * topbar.data('index')) + '%'});
2578               section.find('>.name').css({right : 100 * topbar.data('index') + '%'});
2579             }
2580
2581             topbar.css('height', $this.siblings('ul').outerHeight(true) + topbar.data('height'));
2582           }
2583         });
2584
2585       S(window).off('.topbar').on('resize.fndtn.topbar', self.throttle(function () {
2586           self.resize.call(self);
2587       }, 50)).trigger('resize').trigger('resize.fndtn.topbar').load(function () {
2588           // Ensure that the offset is calculated after all of the pages resources have loaded
2589           S(this).trigger('resize.fndtn.topbar');
2590       });
2591
2592       S('body').off('.topbar').on('click.fndtn.topbar', function (e) {
2593         var parent = S(e.target).closest('li').closest('li.hover');
2594
2595         if (parent.length > 0) {
2596           return;
2597         }
2598
2599         S('[' + self.attr_name() + '] li.hover').removeClass('hover');
2600       });
2601
2602       // Go up a level on Click
2603       S(this.scope).on('click.fndtn.topbar', '[' + this.attr_name() + '] .has-dropdown .back', function (e) {
2604         e.preventDefault();
2605
2606         var $this = S(this),
2607             topbar = $this.closest('[' + self.attr_name() + ']'),
2608             section = topbar.find('section, .top-bar-section'),
2609             settings = topbar.data(self.attr_name(true) + '-init'),
2610             $movedLi = $this.closest('li.moved'),
2611             $previousLevelUl = $movedLi.parent();
2612
2613         topbar.data('index', topbar.data('index') - 1);
2614
2615         if (!self.rtl) {
2616           section.css({left : -(100 * topbar.data('index')) + '%'});
2617           section.find('>.name').css({left : 100 * topbar.data('index') + '%'});
2618         } else {
2619           section.css({right : -(100 * topbar.data('index')) + '%'});
2620           section.find('>.name').css({right : 100 * topbar.data('index') + '%'});
2621         }
2622
2623         if (topbar.data('index') === 0) {
2624           topbar.css('height', '');
2625         } else {
2626           topbar.css('height', $previousLevelUl.outerHeight(true) + topbar.data('height'));
2627         }
2628
2629         setTimeout(function () {
2630           $movedLi.removeClass('moved');
2631         }, 300);
2632       });
2633
2634       // Show dropdown menus when their items are focused
2635       S(this.scope).find('.dropdown a')
2636         .focus(function () {
2637           $(this).parents('.has-dropdown').addClass('hover');
2638         })
2639         .blur(function () {
2640           $(this).parents('.has-dropdown').removeClass('hover');
2641         });
2642     },
2643
2644     resize : function () {
2645       var self = this;
2646       self.S('[' + this.attr_name() + ']').each(function () {
2647         var topbar = self.S(this),
2648             settings = topbar.data(self.attr_name(true) + '-init');
2649
2650         var stickyContainer = topbar.parent('.' + self.settings.sticky_class);
2651         var stickyOffset;
2652
2653         if (!self.breakpoint()) {
2654           var doToggle = topbar.hasClass('expanded');
2655           topbar
2656             .css('height', '')
2657             .removeClass('expanded')
2658             .find('li')
2659             .removeClass('hover');
2660
2661             if (doToggle) {
2662               self.toggle(topbar);
2663             }
2664         }
2665
2666         if (self.is_sticky(topbar, stickyContainer, settings)) {
2667           if (stickyContainer.hasClass('fixed')) {
2668             // Remove the fixed to allow for correct calculation of the offset.
2669             stickyContainer.removeClass('fixed');
2670
2671             stickyOffset = stickyContainer.offset().top;
2672             if (self.S(document.body).hasClass('f-topbar-fixed')) {
2673               stickyOffset -= topbar.data('height');
2674             }
2675
2676             topbar.data('stickyoffset', stickyOffset);
2677             stickyContainer.addClass('fixed');
2678           } else {
2679             stickyOffset = stickyContainer.offset().top;
2680             topbar.data('stickyoffset', stickyOffset);
2681           }
2682         }
2683
2684       });
2685     },
2686
2687     breakpoint : function () {
2688       return !matchMedia(Foundation.media_queries['topbar']).matches;
2689     },
2690
2691     small : function () {
2692       return matchMedia(Foundation.media_queries['small']).matches;
2693     },
2694
2695     medium : function () {
2696       return matchMedia(Foundation.media_queries['medium']).matches;
2697     },
2698
2699     large : function () {
2700       return matchMedia(Foundation.media_queries['large']).matches;
2701     },
2702
2703     assemble : function (topbar) {
2704       var self = this,
2705           settings = topbar.data(this.attr_name(true) + '-init'),
2706           section = self.S('section, .top-bar-section', topbar);
2707
2708       // Pull element out of the DOM for manipulation
2709       section.detach();
2710
2711       self.S('.has-dropdown>a', section).each(function () {
2712         var $link = self.S(this),
2713             $dropdown = $link.siblings('.dropdown'),
2714             url = $link.attr('href'),
2715             $titleLi;
2716
2717         if (!$dropdown.find('.title.back').length) {
2718
2719           if (settings.mobile_show_parent_link == true && url) {
2720             $titleLi = $('<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5></li><li class="parent-link hide-for-large-up"><a class="parent-link js-generated" href="' + url + '">' + $link.html() +'</a></li>');
2721           } else {
2722             $titleLi = $('<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5>');
2723           }
2724
2725           // Copy link to subnav
2726           if (settings.custom_back_text == true) {
2727             $('h5>a', $titleLi).html(settings.back_text);
2728           } else {
2729             $('h5>a', $titleLi).html('&laquo; ' + $link.html());
2730           }
2731           $dropdown.prepend($titleLi);
2732         }
2733       });
2734
2735       // Put element back in the DOM
2736       section.appendTo(topbar);
2737
2738       // check for sticky
2739       this.sticky();
2740
2741       this.assembled(topbar);
2742     },
2743
2744     assembled : function (topbar) {
2745       topbar.data(this.attr_name(true), $.extend({}, topbar.data(this.attr_name(true)), {assembled : true}));
2746     },
2747
2748     height : function (ul) {
2749       var total = 0,
2750           self = this;
2751
2752       $('> li', ul).each(function () {
2753         total += self.S(this).outerHeight(true);
2754       });
2755
2756       return total;
2757     },
2758
2759     sticky : function () {
2760       var self = this;
2761
2762       this.S(window).on('scroll', function () {
2763         self.update_sticky_positioning();
2764       });
2765     },
2766
2767     update_sticky_positioning : function () {
2768       var klass = '.' + this.settings.sticky_class,
2769           $window = this.S(window),
2770           self = this;
2771
2772       if (self.settings.sticky_topbar && self.is_sticky(this.settings.sticky_topbar, this.settings.sticky_topbar.parent(), this.settings)) {
2773         var distance = this.settings.sticky_topbar.data('stickyoffset');
2774         if (!self.S(klass).hasClass('expanded')) {
2775           if ($window.scrollTop() > (distance)) {
2776             if (!self.S(klass).hasClass('fixed')) {
2777               self.S(klass).addClass('fixed');
2778               self.S('body').addClass('f-topbar-fixed');
2779             }
2780           } else if ($window.scrollTop() <= distance) {
2781             if (self.S(klass).hasClass('fixed')) {
2782               self.S(klass).removeClass('fixed');
2783               self.S('body').removeClass('f-topbar-fixed');
2784             }
2785           }
2786         }
2787       }
2788     },
2789
2790     off : function () {
2791       this.S(this.scope).off('.fndtn.topbar');
2792       this.S(window).off('.fndtn.topbar');
2793     },
2794
2795     reflow : function () {}
2796   };
2797 }(jQuery, window, window.document));