From e002d09d2b6b2317fec6caa8836b20e6709c5da3 Mon Sep 17 00:00:00 2001 From: Jinwei Zhao Date: Mon, 4 Apr 2016 14:00:39 +0800 Subject: jinwei.me --- Code/ZJW/javascripts/webflow.js | 4445 --------------------------------------- 1 file changed, 4445 deletions(-) delete mode 100644 Code/ZJW/javascripts/webflow.js (limited to 'Code/ZJW/javascripts/webflow.js') diff --git a/Code/ZJW/javascripts/webflow.js b/Code/ZJW/javascripts/webflow.js deleted file mode 100644 index b048709..0000000 --- a/Code/ZJW/javascripts/webflow.js +++ /dev/null @@ -1,4445 +0,0 @@ -/*! - * ---------------------------------------------------------------------- - * Webflow: Front-end site library - * @license MIT - * Other scripts may access this api using an async handler: - * var Webflow = Webflow || []; - * Webflow.push(readyFunction); - * ---------------------------------------------------------------------- - */ -var Webflow = { - w: Webflow -}; -Webflow.init = function() { - 'use strict'; - - var $ = window.$; - var api = {}; - var modules = {}; - var primary = []; - var secondary = this.w || []; - var $win = $(window); - var _ = api._ = underscore(); - var domready = false; - var tram = window.tram; - var Modernizr = window.Modernizr; - var noop = function() {}; - tram.config.hideBackface = false; - tram.config.keepInherited = true; - - /** - * Webflow.define() - Define a webflow.js module - * @param {string} name - * @param {function} factory - */ - api.define = function(name, factory) { - var module = modules[name] = factory($, _); - if (!module) return; - // If running in Webflow app, subscribe to design/preview events - if (api.env()) { - $.isFunction(module.design) && window.addEventListener('__wf_design', module.design); - $.isFunction(module.preview) && window.addEventListener('__wf_preview', module.preview); - } - // Subscribe to module front-end events - $.isFunction(module.destroy) && $win.on('__wf_destroy', module.destroy); - // Look for a ready method on module - if (module.ready && $.isFunction(module.ready)) { - // If domready has already happened, call ready method - if (domready) module.ready(); - // Otherwise push ready method into primary queue - else primary.push(module.ready); - } - }; - - /** - * Webflow.require() - Load a Webflow.js module - * @param {string} name - * @return {object} - */ - api.require = function(name) { - return modules[name]; - }; - - /** - * Webflow.push() - Add a ready handler into secondary queue - * @param {function} ready Callback to invoke on domready - */ - api.push = function(ready) { - // If domready has already happened, invoke handler - if (domready) { - $.isFunction(ready) && ready(); - return; - } - // Otherwise push into secondary queue - secondary.push(ready); - }; - - /** - * Webflow.env() - Get the state of the Webflow app - * @param {string} mode [optional] - * @return {boolean} - */ - api.env = function(mode) { - var designFlag = window.__wf_design; - var inApp = typeof designFlag != 'undefined'; - if (!mode) return inApp; - if (mode == 'design') return inApp && designFlag; - if (mode == 'preview') return inApp && !designFlag; - if (mode == 'slug') return inApp && window.__wf_slug; - }; - - // Feature detects + browser sniffs ಠ_ಠ - var userAgent = navigator.userAgent.toLowerCase(); - var appVersion = navigator.appVersion.toLowerCase(); - api.env.touch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch; - var chrome = api.env.chrome = (window.chrome || /chrome/.test(userAgent)) && parseInt(appVersion.match(/chrome\/(\d+)\./)[1], 10); - var ios = api.env.ios = Modernizr && Modernizr.ios; - api.env.safari = /safari/.test(userAgent) && !chrome && !ios; - - /** - * Webflow.resize, Webflow.scroll - throttled event proxies - */ - var resizeEvents = 'resize.webflow orientationchange.webflow load.webflow'; - var scrollEvents = 'scroll.webflow ' + resizeEvents; - api.resize = eventProxy($win, resizeEvents); - api.scroll = eventProxy($win, scrollEvents); - api.redraw = eventProxy(); - - // Create a proxy instance for throttled events - function eventProxy(target, types) { - - // Set up throttled method (using custom frame-based _.throttle) - var handlers = []; - var proxy = {}; - proxy.up = _.throttle(function(evt) { - _.each(handlers, function(h) { - h(evt); - }); - }); - - // Bind events to target - if (target && types) target.on(types, proxy.up); - - /** - * Add an event handler - * @param {function} handler - */ - proxy.on = function(handler) { - if (typeof handler != 'function') return; - if (_.contains(handlers, handler)) return; - handlers.push(handler); - }; - - /** - * Remove an event handler - * @param {function} handler - */ - proxy.off = function(handler) { - handlers = _.filter(handlers, function(h) { - return h !== handler; - }); - }; - return proxy; - } - - // Provide optional IX events to components - api.ixEvents = function() { - var ix = api.require('ix'); - return (ix && ix.events) || { - reset: noop, - intro: noop, - outro: noop - }; - }; - - // Webflow.location() - Wrap window.location in api - api.location = function(url) { - window.location = url; - }; - - // Webflow.app - Designer-specific methods - api.app = api.env() ? {} : null; - if (api.app) { - - // Trigger redraw for specific elements - var Event = window.Event; - var redraw = new Event('__wf_redraw'); - api.app.redrawElement = function(i, el) { - el.dispatchEvent(redraw); - }; - - // Webflow.location - Re-route location change to trigger an event - api.location = function(url) { - window.dispatchEvent(new CustomEvent('__wf_location', { - detail: url - })); - }; - } - - // Webflow.ready() - Call primary and secondary handlers - api.ready = function() { - domready = true; - $.each(primary.concat(secondary), function(index, value) { - $.isFunction(value) && value(); - }); - // Trigger resize - api.resize.up(); - }; - - // Webflow.destroy() - Trigger a cleanup event for all modules - api.destroy = function() { - $win.triggerHandler('__wf_destroy'); - }; - - // Listen for domready - $(api.ready); - - /*! - * Webflow._ (aka) Underscore.js 1.6.0 (custom build) - * _.each - * _.map - * _.find - * _.filter - * _.any - * _.contains - * _.delay - * _.defer - * _.throttle (webflow) - * _.debounce - * _.keys - * _.has - * _.now - * - * http://underscorejs.org - * (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Underscore may be freely distributed under the MIT license. - */ - function underscore() { - var _ = {}; - - // Current version. - _.VERSION = '1.6.0-Webflow'; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, - ObjProto = Object.prototype, - FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var - push = ArrayProto.push, - slice = ArrayProto.slice, - concat = ArrayProto.concat, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - /* jshint shadow:true */ - if (obj == null) return obj; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, length = obj.length; i < length; i++) { - if (iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - var keys = _.keys(obj); - for (var i = 0, length = keys.length; i < length; i++) { - if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; - } - } - return obj; - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = _.collect = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results.push(iterator.call(context, value, index, list)); - }); - return results; - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, predicate, context) { - var result; - any(obj, function(value, index, list) { - if (predicate.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, predicate, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context); - each(obj, function(value, index, list) { - if (predicate.call(context, value, index, list)) results.push(value); - }); - return results; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, predicate, context) { - predicate || (predicate = _.identity); - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context); - each(obj, function(value, index, list) { - if (result || (result = predicate.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if the array or object contains a given value (using `===`). - // Aliased as `include`. - _.contains = _.include = function(obj, target) { - if (obj == null) return false; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - return any(obj, function(value) { - return value === target; - }); - }; - - // Function (ahem) Functions - // -------------------- - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function() { - return func.apply(null, args); - }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Returns a function, that, when invoked, will only be triggered once every - // browser animation frame - using tram's requestAnimationFrame polyfill. - _.throttle = function(func) { - var wait, args, context; - return function() { - if (wait) return; - wait = true; - args = arguments; - context = this; - tram.frame(function() { - wait = false; - func.apply(context, args); - }); - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, args, context, timestamp, result; - - var later = function() { - var last = _.now() - timestamp; - if (last < wait) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - context = args = null; - } - } - }; - - return function() { - context = this; - args = arguments; - timestamp = _.now(); - var callNow = immediate && !timeout; - if (!timeout) { - timeout = setTimeout(later, wait); - } - if (callNow) { - result = func.apply(context, args); - context = args = null; - } - - return result; - }; - }; - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = function(obj) { - if (!_.isObject(obj)) return []; - if (nativeKeys) return nativeKeys(obj); - var keys = []; - for (var key in obj) - if (_.has(obj, key)) keys.push(key); - return keys; - }; - - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return hasOwnProperty.call(obj, key); - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Utility Functions - // ----------------- - - // A (possibly faster) way to get the current timestamp as an integer. - _.now = Date.now || function() { - return new Date().getTime(); - }; - - // Export underscore - return _; - } - - // Export api - Webflow = api; -}; -/*! - * ---------------------------------------------------------------------- - * Webflow: 3rd party plugins - */ -/* jshint ignore:start */ -/*! - * tram.js v0.8.1-global - * Cross-browser CSS3 transitions in JavaScript - * https://github.com/bkwld/tram - * MIT License - */ -window.tram = function(a) { - function b(a, b) { - var c = new L.Bare; - return c.init(a, b) - } - - function c(a) { - return a.replace(/[A-Z]/g, function(a) { - return "-" + a.toLowerCase() - }) - } - - function d(a) { - var b = parseInt(a.slice(1), 16), - c = b >> 16 & 255, - d = b >> 8 & 255, - e = 255 & b; - return [c, d, e] - } - - function e(a, b, c) { - return "#" + (1 << 24 | a << 16 | b << 8 | c).toString(16).slice(1) - } - - function f() {} - - function g(a, b) { - _("Type warning: Expected: [" + a + "] Got: [" + typeof b + "] " + b) - } - - function h(a, b, c) { - _("Units do not match [" + a + "]: " + b + ", " + c) - } - - function i(a, b, c) { - if (void 0 !== b && (c = b), void 0 === a) return c; - var d = c; - return Z.test(a) || !$.test(a) ? d = parseInt(a, 10) : $.test(a) && (d = 1e3 * parseFloat(a)), 0 > d && (d = 0), d === d ? d : c - } - - function j(a) { - for (var b = -1, c = a ? a.length : 0, d = []; ++b < c;) { - var e = a[b]; - e && d.push(e) - } - return d - } - var k = function(a, b, c) { - function d(a) { - return "object" == typeof a - } - - function e(a) { - return "function" == typeof a - } - - function f() {} - - function g(h, i) { - function j() { - var a = new k; - return e(a.init) && a.init.apply(a, arguments), a - } - - function k() {} - i === c && (i = h, h = Object), j.Bare = k; - var l, m = f[a] = h[a], - n = k[a] = j[a] = new f; - return n.constructor = j, j.mixin = function(b) { - return k[a] = j[a] = g(j, b)[a], j - }, j.open = function(a) { - if (l = {}, e(a) ? l = a.call(j, n, m, j, h) : d(a) && (l = a), d(l)) - for (var c in l) b.call(l, c) && (n[c] = l[c]); - return e(n.init) || (n.init = h), j - }, j.open(i) - } - return g - }("prototype", {}.hasOwnProperty), - l = { - ease: ["ease", - function(a, b, c, d) { - var e = (a /= d) * a, - f = e * a; - return b + c * (-2.75 * f * e + 11 * e * e + -15.5 * f + 8 * e + .25 * a) - } - ], - "ease-in": ["ease-in", - function(a, b, c, d) { - var e = (a /= d) * a, - f = e * a; - return b + c * (-1 * f * e + 3 * e * e + -3 * f + 2 * e) - } - ], - "ease-out": ["ease-out", - function(a, b, c, d) { - var e = (a /= d) * a, - f = e * a; - return b + c * (.3 * f * e + -1.6 * e * e + 2.2 * f + -1.8 * e + 1.9 * a) - } - ], - "ease-in-out": ["ease-in-out", - function(a, b, c, d) { - var e = (a /= d) * a, - f = e * a; - return b + c * (2 * f * e + -5 * e * e + 2 * f + 2 * e) - } - ], - linear: ["linear", - function(a, b, c, d) { - return c * a / d + b - } - ], - "ease-in-quad": ["cubic-bezier(0.550, 0.085, 0.680, 0.530)", - function(a, b, c, d) { - return c * (a /= d) * a + b - } - ], - "ease-out-quad": ["cubic-bezier(0.250, 0.460, 0.450, 0.940)", - function(a, b, c, d) { - return -c * (a /= d) * (a - 2) + b - } - ], - "ease-in-out-quad": ["cubic-bezier(0.455, 0.030, 0.515, 0.955)", - function(a, b, c, d) { - return (a /= d / 2) < 1 ? c / 2 * a * a + b : -c / 2 * (--a * (a - 2) - 1) + b - } - ], - "ease-in-cubic": ["cubic-bezier(0.550, 0.055, 0.675, 0.190)", - function(a, b, c, d) { - return c * (a /= d) * a * a + b - } - ], - "ease-out-cubic": ["cubic-bezier(0.215, 0.610, 0.355, 1)", - function(a, b, c, d) { - return c * ((a = a / d - 1) * a * a + 1) + b - } - ], - "ease-in-out-cubic": ["cubic-bezier(0.645, 0.045, 0.355, 1)", - function(a, b, c, d) { - return (a /= d / 2) < 1 ? c / 2 * a * a * a + b : c / 2 * ((a -= 2) * a * a + 2) + b - } - ], - "ease-in-quart": ["cubic-bezier(0.895, 0.030, 0.685, 0.220)", - function(a, b, c, d) { - return c * (a /= d) * a * a * a + b - } - ], - "ease-out-quart": ["cubic-bezier(0.165, 0.840, 0.440, 1)", - function(a, b, c, d) { - return -c * ((a = a / d - 1) * a * a * a - 1) + b - } - ], - "ease-in-out-quart": ["cubic-bezier(0.770, 0, 0.175, 1)", - function(a, b, c, d) { - return (a /= d / 2) < 1 ? c / 2 * a * a * a * a + b : -c / 2 * ((a -= 2) * a * a * a - 2) + b - } - ], - "ease-in-quint": ["cubic-bezier(0.755, 0.050, 0.855, 0.060)", - function(a, b, c, d) { - return c * (a /= d) * a * a * a * a + b - } - ], - "ease-out-quint": ["cubic-bezier(0.230, 1, 0.320, 1)", - function(a, b, c, d) { - return c * ((a = a / d - 1) * a * a * a * a + 1) + b - } - ], - "ease-in-out-quint": ["cubic-bezier(0.860, 0, 0.070, 1)", - function(a, b, c, d) { - return (a /= d / 2) < 1 ? c / 2 * a * a * a * a * a + b : c / 2 * ((a -= 2) * a * a * a * a + 2) + b - } - ], - "ease-in-sine": ["cubic-bezier(0.470, 0, 0.745, 0.715)", - function(a, b, c, d) { - return -c * Math.cos(a / d * (Math.PI / 2)) + c + b - } - ], - "ease-out-sine": ["cubic-bezier(0.390, 0.575, 0.565, 1)", - function(a, b, c, d) { - return c * Math.sin(a / d * (Math.PI / 2)) + b - } - ], - "ease-in-out-sine": ["cubic-bezier(0.445, 0.050, 0.550, 0.950)", - function(a, b, c, d) { - return -c / 2 * (Math.cos(Math.PI * a / d) - 1) + b - } - ], - "ease-in-expo": ["cubic-bezier(0.950, 0.050, 0.795, 0.035)", - function(a, b, c, d) { - return 0 === a ? b : c * Math.pow(2, 10 * (a / d - 1)) + b - } - ], - "ease-out-expo": ["cubic-bezier(0.190, 1, 0.220, 1)", - function(a, b, c, d) { - return a === d ? b + c : c * (-Math.pow(2, -10 * a / d) + 1) + b - } - ], - "ease-in-out-expo": ["cubic-bezier(1, 0, 0, 1)", - function(a, b, c, d) { - 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 - } - ], - "ease-in-circ": ["cubic-bezier(0.600, 0.040, 0.980, 0.335)", - function(a, b, c, d) { - return -c * (Math.sqrt(1 - (a /= d) * a) - 1) + b - } - ], - "ease-out-circ": ["cubic-bezier(0.075, 0.820, 0.165, 1)", - function(a, b, c, d) { - return c * Math.sqrt(1 - (a = a / d - 1) * a) + b - } - ], - "ease-in-out-circ": ["cubic-bezier(0.785, 0.135, 0.150, 0.860)", - function(a, b, c, d) { - return (a /= d / 2) < 1 ? -c / 2 * (Math.sqrt(1 - a * a) - 1) + b : c / 2 * (Math.sqrt(1 - (a -= 2) * a) + 1) + b - } - ], - "ease-in-back": ["cubic-bezier(0.600, -0.280, 0.735, 0.045)", - function(a, b, c, d, e) { - return void 0 === e && (e = 1.70158), c * (a /= d) * a * ((e + 1) * a - e) + b - } - ], - "ease-out-back": ["cubic-bezier(0.175, 0.885, 0.320, 1.275)", - function(a, b, c, d, e) { - return void 0 === e && (e = 1.70158), c * ((a = a / d - 1) * a * ((e + 1) * a + e) + 1) + b - } - ], - "ease-in-out-back": ["cubic-bezier(0.680, -0.550, 0.265, 1.550)", - function(a, b, c, d, e) { - 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 - } - ] - }, - m = { - "ease-in-back": "cubic-bezier(0.600, 0, 0.735, 0.045)", - "ease-out-back": "cubic-bezier(0.175, 0.885, 0.320, 1)", - "ease-in-out-back": "cubic-bezier(0.680, 0, 0.265, 1)" - }, - n = document, - o = window, - p = "bkwld-tram", - q = /[\-\.0-9]/g, - r = /[A-Z]/, - s = "number", - t = /^(rgb|#)/, - u = /(em|cm|mm|in|pt|pc|px)$/, - v = /(em|cm|mm|in|pt|pc|px|%)$/, - w = /(deg|rad|turn)$/, - x = "unitless", - y = /(all|none) 0s ease 0s/, - z = /^(width|height)$/, - A = " ", - B = n.createElement("a"), - C = ["Webkit", "Moz", "O", "ms"], - D = ["-webkit-", "-moz-", "-o-", "-ms-"], - E = function(a) { - if (a in B.style) return { - dom: a, - css: a - }; - var b, c, d = "", - e = a.split("-"); - for (b = 0; b < e.length; b++) d += e[b].charAt(0).toUpperCase() + e[b].slice(1); - for (b = 0; b < C.length; b++) - if (c = C[b] + d, c in B.style) return { - dom: c, - css: D[b] + a - } - }, - F = b.support = { - bind: Function.prototype.bind, - transform: E("transform"), - transition: E("transition"), - backface: E("backface-visibility"), - timing: E("transition-timing-function") - }; - if (F.transition) { - var G = F.timing.dom; - if (B.style[G] = l["ease-in-back"][0], !B.style[G]) - for (var H in m) l[H][0] = m[H] - } - var I = b.frame = function() { - var a = o.requestAnimationFrame || o.webkitRequestAnimationFrame || o.mozRequestAnimationFrame || o.oRequestAnimationFrame || o.msRequestAnimationFrame; - return a && F.bind ? a.bind(o) : function(a) { - o.setTimeout(a, 16) - } - }(), - J = b.now = function() { - var a = o.performance, - b = a && (a.now || a.webkitNow || a.msNow || a.mozNow); - return b && F.bind ? b.bind(a) : Date.now || function() { - return +new Date - } - }(), - K = k(function(b) { - function d(a, b) { - var c = j(("" + a).split(A)), - d = c[0]; - b = b || {}; - var e = X[d]; - if (!e) return _("Unsupported property: " + d); - if (!b.weak || !this.props[d]) { - var f = e[0], - g = this.props[d]; - return g || (g = this.props[d] = new f.Bare), g.init(this.$el, c, e, b), g - } - } - - function e(a, b, c) { - if (a) { - var e = typeof a; - if (b || (this.timer && this.timer.destroy(), this.queue = [], this.active = !1), "number" == e && b) return this.timer = new R({ - duration: a, - context: this, - complete: h - }), void(this.active = !0); - if ("string" == e && b) { - switch (a) { - case "hide": - n.call(this); - break; - case "stop": - k.call(this); - break; - case "redraw": - o.call(this); - break; - default: - d.call(this, a, c && c[1]) - } - return h.call(this) - } - if ("function" == e) return void a.call(this, this); - if ("object" == e) { - var f = 0; - t.call(this, a, function(a, b) { - a.span > f && (f = a.span), a.stop(), a.animate(b) - }, function(a) { - "wait" in a && (f = i(a.wait, 0)) - }), s.call(this), f > 0 && (this.timer = new R({ - duration: f, - context: this - }), this.active = !0, b && (this.timer.complete = h)); - var g = this, - j = !1, - l = {}; - I(function() { - t.call(g, a, function(a) { - a.active && (j = !0, l[a.name] = a.nextStyle) - }), j && g.$el.css(l) - }) - } - } - } - - function f(a) { - a = i(a, 0), this.active ? this.queue.push({ - options: a - }) : (this.timer = new R({ - duration: a, - context: this, - complete: h - }), this.active = !0) - } - - function g(a) { - return this.active ? (this.queue.push({ - options: a, - args: arguments - }), void(this.timer.complete = h)) : _("No active transition timer. Use start() or wait() before then().") - } - - function h() { - if (this.timer && this.timer.destroy(), this.active = !1, this.queue.length) { - var a = this.queue.shift(); - e.call(this, a.options, !0, a.args) - } - } - - function k(a) { - this.timer && this.timer.destroy(), this.queue = [], this.active = !1; - var b; - "string" == typeof a ? (b = {}, b[a] = 1) : b = "object" == typeof a && null != a ? a : this.props, t.call(this, b, u), s.call(this) - } - - function l(a) { - k.call(this, a), t.call(this, a, v, w) - } - - function m(a) { - "string" != typeof a && (a = "block"), this.el.style.display = a - } - - function n() { - k.call(this), this.el.style.display = "none" - } - - function o() { - this.el.offsetHeight - } - - function q() { - k.call(this), a.removeData(this.el, p), this.$el = this.el = null - } - - function s() { - var a, b, c = []; - this.upstream && c.push(this.upstream); - for (a in this.props) b = this.props[a], b.active && c.push(b.string); - c = c.join(","), this.style !== c && (this.style = c, this.el.style[F.transition.dom] = c) - } - - function t(a, b, e) { - var f, g, h, i, j = b !== u, - k = {}; - 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)); - for (f in k) { - if (h = k[f], g = this.props[f], !g) { - if (!j) continue; - g = d.call(this, f) - } - b.call(this, g, h) - } - e && i && e.call(this, i) - } - - function u(a) { - a.stop() - } - - function v(a, b) { - a.set(b) - } - - function w(a) { - this.$el.css(a) - } - - function x(a, c) { - b[a] = function() { - return this.children ? z.call(this, c, arguments) : (this.el && c.apply(this, arguments), this) - } - } - - function z(a, b) { - var c, d = this.children.length; - for (c = 0; d > c; c++) a.apply(this.children[c], b); - return this - } - b.init = function(b) { - if (this.$el = a(b), this.el = this.$el[0], this.props = {}, this.queue = [], this.style = "", this.active = !1, T.keepInherited && !T.fallback) { - var c = V(this.el, "transition"); - c && !y.test(c) && (this.upstream = c) - } - F.backface && T.hideBackface && U(this.el, F.backface.css, "hidden") - }, 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) - }), - L = k(K, function(b) { - function c(b, c) { - var d = a.data(b, p) || a.data(b, p, new K.Bare); - return d.el || d.init(b), c ? d.start(c) : d - } - b.init = function(b, d) { - var e = a(b); - if (!e.length) return this; - if (1 === e.length) return c(e[0], d); - var f = []; - return e.each(function(a, b) { - f.push(c(b, d)) - }), this.children = f, this - } - }), - M = k(function(a) { - function b() { - var a = this.get(); - this.update("auto"); - var b = this.get(); - return this.update(a), b - } - - function c(a, b, c) { - return void 0 !== b && (c = b), a in l ? a : c - } - - function d(a) { - var b = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(a); - return (b ? e(b[1], b[2], b[3]) : a).replace(/#(\w)(\w)(\w)$/, "#$1$1$2$2$3$3") - } - var f = { - duration: 500, - ease: "ease", - delay: 0 - }; - a.init = function(a, b, d, e) { - this.$el = a, this.el = a[0]; - var g = b[0]; - 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" : "")) - }, a.set = function(a) { - a = this.convert(a, this.type), this.update(a), this.redraw() - }, a.transition = function(a) { - 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 - }, a.fallback = function(a) { - var c = this.el.style[this.name] || this.convert(this.get(), this.type); - 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({ - from: c, - to: a, - duration: this.duration, - delay: this.delay, - ease: this.ease, - update: this.update, - context: this - }) - }, a.get = function() { - return V(this.el, this.name) - }, a.update = function(a) { - U(this.el, this.name, a) - }, a.stop = function() { - (this.active || this.nextStyle) && (this.active = !1, this.nextStyle = null, U(this.el, this.name, this.get())); - var a = this.tween; - a && a.context && a.destroy() - }, a.convert = function(a, b) { - if ("auto" == a && this.auto) return a; - var c, e = "number" == typeof a, - f = "string" == typeof a; - switch (b) { - case s: - if (e) return a; - if (f && "" === a.replace(q, "")) return +a; - c = "number(unitless)"; - break; - case t: - if (f) { - if ("" === a && this.original) return this.original; - if (b.test(a)) return "#" == a.charAt(0) && 7 == a.length ? a : d(a) - } - c = "hex or rgb string"; - break; - case u: - if (e) return a + this.unit; - if (f && b.test(a)) return a; - c = "number(px) or string(unit)"; - break; - case v: - if (e) return a + this.unit; - if (f && b.test(a)) return a; - c = "number(px) or string(unit or %)"; - break; - case w: - if (e) return a + this.angle; - if (f && b.test(a)) return a; - c = "number(deg) or string(angle)"; - break; - case x: - if (e) return a; - if (f && v.test(a)) return a; - c = "number(unitless) or string(unit or %)" - } - return g(c, a), a - }, a.redraw = function() { - this.el.offsetHeight - } - }), - N = k(M, function(a, b) { - a.init = function() { - b.init.apply(this, arguments), this.original || (this.original = this.convert(this.get(), t)) - } - }), - O = k(M, function(a, b) { - a.init = function() { - b.init.apply(this, arguments), this.animate = this.fallback - }, a.get = function() { - return this.$el[this.name]() - }, a.update = function(a) { - this.$el[this.name](a) - } - }), - P = k(M, function(a, b) { - function c(a, b) { - var c, d, e, f, g; - 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) - } - a.init = function() { - 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())) - }, a.set = function(a) { - c.call(this, a, function(a, b) { - this.current[a] = b - }), U(this.el, this.name, this.style(this.current)), this.redraw() - }, a.transition = function(a) { - var b = this.values(a); - this.tween = new S({ - current: this.current, - values: b, - duration: this.duration, - delay: this.delay, - ease: this.ease - }); - var c, d = {}; - for (c in this.current) d[c] = c in b ? b[c] : this.current[c]; - this.active = !0, this.nextStyle = this.style(d) - }, a.fallback = function(a) { - var b = this.values(a); - this.tween = new S({ - current: this.current, - values: b, - duration: this.duration, - delay: this.delay, - ease: this.ease, - update: this.update, - context: this - }) - }, a.update = function() { - U(this.el, this.name, this.style(this.current)) - }, a.style = function(a) { - var b, c = ""; - for (b in a) c += b + "(" + a[b] + ") "; - return c - }, a.values = function(a) { - var b, d = {}; - return c.call(this, a, function(a, c, e) { - d[a] = c, void 0 === this.current[a] && (b = 0, ~a.indexOf("scale") && (b = 1), this.current[a] = this.convert(b, e)) - }), d - } - }), - Q = k(function(b) { - function c(a) { - 1 === n.push(a) && I(g) - } - - function g() { - var a, b, c, d = n.length; - if (d) - for (I(g), b = J(), a = d; a--;) c = n[a], c && c.render(b) - } - - function i(b) { - var c, d = a.inArray(b, n); - d >= 0 && (c = n.slice(d + 1), n.length = d, c.length && (n = n.concat(c))) - } - - function j(a) { - return Math.round(a * o) / o - } - - function k(a, b, c) { - return e(a[0] + c * (b[0] - a[0]), a[1] + c * (b[1] - a[1]), a[2] + c * (b[2] - a[2])) - } - var m = { - ease: l.ease[1], - from: 0, - to: 1 - }; - b.init = function(a) { - this.duration = a.duration || 0, this.delay = a.delay || 0; - var b = a.ease || m.ease; - 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; - var c = a.from, - d = a.to; - 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() - }, b.play = function() { - this.active || (this.start || (this.start = J()), this.active = !0, c(this)) - }, b.stop = function() { - this.active && (this.active = !1, i(this)) - }, b.render = function(a) { - var b, c = a - this.start; - if (this.delay) { - if (c <= this.delay) return; - c -= this.delay - } - if (c < this.duration) { - var d = this.ease(c, 0, 1, this.duration); - 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) - } - 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() - }, b.format = function(a, b) { - 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); - if (!this.unit) { - var c = b.replace(q, ""), - e = a.replace(q, ""); - c !== e && h("tween", b, a), this.unit = c - } - b = parseFloat(b), a = parseFloat(a), this.begin = this.value = b, this.change = a - b - }, b.destroy = function() { - this.stop(), this.context = null, this.ease = this.update = this.complete = f - }; - var n = [], - o = 1e3 - }), - R = k(Q, function(a) { - a.init = function(a) { - this.duration = a.duration || 0, this.complete = a.complete || f, this.context = a.context, this.play() - }, a.render = function(a) { - var b = a - this.start; - b < this.duration || (this.complete.call(this.context), this.destroy()) - } - }), - S = k(Q, function(a, b) { - a.init = function(a) { - this.context = a.context, this.update = a.update, this.tweens = [], this.current = a.current; - var b, c; - for (b in a.values) c = a.values[b], this.current[b] !== c && this.tweens.push(new Q({ - name: b, - from: this.current[b], - to: c, - duration: a.duration, - delay: a.delay, - ease: a.ease, - autoplay: !1 - })); - this.play() - }, a.render = function(a) { - var b, c, d = this.tweens.length, - e = !1; - for (b = d; b--;) c = this.tweens[b], c.context && (c.render(a), this.current[c.name] = c.value, e = !0); - return e ? void(this.update && this.update.call(this.context)) : this.destroy() - }, a.destroy = function() { - if (b.destroy.call(this), this.tweens) { - var a, c = this.tweens.length; - for (a = c; a--;) this.tweens[a].destroy(); - this.tweens = null, this.current = null - } - } - }), - T = b.config = { - defaultUnit: "px", - defaultAngle: "deg", - keepInherited: !1, - hideBackface: !1, - perspective: "", - fallback: !F.transition, - agentTests: [] - }; - b.fallback = function(a) { - if (!F.transition) return T.fallback = !0; - T.agentTests.push("(" + a + ")"); - var b = new RegExp(T.agentTests.join("|"), "i"); - T.fallback = b.test(navigator.userAgent) - }, b.fallback("6.0.[2-5] Safari"), b.tween = function(a) { - return new Q(a) - }, b.delay = function(a, b, c) { - return new R({ - complete: b, - duration: a, - context: c - }) - }, a.fn.tram = function(a) { - return b.call(null, this, a) - }; - var U = a.style, - V = a.css, - W = { - transform: F.transform && F.transform.css - }, - X = { - color: [N, t], - background: [N, t, "background-color"], - "outline-color": [N, t], - "border-color": [N, t], - "border-top-color": [N, t], - "border-right-color": [N, t], - "border-bottom-color": [N, t], - "border-left-color": [N, t], - "border-width": [M, u], - "border-top-width": [M, u], - "border-right-width": [M, u], - "border-bottom-width": [M, u], - "border-left-width": [M, u], - "border-spacing": [M, u], - "letter-spacing": [M, u], - margin: [M, u], - "margin-top": [M, u], - "margin-right": [M, u], - "margin-bottom": [M, u], - "margin-left": [M, u], - padding: [M, u], - "padding-top": [M, u], - "padding-right": [M, u], - "padding-bottom": [M, u], - "padding-left": [M, u], - "outline-width": [M, u], - opacity: [M, s], - top: [M, v], - right: [M, v], - bottom: [M, v], - left: [M, v], - "font-size": [M, v], - "text-indent": [M, v], - "word-spacing": [M, v], - width: [M, v], - "min-width": [M, v], - "max-width": [M, v], - height: [M, v], - "min-height": [M, v], - "max-height": [M, v], - "line-height": [M, x], - "scroll-top": [O, s, "scrollTop"], - "scroll-left": [O, s, "scrollLeft"] - }, - Y = {}; - F.transform && (X.transform = [P], Y = { - x: [v, "translateX"], - y: [v, "translateY"], - rotate: [w], - rotateX: [w], - rotateY: [w], - scale: [s], - scaleX: [s], - scaleY: [s], - skew: [w], - skewX: [w], - skewY: [w] - }), F.transform && F.backface && (Y.z = [v, "translateZ"], Y.rotateZ = [w], Y.scaleZ = [s], Y.perspective = [u]); - var Z = /ms/, - $ = /s|\./, - _ = function() { - var a = "warn", - b = window.console; - return b && b[a] ? function(c) { - b[a](c) - } : f - }(); - return a.tram = b -}(window.jQuery); -/*! - * jQuery-ajaxTransport-XDomainRequest - v1.0.1 - 2013-10-17 - * https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest - * Copyright (c) 2013 Jason Moon (@JSONMOON) - * Licensed MIT (/blob/master/LICENSE.txt) - */ -(function($) { - if (!$.support.cors && $.ajaxTransport && window.XDomainRequest) { - var n = /^https?:\/\//i; - var o = /^get|post$/i; - var p = new RegExp('^' + location.protocol, 'i'); - var q = /text\/html/i; - var r = /\/json/i; - var s = /\/xml/i; - $.ajaxTransport('* text html xml json', function(i, j, k) { - if (i.crossDomain && i.async && o.test(i.type) && n.test(i.url) && p.test(i.url)) { - var l = null; - var m = (j.dataType || '').toLowerCase(); - return { - send: function(f, g) { - l = new XDomainRequest(); - if (/^\d+$/.test(j.timeout)) { - l.timeout = j.timeout - } - l.ontimeout = function() { - g(500, 'timeout') - }; - l.onload = function() { - var a = 'Content-Length: ' + l.responseText.length + '\r\nContent-Type: ' + l.contentType; - var b = { - code: 200, - message: 'success' - }; - var c = { - text: l.responseText - }; - try { - if (m === 'html' || q.test(l.contentType)) { - c.html = l.responseText - } else if (m === 'json' || (m !== 'text' && r.test(l.contentType))) { - try { - c.json = $.parseJSON(l.responseText) - } catch (e) { - b.code = 500; - b.message = 'parseerror' - } - } else if (m === 'xml' || (m !== 'text' && s.test(l.contentType))) { - var d = new ActiveXObject('Microsoft.XMLDOM'); - d.async = false; - try { - d.loadXML(l.responseText) - } catch (e) { - d = undefined - } - if (!d || !d.documentElement || d.getElementsByTagName('parsererror').length) { - b.code = 500; - b.message = 'parseerror'; - throw 'Invalid XML: ' + l.responseText; - } - c.xml = d - } - } catch (parseMessage) { - throw parseMessage; - } finally { - g(b.code, b.message, c, a) - } - }; - l.onprogress = function() {}; - l.onerror = function() { - g(500, 'error', { - text: l.responseText - }) - }; - var h = ''; - if (j.data) { - h = ($.type(j.data) === 'string') ? j.data : $.param(j.data) - } - l.open(i.type, i.url); - l.send(h) - }, - abort: function() { - if (l) { - l.abort() - } - } - } - } - }) - } -})(jQuery); -/* jshint ignore:end */ -/** - * ---------------------------------------------------------------------- - * Init lib after plugins - */ -Webflow.init(); -/** - * ---------------------------------------------------------------------- - * Webflow: Interactions - */ -Webflow.define('ix', function($, _) { - 'use strict'; - - var api = {}; - var designer; - var $win = $(window); - var namespace = '.w-ix'; - var tram = window.tram; - var env = Webflow.env; - var ios = env.ios; - var inApp = env(); - var emptyFix = env.chrome && env.chrome < 35; - var transNone = 'none 0s ease 0s'; - var introEvent = 'w-ix-intro' + namespace; - var outroEvent = 'w-ix-outro' + namespace; - var fallbackProps = /width|height/; - var eventQueue = []; - var $subs = $(); - var config = {}; - var anchors = []; - var loads = []; - var readys = []; - var unique = 0; - var store; - - // Component types and proxy selectors - var components = { - tabs: '.w-tab-link, .w-tab-pane', - dropdown: '.w-dropdown', - slider: '.w-slide', - navbar: '.w-nav' - }; - - // ----------------------------------- - // Module methods - - api.init = function(list) { - setTimeout(function() { - init(list); - }, 1); - }; - - api.preview = function() { - designer = false; - setTimeout(function() { - init(window.__wf_ix); - }, 1); - }; - - api.design = function() { - designer = true; - $subs.each(teardown); - Webflow.scroll.off(scroll); - asyncEvents(); - anchors = []; - loads = []; - readys = []; - }; - - api.run = run; - api.events = {}; - api.style = inApp ? styleApp : stylePub; - - // ----------------------------------- - // Private methods - - function init(list) { - if (!list) return; - store = {}; - - // Map all interactions to a hash using slug as key. - config = {}; - _.each(list, function(item) { - config[item.slug] = item.value; - }); - - // Build each element's interaction keying from data attribute - var els = $('[data-ix]'); - if (!els.length) return; - els.each(teardown); - els.each(build); - - // Listen for scroll events if any anchors exist - if (anchors.length) { - Webflow.scroll.on(scroll); - setTimeout(scroll, 1); - } - - // Handle loads or readys if they exist - if (loads.length) $win.on('load', runLoads); - if (readys.length) setTimeout(runReadys, 1); - - // Init module events - initEvents(); - } - - function build(i, el) { - var $el = $(el); - var id = $el.attr('data-ix'); - var ix = config[id]; - if (!ix) return; - var triggers = ix.triggers; - if (!triggers) return; - var state = store[id] || (store[id] = {}); - - // Set initial styles, unless we detect an iOS device + any non-iOS triggers - var setStyles = !(ios && _.any(triggers, isNonIOS)); - if (setStyles) api.style($el, ix.style); - - _.each(triggers, function(trigger) { - var type = trigger.type; - var stepsB = trigger.stepsB && trigger.stepsB.length; - - function runA() { - run(trigger, $el, { - group: 'A' - }); - } - - function runB() { - run(trigger, $el, { - group: 'B' - }); - } - - if (type == 'load') { - (trigger.preload && !inApp) ? loads.push(runA) : readys.push(runA); - return; - } - - if (type == 'click') { - var stateKey = 'click:' + unique++; - if (trigger.descend) stateKey += ':descend'; - if (trigger.siblings) stateKey += ':siblings'; - if (trigger.selector) stateKey += ':' + trigger.selector; - - $el.on('click' + namespace, function(evt) { - if ($el.attr('href') === '#') evt.preventDefault(); - - run(trigger, $el, { - group: state[stateKey] ? 'B' : 'A' - }); - if (stepsB) state[stateKey] = !state[stateKey]; - }); - $subs = $subs.add($el); - return; - } - - if (type == 'hover') { - $el.on('mouseenter' + namespace, runA); - $el.on('mouseleave' + namespace, runB); - $subs = $subs.add($el); - return; - } - - // Check for a component proxy selector - var proxy = components[type]; - if (proxy) { - var $proxy = $el.closest(proxy); - $proxy.on(introEvent, runA).on(outroEvent, runB); - $subs = $subs.add($proxy); - return; - } - - // Ignore the following triggers on iOS devices - if (ios) return; - - if (type == 'scroll') { - anchors.push({ - el: $el, - trigger: trigger, - state: { - active: false - }, - offsetTop: convert(trigger.offsetTop), - offsetBot: convert(trigger.offsetBot) - }); - return; - } - }); - } - - function isNonIOS(trigger) { - return trigger.type == 'scroll'; - } - - function convert(offset) { - if (!offset) return 0; - offset = offset + ''; - var result = parseInt(offset, 10); - if (result !== result) return 0; - if (offset.indexOf('%') > 0) { - result = result / 100; - if (result >= 1) result = 0.999; - } - return result; - } - - function teardown(i, el) { - $(el).off(namespace); - } - - function scroll() { - var viewTop = $win.scrollTop(); - var viewHeight = $win.height(); - - // Check each anchor for a valid scroll trigger - var count = anchors.length; - for (var i = 0; i < count; i++) { - var anchor = anchors[i]; - var $el = anchor.el; - var trigger = anchor.trigger; - var stepsB = trigger.stepsB && trigger.stepsB.length; - var state = anchor.state; - var top = $el.offset().top; - var height = $el.outerHeight(); - var offsetTop = anchor.offsetTop; - var offsetBot = anchor.offsetBot; - if (offsetTop < 1 && offsetTop > 0) offsetTop *= viewHeight; - if (offsetBot < 1 && offsetBot > 0) offsetBot *= viewHeight; - var active = (top + height - offsetTop >= viewTop && top + offsetBot <= viewTop + viewHeight); - if (active === state.active) continue; - if (active === false && !stepsB) continue; - state.active = active; - run(trigger, $el, { - group: active ? 'A' : 'B' - }); - } - } - - function runLoads() { - var count = loads.length; - for (var i = 0; i < count; i++) { - loads[i](); - } - } - - function runReadys() { - var count = readys.length; - for (var i = 0; i < count; i++) { - readys[i](); - } - } - - function run(trigger, $el, opts, replay) { - opts = opts || {}; - var done = opts.done; - - // Do not run in designer unless forced - if (designer && !opts.force) return; - - // Operate on a set of grouped steps - var group = opts.group || 'A'; - var loop = trigger['loop' + group]; - var steps = trigger['steps' + group]; - if (!steps || !steps.length) return; - if (steps.length < 2) loop = false; - - // One-time init before any loops - if (!replay) { - - // Find selector within element descendants, siblings, or query whole document - var selector = trigger.selector; - if (selector) { - $el = ( - trigger.descend ? $el.find(selector) : - trigger.siblings ? $el.siblings(selector) : - $(selector) - ); - if (inApp) $el.attr('data-ix-affect', 1); - } - - // Apply empty fix for certain Chrome versions - if (emptyFix) $el.addClass('w-ix-emptyfix'); - } - - var _tram = tram($el); - - // Add steps - var meta = {}; - for (var i = 0; i < steps.length; i++) { - addStep(_tram, steps[i], meta); - } - - function fin() { - // Run trigger again if looped - if (loop) return run(trigger, $el, opts, true); - - // Reset any 'auto' values - if (meta.width == 'auto') _tram.set({ - width: 'auto' - }); - if (meta.height == 'auto') _tram.set({ - height: 'auto' - }); - - // Run callback - done && done(); - } - - // Add final step to queue if tram has started - meta.start ? _tram.then(fin) : fin(); - } - - function addStep(_tram, step, meta) { - var addMethod = 'add'; - var startMethod = 'start'; - - // Once the transition has started, we will always use then() to add to the queue. - if (meta.start) addMethod = startMethod = 'then'; - - // Parse transitions string on the current step - var transitions = step.transition; - if (transitions) { - transitions = transitions.split(','); - for (var i = 0; i < transitions.length; i++) { - var transition = transitions[i]; - var options = fallbackProps.test(transition) ? { - fallback: true - } : null; - _tram[addMethod](transition, options); - } - } - - // Build a clean object to pass to the tram method - var clean = tramify(step) || {}; - - // Store last width and height values - if (clean.width != null) meta.width = clean.width; - if (clean.height != null) meta.height = clean.height; - - // When transitions are not present, set values immediately and continue queue. - if (transitions == null) { - - // If we have started, wrap set() in then() and reset queue - if (meta.start) { - _tram.then(function() { - var queue = this.queue; - this.set(clean); - if (clean.display) { - _tram.redraw(); - Webflow.redraw.up(); - } - this.queue = queue; - this.next(); - }); - } else { - _tram.set(clean); - - // Always redraw after setting display - if (clean.display) { - _tram.redraw(); - Webflow.redraw.up(); - } - } - - // Use the wait() method to kick off queue in absence of transitions. - var wait = clean.wait; - if (wait != null) { - _tram.wait(wait); - meta.start = true; - } - - // Otherwise, when transitions are present - } else { - - // If display is present, handle it separately - if (clean.display) { - var display = clean.display; - delete clean.display; - - // If we've already started, we need to wrap it in a then() - if (meta.start) { - _tram.then(function() { - var queue = this.queue; - this.set({ - display: display - }).redraw(); - Webflow.redraw.up(); - this.queue = queue; - this.next(); - }); - } else { - _tram.set({ - display: display - }).redraw(); - Webflow.redraw.up(); - } - } - - // Otherwise, start a transition using the current start method. - _tram[startMethod](clean); - meta.start = true; - } - } - - // (In app) Set styles immediately and manage upstream transition - function styleApp(el, data) { - var _tram = tram(el); - - // Get computed transition value - el.css('transition', ''); - var computed = el.css('transition'); - - // If computed is disabled, clear upstream - if (computed === transNone) computed = _tram.upstream = null; - - // Disable upstream temporarily - _tram.upstream = transNone; - - // Set values immediately - _tram.set(tramify(data)); - - // Only restore upstream in preview mode - _tram.upstream = computed; - } - - // (Published) Set styles immediately on specified jquery element - function stylePub(el, data) { - tram(el).set(tramify(data)); - } - - // Build a clean object for tram - function tramify(obj) { - var result = {}; - var found = false; - for (var x in obj) { - if (x === 'transition') continue; - result[x] = obj[x]; - found = true; - } - // If empty, return null for tram.set/stop compliance - return found ? result : null; - } - - // Events used by other webflow modules - var events = { - reset: function(i, el) { - el.__wf_intro = null; - }, - intro: function(i, el) { - if (el.__wf_intro) return; - el.__wf_intro = true; - $(el).triggerHandler(introEvent); - }, - outro: function(i, el) { - if (!el.__wf_intro) return; - el.__wf_intro = null; - $(el).triggerHandler(outroEvent); - } - }; - - // Trigger events in queue + point to sync methods - function initEvents() { - var count = eventQueue.length; - for (var i = 0; i < count; i++) { - var memo = eventQueue[i]; - memo[0](0, memo[1]); - } - eventQueue = []; - $.extend(api.events, events); - } - - // Replace events with async methods prior to init - function asyncEvents() { - _.each(events, function(func, name) { - api.events[name] = function(i, el) { - eventQueue.push([func, el]); - }; - }); - } - - asyncEvents(); - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Touch events - */ -Webflow.define('touch', function($, _) { - 'use strict'; - - var api = {}; - var fallback = !document.addEventListener; - var getSelection = window.getSelection; - - // Fallback to click events in old IE - if (fallback) { - $.event.special.tap = { - bindType: 'click', - delegateType: 'click' - }; - } - - api.init = function(el) { - if (fallback) return null; - el = typeof el === 'string' ? $(el).get(0) : el; - return el ? new Touch(el) : null; - }; - - function Touch(el) { - var active = false; - var dirty = false; - var useTouch = false; - var thresholdX = Math.min(Math.round(window.innerWidth * 0.04), 40); - var startX, startY, lastX; - var _move = _.throttle(move); - - el.addEventListener('touchstart', start, false); - el.addEventListener('touchmove', _move, false); - el.addEventListener('touchend', end, false); - el.addEventListener('touchcancel', cancel, false); - el.addEventListener('mousedown', start, false); - el.addEventListener('mousemove', _move, false); - el.addEventListener('mouseup', end, false); - el.addEventListener('mouseout', cancel, false); - - function start(evt) { - // We don’t handle multi-touch events yet. - var touches = evt.touches; - if (touches && touches.length > 1) { - return; - } - - active = true; - dirty = false; - - if (touches) { - useTouch = true; - startX = touches[0].clientX; - startY = touches[0].clientY; - } else { - startX = evt.clientX; - startY = evt.clientY; - } - - lastX = startX; - } - - function move(evt) { - if (!active) return; - - if (useTouch && evt.type === 'mousemove') { - evt.preventDefault(); - evt.stopPropagation(); - return; - } - - var touches = evt.touches; - var x = touches ? touches[0].clientX : evt.clientX; - var y = touches ? touches[0].clientY : evt.clientY; - - var velocityX = x - lastX; - lastX = x; - - // Allow swipes while pointer is down, but prevent them during text selection - if (Math.abs(velocityX) > thresholdX && getSelection && getSelection() + '' === '') { - triggerEvent('swipe', evt, { - direction: velocityX > 0 ? 'right' : 'left' - }); - cancel(); - } - - // If pointer moves more than 10px flag to cancel tap - if (Math.abs(x - startX) > 10 || Math.abs(y - startY) > 10) { - dirty = true; - } - } - - function end(evt) { - if (!active) return; - active = false; - - if (useTouch && evt.type === 'mouseup') { - evt.preventDefault(); - evt.stopPropagation(); - useTouch = false; - return; - } - - if (!dirty) triggerEvent('tap', evt); - } - - function cancel(evt) { - active = false; - } - - function destroy() { - el.removeEventListener('touchstart', start, false); - el.removeEventListener('touchmove', _move, false); - el.removeEventListener('touchend', end, false); - el.removeEventListener('touchcancel', cancel, false); - el.removeEventListener('mousedown', start, false); - el.removeEventListener('mousemove', _move, false); - el.removeEventListener('mouseup', end, false); - el.removeEventListener('mouseout', cancel, false); - el = null; - } - - // Public instance methods - this.destroy = destroy; - } - - // Wrap native event to supoprt preventdefault + stopPropagation - function triggerEvent(type, evt, data) { - var newEvent = $.Event(type, { - originalEvent: evt - }); - $(evt.target).trigger(newEvent, data); - } - - // Listen for touch events on all nodes by default. - api.instance = api.init(document); - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Forms - */ -Webflow.define('forms', function($, _) { - 'use strict'; - - var api = {}; - var $doc = $(document); - var $forms; - var loc = window.location; - var retro = window.XDomainRequest && !window.atob; - var namespace = '.w-form'; - var siteId; - var emailField = /e(\-)?mail/i; - var emailValue = /^\S+@\S+$/; - var alert = window.alert; - var listening; - - // MailChimp domains: list-manage.com + mirrors - var chimpRegex = /list-manage[1-9]?.com/i; - - api.ready = function() { - // Init forms - init(); - - // Wire document events once - if (!listening) addListeners(); - }; - - api.preview = api.design = function() { - init(); - }; - - function init() { - siteId = $('html').attr('data-wf-site'); - - $forms = $(namespace + ' form'); - if (!$forms.length) return; - $forms.each(build); - } - - function build(i, el) { - // Store form state using namespace - var $el = $(el); - var data = $.data(el, namespace); - if (!data) data = $.data(el, namespace, { - form: $el - }); // data.form - - reset(data); - var wrap = $el.closest('div.w-form'); - data.done = wrap.find('> .w-form-done'); - data.fail = wrap.find('> .w-form-fail'); - - var action = data.action = $el.attr('action'); - data.handler = null; - data.redirect = $el.attr('data-redirect'); - - // MailChimp form - if (chimpRegex.test(action)) { - data.handler = submitMailChimp; - return; - } - - // Custom form action - if (action) return; - - // Webflow form - if (siteId) { - data.handler = submitWebflow; - return; - } - - // Alert for disconnected Webflow forms - disconnected(); - } - - function addListeners() { - listening = true; - - // Handle form submission for Webflow forms - $doc.on('submit', namespace + ' form', function(evt) { - var data = $.data(this, namespace); - if (data.handler) { - data.evt = evt; - data.handler(data); - } - }); - } - - // Reset data common to all submit handlers - function reset(data) { - var btn = data.btn = data.form.find(':input[type="submit"]'); - data.wait = data.btn.attr('data-wait') || null; - data.success = false; - btn.prop('disabled', false); - data.label && btn.val(data.label); - } - - // Disable submit button - function disableBtn(data) { - var btn = data.btn; - var wait = data.wait; - btn.prop('disabled', true); - // Show wait text and store previous label - if (wait) { - data.label = btn.val(); - btn.val(wait); - } - } - - // Find form fields, validate, and set value pairs - function findFields(form, result) { - var status = null; - result = result || {}; - - // The ":input" selector is a jQuery shortcut to select all inputs, selects, textareas - form.find(':input:not([type="submit"])').each(function(i, el) { - var field = $(el); - var type = field.attr('type'); - var name = field.attr('data-name') || field.attr('name') || ('Field ' + (i + 1)); - var value = field.val(); - - if (type == 'checkbox') { - value = field.is(':checked'); - } - if (type == 'radio') { - // Radio group value already processed - if (result[name] === null || typeof result[name] == 'string') { - return; - } - - value = form.find('input[name="' + field.attr('name') + '"]:checked').val() || null; - } - - if (typeof value == 'string') value = $.trim(value); - result[name] = value; - status = status || getStatus(field, name, value); - }); - - return status; - } - - function getStatus(field, name, value) { - var status = null; - if (!field.attr('required')) return null; - if (!value) status = 'Please fill out the required field: ' + name; - else if (emailField.test(name) || emailField.test(field.attr('type'))) { - if (!emailValue.test(value)) status = 'Please enter a valid email address for: ' + name; - } - return status; - } - - // Submit form to Webflow - function submitWebflow(data) { - reset(data); - - var form = data.form; - var payload = { - name: form.attr('data-name') || form.attr('name') || 'Untitled Form', - source: loc.href, - test: Webflow.env(), - fields: {} - }; - - preventDefault(data); - - // Find & populate all fields - var status = findFields(form, payload.fields); - if (status) return alert(status); - - // Disable submit button - disableBtn(data); - - // Read site ID - // NOTE: If this site is exported, the HTML tag must retain the data-wf-site attribute for forms to work - if (!siteId) { - afterSubmit(data); - return; - } - var url = 'https://webflow.com/api/v1/form/' + siteId; - - // Work around same-protocol IE XDR limitation - if (retro && url.indexOf('https://webflow.com') >= 0) { - url = url.replace('https://webflow.com/', 'http://data.webflow.com/'); - } - - $.ajax({ - url: url, - type: 'POST', - data: payload, - dataType: 'json', - crossDomain: true - }).done(function() { - data.success = true; - afterSubmit(data); - }).fail(function() { - afterSubmit(data); - }); - } - - // Submit form to MailChimp - function submitMailChimp(data) { - reset(data); - - var form = data.form; - var payload = {}; - - // Skip Ajax submission if http/s mismatch, fallback to POST instead - if (/^https/.test(loc.href) && !/^https/.test(data.action)) { - form.attr('method', 'post'); - return; - } - - preventDefault(data); - - // Find & populate all fields - var status = findFields(form, payload); - if (status) return alert(status); - - // Disable submit button - disableBtn(data); - - // Use special format for MailChimp params - var fullName; - _.each(payload, function(value, key) { - if (emailField.test(key)) payload.EMAIL = value; - if (/^((full[ _-]?)?name)$/i.test(key)) fullName = value; - if (/^(first[ _-]?name)$/i.test(key)) payload.FNAME = value; - if (/^(last[ _-]?name)$/i.test(key)) payload.LNAME = value; - }); - - if (fullName && !payload.FNAME) { - fullName = fullName.split(' '); - payload.FNAME = fullName[0]; - payload.LNAME = payload.LNAME || fullName[1]; - } - - // Use the (undocumented) MailChimp jsonp api - var url = data.action.replace('/post?', '/post-json?') + '&c=?'; - // Add special param to prevent bot signups - var userId = url.indexOf('u=') + 2; - userId = url.substring(userId, url.indexOf('&', userId)); - var listId = url.indexOf('id=') + 3; - listId = url.substring(listId, url.indexOf('&', listId)); - payload['b_' + userId + '_' + listId] = ''; - - $.ajax({ - url: url, - data: payload, - dataType: 'jsonp' - }).done(function(resp) { - data.success = (resp.result == 'success' || /already/.test(resp.msg)); - if (!data.success) console.info('MailChimp error: ' + resp.msg); - afterSubmit(data); - }).fail(function() { - afterSubmit(data); - }); - } - - // Common callback which runs after all Ajax submissions - function afterSubmit(data) { - var form = data.form; - var wrap = form.closest('div.w-form'); - var redirect = data.redirect; - var success = data.success; - - // Redirect to a success url if defined - if (success && redirect) { - Webflow.location(redirect); - return; - } - - // Show or hide status divs - data.done.toggle(success); - data.fail.toggle(!success); - - // Hide form on success - form.toggle(!success); - - // Reset data and enable submit button - reset(data); - } - - function preventDefault(data) { - data.evt && data.evt.preventDefault(); - data.evt = null; - } - - var disconnected = _.debounce(function() { - 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 support@webflow.com to fix this issue.'); - }, 100); - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Smooth scroll - */ -Webflow.define('scroll', function($) { - 'use strict'; - - var $doc = $(document); - var win = window; - var loc = win.location; - var history = win.history; - var validHash = /^[a-zA-Z][\w:.-]*$/; - - function ready() { - // If hash is already present on page load, scroll to it right away - if (loc.hash) { - findEl(loc.hash.substring(1)); - } - - // When clicking on a link, check if it links to another part of the page - $doc.on('click', 'a', function(e) { - if (Webflow.env('design')) { - return; - } - - // Ignore links being used by jQuery mobile - if (window.$.mobile && $(e.currentTarget).hasClass('ui-link')) return; - - var hash = this.hash ? this.hash.substring(1) : null; - if (hash) { - findEl(hash, e); - } - }); - } - - function findEl(hash, e) { - if (!validHash.test(hash)) return; - - var el = $('#' + hash); - if (!el.length) { - return; - } - - if (e) { - e.preventDefault(); - e.stopPropagation(); - } - - // Push new history state - if (loc.hash !== hash && history && history.pushState) { - var oldHash = history.state && history.state.hash; - if (oldHash !== hash) { - history.pushState({ - hash: hash - }, '', '#' + hash); - } - } - - // If a fixed header exists, offset for the height - var header = $('header, body > .header, body > .w-nav'); - var offset = header.css('position') === 'fixed' ? header.outerHeight() : 0; - - win.setTimeout(function() { - scroll(el, offset); - }, e ? 0 : 300); - } - - function scroll(el, offset) { - var start = $(win).scrollTop(); - var end = el.offset().top - offset; - - // If specified, scroll so that the element ends up in the middle of the viewport - if (el.data('scroll') == 'mid') { - var available = $(win).height() - offset; - var elHeight = el.outerHeight(); - if (elHeight < available) { - end -= Math.round((available - elHeight) / 2); - } - } - - var mult = 1; - - // Check for custom time multiplier on the body and the element - $('body').add(el).each(function(i) { - var time = parseFloat($(this).attr('data-scroll-time'), 10); - if (!isNaN(time) && (time === 0 || time > 0)) { - mult = time; - } - }); - - // Shim for IE8 and below - if (!Date.now) { - Date.now = function() { - return new Date().getTime(); - }; - } - - var clock = Date.now(); - var animate = win.requestAnimationFrame || win.mozRequestAnimationFrame || win.webkitRequestAnimationFrame || function(fn) { - win.setTimeout(fn, 15); - }; - var duration = (472.143 * Math.log(Math.abs(start - end) + 125) - 2000) * mult; - - var step = function() { - var elapsed = Date.now() - clock; - win.scroll(0, getY(start, end, elapsed, duration)); - - if (elapsed <= duration) { - animate(step); - } - }; - - step(); - } - - function getY(start, end, elapsed, duration) { - if (elapsed > duration) { - return end; - } - - return start + (end - start) * ease(elapsed / duration); - } - - function ease(t) { - return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; - } - - // Export module - return { - ready: ready - }; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Auto-select links to current page or section - */ -Webflow.define('links', function($, _) { - 'use strict'; - - var api = {}; - var $win = $(window); - var designer; - var inApp = Webflow.env(); - var location = window.location; - var linkCurrent = 'w--current'; - var validHash = /^#[a-zA-Z][\w:.-]*$/; - var indexPage = /index\.(html|php)$/; - var dirList = /\/$/; - var anchors; - var slug; - - // ----------------------------------- - // Module methods - - api.ready = api.design = api.preview = init; - - // ----------------------------------- - // Private methods - - function init() { - designer = inApp && Webflow.env('design'); - slug = Webflow.env('slug') || location.pathname || ''; - - // Reset scroll listener, init anchors - Webflow.scroll.off(scroll); - anchors = []; - - // Test all links for a selectable href - var links = document.links; - for (var i = 0; i < links.length; ++i) { - select(links[i]); - } - - // Listen for scroll if any anchors exist - if (anchors.length) { - Webflow.scroll.on(scroll); - scroll(); - } - } - - function select(link) { - var href = link.getAttribute('href'); - - // Ignore any hrefs with a colon to safely avoid all uri schemes - if (href.indexOf(':') >= 0) return; - - var $link = $(link); - - // Check for valid hash links w/ sections and use scroll anchor - if (href.indexOf('#') === 0 && validHash.test(href)) { - // Ignore #edit anchors - if (href === '#edit') return; - var $section = $(href); - $section.length && anchors.push({ - link: $link, - sec: $section, - active: false - }); - return; - } - - // Determine whether the link should be selected - var match = (link.href === location.href) || (href === slug) || (indexPage.test(href) && dirList.test(slug)); - setClass($link, linkCurrent, match); - } - - function scroll() { - var viewTop = $win.scrollTop(); - var viewHeight = $win.height(); - - // Check each anchor for a section in view - _.each(anchors, function(anchor) { - var $link = anchor.link; - var $section = anchor.sec; - var top = $section.offset().top; - var height = $section.outerHeight(); - var offset = viewHeight * 0.5; - var active = ($section.is(':visible') && - top + height - offset >= viewTop && - top + offset <= viewTop + viewHeight); - if (anchor.active === active) return; - anchor.active = active; - setClass($link, linkCurrent, active); - if (designer) $link[0].__wf_current = active; - }); - } - - function setClass($elem, className, add) { - var exists = $elem.hasClass(className); - if (add && exists) return; - if (!add && !exists) return; - add ? $elem.addClass(className) : $elem.removeClass(className); - } - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Slider component - */ -Webflow.define('slider', function($, _) { - 'use strict'; - - var api = {}; - var tram = window.tram; - var $doc = $(document); - var $sliders; - var designer; - var inApp = Webflow.env(); - var namespace = '.w-slider'; - var dot = '
'; - var ix = Webflow.ixEvents(); - var fallback; - var redraw; - - // ----------------------------------- - // Module methods - - api.ready = function() { - init(); - }; - - api.design = function() { - designer = true; - init(); - }; - - api.preview = function() { - designer = false; - init(); - }; - - api.redraw = function() { - redraw = true; - init(); - }; - - api.destroy = removeListeners; - - // ----------------------------------- - // Private methods - - function init() { - // Find all sliders on the page - $sliders = $doc.find(namespace); - if (!$sliders.length) return; - $sliders.filter(':visible').each(build); - redraw = null; - if (fallback) return; - - // Wire events - removeListeners(); - addListeners(); - } - - function removeListeners() { - Webflow.resize.off(renderAll); - Webflow.redraw.off(api.redraw); - } - - function addListeners() { - Webflow.resize.on(renderAll); - Webflow.redraw.on(api.redraw); - } - - function renderAll() { - $sliders.filter(':visible').each(render); - } - - function build(i, el) { - var $el = $(el); - - // Store slider state in data - var data = $.data(el, namespace); - if (!data) data = $.data(el, namespace, { - index: 0, - depth: 1, - el: $el, - config: {} - }); - data.mask = $el.children('.w-slider-mask'); - data.left = $el.children('.w-slider-arrow-left'); - data.right = $el.children('.w-slider-arrow-right'); - data.nav = $el.children('.w-slider-nav'); - data.slides = data.mask.children('.w-slide'); - data.slides.each(ix.reset); - if (redraw) data.maskWidth = 0; - - // Disable in old browsers - if (!tram.support.transform) { - data.left.hide(); - data.right.hide(); - data.nav.hide(); - fallback = true; - return; - } - - // Remove old events - data.el.off(namespace); - data.left.off(namespace); - data.right.off(namespace); - data.nav.off(namespace); - - // Set config from data attributes - configure(data); - - // Add events based on mode - if (designer) { - data.el.on('setting' + namespace, handler(data)); - stopTimer(data); - data.hasTimer = false; - } else { - data.el.on('swipe' + namespace, handler(data)); - data.left.on('tap' + namespace, previous(data)); - data.right.on('tap' + namespace, next(data)); - - // Start timer if autoplay is true, only once - if (data.config.autoplay && !data.hasTimer) { - data.hasTimer = true; - data.timerCount = 1; - startTimer(data); - } - } - - // Listen to nav events - data.nav.on('tap' + namespace, '> div', handler(data)); - - // Remove gaps from formatted html (for inline-blocks) - if (!inApp) { - data.mask.contents().filter(function() { - return this.nodeType === 3; - }).remove(); - } - - // Run first render - render(i, el); - } - - function configure(data) { - var config = {}; - - config.crossOver = 0; - - // Set config options from data attributes - config.animation = data.el.attr('data-animation') || 'slide'; - if (config.animation == 'outin') { - config.animation = 'cross'; - config.crossOver = 0.5; - } - config.easing = data.el.attr('data-easing') || 'ease'; - - var duration = data.el.attr('data-duration'); - config.duration = duration != null ? +duration : 500; - - if (+data.el.attr('data-infinite')) config.infinite = true; - - if (+data.el.attr('data-hide-arrows')) { - config.hideArrows = true; - } else if (data.config.hideArrows) { - data.left.show(); - data.right.show(); - } - - if (+data.el.attr('data-autoplay')) { - config.autoplay = true; - config.delay = +data.el.attr('data-delay') || 2000; - config.timerMax = +data.el.attr('data-autoplay-limit'); - // Disable timer on first touch or mouse down - var touchEvents = 'mousedown' + namespace + ' touchstart' + namespace; - if (!designer) data.el.off(touchEvents).one(touchEvents, function() { - stopTimer(data); - }); - } - - // Use edge buffer to help calculate page count - var arrowWidth = data.right.width(); - config.edge = arrowWidth ? arrowWidth + 40 : 100; - - // Store config in data - data.config = config; - } - - function previous(data) { - return function(evt) { - change(data, { - index: data.index - 1, - vector: -1 - }); - }; - } - - function next(data) { - return function(evt) { - change(data, { - index: data.index + 1, - vector: 1 - }); - }; - } - - function select(data, value) { - // Select page based on slide element index - var found = null; - if (value === data.slides.length) { - init(); - layout(data); // Rebuild and find new slides - } - _.each(data.anchors, function(anchor, index) { - $(anchor.els).each(function(i, el) { - if ($(el).index() === value) found = index; - }); - }); - if (found != null) change(data, { - index: found, - immediate: true - }); - } - - function startTimer(data) { - stopTimer(data); - var config = data.config; - var timerMax = config.timerMax; - if (timerMax && data.timerCount++ > timerMax) return; - data.timerId = window.setTimeout(function() { - if (data.timerId == null || designer) return; - next(data)(); - startTimer(data); - }, config.delay); - } - - function stopTimer(data) { - window.clearTimeout(data.timerId); - data.timerId = null; - } - - function handler(data) { - return function(evt, options) { - options = options || {}; - - // Designer settings - if (designer && evt.type == 'setting') { - if (options.select == 'prev') return previous(data)(); - if (options.select == 'next') return next(data)(); - configure(data); - layout(data); - if (options.select == null) return; - select(data, options.select); - return; - } - - // Swipe event - if (evt.type == 'swipe') { - if (options.direction == 'left') return next(data)(); - if (options.direction == 'right') return previous(data)(); - return; - } - - // Page buttons - if (data.nav.has(evt.target).length) { - change(data, { - index: $(evt.target).index() - }); - } - }; - } - - function change(data, options) { - options = options || {}; - var config = data.config; - var anchors = data.anchors; - - // Set new index - data.previous = data.index; - var index = options.index; - var shift = {}; - if (index < 0) { - index = anchors.length - 1; - if (config.infinite) { - // Shift first slide to the end - shift.x = -data.endX; - shift.from = 0; - shift.to = anchors[0].width; - } - } else if (index >= anchors.length) { - index = 0; - if (config.infinite) { - // Shift last slide to the start - shift.x = anchors[anchors.length - 1].width; - shift.from = -anchors[anchors.length - 1].x; - shift.to = shift.from - shift.x; - } - } - data.index = index; - - // Select page nav - var active = data.nav.children().eq(data.index).addClass('w-active'); - data.nav.children().not(active).removeClass('w-active'); - - // Hide arrows - if (config.hideArrows) { - data.index === anchors.length - 1 ? data.right.hide() : data.right.show(); - data.index === 0 ? data.left.hide() : data.left.show(); - } - - // Get page offset from anchors - var lastOffsetX = data.offsetX || 0; - var offsetX = data.offsetX = -anchors[data.index].x; - var resetConfig = { - x: offsetX, - opacity: 1, - visibility: '' - }; - - // Transition slides - var targets = $(anchors[data.index].els); - var previous = $(anchors[data.previous] && anchors[data.previous].els); - var others = data.slides.not(targets); - var animation = config.animation; - var easing = config.easing; - var duration = Math.round(config.duration); - var vector = options.vector || (data.index > data.previous ? 1 : -1); - var fadeRule = 'opacity ' + duration + 'ms ' + easing; - var slideRule = 'transform ' + duration + 'ms ' + easing; - - // Trigger IX events - if (!designer) { - targets.each(ix.intro); - others.each(ix.outro); - } - - // Set immediately after layout changes (but not during redraw) - if (options.immediate && !redraw) { - tram(targets).set(resetConfig); - resetOthers(); - return; - } - - // Exit early if index is unchanged - if (data.index == data.previous) return; - - // Cross Fade / Out-In - if (animation == 'cross') { - var reduced = Math.round(duration - duration * config.crossOver); - var wait = Math.round(duration - reduced); - fadeRule = 'opacity ' + reduced + 'ms ' + easing; - tram(previous) - .set({ - visibility: '' - }) - .add(fadeRule) - .start({ - opacity: 0 - }); - tram(targets) - .set({ - visibility: '', - x: offsetX, - opacity: 0, - zIndex: data.depth++ - }) - .add(fadeRule) - .wait(wait) - .then({ - opacity: 1 - }) - .then(resetOthers); - return; - } - - // Fade Over - if (animation == 'fade') { - tram(previous) - .set({ - visibility: '' - }) - .stop(); - tram(targets) - .set({ - visibility: '', - x: offsetX, - opacity: 0, - zIndex: data.depth++ - }) - .add(fadeRule) - .start({ - opacity: 1 - }) - .then(resetOthers); - return; - } - - // Slide Over - if (animation == 'over') { - resetConfig = { - x: data.endX - }; - tram(previous) - .set({ - visibility: '' - }) - .stop(); - tram(targets) - .set({ - visibility: '', - zIndex: data.depth++, - x: offsetX + anchors[data.index].width * vector - }) - .add(slideRule) - .start({ - x: offsetX - }) - .then(resetOthers); - return; - } - - // Slide - infinite scroll - if (config.infinite && shift.x) { - tram(data.slides.not(previous)) - .set({ - visibility: '', - x: shift.x - }) - .add(slideRule) - .start({ - x: offsetX - }); - tram(previous) - .set({ - visibility: '', - x: shift.from - }) - .add(slideRule) - .start({ - x: shift.to - }); - data.shifted = previous; - - } else { - if (config.infinite && data.shifted) { - tram(data.shifted).set({ - visibility: '', - x: lastOffsetX - }); - data.shifted = null; - } - - // Slide - basic scroll - tram(data.slides) - .set({ - visibility: '' - }) - .add(slideRule) - .start({ - x: offsetX - }); - } - - // Helper to move others out of view - function resetOthers() { - var targets = $(anchors[data.index].els); - var others = data.slides.not(targets); - if (animation != 'slide') resetConfig.visibility = 'hidden'; - tram(others).set(resetConfig); - } - } - - function render(i, el) { - var data = $.data(el, namespace); - if (maskChanged(data)) return layout(data); - if (designer && slidesChanged(data)) layout(data); - } - - function layout(data) { - // Determine page count from width of slides - var pages = 1; - var offset = 0; - var anchor = 0; - var width = 0; - data.anchors = [{ - els: [], - x: 0, - width: 0 - }]; - data.slides.each(function(i, el) { - if (anchor - offset > data.maskWidth - data.config.edge) { - pages++; - offset += data.maskWidth; - // Store page anchor for transition - data.anchors[pages - 1] = { - els: [], - x: anchor, - width: 0 - }; - } - // Set next anchor using current width + margin - width = $(el).outerWidth(true); - anchor += width; - data.anchors[pages - 1].width += width; - data.anchors[pages - 1].els.push(el); - }); - data.endX = anchor; - - // Build dots if nav exists and needs updating - if (designer) data.pages = null; - if (data.nav.length && data.pages !== pages) { - data.pages = pages; - buildNav(data); - } - - // Make sure index is still within range and call change handler - var index = data.index; - if (index >= pages) index = pages - 1; - change(data, { - immediate: true, - index: index - }); - } - - function buildNav(data) { - var dots = []; - var $dot; - var spacing = data.el.attr('data-nav-spacing'); - if (spacing) spacing = parseFloat(spacing) + 'px'; - for (var i = 0; i < data.pages; i++) { - $dot = $(dot); - if (data.nav.hasClass('w-num')) $dot.text(i + 1); - if (spacing != null) $dot.css({ - 'margin-left': spacing, - 'margin-right': spacing - }); - dots.push($dot); - } - data.nav.empty().append(dots); - } - - function maskChanged(data) { - var maskWidth = data.mask.width(); - if (data.maskWidth !== maskWidth) { - data.maskWidth = maskWidth; - return true; - } - return false; - } - - function slidesChanged(data) { - var slidesWidth = 0; - data.slides.each(function(i, el) { - slidesWidth += $(el).outerWidth(true); - }); - if (data.slidesWidth !== slidesWidth) { - data.slidesWidth = slidesWidth; - return true; - } - return false; - } - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Lightbox component - */ -var lightbox = (function(window, document, $, tram, undefined) { - 'use strict'; - - var isArray = Array.isArray; - var namespace = 'w-lightbox'; - var prefix = namespace + '-'; - var prefixRegex = /(^|\s+)/g; - var matchMedia = window.matchMedia || function(media) { - // IE9 polyfill - return { - matches: window.styleMedia.matchMedium(media) - }; - }; - var pixelRatio = window.devicePixelRatio || 1; - var breakpoint = '(min-width: 1025px)'; - - // Array of objects describing items to be displayed. - var items = []; - - // Index of the currently displayed item. - var currentIndex; - - // Object holding references to jQuery wrapped nodes. - var $refs; - - // Instance of Spinner - var spinner; - - function lightbox(thing, index) { - items = isArray(thing) ? thing : [thing]; - - if (!$refs) { - lightbox.build(); - } - - if (items.length > 1) { - $refs.items = $refs.empty; - - items.forEach(function(item) { - var $thumbnail = dom('thumbnail'); - var $item = dom('item').append($thumbnail); - - $refs.items = $refs.items.add($item); - - loadImage(item.url, function($image) { - if ($image.prop('width') > $image.prop('height')) { - addClass($image, 'wide'); - } else { - addClass($image, 'tall'); - } - $thumbnail.append(addClass($image, 'thumbnail-image')); - }); - }); - - $refs.strip.empty().append($refs.items); - addClass($refs.content, 'group'); - } - - tram( - // Focus the lightbox to receive keyboard events. - removeClass($refs.lightbox, 'hide').focus() - ) - .add('opacity .3s') - .start({ - opacity: 1 - }); - - // Prevent document from scrolling while lightbox is active. - addClass($refs.html, 'noscroll'); - - return lightbox.show(index || 0); - } - - /** - * Creates the DOM structure required by the lightbox. - */ - lightbox.build = function() { - // In case `build` is called more than once. - lightbox.destroy(); - - $refs = { - html: $(document.documentElement), - // Empty jQuery object can be used to build new ones using `.add`. - empty: $() - }; - - $refs.arrowLeft = dom('control left inactive'); - $refs.arrowRight = dom('control right inactive'); - $refs.close = dom('control close'); - $refs.controls = $refs.empty.add($refs.arrowLeft).add($refs.arrowRight).add($refs.close); - - $refs.spinner = dom('spinner'); - $refs.strip = dom('strip'); - - spinner = new Spinner($refs.spinner, prefixed('hide')); - - $refs.content = dom('content') - .append($refs.spinner, $refs.controls); - - $refs.container = dom('container') - .append($refs.content, $refs.strip); - - $refs.lightbox = dom('backdrop hide') - .append($refs.container); - - // We are delegating events for performance reasons and also - // to not have to reattach handlers when images change. - $refs.strip.on('tap', selector('item'), itemTapHandler); - $refs.content - .on('swipe', swipeHandler) - .on('tap', selector('left'), preventDefaultAnd(lightbox.prev)) - .on('tap', selector('right'), preventDefaultAnd(lightbox.next)) - .on('tap', selector('close'), preventDefaultAnd(lightbox.hide)) - .on('tap', selector('image, caption'), toggleControlsOr(lightbox.next)); - $refs.container.on( - 'tap', selector('view, strip'), toggleControlsOr(lightbox.hide) - ) - // Prevent images from being dragged around. - .on('dragstart', selector('img'), preventDefault); - $refs.lightbox - .on('keydown', keyHandler) - // While visible, prevent lightbox from loosing focus to other nodes. - // IE looses focus without letting us know. - .on('focusin', focusThis) - // Unfortunately setTimeout is needed because of a 14 year old - // Firefox bug (https://bugzilla.mozilla.org/show_bug.cgi?id=53579#c4). - .on('blur', function() { - setTimeout(focusThis.bind(this), 0); - }); - - // The `tabindex` attribute is needed to enable non-input elements - // to receive keyboard events. - $('body').append($refs.lightbox.prop('tabIndex', 0)); - - return lightbox; - }; - - /** - * Dispose of DOM nodes created by the lightbox. - */ - lightbox.destroy = function() { - if (!$refs) { - return; - } - - // Event handlers are also removed. - $refs.lightbox.remove(); - $refs = undefined; - }; - - /** - * Show a specific item. - */ - lightbox.show = function(index) { - // Bail if we are already showing this item. - if (index === currentIndex) { - return; - } - - var item = items[index]; - var previousIndex = currentIndex; - currentIndex = index; - spinner.show(); - - // For videos, load an empty SVG with the video dimensions to preserve - // the video’s aspect ratio while being responsive. - var url = item.html && svgDataUri(item.width, item.height) || item.url; - loadImage(url, function($image) { - // Make sure this is the last item requested to be shown since - // images can finish loading in a different order than they were - // requested in. - if (index != currentIndex) { - return; - } - - var $figure = dom('figure', 'figure').append(addClass($image, 'image')); - var $frame = dom('frame').append($figure); - var $newView = dom('view').append($frame); - - if (item.html) { - $figure.append(addClass($(item.html), 'embed')); - } - - if (item.caption) { - $figure.append(dom('caption', 'figcaption').text(item.caption)); - } - - spinner.hide(); - - toggleClass($refs.arrowLeft, 'inactive', index <= 0); - toggleClass($refs.arrowRight, 'inactive', index >= items.length - 1); - - $refs.spinner.before($newView); - - if ($refs.view) { - tram($refs.view) - .add('opacity .3s') - .start({ - opacity: 0 - }) - .then(remover($refs.view)); - - tram($newView) - .add('opacity .3s') - .add('transform .3s') - .set({ - opacity: 0, - x: index > previousIndex ? '80px' : '-80px' - }) - .start({ - opacity: 1, - x: 0 - }); - } - - $refs.view = $newView; - - if ($refs.items) { - // Mark proper thumbnail as active - addClass(removeClass($refs.items, 'active').eq(index), 'active'); - } - }); - - return lightbox; - }; - - /** - * Hides the lightbox. - */ - lightbox.hide = function() { - tram($refs.lightbox) - .add('opacity .3s') - .start({ - opacity: 0 - }) - .then(hideLightbox); - - return lightbox; - }; - - lightbox.prev = function() { - if (currentIndex > 0) { - lightbox.show(currentIndex - 1); - } - }; - - lightbox.next = function() { - if (currentIndex < items.length - 1) { - lightbox.show(currentIndex + 1); - } - }; - - function toggleControlsOr(callback) { - return function(event) { - // We only care about events triggered directly on the bound selectors. - if (this != event.target) { - return; - } - - event.stopPropagation(); - event.preventDefault(); - - if (matchMedia(breakpoint).matches) { - callback(); - } else { - toggleClass($refs.controls, 'visible'); - } - }; - } - - var itemTapHandler = function(event) { - var index = $(this).index(); - - event.preventDefault(); - lightbox.show(index); - }; - - var swipeHandler = function(event, data) { - // Prevent scrolling. - event.preventDefault(); - - if (data.direction == 'left') { - lightbox.next(); - } else if (data.direction == 'right') { - lightbox.prev(); - } - }; - - function preventDefaultAnd(action) { - return function(event) { - // Prevents click events and zooming. - event.preventDefault(); - action(); - }; - } - - var focusThis = function() { - this.focus(); - }; - - function preventDefault(event) { - event.preventDefault(); - } - - function keyHandler(event) { - var keyCode = event.keyCode; - - // [esc] - if (keyCode == 27) { - lightbox.hide(); - } - - // [◀] - else if (keyCode == 37) { - lightbox.prev(); - } - - // [▶] - else if (keyCode == 39) { - lightbox.next(); - } - } - - function hideLightbox() { - removeClass($refs.html, 'noscroll'); - addClass($refs.lightbox, 'hide'); - $refs.strip.empty(); - $refs.view && $refs.view.remove(); - - // Reset some stuff - removeClass($refs.content, 'group'); - removeClass($refs.controls, 'visible'); - addClass($refs.arrowLeft, 'inactive'); - addClass($refs.arrowRight, 'inactive'); - - currentIndex = $refs.view = undefined; - } - - function loadImage(url, callback) { - var $image = dom('img', 'img'); - - $image.one('load', function() { - callback($image); - }); - - // Start loading image. - $image.attr('src', url); - - return $image; - } - - function remover($element) { - return function() { - $element.remove(); - }; - } - - /** - * Spinner - */ - function Spinner($spinner, className, delay) { - this.$element = $spinner; - this.className = className; - this.delay = delay || 200; - this.hide(); - } - - Spinner.prototype.show = function() { - var spinner = this; - - // Bail if we are already showing the spinner. - if (spinner.timeoutId) { - return; - } - - spinner.timeoutId = setTimeout(function() { - spinner.$element.removeClass(spinner.className); - delete spinner.timeoutId; - }, spinner.delay); - }; - - Spinner.prototype.hide = function() { - var spinner = this; - if (spinner.timeoutId) { - clearTimeout(spinner.timeoutId); - delete spinner.timeoutId; - return; - } - - spinner.$element.addClass(spinner.className); - }; - - function prefixed(string, isSelector) { - return string.replace(prefixRegex, (isSelector ? ' .' : ' ') + prefix); - } - - function selector(string) { - return prefixed(string, true); - } - - /** - * jQuery.addClass with auto-prefixing - * @param {jQuery} Element to add class to - * @param {string} Class name that will be prefixed and added to element - * @return {jQuery} - */ - function addClass($element, className) { - return $element.addClass(prefixed(className)); - } - - /** - * jQuery.removeClass with auto-prefixing - * @param {jQuery} Element to remove class from - * @param {string} Class name that will be prefixed and removed from element - * @return {jQuery} - */ - function removeClass($element, className) { - return $element.removeClass(prefixed(className)); - } - - /** - * jQuery.toggleClass with auto-prefixing - * @param {jQuery} Element where class will be toggled - * @param {string} Class name that will be prefixed and toggled - * @param {boolean} Optional boolean that determines if class will be added or removed - * @return {jQuery} - */ - function toggleClass($element, className, shouldAdd) { - return $element.toggleClass(prefixed(className), shouldAdd); - } - - /** - * Create a new DOM element wrapped in a jQuery object, - * decorated with our custom methods. - * @param {string} className - * @param {string} [tag] - * @return {jQuery} - */ - function dom(className, tag) { - return addClass($(document.createElement(tag || 'div')), className); - } - - function isObject(value) { - return typeof value == 'object' && null != value && !isArray(value); - } - - function svgDataUri(width, height) { - var svg = ''; - return 'data:image/svg+xml;charset=utf-8,' + encodeURI(svg); - } - - // Compute some dimensions manually for iOS, because of buggy support for VH. - // Also, Android built-in browser does not support viewport units. - (function() { - var ua = window.navigator.userAgent; - var iOS = /(iPhone|iPod|iPad).+AppleWebKit/i.test(ua); - var android = ua.indexOf('Android ') > -1 && ua.indexOf('Chrome') == -1; - - if (!iOS && !android) { - return; - } - - var styleNode = document.createElement('style'); - document.head.appendChild(styleNode); - window.addEventListener('orientationchange', refresh, true); - - function refresh() { - var vh = window.innerHeight; - var vw = window.innerWidth; - var content = - '.w-lightbox-content, .w-lightbox-view, .w-lightbox-view:before {' + - 'height:' + vh + 'px' + - '}' + - '.w-lightbox-view {' + - 'width:' + vw + 'px' + - '}' + - '.w-lightbox-group, .w-lightbox-group .w-lightbox-view, .w-lightbox-group .w-lightbox-view:before {' + - 'height:' + (0.86 * vh) + 'px' + - '}' + - '.w-lightbox-image {' + - 'max-width:' + vw + 'px;' + - 'max-height:' + vh + 'px' + - '}' + - '.w-lightbox-group .w-lightbox-image {' + - 'max-height:' + (0.86 * vh) + 'px' + - '}' + - '.w-lightbox-strip {' + - 'padding: 0 ' + (0.01 * vh) + 'px' + - '}' + - '.w-lightbox-item {' + - 'width:' + (0.1 * vh) + 'px;' + - 'padding:' + (0.02 * vh) + 'px ' + (0.01 * vh) + 'px' + - '}' + - '.w-lightbox-thumbnail {' + - 'height:' + (0.1 * vh) + 'px' + - '}'; - - styleNode.textContent = content; - } - - refresh(); - })(); - - return lightbox; -})(window, document, jQuery, window.tram); - -Webflow.define('lightbox', function($, _) { - 'use strict'; - - var api = {}; - var $doc = $(document); - var $body; - var $lightboxes; - var designer; - var inApp = Webflow.env(); - var namespace = '.w-lightbox'; - var groups; - - // ----------------------------------- - // Module methods - - api.ready = api.design = api.preview = init; - - // ----------------------------------- - // Private methods - - function init() { - designer = inApp && Webflow.env('design'); - $body = $(document.body); - - // Reset Lightbox - lightbox.destroy(); - - // Reset groups - groups = {}; - - // Find all instances on the page - $lightboxes = $doc.find(namespace); - $lightboxes.each(build); - } - - function build(i, el) { - var $el = $(el); - - // Store state in data - var data = $.data(el, namespace); - if (!data) data = $.data(el, namespace, { - el: $el, - mode: 'images', - images: [], - embed: '' - }); - - // Remove old events - data.el.off(namespace); - - // Set config from json script tag - configure(data); - - // Add events based on mode - if (designer) { - data.el.on('setting' + namespace, configure.bind(null, data)); - } else { - data.el - .on('tap' + namespace, tapHandler(data)) - // Prevent page scrolling to top when clicking on lightbox triggers. - .on('click' + namespace, function(e) { - e.preventDefault(); - }); - } - } - - function configure(data) { - var json = data.el.children('.w-json').html(); - var groupId, group; - - if (!json) { - data.images = []; - return; - } - - try { - json = JSON.parse(json); - data.mode = json.mode; - - if (json.mode == 'video') { - data.embed = json.embed; - } else { - groupId = json.groupId; - if (groupId) { - group = groups[groupId]; - if (!group) { - group = groups[groupId] = []; - } - - data.images = group; - - if (json.images.length) { - data.index = group.length; - group.push.apply(group, json.images); - } - } else { - data.images = json.images; - } - } - } catch (e) { - console.error('Malformed lightbox JSON configuration.', e.message); - } - } - - function tapHandler(data) { - return function() { - if (data.mode == 'video') { - data.embed && lightbox(data.embed); - } else { - data.images.length && lightbox(data.images, data.index || 0); - } - }; - } - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Navbar component - */ -Webflow.define('navbar', function($, _) { - 'use strict'; - - var api = {}; - var tram = window.tram; - var $win = $(window); - var $doc = $(document); - var $body; - var $navbars; - var designer; - var inApp = Webflow.env(); - var overlay = '
'; - var namespace = '.w-nav'; - var buttonOpen = 'w--open'; - var menuOpen = 'w--nav-menu-open'; - var linkOpen = 'w--nav-link-open'; - var ix = Webflow.ixEvents(); - - // ----------------------------------- - // Module methods - - api.ready = api.design = api.preview = init; - api.destroy = removeListeners; - - // ----------------------------------- - // Private methods - - function init() { - designer = inApp && Webflow.env('design'); - $body = $(document.body); - - // Find all instances on the page - $navbars = $doc.find(namespace); - if (!$navbars.length) return; - $navbars.each(build); - - // Wire events - removeListeners(); - addListeners(); - } - - function removeListeners() { - Webflow.resize.off(resizeAll); - } - - function addListeners() { - Webflow.resize.on(resizeAll); - } - - function resizeAll() { - $navbars.each(resize); - } - - function build(i, el) { - var $el = $(el); - - // Store state in data - var data = $.data(el, namespace); - if (!data) data = $.data(el, namespace, { - open: false, - el: $el, - config: {} - }); - data.menu = $el.find('.w-nav-menu'); - data.links = data.menu.find('.w-nav-link'); - data.dropdowns = data.menu.find('.w-dropdown'); - data.button = $el.find('.w-nav-button'); - data.container = $el.find('.w-container'); - data.outside = outside(data); - - // Remove old events - data.el.off(namespace); - data.button.off(namespace); - data.menu.off(namespace); - - // Set config from data attributes - configure(data); - - // Add events based on mode - if (designer) { - removeOverlay(data); - data.el.on('setting' + namespace, handler(data)); - } else { - addOverlay(data); - data.button.on('tap' + namespace, toggle(data)); - data.menu.on('tap' + namespace, 'a', navigate(data)); - } - - // Trigger initial resize - resize(i, el); - } - - function removeOverlay(data) { - if (!data.overlay) return; - close(data, true); - data.overlay.remove(); - data.overlay = null; - } - - function addOverlay(data) { - if (data.overlay) return; - data.overlay = $(overlay).appendTo(data.el); - data.parent = data.menu.parent(); - close(data, true); - } - - function configure(data) { - var config = {}; - var old = data.config || {}; - - // Set config options from data attributes - var animation = config.animation = data.el.attr('data-animation') || 'default'; - config.animOver = /^over/.test(animation); - config.animDirect = /left$/.test(animation) ? -1 : 1; - - // Re-open menu if the animation type changed - if (old.animation != animation) { - data.open && _.defer(reopen, data); - } - - config.easing = data.el.attr('data-easing') || 'ease'; - config.easing2 = data.el.attr('data-easing2') || 'ease'; - - var duration = data.el.attr('data-duration'); - config.duration = duration != null ? +duration : 400; - - config.docHeight = data.el.attr('data-doc-height'); - - // Store config in data - data.config = config; - } - - function handler(data) { - return function(evt, options) { - options = options || {}; - var winWidth = $win.width(); - configure(data); - options.open === true && open(data, true); - options.open === false && close(data, true); - // Reopen if media query changed after setting - data.open && _.defer(function() { - if (winWidth != $win.width()) reopen(data); - }); - }; - } - - function closeEach(i, el) { - var data = $.data(el, namespace); - data.open && close(data); - } - - function reopen(data) { - if (!data.open) return; - close(data, true); - open(data, true); - } - - function toggle(data) { - return _.debounce(function(evt) { - data.open ? close(data) : open(data); - }); - } - - function navigate(data) { - return function(evt) { - var link = $(this); - var href = link.attr('href'); - - // Close when navigating to an in-page anchor - if (href && href.indexOf('#') === 0 && data.open) { - // Avoid empty hash links - if (href.length === 1) evt.preventDefault(); - close(data); - } - }; - } - - function outside(data) { - // Unbind previous tap handler if it exists - if (data.outside) $doc.off('tap' + namespace, data.outside); - - // Close menu when tapped outside - return _.debounce(function(evt) { - if (!data.open) return; - var menu = $(evt.target).closest('.w-nav-menu'); - if (!data.menu.is(menu)) { - close(data); - } - }); - } - - function resize(i, el) { - var data = $.data(el, namespace); - // Check for collapsed state based on button display - var collapsed = data.collapsed = data.button.css('display') != 'none'; - // Close menu if button is no longer visible (and not in designer) - if (data.open && !collapsed && !designer) close(data, true); - // Set max-width of links + dropdowns to match container - if (data.container.length) { - var updateEachMax = updateMax(data); - data.links.each(updateEachMax); - data.dropdowns.each(updateEachMax); - } - // If currently open, update height to match body - if (data.open) { - setOverlayHeight(data); - } - } - - var maxWidth = 'max-width'; - - function updateMax(data) { - // Set max-width of each element to match container - var containMax = data.container.css(maxWidth); - if (containMax == 'none') containMax = ''; - return function(i, link) { - link = $(link); - link.css(maxWidth, ''); - // Don't set the max-width if an upstream value exists - if (link.css(maxWidth) == 'none') link.css(maxWidth, containMax); - }; - } - - function open(data, immediate) { - if (data.open) return; - data.open = true; - data.menu.addClass(menuOpen); - data.links.addClass(linkOpen); - data.button.addClass(buttonOpen); - var config = data.config; - var animation = config.animation; - if (animation == 'none' || !tram.support.transform) immediate = true; - var bodyHeight = setOverlayHeight(data); - var menuHeight = data.menu.outerHeight(true); - var menuWidth = data.menu.outerWidth(true); - var navHeight = data.el.height(); - var navbarEl = data.el[0]; - resize(0, navbarEl); - ix.intro(0, navbarEl); - - // Listen for tap outside events - if (!designer) $doc.on('tap' + namespace, data.outside); - - // No transition for immediate - if (immediate) return; - - var transConfig = 'transform ' + config.duration + 'ms ' + config.easing; - - // Add menu to overlay - if (data.overlay) { - data.overlay.show().append(data.menu); - } - - // Over left/right - if (config.animOver) { - tram(data.menu) - .add(transConfig) - .set({ - x: config.animDirect * menuWidth, - height: bodyHeight - }).start({ - x: 0 - }); - data.overlay && data.overlay.width(menuWidth); - return; - } - - // Drop Down - var offsetY = navHeight + menuHeight; - tram(data.menu) - .add(transConfig) - .set({ - y: -offsetY - }).start({ - y: 0 - }); - } - - function setOverlayHeight(data) { - var config = data.config; - var bodyHeight = config.docHeight ? $doc.height() : $body.height(); - if (config.animOver) { - data.menu.height(bodyHeight); - } else if (data.el.css('position') != 'fixed') { - bodyHeight -= data.el.height(); - } - data.overlay && data.overlay.height(bodyHeight); - return bodyHeight; - } - - function close(data, immediate) { - if (!data.open) return; - data.open = false; - data.button.removeClass(buttonOpen); - var config = data.config; - if (config.animation == 'none' || !tram.support.transform) immediate = true; - var animation = config.animation; - ix.outro(0, data.el[0]); - - // Stop listening for tap outside events - $doc.off('tap' + namespace, data.outside); - - if (immediate) { - tram(data.menu).stop(); - complete(); - return; - } - - var transConfig = 'transform ' + config.duration + 'ms ' + config.easing2; - var menuHeight = data.menu.outerHeight(true); - var menuWidth = data.menu.outerWidth(true); - var navHeight = data.el.height(); - - // Over left/right - if (config.animOver) { - tram(data.menu) - .add(transConfig) - .start({ - x: menuWidth * config.animDirect - }).then(complete); - return; - } - - // Drop Down - var offsetY = navHeight + menuHeight; - tram(data.menu) - .add(transConfig) - .start({ - y: -offsetY - }).then(complete); - - function complete() { - data.menu.height(''); - tram(data.menu).set({ - x: 0, - y: 0 - }); - data.menu.removeClass(menuOpen); - data.links.removeClass(linkOpen); - if (data.overlay && data.overlay.children().length) { - // Move menu back to parent - data.menu.appendTo(data.parent); - data.overlay.attr('style', '').hide(); - } - - // Trigger event so other components can hook in (dropdown) - data.el.triggerHandler('w-close'); - } - } - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Dropdown component - */ -Webflow.define('dropdown', function($, _) { - 'use strict'; - - var api = {}; - var tram = window.tram; - var $doc = $(document); - var $dropdowns; - var designer; - var inApp = Webflow.env(); - var namespace = '.w-dropdown'; - var stateOpen = 'w--open'; - var closeEvent = 'w-close' + namespace; - var ix = Webflow.ixEvents(); - - // ----------------------------------- - // Module methods - - api.ready = api.design = api.preview = init; - - // ----------------------------------- - // Private methods - - function init() { - designer = inApp && Webflow.env('design'); - - // Find all instances on the page - $dropdowns = $doc.find(namespace); - $dropdowns.each(build); - } - - function build(i, el) { - var $el = $(el); - - // Store state in data - var data = $.data(el, namespace); - if (!data) data = $.data(el, namespace, { - open: false, - el: $el, - config: {} - }); - data.list = $el.children('.w-dropdown-list'); - data.toggle = $el.children('.w-dropdown-toggle'); - data.links = data.list.children('.w-dropdown-link'); - data.outside = outside(data); - data.complete = complete(data); - - // Remove old events - $el.off(namespace); - data.toggle.off(namespace); - - // Set config from data attributes - configure(data); - - if (data.nav) data.nav.off(namespace); - data.nav = $el.closest('.w-nav'); - data.nav.on(closeEvent, handler(data)); - - // Add events based on mode - if (designer) { - $el.on('setting' + namespace, handler(data)); - } else { - data.toggle.on('tap' + namespace, toggle(data)); - $el.on(closeEvent, handler(data)); - // Close in preview mode - inApp && close(data); - } - } - - function configure(data) { - data.config = { - hover: +data.el.attr('data-hover'), - delay: +data.el.attr('data-delay') || 0 - }; - } - - function handler(data) { - return function(evt, options) { - options = options || {}; - - if (evt.type == 'w-close') { - return close(data); - } - - if (evt.type == 'setting') { - configure(data); - options.open === true && open(data, true); - options.open === false && close(data, true); - return; - } - }; - } - - function toggle(data) { - return _.debounce(function(evt) { - data.open ? close(data) : open(data); - }); - } - - function open(data, immediate) { - if (data.open) return; - closeOthers(data); - data.open = true; - data.list.addClass(stateOpen); - data.toggle.addClass(stateOpen); - ix.intro(0, data.el[0]); - - // Listen for tap outside events - if (!designer) $doc.on('tap' + namespace, data.outside); - - // Clear previous delay - window.clearTimeout(data.delayId); - } - - function close(data, immediate) { - if (!data.open) return; - data.open = false; - var config = data.config; - ix.outro(0, data.el[0]); - - // Stop listening for tap outside events - $doc.off('tap' + namespace, data.outside); - - // Clear previous delay - window.clearTimeout(data.delayId); - - // Skip delay during immediate - if (!config.delay || immediate) return data.complete(); - - // Optionally wait for delay before close - data.delayId = window.setTimeout(data.complete, config.delay); - } - - function closeOthers(data) { - var self = data.el[0]; - $dropdowns.each(function(i, other) { - var $other = $(other); - if ($other.is(self) || $other.has(self).length) return; - $other.triggerHandler(closeEvent); - }); - } - - function outside(data) { - // Unbind previous tap handler if it exists - if (data.outside) $doc.off('tap' + namespace, data.outside); - - // Close menu when tapped outside - return _.debounce(function(evt) { - if (!data.open) return; - var $target = $(evt.target); - if ($target.closest('.w-dropdown-toggle').length) return; - if (!data.el.is($target.closest(namespace))) { - close(data); - } - }); - } - - function complete(data) { - return function() { - data.list.removeClass(stateOpen); - data.toggle.removeClass(stateOpen); - }; - } - - // Export module - return api; -}); -/** - * ---------------------------------------------------------------------- - * Webflow: Tabs component - */ -Webflow.define('tabs', function($, _) { - 'use strict'; - - var api = {}; - var tram = window.tram; - var $win = $(window); - var $doc = $(document); - var $tabs; - var design; - var env = Webflow.env; - var safari = env.safari; - var inApp = env(); - var tabAttr = 'data-w-tab'; - var namespace = '.w-tabs'; - var linkCurrent = 'w--current'; - var tabActive = 'w--tab-active'; - var ix = Webflow.ixEvents(); - - // ----------------------------------- - // Module methods - - api.ready = api.design = api.preview = init; - - // ----------------------------------- - // Private methods - - function init() { - design = inApp && Webflow.env('design'); - - // Find all instances on the page - $tabs = $doc.find(namespace); - if (!$tabs.length) return; - $tabs.each(build); - } - - function build(i, el) { - var $el = $(el); - - // Store state in data - var data = $.data(el, namespace); - if (!data) data = $.data(el, namespace, { - el: $el, - config: {} - }); - data.current = null; - data.menu = $el.children('.w-tab-menu'); - data.links = data.menu.children('.w-tab-link'); - data.content = $el.children('.w-tab-content'); - data.panes = data.content.children('.w-tab-pane'); - - // Remove old events - data.el.off(namespace); - data.links.off(namespace); - - // Set config from data attributes - configure(data); - - // Wire up events when not in design mode - if (!design) { - data.links.on('click' + namespace, linkSelect(data)); - - // Trigger first intro event from current tab - var $link = data.links.filter('.' + linkCurrent); - var tab = $link.attr(tabAttr); - tab && changeTab(data, { - tab: tab, - immediate: true - }); - } - } - - function configure(data) { - var config = {}; - var old = data.config || {}; - - // Set config options from data attributes - config.easing = data.el.attr('data-easing') || 'ease'; - - var intro = +data.el.attr('data-duration-in'); - intro = config.intro = intro === intro ? intro : 0; - - var outro = +data.el.attr('data-duration-out'); - outro = config.outro = outro === outro ? outro : 0; - - config.immediate = !intro && !outro; - - // Store config in data - data.config = config; - } - - function linkSelect(data) { - return function(evt) { - var tab = evt.currentTarget.getAttribute(tabAttr); - tab && changeTab(data, { - tab: tab - }); - }; - } - - function changeTab(data, options) { - options = options || {}; - - var config = data.config; - var easing = config.easing; - var tab = options.tab; - - // Don't select the same tab twice - if (tab === data.current) return; - data.current = tab; - - // Select the current link - data.links.each(function(i, el) { - var $el = $(el); - if (el.getAttribute(tabAttr) === tab) $el.addClass(linkCurrent).each(ix.intro); - else if ($el.hasClass(linkCurrent)) $el.removeClass(linkCurrent).each(ix.outro); - }); - - // Find the new tab panes and keep track of previous - var targets = []; - var previous = []; - data.panes.each(function(i, el) { - var $el = $(el); - if (el.getAttribute(tabAttr) === tab) { - targets.push(el); - } else if ($el.hasClass(tabActive)) { - previous.push(el); - } - }); - - var $targets = $(targets); - var $previous = $(previous); - - // Switch tabs immediately and bypass transitions - if (options.immediate || config.immediate) { - $targets.addClass(tabActive).each(ix.intro); - $previous.removeClass(tabActive); - Webflow.redraw.up(); - return; - } - - // Fade out the currently active tab before intro - if ($previous.length && config.outro) { - $previous.each(ix.outro); - tram($previous) - .add('opacity ' + config.outro + 'ms ' + easing, { - fallback: safari - }) - .start({ - opacity: 0 - }) - .then(intro); - } else { - // Skip the outro and play intro - intro(); - } - - // Fade in the new target - function intro() { - // Clear previous active class + inline style - $previous.removeClass(tabActive).removeAttr('style'); - - // Add active class to new target - $targets.addClass(tabActive).each(ix.intro); - Webflow.redraw.up(); - - // Set opacity immediately if intro is zero - if (!config.intro) return tram($targets).set({ - opacity: 1 - }); - - // Otherwise fade in opacity - tram($targets) - .set({ - opacity: 0 - }) - .redraw() - .add('opacity ' + config.intro + 'ms ' + easing, { - fallback: safari - }) - .start({ - opacity: 1 - }); - } - } - - // Export module - return api; -}); \ No newline at end of file -- cgit v1.2.3