diff options
Diffstat (limited to 'deprecated/ZJW/javascripts/webflow.js')
-rw-r--r-- | deprecated/ZJW/javascripts/webflow.js | 4445 |
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 | */ | ||
10 | var Webflow = { | ||
11 | w: Webflow | ||
12 | }; | ||
13 | Webflow.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 | */ | ||
462 | window.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 | */ | ||
1379 | Webflow.init(); | ||
1380 | /** | ||
1381 | * ---------------------------------------------------------------------- | ||
1382 | * Webflow: Interactions | ||
1383 | */ | ||
1384 | Webflow.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 | */ | ||
1865 | Webflow.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 | */ | ||
2007 | Webflow.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 | */ | ||
2304 | Webflow.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 | */ | ||
2436 | Webflow.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 | */ | ||
2541 | Webflow.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 | */ | ||
3104 | var 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 | |||
3610 | Webflow.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 | */ | ||
3731 | Webflow.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 | */ | ||
4088 | Webflow.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 | */ | ||
4258 | Webflow.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 | ||