aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deprecated/ZJW/javascripts/webflow.js')
-rw-r--r--deprecated/ZJW/javascripts/webflow.js4445
1 files changed, 4445 insertions, 0 deletions
diff --git a/deprecated/ZJW/javascripts/webflow.js b/deprecated/ZJW/javascripts/webflow.js
new file mode 100644
index 0000000..b048709
--- /dev/null
+++ b/deprecated/ZJW/javascripts/webflow.js
@@ -0,0 +1,4445 @@
1/*!
2 * ----------------------------------------------------------------------
3 * Webflow: Front-end site library
4 * @license MIT
5 * Other scripts may access this api using an async handler:
6 * var Webflow = Webflow || [];
7 * Webflow.push(readyFunction);
8 * ----------------------------------------------------------------------
9 */
10var Webflow = {
11 w: Webflow
12};
13Webflow.init = function() {
14 'use strict';
15
16 var $ = window.$;
17 var api = {};
18 var modules = {};
19 var primary = [];
20 var secondary = this.w || [];
21 var $win = $(window);
22 var _ = api._ = underscore();
23 var domready = false;
24 var tram = window.tram;
25 var Modernizr = window.Modernizr;
26 var noop = function() {};
27 tram.config.hideBackface = false;
28 tram.config.keepInherited = true;
29
30 /**
31 * Webflow.define() - Define a webflow.js module
32 * @param {string} name
33 * @param {function} factory
34 */
35 api.define = function(name, factory) {
36 var module = modules[name] = factory($, _);
37 if (!module) return;
38 // If running in Webflow app, subscribe to design/preview events
39 if (api.env()) {
40 $.isFunction(module.design) && window.addEventListener('__wf_design', module.design);
41 $.isFunction(module.preview) && window.addEventListener('__wf_preview', module.preview);
42 }
43 // Subscribe to module front-end events
44 $.isFunction(module.destroy) && $win.on('__wf_destroy', module.destroy);
45 // Look for a ready method on module
46 if (module.ready && $.isFunction(module.ready)) {
47 // If domready has already happened, call ready method
48 if (domready) module.ready();
49 // Otherwise push ready method into primary queue
50 else primary.push(module.ready);
51 }
52 };
53
54 /**
55 * Webflow.require() - Load a Webflow.js module
56 * @param {string} name
57 * @return {object}
58 */
59 api.require = function(name) {
60 return modules[name];
61 };
62
63 /**
64 * Webflow.push() - Add a ready handler into secondary queue
65 * @param {function} ready Callback to invoke on domready
66 */
67 api.push = function(ready) {
68 // If domready has already happened, invoke handler
69 if (domready) {
70 $.isFunction(ready) && ready();
71 return;
72 }
73 // Otherwise push into secondary queue
74 secondary.push(ready);
75 };
76
77 /**
78 * Webflow.env() - Get the state of the Webflow app
79 * @param {string} mode [optional]
80 * @return {boolean}
81 */
82 api.env = function(mode) {
83 var designFlag = window.__wf_design;
84 var inApp = typeof designFlag != 'undefined';
85 if (!mode) return inApp;
86 if (mode == 'design') return inApp && designFlag;
87 if (mode == 'preview') return inApp && !designFlag;
88 if (mode == 'slug') return inApp && window.__wf_slug;
89 };
90
91 // Feature detects + browser sniffs ಠ_ಠ
92 var userAgent = navigator.userAgent.toLowerCase();
93 var appVersion = navigator.appVersion.toLowerCase();
94 api.env.touch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch;
95 var chrome = api.env.chrome = (window.chrome || /chrome/.test(userAgent)) && parseInt(appVersion.match(/chrome\/(\d+)\./)[1], 10);
96 var ios = api.env.ios = Modernizr && Modernizr.ios;
97 api.env.safari = /safari/.test(userAgent) && !chrome && !ios;
98
99 /**
100 * Webflow.resize, Webflow.scroll - throttled event proxies
101 */
102 var resizeEvents = 'resize.webflow orientationchange.webflow load.webflow';
103 var scrollEvents = 'scroll.webflow ' + resizeEvents;
104 api.resize = eventProxy($win, resizeEvents);
105 api.scroll = eventProxy($win, scrollEvents);
106 api.redraw = eventProxy();
107
108 // Create a proxy instance for throttled events
109 function eventProxy(target, types) {
110
111 // Set up throttled method (using custom frame-based _.throttle)
112 var handlers = [];
113 var proxy = {};
114 proxy.up = _.throttle(function(evt) {
115 _.each(handlers, function(h) {
116 h(evt);
117 });
118 });
119
120 // Bind events to target
121 if (target && types) target.on(types, proxy.up);
122
123 /**
124 * Add an event handler
125 * @param {function} handler
126 */
127 proxy.on = function(handler) {
128 if (typeof handler != 'function') return;
129 if (_.contains(handlers, handler)) return;
130 handlers.push(handler);
131 };
132
133 /**
134 * Remove an event handler
135 * @param {function} handler
136 */
137 proxy.off = function(handler) {
138 handlers = _.filter(handlers, function(h) {
139 return h !== handler;
140 });
141 };
142 return proxy;
143 }
144
145 // Provide optional IX events to components
146 api.ixEvents = function() {
147 var ix = api.require('ix');
148 return (ix && ix.events) || {
149 reset: noop,
150 intro: noop,
151 outro: noop
152 };
153 };
154
155 // Webflow.location() - Wrap window.location in api
156 api.location = function(url) {
157 window.location = url;
158 };
159
160 // Webflow.app - Designer-specific methods
161 api.app = api.env() ? {} : null;
162 if (api.app) {
163
164 // Trigger redraw for specific elements
165 var Event = window.Event;
166 var redraw = new Event('__wf_redraw');
167 api.app.redrawElement = function(i, el) {
168 el.dispatchEvent(redraw);
169 };
170
171 // Webflow.location - Re-route location change to trigger an event
172 api.location = function(url) {
173 window.dispatchEvent(new CustomEvent('__wf_location', {
174 detail: url
175 }));
176 };
177 }
178
179 // Webflow.ready() - Call primary and secondary handlers
180 api.ready = function() {
181 domready = true;
182 $.each(primary.concat(secondary), function(index, value) {
183 $.isFunction(value) && value();
184 });
185 // Trigger resize
186 api.resize.up();
187 };
188
189 // Webflow.destroy() - Trigger a cleanup event for all modules
190 api.destroy = function() {
191 $win.triggerHandler('__wf_destroy');
192 };
193
194 // Listen for domready
195 $(api.ready);
196
197 /*!
198 * Webflow._ (aka) Underscore.js 1.6.0 (custom build)
199 * _.each
200 * _.map
201 * _.find
202 * _.filter
203 * _.any
204 * _.contains
205 * _.delay
206 * _.defer
207 * _.throttle (webflow)
208 * _.debounce
209 * _.keys
210 * _.has
211 * _.now
212 *
213 * http://underscorejs.org
214 * (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
215 * Underscore may be freely distributed under the MIT license.
216 */
217 function underscore() {
218 var _ = {};
219
220 // Current version.
221 _.VERSION = '1.6.0-Webflow';
222
223 // Establish the object that gets returned to break out of a loop iteration.
224 var breaker = {};
225
226 // Save bytes in the minified (but not gzipped) version:
227 var ArrayProto = Array.prototype,
228 ObjProto = Object.prototype,
229 FuncProto = Function.prototype;
230
231 // Create quick reference variables for speed access to core prototypes.
232 var
233 push = ArrayProto.push,
234 slice = ArrayProto.slice,
235 concat = ArrayProto.concat,
236 toString = ObjProto.toString,
237 hasOwnProperty = ObjProto.hasOwnProperty;
238
239 // All **ECMAScript 5** native function implementations that we hope to use
240 // are declared here.
241 var
242 nativeForEach = ArrayProto.forEach,
243 nativeMap = ArrayProto.map,
244 nativeReduce = ArrayProto.reduce,
245 nativeReduceRight = ArrayProto.reduceRight,
246 nativeFilter = ArrayProto.filter,
247 nativeEvery = ArrayProto.every,
248 nativeSome = ArrayProto.some,
249 nativeIndexOf = ArrayProto.indexOf,
250 nativeLastIndexOf = ArrayProto.lastIndexOf,
251 nativeIsArray = Array.isArray,
252 nativeKeys = Object.keys,
253 nativeBind = FuncProto.bind;
254
255 // Collection Functions
256 // --------------------
257
258 // The cornerstone, an `each` implementation, aka `forEach`.
259 // Handles objects with the built-in `forEach`, arrays, and raw objects.
260 // Delegates to **ECMAScript 5**'s native `forEach` if available.
261 var each = _.each = _.forEach = function(obj, iterator, context) {
262 /* jshint shadow:true */
263 if (obj == null) return obj;
264 if (nativeForEach && obj.forEach === nativeForEach) {
265 obj.forEach(iterator, context);
266 } else if (obj.length === +obj.length) {
267 for (var i = 0, length = obj.length; i < length; i++) {
268 if (iterator.call(context, obj[i], i, obj) === breaker) return;
269 }
270 } else {
271 var keys = _.keys(obj);
272 for (var i = 0, length = keys.length; i < length; i++) {
273 if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
274 }
275 }
276 return obj;
277 };
278
279 // Return the results of applying the iterator to each element.
280 // Delegates to **ECMAScript 5**'s native `map` if available.
281 _.map = _.collect = function(obj, iterator, context) {
282 var results = [];
283 if (obj == null) return results;
284 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
285 each(obj, function(value, index, list) {
286 results.push(iterator.call(context, value, index, list));
287 });
288 return results;
289 };
290
291 // Return the first value which passes a truth test. Aliased as `detect`.
292 _.find = _.detect = function(obj, predicate, context) {
293 var result;
294 any(obj, function(value, index, list) {
295 if (predicate.call(context, value, index, list)) {
296 result = value;
297 return true;
298 }
299 });
300 return result;
301 };
302
303 // Return all the elements that pass a truth test.
304 // Delegates to **ECMAScript 5**'s native `filter` if available.
305 // Aliased as `select`.
306 _.filter = _.select = function(obj, predicate, context) {
307 var results = [];
308 if (obj == null) return results;
309 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
310 each(obj, function(value, index, list) {
311 if (predicate.call(context, value, index, list)) results.push(value);
312 });
313 return results;
314 };
315
316 // Determine if at least one element in the object matches a truth test.
317 // Delegates to **ECMAScript 5**'s native `some` if available.
318 // Aliased as `any`.
319 var any = _.some = _.any = function(obj, predicate, context) {
320 predicate || (predicate = _.identity);
321 var result = false;
322 if (obj == null) return result;
323 if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
324 each(obj, function(value, index, list) {
325 if (result || (result = predicate.call(context, value, index, list))) return breaker;
326 });
327 return !!result;
328 };
329
330 // Determine if the array or object contains a given value (using `===`).
331 // Aliased as `include`.
332 _.contains = _.include = function(obj, target) {
333 if (obj == null) return false;
334 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
335 return any(obj, function(value) {
336 return value === target;
337 });
338 };
339
340 // Function (ahem) Functions
341 // --------------------
342
343 // Delays a function for the given number of milliseconds, and then calls
344 // it with the arguments supplied.
345 _.delay = function(func, wait) {
346 var args = slice.call(arguments, 2);
347 return setTimeout(function() {
348 return func.apply(null, args);
349 }, wait);
350 };
351
352 // Defers a function, scheduling it to run after the current call stack has
353 // cleared.
354 _.defer = function(func) {
355 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
356 };
357
358 // Returns a function, that, when invoked, will only be triggered once every
359 // browser animation frame - using tram's requestAnimationFrame polyfill.
360 _.throttle = function(func) {
361 var wait, args, context;
362 return function() {
363 if (wait) return;
364 wait = true;
365 args = arguments;
366 context = this;
367 tram.frame(function() {
368 wait = false;
369 func.apply(context, args);
370 });
371 };
372 };
373
374 // Returns a function, that, as long as it continues to be invoked, will not
375 // be triggered. The function will be called after it stops being called for
376 // N milliseconds. If `immediate` is passed, trigger the function on the
377 // leading edge, instead of the trailing.
378 _.debounce = function(func, wait, immediate) {
379 var timeout, args, context, timestamp, result;
380
381 var later = function() {
382 var last = _.now() - timestamp;
383 if (last < wait) {
384 timeout = setTimeout(later, wait - last);
385 } else {
386 timeout = null;
387 if (!immediate) {
388 result = func.apply(context, args);
389 context = args = null;
390 }
391 }
392 };
393
394 return function() {
395 context = this;
396 args = arguments;
397 timestamp = _.now();
398 var callNow = immediate && !timeout;
399 if (!timeout) {
400 timeout = setTimeout(later, wait);
401 }
402 if (callNow) {
403 result = func.apply(context, args);
404 context = args = null;
405 }
406
407 return result;
408 };
409 };
410
411 // Object Functions
412 // ----------------
413
414 // Retrieve the names of an object's properties.
415 // Delegates to **ECMAScript 5**'s native `Object.keys`
416 _.keys = function(obj) {
417 if (!_.isObject(obj)) return [];
418 if (nativeKeys) return nativeKeys(obj);
419 var keys = [];
420 for (var key in obj)
421 if (_.has(obj, key)) keys.push(key);
422 return keys;
423 };
424
425 // Shortcut function for checking if an object has a given property directly
426 // on itself (in other words, not on a prototype).
427 _.has = function(obj, key) {
428 return hasOwnProperty.call(obj, key);
429 };
430
431 // Is a given variable an object?
432 _.isObject = function(obj) {
433 return obj === Object(obj);
434 };
435
436 // Utility Functions
437 // -----------------
438
439 // A (possibly faster) way to get the current timestamp as an integer.
440 _.now = Date.now || function() {
441 return new Date().getTime();
442 };
443
444 // Export underscore
445 return _;
446 }
447
448 // Export api
449 Webflow = api;
450};
451/*!
452 * ----------------------------------------------------------------------
453 * Webflow: 3rd party plugins
454 */
455/* jshint ignore:start */
456/*!
457 * tram.js v0.8.1-global
458 * Cross-browser CSS3 transitions in JavaScript
459 * https://github.com/bkwld/tram
460 * MIT License
461 */
462window.tram = function(a) {
463 function b(a, b) {
464 var c = new L.Bare;
465 return c.init(a, b)
466 }
467
468 function c(a) {
469 return a.replace(/[A-Z]/g, function(a) {
470 return "-" + a.toLowerCase()
471 })
472 }
473
474 function d(a) {
475 var b = parseInt(a.slice(1), 16),
476 c = b >> 16 & 255,
477 d = b >> 8 & 255,
478 e = 255 & b;
479 return [c, d, e]
480 }
481
482 function e(a, b, c) {
483 return "#" + (1 << 24 | a << 16 | b << 8 | c).toString(16).slice(1)
484 }
485
486 function f() {}
487
488 function g(a, b) {
489 _("Type warning: Expected: [" + a + "] Got: [" + typeof b + "] " + b)
490 }
491
492 function h(a, b, c) {
493 _("Units do not match [" + a + "]: " + b + ", " + c)
494 }
495
496 function i(a, b, c) {
497 if (void 0 !== b && (c = b), void 0 === a) return c;
498 var d = c;
499 return Z.test(a) || !$.test(a) ? d = parseInt(a, 10) : $.test(a) && (d = 1e3 * parseFloat(a)), 0 > d && (d = 0), d === d ? d : c
500 }
501
502 function j(a) {
503 for (var b = -1, c = a ? a.length : 0, d = []; ++b < c;) {
504 var e = a[b];
505 e && d.push(e)
506 }
507 return d
508 }
509 var k = function(a, b, c) {
510 function d(a) {
511 return "object" == typeof a
512 }
513
514 function e(a) {
515 return "function" == typeof a
516 }
517
518 function f() {}
519
520 function g(h, i) {
521 function j() {
522 var a = new k;
523 return e(a.init) && a.init.apply(a, arguments), a
524 }
525
526 function k() {}
527 i === c && (i = h, h = Object), j.Bare = k;
528 var l, m = f[a] = h[a],
529 n = k[a] = j[a] = new f;
530 return n.constructor = j, j.mixin = function(b) {
531 return k[a] = j[a] = g(j, b)[a], j
532 }, j.open = function(a) {
533 if (l = {}, e(a) ? l = a.call(j, n, m, j, h) : d(a) && (l = a), d(l))
534 for (var c in l) b.call(l, c) && (n[c] = l[c]);
535 return e(n.init) || (n.init = h), j
536 }, j.open(i)
537 }
538 return g
539 }("prototype", {}.hasOwnProperty),
540 l = {
541 ease: ["ease",
542 function(a, b, c, d) {
543 var e = (a /= d) * a,
544 f = e * a;
545 return b + c * (-2.75 * f * e + 11 * e * e + -15.5 * f + 8 * e + .25 * a)
546 }
547 ],
548 "ease-in": ["ease-in",
549 function(a, b, c, d) {
550 var e = (a /= d) * a,
551 f = e * a;
552 return b + c * (-1 * f * e + 3 * e * e + -3 * f + 2 * e)
553 }
554 ],
555 "ease-out": ["ease-out",
556 function(a, b, c, d) {
557 var e = (a /= d) * a,
558 f = e * a;
559 return b + c * (.3 * f * e + -1.6 * e * e + 2.2 * f + -1.8 * e + 1.9 * a)
560 }
561 ],
562 "ease-in-out": ["ease-in-out",
563 function(a, b, c, d) {
564 var e = (a /= d) * a,
565 f = e * a;
566 return b + c * (2 * f * e + -5 * e * e + 2 * f + 2 * e)
567 }
568 ],
569 linear: ["linear",
570 function(a, b, c, d) {
571 return c * a / d + b
572 }
573 ],
574 "ease-in-quad": ["cubic-bezier(0.550, 0.085, 0.680, 0.530)",
575 function(a, b, c, d) {
576 return c * (a /= d) * a + b
577 }
578 ],
579 "ease-out-quad": ["cubic-bezier(0.250, 0.460, 0.450, 0.940)",
580 function(a, b, c, d) {
581 return -c * (a /= d) * (a - 2) + b
582 }
583 ],
584 "ease-in-out-quad": ["cubic-bezier(0.455, 0.030, 0.515, 0.955)",
585 function(a, b, c, d) {
586 return (a /= d / 2) < 1 ? c / 2 * a * a + b : -c / 2 * (--a * (a - 2) - 1) + b
587 }
588 ],
589 "ease-in-cubic": ["cubic-bezier(0.550, 0.055, 0.675, 0.190)",
590 function(a, b, c, d) {
591 return c * (a /= d) * a * a + b
592 }
593 ],
594 "ease-out-cubic": ["cubic-bezier(0.215, 0.610, 0.355, 1)",
595 function(a, b, c, d) {
596 return c * ((a = a / d - 1) * a * a + 1) + b
597 }
598 ],
599 "ease-in-out-cubic": ["cubic-bezier(0.645, 0.045, 0.355, 1)",
600 function(a, b, c, d) {
601 return (a /= d / 2) < 1 ? c / 2 * a * a * a + b : c / 2 * ((a -= 2) * a * a + 2) + b
602 }
603 ],
604 "ease-in-quart": ["cubic-bezier(0.895, 0.030, 0.685, 0.220)",
605 function(a, b, c, d) {
606 return c * (a /= d) * a * a * a + b
607 }
608 ],
609 "ease-out-quart": ["cubic-bezier(0.165, 0.840, 0.440, 1)",
610 function(a, b, c, d) {
611 return -c * ((a = a / d - 1) * a * a * a - 1) + b
612 }
613 ],
614 "ease-in-out-quart": ["cubic-bezier(0.770, 0, 0.175, 1)",
615 function(a, b, c, d) {
616 return (a /= d / 2) < 1 ? c / 2 * a * a * a * a + b : -c / 2 * ((a -= 2) * a * a * a - 2) + b
617 }
618 ],
619 "ease-in-quint": ["cubic-bezier(0.755, 0.050, 0.855, 0.060)",
620 function(a, b, c, d) {
621 return c * (a /= d) * a * a * a * a + b
622 }
623 ],
624 "ease-out-quint": ["cubic-bezier(0.230, 1, 0.320, 1)",
625 function(a, b, c, d) {
626 return c * ((a = a / d - 1) * a * a * a * a + 1) + b
627 }
628 ],
629 "ease-in-out-quint": ["cubic-bezier(0.860, 0, 0.070, 1)",
630 function(a, b, c, d) {
631 return (a /= d / 2) < 1 ? c / 2 * a * a * a * a * a + b : c / 2 * ((a -= 2) * a * a * a * a + 2) + b
632 }
633 ],
634 "ease-in-sine": ["cubic-bezier(0.470, 0, 0.745, 0.715)",
635 function(a, b, c, d) {
636 return -c * Math.cos(a / d * (Math.PI / 2)) + c + b
637 }
638 ],
639 "ease-out-sine": ["cubic-bezier(0.390, 0.575, 0.565, 1)",
640 function(a, b, c, d) {
641 return c * Math.sin(a / d * (Math.PI / 2)) + b
642 }
643 ],
644 "ease-in-out-sine": ["cubic-bezier(0.445, 0.050, 0.550, 0.950)",
645 function(a, b, c, d) {
646 return -c / 2 * (Math.cos(Math.PI * a / d) - 1) + b
647 }
648 ],
649 "ease-in-expo": ["cubic-bezier(0.950, 0.050, 0.795, 0.035)",
650 function(a, b, c, d) {
651 return 0 === a ? b : c * Math.pow(2, 10 * (a / d - 1)) + b
652 }
653 ],
654 "ease-out-expo": ["cubic-bezier(0.190, 1, 0.220, 1)",
655 function(a, b, c, d) {
656 return a === d ? b + c : c * (-Math.pow(2, -10 * a / d) + 1) + b
657 }
658 ],
659 "ease-in-out-expo": ["cubic-bezier(1, 0, 0, 1)",
660 function(a, b, c, d) {
661 return 0 === a ? b : a === d ? b + c : (a /= d / 2) < 1 ? c / 2 * Math.pow(2, 10 * (a - 1)) + b : c / 2 * (-Math.pow(2, -10 * --a) + 2) + b
662 }
663 ],
664 "ease-in-circ": ["cubic-bezier(0.600, 0.040, 0.980, 0.335)",
665 function(a, b, c, d) {
666 return -c * (Math.sqrt(1 - (a /= d) * a) - 1) + b
667 }
668 ],
669 "ease-out-circ": ["cubic-bezier(0.075, 0.820, 0.165, 1)",
670 function(a, b, c, d) {
671 return c * Math.sqrt(1 - (a = a / d - 1) * a) + b
672 }
673 ],
674 "ease-in-out-circ": ["cubic-bezier(0.785, 0.135, 0.150, 0.860)",
675 function(a, b, c, d) {
676 return (a /= d / 2) < 1 ? -c / 2 * (Math.sqrt(1 - a * a) - 1) + b : c / 2 * (Math.sqrt(1 - (a -= 2) * a) + 1) + b
677 }
678 ],
679 "ease-in-back": ["cubic-bezier(0.600, -0.280, 0.735, 0.045)",
680 function(a, b, c, d, e) {
681 return void 0 === e && (e = 1.70158), c * (a /= d) * a * ((e + 1) * a - e) + b
682 }
683 ],
684 "ease-out-back": ["cubic-bezier(0.175, 0.885, 0.320, 1.275)",
685 function(a, b, c, d, e) {
686 return void 0 === e && (e = 1.70158), c * ((a = a / d - 1) * a * ((e + 1) * a + e) + 1) + b
687 }
688 ],
689 "ease-in-out-back": ["cubic-bezier(0.680, -0.550, 0.265, 1.550)",
690 function(a, b, c, d, e) {
691 return void 0 === e && (e = 1.70158), (a /= d / 2) < 1 ? c / 2 * a * a * (((e *= 1.525) + 1) * a - e) + b : c / 2 * ((a -= 2) * a * (((e *= 1.525) + 1) * a + e) + 2) + b
692 }
693 ]
694 },
695 m = {
696 "ease-in-back": "cubic-bezier(0.600, 0, 0.735, 0.045)",
697 "ease-out-back": "cubic-bezier(0.175, 0.885, 0.320, 1)",
698 "ease-in-out-back": "cubic-bezier(0.680, 0, 0.265, 1)"
699 },
700 n = document,
701 o = window,
702 p = "bkwld-tram",
703 q = /[\-\.0-9]/g,
704 r = /[A-Z]/,
705 s = "number",
706 t = /^(rgb|#)/,
707 u = /(em|cm|mm|in|pt|pc|px)$/,
708 v = /(em|cm|mm|in|pt|pc|px|%)$/,
709 w = /(deg|rad|turn)$/,
710 x = "unitless",
711 y = /(all|none) 0s ease 0s/,
712 z = /^(width|height)$/,
713 A = " ",
714 B = n.createElement("a"),
715 C = ["Webkit", "Moz", "O", "ms"],
716 D = ["-webkit-", "-moz-", "-o-", "-ms-"],
717 E = function(a) {
718 if (a in B.style) return {
719 dom: a,
720 css: a
721 };
722 var b, c, d = "",
723 e = a.split("-");
724 for (b = 0; b < e.length; b++) d += e[b].charAt(0).toUpperCase() + e[b].slice(1);
725 for (b = 0; b < C.length; b++)
726 if (c = C[b] + d, c in B.style) return {
727 dom: c,
728 css: D[b] + a
729 }
730 },
731 F = b.support = {
732 bind: Function.prototype.bind,
733 transform: E("transform"),
734 transition: E("transition"),
735 backface: E("backface-visibility"),
736 timing: E("transition-timing-function")
737 };
738 if (F.transition) {
739 var G = F.timing.dom;
740 if (B.style[G] = l["ease-in-back"][0], !B.style[G])
741 for (var H in m) l[H][0] = m[H]
742 }
743 var I = b.frame = function() {
744 var a = o.requestAnimationFrame || o.webkitRequestAnimationFrame || o.mozRequestAnimationFrame || o.oRequestAnimationFrame || o.msRequestAnimationFrame;
745 return a && F.bind ? a.bind(o) : function(a) {
746 o.setTimeout(a, 16)
747 }
748 }(),
749 J = b.now = function() {
750 var a = o.performance,
751 b = a && (a.now || a.webkitNow || a.msNow || a.mozNow);
752 return b && F.bind ? b.bind(a) : Date.now || function() {
753 return +new Date
754 }
755 }(),
756 K = k(function(b) {
757 function d(a, b) {
758 var c = j(("" + a).split(A)),
759 d = c[0];
760 b = b || {};
761 var e = X[d];
762 if (!e) return _("Unsupported property: " + d);
763 if (!b.weak || !this.props[d]) {
764 var f = e[0],
765 g = this.props[d];
766 return g || (g = this.props[d] = new f.Bare), g.init(this.$el, c, e, b), g
767 }
768 }
769
770 function e(a, b, c) {
771 if (a) {
772 var e = typeof a;
773 if (b || (this.timer && this.timer.destroy(), this.queue = [], this.active = !1), "number" == e && b) return this.timer = new R({
774 duration: a,
775 context: this,
776 complete: h
777 }), void(this.active = !0);
778 if ("string" == e && b) {
779 switch (a) {
780 case "hide":
781 n.call(this);
782 break;
783 case "stop":
784 k.call(this);
785 break;
786 case "redraw":
787 o.call(this);
788 break;
789 default:
790 d.call(this, a, c && c[1])
791 }
792 return h.call(this)
793 }
794 if ("function" == e) return void a.call(this, this);
795 if ("object" == e) {
796 var f = 0;
797 t.call(this, a, function(a, b) {
798 a.span > f && (f = a.span), a.stop(), a.animate(b)
799 }, function(a) {
800 "wait" in a && (f = i(a.wait, 0))
801 }), s.call(this), f > 0 && (this.timer = new R({
802 duration: f,
803 context: this
804 }), this.active = !0, b && (this.timer.complete = h));
805 var g = this,
806 j = !1,
807 l = {};
808 I(function() {
809 t.call(g, a, function(a) {
810 a.active && (j = !0, l[a.name] = a.nextStyle)
811 }), j && g.$el.css(l)
812 })
813 }
814 }
815 }
816
817 function f(a) {
818 a = i(a, 0), this.active ? this.queue.push({
819 options: a
820 }) : (this.timer = new R({
821 duration: a,
822 context: this,
823 complete: h
824 }), this.active = !0)
825 }
826
827 function g(a) {
828 return this.active ? (this.queue.push({
829 options: a,
830 args: arguments
831 }), void(this.timer.complete = h)) : _("No active transition timer. Use start() or wait() before then().")
832 }
833
834 function h() {
835 if (this.timer && this.timer.destroy(), this.active = !1, this.queue.length) {
836 var a = this.queue.shift();
837 e.call(this, a.options, !0, a.args)
838 }
839 }
840
841 function k(a) {
842 this.timer && this.timer.destroy(), this.queue = [], this.active = !1;
843 var b;
844 "string" == typeof a ? (b = {}, b[a] = 1) : b = "object" == typeof a && null != a ? a : this.props, t.call(this, b, u), s.call(this)
845 }
846
847 function l(a) {
848 k.call(this, a), t.call(this, a, v, w)
849 }
850
851 function m(a) {
852 "string" != typeof a && (a = "block"), this.el.style.display = a
853 }
854
855 function n() {
856 k.call(this), this.el.style.display = "none"
857 }
858
859 function o() {
860 this.el.offsetHeight
861 }
862
863 function q() {
864 k.call(this), a.removeData(this.el, p), this.$el = this.el = null
865 }
866
867 function s() {
868 var a, b, c = [];
869 this.upstream && c.push(this.upstream);
870 for (a in this.props) b = this.props[a], b.active && c.push(b.string);
871 c = c.join(","), this.style !== c && (this.style = c, this.el.style[F.transition.dom] = c)
872 }
873
874 function t(a, b, e) {
875 var f, g, h, i, j = b !== u,
876 k = {};
877 for (f in a) h = a[f], f in Y ? (k.transform || (k.transform = {}), k.transform[f] = h) : (r.test(f) && (f = c(f)), f in X ? k[f] = h : (i || (i = {}), i[f] = h));
878 for (f in k) {
879 if (h = k[f], g = this.props[f], !g) {
880 if (!j) continue;
881 g = d.call(this, f)
882 }
883 b.call(this, g, h)
884 }
885 e && i && e.call(this, i)
886 }
887
888 function u(a) {
889 a.stop()
890 }
891
892 function v(a, b) {
893 a.set(b)
894 }
895
896 function w(a) {
897 this.$el.css(a)
898 }
899
900 function x(a, c) {
901 b[a] = function() {
902 return this.children ? z.call(this, c, arguments) : (this.el && c.apply(this, arguments), this)
903 }
904 }
905
906 function z(a, b) {
907 var c, d = this.children.length;
908 for (c = 0; d > c; c++) a.apply(this.children[c], b);
909 return this
910 }
911 b.init = function(b) {
912 if (this.$el = a(b), this.el = this.$el[0], this.props = {}, this.queue = [], this.style = "", this.active = !1, T.keepInherited && !T.fallback) {
913 var c = V(this.el, "transition");
914 c && !y.test(c) && (this.upstream = c)
915 }
916 F.backface && T.hideBackface && U(this.el, F.backface.css, "hidden")
917 }, x("add", d), x("start", e), x("wait", f), x("then", g), x("next", h), x("stop", k), x("set", l), x("show", m), x("hide", n), x("redraw", o), x("destroy", q)
918 }),
919 L = k(K, function(b) {
920 function c(b, c) {
921 var d = a.data(b, p) || a.data(b, p, new K.Bare);
922 return d.el || d.init(b), c ? d.start(c) : d
923 }
924 b.init = function(b, d) {
925 var e = a(b);
926 if (!e.length) return this;
927 if (1 === e.length) return c(e[0], d);
928 var f = [];
929 return e.each(function(a, b) {
930 f.push(c(b, d))
931 }), this.children = f, this
932 }
933 }),
934 M = k(function(a) {
935 function b() {
936 var a = this.get();
937 this.update("auto");
938 var b = this.get();
939 return this.update(a), b
940 }
941
942 function c(a, b, c) {
943 return void 0 !== b && (c = b), a in l ? a : c
944 }
945
946 function d(a) {
947 var b = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(a);
948 return (b ? e(b[1], b[2], b[3]) : a).replace(/#(\w)(\w)(\w)$/, "#$1$1$2$2$3$3")
949 }
950 var f = {
951 duration: 500,
952 ease: "ease",
953 delay: 0
954 };
955 a.init = function(a, b, d, e) {
956 this.$el = a, this.el = a[0];
957 var g = b[0];
958 d[2] && (g = d[2]), W[g] && (g = W[g]), this.name = g, this.type = d[1], this.duration = i(b[1], this.duration, f.duration), this.ease = c(b[2], this.ease, f.ease), this.delay = i(b[3], this.delay, f.delay), this.span = this.duration + this.delay, this.active = !1, this.nextStyle = null, this.auto = z.test(this.name), this.unit = e.unit || this.unit || T.defaultUnit, this.angle = e.angle || this.angle || T.defaultAngle, T.fallback || e.fallback ? this.animate = this.fallback : (this.animate = this.transition, this.string = this.name + A + this.duration + "ms" + ("ease" != this.ease ? A + l[this.ease][0] : "") + (this.delay ? A + this.delay + "ms" : ""))
959 }, a.set = function(a) {
960 a = this.convert(a, this.type), this.update(a), this.redraw()
961 }, a.transition = function(a) {
962 this.active = !0, a = this.convert(a, this.type), this.auto && ("auto" == this.el.style[this.name] && (this.update(this.get()), this.redraw()), "auto" == a && (a = b.call(this))), this.nextStyle = a
963 }, a.fallback = function(a) {
964 var c = this.el.style[this.name] || this.convert(this.get(), this.type);
965 a = this.convert(a, this.type), this.auto && ("auto" == c && (c = this.convert(this.get(), this.type)), "auto" == a && (a = b.call(this))), this.tween = new Q({
966 from: c,
967 to: a,
968 duration: this.duration,
969 delay: this.delay,
970 ease: this.ease,
971 update: this.update,
972 context: this
973 })
974 }, a.get = function() {
975 return V(this.el, this.name)
976 }, a.update = function(a) {
977 U(this.el, this.name, a)
978 }, a.stop = function() {
979 (this.active || this.nextStyle) && (this.active = !1, this.nextStyle = null, U(this.el, this.name, this.get()));
980 var a = this.tween;
981 a && a.context && a.destroy()
982 }, a.convert = function(a, b) {
983 if ("auto" == a && this.auto) return a;
984 var c, e = "number" == typeof a,
985 f = "string" == typeof a;
986 switch (b) {
987 case s:
988 if (e) return a;
989 if (f && "" === a.replace(q, "")) return +a;
990 c = "number(unitless)";
991 break;
992 case t:
993 if (f) {
994 if ("" === a && this.original) return this.original;
995 if (b.test(a)) return "#" == a.charAt(0) && 7 == a.length ? a : d(a)
996 }
997 c = "hex or rgb string";
998 break;
999 case u:
1000 if (e) return a + this.unit;
1001 if (f && b.test(a)) return a;
1002 c = "number(px) or string(unit)";
1003 break;
1004 case v:
1005 if (e) return a + this.unit;
1006 if (f && b.test(a)) return a;
1007 c = "number(px) or string(unit or %)";
1008 break;
1009 case w:
1010 if (e) return a + this.angle;
1011 if (f && b.test(a)) return a;
1012 c = "number(deg) or string(angle)";
1013 break;
1014 case x:
1015 if (e) return a;
1016 if (f && v.test(a)) return a;
1017 c = "number(unitless) or string(unit or %)"
1018 }
1019 return g(c, a), a
1020 }, a.redraw = function() {
1021 this.el.offsetHeight
1022 }
1023 }),
1024 N = k(M, function(a, b) {
1025 a.init = function() {
1026 b.init.apply(this, arguments), this.original || (this.original = this.convert(this.get(), t))
1027 }
1028 }),
1029 O = k(M, function(a, b) {
1030 a.init = function() {
1031 b.init.apply(this, arguments), this.animate = this.fallback
1032 }, a.get = function() {
1033 return this.$el[this.name]()
1034 }, a.update = function(a) {
1035 this.$el[this.name](a)
1036 }
1037 }),
1038 P = k(M, function(a, b) {
1039 function c(a, b) {
1040 var c, d, e, f, g;
1041 for (c in a) f = Y[c], e = f[0], d = f[1] || c, g = this.convert(a[c], e), b.call(this, d, g, e)
1042 }
1043 a.init = function() {
1044 b.init.apply(this, arguments), this.current || (this.current = {}, Y.perspective && T.perspective && (this.current.perspective = T.perspective, U(this.el, this.name, this.style(this.current)), this.redraw()))
1045 }, a.set = function(a) {
1046 c.call(this, a, function(a, b) {
1047 this.current[a] = b
1048 }), U(this.el, this.name, this.style(this.current)), this.redraw()
1049 }, a.transition = function(a) {
1050 var b = this.values(a);
1051 this.tween = new S({
1052 current: this.current,
1053 values: b,
1054 duration: this.duration,
1055 delay: this.delay,
1056 ease: this.ease
1057 });
1058 var c, d = {};
1059 for (c in this.current) d[c] = c in b ? b[c] : this.current[c];
1060 this.active = !0, this.nextStyle = this.style(d)
1061 }, a.fallback = function(a) {
1062 var b = this.values(a);
1063 this.tween = new S({
1064 current: this.current,
1065 values: b,
1066 duration: this.duration,
1067 delay: this.delay,
1068 ease: this.ease,
1069 update: this.update,
1070 context: this
1071 })
1072 }, a.update = function() {
1073 U(this.el, this.name, this.style(this.current))
1074 }, a.style = function(a) {
1075 var b, c = "";
1076 for (b in a) c += b + "(" + a[b] + ") ";
1077 return c
1078 }, a.values = function(a) {
1079 var b, d = {};
1080 return c.call(this, a, function(a, c, e) {
1081 d[a] = c, void 0 === this.current[a] && (b = 0, ~a.indexOf("scale") && (b = 1), this.current[a] = this.convert(b, e))
1082 }), d
1083 }
1084 }),
1085 Q = k(function(b) {
1086 function c(a) {
1087 1 === n.push(a) && I(g)
1088 }
1089
1090 function g() {
1091 var a, b, c, d = n.length;
1092 if (d)
1093 for (I(g), b = J(), a = d; a--;) c = n[a], c && c.render(b)
1094 }
1095
1096 function i(b) {
1097 var c, d = a.inArray(b, n);
1098 d >= 0 && (c = n.slice(d + 1), n.length = d, c.length && (n = n.concat(c)))
1099 }
1100
1101 function j(a) {
1102 return Math.round(a * o) / o
1103 }
1104
1105 function k(a, b, c) {
1106 return e(a[0] + c * (b[0] - a[0]), a[1] + c * (b[1] - a[1]), a[2] + c * (b[2] - a[2]))
1107 }
1108 var m = {
1109 ease: l.ease[1],
1110 from: 0,
1111 to: 1
1112 };
1113 b.init = function(a) {
1114 this.duration = a.duration || 0, this.delay = a.delay || 0;
1115 var b = a.ease || m.ease;
1116 l[b] && (b = l[b][1]), "function" != typeof b && (b = m.ease), this.ease = b, this.update = a.update || f, this.complete = a.complete || f, this.context = a.context || this, this.name = a.name;
1117 var c = a.from,
1118 d = a.to;
1119 void 0 === c && (c = m.from), void 0 === d && (d = m.to), this.unit = a.unit || "", "number" == typeof c && "number" == typeof d ? (this.begin = c, this.change = d - c) : this.format(d, c), this.value = this.begin + this.unit, this.start = J(), a.autoplay !== !1 && this.play()
1120 }, b.play = function() {
1121 this.active || (this.start || (this.start = J()), this.active = !0, c(this))
1122 }, b.stop = function() {
1123 this.active && (this.active = !1, i(this))
1124 }, b.render = function(a) {
1125 var b, c = a - this.start;
1126 if (this.delay) {
1127 if (c <= this.delay) return;
1128 c -= this.delay
1129 }
1130 if (c < this.duration) {
1131 var d = this.ease(c, 0, 1, this.duration);
1132 return b = this.startRGB ? k(this.startRGB, this.endRGB, d) : j(this.begin + d * this.change), this.value = b + this.unit, void this.update.call(this.context, this.value)
1133 }
1134 b = this.endHex || this.begin + this.change, this.value = b + this.unit, this.update.call(this.context, this.value), this.complete.call(this.context), this.destroy()
1135 }, b.format = function(a, b) {
1136 if (b += "", a += "", "#" == a.charAt(0)) return this.startRGB = d(b), this.endRGB = d(a), this.endHex = a, this.begin = 0, void(this.change = 1);
1137 if (!this.unit) {
1138 var c = b.replace(q, ""),
1139 e = a.replace(q, "");
1140 c !== e && h("tween", b, a), this.unit = c
1141 }
1142 b = parseFloat(b), a = parseFloat(a), this.begin = this.value = b, this.change = a - b
1143 }, b.destroy = function() {
1144 this.stop(), this.context = null, this.ease = this.update = this.complete = f
1145 };
1146 var n = [],
1147 o = 1e3
1148 }),
1149 R = k(Q, function(a) {
1150 a.init = function(a) {
1151 this.duration = a.duration || 0, this.complete = a.complete || f, this.context = a.context, this.play()
1152 }, a.render = function(a) {
1153 var b = a - this.start;
1154 b < this.duration || (this.complete.call(this.context), this.destroy())
1155 }
1156 }),
1157 S = k(Q, function(a, b) {
1158 a.init = function(a) {
1159 this.context = a.context, this.update = a.update, this.tweens = [], this.current = a.current;
1160 var b, c;
1161 for (b in a.values) c = a.values[b], this.current[b] !== c && this.tweens.push(new Q({
1162 name: b,
1163 from: this.current[b],
1164 to: c,
1165 duration: a.duration,
1166 delay: a.delay,
1167 ease: a.ease,
1168 autoplay: !1
1169 }));
1170 this.play()
1171 }, a.render = function(a) {
1172 var b, c, d = this.tweens.length,
1173 e = !1;
1174 for (b = d; b--;) c = this.tweens[b], c.context && (c.render(a), this.current[c.name] = c.value, e = !0);
1175 return e ? void(this.update && this.update.call(this.context)) : this.destroy()
1176 }, a.destroy = function() {
1177 if (b.destroy.call(this), this.tweens) {
1178 var a, c = this.tweens.length;
1179 for (a = c; a--;) this.tweens[a].destroy();
1180 this.tweens = null, this.current = null
1181 }
1182 }
1183 }),
1184 T = b.config = {
1185 defaultUnit: "px",
1186 defaultAngle: "deg",
1187 keepInherited: !1,
1188 hideBackface: !1,
1189 perspective: "",
1190 fallback: !F.transition,
1191 agentTests: []
1192 };
1193 b.fallback = function(a) {
1194 if (!F.transition) return T.fallback = !0;
1195 T.agentTests.push("(" + a + ")");
1196 var b = new RegExp(T.agentTests.join("|"), "i");
1197 T.fallback = b.test(navigator.userAgent)
1198 }, b.fallback("6.0.[2-5] Safari"), b.tween = function(a) {
1199 return new Q(a)
1200 }, b.delay = function(a, b, c) {
1201 return new R({
1202 complete: b,
1203 duration: a,
1204 context: c
1205 })
1206 }, a.fn.tram = function(a) {
1207 return b.call(null, this, a)
1208 };
1209 var U = a.style,
1210 V = a.css,
1211 W = {
1212 transform: F.transform && F.transform.css
1213 },
1214 X = {
1215 color: [N, t],
1216 background: [N, t, "background-color"],
1217 "outline-color": [N, t],
1218 "border-color": [N, t],
1219 "border-top-color": [N, t],
1220 "border-right-color": [N, t],
1221 "border-bottom-color": [N, t],
1222 "border-left-color": [N, t],
1223 "border-width": [M, u],
1224 "border-top-width": [M, u],
1225 "border-right-width": [M, u],
1226 "border-bottom-width": [M, u],
1227 "border-left-width": [M, u],
1228 "border-spacing": [M, u],
1229 "letter-spacing": [M, u],
1230 margin: [M, u],
1231 "margin-top": [M, u],
1232 "margin-right": [M, u],
1233 "margin-bottom": [M, u],
1234 "margin-left": [M, u],
1235 padding: [M, u],
1236 "padding-top": [M, u],
1237 "padding-right": [M, u],
1238 "padding-bottom": [M, u],
1239 "padding-left": [M, u],
1240 "outline-width": [M, u],
1241 opacity: [M, s],
1242 top: [M, v],
1243 right: [M, v],
1244 bottom: [M, v],
1245 left: [M, v],
1246 "font-size": [M, v],
1247 "text-indent": [M, v],
1248 "word-spacing": [M, v],
1249 width: [M, v],
1250 "min-width": [M, v],
1251 "max-width": [M, v],
1252 height: [M, v],
1253 "min-height": [M, v],
1254 "max-height": [M, v],
1255 "line-height": [M, x],
1256 "scroll-top": [O, s, "scrollTop"],
1257 "scroll-left": [O, s, "scrollLeft"]
1258 },
1259 Y = {};
1260 F.transform && (X.transform = [P], Y = {
1261 x: [v, "translateX"],
1262 y: [v, "translateY"],
1263 rotate: [w],
1264 rotateX: [w],
1265 rotateY: [w],
1266 scale: [s],
1267 scaleX: [s],
1268 scaleY: [s],
1269 skew: [w],
1270 skewX: [w],
1271 skewY: [w]
1272 }), F.transform && F.backface && (Y.z = [v, "translateZ"], Y.rotateZ = [w], Y.scaleZ = [s], Y.perspective = [u]);
1273 var Z = /ms/,
1274 $ = /s|\./,
1275 _ = function() {
1276 var a = "warn",
1277 b = window.console;
1278 return b && b[a] ? function(c) {
1279 b[a](c)
1280 } : f
1281 }();
1282 return a.tram = b
1283}(window.jQuery);
1284/*!
1285 * jQuery-ajaxTransport-XDomainRequest - v1.0.1 - 2013-10-17
1286 * https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
1287 * Copyright (c) 2013 Jason Moon (@JSONMOON)
1288 * Licensed MIT (/blob/master/LICENSE.txt)
1289 */
1290(function($) {
1291 if (!$.support.cors && $.ajaxTransport && window.XDomainRequest) {
1292 var n = /^https?:\/\//i;
1293 var o = /^get|post$/i;
1294 var p = new RegExp('^' + location.protocol, 'i');
1295 var q = /text\/html/i;
1296 var r = /\/json/i;
1297 var s = /\/xml/i;
1298 $.ajaxTransport('* text html xml json', function(i, j, k) {
1299 if (i.crossDomain && i.async && o.test(i.type) && n.test(i.url) && p.test(i.url)) {
1300 var l = null;
1301 var m = (j.dataType || '').toLowerCase();
1302 return {
1303 send: function(f, g) {
1304 l = new XDomainRequest();
1305 if (/^\d+$/.test(j.timeout)) {
1306 l.timeout = j.timeout
1307 }
1308 l.ontimeout = function() {
1309 g(500, 'timeout')
1310 };
1311 l.onload = function() {
1312 var a = 'Content-Length: ' + l.responseText.length + '\r\nContent-Type: ' + l.contentType;
1313 var b = {
1314 code: 200,
1315 message: 'success'
1316 };
1317 var c = {
1318 text: l.responseText
1319 };
1320 try {
1321 if (m === 'html' || q.test(l.contentType)) {
1322 c.html = l.responseText
1323 } else if (m === 'json' || (m !== 'text' && r.test(l.contentType))) {
1324 try {
1325 c.json = $.parseJSON(l.responseText)
1326 } catch (e) {
1327 b.code = 500;
1328 b.message = 'parseerror'
1329 }
1330 } else if (m === 'xml' || (m !== 'text' && s.test(l.contentType))) {
1331 var d = new ActiveXObject('Microsoft.XMLDOM');
1332 d.async = false;
1333 try {
1334 d.loadXML(l.responseText)
1335 } catch (e) {
1336 d = undefined
1337 }
1338 if (!d || !d.documentElement || d.getElementsByTagName('parsererror').length) {
1339 b.code = 500;
1340 b.message = 'parseerror';
1341 throw 'Invalid XML: ' + l.responseText;
1342 }
1343 c.xml = d
1344 }
1345 } catch (parseMessage) {
1346 throw parseMessage;
1347 } finally {
1348 g(b.code, b.message, c, a)
1349 }
1350 };
1351 l.onprogress = function() {};
1352 l.onerror = function() {
1353 g(500, 'error', {
1354 text: l.responseText
1355 })
1356 };
1357 var h = '';
1358 if (j.data) {
1359 h = ($.type(j.data) === 'string') ? j.data : $.param(j.data)
1360 }
1361 l.open(i.type, i.url);
1362 l.send(h)
1363 },
1364 abort: function() {
1365 if (l) {
1366 l.abort()
1367 }
1368 }
1369 }
1370 }
1371 })
1372 }
1373})(jQuery);
1374/* jshint ignore:end */
1375/**
1376 * ----------------------------------------------------------------------
1377 * Init lib after plugins
1378 */
1379Webflow.init();
1380/**
1381 * ----------------------------------------------------------------------
1382 * Webflow: Interactions
1383 */
1384Webflow.define('ix', function($, _) {
1385 'use strict';
1386
1387 var api = {};
1388 var designer;
1389 var $win = $(window);
1390 var namespace = '.w-ix';
1391 var tram = window.tram;
1392 var env = Webflow.env;
1393 var ios = env.ios;
1394 var inApp = env();
1395 var emptyFix = env.chrome && env.chrome < 35;
1396 var transNone = 'none 0s ease 0s';
1397 var introEvent = 'w-ix-intro' + namespace;
1398 var outroEvent = 'w-ix-outro' + namespace;
1399 var fallbackProps = /width|height/;
1400 var eventQueue = [];
1401 var $subs = $();
1402 var config = {};
1403 var anchors = [];
1404 var loads = [];
1405 var readys = [];
1406 var unique = 0;
1407 var store;
1408
1409 // Component types and proxy selectors
1410 var components = {
1411 tabs: '.w-tab-link, .w-tab-pane',
1412 dropdown: '.w-dropdown',
1413 slider: '.w-slide',
1414 navbar: '.w-nav'
1415 };
1416
1417 // -----------------------------------
1418 // Module methods
1419
1420 api.init = function(list) {
1421 setTimeout(function() {
1422 init(list);
1423 }, 1);
1424 };
1425
1426 api.preview = function() {
1427 designer = false;
1428 setTimeout(function() {
1429 init(window.__wf_ix);
1430 }, 1);
1431 };
1432
1433 api.design = function() {
1434 designer = true;
1435 $subs.each(teardown);
1436 Webflow.scroll.off(scroll);
1437 asyncEvents();
1438 anchors = [];
1439 loads = [];
1440 readys = [];
1441 };
1442
1443 api.run = run;
1444 api.events = {};
1445 api.style = inApp ? styleApp : stylePub;
1446
1447 // -----------------------------------
1448 // Private methods
1449
1450 function init(list) {
1451 if (!list) return;
1452 store = {};
1453
1454 // Map all interactions to a hash using slug as key.
1455 config = {};
1456 _.each(list, function(item) {
1457 config[item.slug] = item.value;
1458 });
1459
1460 // Build each element's interaction keying from data attribute
1461 var els = $('[data-ix]');
1462 if (!els.length) return;
1463 els.each(teardown);
1464 els.each(build);
1465
1466 // Listen for scroll events if any anchors exist
1467 if (anchors.length) {
1468 Webflow.scroll.on(scroll);
1469 setTimeout(scroll, 1);
1470 }
1471
1472 // Handle loads or readys if they exist
1473 if (loads.length) $win.on('load', runLoads);
1474 if (readys.length) setTimeout(runReadys, 1);
1475
1476 // Init module events
1477 initEvents();
1478 }
1479
1480 function build(i, el) {
1481 var $el = $(el);
1482 var id = $el.attr('data-ix');
1483 var ix = config[id];
1484 if (!ix) return;
1485 var triggers = ix.triggers;
1486 if (!triggers) return;
1487 var state = store[id] || (store[id] = {});
1488
1489 // Set initial styles, unless we detect an iOS device + any non-iOS triggers
1490 var setStyles = !(ios && _.any(triggers, isNonIOS));
1491 if (setStyles) api.style($el, ix.style);
1492
1493 _.each(triggers, function(trigger) {
1494 var type = trigger.type;
1495 var stepsB = trigger.stepsB && trigger.stepsB.length;
1496
1497 function runA() {
1498 run(trigger, $el, {
1499 group: 'A'
1500 });
1501 }
1502
1503 function runB() {
1504 run(trigger, $el, {
1505 group: 'B'
1506 });
1507 }
1508
1509 if (type == 'load') {
1510 (trigger.preload && !inApp) ? loads.push(runA) : readys.push(runA);
1511 return;
1512 }
1513
1514 if (type == 'click') {
1515 var stateKey = 'click:' + unique++;
1516 if (trigger.descend) stateKey += ':descend';
1517 if (trigger.siblings) stateKey += ':siblings';
1518 if (trigger.selector) stateKey += ':' + trigger.selector;
1519
1520 $el.on('click' + namespace, function(evt) {
1521 if ($el.attr('href') === '#') evt.preventDefault();
1522
1523 run(trigger, $el, {
1524 group: state[stateKey] ? 'B' : 'A'
1525 });
1526 if (stepsB) state[stateKey] = !state[stateKey];
1527 });
1528 $subs = $subs.add($el);
1529 return;
1530 }
1531
1532 if (type == 'hover') {
1533 $el.on('mouseenter' + namespace, runA);
1534 $el.on('mouseleave' + namespace, runB);
1535 $subs = $subs.add($el);
1536 return;
1537 }
1538
1539 // Check for a component proxy selector
1540 var proxy = components[type];
1541 if (proxy) {
1542 var $proxy = $el.closest(proxy);
1543 $proxy.on(introEvent, runA).on(outroEvent, runB);
1544 $subs = $subs.add($proxy);
1545 return;
1546 }
1547
1548 // Ignore the following triggers on iOS devices
1549 if (ios) return;
1550
1551 if (type == 'scroll') {
1552 anchors.push({
1553 el: $el,
1554 trigger: trigger,
1555 state: {
1556 active: false
1557 },
1558 offsetTop: convert(trigger.offsetTop),
1559 offsetBot: convert(trigger.offsetBot)
1560 });
1561 return;
1562 }
1563 });
1564 }
1565
1566 function isNonIOS(trigger) {
1567 return trigger.type == 'scroll';
1568 }
1569
1570 function convert(offset) {
1571 if (!offset) return 0;
1572 offset = offset + '';
1573 var result = parseInt(offset, 10);
1574 if (result !== result) return 0;
1575 if (offset.indexOf('%') > 0) {
1576 result = result / 100;
1577 if (result >= 1) result = 0.999;
1578 }
1579 return result;
1580 }
1581
1582 function teardown(i, el) {
1583 $(el).off(namespace);
1584 }
1585
1586 function scroll() {
1587 var viewTop = $win.scrollTop();
1588 var viewHeight = $win.height();
1589
1590 // Check each anchor for a valid scroll trigger
1591 var count = anchors.length;
1592 for (var i = 0; i < count; i++) {
1593 var anchor = anchors[i];
1594 var $el = anchor.el;
1595 var trigger = anchor.trigger;
1596 var stepsB = trigger.stepsB && trigger.stepsB.length;
1597 var state = anchor.state;
1598 var top = $el.offset().top;
1599 var height = $el.outerHeight();
1600 var offsetTop = anchor.offsetTop;
1601 var offsetBot = anchor.offsetBot;
1602 if (offsetTop < 1 && offsetTop > 0) offsetTop *= viewHeight;
1603 if (offsetBot < 1 && offsetBot > 0) offsetBot *= viewHeight;
1604 var active = (top + height - offsetTop >= viewTop && top + offsetBot <= viewTop + viewHeight);
1605 if (active === state.active) continue;
1606 if (active === false && !stepsB) continue;
1607 state.active = active;
1608 run(trigger, $el, {
1609 group: active ? 'A' : 'B'
1610 });
1611 }
1612 }
1613
1614 function runLoads() {
1615 var count = loads.length;
1616 for (var i = 0; i < count; i++) {
1617 loads[i]();
1618 }
1619 }
1620
1621 function runReadys() {
1622 var count = readys.length;
1623 for (var i = 0; i < count; i++) {
1624 readys[i]();
1625 }
1626 }
1627
1628 function run(trigger, $el, opts, replay) {
1629 opts = opts || {};
1630 var done = opts.done;
1631
1632 // Do not run in designer unless forced
1633 if (designer && !opts.force) return;
1634
1635 // Operate on a set of grouped steps
1636 var group = opts.group || 'A';
1637 var loop = trigger['loop' + group];
1638 var steps = trigger['steps' + group];
1639 if (!steps || !steps.length) return;
1640 if (steps.length < 2) loop = false;
1641
1642 // One-time init before any loops
1643 if (!replay) {
1644
1645 // Find selector within element descendants, siblings, or query whole document
1646 var selector = trigger.selector;
1647 if (selector) {
1648 $el = (
1649 trigger.descend ? $el.find(selector) :
1650 trigger.siblings ? $el.siblings(selector) :
1651 $(selector)
1652 );
1653 if (inApp) $el.attr('data-ix-affect', 1);
1654 }
1655
1656 // Apply empty fix for certain Chrome versions
1657 if (emptyFix) $el.addClass('w-ix-emptyfix');
1658 }
1659
1660 var _tram = tram($el);
1661
1662 // Add steps
1663 var meta = {};
1664 for (var i = 0; i < steps.length; i++) {
1665 addStep(_tram, steps[i], meta);
1666 }
1667
1668 function fin() {
1669 // Run trigger again if looped
1670 if (loop) return run(trigger, $el, opts, true);
1671
1672 // Reset any 'auto' values
1673 if (meta.width == 'auto') _tram.set({
1674 width: 'auto'
1675 });
1676 if (meta.height == 'auto') _tram.set({
1677 height: 'auto'
1678 });
1679
1680 // Run callback
1681 done && done();
1682 }
1683
1684 // Add final step to queue if tram has started
1685 meta.start ? _tram.then(fin) : fin();
1686 }
1687
1688 function addStep(_tram, step, meta) {
1689 var addMethod = 'add';
1690 var startMethod = 'start';
1691
1692 // Once the transition has started, we will always use then() to add to the queue.
1693 if (meta.start) addMethod = startMethod = 'then';
1694
1695 // Parse transitions string on the current step
1696 var transitions = step.transition;
1697 if (transitions) {
1698 transitions = transitions.split(',');
1699 for (var i = 0; i < transitions.length; i++) {
1700 var transition = transitions[i];
1701 var options = fallbackProps.test(transition) ? {
1702 fallback: true
1703 } : null;
1704 _tram[addMethod](transition, options);
1705 }
1706 }
1707
1708 // Build a clean object to pass to the tram method
1709 var clean = tramify(step) || {};
1710
1711 // Store last width and height values
1712 if (clean.width != null) meta.width = clean.width;
1713 if (clean.height != null) meta.height = clean.height;
1714
1715 // When transitions are not present, set values immediately and continue queue.
1716 if (transitions == null) {
1717
1718 // If we have started, wrap set() in then() and reset queue
1719 if (meta.start) {
1720 _tram.then(function() {
1721 var queue = this.queue;
1722 this.set(clean);
1723 if (clean.display) {
1724 _tram.redraw();
1725 Webflow.redraw.up();
1726 }
1727 this.queue = queue;
1728 this.next();
1729 });
1730 } else {
1731 _tram.set(clean);
1732
1733 // Always redraw after setting display
1734 if (clean.display) {
1735 _tram.redraw();
1736 Webflow.redraw.up();
1737 }
1738 }
1739
1740 // Use the wait() method to kick off queue in absence of transitions.
1741 var wait = clean.wait;
1742 if (wait != null) {
1743 _tram.wait(wait);
1744 meta.start = true;
1745 }
1746
1747 // Otherwise, when transitions are present
1748 } else {
1749
1750 // If display is present, handle it separately
1751 if (clean.display) {
1752 var display = clean.display;
1753 delete clean.display;
1754
1755 // If we've already started, we need to wrap it in a then()
1756 if (meta.start) {
1757 _tram.then(function() {
1758 var queue = this.queue;
1759 this.set({
1760 display: display
1761 }).redraw();
1762 Webflow.redraw.up();
1763 this.queue = queue;
1764 this.next();
1765 });
1766 } else {
1767 _tram.set({
1768 display: display
1769 }).redraw();
1770 Webflow.redraw.up();
1771 }
1772 }
1773
1774 // Otherwise, start a transition using the current start method.
1775 _tram[startMethod](clean);
1776 meta.start = true;
1777 }
1778 }
1779
1780 // (In app) Set styles immediately and manage upstream transition
1781 function styleApp(el, data) {
1782 var _tram = tram(el);
1783
1784 // Get computed transition value
1785 el.css('transition', '');
1786 var computed = el.css('transition');
1787
1788 // If computed is disabled, clear upstream
1789 if (computed === transNone) computed = _tram.upstream = null;
1790
1791 // Disable upstream temporarily
1792 _tram.upstream = transNone;
1793
1794 // Set values immediately
1795 _tram.set(tramify(data));
1796
1797 // Only restore upstream in preview mode
1798 _tram.upstream = computed;
1799 }
1800
1801 // (Published) Set styles immediately on specified jquery element
1802 function stylePub(el, data) {
1803 tram(el).set(tramify(data));
1804 }
1805
1806 // Build a clean object for tram
1807 function tramify(obj) {
1808 var result = {};
1809 var found = false;
1810 for (var x in obj) {
1811 if (x === 'transition') continue;
1812 result[x] = obj[x];
1813 found = true;
1814 }
1815 // If empty, return null for tram.set/stop compliance
1816 return found ? result : null;
1817 }
1818
1819 // Events used by other webflow modules
1820 var events = {
1821 reset: function(i, el) {
1822 el.__wf_intro = null;
1823 },
1824 intro: function(i, el) {
1825 if (el.__wf_intro) return;
1826 el.__wf_intro = true;
1827 $(el).triggerHandler(introEvent);
1828 },
1829 outro: function(i, el) {
1830 if (!el.__wf_intro) return;
1831 el.__wf_intro = null;
1832 $(el).triggerHandler(outroEvent);
1833 }
1834 };
1835
1836 // Trigger events in queue + point to sync methods
1837 function initEvents() {
1838 var count = eventQueue.length;
1839 for (var i = 0; i < count; i++) {
1840 var memo = eventQueue[i];
1841 memo[0](0, memo[1]);
1842 }
1843 eventQueue = [];
1844 $.extend(api.events, events);
1845 }
1846
1847 // Replace events with async methods prior to init
1848 function asyncEvents() {
1849 _.each(events, function(func, name) {
1850 api.events[name] = function(i, el) {
1851 eventQueue.push([func, el]);
1852 };
1853 });
1854 }
1855
1856 asyncEvents();
1857
1858 // Export module
1859 return api;
1860});
1861/**
1862 * ----------------------------------------------------------------------
1863 * Webflow: Touch events
1864 */
1865Webflow.define('touch', function($, _) {
1866 'use strict';
1867
1868 var api = {};
1869 var fallback = !document.addEventListener;
1870 var getSelection = window.getSelection;
1871
1872 // Fallback to click events in old IE
1873 if (fallback) {
1874 $.event.special.tap = {
1875 bindType: 'click',
1876 delegateType: 'click'
1877 };
1878 }
1879
1880 api.init = function(el) {
1881 if (fallback) return null;
1882 el = typeof el === 'string' ? $(el).get(0) : el;
1883 return el ? new Touch(el) : null;
1884 };
1885
1886 function Touch(el) {
1887 var active = false;
1888 var dirty = false;
1889 var useTouch = false;
1890 var thresholdX = Math.min(Math.round(window.innerWidth * 0.04), 40);
1891 var startX, startY, lastX;
1892 var _move = _.throttle(move);
1893
1894 el.addEventListener('touchstart', start, false);
1895 el.addEventListener('touchmove', _move, false);
1896 el.addEventListener('touchend', end, false);
1897 el.addEventListener('touchcancel', cancel, false);
1898 el.addEventListener('mousedown', start, false);
1899 el.addEventListener('mousemove', _move, false);
1900 el.addEventListener('mouseup', end, false);
1901 el.addEventListener('mouseout', cancel, false);
1902
1903 function start(evt) {
1904 // We don’t handle multi-touch events yet.
1905 var touches = evt.touches;
1906 if (touches && touches.length > 1) {
1907 return;
1908 }
1909
1910 active = true;
1911 dirty = false;
1912
1913 if (touches) {
1914 useTouch = true;
1915 startX = touches[0].clientX;
1916 startY = touches[0].clientY;
1917 } else {
1918 startX = evt.clientX;
1919 startY = evt.clientY;
1920 }
1921
1922 lastX = startX;
1923 }
1924
1925 function move(evt) {
1926 if (!active) return;
1927
1928 if (useTouch && evt.type === 'mousemove') {
1929 evt.preventDefault();
1930 evt.stopPropagation();
1931 return;
1932 }
1933
1934 var touches = evt.touches;
1935 var x = touches ? touches[0].clientX : evt.clientX;
1936 var y = touches ? touches[0].clientY : evt.clientY;
1937
1938 var velocityX = x - lastX;
1939 lastX = x;
1940
1941 // Allow swipes while pointer is down, but prevent them during text selection
1942 if (Math.abs(velocityX) > thresholdX && getSelection && getSelection() + '' === '') {
1943 triggerEvent('swipe', evt, {
1944 direction: velocityX > 0 ? 'right' : 'left'
1945 });
1946 cancel();
1947 }
1948
1949 // If pointer moves more than 10px flag to cancel tap
1950 if (Math.abs(x - startX) > 10 || Math.abs(y - startY) > 10) {
1951 dirty = true;
1952 }
1953 }
1954
1955 function end(evt) {
1956 if (!active) return;
1957 active = false;
1958
1959 if (useTouch && evt.type === 'mouseup') {
1960 evt.preventDefault();
1961 evt.stopPropagation();
1962 useTouch = false;
1963 return;
1964 }
1965
1966 if (!dirty) triggerEvent('tap', evt);
1967 }
1968
1969 function cancel(evt) {
1970 active = false;
1971 }
1972
1973 function destroy() {
1974 el.removeEventListener('touchstart', start, false);
1975 el.removeEventListener('touchmove', _move, false);
1976 el.removeEventListener('touchend', end, false);
1977 el.removeEventListener('touchcancel', cancel, false);
1978 el.removeEventListener('mousedown', start, false);
1979 el.removeEventListener('mousemove', _move, false);
1980 el.removeEventListener('mouseup', end, false);
1981 el.removeEventListener('mouseout', cancel, false);
1982 el = null;
1983 }
1984
1985 // Public instance methods
1986 this.destroy = destroy;
1987 }
1988
1989 // Wrap native event to supoprt preventdefault + stopPropagation
1990 function triggerEvent(type, evt, data) {
1991 var newEvent = $.Event(type, {
1992 originalEvent: evt
1993 });
1994 $(evt.target).trigger(newEvent, data);
1995 }
1996
1997 // Listen for touch events on all nodes by default.
1998 api.instance = api.init(document);
1999
2000 // Export module
2001 return api;
2002});
2003/**
2004 * ----------------------------------------------------------------------
2005 * Webflow: Forms
2006 */
2007Webflow.define('forms', function($, _) {
2008 'use strict';
2009
2010 var api = {};
2011 var $doc = $(document);
2012 var $forms;
2013 var loc = window.location;
2014 var retro = window.XDomainRequest && !window.atob;
2015 var namespace = '.w-form';
2016 var siteId;
2017 var emailField = /e(\-)?mail/i;
2018 var emailValue = /^\S+@\S+$/;
2019 var alert = window.alert;
2020 var listening;
2021
2022 // MailChimp domains: list-manage.com + mirrors
2023 var chimpRegex = /list-manage[1-9]?.com/i;
2024
2025 api.ready = function() {
2026 // Init forms
2027 init();
2028
2029 // Wire document events once
2030 if (!listening) addListeners();
2031 };
2032
2033 api.preview = api.design = function() {
2034 init();
2035 };
2036
2037 function init() {
2038 siteId = $('html').attr('data-wf-site');
2039
2040 $forms = $(namespace + ' form');
2041 if (!$forms.length) return;
2042 $forms.each(build);
2043 }
2044
2045 function build(i, el) {
2046 // Store form state using namespace
2047 var $el = $(el);
2048 var data = $.data(el, namespace);
2049 if (!data) data = $.data(el, namespace, {
2050 form: $el
2051 }); // data.form
2052
2053 reset(data);
2054 var wrap = $el.closest('div.w-form');
2055 data.done = wrap.find('> .w-form-done');
2056 data.fail = wrap.find('> .w-form-fail');
2057
2058 var action = data.action = $el.attr('action');
2059 data.handler = null;
2060 data.redirect = $el.attr('data-redirect');
2061
2062 // MailChimp form
2063 if (chimpRegex.test(action)) {
2064 data.handler = submitMailChimp;
2065 return;
2066 }
2067
2068 // Custom form action
2069 if (action) return;
2070
2071 // Webflow form
2072 if (siteId) {
2073 data.handler = submitWebflow;
2074 return;
2075 }
2076
2077 // Alert for disconnected Webflow forms
2078 disconnected();
2079 }
2080
2081 function addListeners() {
2082 listening = true;
2083
2084 // Handle form submission for Webflow forms
2085 $doc.on('submit', namespace + ' form', function(evt) {
2086 var data = $.data(this, namespace);
2087 if (data.handler) {
2088 data.evt = evt;
2089 data.handler(data);
2090 }
2091 });
2092 }
2093
2094 // Reset data common to all submit handlers
2095 function reset(data) {
2096 var btn = data.btn = data.form.find(':input[type="submit"]');
2097 data.wait = data.btn.attr('data-wait') || null;
2098 data.success = false;
2099 btn.prop('disabled', false);
2100 data.label && btn.val(data.label);
2101 }
2102
2103 // Disable submit button
2104 function disableBtn(data) {
2105 var btn = data.btn;
2106 var wait = data.wait;
2107 btn.prop('disabled', true);
2108 // Show wait text and store previous label
2109 if (wait) {
2110 data.label = btn.val();
2111 btn.val(wait);
2112 }
2113 }
2114
2115 // Find form fields, validate, and set value pairs
2116 function findFields(form, result) {
2117 var status = null;
2118 result = result || {};
2119
2120 // The ":input" selector is a jQuery shortcut to select all inputs, selects, textareas
2121 form.find(':input:not([type="submit"])').each(function(i, el) {
2122 var field = $(el);
2123 var type = field.attr('type');
2124 var name = field.attr('data-name') || field.attr('name') || ('Field ' + (i + 1));
2125 var value = field.val();
2126
2127 if (type == 'checkbox') {
2128 value = field.is(':checked');
2129 }
2130 if (type == 'radio') {
2131 // Radio group value already processed
2132 if (result[name] === null || typeof result[name] == 'string') {
2133 return;
2134 }
2135
2136 value = form.find('input[name="' + field.attr('name') + '"]:checked').val() || null;
2137 }
2138
2139 if (typeof value == 'string') value = $.trim(value);
2140 result[name] = value;
2141 status = status || getStatus(field, name, value);
2142 });
2143
2144 return status;
2145 }
2146
2147 function getStatus(field, name, value) {
2148 var status = null;
2149 if (!field.attr('required')) return null;
2150 if (!value) status = 'Please fill out the required field: ' + name;
2151 else if (emailField.test(name) || emailField.test(field.attr('type'))) {
2152 if (!emailValue.test(value)) status = 'Please enter a valid email address for: ' + name;
2153 }
2154 return status;
2155 }
2156
2157 // Submit form to Webflow
2158 function submitWebflow(data) {
2159 reset(data);
2160
2161 var form = data.form;
2162 var payload = {
2163 name: form.attr('data-name') || form.attr('name') || 'Untitled Form',
2164 source: loc.href,
2165 test: Webflow.env(),
2166 fields: {}
2167 };
2168
2169 preventDefault(data);
2170
2171 // Find & populate all fields
2172 var status = findFields(form, payload.fields);
2173 if (status) return alert(status);
2174
2175 // Disable submit button
2176 disableBtn(data);
2177
2178 // Read site ID
2179 // NOTE: If this site is exported, the HTML tag must retain the data-wf-site attribute for forms to work
2180 if (!siteId) {
2181 afterSubmit(data);
2182 return;
2183 }
2184 var url = 'https://webflow.com/api/v1/form/' + siteId;
2185
2186 // Work around same-protocol IE XDR limitation
2187 if (retro && url.indexOf('https://webflow.com') >= 0) {
2188 url = url.replace('https://webflow.com/', 'http://data.webflow.com/');
2189 }
2190
2191 $.ajax({
2192 url: url,
2193 type: 'POST',
2194 data: payload,
2195 dataType: 'json',
2196 crossDomain: true
2197 }).done(function() {
2198 data.success = true;
2199 afterSubmit(data);
2200 }).fail(function() {
2201 afterSubmit(data);
2202 });
2203 }
2204
2205 // Submit form to MailChimp
2206 function submitMailChimp(data) {
2207 reset(data);
2208
2209 var form = data.form;
2210 var payload = {};
2211
2212 // Skip Ajax submission if http/s mismatch, fallback to POST instead
2213 if (/^https/.test(loc.href) && !/^https/.test(data.action)) {
2214 form.attr('method', 'post');
2215 return;
2216 }
2217
2218 preventDefault(data);
2219
2220 // Find & populate all fields
2221 var status = findFields(form, payload);
2222 if (status) return alert(status);
2223
2224 // Disable submit button
2225 disableBtn(data);
2226
2227 // Use special format for MailChimp params
2228 var fullName;
2229 _.each(payload, function(value, key) {
2230 if (emailField.test(key)) payload.EMAIL = value;
2231 if (/^((full[ _-]?)?name)$/i.test(key)) fullName = value;
2232 if (/^(first[ _-]?name)$/i.test(key)) payload.FNAME = value;
2233 if (/^(last[ _-]?name)$/i.test(key)) payload.LNAME = value;
2234 });
2235
2236 if (fullName && !payload.FNAME) {
2237 fullName = fullName.split(' ');
2238 payload.FNAME = fullName[0];
2239 payload.LNAME = payload.LNAME || fullName[1];
2240 }
2241
2242 // Use the (undocumented) MailChimp jsonp api
2243 var url = data.action.replace('/post?', '/post-json?') + '&c=?';
2244 // Add special param to prevent bot signups
2245 var userId = url.indexOf('u=') + 2;
2246 userId = url.substring(userId, url.indexOf('&', userId));
2247 var listId = url.indexOf('id=') + 3;
2248 listId = url.substring(listId, url.indexOf('&', listId));
2249 payload['b_' + userId + '_' + listId] = '';
2250
2251 $.ajax({
2252 url: url,
2253 data: payload,
2254 dataType: 'jsonp'
2255 }).done(function(resp) {
2256 data.success = (resp.result == 'success' || /already/.test(resp.msg));
2257 if (!data.success) console.info('MailChimp error: ' + resp.msg);
2258 afterSubmit(data);
2259 }).fail(function() {
2260 afterSubmit(data);
2261 });
2262 }
2263
2264 // Common callback which runs after all Ajax submissions
2265 function afterSubmit(data) {
2266 var form = data.form;
2267 var wrap = form.closest('div.w-form');
2268 var redirect = data.redirect;
2269 var success = data.success;
2270
2271 // Redirect to a success url if defined
2272 if (success && redirect) {
2273 Webflow.location(redirect);
2274 return;
2275 }
2276
2277 // Show or hide status divs
2278 data.done.toggle(success);
2279 data.fail.toggle(!success);
2280
2281 // Hide form on success
2282 form.toggle(!success);
2283
2284 // Reset data and enable submit button
2285 reset(data);
2286 }
2287
2288 function preventDefault(data) {
2289 data.evt && data.evt.preventDefault();
2290 data.evt = null;
2291 }
2292
2293 var disconnected = _.debounce(function() {
2294 alert('Oops! This page has a form that is powered by Webflow, but important code was removed that is required to make the form work. Please contact [email protected] to fix this issue.');
2295 }, 100);
2296
2297 // Export module
2298 return api;
2299});
2300/**
2301 * ----------------------------------------------------------------------
2302 * Webflow: Smooth scroll
2303 */
2304Webflow.define('scroll', function($) {
2305 'use strict';
2306
2307 var $doc = $(document);
2308 var win = window;
2309 var loc = win.location;
2310 var history = win.history;
2311 var validHash = /^[a-zA-Z][\w:.-]*$/;
2312
2313 function ready() {
2314 // If hash is already present on page load, scroll to it right away
2315 if (loc.hash) {
2316 findEl(loc.hash.substring(1));
2317 }
2318
2319 // When clicking on a link, check if it links to another part of the page
2320 $doc.on('click', 'a', function(e) {
2321 if (Webflow.env('design')) {
2322 return;
2323 }
2324
2325 // Ignore links being used by jQuery mobile
2326 if (window.$.mobile && $(e.currentTarget).hasClass('ui-link')) return;
2327
2328 var hash = this.hash ? this.hash.substring(1) : null;
2329 if (hash) {
2330 findEl(hash, e);
2331 }
2332 });
2333 }
2334
2335 function findEl(hash, e) {
2336 if (!validHash.test(hash)) return;
2337
2338 var el = $('#' + hash);
2339 if (!el.length) {
2340 return;
2341 }
2342
2343 if (e) {
2344 e.preventDefault();
2345 e.stopPropagation();
2346 }
2347
2348 // Push new history state
2349 if (loc.hash !== hash && history && history.pushState) {
2350 var oldHash = history.state && history.state.hash;
2351 if (oldHash !== hash) {
2352 history.pushState({
2353 hash: hash
2354 }, '', '#' + hash);
2355 }
2356 }
2357
2358 // If a fixed header exists, offset for the height
2359 var header = $('header, body > .header, body > .w-nav');
2360 var offset = header.css('position') === 'fixed' ? header.outerHeight() : 0;
2361
2362 win.setTimeout(function() {
2363 scroll(el, offset);
2364 }, e ? 0 : 300);
2365 }
2366
2367 function scroll(el, offset) {
2368 var start = $(win).scrollTop();
2369 var end = el.offset().top - offset;
2370
2371 // If specified, scroll so that the element ends up in the middle of the viewport
2372 if (el.data('scroll') == 'mid') {
2373 var available = $(win).height() - offset;
2374 var elHeight = el.outerHeight();
2375 if (elHeight < available) {
2376 end -= Math.round((available - elHeight) / 2);
2377 }
2378 }
2379
2380 var mult = 1;
2381
2382 // Check for custom time multiplier on the body and the element
2383 $('body').add(el).each(function(i) {
2384 var time = parseFloat($(this).attr('data-scroll-time'), 10);
2385 if (!isNaN(time) && (time === 0 || time > 0)) {
2386 mult = time;
2387 }
2388 });
2389
2390 // Shim for IE8 and below
2391 if (!Date.now) {
2392 Date.now = function() {
2393 return new Date().getTime();
2394 };
2395 }
2396
2397 var clock = Date.now();
2398 var animate = win.requestAnimationFrame || win.mozRequestAnimationFrame || win.webkitRequestAnimationFrame || function(fn) {
2399 win.setTimeout(fn, 15);
2400 };
2401 var duration = (472.143 * Math.log(Math.abs(start - end) + 125) - 2000) * mult;
2402
2403 var step = function() {
2404 var elapsed = Date.now() - clock;
2405 win.scroll(0, getY(start, end, elapsed, duration));
2406
2407 if (elapsed <= duration) {
2408 animate(step);
2409 }
2410 };
2411
2412 step();
2413 }
2414
2415 function getY(start, end, elapsed, duration) {
2416 if (elapsed > duration) {
2417 return end;
2418 }
2419
2420 return start + (end - start) * ease(elapsed / duration);
2421 }
2422
2423 function ease(t) {
2424 return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
2425 }
2426
2427 // Export module
2428 return {
2429 ready: ready
2430 };
2431});
2432/**
2433 * ----------------------------------------------------------------------
2434 * Webflow: Auto-select links to current page or section
2435 */
2436Webflow.define('links', function($, _) {
2437 'use strict';
2438
2439 var api = {};
2440 var $win = $(window);
2441 var designer;
2442 var inApp = Webflow.env();
2443 var location = window.location;
2444 var linkCurrent = 'w--current';
2445 var validHash = /^#[a-zA-Z][\w:.-]*$/;
2446 var indexPage = /index\.(html|php)$/;
2447 var dirList = /\/$/;
2448 var anchors;
2449 var slug;
2450
2451 // -----------------------------------
2452 // Module methods
2453
2454 api.ready = api.design = api.preview = init;
2455
2456 // -----------------------------------
2457 // Private methods
2458
2459 function init() {
2460 designer = inApp && Webflow.env('design');
2461 slug = Webflow.env('slug') || location.pathname || '';
2462
2463 // Reset scroll listener, init anchors
2464 Webflow.scroll.off(scroll);
2465 anchors = [];
2466
2467 // Test all links for a selectable href
2468 var links = document.links;
2469 for (var i = 0; i < links.length; ++i) {
2470 select(links[i]);
2471 }
2472
2473 // Listen for scroll if any anchors exist
2474 if (anchors.length) {
2475 Webflow.scroll.on(scroll);
2476 scroll();
2477 }
2478 }
2479
2480 function select(link) {
2481 var href = link.getAttribute('href');
2482
2483 // Ignore any hrefs with a colon to safely avoid all uri schemes
2484 if (href.indexOf(':') >= 0) return;
2485
2486 var $link = $(link);
2487
2488 // Check for valid hash links w/ sections and use scroll anchor
2489 if (href.indexOf('#') === 0 && validHash.test(href)) {
2490 // Ignore #edit anchors
2491 if (href === '#edit') return;
2492 var $section = $(href);
2493 $section.length && anchors.push({
2494 link: $link,
2495 sec: $section,
2496 active: false
2497 });
2498 return;
2499 }
2500
2501 // Determine whether the link should be selected
2502 var match = (link.href === location.href) || (href === slug) || (indexPage.test(href) && dirList.test(slug));
2503 setClass($link, linkCurrent, match);
2504 }
2505
2506 function scroll() {
2507 var viewTop = $win.scrollTop();
2508 var viewHeight = $win.height();
2509
2510 // Check each anchor for a section in view
2511 _.each(anchors, function(anchor) {
2512 var $link = anchor.link;
2513 var $section = anchor.sec;
2514 var top = $section.offset().top;
2515 var height = $section.outerHeight();
2516 var offset = viewHeight * 0.5;
2517 var active = ($section.is(':visible') &&
2518 top + height - offset >= viewTop &&
2519 top + offset <= viewTop + viewHeight);
2520 if (anchor.active === active) return;
2521 anchor.active = active;
2522 setClass($link, linkCurrent, active);
2523 if (designer) $link[0].__wf_current = active;
2524 });
2525 }
2526
2527 function setClass($elem, className, add) {
2528 var exists = $elem.hasClass(className);
2529 if (add && exists) return;
2530 if (!add && !exists) return;
2531 add ? $elem.addClass(className) : $elem.removeClass(className);
2532 }
2533
2534 // Export module
2535 return api;
2536});
2537/**
2538 * ----------------------------------------------------------------------
2539 * Webflow: Slider component
2540 */
2541Webflow.define('slider', function($, _) {
2542 'use strict';
2543
2544 var api = {};
2545 var tram = window.tram;
2546 var $doc = $(document);
2547 var $sliders;
2548 var designer;
2549 var inApp = Webflow.env();
2550 var namespace = '.w-slider';
2551 var dot = '<div class="w-slider-dot" data-wf-ignore />';
2552 var ix = Webflow.ixEvents();
2553 var fallback;
2554 var redraw;
2555
2556 // -----------------------------------
2557 // Module methods
2558
2559 api.ready = function() {
2560 init();
2561 };
2562
2563 api.design = function() {
2564 designer = true;
2565 init();
2566 };
2567
2568 api.preview = function() {
2569 designer = false;
2570 init();
2571 };
2572
2573 api.redraw = function() {
2574 redraw = true;
2575 init();
2576 };
2577
2578 api.destroy = removeListeners;
2579
2580 // -----------------------------------
2581 // Private methods
2582
2583 function init() {
2584 // Find all sliders on the page
2585 $sliders = $doc.find(namespace);
2586 if (!$sliders.length) return;
2587 $sliders.filter(':visible').each(build);
2588 redraw = null;
2589 if (fallback) return;
2590
2591 // Wire events
2592 removeListeners();
2593 addListeners();
2594 }
2595
2596 function removeListeners() {
2597 Webflow.resize.off(renderAll);
2598 Webflow.redraw.off(api.redraw);
2599 }
2600
2601 function addListeners() {
2602 Webflow.resize.on(renderAll);
2603 Webflow.redraw.on(api.redraw);
2604 }
2605
2606 function renderAll() {
2607 $sliders.filter(':visible').each(render);
2608 }
2609
2610 function build(i, el) {
2611 var $el = $(el);
2612
2613 // Store slider state in data
2614 var data = $.data(el, namespace);
2615 if (!data) data = $.data(el, namespace, {
2616 index: 0,
2617 depth: 1,
2618 el: $el,
2619 config: {}
2620 });
2621 data.mask = $el.children('.w-slider-mask');
2622 data.left = $el.children('.w-slider-arrow-left');
2623 data.right = $el.children('.w-slider-arrow-right');
2624 data.nav = $el.children('.w-slider-nav');
2625 data.slides = data.mask.children('.w-slide');
2626 data.slides.each(ix.reset);
2627 if (redraw) data.maskWidth = 0;
2628
2629 // Disable in old browsers
2630 if (!tram.support.transform) {
2631 data.left.hide();
2632 data.right.hide();
2633 data.nav.hide();
2634 fallback = true;
2635 return;
2636 }
2637
2638 // Remove old events
2639 data.el.off(namespace);
2640 data.left.off(namespace);
2641 data.right.off(namespace);
2642 data.nav.off(namespace);
2643
2644 // Set config from data attributes
2645 configure(data);
2646
2647 // Add events based on mode
2648 if (designer) {
2649 data.el.on('setting' + namespace, handler(data));
2650 stopTimer(data);
2651 data.hasTimer = false;
2652 } else {
2653 data.el.on('swipe' + namespace, handler(data));
2654 data.left.on('tap' + namespace, previous(data));
2655 data.right.on('tap' + namespace, next(data));
2656
2657 // Start timer if autoplay is true, only once
2658 if (data.config.autoplay && !data.hasTimer) {
2659 data.hasTimer = true;
2660 data.timerCount = 1;
2661 startTimer(data);
2662 }
2663 }
2664
2665 // Listen to nav events
2666 data.nav.on('tap' + namespace, '> div', handler(data));
2667
2668 // Remove gaps from formatted html (for inline-blocks)
2669 if (!inApp) {
2670 data.mask.contents().filter(function() {
2671 return this.nodeType === 3;
2672 }).remove();
2673 }
2674
2675 // Run first render
2676 render(i, el);
2677 }
2678
2679 function configure(data) {
2680 var config = {};
2681
2682 config.crossOver = 0;
2683
2684 // Set config options from data attributes
2685 config.animation = data.el.attr('data-animation') || 'slide';
2686 if (config.animation == 'outin') {
2687 config.animation = 'cross';
2688 config.crossOver = 0.5;
2689 }
2690 config.easing = data.el.attr('data-easing') || 'ease';
2691
2692 var duration = data.el.attr('data-duration');
2693 config.duration = duration != null ? +duration : 500;
2694
2695 if (+data.el.attr('data-infinite')) config.infinite = true;
2696
2697 if (+data.el.attr('data-hide-arrows')) {
2698 config.hideArrows = true;
2699 } else if (data.config.hideArrows) {
2700 data.left.show();
2701 data.right.show();
2702 }
2703
2704 if (+data.el.attr('data-autoplay')) {
2705 config.autoplay = true;
2706 config.delay = +data.el.attr('data-delay') || 2000;
2707 config.timerMax = +data.el.attr('data-autoplay-limit');
2708 // Disable timer on first touch or mouse down
2709 var touchEvents = 'mousedown' + namespace + ' touchstart' + namespace;
2710 if (!designer) data.el.off(touchEvents).one(touchEvents, function() {
2711 stopTimer(data);
2712 });
2713 }
2714
2715 // Use edge buffer to help calculate page count
2716 var arrowWidth = data.right.width();
2717 config.edge = arrowWidth ? arrowWidth + 40 : 100;
2718
2719 // Store config in data
2720 data.config = config;
2721 }
2722
2723 function previous(data) {
2724 return function(evt) {
2725 change(data, {
2726 index: data.index - 1,
2727 vector: -1
2728 });
2729 };
2730 }
2731
2732 function next(data) {
2733 return function(evt) {
2734 change(data, {
2735 index: data.index + 1,
2736 vector: 1
2737 });
2738 };
2739 }
2740
2741 function select(data, value) {
2742 // Select page based on slide element index
2743 var found = null;
2744 if (value === data.slides.length) {
2745 init();
2746 layout(data); // Rebuild and find new slides
2747 }
2748 _.each(data.anchors, function(anchor, index) {
2749 $(anchor.els).each(function(i, el) {
2750 if ($(el).index() === value) found = index;
2751 });
2752 });
2753 if (found != null) change(data, {
2754 index: found,
2755 immediate: true
2756 });
2757 }
2758
2759 function startTimer(data) {
2760 stopTimer(data);
2761 var config = data.config;
2762 var timerMax = config.timerMax;
2763 if (timerMax && data.timerCount++ > timerMax) return;
2764 data.timerId = window.setTimeout(function() {
2765 if (data.timerId == null || designer) return;
2766 next(data)();
2767 startTimer(data);
2768 }, config.delay);
2769 }
2770
2771 function stopTimer(data) {
2772 window.clearTimeout(data.timerId);
2773 data.timerId = null;
2774 }
2775
2776 function handler(data) {
2777 return function(evt, options) {
2778 options = options || {};
2779
2780 // Designer settings
2781 if (designer && evt.type == 'setting') {
2782 if (options.select == 'prev') return previous(data)();
2783 if (options.select == 'next') return next(data)();
2784 configure(data);
2785 layout(data);
2786 if (options.select == null) return;
2787 select(data, options.select);
2788 return;
2789 }
2790
2791 // Swipe event
2792 if (evt.type == 'swipe') {
2793 if (options.direction == 'left') return next(data)();
2794 if (options.direction == 'right') return previous(data)();
2795 return;
2796 }
2797
2798 // Page buttons
2799 if (data.nav.has(evt.target).length) {
2800 change(data, {
2801 index: $(evt.target).index()
2802 });
2803 }
2804 };
2805 }
2806
2807 function change(data, options) {
2808 options = options || {};
2809 var config = data.config;
2810 var anchors = data.anchors;
2811
2812 // Set new index
2813 data.previous = data.index;
2814 var index = options.index;
2815 var shift = {};
2816 if (index < 0) {
2817 index = anchors.length - 1;
2818 if (config.infinite) {
2819 // Shift first slide to the end
2820 shift.x = -data.endX;
2821 shift.from = 0;
2822 shift.to = anchors[0].width;
2823 }
2824 } else if (index >= anchors.length) {
2825 index = 0;
2826 if (config.infinite) {
2827 // Shift last slide to the start
2828 shift.x = anchors[anchors.length - 1].width;
2829 shift.from = -anchors[anchors.length - 1].x;
2830 shift.to = shift.from - shift.x;
2831 }
2832 }
2833 data.index = index;
2834
2835 // Select page nav
2836 var active = data.nav.children().eq(data.index).addClass('w-active');
2837 data.nav.children().not(active).removeClass('w-active');
2838
2839 // Hide arrows
2840 if (config.hideArrows) {
2841 data.index === anchors.length - 1 ? data.right.hide() : data.right.show();
2842 data.index === 0 ? data.left.hide() : data.left.show();
2843 }
2844
2845 // Get page offset from anchors
2846 var lastOffsetX = data.offsetX || 0;
2847 var offsetX = data.offsetX = -anchors[data.index].x;
2848 var resetConfig = {
2849 x: offsetX,
2850 opacity: 1,
2851 visibility: ''
2852 };
2853
2854 // Transition slides
2855 var targets = $(anchors[data.index].els);
2856 var previous = $(anchors[data.previous] && anchors[data.previous].els);
2857 var others = data.slides.not(targets);
2858 var animation = config.animation;
2859 var easing = config.easing;
2860 var duration = Math.round(config.duration);
2861 var vector = options.vector || (data.index > data.previous ? 1 : -1);
2862 var fadeRule = 'opacity ' + duration + 'ms ' + easing;
2863 var slideRule = 'transform ' + duration + 'ms ' + easing;
2864
2865 // Trigger IX events
2866 if (!designer) {
2867 targets.each(ix.intro);
2868 others.each(ix.outro);
2869 }
2870
2871 // Set immediately after layout changes (but not during redraw)
2872 if (options.immediate && !redraw) {
2873 tram(targets).set(resetConfig);
2874 resetOthers();
2875 return;
2876 }
2877
2878 // Exit early if index is unchanged
2879 if (data.index == data.previous) return;
2880
2881 // Cross Fade / Out-In
2882 if (animation == 'cross') {
2883 var reduced = Math.round(duration - duration * config.crossOver);
2884 var wait = Math.round(duration - reduced);
2885 fadeRule = 'opacity ' + reduced + 'ms ' + easing;
2886 tram(previous)
2887 .set({
2888 visibility: ''
2889 })
2890 .add(fadeRule)
2891 .start({
2892 opacity: 0
2893 });
2894 tram(targets)
2895 .set({
2896 visibility: '',
2897 x: offsetX,
2898 opacity: 0,
2899 zIndex: data.depth++
2900 })
2901 .add(fadeRule)
2902 .wait(wait)
2903 .then({
2904 opacity: 1
2905 })
2906 .then(resetOthers);
2907 return;
2908 }
2909
2910 // Fade Over
2911 if (animation == 'fade') {
2912 tram(previous)
2913 .set({
2914 visibility: ''
2915 })
2916 .stop();
2917 tram(targets)
2918 .set({
2919 visibility: '',
2920 x: offsetX,
2921 opacity: 0,
2922 zIndex: data.depth++
2923 })
2924 .add(fadeRule)
2925 .start({
2926 opacity: 1
2927 })
2928 .then(resetOthers);
2929 return;
2930 }
2931
2932 // Slide Over
2933 if (animation == 'over') {
2934 resetConfig = {
2935 x: data.endX
2936 };
2937 tram(previous)
2938 .set({
2939 visibility: ''
2940 })
2941 .stop();
2942 tram(targets)
2943 .set({
2944 visibility: '',
2945 zIndex: data.depth++,
2946 x: offsetX + anchors[data.index].width * vector
2947 })
2948 .add(slideRule)
2949 .start({
2950 x: offsetX
2951 })
2952 .then(resetOthers);
2953 return;
2954 }
2955
2956 // Slide - infinite scroll
2957 if (config.infinite && shift.x) {
2958 tram(data.slides.not(previous))
2959 .set({
2960 visibility: '',
2961 x: shift.x
2962 })
2963 .add(slideRule)
2964 .start({
2965 x: offsetX
2966 });
2967 tram(previous)
2968 .set({
2969 visibility: '',
2970 x: shift.from
2971 })
2972 .add(slideRule)
2973 .start({
2974 x: shift.to
2975 });
2976 data.shifted = previous;
2977
2978 } else {
2979 if (config.infinite && data.shifted) {
2980 tram(data.shifted).set({
2981 visibility: '',
2982 x: lastOffsetX
2983 });
2984 data.shifted = null;
2985 }
2986
2987 // Slide - basic scroll
2988 tram(data.slides)
2989 .set({
2990 visibility: ''
2991 })
2992 .add(slideRule)
2993 .start({
2994 x: offsetX
2995 });
2996 }
2997
2998 // Helper to move others out of view
2999 function resetOthers() {
3000 var targets = $(anchors[data.index].els);
3001 var others = data.slides.not(targets);
3002 if (animation != 'slide') resetConfig.visibility = 'hidden';
3003 tram(others).set(resetConfig);
3004 }
3005 }
3006
3007 function render(i, el) {
3008 var data = $.data(el, namespace);
3009 if (maskChanged(data)) return layout(data);
3010 if (designer && slidesChanged(data)) layout(data);
3011 }
3012
3013 function layout(data) {
3014 // Determine page count from width of slides
3015 var pages = 1;
3016 var offset = 0;
3017 var anchor = 0;
3018 var width = 0;
3019 data.anchors = [{
3020 els: [],
3021 x: 0,
3022 width: 0
3023 }];
3024 data.slides.each(function(i, el) {
3025 if (anchor - offset > data.maskWidth - data.config.edge) {
3026 pages++;
3027 offset += data.maskWidth;
3028 // Store page anchor for transition
3029 data.anchors[pages - 1] = {
3030 els: [],
3031 x: anchor,
3032 width: 0
3033 };
3034 }
3035 // Set next anchor using current width + margin
3036 width = $(el).outerWidth(true);
3037 anchor += width;
3038 data.anchors[pages - 1].width += width;
3039 data.anchors[pages - 1].els.push(el);
3040 });
3041 data.endX = anchor;
3042
3043 // Build dots if nav exists and needs updating
3044 if (designer) data.pages = null;
3045 if (data.nav.length && data.pages !== pages) {
3046 data.pages = pages;
3047 buildNav(data);
3048 }
3049
3050 // Make sure index is still within range and call change handler
3051 var index = data.index;
3052 if (index >= pages) index = pages - 1;
3053 change(data, {
3054 immediate: true,
3055 index: index
3056 });
3057 }
3058
3059 function buildNav(data) {
3060 var dots = [];
3061 var $dot;
3062 var spacing = data.el.attr('data-nav-spacing');
3063 if (spacing) spacing = parseFloat(spacing) + 'px';
3064 for (var i = 0; i < data.pages; i++) {
3065 $dot = $(dot);
3066 if (data.nav.hasClass('w-num')) $dot.text(i + 1);
3067 if (spacing != null) $dot.css({
3068 'margin-left': spacing,
3069 'margin-right': spacing
3070 });
3071 dots.push($dot);
3072 }
3073 data.nav.empty().append(dots);
3074 }
3075
3076 function maskChanged(data) {
3077 var maskWidth = data.mask.width();
3078 if (data.maskWidth !== maskWidth) {
3079 data.maskWidth = maskWidth;
3080 return true;
3081 }
3082 return false;
3083 }
3084
3085 function slidesChanged(data) {
3086 var slidesWidth = 0;
3087 data.slides.each(function(i, el) {
3088 slidesWidth += $(el).outerWidth(true);
3089 });
3090 if (data.slidesWidth !== slidesWidth) {
3091 data.slidesWidth = slidesWidth;
3092 return true;
3093 }
3094 return false;
3095 }
3096
3097 // Export module
3098 return api;
3099});
3100/**
3101 * ----------------------------------------------------------------------
3102 * Webflow: Lightbox component
3103 */
3104var lightbox = (function(window, document, $, tram, undefined) {
3105 'use strict';
3106
3107 var isArray = Array.isArray;
3108 var namespace = 'w-lightbox';
3109 var prefix = namespace + '-';
3110 var prefixRegex = /(^|\s+)/g;
3111 var matchMedia = window.matchMedia || function(media) {
3112 // IE9 polyfill
3113 return {
3114 matches: window.styleMedia.matchMedium(media)
3115 };
3116 };
3117 var pixelRatio = window.devicePixelRatio || 1;
3118 var breakpoint = '(min-width: 1025px)';
3119
3120 // Array of objects describing items to be displayed.
3121 var items = [];
3122
3123 // Index of the currently displayed item.
3124 var currentIndex;
3125
3126 // Object holding references to jQuery wrapped nodes.
3127 var $refs;
3128
3129 // Instance of Spinner
3130 var spinner;
3131
3132 function lightbox(thing, index) {
3133 items = isArray(thing) ? thing : [thing];
3134
3135 if (!$refs) {
3136 lightbox.build();
3137 }
3138
3139 if (items.length > 1) {
3140 $refs.items = $refs.empty;
3141
3142 items.forEach(function(item) {
3143 var $thumbnail = dom('thumbnail');
3144 var $item = dom('item').append($thumbnail);
3145
3146 $refs.items = $refs.items.add($item);
3147
3148 loadImage(item.url, function($image) {
3149 if ($image.prop('width') > $image.prop('height')) {
3150 addClass($image, 'wide');
3151 } else {
3152 addClass($image, 'tall');
3153 }
3154 $thumbnail.append(addClass($image, 'thumbnail-image'));
3155 });
3156 });
3157
3158 $refs.strip.empty().append($refs.items);
3159 addClass($refs.content, 'group');
3160 }
3161
3162 tram(
3163 // Focus the lightbox to receive keyboard events.
3164 removeClass($refs.lightbox, 'hide').focus()
3165 )
3166 .add('opacity .3s')
3167 .start({
3168 opacity: 1
3169 });
3170
3171 // Prevent document from scrolling while lightbox is active.
3172 addClass($refs.html, 'noscroll');
3173
3174 return lightbox.show(index || 0);
3175 }
3176
3177 /**
3178 * Creates the DOM structure required by the lightbox.
3179 */
3180 lightbox.build = function() {
3181 // In case `build` is called more than once.
3182 lightbox.destroy();
3183
3184 $refs = {
3185 html: $(document.documentElement),
3186 // Empty jQuery object can be used to build new ones using `.add`.
3187 empty: $()
3188 };
3189
3190 $refs.arrowLeft = dom('control left inactive');
3191 $refs.arrowRight = dom('control right inactive');
3192 $refs.close = dom('control close');
3193 $refs.controls = $refs.empty.add($refs.arrowLeft).add($refs.arrowRight).add($refs.close);
3194
3195 $refs.spinner = dom('spinner');
3196 $refs.strip = dom('strip');
3197
3198 spinner = new Spinner($refs.spinner, prefixed('hide'));
3199
3200 $refs.content = dom('content')
3201 .append($refs.spinner, $refs.controls);
3202
3203 $refs.container = dom('container')
3204 .append($refs.content, $refs.strip);
3205
3206 $refs.lightbox = dom('backdrop hide')
3207 .append($refs.container);
3208
3209 // We are delegating events for performance reasons and also
3210 // to not have to reattach handlers when images change.
3211 $refs.strip.on('tap', selector('item'), itemTapHandler);
3212 $refs.content
3213 .on('swipe', swipeHandler)
3214 .on('tap', selector('left'), preventDefaultAnd(lightbox.prev))
3215 .on('tap', selector('right'), preventDefaultAnd(lightbox.next))
3216 .on('tap', selector('close'), preventDefaultAnd(lightbox.hide))
3217 .on('tap', selector('image, caption'), toggleControlsOr(lightbox.next));
3218 $refs.container.on(
3219 'tap', selector('view, strip'), toggleControlsOr(lightbox.hide)
3220 )
3221 // Prevent images from being dragged around.
3222 .on('dragstart', selector('img'), preventDefault);
3223 $refs.lightbox
3224 .on('keydown', keyHandler)
3225 // While visible, prevent lightbox from loosing focus to other nodes.
3226 // IE looses focus without letting us know.
3227 .on('focusin', focusThis)
3228 // Unfortunately setTimeout is needed because of a 14 year old
3229 // Firefox bug (https://bugzilla.mozilla.org/show_bug.cgi?id=53579#c4).
3230 .on('blur', function() {
3231 setTimeout(focusThis.bind(this), 0);
3232 });
3233
3234 // The `tabindex` attribute is needed to enable non-input elements
3235 // to receive keyboard events.
3236 $('body').append($refs.lightbox.prop('tabIndex', 0));
3237
3238 return lightbox;
3239 };
3240
3241 /**
3242 * Dispose of DOM nodes created by the lightbox.
3243 */
3244 lightbox.destroy = function() {
3245 if (!$refs) {
3246 return;
3247 }
3248
3249 // Event handlers are also removed.
3250 $refs.lightbox.remove();
3251 $refs = undefined;
3252 };
3253
3254 /**
3255 * Show a specific item.
3256 */
3257 lightbox.show = function(index) {
3258 // Bail if we are already showing this item.
3259 if (index === currentIndex) {
3260 return;
3261 }
3262
3263 var item = items[index];
3264 var previousIndex = currentIndex;
3265 currentIndex = index;
3266 spinner.show();
3267
3268 // For videos, load an empty SVG with the video dimensions to preserve
3269 // the video’s aspect ratio while being responsive.
3270 var url = item.html && svgDataUri(item.width, item.height) || item.url;
3271 loadImage(url, function($image) {
3272 // Make sure this is the last item requested to be shown since
3273 // images can finish loading in a different order than they were
3274 // requested in.
3275 if (index != currentIndex) {
3276 return;
3277 }
3278
3279 var $figure = dom('figure', 'figure').append(addClass($image, 'image'));
3280 var $frame = dom('frame').append($figure);
3281 var $newView = dom('view').append($frame);
3282
3283 if (item.html) {
3284 $figure.append(addClass($(item.html), 'embed'));
3285 }
3286
3287 if (item.caption) {
3288 $figure.append(dom('caption', 'figcaption').text(item.caption));
3289 }
3290
3291 spinner.hide();
3292
3293 toggleClass($refs.arrowLeft, 'inactive', index <= 0);
3294 toggleClass($refs.arrowRight, 'inactive', index >= items.length - 1);
3295
3296 $refs.spinner.before($newView);
3297
3298 if ($refs.view) {
3299 tram($refs.view)
3300 .add('opacity .3s')
3301 .start({
3302 opacity: 0
3303 })
3304 .then(remover($refs.view));
3305
3306 tram($newView)
3307 .add('opacity .3s')
3308 .add('transform .3s')
3309 .set({
3310 opacity: 0,
3311 x: index > previousIndex ? '80px' : '-80px'
3312 })
3313 .start({
3314 opacity: 1,
3315 x: 0
3316 });
3317 }
3318
3319 $refs.view = $newView;
3320
3321 if ($refs.items) {
3322 // Mark proper thumbnail as active
3323 addClass(removeClass($refs.items, 'active').eq(index), 'active');
3324 }
3325 });
3326
3327 return lightbox;
3328 };
3329
3330 /**
3331 * Hides the lightbox.
3332 */
3333 lightbox.hide = function() {
3334 tram($refs.lightbox)
3335 .add('opacity .3s')
3336 .start({
3337 opacity: 0
3338 })
3339 .then(hideLightbox);
3340
3341 return lightbox;
3342 };
3343
3344 lightbox.prev = function() {
3345 if (currentIndex > 0) {
3346 lightbox.show(currentIndex - 1);
3347 }
3348 };
3349
3350 lightbox.next = function() {
3351 if (currentIndex < items.length - 1) {
3352 lightbox.show(currentIndex + 1);
3353 }
3354 };
3355
3356 function toggleControlsOr(callback) {
3357 return function(event) {
3358 // We only care about events triggered directly on the bound selectors.
3359 if (this != event.target) {
3360 return;
3361 }
3362
3363 event.stopPropagation();
3364 event.preventDefault();
3365
3366 if (matchMedia(breakpoint).matches) {
3367 callback();
3368 } else {
3369 toggleClass($refs.controls, 'visible');
3370 }
3371 };
3372 }
3373
3374 var itemTapHandler = function(event) {
3375 var index = $(this).index();
3376
3377 event.preventDefault();
3378 lightbox.show(index);
3379 };
3380
3381 var swipeHandler = function(event, data) {
3382 // Prevent scrolling.
3383 event.preventDefault();
3384
3385 if (data.direction == 'left') {
3386 lightbox.next();
3387 } else if (data.direction == 'right') {
3388 lightbox.prev();
3389 }
3390 };
3391
3392 function preventDefaultAnd(action) {
3393 return function(event) {
3394 // Prevents click events and zooming.
3395 event.preventDefault();
3396 action();
3397 };
3398 }
3399
3400 var focusThis = function() {
3401 this.focus();
3402 };
3403
3404 function preventDefault(event) {
3405 event.preventDefault();
3406 }
3407
3408 function keyHandler(event) {
3409 var keyCode = event.keyCode;
3410
3411 // [esc]
3412 if (keyCode == 27) {
3413 lightbox.hide();
3414 }
3415
3416 // [◀]
3417 else if (keyCode == 37) {
3418 lightbox.prev();
3419 }
3420
3421 // [▶]
3422 else if (keyCode == 39) {
3423 lightbox.next();
3424 }
3425 }
3426
3427 function hideLightbox() {
3428 removeClass($refs.html, 'noscroll');
3429 addClass($refs.lightbox, 'hide');
3430 $refs.strip.empty();
3431 $refs.view && $refs.view.remove();
3432
3433 // Reset some stuff
3434 removeClass($refs.content, 'group');
3435 removeClass($refs.controls, 'visible');
3436 addClass($refs.arrowLeft, 'inactive');
3437 addClass($refs.arrowRight, 'inactive');
3438
3439 currentIndex = $refs.view = undefined;
3440 }
3441
3442 function loadImage(url, callback) {
3443 var $image = dom('img', 'img');
3444
3445 $image.one('load', function() {
3446 callback($image);
3447 });
3448
3449 // Start loading image.
3450 $image.attr('src', url);
3451
3452 return $image;
3453 }
3454
3455 function remover($element) {
3456 return function() {
3457 $element.remove();
3458 };
3459 }
3460
3461 /**
3462 * Spinner
3463 */
3464 function Spinner($spinner, className, delay) {
3465 this.$element = $spinner;
3466 this.className = className;
3467 this.delay = delay || 200;
3468 this.hide();
3469 }
3470
3471 Spinner.prototype.show = function() {
3472 var spinner = this;
3473
3474 // Bail if we are already showing the spinner.
3475 if (spinner.timeoutId) {
3476 return;
3477 }
3478
3479 spinner.timeoutId = setTimeout(function() {
3480 spinner.$element.removeClass(spinner.className);
3481 delete spinner.timeoutId;
3482 }, spinner.delay);
3483 };
3484
3485 Spinner.prototype.hide = function() {
3486 var spinner = this;
3487 if (spinner.timeoutId) {
3488 clearTimeout(spinner.timeoutId);
3489 delete spinner.timeoutId;
3490 return;
3491 }
3492
3493 spinner.$element.addClass(spinner.className);
3494 };
3495
3496 function prefixed(string, isSelector) {
3497 return string.replace(prefixRegex, (isSelector ? ' .' : ' ') + prefix);
3498 }
3499
3500 function selector(string) {
3501 return prefixed(string, true);
3502 }
3503
3504 /**
3505 * jQuery.addClass with auto-prefixing
3506 * @param {jQuery} Element to add class to
3507 * @param {string} Class name that will be prefixed and added to element
3508 * @return {jQuery}
3509 */
3510 function addClass($element, className) {
3511 return $element.addClass(prefixed(className));
3512 }
3513
3514 /**
3515 * jQuery.removeClass with auto-prefixing
3516 * @param {jQuery} Element to remove class from
3517 * @param {string} Class name that will be prefixed and removed from element
3518 * @return {jQuery}
3519 */
3520 function removeClass($element, className) {
3521 return $element.removeClass(prefixed(className));
3522 }
3523
3524 /**
3525 * jQuery.toggleClass with auto-prefixing
3526 * @param {jQuery} Element where class will be toggled
3527 * @param {string} Class name that will be prefixed and toggled
3528 * @param {boolean} Optional boolean that determines if class will be added or removed
3529 * @return {jQuery}
3530 */
3531 function toggleClass($element, className, shouldAdd) {
3532 return $element.toggleClass(prefixed(className), shouldAdd);
3533 }
3534
3535 /**
3536 * Create a new DOM element wrapped in a jQuery object,
3537 * decorated with our custom methods.
3538 * @param {string} className
3539 * @param {string} [tag]
3540 * @return {jQuery}
3541 */
3542 function dom(className, tag) {
3543 return addClass($(document.createElement(tag || 'div')), className);
3544 }
3545
3546 function isObject(value) {
3547 return typeof value == 'object' && null != value && !isArray(value);
3548 }
3549
3550 function svgDataUri(width, height) {
3551 var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '"/>';
3552 return 'data:image/svg+xml;charset=utf-8,' + encodeURI(svg);
3553 }
3554
3555 // Compute some dimensions manually for iOS, because of buggy support for VH.
3556 // Also, Android built-in browser does not support viewport units.
3557 (function() {
3558 var ua = window.navigator.userAgent;
3559 var iOS = /(iPhone|iPod|iPad).+AppleWebKit/i.test(ua);
3560 var android = ua.indexOf('Android ') > -1 && ua.indexOf('Chrome') == -1;
3561
3562 if (!iOS && !android) {
3563 return;
3564 }
3565
3566 var styleNode = document.createElement('style');
3567 document.head.appendChild(styleNode);
3568 window.addEventListener('orientationchange', refresh, true);
3569
3570 function refresh() {
3571 var vh = window.innerHeight;
3572 var vw = window.innerWidth;
3573 var content =
3574 '.w-lightbox-content, .w-lightbox-view, .w-lightbox-view:before {' +
3575 'height:' + vh + 'px' +
3576 '}' +
3577 '.w-lightbox-view {' +
3578 'width:' + vw + 'px' +
3579 '}' +
3580 '.w-lightbox-group, .w-lightbox-group .w-lightbox-view, .w-lightbox-group .w-lightbox-view:before {' +
3581 'height:' + (0.86 * vh) + 'px' +
3582 '}' +
3583 '.w-lightbox-image {' +
3584 'max-width:' + vw + 'px;' +
3585 'max-height:' + vh + 'px' +
3586 '}' +
3587 '.w-lightbox-group .w-lightbox-image {' +
3588 'max-height:' + (0.86 * vh) + 'px' +
3589 '}' +
3590 '.w-lightbox-strip {' +
3591 'padding: 0 ' + (0.01 * vh) + 'px' +
3592 '}' +
3593 '.w-lightbox-item {' +
3594 'width:' + (0.1 * vh) + 'px;' +
3595 'padding:' + (0.02 * vh) + 'px ' + (0.01 * vh) + 'px' +
3596 '}' +
3597 '.w-lightbox-thumbnail {' +
3598 'height:' + (0.1 * vh) + 'px' +
3599 '}';
3600
3601 styleNode.textContent = content;
3602 }
3603
3604 refresh();
3605 })();
3606
3607 return lightbox;
3608})(window, document, jQuery, window.tram);
3609
3610Webflow.define('lightbox', function($, _) {
3611 'use strict';
3612
3613 var api = {};
3614 var $doc = $(document);
3615 var $body;
3616 var $lightboxes;
3617 var designer;
3618 var inApp = Webflow.env();
3619 var namespace = '.w-lightbox';
3620 var groups;
3621
3622 // -----------------------------------
3623 // Module methods
3624
3625 api.ready = api.design = api.preview = init;
3626
3627 // -----------------------------------
3628 // Private methods
3629
3630 function init() {
3631 designer = inApp && Webflow.env('design');
3632 $body = $(document.body);
3633
3634 // Reset Lightbox
3635 lightbox.destroy();
3636
3637 // Reset groups
3638 groups = {};
3639
3640 // Find all instances on the page
3641 $lightboxes = $doc.find(namespace);
3642 $lightboxes.each(build);
3643 }
3644
3645 function build(i, el) {
3646 var $el = $(el);
3647
3648 // Store state in data
3649 var data = $.data(el, namespace);
3650 if (!data) data = $.data(el, namespace, {
3651 el: $el,
3652 mode: 'images',
3653 images: [],
3654 embed: ''
3655 });
3656
3657 // Remove old events
3658 data.el.off(namespace);
3659
3660 // Set config from json script tag
3661 configure(data);
3662
3663 // Add events based on mode
3664 if (designer) {
3665 data.el.on('setting' + namespace, configure.bind(null, data));
3666 } else {
3667 data.el
3668 .on('tap' + namespace, tapHandler(data))
3669 // Prevent page scrolling to top when clicking on lightbox triggers.
3670 .on('click' + namespace, function(e) {
3671 e.preventDefault();
3672 });
3673 }
3674 }
3675
3676 function configure(data) {
3677 var json = data.el.children('.w-json').html();
3678 var groupId, group;
3679
3680 if (!json) {
3681 data.images = [];
3682 return;
3683 }
3684
3685 try {
3686 json = JSON.parse(json);
3687 data.mode = json.mode;
3688
3689 if (json.mode == 'video') {
3690 data.embed = json.embed;
3691 } else {
3692 groupId = json.groupId;
3693 if (groupId) {
3694 group = groups[groupId];
3695 if (!group) {
3696 group = groups[groupId] = [];
3697 }
3698
3699 data.images = group;
3700
3701 if (json.images.length) {
3702 data.index = group.length;
3703 group.push.apply(group, json.images);
3704 }
3705 } else {
3706 data.images = json.images;
3707 }
3708 }
3709 } catch (e) {
3710 console.error('Malformed lightbox JSON configuration.', e.message);
3711 }
3712 }
3713
3714 function tapHandler(data) {
3715 return function() {
3716 if (data.mode == 'video') {
3717 data.embed && lightbox(data.embed);
3718 } else {
3719 data.images.length && lightbox(data.images, data.index || 0);
3720 }
3721 };
3722 }
3723
3724 // Export module
3725 return api;
3726});
3727/**
3728 * ----------------------------------------------------------------------
3729 * Webflow: Navbar component
3730 */
3731Webflow.define('navbar', function($, _) {
3732 'use strict';
3733
3734 var api = {};
3735 var tram = window.tram;
3736 var $win = $(window);
3737 var $doc = $(document);
3738 var $body;
3739 var $navbars;
3740 var designer;
3741 var inApp = Webflow.env();
3742 var overlay = '<div class="w-nav-overlay" data-wf-ignore />';
3743 var namespace = '.w-nav';
3744 var buttonOpen = 'w--open';
3745 var menuOpen = 'w--nav-menu-open';
3746 var linkOpen = 'w--nav-link-open';
3747 var ix = Webflow.ixEvents();
3748
3749 // -----------------------------------
3750 // Module methods
3751
3752 api.ready = api.design = api.preview = init;
3753 api.destroy = removeListeners;
3754
3755 // -----------------------------------
3756 // Private methods
3757
3758 function init() {
3759 designer = inApp && Webflow.env('design');
3760 $body = $(document.body);
3761
3762 // Find all instances on the page
3763 $navbars = $doc.find(namespace);
3764 if (!$navbars.length) return;
3765 $navbars.each(build);
3766
3767 // Wire events
3768 removeListeners();
3769 addListeners();
3770 }
3771
3772 function removeListeners() {
3773 Webflow.resize.off(resizeAll);
3774 }
3775
3776 function addListeners() {
3777 Webflow.resize.on(resizeAll);
3778 }
3779
3780 function resizeAll() {
3781 $navbars.each(resize);
3782 }
3783
3784 function build(i, el) {
3785 var $el = $(el);
3786
3787 // Store state in data
3788 var data = $.data(el, namespace);
3789 if (!data) data = $.data(el, namespace, {
3790 open: false,
3791 el: $el,
3792 config: {}
3793 });
3794 data.menu = $el.find('.w-nav-menu');
3795 data.links = data.menu.find('.w-nav-link');
3796 data.dropdowns = data.menu.find('.w-dropdown');
3797 data.button = $el.find('.w-nav-button');
3798 data.container = $el.find('.w-container');
3799 data.outside = outside(data);
3800
3801 // Remove old events
3802 data.el.off(namespace);
3803 data.button.off(namespace);
3804 data.menu.off(namespace);
3805
3806 // Set config from data attributes
3807 configure(data);
3808
3809 // Add events based on mode
3810 if (designer) {
3811 removeOverlay(data);
3812 data.el.on('setting' + namespace, handler(data));
3813 } else {
3814 addOverlay(data);
3815 data.button.on('tap' + namespace, toggle(data));
3816 data.menu.on('tap' + namespace, 'a', navigate(data));
3817 }
3818
3819 // Trigger initial resize
3820 resize(i, el);
3821 }
3822
3823 function removeOverlay(data) {
3824 if (!data.overlay) return;
3825 close(data, true);
3826 data.overlay.remove();
3827 data.overlay = null;
3828 }
3829
3830 function addOverlay(data) {
3831 if (data.overlay) return;
3832 data.overlay = $(overlay).appendTo(data.el);
3833 data.parent = data.menu.parent();
3834 close(data, true);
3835 }
3836
3837 function configure(data) {
3838 var config = {};
3839 var old = data.config || {};
3840
3841 // Set config options from data attributes
3842 var animation = config.animation = data.el.attr('data-animation') || 'default';
3843 config.animOver = /^over/.test(animation);
3844 config.animDirect = /left$/.test(animation) ? -1 : 1;
3845
3846 // Re-open menu if the animation type changed
3847 if (old.animation != animation) {
3848 data.open && _.defer(reopen, data);
3849 }
3850
3851 config.easing = data.el.attr('data-easing') || 'ease';
3852 config.easing2 = data.el.attr('data-easing2') || 'ease';
3853
3854 var duration = data.el.attr('data-duration');
3855 config.duration = duration != null ? +duration : 400;
3856
3857 config.docHeight = data.el.attr('data-doc-height');
3858
3859 // Store config in data
3860 data.config = config;
3861 }
3862
3863 function handler(data) {
3864 return function(evt, options) {
3865 options = options || {};
3866 var winWidth = $win.width();
3867 configure(data);
3868 options.open === true && open(data, true);
3869 options.open === false && close(data, true);
3870 // Reopen if media query changed after setting
3871 data.open && _.defer(function() {
3872 if (winWidth != $win.width()) reopen(data);
3873 });
3874 };
3875 }
3876
3877 function closeEach(i, el) {
3878 var data = $.data(el, namespace);
3879 data.open && close(data);
3880 }
3881
3882 function reopen(data) {
3883 if (!data.open) return;
3884 close(data, true);
3885 open(data, true);
3886 }
3887
3888 function toggle(data) {
3889 return _.debounce(function(evt) {
3890 data.open ? close(data) : open(data);
3891 });
3892 }
3893
3894 function navigate(data) {
3895 return function(evt) {
3896 var link = $(this);
3897 var href = link.attr('href');
3898
3899 // Close when navigating to an in-page anchor
3900 if (href && href.indexOf('#') === 0 && data.open) {
3901 // Avoid empty hash links
3902 if (href.length === 1) evt.preventDefault();
3903 close(data);
3904 }
3905 };
3906 }
3907
3908 function outside(data) {
3909 // Unbind previous tap handler if it exists
3910 if (data.outside) $doc.off('tap' + namespace, data.outside);
3911
3912 // Close menu when tapped outside
3913 return _.debounce(function(evt) {
3914 if (!data.open) return;
3915 var menu = $(evt.target).closest('.w-nav-menu');
3916 if (!data.menu.is(menu)) {
3917 close(data);
3918 }
3919 });
3920 }
3921
3922 function resize(i, el) {
3923 var data = $.data(el, namespace);
3924 // Check for collapsed state based on button display
3925 var collapsed = data.collapsed = data.button.css('display') != 'none';
3926 // Close menu if button is no longer visible (and not in designer)
3927 if (data.open && !collapsed && !designer) close(data, true);
3928 // Set max-width of links + dropdowns to match container
3929 if (data.container.length) {
3930 var updateEachMax = updateMax(data);
3931 data.links.each(updateEachMax);
3932 data.dropdowns.each(updateEachMax);
3933 }
3934 // If currently open, update height to match body
3935 if (data.open) {
3936 setOverlayHeight(data);
3937 }
3938 }
3939
3940 var maxWidth = 'max-width';
3941
3942 function updateMax(data) {
3943 // Set max-width of each element to match container
3944 var containMax = data.container.css(maxWidth);
3945 if (containMax == 'none') containMax = '';
3946 return function(i, link) {
3947 link = $(link);
3948 link.css(maxWidth, '');
3949 // Don't set the max-width if an upstream value exists
3950 if (link.css(maxWidth) == 'none') link.css(maxWidth, containMax);
3951 };
3952 }
3953
3954 function open(data, immediate) {
3955 if (data.open) return;
3956 data.open = true;
3957 data.menu.addClass(menuOpen);
3958 data.links.addClass(linkOpen);
3959 data.button.addClass(buttonOpen);
3960 var config = data.config;
3961 var animation = config.animation;
3962 if (animation == 'none' || !tram.support.transform) immediate = true;
3963 var bodyHeight = setOverlayHeight(data);
3964 var menuHeight = data.menu.outerHeight(true);
3965 var menuWidth = data.menu.outerWidth(true);
3966 var navHeight = data.el.height();
3967 var navbarEl = data.el[0];
3968 resize(0, navbarEl);
3969 ix.intro(0, navbarEl);
3970
3971 // Listen for tap outside events
3972 if (!designer) $doc.on('tap' + namespace, data.outside);
3973
3974 // No transition for immediate
3975 if (immediate) return;
3976
3977 var transConfig = 'transform ' + config.duration + 'ms ' + config.easing;
3978
3979 // Add menu to overlay
3980 if (data.overlay) {
3981 data.overlay.show().append(data.menu);
3982 }
3983
3984 // Over left/right
3985 if (config.animOver) {
3986 tram(data.menu)
3987 .add(transConfig)
3988 .set({
3989 x: config.animDirect * menuWidth,
3990 height: bodyHeight
3991 }).start({
3992 x: 0
3993 });
3994 data.overlay && data.overlay.width(menuWidth);
3995 return;
3996 }
3997
3998 // Drop Down
3999 var offsetY = navHeight + menuHeight;
4000 tram(data.menu)
4001 .add(transConfig)
4002 .set({
4003 y: -offsetY
4004 }).start({
4005 y: 0
4006 });
4007 }
4008
4009 function setOverlayHeight(data) {
4010 var config = data.config;
4011 var bodyHeight = config.docHeight ? $doc.height() : $body.height();
4012 if (config.animOver) {
4013 data.menu.height(bodyHeight);
4014 } else if (data.el.css('position') != 'fixed') {
4015 bodyHeight -= data.el.height();
4016 }
4017 data.overlay && data.overlay.height(bodyHeight);
4018 return bodyHeight;
4019 }
4020
4021 function close(data, immediate) {
4022 if (!data.open) return;
4023 data.open = false;
4024 data.button.removeClass(buttonOpen);
4025 var config = data.config;
4026 if (config.animation == 'none' || !tram.support.transform) immediate = true;
4027 var animation = config.animation;
4028 ix.outro(0, data.el[0]);
4029
4030 // Stop listening for tap outside events
4031 $doc.off('tap' + namespace, data.outside);
4032
4033 if (immediate) {
4034 tram(data.menu).stop();
4035 complete();
4036 return;
4037 }
4038
4039 var transConfig = 'transform ' + config.duration + 'ms ' + config.easing2;
4040 var menuHeight = data.menu.outerHeight(true);
4041 var menuWidth = data.menu.outerWidth(true);
4042 var navHeight = data.el.height();
4043
4044 // Over left/right
4045 if (config.animOver) {
4046 tram(data.menu)
4047 .add(transConfig)
4048 .start({
4049 x: menuWidth * config.animDirect
4050 }).then(complete);
4051 return;
4052 }
4053
4054 // Drop Down
4055 var offsetY = navHeight + menuHeight;
4056 tram(data.menu)
4057 .add(transConfig)
4058 .start({
4059 y: -offsetY
4060 }).then(complete);
4061
4062 function complete() {
4063 data.menu.height('');
4064 tram(data.menu).set({
4065 x: 0,
4066 y: 0
4067 });
4068 data.menu.removeClass(menuOpen);
4069 data.links.removeClass(linkOpen);
4070 if (data.overlay && data.overlay.children().length) {
4071 // Move menu back to parent
4072 data.menu.appendTo(data.parent);
4073 data.overlay.attr('style', '').hide();
4074 }
4075
4076 // Trigger event so other components can hook in (dropdown)
4077 data.el.triggerHandler('w-close');
4078 }
4079 }
4080
4081 // Export module
4082 return api;
4083});
4084/**
4085 * ----------------------------------------------------------------------
4086 * Webflow: Dropdown component
4087 */
4088Webflow.define('dropdown', function($, _) {
4089 'use strict';
4090
4091 var api = {};
4092 var tram = window.tram;
4093 var $doc = $(document);
4094 var $dropdowns;
4095 var designer;
4096 var inApp = Webflow.env();
4097 var namespace = '.w-dropdown';
4098 var stateOpen = 'w--open';
4099 var closeEvent = 'w-close' + namespace;
4100 var ix = Webflow.ixEvents();
4101
4102 // -----------------------------------
4103 // Module methods
4104
4105 api.ready = api.design = api.preview = init;
4106
4107 // -----------------------------------
4108 // Private methods
4109
4110 function init() {
4111 designer = inApp && Webflow.env('design');
4112
4113 // Find all instances on the page
4114 $dropdowns = $doc.find(namespace);
4115 $dropdowns.each(build);
4116 }
4117
4118 function build(i, el) {
4119 var $el = $(el);
4120
4121 // Store state in data
4122 var data = $.data(el, namespace);
4123 if (!data) data = $.data(el, namespace, {
4124 open: false,
4125 el: $el,
4126 config: {}
4127 });
4128 data.list = $el.children('.w-dropdown-list');
4129 data.toggle = $el.children('.w-dropdown-toggle');
4130 data.links = data.list.children('.w-dropdown-link');
4131 data.outside = outside(data);
4132 data.complete = complete(data);
4133
4134 // Remove old events
4135 $el.off(namespace);
4136 data.toggle.off(namespace);
4137
4138 // Set config from data attributes
4139 configure(data);
4140
4141 if (data.nav) data.nav.off(namespace);
4142 data.nav = $el.closest('.w-nav');
4143 data.nav.on(closeEvent, handler(data));
4144
4145 // Add events based on mode
4146 if (designer) {
4147 $el.on('setting' + namespace, handler(data));
4148 } else {
4149 data.toggle.on('tap' + namespace, toggle(data));
4150 $el.on(closeEvent, handler(data));
4151 // Close in preview mode
4152 inApp && close(data);
4153 }
4154 }
4155
4156 function configure(data) {
4157 data.config = {
4158 hover: +data.el.attr('data-hover'),
4159 delay: +data.el.attr('data-delay') || 0
4160 };
4161 }
4162
4163 function handler(data) {
4164 return function(evt, options) {
4165 options = options || {};
4166
4167 if (evt.type == 'w-close') {
4168 return close(data);
4169 }
4170
4171 if (evt.type == 'setting') {
4172 configure(data);
4173 options.open === true && open(data, true);
4174 options.open === false && close(data, true);
4175 return;
4176 }
4177 };
4178 }
4179
4180 function toggle(data) {
4181 return _.debounce(function(evt) {
4182 data.open ? close(data) : open(data);
4183 });
4184 }
4185
4186 function open(data, immediate) {
4187 if (data.open) return;
4188 closeOthers(data);
4189 data.open = true;
4190 data.list.addClass(stateOpen);
4191 data.toggle.addClass(stateOpen);
4192 ix.intro(0, data.el[0]);
4193
4194 // Listen for tap outside events
4195 if (!designer) $doc.on('tap' + namespace, data.outside);
4196
4197 // Clear previous delay
4198 window.clearTimeout(data.delayId);
4199 }
4200
4201 function close(data, immediate) {
4202 if (!data.open) return;
4203 data.open = false;
4204 var config = data.config;
4205 ix.outro(0, data.el[0]);
4206
4207 // Stop listening for tap outside events
4208 $doc.off('tap' + namespace, data.outside);
4209
4210 // Clear previous delay
4211 window.clearTimeout(data.delayId);
4212
4213 // Skip delay during immediate
4214 if (!config.delay || immediate) return data.complete();
4215
4216 // Optionally wait for delay before close
4217 data.delayId = window.setTimeout(data.complete, config.delay);
4218 }
4219
4220 function closeOthers(data) {
4221 var self = data.el[0];
4222 $dropdowns.each(function(i, other) {
4223 var $other = $(other);
4224 if ($other.is(self) || $other.has(self).length) return;
4225 $other.triggerHandler(closeEvent);
4226 });
4227 }
4228
4229 function outside(data) {
4230 // Unbind previous tap handler if it exists
4231 if (data.outside) $doc.off('tap' + namespace, data.outside);
4232
4233 // Close menu when tapped outside
4234 return _.debounce(function(evt) {
4235 if (!data.open) return;
4236 var $target = $(evt.target);
4237 if ($target.closest('.w-dropdown-toggle').length) return;
4238 if (!data.el.is($target.closest(namespace))) {
4239 close(data);
4240 }
4241 });
4242 }
4243
4244 function complete(data) {
4245 return function() {
4246 data.list.removeClass(stateOpen);
4247 data.toggle.removeClass(stateOpen);
4248 };
4249 }
4250
4251 // Export module
4252 return api;
4253});
4254/**
4255 * ----------------------------------------------------------------------
4256 * Webflow: Tabs component
4257 */
4258Webflow.define('tabs', function($, _) {
4259 'use strict';
4260
4261 var api = {};
4262 var tram = window.tram;
4263 var $win = $(window);
4264 var $doc = $(document);
4265 var $tabs;
4266 var design;
4267 var env = Webflow.env;
4268 var safari = env.safari;
4269 var inApp = env();
4270 var tabAttr = 'data-w-tab';
4271 var namespace = '.w-tabs';
4272 var linkCurrent = 'w--current';
4273 var tabActive = 'w--tab-active';
4274 var ix = Webflow.ixEvents();
4275
4276 // -----------------------------------
4277 // Module methods
4278
4279 api.ready = api.design = api.preview = init;
4280
4281 // -----------------------------------
4282 // Private methods
4283
4284 function init() {
4285 design = inApp && Webflow.env('design');
4286
4287 // Find all instances on the page
4288 $tabs = $doc.find(namespace);
4289 if (!$tabs.length) return;
4290 $tabs.each(build);
4291 }
4292
4293 function build(i, el) {
4294 var $el = $(el);
4295
4296 // Store state in data
4297 var data = $.data(el, namespace);
4298 if (!data) data = $.data(el, namespace, {
4299 el: $el,
4300 config: {}
4301 });
4302 data.current = null;
4303 data.menu = $el.children('.w-tab-menu');
4304 data.links = data.menu.children('.w-tab-link');
4305 data.content = $el.children('.w-tab-content');
4306 data.panes = data.content.children('.w-tab-pane');
4307
4308 // Remove old events
4309 data.el.off(namespace);
4310 data.links.off(namespace);
4311
4312 // Set config from data attributes
4313 configure(data);
4314
4315 // Wire up events when not in design mode
4316 if (!design) {
4317 data.links.on('click' + namespace, linkSelect(data));
4318
4319 // Trigger first intro event from current tab
4320 var $link = data.links.filter('.' + linkCurrent);
4321 var tab = $link.attr(tabAttr);
4322 tab && changeTab(data, {
4323 tab: tab,
4324 immediate: true
4325 });
4326 }
4327 }
4328
4329 function configure(data) {
4330 var config = {};
4331 var old = data.config || {};
4332
4333 // Set config options from data attributes
4334 config.easing = data.el.attr('data-easing') || 'ease';
4335
4336 var intro = +data.el.attr('data-duration-in');
4337 intro = config.intro = intro === intro ? intro : 0;
4338
4339 var outro = +data.el.attr('data-duration-out');
4340 outro = config.outro = outro === outro ? outro : 0;
4341
4342 config.immediate = !intro && !outro;
4343
4344 // Store config in data
4345 data.config = config;
4346 }
4347
4348 function linkSelect(data) {
4349 return function(evt) {
4350 var tab = evt.currentTarget.getAttribute(tabAttr);
4351 tab && changeTab(data, {
4352 tab: tab
4353 });
4354 };
4355 }
4356
4357 function changeTab(data, options) {
4358 options = options || {};
4359
4360 var config = data.config;
4361 var easing = config.easing;
4362 var tab = options.tab;
4363
4364 // Don't select the same tab twice
4365 if (tab === data.current) return;
4366 data.current = tab;
4367
4368 // Select the current link
4369 data.links.each(function(i, el) {
4370 var $el = $(el);
4371 if (el.getAttribute(tabAttr) === tab) $el.addClass(linkCurrent).each(ix.intro);
4372 else if ($el.hasClass(linkCurrent)) $el.removeClass(linkCurrent).each(ix.outro);
4373 });
4374
4375 // Find the new tab panes and keep track of previous
4376 var targets = [];
4377 var previous = [];
4378 data.panes.each(function(i, el) {
4379 var $el = $(el);
4380 if (el.getAttribute(tabAttr) === tab) {
4381 targets.push(el);
4382 } else if ($el.hasClass(tabActive)) {
4383 previous.push(el);
4384 }
4385 });
4386
4387 var $targets = $(targets);
4388 var $previous = $(previous);
4389
4390 // Switch tabs immediately and bypass transitions
4391 if (options.immediate || config.immediate) {
4392 $targets.addClass(tabActive).each(ix.intro);
4393 $previous.removeClass(tabActive);
4394 Webflow.redraw.up();
4395 return;
4396 }
4397
4398 // Fade out the currently active tab before intro
4399 if ($previous.length && config.outro) {
4400 $previous.each(ix.outro);
4401 tram($previous)
4402 .add('opacity ' + config.outro + 'ms ' + easing, {
4403 fallback: safari
4404 })
4405 .start({
4406 opacity: 0
4407 })
4408 .then(intro);
4409 } else {
4410 // Skip the outro and play intro
4411 intro();
4412 }
4413
4414 // Fade in the new target
4415 function intro() {
4416 // Clear previous active class + inline style
4417 $previous.removeClass(tabActive).removeAttr('style');
4418
4419 // Add active class to new target
4420 $targets.addClass(tabActive).each(ix.intro);
4421 Webflow.redraw.up();
4422
4423 // Set opacity immediately if intro is zero
4424 if (!config.intro) return tram($targets).set({
4425 opacity: 1
4426 });
4427
4428 // Otherwise fade in opacity
4429 tram($targets)
4430 .set({
4431 opacity: 0
4432 })
4433 .redraw()
4434 .add('opacity ' + config.intro + 'ms ' + easing, {
4435 fallback: safari
4436 })
4437 .start({
4438 opacity: 1
4439 });
4440 }
4441 }
4442
4443 // Export module
4444 return api;
4445}); \ No newline at end of file
Powered by cgit v1.2.3 (git 2.41.0)