/* ---------------------------------------------------------- * Plugins * ---------------------------------------------------------- */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.window = global.window || {})); }(this, (function (exports) { 'use strict'; function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } /*! * GSAP 3.11.3 * https://greensock.com * * @license Copyright 2008-2022, GreenSock. All rights reserved. * Subject to the terms at https://greensock.com/standard-license or for * Club GreenSock members, the agreement issued with that membership. * @author: Jack Doyle, jack@greensock.com */ var _config = { autoSleep: 120, force3D: "auto", nullTargetWarn: 1, units: { lineHeight: "" } }, _defaults = { duration: .5, overwrite: false, delay: 0 }, _suppressOverwrites, _reverting, _context, _bigNum = 1e8, _tinyNum = 1 / _bigNum, _2PI = Math.PI * 2, _HALF_PI = _2PI / 4, _gsID = 0, _sqrt = Math.sqrt, _cos = Math.cos, _sin = Math.sin, _isString = function _isString(value) { return typeof value === "string"; }, _isFunction = function _isFunction(value) { return typeof value === "function"; }, _isNumber = function _isNumber(value) { return typeof value === "number"; }, _isUndefined = function _isUndefined(value) { return typeof value === "undefined"; }, _isObject = function _isObject(value) { return typeof value === "object"; }, _isNotFalse = function _isNotFalse(value) { return value !== false; }, _windowExists = function _windowExists() { return typeof window !== "undefined"; }, _isFuncOrString = function _isFuncOrString(value) { return _isFunction(value) || _isString(value); }, _isTypedArray = typeof ArrayBuffer === "function" && ArrayBuffer.isView || function () {}, _isArray = Array.isArray, _strictNumExp = /(?:-?\.?\d|\.)+/gi, _numExp = /[-+=.]*\d+[.e\-+]*\d*[e\-+]*\d*/g, _numWithUnitExp = /[-+=.]*\d+[.e-]*\d*[a-z%]*/g, _complexStringNumExp = /[-+=.]*\d+\.?\d*(?:e-|e\+)?\d*/gi, _relExp = /[+-]=-?[.\d]+/, _delimitedValueExp = /[^,'"\[\]\s]+/gi, _unitExp = /^[+\-=e\s\d]*\d+[.\d]*([a-z]*|%)\s*$/i, _globalTimeline, _win, _coreInitted, _doc, _globals = {}, _installScope = {}, _coreReady, _install = function _install(scope) { return (_installScope = _merge(scope, _globals)) && gsap; }, _missingPlugin = function _missingPlugin(property, value) { return console.warn("Invalid property", property, "set to", value, "Missing plugin? gsap.registerPlugin()"); }, _warn = function _warn(message, suppress) { return !suppress && console.warn(message); }, _addGlobal = function _addGlobal(name, obj) { return name && (_globals[name] = obj) && _installScope && (_installScope[name] = obj) || _globals; }, _emptyFunc = function _emptyFunc() { return 0; }, _startAtRevertConfig = { suppressEvents: true, isStart: true, kill: false }, _revertConfigNoKill = { suppressEvents: true, kill: false }, _revertConfig = { suppressEvents: true }, _reservedProps = {}, _lazyTweens = [], _lazyLookup = {}, _lastRenderedFrame, _plugins = {}, _effects = {}, _nextGCFrame = 30, _harnessPlugins = [], _callbackNames = "", _harness = function _harness(targets) { var target = targets[0], harnessPlugin, i; _isObject(target) || _isFunction(target) || (targets = [targets]); if (!(harnessPlugin = (target._gsap || {}).harness)) { i = _harnessPlugins.length; while (i-- && !_harnessPlugins[i].targetTest(target)) {} harnessPlugin = _harnessPlugins[i]; } i = targets.length; while (i--) { targets[i] && (targets[i]._gsap || (targets[i]._gsap = new GSCache(targets[i], harnessPlugin))) || targets.splice(i, 1); } return targets; }, _getCache = function _getCache(target) { return target._gsap || _harness(toArray(target))[0]._gsap; }, _getProperty = function _getProperty(target, property, v) { return (v = target[property]) && _isFunction(v) ? target[property]() : _isUndefined(v) && target.getAttribute && target.getAttribute(property) || v; }, _forEachName = function _forEachName(names, func) { return (names = names.split(",")).forEach(func) || names; }, _round = function _round(value) { return Math.round(value * 100000) / 100000 || 0; }, _roundPrecise = function _roundPrecise(value) { return Math.round(value * 10000000) / 10000000 || 0; }, _parseRelative = function _parseRelative(start, value) { var operator = value.charAt(0), end = parseFloat(value.substr(2)); start = parseFloat(start); return operator === "+" ? start + end : operator === "-" ? start - end : operator === "*" ? start * end : start / end; }, _arrayContainsAny = function _arrayContainsAny(toSearch, toFind) { var l = toFind.length, i = 0; for (; toSearch.indexOf(toFind[i]) < 0 && ++i < l;) {} return i < l; }, _lazyRender = function _lazyRender() { var l = _lazyTweens.length, a = _lazyTweens.slice(0), i, tween; _lazyLookup = {}; _lazyTweens.length = 0; for (i = 0; i < l; i++) { tween = a[i]; tween && tween._lazy && (tween.render(tween._lazy[0], tween._lazy[1], true)._lazy = 0); } }, _lazySafeRender = function _lazySafeRender(animation, time, suppressEvents, force) { _lazyTweens.length && _lazyRender(); animation.render(time, suppressEvents, force || _reverting && time < 0 && (animation._initted || animation._startAt)); _lazyTweens.length && _lazyRender(); }, _numericIfPossible = function _numericIfPossible(value) { var n = parseFloat(value); return (n || n === 0) && (value + "").match(_delimitedValueExp).length < 2 ? n : _isString(value) ? value.trim() : value; }, _passThrough = function _passThrough(p) { return p; }, _setDefaults = function _setDefaults(obj, defaults) { for (var p in defaults) { p in obj || (obj[p] = defaults[p]); } return obj; }, _setKeyframeDefaults = function _setKeyframeDefaults(excludeDuration) { return function (obj, defaults) { for (var p in defaults) { p in obj || p === "duration" && excludeDuration || p === "ease" || (obj[p] = defaults[p]); } }; }, _merge = function _merge(base, toMerge) { for (var p in toMerge) { base[p] = toMerge[p]; } return base; }, _mergeDeep = function _mergeDeep(base, toMerge) { for (var p in toMerge) { p !== "__proto__" && p !== "constructor" && p !== "prototype" && (base[p] = _isObject(toMerge[p]) ? _mergeDeep(base[p] || (base[p] = {}), toMerge[p]) : toMerge[p]); } return base; }, _copyExcluding = function _copyExcluding(obj, excluding) { var copy = {}, p; for (p in obj) { p in excluding || (copy[p] = obj[p]); } return copy; }, _inheritDefaults = function _inheritDefaults(vars) { var parent = vars.parent || _globalTimeline, func = vars.keyframes ? _setKeyframeDefaults(_isArray(vars.keyframes)) : _setDefaults; if (_isNotFalse(vars.inherit)) { while (parent) { func(vars, parent.vars.defaults); parent = parent.parent || parent._dp; } } return vars; }, _arraysMatch = function _arraysMatch(a1, a2) { var i = a1.length, match = i === a2.length; while (match && i-- && a1[i] === a2[i]) {} return i < 0; }, _addLinkedListItem = function _addLinkedListItem(parent, child, firstProp, lastProp, sortBy) { if (firstProp === void 0) { firstProp = "_first"; } if (lastProp === void 0) { lastProp = "_last"; } var prev = parent[lastProp], t; if (sortBy) { t = child[sortBy]; while (prev && prev[sortBy] > t) { prev = prev._prev; } } if (prev) { child._next = prev._next; prev._next = child; } else { child._next = parent[firstProp]; parent[firstProp] = child; } if (child._next) { child._next._prev = child; } else { parent[lastProp] = child; } child._prev = prev; child.parent = child._dp = parent; return child; }, _removeLinkedListItem = function _removeLinkedListItem(parent, child, firstProp, lastProp) { if (firstProp === void 0) { firstProp = "_first"; } if (lastProp === void 0) { lastProp = "_last"; } var prev = child._prev, next = child._next; if (prev) { prev._next = next; } else if (parent[firstProp] === child) { parent[firstProp] = next; } if (next) { next._prev = prev; } else if (parent[lastProp] === child) { parent[lastProp] = prev; } child._next = child._prev = child.parent = null; }, _removeFromParent = function _removeFromParent(child, onlyIfParentHasAutoRemove) { child.parent && (!onlyIfParentHasAutoRemove || child.parent.autoRemoveChildren) && child.parent.remove(child); child._act = 0; }, _uncache = function _uncache(animation, child) { if (animation && (!child || child._end > animation._dur || child._start < 0)) { var a = animation; while (a) { a._dirty = 1; a = a.parent; } } return animation; }, _recacheAncestors = function _recacheAncestors(animation) { var parent = animation.parent; while (parent && parent.parent) { parent._dirty = 1; parent.totalDuration(); parent = parent.parent; } return animation; }, _rewindStartAt = function _rewindStartAt(tween, totalTime, suppressEvents, force) { return tween._startAt && (_reverting ? tween._startAt.revert(_revertConfigNoKill) : tween.vars.immediateRender && !tween.vars.autoRevert || tween._startAt.render(totalTime, true, force)); }, _hasNoPausedAncestors = function _hasNoPausedAncestors(animation) { return !animation || animation._ts && _hasNoPausedAncestors(animation.parent); }, _elapsedCycleDuration = function _elapsedCycleDuration(animation) { return animation._repeat ? _animationCycle(animation._tTime, animation = animation.duration() + animation._rDelay) * animation : 0; }, _animationCycle = function _animationCycle(tTime, cycleDuration) { var whole = Math.floor(tTime /= cycleDuration); return tTime && whole === tTime ? whole - 1 : whole; }, _parentToChildTotalTime = function _parentToChildTotalTime(parentTime, child) { return (parentTime - child._start) * child._ts + (child._ts >= 0 ? 0 : child._dirty ? child.totalDuration() : child._tDur); }, _setEnd = function _setEnd(animation) { return animation._end = _roundPrecise(animation._start + (animation._tDur / Math.abs(animation._ts || animation._rts || _tinyNum) || 0)); }, _alignPlayhead = function _alignPlayhead(animation, totalTime) { var parent = animation._dp; if (parent && parent.smoothChildTiming && animation._ts) { animation._start = _roundPrecise(parent._time - (animation._ts > 0 ? totalTime / animation._ts : ((animation._dirty ? animation.totalDuration() : animation._tDur) - totalTime) / -animation._ts)); _setEnd(animation); parent._dirty || _uncache(parent, animation); } return animation; }, _postAddChecks = function _postAddChecks(timeline, child) { var t; if (child._time || child._initted && !child._dur) { t = _parentToChildTotalTime(timeline.rawTime(), child); if (!child._dur || _clamp(0, child.totalDuration(), t) - child._tTime > _tinyNum) { child.render(t, true); } } if (_uncache(timeline, child)._dp && timeline._initted && timeline._time >= timeline._dur && timeline._ts) { if (timeline._dur < timeline.duration()) { t = timeline; while (t._dp) { t.rawTime() >= 0 && t.totalTime(t._tTime); t = t._dp; } } timeline._zTime = -_tinyNum; } }, _addToTimeline = function _addToTimeline(timeline, child, position, skipChecks) { child.parent && _removeFromParent(child); child._start = _roundPrecise((_isNumber(position) ? position : position || timeline !== _globalTimeline ? _parsePosition(timeline, position, child) : timeline._time) + child._delay); child._end = _roundPrecise(child._start + (child.totalDuration() / Math.abs(child.timeScale()) || 0)); _addLinkedListItem(timeline, child, "_first", "_last", timeline._sort ? "_start" : 0); _isFromOrFromStart(child) || (timeline._recent = child); skipChecks || _postAddChecks(timeline, child); timeline._ts < 0 && _alignPlayhead(timeline, timeline._tTime); return timeline; }, _scrollTrigger = function _scrollTrigger(animation, trigger) { return (_globals.ScrollTrigger || _missingPlugin("scrollTrigger", trigger)) && _globals.ScrollTrigger.create(trigger, animation); }, _attemptInitTween = function _attemptInitTween(tween, time, force, suppressEvents, tTime) { _initTween(tween, time, tTime); if (!tween._initted) { return 1; } if (!force && tween._pt && !_reverting && (tween._dur && tween.vars.lazy !== false || !tween._dur && tween.vars.lazy) && _lastRenderedFrame !== _ticker.frame) { _lazyTweens.push(tween); tween._lazy = [tTime, suppressEvents]; return 1; } }, _parentPlayheadIsBeforeStart = function _parentPlayheadIsBeforeStart(_ref) { var parent = _ref.parent; return parent && parent._ts && parent._initted && !parent._lock && (parent.rawTime() < 0 || _parentPlayheadIsBeforeStart(parent)); }, _isFromOrFromStart = function _isFromOrFromStart(_ref2) { var data = _ref2.data; return data === "isFromStart" || data === "isStart"; }, _renderZeroDurationTween = function _renderZeroDurationTween(tween, totalTime, suppressEvents, force) { var prevRatio = tween.ratio, ratio = totalTime < 0 || !totalTime && (!tween._start && _parentPlayheadIsBeforeStart(tween) && !(!tween._initted && _isFromOrFromStart(tween)) || (tween._ts < 0 || tween._dp._ts < 0) && !_isFromOrFromStart(tween)) ? 0 : 1, repeatDelay = tween._rDelay, tTime = 0, pt, iteration, prevIteration; if (repeatDelay && tween._repeat) { tTime = _clamp(0, tween._tDur, totalTime); iteration = _animationCycle(tTime, repeatDelay); tween._yoyo && iteration & 1 && (ratio = 1 - ratio); if (iteration !== _animationCycle(tween._tTime, repeatDelay)) { prevRatio = 1 - ratio; tween.vars.repeatRefresh && tween._initted && tween.invalidate(); } } if (ratio !== prevRatio || _reverting || force || tween._zTime === _tinyNum || !totalTime && tween._zTime) { if (!tween._initted && _attemptInitTween(tween, totalTime, force, suppressEvents, tTime)) { return; } prevIteration = tween._zTime; tween._zTime = totalTime || (suppressEvents ? _tinyNum : 0); suppressEvents || (suppressEvents = totalTime && !prevIteration); tween.ratio = ratio; tween._from && (ratio = 1 - ratio); tween._time = 0; tween._tTime = tTime; pt = tween._pt; while (pt) { pt.r(ratio, pt.d); pt = pt._next; } totalTime < 0 && _rewindStartAt(tween, totalTime, suppressEvents, true); tween._onUpdate && !suppressEvents && _callback(tween, "onUpdate"); tTime && tween._repeat && !suppressEvents && tween.parent && _callback(tween, "onRepeat"); if ((totalTime >= tween._tDur || totalTime < 0) && tween.ratio === ratio) { ratio && _removeFromParent(tween, 1); if (!suppressEvents && !_reverting) { _callback(tween, ratio ? "onComplete" : "onReverseComplete", true); tween._prom && tween._prom(); } } } else if (!tween._zTime) { tween._zTime = totalTime; } }, _findNextPauseTween = function _findNextPauseTween(animation, prevTime, time) { var child; if (time > prevTime) { child = animation._first; while (child && child._start <= time) { if (child.data === "isPause" && child._start > prevTime) { return child; } child = child._next; } } else { child = animation._last; while (child && child._start >= time) { if (child.data === "isPause" && child._start < prevTime) { return child; } child = child._prev; } } }, _setDuration = function _setDuration(animation, duration, skipUncache, leavePlayhead) { var repeat = animation._repeat, dur = _roundPrecise(duration) || 0, totalProgress = animation._tTime / animation._tDur; totalProgress && !leavePlayhead && (animation._time *= dur / animation._dur); animation._dur = dur; animation._tDur = !repeat ? dur : repeat < 0 ? 1e10 : _roundPrecise(dur * (repeat + 1) + animation._rDelay * repeat); totalProgress > 0 && !leavePlayhead && _alignPlayhead(animation, animation._tTime = animation._tDur * totalProgress); animation.parent && _setEnd(animation); skipUncache || _uncache(animation.parent, animation); return animation; }, _onUpdateTotalDuration = function _onUpdateTotalDuration(animation) { return animation instanceof Timeline ? _uncache(animation) : _setDuration(animation, animation._dur); }, _zeroPosition = { _start: 0, endTime: _emptyFunc, totalDuration: _emptyFunc }, _parsePosition = function _parsePosition(animation, position, percentAnimation) { var labels = animation.labels, recent = animation._recent || _zeroPosition, clippedDuration = animation.duration() >= _bigNum ? recent.endTime(false) : animation._dur, i, offset, isPercent; if (_isString(position) && (isNaN(position) || position in labels)) { offset = position.charAt(0); isPercent = position.substr(-1) === "%"; i = position.indexOf("="); if (offset === "<" || offset === ">") { i >= 0 && (position = position.replace(/=/, "")); return (offset === "<" ? recent._start : recent.endTime(recent._repeat >= 0)) + (parseFloat(position.substr(1)) || 0) * (isPercent ? (i < 0 ? recent : percentAnimation).totalDuration() / 100 : 1); } if (i < 0) { position in labels || (labels[position] = clippedDuration); return labels[position]; } offset = parseFloat(position.charAt(i - 1) + position.substr(i + 1)); if (isPercent && percentAnimation) { offset = offset / 100 * (_isArray(percentAnimation) ? percentAnimation[0] : percentAnimation).totalDuration(); } return i > 1 ? _parsePosition(animation, position.substr(0, i - 1), percentAnimation) + offset : clippedDuration + offset; } return position == null ? clippedDuration : +position; }, _createTweenType = function _createTweenType(type, params, timeline) { var isLegacy = _isNumber(params[1]), varsIndex = (isLegacy ? 2 : 1) + (type < 2 ? 0 : 1), vars = params[varsIndex], irVars, parent; isLegacy && (vars.duration = params[1]); vars.parent = timeline; if (type) { irVars = vars; parent = timeline; while (parent && !("immediateRender" in irVars)) { irVars = parent.vars.defaults || {}; parent = _isNotFalse(parent.vars.inherit) && parent.parent; } vars.immediateRender = _isNotFalse(irVars.immediateRender); type < 2 ? vars.runBackwards = 1 : vars.startAt = params[varsIndex - 1]; } return new Tween(params[0], vars, params[varsIndex + 1]); }, _conditionalReturn = function _conditionalReturn(value, func) { return value || value === 0 ? func(value) : func; }, _clamp = function _clamp(min, max, value) { return value < min ? min : value > max ? max : value; }, getUnit = function getUnit(value, v) { return !_isString(value) || !(v = _unitExp.exec(value)) ? "" : v[1]; }, clamp = function clamp(min, max, value) { return _conditionalReturn(value, function (v) { return _clamp(min, max, v); }); }, _slice = [].slice, _isArrayLike = function _isArrayLike(value, nonEmpty) { return value && _isObject(value) && "length" in value && (!nonEmpty && !value.length || value.length - 1 in value && _isObject(value[0])) && !value.nodeType && value !== _win; }, _flatten = function _flatten(ar, leaveStrings, accumulator) { if (accumulator === void 0) { accumulator = []; } return ar.forEach(function (value) { var _accumulator; return _isString(value) && !leaveStrings || _isArrayLike(value, 1) ? (_accumulator = accumulator).push.apply(_accumulator, toArray(value)) : accumulator.push(value); }) || accumulator; }, toArray = function toArray(value, scope, leaveStrings) { return _context && !scope && _context.selector ? _context.selector(value) : _isString(value) && !leaveStrings && (_coreInitted || !_wake()) ? _slice.call((scope || _doc).querySelectorAll(value), 0) : _isArray(value) ? _flatten(value, leaveStrings) : _isArrayLike(value) ? _slice.call(value, 0) : value ? [value] : []; }, selector = function selector(value) { value = toArray(value)[0] || _warn("Invalid scope") || {}; return function (v) { var el = value.current || value.nativeElement || value; return toArray(v, el.querySelectorAll ? el : el === value ? _warn("Invalid scope") || _doc.createElement("div") : value); }; }, shuffle = function shuffle(a) { return a.sort(function () { return .5 - Math.random(); }); }, distribute = function distribute(v) { if (_isFunction(v)) { return v; } var vars = _isObject(v) ? v : { each: v }, ease = _parseEase(vars.ease), from = vars.from || 0, base = parseFloat(vars.base) || 0, cache = {}, isDecimal = from > 0 && from < 1, ratios = isNaN(from) || isDecimal, axis = vars.axis, ratioX = from, ratioY = from; if (_isString(from)) { ratioX = ratioY = { center: .5, edges: .5, end: 1 }[from] || 0; } else if (!isDecimal && ratios) { ratioX = from[0]; ratioY = from[1]; } return function (i, target, a) { var l = (a || vars).length, distances = cache[l], originX, originY, x, y, d, j, max, min, wrapAt; if (!distances) { wrapAt = vars.grid === "auto" ? 0 : (vars.grid || [1, _bigNum])[1]; if (!wrapAt) { max = -_bigNum; while (max < (max = a[wrapAt++].getBoundingClientRect().left) && wrapAt < l) {} wrapAt--; } distances = cache[l] = []; originX = ratios ? Math.min(wrapAt, l) * ratioX - .5 : from % wrapAt; originY = wrapAt === _bigNum ? 0 : ratios ? l * ratioY / wrapAt - .5 : from / wrapAt | 0; max = 0; min = _bigNum; for (j = 0; j < l; j++) { x = j % wrapAt - originX; y = originY - (j / wrapAt | 0); distances[j] = d = !axis ? _sqrt(x * x + y * y) : Math.abs(axis === "y" ? y : x); d > max && (max = d); d < min && (min = d); } from === "random" && shuffle(distances); distances.max = max - min; distances.min = min; distances.v = l = (parseFloat(vars.amount) || parseFloat(vars.each) * (wrapAt > l ? l - 1 : !axis ? Math.max(wrapAt, l / wrapAt) : axis === "y" ? l / wrapAt : wrapAt) || 0) * (from === "edges" ? -1 : 1); distances.b = l < 0 ? base - l : base; distances.u = getUnit(vars.amount || vars.each) || 0; ease = ease && l < 0 ? _invertEase(ease) : ease; } l = (distances[i] - distances.min) / distances.max || 0; return _roundPrecise(distances.b + (ease ? ease(l) : l) * distances.v) + distances.u; }; }, _roundModifier = function _roundModifier(v) { var p = Math.pow(10, ((v + "").split(".")[1] || "").length); return function (raw) { var n = _roundPrecise(Math.round(parseFloat(raw) / v) * v * p); return (n - n % 1) / p + (_isNumber(raw) ? 0 : getUnit(raw)); }; }, snap = function snap(snapTo, value) { var isArray = _isArray(snapTo), radius, is2D; if (!isArray && _isObject(snapTo)) { radius = isArray = snapTo.radius || _bigNum; if (snapTo.values) { snapTo = toArray(snapTo.values); if (is2D = !_isNumber(snapTo[0])) { radius *= radius; } } else { snapTo = _roundModifier(snapTo.increment); } } return _conditionalReturn(value, !isArray ? _roundModifier(snapTo) : _isFunction(snapTo) ? function (raw) { is2D = snapTo(raw); return Math.abs(is2D - raw) <= radius ? is2D : raw; } : function (raw) { var x = parseFloat(is2D ? raw.x : raw), y = parseFloat(is2D ? raw.y : 0), min = _bigNum, closest = 0, i = snapTo.length, dx, dy; while (i--) { if (is2D) { dx = snapTo[i].x - x; dy = snapTo[i].y - y; dx = dx * dx + dy * dy; } else { dx = Math.abs(snapTo[i] - x); } if (dx < min) { min = dx; closest = i; } } closest = !radius || min <= radius ? snapTo[closest] : raw; return is2D || closest === raw || _isNumber(raw) ? closest : closest + getUnit(raw); }); }, random = function random(min, max, roundingIncrement, returnFunction) { return _conditionalReturn(_isArray(min) ? !max : roundingIncrement === true ? !!(roundingIncrement = 0) : !returnFunction, function () { return _isArray(min) ? min[~~(Math.random() * min.length)] : (roundingIncrement = roundingIncrement || 1e-5) && (returnFunction = roundingIncrement < 1 ? Math.pow(10, (roundingIncrement + "").length - 2) : 1) && Math.floor(Math.round((min - roundingIncrement / 2 + Math.random() * (max - min + roundingIncrement * .99)) / roundingIncrement) * roundingIncrement * returnFunction) / returnFunction; }); }, pipe = function pipe() { for (var _len = arguments.length, functions = new Array(_len), _key = 0; _key < _len; _key++) { functions[_key] = arguments[_key]; } return function (value) { return functions.reduce(function (v, f) { return f(v); }, value); }; }, unitize = function unitize(func, unit) { return function (value) { return func(parseFloat(value)) + (unit || getUnit(value)); }; }, normalize = function normalize(min, max, value) { return mapRange(min, max, 0, 1, value); }, _wrapArray = function _wrapArray(a, wrapper, value) { return _conditionalReturn(value, function (index) { return a[~~wrapper(index)]; }); }, wrap = function wrap(min, max, value) { var range = max - min; return _isArray(min) ? _wrapArray(min, wrap(0, min.length), max) : _conditionalReturn(value, function (value) { return (range + (value - min) % range) % range + min; }); }, wrapYoyo = function wrapYoyo(min, max, value) { var range = max - min, total = range * 2; return _isArray(min) ? _wrapArray(min, wrapYoyo(0, min.length - 1), max) : _conditionalReturn(value, function (value) { value = (total + (value - min) % total) % total || 0; return min + (value > range ? total - value : value); }); }, _replaceRandom = function _replaceRandom(value) { var prev = 0, s = "", i, nums, end, isArray; while (~(i = value.indexOf("random(", prev))) { end = value.indexOf(")", i); isArray = value.charAt(i + 7) === "["; nums = value.substr(i + 7, end - i - 7).match(isArray ? _delimitedValueExp : _strictNumExp); s += value.substr(prev, i - prev) + random(isArray ? nums : +nums[0], isArray ? 0 : +nums[1], +nums[2] || 1e-5); prev = end + 1; } return s + value.substr(prev, value.length - prev); }, mapRange = function mapRange(inMin, inMax, outMin, outMax, value) { var inRange = inMax - inMin, outRange = outMax - outMin; return _conditionalReturn(value, function (value) { return outMin + ((value - inMin) / inRange * outRange || 0); }); }, interpolate = function interpolate(start, end, progress, mutate) { var func = isNaN(start + end) ? 0 : function (p) { return (1 - p) * start + p * end; }; if (!func) { var isString = _isString(start), master = {}, p, i, interpolators, l, il; progress === true && (mutate = 1) && (progress = null); if (isString) { start = { p: start }; end = { p: end }; } else if (_isArray(start) && !_isArray(end)) { interpolators = []; l = start.length; il = l - 2; for (i = 1; i < l; i++) { interpolators.push(interpolate(start[i - 1], start[i])); } l--; func = function func(p) { p *= l; var i = Math.min(il, ~~p); return interpolators[i](p - i); }; progress = end; } else if (!mutate) { start = _merge(_isArray(start) ? [] : {}, start); } if (!interpolators) { for (p in end) { _addPropTween.call(master, start, p, "get", end[p]); } func = function func(p) { return _renderPropTweens(p, master) || (isString ? start.p : start); }; } } return _conditionalReturn(progress, func); }, _getLabelInDirection = function _getLabelInDirection(timeline, fromTime, backward) { var labels = timeline.labels, min = _bigNum, p, distance, label; for (p in labels) { distance = labels[p] - fromTime; if (distance < 0 === !!backward && distance && min > (distance = Math.abs(distance))) { label = p; min = distance; } } return label; }, _callback = function _callback(animation, type, executeLazyFirst) { var v = animation.vars, callback = v[type], prevContext = _context, context = animation._ctx, params, scope, result; if (!callback) { return; } params = v[type + "Params"]; scope = v.callbackScope || animation; executeLazyFirst && _lazyTweens.length && _lazyRender(); context && (_context = context); result = params ? callback.apply(scope, params) : callback.call(scope); _context = prevContext; return result; }, _interrupt = function _interrupt(animation) { _removeFromParent(animation); animation.scrollTrigger && animation.scrollTrigger.kill(!!_reverting); animation.progress() < 1 && _callback(animation, "onInterrupt"); return animation; }, _quickTween, _createPlugin = function _createPlugin(config) { config = !config.name && config["default"] || config; var name = config.name, isFunc = _isFunction(config), Plugin = name && !isFunc && config.init ? function () { this._props = []; } : config, instanceDefaults = { init: _emptyFunc, render: _renderPropTweens, add: _addPropTween, kill: _killPropTweensOf, modifier: _addPluginModifier, rawVars: 0 }, statics = { targetTest: 0, get: 0, getSetter: _getSetter, aliases: {}, register: 0 }; _wake(); if (config !== Plugin) { if (_plugins[name]) { return; } _setDefaults(Plugin, _setDefaults(_copyExcluding(config, instanceDefaults), statics)); _merge(Plugin.prototype, _merge(instanceDefaults, _copyExcluding(config, statics))); _plugins[Plugin.prop = name] = Plugin; if (config.targetTest) { _harnessPlugins.push(Plugin); _reservedProps[name] = 1; } name = (name === "css" ? "CSS" : name.charAt(0).toUpperCase() + name.substr(1)) + "Plugin"; } _addGlobal(name, Plugin); config.register && config.register(gsap, Plugin, PropTween); }, _255 = 255, _colorLookup = { aqua: [0, _255, _255], lime: [0, _255, 0], silver: [192, 192, 192], black: [0, 0, 0], maroon: [128, 0, 0], teal: [0, 128, 128], blue: [0, 0, _255], navy: [0, 0, 128], white: [_255, _255, _255], olive: [128, 128, 0], yellow: [_255, _255, 0], orange: [_255, 165, 0], gray: [128, 128, 128], purple: [128, 0, 128], green: [0, 128, 0], red: [_255, 0, 0], pink: [_255, 192, 203], cyan: [0, _255, _255], transparent: [_255, _255, _255, 0] }, _hue = function _hue(h, m1, m2) { h += h < 0 ? 1 : h > 1 ? -1 : 0; return (h * 6 < 1 ? m1 + (m2 - m1) * h * 6 : h < .5 ? m2 : h * 3 < 2 ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * _255 + .5 | 0; }, splitColor = function splitColor(v, toHSL, forceAlpha) { var a = !v ? _colorLookup.black : _isNumber(v) ? [v >> 16, v >> 8 & _255, v & _255] : 0, r, g, b, h, s, l, max, min, d, wasHSL; if (!a) { if (v.substr(-1) === ",") { v = v.substr(0, v.length - 1); } if (_colorLookup[v]) { a = _colorLookup[v]; } else if (v.charAt(0) === "#") { if (v.length < 6) { r = v.charAt(1); g = v.charAt(2); b = v.charAt(3); v = "#" + r + r + g + g + b + b + (v.length === 5 ? v.charAt(4) + v.charAt(4) : ""); } if (v.length === 9) { a = parseInt(v.substr(1, 6), 16); return [a >> 16, a >> 8 & _255, a & _255, parseInt(v.substr(7), 16) / 255]; } v = parseInt(v.substr(1), 16); a = [v >> 16, v >> 8 & _255, v & _255]; } else if (v.substr(0, 3) === "hsl") { a = wasHSL = v.match(_strictNumExp); if (!toHSL) { h = +a[0] % 360 / 360; s = +a[1] / 100; l = +a[2] / 100; g = l <= .5 ? l * (s + 1) : l + s - l * s; r = l * 2 - g; a.length > 3 && (a[3] *= 1); a[0] = _hue(h + 1 / 3, r, g); a[1] = _hue(h, r, g); a[2] = _hue(h - 1 / 3, r, g); } else if (~v.indexOf("=")) { a = v.match(_numExp); forceAlpha && a.length < 4 && (a[3] = 1); return a; } } else { a = v.match(_strictNumExp) || _colorLookup.transparent; } a = a.map(Number); } if (toHSL && !wasHSL) { r = a[0] / _255; g = a[1] / _255; b = a[2] / _255; max = Math.max(r, g, b); min = Math.min(r, g, b); l = (max + min) / 2; if (max === min) { h = s = 0; } else { d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4; h *= 60; } a[0] = ~~(h + .5); a[1] = ~~(s * 100 + .5); a[2] = ~~(l * 100 + .5); } forceAlpha && a.length < 4 && (a[3] = 1); return a; }, _colorOrderData = function _colorOrderData(v) { var values = [], c = [], i = -1; v.split(_colorExp).forEach(function (v) { var a = v.match(_numWithUnitExp) || []; values.push.apply(values, a); c.push(i += a.length + 1); }); values.c = c; return values; }, _formatColors = function _formatColors(s, toHSL, orderMatchData) { var result = "", colors = (s + result).match(_colorExp), type = toHSL ? "hsla(" : "rgba(", i = 0, c, shell, d, l; if (!colors) { return s; } colors = colors.map(function (color) { return (color = splitColor(color, toHSL, 1)) && type + (toHSL ? color[0] + "," + color[1] + "%," + color[2] + "%," + color[3] : color.join(",")) + ")"; }); if (orderMatchData) { d = _colorOrderData(s); c = orderMatchData.c; if (c.join(result) !== d.c.join(result)) { shell = s.replace(_colorExp, "1").split(_numWithUnitExp); l = shell.length - 1; for (; i < l; i++) { result += shell[i] + (~c.indexOf(i) ? colors.shift() || type + "0,0,0,0)" : (d.length ? d : colors.length ? colors : orderMatchData).shift()); } } } if (!shell) { shell = s.split(_colorExp); l = shell.length - 1; for (; i < l; i++) { result += shell[i] + colors[i]; } } return result + shell[l]; }, _colorExp = function () { var s = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#(?:[0-9a-f]{3,4}){1,2}\\b", p; for (p in _colorLookup) { s += "|" + p + "\\b"; } return new RegExp(s + ")", "gi"); }(), _hslExp = /hsl[a]?\(/, _colorStringFilter = function _colorStringFilter(a) { var combined = a.join(" "), toHSL; _colorExp.lastIndex = 0; if (_colorExp.test(combined)) { toHSL = _hslExp.test(combined); a[1] = _formatColors(a[1], toHSL); a[0] = _formatColors(a[0], toHSL, _colorOrderData(a[1])); return true; } }, _tickerActive, _ticker = function () { var _getTime = Date.now, _lagThreshold = 500, _adjustedLag = 33, _startTime = _getTime(), _lastUpdate = _startTime, _gap = 1000 / 240, _nextTime = _gap, _listeners = [], _id, _req, _raf, _self, _delta, _i, _tick = function _tick(v) { var elapsed = _getTime() - _lastUpdate, manual = v === true, overlap, dispatch, time, frame; elapsed > _lagThreshold && (_startTime += elapsed - _adjustedLag); _lastUpdate += elapsed; time = _lastUpdate - _startTime; overlap = time - _nextTime; if (overlap > 0 || manual) { frame = ++_self.frame; _delta = time - _self.time * 1000; _self.time = time = time / 1000; _nextTime += overlap + (overlap >= _gap ? 4 : _gap - overlap); dispatch = 1; } manual || (_id = _req(_tick)); if (dispatch) { for (_i = 0; _i < _listeners.length; _i++) { _listeners[_i](time, _delta, frame, v); } } }; _self = { time: 0, frame: 0, tick: function tick() { _tick(true); }, deltaRatio: function deltaRatio(fps) { return _delta / (1000 / (fps || 60)); }, wake: function wake() { if (_coreReady) { if (!_coreInitted && _windowExists()) { _win = _coreInitted = window; _doc = _win.document || {}; _globals.gsap = gsap; (_win.gsapVersions || (_win.gsapVersions = [])).push(gsap.version); _install(_installScope || _win.GreenSockGlobals || !_win.gsap && _win || {}); _raf = _win.requestAnimationFrame; } _id && _self.sleep(); _req = _raf || function (f) { return setTimeout(f, _nextTime - _self.time * 1000 + 1 | 0); }; _tickerActive = 1; _tick(2); } }, sleep: function sleep() { (_raf ? _win.cancelAnimationFrame : clearTimeout)(_id); _tickerActive = 0; _req = _emptyFunc; }, lagSmoothing: function lagSmoothing(threshold, adjustedLag) { _lagThreshold = threshold || 1 / _tinyNum; _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0); }, fps: function fps(_fps) { _gap = 1000 / (_fps || 240); _nextTime = _self.time * 1000 + _gap; }, add: function add(callback, once, prioritize) { var func = once ? function (t, d, f, v) { callback(t, d, f, v); _self.remove(func); } : callback; _self.remove(callback); _listeners[prioritize ? "unshift" : "push"](func); _wake(); return func; }, remove: function remove(callback, i) { ~(i = _listeners.indexOf(callback)) && _listeners.splice(i, 1) && _i >= i && _i--; }, _listeners: _listeners }; return _self; }(), _wake = function _wake() { return !_tickerActive && _ticker.wake(); }, _easeMap = {}, _customEaseExp = /^[\d.\-M][\d.\-,\s]/, _quotesExp = /["']/g, _parseObjectInString = function _parseObjectInString(value) { var obj = {}, split = value.substr(1, value.length - 3).split(":"), key = split[0], i = 1, l = split.length, index, val, parsedVal; for (; i < l; i++) { val = split[i]; index = i !== l - 1 ? val.lastIndexOf(",") : val.length; parsedVal = val.substr(0, index); obj[key] = isNaN(parsedVal) ? parsedVal.replace(_quotesExp, "").trim() : +parsedVal; key = val.substr(index + 1).trim(); } return obj; }, _valueInParentheses = function _valueInParentheses(value) { var open = value.indexOf("(") + 1, close = value.indexOf(")"), nested = value.indexOf("(", open); return value.substring(open, ~nested && nested < close ? value.indexOf(")", close + 1) : close); }, _configEaseFromString = function _configEaseFromString(name) { var split = (name + "").split("("), ease = _easeMap[split[0]]; return ease && split.length > 1 && ease.config ? ease.config.apply(null, ~name.indexOf("{") ? [_parseObjectInString(split[1])] : _valueInParentheses(name).split(",").map(_numericIfPossible)) : _easeMap._CE && _customEaseExp.test(name) ? _easeMap._CE("", name) : ease; }, _invertEase = function _invertEase(ease) { return function (p) { return 1 - ease(1 - p); }; }, _propagateYoyoEase = function _propagateYoyoEase(timeline, isYoyo) { var child = timeline._first, ease; while (child) { if (child instanceof Timeline) { _propagateYoyoEase(child, isYoyo); } else if (child.vars.yoyoEase && (!child._yoyo || !child._repeat) && child._yoyo !== isYoyo) { if (child.timeline) { _propagateYoyoEase(child.timeline, isYoyo); } else { ease = child._ease; child._ease = child._yEase; child._yEase = ease; child._yoyo = isYoyo; } } child = child._next; } }, _parseEase = function _parseEase(ease, defaultEase) { return !ease ? defaultEase : (_isFunction(ease) ? ease : _easeMap[ease] || _configEaseFromString(ease)) || defaultEase; }, _insertEase = function _insertEase(names, easeIn, easeOut, easeInOut) { if (easeOut === void 0) { easeOut = function easeOut(p) { return 1 - easeIn(1 - p); }; } if (easeInOut === void 0) { easeInOut = function easeInOut(p) { return p < .5 ? easeIn(p * 2) / 2 : 1 - easeIn((1 - p) * 2) / 2; }; } var ease = { easeIn: easeIn, easeOut: easeOut, easeInOut: easeInOut }, lowercaseName; _forEachName(names, function (name) { _easeMap[name] = _globals[name] = ease; _easeMap[lowercaseName = name.toLowerCase()] = easeOut; for (var p in ease) { _easeMap[lowercaseName + (p === "easeIn" ? ".in" : p === "easeOut" ? ".out" : ".inOut")] = _easeMap[name + "." + p] = ease[p]; } }); return ease; }, _easeInOutFromOut = function _easeInOutFromOut(easeOut) { return function (p) { return p < .5 ? (1 - easeOut(1 - p * 2)) / 2 : .5 + easeOut((p - .5) * 2) / 2; }; }, _configElastic = function _configElastic(type, amplitude, period) { var p1 = amplitude >= 1 ? amplitude : 1, p2 = (period || (type ? .3 : .45)) / (amplitude < 1 ? amplitude : 1), p3 = p2 / _2PI * (Math.asin(1 / p1) || 0), easeOut = function easeOut(p) { return p === 1 ? 1 : p1 * Math.pow(2, -10 * p) * _sin((p - p3) * p2) + 1; }, ease = type === "out" ? easeOut : type === "in" ? function (p) { return 1 - easeOut(1 - p); } : _easeInOutFromOut(easeOut); p2 = _2PI / p2; ease.config = function (amplitude, period) { return _configElastic(type, amplitude, period); }; return ease; }, _configBack = function _configBack(type, overshoot) { if (overshoot === void 0) { overshoot = 1.70158; } var easeOut = function easeOut(p) { return p ? --p * p * ((overshoot + 1) * p + overshoot) + 1 : 0; }, ease = type === "out" ? easeOut : type === "in" ? function (p) { return 1 - easeOut(1 - p); } : _easeInOutFromOut(easeOut); ease.config = function (overshoot) { return _configBack(type, overshoot); }; return ease; }; _forEachName("Linear,Quad,Cubic,Quart,Quint,Strong", function (name, i) { var power = i < 5 ? i + 1 : i; _insertEase(name + ",Power" + (power - 1), i ? function (p) { return Math.pow(p, power); } : function (p) { return p; }, function (p) { return 1 - Math.pow(1 - p, power); }, function (p) { return p < .5 ? Math.pow(p * 2, power) / 2 : 1 - Math.pow((1 - p) * 2, power) / 2; }); }); _easeMap.Linear.easeNone = _easeMap.none = _easeMap.Linear.easeIn; _insertEase("Elastic", _configElastic("in"), _configElastic("out"), _configElastic()); (function (n, c) { var n1 = 1 / c, n2 = 2 * n1, n3 = 2.5 * n1, easeOut = function easeOut(p) { return p < n1 ? n * p * p : p < n2 ? n * Math.pow(p - 1.5 / c, 2) + .75 : p < n3 ? n * (p -= 2.25 / c) * p + .9375 : n * Math.pow(p - 2.625 / c, 2) + .984375; }; _insertEase("Bounce", function (p) { return 1 - easeOut(1 - p); }, easeOut); })(7.5625, 2.75); _insertEase("Expo", function (p) { return p ? Math.pow(2, 10 * (p - 1)) : 0; }); _insertEase("Circ", function (p) { return -(_sqrt(1 - p * p) - 1); }); _insertEase("Sine", function (p) { return p === 1 ? 1 : -_cos(p * _HALF_PI) + 1; }); _insertEase("Back", _configBack("in"), _configBack("out"), _configBack()); _easeMap.SteppedEase = _easeMap.steps = _globals.SteppedEase = { config: function config(steps, immediateStart) { if (steps === void 0) { steps = 1; } var p1 = 1 / steps, p2 = steps + (immediateStart ? 0 : 1), p3 = immediateStart ? 1 : 0, max = 1 - _tinyNum; return function (p) { return ((p2 * _clamp(0, max, p) | 0) + p3) * p1; }; } }; _defaults.ease = _easeMap["quad.out"]; _forEachName("onComplete,onUpdate,onStart,onRepeat,onReverseComplete,onInterrupt", function (name) { return _callbackNames += name + "," + name + "Params,"; }); var GSCache = function GSCache(target, harness) { this.id = _gsID++; target._gsap = this; this.target = target; this.harness = harness; this.get = harness ? harness.get : _getProperty; this.set = harness ? harness.getSetter : _getSetter; }; var Animation = function () { function Animation(vars) { this.vars = vars; this._delay = +vars.delay || 0; if (this._repeat = vars.repeat === Infinity ? -2 : vars.repeat || 0) { this._rDelay = vars.repeatDelay || 0; this._yoyo = !!vars.yoyo || !!vars.yoyoEase; } this._ts = 1; _setDuration(this, +vars.duration, 1, 1); this.data = vars.data; if (_context) { this._ctx = _context; _context.data.push(this); } _tickerActive || _ticker.wake(); } var _proto = Animation.prototype; _proto.delay = function delay(value) { if (value || value === 0) { this.parent && this.parent.smoothChildTiming && this.startTime(this._start + value - this._delay); this._delay = value; return this; } return this._delay; }; _proto.duration = function duration(value) { return arguments.length ? this.totalDuration(this._repeat > 0 ? value + (value + this._rDelay) * this._repeat : value) : this.totalDuration() && this._dur; }; _proto.totalDuration = function totalDuration(value) { if (!arguments.length) { return this._tDur; } this._dirty = 0; return _setDuration(this, this._repeat < 0 ? value : (value - this._repeat * this._rDelay) / (this._repeat + 1)); }; _proto.totalTime = function totalTime(_totalTime, suppressEvents) { _wake(); if (!arguments.length) { return this._tTime; } var parent = this._dp; if (parent && parent.smoothChildTiming && this._ts) { _alignPlayhead(this, _totalTime); !parent._dp || parent.parent || _postAddChecks(parent, this); while (parent && parent.parent) { if (parent.parent._time !== parent._start + (parent._ts >= 0 ? parent._tTime / parent._ts : (parent.totalDuration() - parent._tTime) / -parent._ts)) { parent.totalTime(parent._tTime, true); } parent = parent.parent; } if (!this.parent && this._dp.autoRemoveChildren && (this._ts > 0 && _totalTime < this._tDur || this._ts < 0 && _totalTime > 0 || !this._tDur && !_totalTime)) { _addToTimeline(this._dp, this, this._start - this._delay); } } if (this._tTime !== _totalTime || !this._dur && !suppressEvents || this._initted && Math.abs(this._zTime) === _tinyNum || !_totalTime && !this._initted && (this.add || this._ptLookup)) { this._ts || (this._pTime = _totalTime); _lazySafeRender(this, _totalTime, suppressEvents); } return this; }; _proto.time = function time(value, suppressEvents) { return arguments.length ? this.totalTime(Math.min(this.totalDuration(), value + _elapsedCycleDuration(this)) % (this._dur + this._rDelay) || (value ? this._dur : 0), suppressEvents) : this._time; }; _proto.totalProgress = function totalProgress(value, suppressEvents) { return arguments.length ? this.totalTime(this.totalDuration() * value, suppressEvents) : this.totalDuration() ? Math.min(1, this._tTime / this._tDur) : this.ratio; }; _proto.progress = function progress(value, suppressEvents) { return arguments.length ? this.totalTime(this.duration() * (this._yoyo && !(this.iteration() & 1) ? 1 - value : value) + _elapsedCycleDuration(this), suppressEvents) : this.duration() ? Math.min(1, this._time / this._dur) : this.ratio; }; _proto.iteration = function iteration(value, suppressEvents) { var cycleDuration = this.duration() + this._rDelay; return arguments.length ? this.totalTime(this._time + (value - 1) * cycleDuration, suppressEvents) : this._repeat ? _animationCycle(this._tTime, cycleDuration) + 1 : 1; }; _proto.timeScale = function timeScale(value) { if (!arguments.length) { return this._rts === -_tinyNum ? 0 : this._rts; } if (this._rts === value) { return this; } var tTime = this.parent && this._ts ? _parentToChildTotalTime(this.parent._time, this) : this._tTime; this._rts = +value || 0; this._ts = this._ps || value === -_tinyNum ? 0 : this._rts; this.totalTime(_clamp(-this._delay, this._tDur, tTime), true); _setEnd(this); return _recacheAncestors(this); }; _proto.paused = function paused(value) { if (!arguments.length) { return this._ps; } if (this._ps !== value) { this._ps = value; if (value) { this._pTime = this._tTime || Math.max(-this._delay, this.rawTime()); this._ts = this._act = 0; } else { _wake(); this._ts = this._rts; this.totalTime(this.parent && !this.parent.smoothChildTiming ? this.rawTime() : this._tTime || this._pTime, this.progress() === 1 && Math.abs(this._zTime) !== _tinyNum && (this._tTime -= _tinyNum)); } } return this; }; _proto.startTime = function startTime(value) { if (arguments.length) { this._start = value; var parent = this.parent || this._dp; parent && (parent._sort || !this.parent) && _addToTimeline(parent, this, value - this._delay); return this; } return this._start; }; _proto.endTime = function endTime(includeRepeats) { return this._start + (_isNotFalse(includeRepeats) ? this.totalDuration() : this.duration()) / Math.abs(this._ts || 1); }; _proto.rawTime = function rawTime(wrapRepeats) { var parent = this.parent || this._dp; return !parent ? this._tTime : wrapRepeats && (!this._ts || this._repeat && this._time && this.totalProgress() < 1) ? this._tTime % (this._dur + this._rDelay) : !this._ts ? this._tTime : _parentToChildTotalTime(parent.rawTime(wrapRepeats), this); }; _proto.revert = function revert(config) { if (config === void 0) { config = _revertConfig; } var prevIsReverting = _reverting; _reverting = config; if (this._initted || this._startAt) { this.timeline && this.timeline.revert(config); this.totalTime(-0.01, config.suppressEvents); } this.data !== "nested" && config.kill !== false && this.kill(); _reverting = prevIsReverting; return this; }; _proto.globalTime = function globalTime(rawTime) { var animation = this, time = arguments.length ? rawTime : animation.rawTime(); while (animation) { time = animation._start + time / (animation._ts || 1); animation = animation._dp; } return !this.parent && this.vars.immediateRender ? -1 : time; }; _proto.repeat = function repeat(value) { if (arguments.length) { this._repeat = value === Infinity ? -2 : value; return _onUpdateTotalDuration(this); } return this._repeat === -2 ? Infinity : this._repeat; }; _proto.repeatDelay = function repeatDelay(value) { if (arguments.length) { var time = this._time; this._rDelay = value; _onUpdateTotalDuration(this); return time ? this.time(time) : this; } return this._rDelay; }; _proto.yoyo = function yoyo(value) { if (arguments.length) { this._yoyo = value; return this; } return this._yoyo; }; _proto.seek = function seek(position, suppressEvents) { return this.totalTime(_parsePosition(this, position), _isNotFalse(suppressEvents)); }; _proto.restart = function restart(includeDelay, suppressEvents) { return this.play().totalTime(includeDelay ? -this._delay : 0, _isNotFalse(suppressEvents)); }; _proto.play = function play(from, suppressEvents) { from != null && this.seek(from, suppressEvents); return this.reversed(false).paused(false); }; _proto.reverse = function reverse(from, suppressEvents) { from != null && this.seek(from || this.totalDuration(), suppressEvents); return this.reversed(true).paused(false); }; _proto.pause = function pause(atTime, suppressEvents) { atTime != null && this.seek(atTime, suppressEvents); return this.paused(true); }; _proto.resume = function resume() { return this.paused(false); }; _proto.reversed = function reversed(value) { if (arguments.length) { !!value !== this.reversed() && this.timeScale(-this._rts || (value ? -_tinyNum : 0)); return this; } return this._rts < 0; }; _proto.invalidate = function invalidate() { this._initted = this._act = 0; this._zTime = -_tinyNum; return this; }; _proto.isActive = function isActive() { var parent = this.parent || this._dp, start = this._start, rawTime; return !!(!parent || this._ts && this._initted && parent.isActive() && (rawTime = parent.rawTime(true)) >= start && rawTime < this.endTime(true) - _tinyNum); }; _proto.eventCallback = function eventCallback(type, callback, params) { var vars = this.vars; if (arguments.length > 1) { if (!callback) { delete vars[type]; } else { vars[type] = callback; params && (vars[type + "Params"] = params); type === "onUpdate" && (this._onUpdate = callback); } return this; } return vars[type]; }; _proto.then = function then(onFulfilled) { var self = this; return new Promise(function (resolve) { var f = _isFunction(onFulfilled) ? onFulfilled : _passThrough, _resolve = function _resolve() { var _then = self.then; self.then = null; _isFunction(f) && (f = f(self)) && (f.then || f === self) && (self.then = _then); resolve(f); self.then = _then; }; if (self._initted && self.totalProgress() === 1 && self._ts >= 0 || !self._tTime && self._ts < 0) { _resolve(); } else { self._prom = _resolve; } }); }; _proto.kill = function kill() { _interrupt(this); }; return Animation; }(); _setDefaults(Animation.prototype, { _time: 0, _start: 0, _end: 0, _tTime: 0, _tDur: 0, _dirty: 0, _repeat: 0, _yoyo: false, parent: null, _initted: false, _rDelay: 0, _ts: 1, _dp: 0, ratio: 0, _zTime: -_tinyNum, _prom: 0, _ps: false, _rts: 1 }); var Timeline = function (_Animation) { _inheritsLoose(Timeline, _Animation); function Timeline(vars, position) { var _this; if (vars === void 0) { vars = {}; } _this = _Animation.call(this, vars) || this; _this.labels = {}; _this.smoothChildTiming = !!vars.smoothChildTiming; _this.autoRemoveChildren = !!vars.autoRemoveChildren; _this._sort = _isNotFalse(vars.sortChildren); _globalTimeline && _addToTimeline(vars.parent || _globalTimeline, _assertThisInitialized(_this), position); vars.reversed && _this.reverse(); vars.paused && _this.paused(true); vars.scrollTrigger && _scrollTrigger(_assertThisInitialized(_this), vars.scrollTrigger); return _this; } var _proto2 = Timeline.prototype; _proto2.to = function to(targets, vars, position) { _createTweenType(0, arguments, this); return this; }; _proto2.from = function from(targets, vars, position) { _createTweenType(1, arguments, this); return this; }; _proto2.fromTo = function fromTo(targets, fromVars, toVars, position) { _createTweenType(2, arguments, this); return this; }; _proto2.set = function set(targets, vars, position) { vars.duration = 0; vars.parent = this; _inheritDefaults(vars).repeatDelay || (vars.repeat = 0); vars.immediateRender = !!vars.immediateRender; new Tween(targets, vars, _parsePosition(this, position), 1); return this; }; _proto2.call = function call(callback, params, position) { return _addToTimeline(this, Tween.delayedCall(0, callback, params), position); }; _proto2.staggerTo = function staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) { vars.duration = duration; vars.stagger = vars.stagger || stagger; vars.onComplete = onCompleteAll; vars.onCompleteParams = onCompleteAllParams; vars.parent = this; new Tween(targets, vars, _parsePosition(this, position)); return this; }; _proto2.staggerFrom = function staggerFrom(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) { vars.runBackwards = 1; _inheritDefaults(vars).immediateRender = _isNotFalse(vars.immediateRender); return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams); }; _proto2.staggerFromTo = function staggerFromTo(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams) { toVars.startAt = fromVars; _inheritDefaults(toVars).immediateRender = _isNotFalse(toVars.immediateRender); return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams); }; _proto2.render = function render(totalTime, suppressEvents, force) { var prevTime = this._time, tDur = this._dirty ? this.totalDuration() : this._tDur, dur = this._dur, tTime = totalTime <= 0 ? 0 : _roundPrecise(totalTime), crossingStart = this._zTime < 0 !== totalTime < 0 && (this._initted || !dur), time, child, next, iteration, cycleDuration, prevPaused, pauseTween, timeScale, prevStart, prevIteration, yoyo, isYoyo; this !== _globalTimeline && tTime > tDur && totalTime >= 0 && (tTime = tDur); if (tTime !== this._tTime || force || crossingStart) { if (prevTime !== this._time && dur) { tTime += this._time - prevTime; totalTime += this._time - prevTime; } time = tTime; prevStart = this._start; timeScale = this._ts; prevPaused = !timeScale; if (crossingStart) { dur || (prevTime = this._zTime); (totalTime || !suppressEvents) && (this._zTime = totalTime); } if (this._repeat) { yoyo = this._yoyo; cycleDuration = dur + this._rDelay; if (this._repeat < -1 && totalTime < 0) { return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force); } time = _roundPrecise(tTime % cycleDuration); if (tTime === tDur) { iteration = this._repeat; time = dur; } else { iteration = ~~(tTime / cycleDuration); if (iteration && iteration === tTime / cycleDuration) { time = dur; iteration--; } time > dur && (time = dur); } prevIteration = _animationCycle(this._tTime, cycleDuration); !prevTime && this._tTime && prevIteration !== iteration && (prevIteration = iteration); if (yoyo && iteration & 1) { time = dur - time; isYoyo = 1; } if (iteration !== prevIteration && !this._lock) { var rewinding = yoyo && prevIteration & 1, doesWrap = rewinding === (yoyo && iteration & 1); iteration < prevIteration && (rewinding = !rewinding); prevTime = rewinding ? 0 : dur; this._lock = 1; this.render(prevTime || (isYoyo ? 0 : _roundPrecise(iteration * cycleDuration)), suppressEvents, !dur)._lock = 0; this._tTime = tTime; !suppressEvents && this.parent && _callback(this, "onRepeat"); this.vars.repeatRefresh && !isYoyo && (this.invalidate()._lock = 1); if (prevTime && prevTime !== this._time || prevPaused !== !this._ts || this.vars.onRepeat && !this.parent && !this._act) { return this; } dur = this._dur; tDur = this._tDur; if (doesWrap) { this._lock = 2; prevTime = rewinding ? dur : -0.0001; this.render(prevTime, true); this.vars.repeatRefresh && !isYoyo && this.invalidate(); } this._lock = 0; if (!this._ts && !prevPaused) { return this; } _propagateYoyoEase(this, isYoyo); } } if (this._hasPause && !this._forcing && this._lock < 2) { pauseTween = _findNextPauseTween(this, _roundPrecise(prevTime), _roundPrecise(time)); if (pauseTween) { tTime -= time - (time = pauseTween._start); } } this._tTime = tTime; this._time = time; this._act = !timeScale; if (!this._initted) { this._onUpdate = this.vars.onUpdate; this._initted = 1; this._zTime = totalTime; prevTime = 0; } if (!prevTime && time && !suppressEvents) { _callback(this, "onStart"); if (this._tTime !== tTime) { return this; } } if (time >= prevTime && totalTime >= 0) { child = this._first; while (child) { next = child._next; if ((child._act || time >= child._start) && child._ts && pauseTween !== child) { if (child.parent !== this) { return this.render(totalTime, suppressEvents, force); } child.render(child._ts > 0 ? (time - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (time - child._start) * child._ts, suppressEvents, force); if (time !== this._time || !this._ts && !prevPaused) { pauseTween = 0; next && (tTime += this._zTime = -_tinyNum); break; } } child = next; } } else { child = this._last; var adjustedTime = totalTime < 0 ? totalTime : time; while (child) { next = child._prev; if ((child._act || adjustedTime <= child._end) && child._ts && pauseTween !== child) { if (child.parent !== this) { return this.render(totalTime, suppressEvents, force); } child.render(child._ts > 0 ? (adjustedTime - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (adjustedTime - child._start) * child._ts, suppressEvents, force || _reverting && (child._initted || child._startAt)); if (time !== this._time || !this._ts && !prevPaused) { pauseTween = 0; next && (tTime += this._zTime = adjustedTime ? -_tinyNum : _tinyNum); break; } } child = next; } } if (pauseTween && !suppressEvents) { this.pause(); pauseTween.render(time >= prevTime ? 0 : -_tinyNum)._zTime = time >= prevTime ? 1 : -1; if (this._ts) { this._start = prevStart; _setEnd(this); return this.render(totalTime, suppressEvents, force); } } this._onUpdate && !suppressEvents && _callback(this, "onUpdate", true); if (tTime === tDur && this._tTime >= this.totalDuration() || !tTime && prevTime) if (prevStart === this._start || Math.abs(timeScale) !== Math.abs(this._ts)) if (!this._lock) { (totalTime || !dur) && (tTime === tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1); if (!suppressEvents && !(totalTime < 0 && !prevTime) && (tTime || prevTime || !tDur)) { _callback(this, tTime === tDur && totalTime >= 0 ? "onComplete" : "onReverseComplete", true); this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom(); } } } return this; }; _proto2.add = function add(child, position) { var _this2 = this; _isNumber(position) || (position = _parsePosition(this, position, child)); if (!(child instanceof Animation)) { if (_isArray(child)) { child.forEach(function (obj) { return _this2.add(obj, position); }); return this; } if (_isString(child)) { return this.addLabel(child, position); } if (_isFunction(child)) { child = Tween.delayedCall(0, child); } else { return this; } } return this !== child ? _addToTimeline(this, child, position) : this; }; _proto2.getChildren = function getChildren(nested, tweens, timelines, ignoreBeforeTime) { if (nested === void 0) { nested = true; } if (tweens === void 0) { tweens = true; } if (timelines === void 0) { timelines = true; } if (ignoreBeforeTime === void 0) { ignoreBeforeTime = -_bigNum; } var a = [], child = this._first; while (child) { if (child._start >= ignoreBeforeTime) { if (child instanceof Tween) { tweens && a.push(child); } else { timelines && a.push(child); nested && a.push.apply(a, child.getChildren(true, tweens, timelines)); } } child = child._next; } return a; }; _proto2.getById = function getById(id) { var animations = this.getChildren(1, 1, 1), i = animations.length; while (i--) { if (animations[i].vars.id === id) { return animations[i]; } } }; _proto2.remove = function remove(child) { if (_isString(child)) { return this.removeLabel(child); } if (_isFunction(child)) { return this.killTweensOf(child); } _removeLinkedListItem(this, child); if (child === this._recent) { this._recent = this._last; } return _uncache(this); }; _proto2.totalTime = function totalTime(_totalTime2, suppressEvents) { if (!arguments.length) { return this._tTime; } this._forcing = 1; if (!this._dp && this._ts) { this._start = _roundPrecise(_ticker.time - (this._ts > 0 ? _totalTime2 / this._ts : (this.totalDuration() - _totalTime2) / -this._ts)); } _Animation.prototype.totalTime.call(this, _totalTime2, suppressEvents); this._forcing = 0; return this; }; _proto2.addLabel = function addLabel(label, position) { this.labels[label] = _parsePosition(this, position); return this; }; _proto2.removeLabel = function removeLabel(label) { delete this.labels[label]; return this; }; _proto2.addPause = function addPause(position, callback, params) { var t = Tween.delayedCall(0, callback || _emptyFunc, params); t.data = "isPause"; this._hasPause = 1; return _addToTimeline(this, t, _parsePosition(this, position)); }; _proto2.removePause = function removePause(position) { var child = this._first; position = _parsePosition(this, position); while (child) { if (child._start === position && child.data === "isPause") { _removeFromParent(child); } child = child._next; } }; _proto2.killTweensOf = function killTweensOf(targets, props, onlyActive) { var tweens = this.getTweensOf(targets, onlyActive), i = tweens.length; while (i--) { _overwritingTween !== tweens[i] && tweens[i].kill(targets, props); } return this; }; _proto2.getTweensOf = function getTweensOf(targets, onlyActive) { var a = [], parsedTargets = toArray(targets), child = this._first, isGlobalTime = _isNumber(onlyActive), children; while (child) { if (child instanceof Tween) { if (_arrayContainsAny(child._targets, parsedTargets) && (isGlobalTime ? (!_overwritingTween || child._initted && child._ts) && child.globalTime(0) <= onlyActive && child.globalTime(child.totalDuration()) > onlyActive : !onlyActive || child.isActive())) { a.push(child); } } else if ((children = child.getTweensOf(parsedTargets, onlyActive)).length) { a.push.apply(a, children); } child = child._next; } return a; }; _proto2.tweenTo = function tweenTo(position, vars) { vars = vars || {}; var tl = this, endTime = _parsePosition(tl, position), _vars = vars, startAt = _vars.startAt, _onStart = _vars.onStart, onStartParams = _vars.onStartParams, immediateRender = _vars.immediateRender, initted, tween = Tween.to(tl, _setDefaults({ ease: vars.ease || "none", lazy: false, immediateRender: false, time: endTime, overwrite: "auto", duration: vars.duration || Math.abs((endTime - (startAt && "time" in startAt ? startAt.time : tl._time)) / tl.timeScale()) || _tinyNum, onStart: function onStart() { tl.pause(); if (!initted) { var duration = vars.duration || Math.abs((endTime - (startAt && "time" in startAt ? startAt.time : tl._time)) / tl.timeScale()); tween._dur !== duration && _setDuration(tween, duration, 0, 1).render(tween._time, true, true); initted = 1; } _onStart && _onStart.apply(tween, onStartParams || []); } }, vars)); return immediateRender ? tween.render(0) : tween; }; _proto2.tweenFromTo = function tweenFromTo(fromPosition, toPosition, vars) { return this.tweenTo(toPosition, _setDefaults({ startAt: { time: _parsePosition(this, fromPosition) } }, vars)); }; _proto2.recent = function recent() { return this._recent; }; _proto2.nextLabel = function nextLabel(afterTime) { if (afterTime === void 0) { afterTime = this._time; } return _getLabelInDirection(this, _parsePosition(this, afterTime)); }; _proto2.previousLabel = function previousLabel(beforeTime) { if (beforeTime === void 0) { beforeTime = this._time; } return _getLabelInDirection(this, _parsePosition(this, beforeTime), 1); }; _proto2.currentLabel = function currentLabel(value) { return arguments.length ? this.seek(value, true) : this.previousLabel(this._time + _tinyNum); }; _proto2.shiftChildren = function shiftChildren(amount, adjustLabels, ignoreBeforeTime) { if (ignoreBeforeTime === void 0) { ignoreBeforeTime = 0; } var child = this._first, labels = this.labels, p; while (child) { if (child._start >= ignoreBeforeTime) { child._start += amount; child._end += amount; } child = child._next; } if (adjustLabels) { for (p in labels) { if (labels[p] >= ignoreBeforeTime) { labels[p] += amount; } } } return _uncache(this); }; _proto2.invalidate = function invalidate(soft) { var child = this._first; this._lock = 0; while (child) { child.invalidate(soft); child = child._next; } return _Animation.prototype.invalidate.call(this, soft); }; _proto2.clear = function clear(includeLabels) { if (includeLabels === void 0) { includeLabels = true; } var child = this._first, next; while (child) { next = child._next; this.remove(child); child = next; } this._dp && (this._time = this._tTime = this._pTime = 0); includeLabels && (this.labels = {}); return _uncache(this); }; _proto2.totalDuration = function totalDuration(value) { var max = 0, self = this, child = self._last, prevStart = _bigNum, prev, start, parent; if (arguments.length) { return self.timeScale((self._repeat < 0 ? self.duration() : self.totalDuration()) / (self.reversed() ? -value : value)); } if (self._dirty) { parent = self.parent; while (child) { prev = child._prev; child._dirty && child.totalDuration(); start = child._start; if (start > prevStart && self._sort && child._ts && !self._lock) { self._lock = 1; _addToTimeline(self, child, start - child._delay, 1)._lock = 0; } else { prevStart = start; } if (start < 0 && child._ts) { max -= start; if (!parent && !self._dp || parent && parent.smoothChildTiming) { self._start += start / self._ts; self._time -= start; self._tTime -= start; } self.shiftChildren(-start, false, -1e999); prevStart = 0; } child._end > max && child._ts && (max = child._end); child = prev; } _setDuration(self, self === _globalTimeline && self._time > max ? self._time : max, 1, 1); self._dirty = 0; } return self._tDur; }; Timeline.updateRoot = function updateRoot(time) { if (_globalTimeline._ts) { _lazySafeRender(_globalTimeline, _parentToChildTotalTime(time, _globalTimeline)); _lastRenderedFrame = _ticker.frame; } if (_ticker.frame >= _nextGCFrame) { _nextGCFrame += _config.autoSleep || 120; var child = _globalTimeline._first; if (!child || !child._ts) if (_config.autoSleep && _ticker._listeners.length < 2) { while (child && !child._ts) { child = child._next; } child || _ticker.sleep(); } } }; return Timeline; }(Animation); _setDefaults(Timeline.prototype, { _lock: 0, _hasPause: 0, _forcing: 0 }); var _addComplexStringPropTween = function _addComplexStringPropTween(target, prop, start, end, setter, stringFilter, funcParam) { var pt = new PropTween(this._pt, target, prop, 0, 1, _renderComplexString, null, setter), index = 0, matchIndex = 0, result, startNums, color, endNum, chunk, startNum, hasRandom, a; pt.b = start; pt.e = end; start += ""; end += ""; if (hasRandom = ~end.indexOf("random(")) { end = _replaceRandom(end); } if (stringFilter) { a = [start, end]; stringFilter(a, target, prop); start = a[0]; end = a[1]; } startNums = start.match(_complexStringNumExp) || []; while (result = _complexStringNumExp.exec(end)) { endNum = result[0]; chunk = end.substring(index, result.index); if (color) { color = (color + 1) % 5; } else if (chunk.substr(-5) === "rgba(") { color = 1; } if (endNum !== startNums[matchIndex++]) { startNum = parseFloat(startNums[matchIndex - 1]) || 0; pt._pt = { _next: pt._pt, p: chunk || matchIndex === 1 ? chunk : ",", s: startNum, c: endNum.charAt(1) === "=" ? _parseRelative(startNum, endNum) - startNum : parseFloat(endNum) - startNum, m: color && color < 4 ? Math.round : 0 }; index = _complexStringNumExp.lastIndex; } } pt.c = index < end.length ? end.substring(index, end.length) : ""; pt.fp = funcParam; if (_relExp.test(end) || hasRandom) { pt.e = 0; } this._pt = pt; return pt; }, _addPropTween = function _addPropTween(target, prop, start, end, index, targets, modifier, stringFilter, funcParam, optional) { _isFunction(end) && (end = end(index || 0, target, targets)); var currentValue = target[prop], parsedStart = start !== "get" ? start : !_isFunction(currentValue) ? currentValue : funcParam ? target[prop.indexOf("set") || !_isFunction(target["get" + prop.substr(3)]) ? prop : "get" + prop.substr(3)](funcParam) : target[prop](), setter = !_isFunction(currentValue) ? _setterPlain : funcParam ? _setterFuncWithParam : _setterFunc, pt; if (_isString(end)) { if (~end.indexOf("random(")) { end = _replaceRandom(end); } if (end.charAt(1) === "=") { pt = _parseRelative(parsedStart, end) + (getUnit(parsedStart) || 0); if (pt || pt === 0) { end = pt; } } } if (!optional || parsedStart !== end || _forceAllPropTweens) { if (!isNaN(parsedStart * end) && end !== "") { pt = new PropTween(this._pt, target, prop, +parsedStart || 0, end - (parsedStart || 0), typeof currentValue === "boolean" ? _renderBoolean : _renderPlain, 0, setter); funcParam && (pt.fp = funcParam); modifier && pt.modifier(modifier, this, target); return this._pt = pt; } !currentValue && !(prop in target) && _missingPlugin(prop, end); return _addComplexStringPropTween.call(this, target, prop, parsedStart, end, setter, stringFilter || _config.stringFilter, funcParam); } }, _processVars = function _processVars(vars, index, target, targets, tween) { _isFunction(vars) && (vars = _parseFuncOrString(vars, tween, index, target, targets)); if (!_isObject(vars) || vars.style && vars.nodeType || _isArray(vars) || _isTypedArray(vars)) { return _isString(vars) ? _parseFuncOrString(vars, tween, index, target, targets) : vars; } var copy = {}, p; for (p in vars) { copy[p] = _parseFuncOrString(vars[p], tween, index, target, targets); } return copy; }, _checkPlugin = function _checkPlugin(property, vars, tween, index, target, targets) { var plugin, pt, ptLookup, i; if (_plugins[property] && (plugin = new _plugins[property]()).init(target, plugin.rawVars ? vars[property] : _processVars(vars[property], index, target, targets, tween), tween, index, targets) !== false) { tween._pt = pt = new PropTween(tween._pt, target, property, 0, 1, plugin.render, plugin, 0, plugin.priority); if (tween !== _quickTween) { ptLookup = tween._ptLookup[tween._targets.indexOf(target)]; i = plugin._props.length; while (i--) { ptLookup[plugin._props[i]] = pt; } } } return plugin; }, _overwritingTween, _forceAllPropTweens, _initTween = function _initTween(tween, time, tTime) { var vars = tween.vars, ease = vars.ease, startAt = vars.startAt, immediateRender = vars.immediateRender, lazy = vars.lazy, onUpdate = vars.onUpdate, onUpdateParams = vars.onUpdateParams, callbackScope = vars.callbackScope, runBackwards = vars.runBackwards, yoyoEase = vars.yoyoEase, keyframes = vars.keyframes, autoRevert = vars.autoRevert, dur = tween._dur, prevStartAt = tween._startAt, targets = tween._targets, parent = tween.parent, fullTargets = parent && parent.data === "nested" ? parent.vars.targets : targets, autoOverwrite = tween._overwrite === "auto" && !_suppressOverwrites, tl = tween.timeline, cleanVars, i, p, pt, target, hasPriority, gsData, harness, plugin, ptLookup, index, harnessVars, overwritten; tl && (!keyframes || !ease) && (ease = "none"); tween._ease = _parseEase(ease, _defaults.ease); tween._yEase = yoyoEase ? _invertEase(_parseEase(yoyoEase === true ? ease : yoyoEase, _defaults.ease)) : 0; if (yoyoEase && tween._yoyo && !tween._repeat) { yoyoEase = tween._yEase; tween._yEase = tween._ease; tween._ease = yoyoEase; } tween._from = !tl && !!vars.runBackwards; if (!tl || keyframes && !vars.stagger) { harness = targets[0] ? _getCache(targets[0]).harness : 0; harnessVars = harness && vars[harness.prop]; cleanVars = _copyExcluding(vars, _reservedProps); if (prevStartAt) { prevStartAt._zTime < 0 && prevStartAt.progress(1); time < 0 && runBackwards && immediateRender && !autoRevert ? prevStartAt.render(-1, true) : prevStartAt.revert(runBackwards && dur ? _revertConfigNoKill : _startAtRevertConfig); prevStartAt._lazy = 0; } if (startAt) { _removeFromParent(tween._startAt = Tween.set(targets, _setDefaults({ data: "isStart", overwrite: false, parent: parent, immediateRender: true, lazy: _isNotFalse(lazy), startAt: null, delay: 0, onUpdate: onUpdate, onUpdateParams: onUpdateParams, callbackScope: callbackScope, stagger: 0 }, startAt))); tween._startAt._dp = 0; time < 0 && (_reverting || !immediateRender && !autoRevert) && tween._startAt.revert(_revertConfigNoKill); if (immediateRender) { if (dur && time <= 0 && tTime <= 0) { time && (tween._zTime = time); return; } } } else if (runBackwards && dur) { if (!prevStartAt) { time && (immediateRender = false); p = _setDefaults({ overwrite: false, data: "isFromStart", lazy: immediateRender && _isNotFalse(lazy), immediateRender: immediateRender, stagger: 0, parent: parent }, cleanVars); harnessVars && (p[harness.prop] = harnessVars); _removeFromParent(tween._startAt = Tween.set(targets, p)); tween._startAt._dp = 0; time < 0 && (_reverting ? tween._startAt.revert(_revertConfigNoKill) : tween._startAt.render(-1, true)); tween._zTime = time; if (!immediateRender) { _initTween(tween._startAt, _tinyNum, _tinyNum); } else if (!time) { return; } } } tween._pt = tween._ptCache = 0; lazy = dur && _isNotFalse(lazy) || lazy && !dur; for (i = 0; i < targets.length; i++) { target = targets[i]; gsData = target._gsap || _harness(targets)[i]._gsap; tween._ptLookup[i] = ptLookup = {}; _lazyLookup[gsData.id] && _lazyTweens.length && _lazyRender(); index = fullTargets === targets ? i : fullTargets.indexOf(target); if (harness && (plugin = new harness()).init(target, harnessVars || cleanVars, tween, index, fullTargets) !== false) { tween._pt = pt = new PropTween(tween._pt, target, plugin.name, 0, 1, plugin.render, plugin, 0, plugin.priority); plugin._props.forEach(function (name) { ptLookup[name] = pt; }); plugin.priority && (hasPriority = 1); } if (!harness || harnessVars) { for (p in cleanVars) { if (_plugins[p] && (plugin = _checkPlugin(p, cleanVars, tween, index, target, fullTargets))) { plugin.priority && (hasPriority = 1); } else { ptLookup[p] = pt = _addPropTween.call(tween, target, p, "get", cleanVars[p], index, fullTargets, 0, vars.stringFilter); } } } tween._op && tween._op[i] && tween.kill(target, tween._op[i]); if (autoOverwrite && tween._pt) { _overwritingTween = tween; _globalTimeline.killTweensOf(target, ptLookup, tween.globalTime(time)); overwritten = !tween.parent; _overwritingTween = 0; } tween._pt && lazy && (_lazyLookup[gsData.id] = 1); } hasPriority && _sortPropTweensByPriority(tween); tween._onInit && tween._onInit(tween); } tween._onUpdate = onUpdate; tween._initted = (!tween._op || tween._pt) && !overwritten; keyframes && time <= 0 && tl.render(_bigNum, true, true); }, _updatePropTweens = function _updatePropTweens(tween, property, value, start, startIsRelative, ratio, time) { var ptCache = (tween._pt && tween._ptCache || (tween._ptCache = {}))[property], pt, rootPT, lookup, i; if (!ptCache) { ptCache = tween._ptCache[property] = []; lookup = tween._ptLookup; i = tween._targets.length; while (i--) { pt = lookup[i][property]; if (pt && pt.d && pt.d._pt) { pt = pt.d._pt; while (pt && pt.p !== property && pt.fp !== property) { pt = pt._next; } } if (!pt) { _forceAllPropTweens = 1; tween.vars[property] = "+=0"; _initTween(tween, time); _forceAllPropTweens = 0; return 1; } ptCache.push(pt); } } i = ptCache.length; while (i--) { rootPT = ptCache[i]; pt = rootPT._pt || rootPT; pt.s = (start || start === 0) && !startIsRelative ? start : pt.s + (start || 0) + ratio * pt.c; pt.c = value - pt.s; rootPT.e && (rootPT.e = _round(value) + getUnit(rootPT.e)); rootPT.b && (rootPT.b = pt.s + getUnit(rootPT.b)); } }, _addAliasesToVars = function _addAliasesToVars(targets, vars) { var harness = targets[0] ? _getCache(targets[0]).harness : 0, propertyAliases = harness && harness.aliases, copy, p, i, aliases; if (!propertyAliases) { return vars; } copy = _merge({}, vars); for (p in propertyAliases) { if (p in copy) { aliases = propertyAliases[p].split(","); i = aliases.length; while (i--) { copy[aliases[i]] = copy[p]; } } } return copy; }, _parseKeyframe = function _parseKeyframe(prop, obj, allProps, easeEach) { var ease = obj.ease || easeEach || "power1.inOut", p, a; if (_isArray(obj)) { a = allProps[prop] || (allProps[prop] = []); obj.forEach(function (value, i) { return a.push({ t: i / (obj.length - 1) * 100, v: value, e: ease }); }); } else { for (p in obj) { a = allProps[p] || (allProps[p] = []); p === "ease" || a.push({ t: parseFloat(prop), v: obj[p], e: ease }); } } }, _parseFuncOrString = function _parseFuncOrString(value, tween, i, target, targets) { return _isFunction(value) ? value.call(tween, i, target, targets) : _isString(value) && ~value.indexOf("random(") ? _replaceRandom(value) : value; }, _staggerTweenProps = _callbackNames + "repeat,repeatDelay,yoyo,repeatRefresh,yoyoEase,autoRevert", _staggerPropsToSkip = {}; _forEachName(_staggerTweenProps + ",id,stagger,delay,duration,paused,scrollTrigger", function (name) { return _staggerPropsToSkip[name] = 1; }); var Tween = function (_Animation2) { _inheritsLoose(Tween, _Animation2); function Tween(targets, vars, position, skipInherit) { var _this3; if (typeof vars === "number") { position.duration = vars; vars = position; position = null; } _this3 = _Animation2.call(this, skipInherit ? vars : _inheritDefaults(vars)) || this; var _this3$vars = _this3.vars, duration = _this3$vars.duration, delay = _this3$vars.delay, immediateRender = _this3$vars.immediateRender, stagger = _this3$vars.stagger, overwrite = _this3$vars.overwrite, keyframes = _this3$vars.keyframes, defaults = _this3$vars.defaults, scrollTrigger = _this3$vars.scrollTrigger, yoyoEase = _this3$vars.yoyoEase, parent = vars.parent || _globalTimeline, parsedTargets = (_isArray(targets) || _isTypedArray(targets) ? _isNumber(targets[0]) : "length" in vars) ? [targets] : toArray(targets), tl, i, copy, l, p, curTarget, staggerFunc, staggerVarsToMerge; _this3._targets = parsedTargets.length ? _harness(parsedTargets) : _warn("GSAP target " + targets + " not found. https://greensock.com", !_config.nullTargetWarn) || []; _this3._ptLookup = []; _this3._overwrite = overwrite; if (keyframes || stagger || _isFuncOrString(duration) || _isFuncOrString(delay)) { vars = _this3.vars; tl = _this3.timeline = new Timeline({ data: "nested", defaults: defaults || {}, targets: parent && parent.data === "nested" ? parent.vars.targets : parsedTargets }); tl.kill(); tl.parent = tl._dp = _assertThisInitialized(_this3); tl._start = 0; if (stagger || _isFuncOrString(duration) || _isFuncOrString(delay)) { l = parsedTargets.length; staggerFunc = stagger && distribute(stagger); if (_isObject(stagger)) { for (p in stagger) { if (~_staggerTweenProps.indexOf(p)) { staggerVarsToMerge || (staggerVarsToMerge = {}); staggerVarsToMerge[p] = stagger[p]; } } } for (i = 0; i < l; i++) { copy = _copyExcluding(vars, _staggerPropsToSkip); copy.stagger = 0; yoyoEase && (copy.yoyoEase = yoyoEase); staggerVarsToMerge && _merge(copy, staggerVarsToMerge); curTarget = parsedTargets[i]; copy.duration = +_parseFuncOrString(duration, _assertThisInitialized(_this3), i, curTarget, parsedTargets); copy.delay = (+_parseFuncOrString(delay, _assertThisInitialized(_this3), i, curTarget, parsedTargets) || 0) - _this3._delay; if (!stagger && l === 1 && copy.delay) { _this3._delay = delay = copy.delay; _this3._start += delay; copy.delay = 0; } tl.to(curTarget, copy, staggerFunc ? staggerFunc(i, curTarget, parsedTargets) : 0); tl._ease = _easeMap.none; } tl.duration() ? duration = delay = 0 : _this3.timeline = 0; } else if (keyframes) { _inheritDefaults(_setDefaults(tl.vars.defaults, { ease: "none" })); tl._ease = _parseEase(keyframes.ease || vars.ease || "none"); var time = 0, a, kf, v; if (_isArray(keyframes)) { keyframes.forEach(function (frame) { return tl.to(parsedTargets, frame, ">"); }); tl.duration(); } else { copy = {}; for (p in keyframes) { p === "ease" || p === "easeEach" || _parseKeyframe(p, keyframes[p], copy, keyframes.easeEach); } for (p in copy) { a = copy[p].sort(function (a, b) { return a.t - b.t; }); time = 0; for (i = 0; i < a.length; i++) { kf = a[i]; v = { ease: kf.e, duration: (kf.t - (i ? a[i - 1].t : 0)) / 100 * duration }; v[p] = kf.v; tl.to(parsedTargets, v, time); time += v.duration; } } tl.duration() < duration && tl.to({}, { duration: duration - tl.duration() }); } } duration || _this3.duration(duration = tl.duration()); } else { _this3.timeline = 0; } if (overwrite === true && !_suppressOverwrites) { _overwritingTween = _assertThisInitialized(_this3); _globalTimeline.killTweensOf(parsedTargets); _overwritingTween = 0; } _addToTimeline(parent, _assertThisInitialized(_this3), position); vars.reversed && _this3.reverse(); vars.paused && _this3.paused(true); if (immediateRender || !duration && !keyframes && _this3._start === _roundPrecise(parent._time) && _isNotFalse(immediateRender) && _hasNoPausedAncestors(_assertThisInitialized(_this3)) && parent.data !== "nested") { _this3._tTime = -_tinyNum; _this3.render(Math.max(0, -delay) || 0); } scrollTrigger && _scrollTrigger(_assertThisInitialized(_this3), scrollTrigger); return _this3; } var _proto3 = Tween.prototype; _proto3.render = function render(totalTime, suppressEvents, force) { var prevTime = this._time, tDur = this._tDur, dur = this._dur, isNegative = totalTime < 0, tTime = totalTime > tDur - _tinyNum && !isNegative ? tDur : totalTime < _tinyNum ? 0 : totalTime, time, pt, iteration, cycleDuration, prevIteration, isYoyo, ratio, timeline, yoyoEase; if (!dur) { _renderZeroDurationTween(this, totalTime, suppressEvents, force); } else if (tTime !== this._tTime || !totalTime || force || !this._initted && this._tTime || this._startAt && this._zTime < 0 !== isNegative) { time = tTime; timeline = this.timeline; if (this._repeat) { cycleDuration = dur + this._rDelay; if (this._repeat < -1 && isNegative) { return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force); } time = _roundPrecise(tTime % cycleDuration); if (tTime === tDur) { iteration = this._repeat; time = dur; } else { iteration = ~~(tTime / cycleDuration); if (iteration && iteration === tTime / cycleDuration) { time = dur; iteration--; } time > dur && (time = dur); } isYoyo = this._yoyo && iteration & 1; if (isYoyo) { yoyoEase = this._yEase; time = dur - time; } prevIteration = _animationCycle(this._tTime, cycleDuration); if (time === prevTime && !force && this._initted) { this._tTime = tTime; return this; } if (iteration !== prevIteration) { timeline && this._yEase && _propagateYoyoEase(timeline, isYoyo); if (this.vars.repeatRefresh && !isYoyo && !this._lock) { this._lock = force = 1; this.render(_roundPrecise(cycleDuration * iteration), true).invalidate()._lock = 0; } } } if (!this._initted) { if (_attemptInitTween(this, isNegative ? totalTime : time, force, suppressEvents, tTime)) { this._tTime = 0; return this; } if (prevTime !== this._time) { return this; } if (dur !== this._dur) { return this.render(totalTime, suppressEvents, force); } } this._tTime = tTime; this._time = time; if (!this._act && this._ts) { this._act = 1; this._lazy = 0; } this.ratio = ratio = (yoyoEase || this._ease)(time / dur); if (this._from) { this.ratio = ratio = 1 - ratio; } if (time && !prevTime && !suppressEvents) { _callback(this, "onStart"); if (this._tTime !== tTime) { return this; } } pt = this._pt; while (pt) { pt.r(ratio, pt.d); pt = pt._next; } timeline && timeline.render(totalTime < 0 ? totalTime : !time && isYoyo ? -_tinyNum : timeline._dur * timeline._ease(time / this._dur), suppressEvents, force) || this._startAt && (this._zTime = totalTime); if (this._onUpdate && !suppressEvents) { isNegative && _rewindStartAt(this, totalTime, suppressEvents, force); _callback(this, "onUpdate"); } this._repeat && iteration !== prevIteration && this.vars.onRepeat && !suppressEvents && this.parent && _callback(this, "onRepeat"); if ((tTime === this._tDur || !tTime) && this._tTime === tTime) { isNegative && !this._onUpdate && _rewindStartAt(this, totalTime, true, true); (totalTime || !dur) && (tTime === this._tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1); if (!suppressEvents && !(isNegative && !prevTime) && (tTime || prevTime || isYoyo)) { _callback(this, tTime === tDur ? "onComplete" : "onReverseComplete", true); this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom(); } } } return this; }; _proto3.targets = function targets() { return this._targets; }; _proto3.invalidate = function invalidate(soft) { (!soft || !this.vars.runBackwards) && (this._startAt = 0); this._pt = this._op = this._onUpdate = this._lazy = this.ratio = 0; this._ptLookup = []; this.timeline && this.timeline.invalidate(soft); return _Animation2.prototype.invalidate.call(this, soft); }; _proto3.resetTo = function resetTo(property, value, start, startIsRelative) { _tickerActive || _ticker.wake(); this._ts || this.play(); var time = Math.min(this._dur, (this._dp._time - this._start) * this._ts), ratio; this._initted || _initTween(this, time); ratio = this._ease(time / this._dur); if (_updatePropTweens(this, property, value, start, startIsRelative, ratio, time)) { return this.resetTo(property, value, start, startIsRelative); } _alignPlayhead(this, 0); this.parent || _addLinkedListItem(this._dp, this, "_first", "_last", this._dp._sort ? "_start" : 0); return this.render(0); }; _proto3.kill = function kill(targets, vars) { if (vars === void 0) { vars = "all"; } if (!targets && (!vars || vars === "all")) { this._lazy = this._pt = 0; return this.parent ? _interrupt(this) : this; } if (this.timeline) { var tDur = this.timeline.totalDuration(); this.timeline.killTweensOf(targets, vars, _overwritingTween && _overwritingTween.vars.overwrite !== true)._first || _interrupt(this); this.parent && tDur !== this.timeline.totalDuration() && _setDuration(this, this._dur * this.timeline._tDur / tDur, 0, 1); return this; } var parsedTargets = this._targets, killingTargets = targets ? toArray(targets) : parsedTargets, propTweenLookup = this._ptLookup, firstPT = this._pt, overwrittenProps, curLookup, curOverwriteProps, props, p, pt, i; if ((!vars || vars === "all") && _arraysMatch(parsedTargets, killingTargets)) { vars === "all" && (this._pt = 0); return _interrupt(this); } overwrittenProps = this._op = this._op || []; if (vars !== "all") { if (_isString(vars)) { p = {}; _forEachName(vars, function (name) { return p[name] = 1; }); vars = p; } vars = _addAliasesToVars(parsedTargets, vars); } i = parsedTargets.length; while (i--) { if (~killingTargets.indexOf(parsedTargets[i])) { curLookup = propTweenLookup[i]; if (vars === "all") { overwrittenProps[i] = vars; props = curLookup; curOverwriteProps = {}; } else { curOverwriteProps = overwrittenProps[i] = overwrittenProps[i] || {}; props = vars; } for (p in props) { pt = curLookup && curLookup[p]; if (pt) { if (!("kill" in pt.d) || pt.d.kill(p) === true) { _removeLinkedListItem(this, pt, "_pt"); } delete curLookup[p]; } if (curOverwriteProps !== "all") { curOverwriteProps[p] = 1; } } } } this._initted && !this._pt && firstPT && _interrupt(this); return this; }; Tween.to = function to(targets, vars) { return new Tween(targets, vars, arguments[2]); }; Tween.from = function from(targets, vars) { return _createTweenType(1, arguments); }; Tween.delayedCall = function delayedCall(delay, callback, params, scope) { return new Tween(callback, 0, { immediateRender: false, lazy: false, overwrite: false, delay: delay, onComplete: callback, onReverseComplete: callback, onCompleteParams: params, onReverseCompleteParams: params, callbackScope: scope }); }; Tween.fromTo = function fromTo(targets, fromVars, toVars) { return _createTweenType(2, arguments); }; Tween.set = function set(targets, vars) { vars.duration = 0; vars.repeatDelay || (vars.repeat = 0); return new Tween(targets, vars); }; Tween.killTweensOf = function killTweensOf(targets, props, onlyActive) { return _globalTimeline.killTweensOf(targets, props, onlyActive); }; return Tween; }(Animation); _setDefaults(Tween.prototype, { _targets: [], _lazy: 0, _startAt: 0, _op: 0, _onInit: 0 }); _forEachName("staggerTo,staggerFrom,staggerFromTo", function (name) { Tween[name] = function () { var tl = new Timeline(), params = _slice.call(arguments, 0); params.splice(name === "staggerFromTo" ? 5 : 4, 0, 0); return tl[name].apply(tl, params); }; }); var _setterPlain = function _setterPlain(target, property, value) { return target[property] = value; }, _setterFunc = function _setterFunc(target, property, value) { return target[property](value); }, _setterFuncWithParam = function _setterFuncWithParam(target, property, value, data) { return target[property](data.fp, value); }, _setterAttribute = function _setterAttribute(target, property, value) { return target.setAttribute(property, value); }, _getSetter = function _getSetter(target, property) { return _isFunction(target[property]) ? _setterFunc : _isUndefined(target[property]) && target.setAttribute ? _setterAttribute : _setterPlain; }, _renderPlain = function _renderPlain(ratio, data) { return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 1000000) / 1000000, data); }, _renderBoolean = function _renderBoolean(ratio, data) { return data.set(data.t, data.p, !!(data.s + data.c * ratio), data); }, _renderComplexString = function _renderComplexString(ratio, data) { var pt = data._pt, s = ""; if (!ratio && data.b) { s = data.b; } else if (ratio === 1 && data.e) { s = data.e; } else { while (pt) { s = pt.p + (pt.m ? pt.m(pt.s + pt.c * ratio) : Math.round((pt.s + pt.c * ratio) * 10000) / 10000) + s; pt = pt._next; } s += data.c; } data.set(data.t, data.p, s, data); }, _renderPropTweens = function _renderPropTweens(ratio, data) { var pt = data._pt; while (pt) { pt.r(ratio, pt.d); pt = pt._next; } }, _addPluginModifier = function _addPluginModifier(modifier, tween, target, property) { var pt = this._pt, next; while (pt) { next = pt._next; pt.p === property && pt.modifier(modifier, tween, target); pt = next; } }, _killPropTweensOf = function _killPropTweensOf(property) { var pt = this._pt, hasNonDependentRemaining, next; while (pt) { next = pt._next; if (pt.p === property && !pt.op || pt.op === property) { _removeLinkedListItem(this, pt, "_pt"); } else if (!pt.dep) { hasNonDependentRemaining = 1; } pt = next; } return !hasNonDependentRemaining; }, _setterWithModifier = function _setterWithModifier(target, property, value, data) { data.mSet(target, property, data.m.call(data.tween, value, data.mt), data); }, _sortPropTweensByPriority = function _sortPropTweensByPriority(parent) { var pt = parent._pt, next, pt2, first, last; while (pt) { next = pt._next; pt2 = first; while (pt2 && pt2.pr > pt.pr) { pt2 = pt2._next; } if (pt._prev = pt2 ? pt2._prev : last) { pt._prev._next = pt; } else { first = pt; } if (pt._next = pt2) { pt2._prev = pt; } else { last = pt; } pt = next; } parent._pt = first; }; var PropTween = function () { function PropTween(next, target, prop, start, change, renderer, data, setter, priority) { this.t = target; this.s = start; this.c = change; this.p = prop; this.r = renderer || _renderPlain; this.d = data || this; this.set = setter || _setterPlain; this.pr = priority || 0; this._next = next; if (next) { next._prev = this; } } var _proto4 = PropTween.prototype; _proto4.modifier = function modifier(func, tween, target) { this.mSet = this.mSet || this.set; this.set = _setterWithModifier; this.m = func; this.mt = target; this.tween = tween; }; return PropTween; }(); _forEachName(_callbackNames + "parent,duration,ease,delay,overwrite,runBackwards,startAt,yoyo,immediateRender,repeat,repeatDelay,data,paused,reversed,lazy,callbackScope,stringFilter,id,yoyoEase,stagger,inherit,repeatRefresh,keyframes,autoRevert,scrollTrigger", function (name) { return _reservedProps[name] = 1; }); _globals.TweenMax = _globals.TweenLite = Tween; _globals.TimelineLite = _globals.TimelineMax = Timeline; _globalTimeline = new Timeline({ sortChildren: false, defaults: _defaults, autoRemoveChildren: true, id: "root", smoothChildTiming: true }); _config.stringFilter = _colorStringFilter; var _media = [], _listeners = {}, _emptyArray = [], _lastMediaTime = 0, _dispatch = function _dispatch(type) { return (_listeners[type] || _emptyArray).map(function (f) { return f(); }); }, _onMediaChange = function _onMediaChange() { var time = Date.now(), matches = []; if (time - _lastMediaTime > 2) { _dispatch("matchMediaInit"); _media.forEach(function (c) { var queries = c.queries, conditions = c.conditions, match, p, anyMatch, toggled; for (p in queries) { match = _win.matchMedia(queries[p]).matches; match && (anyMatch = 1); if (match !== conditions[p]) { conditions[p] = match; toggled = 1; } } if (toggled) { c.revert(); anyMatch && matches.push(c); } }); _dispatch("matchMediaRevert"); matches.forEach(function (c) { return c.onMatch(c); }); _lastMediaTime = time; _dispatch("matchMedia"); } }; var Context = function () { function Context(func, scope) { this.selector = scope && selector(scope); this.data = []; this._r = []; this.isReverted = false; func && this.add(func); } var _proto5 = Context.prototype; _proto5.add = function add(name, func, scope) { if (_isFunction(name)) { scope = func; func = name; name = _isFunction; } var self = this, f = function f() { var prev = _context, prevSelector = self.selector, result; prev && prev !== self && prev.data.push(self); scope && (self.selector = selector(scope)); _context = self; result = func.apply(self, arguments); _isFunction(result) && self._r.push(result); _context = prev; self.selector = prevSelector; self.isReverted = false; return result; }; self.last = f; return name === _isFunction ? f(self) : name ? self[name] = f : f; }; _proto5.ignore = function ignore(func) { var prev = _context; _context = null; func(this); _context = prev; }; _proto5.getTweens = function getTweens() { var a = []; this.data.forEach(function (e) { return e instanceof Context ? a.push.apply(a, e.getTweens()) : e instanceof Tween && !(e.parent && e.parent.data === "nested") && a.push(e); }); return a; }; _proto5.clear = function clear() { this._r.length = this.data.length = 0; }; _proto5.kill = function kill(revert, matchMedia) { var _this4 = this; if (revert) { var tweens = this.getTweens(); this.data.forEach(function (t) { if (t.data === "isFlip") { t.revert(); t.getChildren(true, true, false).forEach(function (tween) { return tweens.splice(tweens.indexOf(tween), 1); }); } }); tweens.map(function (t) { return { g: t.globalTime(0), t: t }; }).sort(function (a, b) { return b.g - a.g || -1; }).forEach(function (o) { return o.t.revert(revert); }); this.data.forEach(function (e) { return !(e instanceof Animation) && e.revert && e.revert(revert); }); this._r.forEach(function (f) { return f(revert, _this4); }); this.isReverted = true; } else { this.data.forEach(function (e) { return e.kill && e.kill(); }); } this.clear(); if (matchMedia) { var i = _media.indexOf(this); !!~i && _media.splice(i, 1); } }; _proto5.revert = function revert(config) { this.kill(config || {}); }; return Context; }(); var MatchMedia = function () { function MatchMedia(scope) { this.contexts = []; this.scope = scope; } var _proto6 = MatchMedia.prototype; _proto6.add = function add(conditions, func, scope) { _isObject(conditions) || (conditions = { matches: conditions }); var context = new Context(0, scope || this.scope), cond = context.conditions = {}, mq, p, active; this.contexts.push(context); func = context.add("onMatch", func); context.queries = conditions; for (p in conditions) { if (p === "all") { active = 1; } else { mq = _win.matchMedia(conditions[p]); if (mq) { _media.indexOf(context) < 0 && _media.push(context); (cond[p] = mq.matches) && (active = 1); mq.addListener ? mq.addListener(_onMediaChange) : mq.addEventListener("change", _onMediaChange); } } } active && func(context); return this; }; _proto6.revert = function revert(config) { this.kill(config || {}); }; _proto6.kill = function kill(revert) { this.contexts.forEach(function (c) { return c.kill(revert, true); }); }; return MatchMedia; }(); var _gsap = { registerPlugin: function registerPlugin() { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } args.forEach(function (config) { return _createPlugin(config); }); }, timeline: function timeline(vars) { return new Timeline(vars); }, getTweensOf: function getTweensOf(targets, onlyActive) { return _globalTimeline.getTweensOf(targets, onlyActive); }, getProperty: function getProperty(target, property, unit, uncache) { _isString(target) && (target = toArray(target)[0]); var getter = _getCache(target || {}).get, format = unit ? _passThrough : _numericIfPossible; unit === "native" && (unit = ""); return !target ? target : !property ? function (property, unit, uncache) { return format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache)); } : format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache)); }, quickSetter: function quickSetter(target, property, unit) { target = toArray(target); if (target.length > 1) { var setters = target.map(function (t) { return gsap.quickSetter(t, property, unit); }), l = setters.length; return function (value) { var i = l; while (i--) { setters[i](value); } }; } target = target[0] || {}; var Plugin = _plugins[property], cache = _getCache(target), p = cache.harness && (cache.harness.aliases || {})[property] || property, setter = Plugin ? function (value) { var p = new Plugin(); _quickTween._pt = 0; p.init(target, unit ? value + unit : value, _quickTween, 0, [target]); p.render(1, p); _quickTween._pt && _renderPropTweens(1, _quickTween); } : cache.set(target, p); return Plugin ? setter : function (value) { return setter(target, p, unit ? value + unit : value, cache, 1); }; }, quickTo: function quickTo(target, property, vars) { var _merge2; var tween = gsap.to(target, _merge((_merge2 = {}, _merge2[property] = "+=0.1", _merge2.paused = true, _merge2), vars || {})), func = function func(value, start, startIsRelative) { return tween.resetTo(property, value, start, startIsRelative); }; func.tween = tween; return func; }, isTweening: function isTweening(targets) { return _globalTimeline.getTweensOf(targets, true).length > 0; }, defaults: function defaults(value) { value && value.ease && (value.ease = _parseEase(value.ease, _defaults.ease)); return _mergeDeep(_defaults, value || {}); }, config: function config(value) { return _mergeDeep(_config, value || {}); }, registerEffect: function registerEffect(_ref3) { var name = _ref3.name, effect = _ref3.effect, plugins = _ref3.plugins, defaults = _ref3.defaults, extendTimeline = _ref3.extendTimeline; (plugins || "").split(",").forEach(function (pluginName) { return pluginName && !_plugins[pluginName] && !_globals[pluginName] && _warn(name + " effect requires " + pluginName + " plugin."); }); _effects[name] = function (targets, vars, tl) { return effect(toArray(targets), _setDefaults(vars || {}, defaults), tl); }; if (extendTimeline) { Timeline.prototype[name] = function (targets, vars, position) { return this.add(_effects[name](targets, _isObject(vars) ? vars : (position = vars) && {}, this), position); }; } }, registerEase: function registerEase(name, ease) { _easeMap[name] = _parseEase(ease); }, parseEase: function parseEase(ease, defaultEase) { return arguments.length ? _parseEase(ease, defaultEase) : _easeMap; }, getById: function getById(id) { return _globalTimeline.getById(id); }, exportRoot: function exportRoot(vars, includeDelayedCalls) { if (vars === void 0) { vars = {}; } var tl = new Timeline(vars), child, next; tl.smoothChildTiming = _isNotFalse(vars.smoothChildTiming); _globalTimeline.remove(tl); tl._dp = 0; tl._time = tl._tTime = _globalTimeline._time; child = _globalTimeline._first; while (child) { next = child._next; if (includeDelayedCalls || !(!child._dur && child instanceof Tween && child.vars.onComplete === child._targets[0])) { _addToTimeline(tl, child, child._start - child._delay); } child = next; } _addToTimeline(_globalTimeline, tl, 0); return tl; }, context: function context(func, scope) { return func ? new Context(func, scope) : _context; }, matchMedia: function matchMedia(scope) { return new MatchMedia(scope); }, matchMediaRefresh: function matchMediaRefresh() { return _media.forEach(function (c) { var cond = c.conditions, found, p; for (p in cond) { if (cond[p]) { cond[p] = false; found = 1; } } found && c.revert(); }) || _onMediaChange(); }, addEventListener: function addEventListener(type, callback) { var a = _listeners[type] || (_listeners[type] = []); ~a.indexOf(callback) || a.push(callback); }, removeEventListener: function removeEventListener(type, callback) { var a = _listeners[type], i = a && a.indexOf(callback); i >= 0 && a.splice(i, 1); }, utils: { wrap: wrap, wrapYoyo: wrapYoyo, distribute: distribute, random: random, snap: snap, normalize: normalize, getUnit: getUnit, clamp: clamp, splitColor: splitColor, toArray: toArray, selector: selector, mapRange: mapRange, pipe: pipe, unitize: unitize, interpolate: interpolate, shuffle: shuffle }, install: _install, effects: _effects, ticker: _ticker, updateRoot: Timeline.updateRoot, plugins: _plugins, globalTimeline: _globalTimeline, core: { PropTween: PropTween, globals: _addGlobal, Tween: Tween, Timeline: Timeline, Animation: Animation, getCache: _getCache, _removeLinkedListItem: _removeLinkedListItem, reverting: function reverting() { return _reverting; }, context: function context(toAdd) { if (toAdd && _context) { _context.data.push(toAdd); toAdd._ctx = _context; } return _context; }, suppressOverwrites: function suppressOverwrites(value) { return _suppressOverwrites = value; } } }; _forEachName("to,from,fromTo,delayedCall,set,killTweensOf", function (name) { return _gsap[name] = Tween[name]; }); _ticker.add(Timeline.updateRoot); _quickTween = _gsap.to({}, { duration: 0 }); var _getPluginPropTween = function _getPluginPropTween(plugin, prop) { var pt = plugin._pt; while (pt && pt.p !== prop && pt.op !== prop && pt.fp !== prop) { pt = pt._next; } return pt; }, _addModifiers = function _addModifiers(tween, modifiers) { var targets = tween._targets, p, i, pt; for (p in modifiers) { i = targets.length; while (i--) { pt = tween._ptLookup[i][p]; if (pt && (pt = pt.d)) { if (pt._pt) { pt = _getPluginPropTween(pt, p); } pt && pt.modifier && pt.modifier(modifiers[p], tween, targets[i], p); } } } }, _buildModifierPlugin = function _buildModifierPlugin(name, modifier) { return { name: name, rawVars: 1, init: function init(target, vars, tween) { tween._onInit = function (tween) { var temp, p; if (_isString(vars)) { temp = {}; _forEachName(vars, function (name) { return temp[name] = 1; }); vars = temp; } if (modifier) { temp = {}; for (p in vars) { temp[p] = modifier(vars[p]); } vars = temp; } _addModifiers(tween, vars); }; } }; }; var gsap = _gsap.registerPlugin({ name: "attr", init: function init(target, vars, tween, index, targets) { var p, pt, v; this.tween = tween; for (p in vars) { v = target.getAttribute(p) || ""; pt = this.add(target, "setAttribute", (v || 0) + "", vars[p], index, targets, 0, 0, p); pt.op = p; pt.b = v; this._props.push(p); } }, render: function render(ratio, data) { var pt = data._pt; while (pt) { _reverting ? pt.set(pt.t, pt.p, pt.b, pt) : pt.r(ratio, pt.d); pt = pt._next; } } }, { name: "endArray", init: function init(target, value) { var i = value.length; while (i--) { this.add(target, i, target[i] || 0, value[i], 0, 0, 0, 0, 0, 1); } } }, _buildModifierPlugin("roundProps", _roundModifier), _buildModifierPlugin("modifiers"), _buildModifierPlugin("snap", snap)) || _gsap; Tween.version = Timeline.version = gsap.version = "3.11.3"; _coreReady = 1; _windowExists() && _wake(); var Power0 = _easeMap.Power0, Power1 = _easeMap.Power1, Power2 = _easeMap.Power2, Power3 = _easeMap.Power3, Power4 = _easeMap.Power4, Linear = _easeMap.Linear, Quad = _easeMap.Quad, Cubic = _easeMap.Cubic, Quart = _easeMap.Quart, Quint = _easeMap.Quint, Strong = _easeMap.Strong, Elastic = _easeMap.Elastic, Back = _easeMap.Back, SteppedEase = _easeMap.SteppedEase, Bounce = _easeMap.Bounce, Sine = _easeMap.Sine, Expo = _easeMap.Expo, Circ = _easeMap.Circ; var _win$1, _doc$1, _docElement, _pluginInitted, _tempDiv, _tempDivStyler, _recentSetterPlugin, _reverting$1, _windowExists$1 = function _windowExists() { return typeof window !== "undefined"; }, _transformProps = {}, _RAD2DEG = 180 / Math.PI, _DEG2RAD = Math.PI / 180, _atan2 = Math.atan2, _bigNum$1 = 1e8, _capsExp = /([A-Z])/g, _horizontalExp = /(left|right|width|margin|padding|x)/i, _complexExp = /[\s,\(]\S/, _propertyAliases = { autoAlpha: "opacity,visibility", scale: "scaleX,scaleY", alpha: "opacity" }, _renderCSSProp = function _renderCSSProp(ratio, data) { return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data); }, _renderPropWithEnd = function _renderPropWithEnd(ratio, data) { return data.set(data.t, data.p, ratio === 1 ? data.e : Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data); }, _renderCSSPropWithBeginning = function _renderCSSPropWithBeginning(ratio, data) { return data.set(data.t, data.p, ratio ? Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u : data.b, data); }, _renderRoundedCSSProp = function _renderRoundedCSSProp(ratio, data) { var value = data.s + data.c * ratio; data.set(data.t, data.p, ~~(value + (value < 0 ? -.5 : .5)) + data.u, data); }, _renderNonTweeningValue = function _renderNonTweeningValue(ratio, data) { return data.set(data.t, data.p, ratio ? data.e : data.b, data); }, _renderNonTweeningValueOnlyAtEnd = function _renderNonTweeningValueOnlyAtEnd(ratio, data) { return data.set(data.t, data.p, ratio !== 1 ? data.b : data.e, data); }, _setterCSSStyle = function _setterCSSStyle(target, property, value) { return target.style[property] = value; }, _setterCSSProp = function _setterCSSProp(target, property, value) { return target.style.setProperty(property, value); }, _setterTransform = function _setterTransform(target, property, value) { return target._gsap[property] = value; }, _setterScale = function _setterScale(target, property, value) { return target._gsap.scaleX = target._gsap.scaleY = value; }, _setterScaleWithRender = function _setterScaleWithRender(target, property, value, data, ratio) { var cache = target._gsap; cache.scaleX = cache.scaleY = value; cache.renderTransform(ratio, cache); }, _setterTransformWithRender = function _setterTransformWithRender(target, property, value, data, ratio) { var cache = target._gsap; cache[property] = value; cache.renderTransform(ratio, cache); }, _transformProp = "transform", _transformOriginProp = _transformProp + "Origin", _saveStyle = function _saveStyle(property, isNotCSS) { var _this = this; var target = this.target, style = target.style; if (property in _transformProps) { this.tfm = this.tfm || {}; if (property !== "transform") { property = _propertyAliases[property] || property; ~property.indexOf(",") ? property.split(",").forEach(function (a) { return _this.tfm[a] = _get(target, a); }) : this.tfm[property] = target._gsap.x ? target._gsap[property] : _get(target, property); } if (this.props.indexOf(_transformProp) >= 0) { return; } if (target._gsap.svg) { this.svgo = target.getAttribute("data-svg-origin"); this.props.push(_transformOriginProp, isNotCSS, ""); } property = _transformProp; } (style || isNotCSS) && this.props.push(property, isNotCSS, style[property]); }, _removeIndependentTransforms = function _removeIndependentTransforms(style) { if (style.translate) { style.removeProperty("translate"); style.removeProperty("scale"); style.removeProperty("rotate"); } }, _revertStyle = function _revertStyle() { var props = this.props, target = this.target, style = target.style, cache = target._gsap, i, p; for (i = 0; i < props.length; i += 3) { props[i + 1] ? target[props[i]] = props[i + 2] : props[i + 2] ? style[props[i]] = props[i + 2] : style.removeProperty(props[i].replace(_capsExp, "-$1").toLowerCase()); } if (this.tfm) { for (p in this.tfm) { cache[p] = this.tfm[p]; } if (cache.svg) { cache.renderTransform(); target.setAttribute("data-svg-origin", this.svgo || ""); } i = _reverting$1(); if (i && !i.isStart && !style[_transformProp]) { _removeIndependentTransforms(style); cache.uncache = 1; } } }, _getStyleSaver = function _getStyleSaver(target, properties) { var saver = { target: target, props: [], revert: _revertStyle, save: _saveStyle }; properties && properties.split(",").forEach(function (p) { return saver.save(p); }); return saver; }, _supports3D, _createElement = function _createElement(type, ns) { var e = _doc$1.createElementNS ? _doc$1.createElementNS((ns || "http://www.w3.org/1999/xhtml").replace(/^https/, "http"), type) : _doc$1.createElement(type); return e.style ? e : _doc$1.createElement(type); }, _getComputedProperty = function _getComputedProperty(target, property, skipPrefixFallback) { var cs = getComputedStyle(target); return cs[property] || cs.getPropertyValue(property.replace(_capsExp, "-$1").toLowerCase()) || cs.getPropertyValue(property) || !skipPrefixFallback && _getComputedProperty(target, _checkPropPrefix(property) || property, 1) || ""; }, _prefixes = "O,Moz,ms,Ms,Webkit".split(","), _checkPropPrefix = function _checkPropPrefix(property, element, preferPrefix) { var e = element || _tempDiv, s = e.style, i = 5; if (property in s && !preferPrefix) { return property; } property = property.charAt(0).toUpperCase() + property.substr(1); while (i-- && !(_prefixes[i] + property in s)) {} return i < 0 ? null : (i === 3 ? "ms" : i >= 0 ? _prefixes[i] : "") + property; }, _initCore = function _initCore() { if (_windowExists$1() && window.document) { _win$1 = window; _doc$1 = _win$1.document; _docElement = _doc$1.documentElement; _tempDiv = _createElement("div") || { style: {} }; _tempDivStyler = _createElement("div"); _transformProp = _checkPropPrefix(_transformProp); _transformOriginProp = _transformProp + "Origin"; _tempDiv.style.cssText = "border-width:0;line-height:0;position:absolute;padding:0"; _supports3D = !!_checkPropPrefix("perspective"); _reverting$1 = gsap.core.reverting; _pluginInitted = 1; } }, _getBBoxHack = function _getBBoxHack(swapIfPossible) { var svg = _createElement("svg", this.ownerSVGElement && this.ownerSVGElement.getAttribute("xmlns") || "http://www.w3.org/2000/svg"), oldParent = this.parentNode, oldSibling = this.nextSibling, oldCSS = this.style.cssText, bbox; _docElement.appendChild(svg); svg.appendChild(this); this.style.display = "block"; if (swapIfPossible) { try { bbox = this.getBBox(); this._gsapBBox = this.getBBox; this.getBBox = _getBBoxHack; } catch (e) {} } else if (this._gsapBBox) { bbox = this._gsapBBox(); } if (oldParent) { if (oldSibling) { oldParent.insertBefore(this, oldSibling); } else { oldParent.appendChild(this); } } _docElement.removeChild(svg); this.style.cssText = oldCSS; return bbox; }, _getAttributeFallbacks = function _getAttributeFallbacks(target, attributesArray) { var i = attributesArray.length; while (i--) { if (target.hasAttribute(attributesArray[i])) { return target.getAttribute(attributesArray[i]); } } }, _getBBox = function _getBBox(target) { var bounds; try { bounds = target.getBBox(); } catch (error) { bounds = _getBBoxHack.call(target, true); } bounds && (bounds.width || bounds.height) || target.getBBox === _getBBoxHack || (bounds = _getBBoxHack.call(target, true)); return bounds && !bounds.width && !bounds.x && !bounds.y ? { x: +_getAttributeFallbacks(target, ["x", "cx", "x1"]) || 0, y: +_getAttributeFallbacks(target, ["y", "cy", "y1"]) || 0, width: 0, height: 0 } : bounds; }, _isSVG = function _isSVG(e) { return !!(e.getCTM && (!e.parentNode || e.ownerSVGElement) && _getBBox(e)); }, _removeProperty = function _removeProperty(target, property) { if (property) { var style = target.style; if (property in _transformProps && property !== _transformOriginProp) { property = _transformProp; } if (style.removeProperty) { if (property.substr(0, 2) === "ms" || property.substr(0, 6) === "webkit") { property = "-" + property; } style.removeProperty(property.replace(_capsExp, "-$1").toLowerCase()); } else { style.removeAttribute(property); } } }, _addNonTweeningPT = function _addNonTweeningPT(plugin, target, property, beginning, end, onlySetAtEnd) { var pt = new PropTween(plugin._pt, target, property, 0, 1, onlySetAtEnd ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue); plugin._pt = pt; pt.b = beginning; pt.e = end; plugin._props.push(property); return pt; }, _nonConvertibleUnits = { deg: 1, rad: 1, turn: 1 }, _nonStandardLayouts = { grid: 1, flex: 1 }, _convertToUnit = function _convertToUnit(target, property, value, unit) { var curValue = parseFloat(value) || 0, curUnit = (value + "").trim().substr((curValue + "").length) || "px", style = _tempDiv.style, horizontal = _horizontalExp.test(property), isRootSVG = target.tagName.toLowerCase() === "svg", measureProperty = (isRootSVG ? "client" : "offset") + (horizontal ? "Width" : "Height"), amount = 100, toPixels = unit === "px", toPercent = unit === "%", px, parent, cache, isSVG; if (unit === curUnit || !curValue || _nonConvertibleUnits[unit] || _nonConvertibleUnits[curUnit]) { return curValue; } curUnit !== "px" && !toPixels && (curValue = _convertToUnit(target, property, value, "px")); isSVG = target.getCTM && _isSVG(target); if ((toPercent || curUnit === "%") && (_transformProps[property] || ~property.indexOf("adius"))) { px = isSVG ? target.getBBox()[horizontal ? "width" : "height"] : target[measureProperty]; return _round(toPercent ? curValue / px * amount : curValue / 100 * px); } style[horizontal ? "width" : "height"] = amount + (toPixels ? curUnit : unit); parent = ~property.indexOf("adius") || unit === "em" && target.appendChild && !isRootSVG ? target : target.parentNode; if (isSVG) { parent = (target.ownerSVGElement || {}).parentNode; } if (!parent || parent === _doc$1 || !parent.appendChild) { parent = _doc$1.body; } cache = parent._gsap; if (cache && toPercent && cache.width && horizontal && cache.time === _ticker.time && !cache.uncache) { return _round(curValue / cache.width * amount); } else { (toPercent || curUnit === "%") && !_nonStandardLayouts[_getComputedProperty(parent, "display")] && (style.position = _getComputedProperty(target, "position")); parent === target && (style.position = "static"); parent.appendChild(_tempDiv); px = _tempDiv[measureProperty]; parent.removeChild(_tempDiv); style.position = "absolute"; if (horizontal && toPercent) { cache = _getCache(parent); cache.time = _ticker.time; cache.width = parent[measureProperty]; } } return _round(toPixels ? px * curValue / amount : px && curValue ? amount / px * curValue : 0); }, _get = function _get(target, property, unit, uncache) { var value; _pluginInitted || _initCore(); if (property in _propertyAliases && property !== "transform") { property = _propertyAliases[property]; if (~property.indexOf(",")) { property = property.split(",")[0]; } } if (_transformProps[property] && property !== "transform") { value = _parseTransform(target, uncache); value = property !== "transformOrigin" ? value[property] : value.svg ? value.origin : _firstTwoOnly(_getComputedProperty(target, _transformOriginProp)) + " " + value.zOrigin + "px"; } else { value = target.style[property]; if (!value || value === "auto" || uncache || ~(value + "").indexOf("calc(")) { value = _specialProps[property] && _specialProps[property](target, property, unit) || _getComputedProperty(target, property) || _getProperty(target, property) || (property === "opacity" ? 1 : 0); } } return unit && !~(value + "").trim().indexOf(" ") ? _convertToUnit(target, property, value, unit) + unit : value; }, _tweenComplexCSSString = function _tweenComplexCSSString(target, prop, start, end) { if (!start || start === "none") { var p = _checkPropPrefix(prop, target, 1), s = p && _getComputedProperty(target, p, 1); if (s && s !== start) { prop = p; start = s; } else if (prop === "borderColor") { start = _getComputedProperty(target, "borderTopColor"); } } var pt = new PropTween(this._pt, target.style, prop, 0, 1, _renderComplexString), index = 0, matchIndex = 0, a, result, startValues, startNum, color, startValue, endValue, endNum, chunk, endUnit, startUnit, endValues; pt.b = start; pt.e = end; start += ""; end += ""; if (end === "auto") { target.style[prop] = end; end = _getComputedProperty(target, prop) || end; target.style[prop] = start; } a = [start, end]; _colorStringFilter(a); start = a[0]; end = a[1]; startValues = start.match(_numWithUnitExp) || []; endValues = end.match(_numWithUnitExp) || []; if (endValues.length) { while (result = _numWithUnitExp.exec(end)) { endValue = result[0]; chunk = end.substring(index, result.index); if (color) { color = (color + 1) % 5; } else if (chunk.substr(-5) === "rgba(" || chunk.substr(-5) === "hsla(") { color = 1; } if (endValue !== (startValue = startValues[matchIndex++] || "")) { startNum = parseFloat(startValue) || 0; startUnit = startValue.substr((startNum + "").length); endValue.charAt(1) === "=" && (endValue = _parseRelative(startNum, endValue) + startUnit); endNum = parseFloat(endValue); endUnit = endValue.substr((endNum + "").length); index = _numWithUnitExp.lastIndex - endUnit.length; if (!endUnit) { endUnit = endUnit || _config.units[prop] || startUnit; if (index === end.length) { end += endUnit; pt.e += endUnit; } } if (startUnit !== endUnit) { startNum = _convertToUnit(target, prop, startValue, endUnit) || 0; } pt._pt = { _next: pt._pt, p: chunk || matchIndex === 1 ? chunk : ",", s: startNum, c: endNum - startNum, m: color && color < 4 || prop === "zIndex" ? Math.round : 0 }; } } pt.c = index < end.length ? end.substring(index, end.length) : ""; } else { pt.r = prop === "display" && end === "none" ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue; } _relExp.test(end) && (pt.e = 0); this._pt = pt; return pt; }, _keywordToPercent = { top: "0%", bottom: "100%", left: "0%", right: "100%", center: "50%" }, _convertKeywordsToPercentages = function _convertKeywordsToPercentages(value) { var split = value.split(" "), x = split[0], y = split[1] || "50%"; if (x === "top" || x === "bottom" || y === "left" || y === "right") { value = x; x = y; y = value; } split[0] = _keywordToPercent[x] || x; split[1] = _keywordToPercent[y] || y; return split.join(" "); }, _renderClearProps = function _renderClearProps(ratio, data) { if (data.tween && data.tween._time === data.tween._dur) { var target = data.t, style = target.style, props = data.u, cache = target._gsap, prop, clearTransforms, i; if (props === "all" || props === true) { style.cssText = ""; clearTransforms = 1; } else { props = props.split(","); i = props.length; while (--i > -1) { prop = props[i]; if (_transformProps[prop]) { clearTransforms = 1; prop = prop === "transformOrigin" ? _transformOriginProp : _transformProp; } _removeProperty(target, prop); } } if (clearTransforms) { _removeProperty(target, _transformProp); if (cache) { cache.svg && target.removeAttribute("transform"); _parseTransform(target, 1); cache.uncache = 1; _removeIndependentTransforms(style); } } } }, _specialProps = { clearProps: function clearProps(plugin, target, property, endValue, tween) { if (tween.data !== "isFromStart") { var pt = plugin._pt = new PropTween(plugin._pt, target, property, 0, 0, _renderClearProps); pt.u = endValue; pt.pr = -10; pt.tween = tween; plugin._props.push(property); return 1; } } }, _identity2DMatrix = [1, 0, 0, 1, 0, 0], _rotationalProperties = {}, _isNullTransform = function _isNullTransform(value) { return value === "matrix(1, 0, 0, 1, 0, 0)" || value === "none" || !value; }, _getComputedTransformMatrixAsArray = function _getComputedTransformMatrixAsArray(target) { var matrixString = _getComputedProperty(target, _transformProp); return _isNullTransform(matrixString) ? _identity2DMatrix : matrixString.substr(7).match(_numExp).map(_round); }, _getMatrix = function _getMatrix(target, force2D) { var cache = target._gsap || _getCache(target), style = target.style, matrix = _getComputedTransformMatrixAsArray(target), parent, nextSibling, temp, addedToDOM; if (cache.svg && target.getAttribute("transform")) { temp = target.transform.baseVal.consolidate().matrix; matrix = [temp.a, temp.b, temp.c, temp.d, temp.e, temp.f]; return matrix.join(",") === "1,0,0,1,0,0" ? _identity2DMatrix : matrix; } else if (matrix === _identity2DMatrix && !target.offsetParent && target !== _docElement && !cache.svg) { temp = style.display; style.display = "block"; parent = target.parentNode; if (!parent || !target.offsetParent) { addedToDOM = 1; nextSibling = target.nextElementSibling; _docElement.appendChild(target); } matrix = _getComputedTransformMatrixAsArray(target); temp ? style.display = temp : _removeProperty(target, "display"); if (addedToDOM) { nextSibling ? parent.insertBefore(target, nextSibling) : parent ? parent.appendChild(target) : _docElement.removeChild(target); } } return force2D && matrix.length > 6 ? [matrix[0], matrix[1], matrix[4], matrix[5], matrix[12], matrix[13]] : matrix; }, _applySVGOrigin = function _applySVGOrigin(target, origin, originIsAbsolute, smooth, matrixArray, pluginToAddPropTweensTo) { var cache = target._gsap, matrix = matrixArray || _getMatrix(target, true), xOriginOld = cache.xOrigin || 0, yOriginOld = cache.yOrigin || 0, xOffsetOld = cache.xOffset || 0, yOffsetOld = cache.yOffset || 0, a = matrix[0], b = matrix[1], c = matrix[2], d = matrix[3], tx = matrix[4], ty = matrix[5], originSplit = origin.split(" "), xOrigin = parseFloat(originSplit[0]) || 0, yOrigin = parseFloat(originSplit[1]) || 0, bounds, determinant, x, y; if (!originIsAbsolute) { bounds = _getBBox(target); xOrigin = bounds.x + (~originSplit[0].indexOf("%") ? xOrigin / 100 * bounds.width : xOrigin); yOrigin = bounds.y + (~(originSplit[1] || originSplit[0]).indexOf("%") ? yOrigin / 100 * bounds.height : yOrigin); } else if (matrix !== _identity2DMatrix && (determinant = a * d - b * c)) { x = xOrigin * (d / determinant) + yOrigin * (-c / determinant) + (c * ty - d * tx) / determinant; y = xOrigin * (-b / determinant) + yOrigin * (a / determinant) - (a * ty - b * tx) / determinant; xOrigin = x; yOrigin = y; } if (smooth || smooth !== false && cache.smooth) { tx = xOrigin - xOriginOld; ty = yOrigin - yOriginOld; cache.xOffset = xOffsetOld + (tx * a + ty * c) - tx; cache.yOffset = yOffsetOld + (tx * b + ty * d) - ty; } else { cache.xOffset = cache.yOffset = 0; } cache.xOrigin = xOrigin; cache.yOrigin = yOrigin; cache.smooth = !!smooth; cache.origin = origin; cache.originIsAbsolute = !!originIsAbsolute; target.style[_transformOriginProp] = "0px 0px"; if (pluginToAddPropTweensTo) { _addNonTweeningPT(pluginToAddPropTweensTo, cache, "xOrigin", xOriginOld, xOrigin); _addNonTweeningPT(pluginToAddPropTweensTo, cache, "yOrigin", yOriginOld, yOrigin); _addNonTweeningPT(pluginToAddPropTweensTo, cache, "xOffset", xOffsetOld, cache.xOffset); _addNonTweeningPT(pluginToAddPropTweensTo, cache, "yOffset", yOffsetOld, cache.yOffset); } target.setAttribute("data-svg-origin", xOrigin + " " + yOrigin); }, _parseTransform = function _parseTransform(target, uncache) { var cache = target._gsap || new GSCache(target); if ("x" in cache && !uncache && !cache.uncache) { return cache; } var style = target.style, invertedScaleX = cache.scaleX < 0, px = "px", deg = "deg", cs = getComputedStyle(target), origin = _getComputedProperty(target, _transformOriginProp) || "0", x, y, z, scaleX, scaleY, rotation, rotationX, rotationY, skewX, skewY, perspective, xOrigin, yOrigin, matrix, angle, cos, sin, a, b, c, d, a12, a22, t1, t2, t3, a13, a23, a33, a42, a43, a32; x = y = z = rotation = rotationX = rotationY = skewX = skewY = perspective = 0; scaleX = scaleY = 1; cache.svg = !!(target.getCTM && _isSVG(target)); if (cs.translate) { if (cs.translate !== "none" || cs.scale !== "none" || cs.rotate !== "none") { style[_transformProp] = (cs.translate !== "none" ? "translate3d(" + (cs.translate + " 0 0").split(" ").slice(0, 3).join(", ") + ") " : "") + (cs.rotate !== "none" ? "rotate(" + cs.rotate + ") " : "") + (cs.scale !== "none" ? "scale(" + cs.scale.split(" ").join(",") + ") " : "") + (cs[_transformProp] !== "none" ? cs[_transformProp] : ""); } style.scale = style.rotate = style.translate = "none"; } matrix = _getMatrix(target, cache.svg); if (cache.svg) { if (cache.uncache) { t2 = target.getBBox(); origin = cache.xOrigin - t2.x + "px " + (cache.yOrigin - t2.y) + "px"; t1 = ""; } else { t1 = !uncache && target.getAttribute("data-svg-origin"); } _applySVGOrigin(target, t1 || origin, !!t1 || cache.originIsAbsolute, cache.smooth !== false, matrix); } xOrigin = cache.xOrigin || 0; yOrigin = cache.yOrigin || 0; if (matrix !== _identity2DMatrix) { a = matrix[0]; b = matrix[1]; c = matrix[2]; d = matrix[3]; x = a12 = matrix[4]; y = a22 = matrix[5]; if (matrix.length === 6) { scaleX = Math.sqrt(a * a + b * b); scaleY = Math.sqrt(d * d + c * c); rotation = a || b ? _atan2(b, a) * _RAD2DEG : 0; skewX = c || d ? _atan2(c, d) * _RAD2DEG + rotation : 0; skewX && (scaleY *= Math.abs(Math.cos(skewX * _DEG2RAD))); if (cache.svg) { x -= xOrigin - (xOrigin * a + yOrigin * c); y -= yOrigin - (xOrigin * b + yOrigin * d); } } else { a32 = matrix[6]; a42 = matrix[7]; a13 = matrix[8]; a23 = matrix[9]; a33 = matrix[10]; a43 = matrix[11]; x = matrix[12]; y = matrix[13]; z = matrix[14]; angle = _atan2(a32, a33); rotationX = angle * _RAD2DEG; if (angle) { cos = Math.cos(-angle); sin = Math.sin(-angle); t1 = a12 * cos + a13 * sin; t2 = a22 * cos + a23 * sin; t3 = a32 * cos + a33 * sin; a13 = a12 * -sin + a13 * cos; a23 = a22 * -sin + a23 * cos; a33 = a32 * -sin + a33 * cos; a43 = a42 * -sin + a43 * cos; a12 = t1; a22 = t2; a32 = t3; } angle = _atan2(-c, a33); rotationY = angle * _RAD2DEG; if (angle) { cos = Math.cos(-angle); sin = Math.sin(-angle); t1 = a * cos - a13 * sin; t2 = b * cos - a23 * sin; t3 = c * cos - a33 * sin; a43 = d * sin + a43 * cos; a = t1; b = t2; c = t3; } angle = _atan2(b, a); rotation = angle * _RAD2DEG; if (angle) { cos = Math.cos(angle); sin = Math.sin(angle); t1 = a * cos + b * sin; t2 = a12 * cos + a22 * sin; b = b * cos - a * sin; a22 = a22 * cos - a12 * sin; a = t1; a12 = t2; } if (rotationX && Math.abs(rotationX) + Math.abs(rotation) > 359.9) { rotationX = rotation = 0; rotationY = 180 - rotationY; } scaleX = _round(Math.sqrt(a * a + b * b + c * c)); scaleY = _round(Math.sqrt(a22 * a22 + a32 * a32)); angle = _atan2(a12, a22); skewX = Math.abs(angle) > 0.0002 ? angle * _RAD2DEG : 0; perspective = a43 ? 1 / (a43 < 0 ? -a43 : a43) : 0; } if (cache.svg) { t1 = target.getAttribute("transform"); cache.forceCSS = target.setAttribute("transform", "") || !_isNullTransform(_getComputedProperty(target, _transformProp)); t1 && target.setAttribute("transform", t1); } } if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) { if (invertedScaleX) { scaleX *= -1; skewX += rotation <= 0 ? 180 : -180; rotation += rotation <= 0 ? 180 : -180; } else { scaleY *= -1; skewX += skewX <= 0 ? 180 : -180; } } uncache = uncache || cache.uncache; cache.x = x - ((cache.xPercent = x && (!uncache && cache.xPercent || (Math.round(target.offsetWidth / 2) === Math.round(-x) ? -50 : 0))) ? target.offsetWidth * cache.xPercent / 100 : 0) + px; cache.y = y - ((cache.yPercent = y && (!uncache && cache.yPercent || (Math.round(target.offsetHeight / 2) === Math.round(-y) ? -50 : 0))) ? target.offsetHeight * cache.yPercent / 100 : 0) + px; cache.z = z + px; cache.scaleX = _round(scaleX); cache.scaleY = _round(scaleY); cache.rotation = _round(rotation) + deg; cache.rotationX = _round(rotationX) + deg; cache.rotationY = _round(rotationY) + deg; cache.skewX = skewX + deg; cache.skewY = skewY + deg; cache.transformPerspective = perspective + px; if (cache.zOrigin = parseFloat(origin.split(" ")[2]) || 0) { style[_transformOriginProp] = _firstTwoOnly(origin); } cache.xOffset = cache.yOffset = 0; cache.force3D = _config.force3D; cache.renderTransform = cache.svg ? _renderSVGTransforms : _supports3D ? _renderCSSTransforms : _renderNon3DTransforms; cache.uncache = 0; return cache; }, _firstTwoOnly = function _firstTwoOnly(value) { return (value = value.split(" "))[0] + " " + value[1]; }, _addPxTranslate = function _addPxTranslate(target, start, value) { var unit = getUnit(start); return _round(parseFloat(start) + parseFloat(_convertToUnit(target, "x", value + "px", unit))) + unit; }, _renderNon3DTransforms = function _renderNon3DTransforms(ratio, cache) { cache.z = "0px"; cache.rotationY = cache.rotationX = "0deg"; cache.force3D = 0; _renderCSSTransforms(ratio, cache); }, _zeroDeg = "0deg", _zeroPx = "0px", _endParenthesis = ") ", _renderCSSTransforms = function _renderCSSTransforms(ratio, cache) { var _ref = cache || this, xPercent = _ref.xPercent, yPercent = _ref.yPercent, x = _ref.x, y = _ref.y, z = _ref.z, rotation = _ref.rotation, rotationY = _ref.rotationY, rotationX = _ref.rotationX, skewX = _ref.skewX, skewY = _ref.skewY, scaleX = _ref.scaleX, scaleY = _ref.scaleY, transformPerspective = _ref.transformPerspective, force3D = _ref.force3D, target = _ref.target, zOrigin = _ref.zOrigin, transforms = "", use3D = force3D === "auto" && ratio && ratio !== 1 || force3D === true; if (zOrigin && (rotationX !== _zeroDeg || rotationY !== _zeroDeg)) { var angle = parseFloat(rotationY) * _DEG2RAD, a13 = Math.sin(angle), a33 = Math.cos(angle), cos; angle = parseFloat(rotationX) * _DEG2RAD; cos = Math.cos(angle); x = _addPxTranslate(target, x, a13 * cos * -zOrigin); y = _addPxTranslate(target, y, -Math.sin(angle) * -zOrigin); z = _addPxTranslate(target, z, a33 * cos * -zOrigin + zOrigin); } if (transformPerspective !== _zeroPx) { transforms += "perspective(" + transformPerspective + _endParenthesis; } if (xPercent || yPercent) { transforms += "translate(" + xPercent + "%, " + yPercent + "%) "; } if (use3D || x !== _zeroPx || y !== _zeroPx || z !== _zeroPx) { transforms += z !== _zeroPx || use3D ? "translate3d(" + x + ", " + y + ", " + z + ") " : "translate(" + x + ", " + y + _endParenthesis; } if (rotation !== _zeroDeg) { transforms += "rotate(" + rotation + _endParenthesis; } if (rotationY !== _zeroDeg) { transforms += "rotateY(" + rotationY + _endParenthesis; } if (rotationX !== _zeroDeg) { transforms += "rotateX(" + rotationX + _endParenthesis; } if (skewX !== _zeroDeg || skewY !== _zeroDeg) { transforms += "skew(" + skewX + ", " + skewY + _endParenthesis; } if (scaleX !== 1 || scaleY !== 1) { transforms += "scale(" + scaleX + ", " + scaleY + _endParenthesis; } target.style[_transformProp] = transforms || "translate(0, 0)"; }, _renderSVGTransforms = function _renderSVGTransforms(ratio, cache) { var _ref2 = cache || this, xPercent = _ref2.xPercent, yPercent = _ref2.yPercent, x = _ref2.x, y = _ref2.y, rotation = _ref2.rotation, skewX = _ref2.skewX, skewY = _ref2.skewY, scaleX = _ref2.scaleX, scaleY = _ref2.scaleY, target = _ref2.target, xOrigin = _ref2.xOrigin, yOrigin = _ref2.yOrigin, xOffset = _ref2.xOffset, yOffset = _ref2.yOffset, forceCSS = _ref2.forceCSS, tx = parseFloat(x), ty = parseFloat(y), a11, a21, a12, a22, temp; rotation = parseFloat(rotation); skewX = parseFloat(skewX); skewY = parseFloat(skewY); if (skewY) { skewY = parseFloat(skewY); skewX += skewY; rotation += skewY; } if (rotation || skewX) { rotation *= _DEG2RAD; skewX *= _DEG2RAD; a11 = Math.cos(rotation) * scaleX; a21 = Math.sin(rotation) * scaleX; a12 = Math.sin(rotation - skewX) * -scaleY; a22 = Math.cos(rotation - skewX) * scaleY; if (skewX) { skewY *= _DEG2RAD; temp = Math.tan(skewX - skewY); temp = Math.sqrt(1 + temp * temp); a12 *= temp; a22 *= temp; if (skewY) { temp = Math.tan(skewY); temp = Math.sqrt(1 + temp * temp); a11 *= temp; a21 *= temp; } } a11 = _round(a11); a21 = _round(a21); a12 = _round(a12); a22 = _round(a22); } else { a11 = scaleX; a22 = scaleY; a21 = a12 = 0; } if (tx && !~(x + "").indexOf("px") || ty && !~(y + "").indexOf("px")) { tx = _convertToUnit(target, "x", x, "px"); ty = _convertToUnit(target, "y", y, "px"); } if (xOrigin || yOrigin || xOffset || yOffset) { tx = _round(tx + xOrigin - (xOrigin * a11 + yOrigin * a12) + xOffset); ty = _round(ty + yOrigin - (xOrigin * a21 + yOrigin * a22) + yOffset); } if (xPercent || yPercent) { temp = target.getBBox(); tx = _round(tx + xPercent / 100 * temp.width); ty = _round(ty + yPercent / 100 * temp.height); } temp = "matrix(" + a11 + "," + a21 + "," + a12 + "," + a22 + "," + tx + "," + ty + ")"; target.setAttribute("transform", temp); forceCSS && (target.style[_transformProp] = temp); }, _addRotationalPropTween = function _addRotationalPropTween(plugin, target, property, startNum, endValue) { var cap = 360, isString = _isString(endValue), endNum = parseFloat(endValue) * (isString && ~endValue.indexOf("rad") ? _RAD2DEG : 1), change = endNum - startNum, finalValue = startNum + change + "deg", direction, pt; if (isString) { direction = endValue.split("_")[1]; if (direction === "short") { change %= cap; if (change !== change % (cap / 2)) { change += change < 0 ? cap : -cap; } } if (direction === "cw" && change < 0) { change = (change + cap * _bigNum$1) % cap - ~~(change / cap) * cap; } else if (direction === "ccw" && change > 0) { change = (change - cap * _bigNum$1) % cap - ~~(change / cap) * cap; } } plugin._pt = pt = new PropTween(plugin._pt, target, property, startNum, change, _renderPropWithEnd); pt.e = finalValue; pt.u = "deg"; plugin._props.push(property); return pt; }, _assign = function _assign(target, source) { for (var p in source) { target[p] = source[p]; } return target; }, _addRawTransformPTs = function _addRawTransformPTs(plugin, transforms, target) { var startCache = _assign({}, target._gsap), exclude = "perspective,force3D,transformOrigin,svgOrigin", style = target.style, endCache, p, startValue, endValue, startNum, endNum, startUnit, endUnit; if (startCache.svg) { startValue = target.getAttribute("transform"); target.setAttribute("transform", ""); style[_transformProp] = transforms; endCache = _parseTransform(target, 1); _removeProperty(target, _transformProp); target.setAttribute("transform", startValue); } else { startValue = getComputedStyle(target)[_transformProp]; style[_transformProp] = transforms; endCache = _parseTransform(target, 1); style[_transformProp] = startValue; } for (p in _transformProps) { startValue = startCache[p]; endValue = endCache[p]; if (startValue !== endValue && exclude.indexOf(p) < 0) { startUnit = getUnit(startValue); endUnit = getUnit(endValue); startNum = startUnit !== endUnit ? _convertToUnit(target, p, startValue, endUnit) : parseFloat(startValue); endNum = parseFloat(endValue); plugin._pt = new PropTween(plugin._pt, endCache, p, startNum, endNum - startNum, _renderCSSProp); plugin._pt.u = endUnit || 0; plugin._props.push(p); } } _assign(endCache, startCache); }; _forEachName("padding,margin,Width,Radius", function (name, index) { var t = "Top", r = "Right", b = "Bottom", l = "Left", props = (index < 3 ? [t, r, b, l] : [t + l, t + r, b + r, b + l]).map(function (side) { return index < 2 ? name + side : "border" + side + name; }); _specialProps[index > 1 ? "border" + name : name] = function (plugin, target, property, endValue, tween) { var a, vars; if (arguments.length < 4) { a = props.map(function (prop) { return _get(plugin, prop, property); }); vars = a.join(" "); return vars.split(a[0]).length === 5 ? a[0] : vars; } a = (endValue + "").split(" "); vars = {}; props.forEach(function (prop, i) { return vars[prop] = a[i] = a[i] || a[(i - 1) / 2 | 0]; }); plugin.init(target, vars, tween); }; }); var CSSPlugin = { name: "css", register: _initCore, targetTest: function targetTest(target) { return target.style && target.nodeType; }, init: function init(target, vars, tween, index, targets) { var props = this._props, style = target.style, startAt = tween.vars.startAt, startValue, endValue, endNum, startNum, type, specialProp, p, startUnit, endUnit, relative, isTransformRelated, transformPropTween, cache, smooth, hasPriority, inlineProps; _pluginInitted || _initCore(); this.styles = this.styles || _getStyleSaver(target); inlineProps = this.styles.props; this.tween = tween; for (p in vars) { if (p === "autoRound") { continue; } endValue = vars[p]; if (_plugins[p] && _checkPlugin(p, vars, tween, index, target, targets)) { continue; } type = typeof endValue; specialProp = _specialProps[p]; if (type === "function") { endValue = endValue.call(tween, index, target, targets); type = typeof endValue; } if (type === "string" && ~endValue.indexOf("random(")) { endValue = _replaceRandom(endValue); } if (specialProp) { specialProp(this, target, p, endValue, tween) && (hasPriority = 1); } else if (p.substr(0, 2) === "--") { startValue = (getComputedStyle(target).getPropertyValue(p) + "").trim(); endValue += ""; _colorExp.lastIndex = 0; if (!_colorExp.test(startValue)) { startUnit = getUnit(startValue); endUnit = getUnit(endValue); } endUnit ? startUnit !== endUnit && (startValue = _convertToUnit(target, p, startValue, endUnit) + endUnit) : startUnit && (endValue += startUnit); this.add(style, "setProperty", startValue, endValue, index, targets, 0, 0, p); props.push(p); inlineProps.push(p, 0, style[p]); } else if (type !== "undefined") { if (startAt && p in startAt) { startValue = typeof startAt[p] === "function" ? startAt[p].call(tween, index, target, targets) : startAt[p]; _isString(startValue) && ~startValue.indexOf("random(") && (startValue = _replaceRandom(startValue)); getUnit(startValue + "") || (startValue += _config.units[p] || getUnit(_get(target, p)) || ""); (startValue + "").charAt(1) === "=" && (startValue = _get(target, p)); } else { startValue = _get(target, p); } startNum = parseFloat(startValue); relative = type === "string" && endValue.charAt(1) === "=" && endValue.substr(0, 2); relative && (endValue = endValue.substr(2)); endNum = parseFloat(endValue); if (p in _propertyAliases) { if (p === "autoAlpha") { if (startNum === 1 && _get(target, "visibility") === "hidden" && endNum) { startNum = 0; } inlineProps.push("visibility", 0, style.visibility); _addNonTweeningPT(this, style, "visibility", startNum ? "inherit" : "hidden", endNum ? "inherit" : "hidden", !endNum); } if (p !== "scale" && p !== "transform") { p = _propertyAliases[p]; ~p.indexOf(",") && (p = p.split(",")[0]); } } isTransformRelated = p in _transformProps; if (isTransformRelated) { this.styles.save(p); if (!transformPropTween) { cache = target._gsap; cache.renderTransform && !vars.parseTransform || _parseTransform(target, vars.parseTransform); smooth = vars.smoothOrigin !== false && cache.smooth; transformPropTween = this._pt = new PropTween(this._pt, style, _transformProp, 0, 1, cache.renderTransform, cache, 0, -1); transformPropTween.dep = 1; } if (p === "scale") { this._pt = new PropTween(this._pt, cache, "scaleY", startNum, (relative ? _parseRelative(startNum, relative + endNum) : endNum) - startNum || 0, _renderCSSProp); this._pt.u = 0; props.push("scaleY", p); p += "X"; } else if (p === "transformOrigin") { inlineProps.push(_transformOriginProp, 0, style[_transformOriginProp]); endValue = _convertKeywordsToPercentages(endValue); if (cache.svg) { _applySVGOrigin(target, endValue, 0, smooth, 0, this); } else { endUnit = parseFloat(endValue.split(" ")[2]) || 0; endUnit !== cache.zOrigin && _addNonTweeningPT(this, cache, "zOrigin", cache.zOrigin, endUnit); _addNonTweeningPT(this, style, p, _firstTwoOnly(startValue), _firstTwoOnly(endValue)); } continue; } else if (p === "svgOrigin") { _applySVGOrigin(target, endValue, 1, smooth, 0, this); continue; } else if (p in _rotationalProperties) { _addRotationalPropTween(this, cache, p, startNum, relative ? _parseRelative(startNum, relative + endValue) : endValue); continue; } else if (p === "smoothOrigin") { _addNonTweeningPT(this, cache, "smooth", cache.smooth, endValue); continue; } else if (p === "force3D") { cache[p] = endValue; continue; } else if (p === "transform") { _addRawTransformPTs(this, endValue, target); continue; } } else if (!(p in style)) { p = _checkPropPrefix(p) || p; } if (isTransformRelated || (endNum || endNum === 0) && (startNum || startNum === 0) && !_complexExp.test(endValue) && p in style) { startUnit = (startValue + "").substr((startNum + "").length); endNum || (endNum = 0); endUnit = getUnit(endValue) || (p in _config.units ? _config.units[p] : startUnit); startUnit !== endUnit && (startNum = _convertToUnit(target, p, startValue, endUnit)); this._pt = new PropTween(this._pt, isTransformRelated ? cache : style, p, startNum, (relative ? _parseRelative(startNum, relative + endNum) : endNum) - startNum, !isTransformRelated && (endUnit === "px" || p === "zIndex") && vars.autoRound !== false ? _renderRoundedCSSProp : _renderCSSProp); this._pt.u = endUnit || 0; if (startUnit !== endUnit && endUnit !== "%") { this._pt.b = startValue; this._pt.r = _renderCSSPropWithBeginning; } } else if (!(p in style)) { if (p in target) { this.add(target, p, startValue || target[p], relative ? relative + endValue : endValue, index, targets); } else { _missingPlugin(p, endValue); continue; } } else { _tweenComplexCSSString.call(this, target, p, startValue, relative ? relative + endValue : endValue); } isTransformRelated || (p in style ? inlineProps.push(p, 0, style[p]) : inlineProps.push(p, 1, startValue || target[p])); props.push(p); } } hasPriority && _sortPropTweensByPriority(this); }, render: function render(ratio, data) { if (data.tween._time || !_reverting$1()) { var pt = data._pt; while (pt) { pt.r(ratio, pt.d); pt = pt._next; } } else { data.styles.revert(); } }, get: _get, aliases: _propertyAliases, getSetter: function getSetter(target, property, plugin) { var p = _propertyAliases[property]; p && p.indexOf(",") < 0 && (property = p); return property in _transformProps && property !== _transformOriginProp && (target._gsap.x || _get(target, "x")) ? plugin && _recentSetterPlugin === plugin ? property === "scale" ? _setterScale : _setterTransform : (_recentSetterPlugin = plugin || {}) && (property === "scale" ? _setterScaleWithRender : _setterTransformWithRender) : target.style && !_isUndefined(target.style[property]) ? _setterCSSStyle : ~property.indexOf("-") ? _setterCSSProp : _getSetter(target, property); }, core: { _removeProperty: _removeProperty, _getMatrix: _getMatrix } }; gsap.utils.checkPrefix = _checkPropPrefix; gsap.core.getStyleSaver = _getStyleSaver; (function (positionAndScale, rotation, others, aliases) { var all = _forEachName(positionAndScale + "," + rotation + "," + others, function (name) { _transformProps[name] = 1; }); _forEachName(rotation, function (name) { _config.units[name] = "deg"; _rotationalProperties[name] = 1; }); _propertyAliases[all[13]] = positionAndScale + "," + rotation; _forEachName(aliases, function (name) { var split = name.split(":"); _propertyAliases[split[1]] = all[split[0]]; }); })("x,y,z,scale,scaleX,scaleY,xPercent,yPercent", "rotation,rotationX,rotationY,skewX,skewY", "transform,transformOrigin,svgOrigin,force3D,smoothOrigin,transformPerspective", "0:translateX,1:translateY,2:translateZ,8:rotate,8:rotationZ,8:rotateZ,9:rotateX,10:rotateY"); _forEachName("x,y,z,top,right,bottom,left,width,height,fontSize,padding,margin,perspective", function (name) { _config.units[name] = "px"; }); gsap.registerPlugin(CSSPlugin); var gsapWithCSS = gsap.registerPlugin(CSSPlugin) || gsap, TweenMaxWithCSS = gsapWithCSS.core.Tween; exports.Back = Back; exports.Bounce = Bounce; exports.CSSPlugin = CSSPlugin; exports.Circ = Circ; exports.Cubic = Cubic; exports.Elastic = Elastic; exports.Expo = Expo; exports.Linear = Linear; exports.Power0 = Power0; exports.Power1 = Power1; exports.Power2 = Power2; exports.Power3 = Power3; exports.Power4 = Power4; exports.Quad = Quad; exports.Quart = Quart; exports.Quint = Quint; exports.Sine = Sine; exports.SteppedEase = SteppedEase; exports.Strong = Strong; exports.TimelineLite = Timeline; exports.TimelineMax = Timeline; exports.TweenLite = Tween; exports.TweenMax = TweenMaxWithCSS; exports.default = gsapWithCSS; exports.gsap = gsapWithCSS; if (typeof(window) === 'undefined' || window !== exports) {Object.defineProperty(exports, '__esModule', { value: true });} else {delete window.default;} }))); (function(window, $) { 'use strict'; var counter = 0, $headCache = $('head'), oldBigText = window.BigText, oldjQueryMethod = $.fn.bigtext, BigText = { DEBUG_MODE: false, DEFAULT_MIN_FONT_SIZE_PX: null, DEFAULT_MAX_FONT_SIZE_PX: 528, GLOBAL_STYLE_ID: 'bigtext-style', STYLE_ID: 'bigtext-id', LINE_CLASS_PREFIX: 'bigtext-line', EXEMPT_CLASS: 'bigtext-exempt', noConflict: function(restore) { if(restore) { $.fn.bigtext = oldjQueryMethod; window.BigText = oldBigText; } return BigText; }, supports: { wholeNumberFontSizeOnly: (function() { if( !( 'getComputedStyle' in window ) ) { return true; } var test = $('
').css({ position: 'absolute', 'font-size': '14.1px' }).insertBefore( $('script').eq(0) ), computedStyle = window.getComputedStyle( test[0], null ); var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px'; test.remove(); return ret; })() }, init: function() { if(!$('#'+BigText.GLOBAL_STYLE_ID).length) { $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }', '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }'])); } }, bindResize: function(eventName, resizeFunction) { var timeoutId; $(window).unbind(eventName).bind(eventName, function() { if( timeoutId ) { clearTimeout( timeoutId ); } timeoutId = setTimeout( resizeFunction, 300 ); }); }, getStyleId: function(id) { return BigText.STYLE_ID + '-' + id; }, generateStyleTag: function(id, css) { return $('').attr('id', id); }, clearCss: function(id) { var styleId = BigText.getStyleId(id); $('#' + styleId).remove(); }, generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes) { var css = []; BigText.clearCss(id); for(var j=0, k=linesFontSizes.length; j= maxWidth) { $line.css(property, ''); if(width === maxWidth) { return { match: 'exact', size: parseFloat((parseFloat(size) - 0.1).toFixed(3)) }; } // Since this is an estimate, we calculate how far over the width we went with the new value. // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value. // Otherwise, we revert to the underestimate. var under = maxWidth - previousWidth, over = width - maxWidth; return { match: 'estimate', size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3)) }; } return width; } function calculateSizes($t, $children, maxWidth, maxFontSize, minFontSize) { var $c = $t.clone(true) .addClass('bigtext-cloned') .css({ fontFamily: $t.css('font-family'), textTransform: $t.css('text-transform'), wordSpacing: $t.css('word-spacing'), letterSpacing: $t.css('letter-spacing'), position: 'absolute', left: BigText.DEBUG_MODE ? 0 : -9999, top: BigText.DEBUG_MODE ? 0 : -9999 }) .appendTo(document.body); // font-size isn't the only thing we can modify, we can also mess with: // word-spacing and letter-spacing. WebKit does not respect subpixel // letter-spacing, word-spacing, or font-size. // TODO try -webkit-transform: scale() as a workaround. var fontSizes = [], wordSpacings = [], minFontSizes = [], ratios = []; $children.css('float', 'left').each(function() { var $line = $(this), // TODO replace 8, 4 with a proportional size to the calculated font-size. intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1], lineMax, newFontSize; if($line.hasClass(BigText.EXEMPT_CLASS)) { fontSizes.push(null); ratios.push(null); minFontSizes.push(false); return; } // TODO we can cache this ratio? var autoGuessSubtraction = 32, // font size in px currentFontSize = parseFloat($line.css('font-size')), ratio = ( $line.width() / currentFontSize ).toFixed(6); newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction; outer: for(var m=0, n=intervals.length; m maxFontSize) { newFontSize = maxFontSize; break outer; } lineMax = testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax); if(typeof lineMax !== 'number') { newFontSize = lineMax.size; if(lineMax.match === 'exact') { break outer; } break inner; } } } ratios.push(maxWidth / newFontSize); if(newFontSize > maxFontSize) { fontSizes.push(maxFontSize); minFontSizes.push(false); } else if(!!minFontSize && newFontSize < minFontSize) { fontSizes.push(minFontSize); minFontSizes.push(true); } else { fontSizes.push(newFontSize); minFontSizes.push(false); } }).each(function(lineNumber) { var $line = $(this), wordSpacing = 0, interval = 1, maxWordSpacing; if($line.hasClass(BigText.EXEMPT_CLASS)) { wordSpacings.push(null); return; } // must re-use font-size, even though it was removed above. $line.css('font-size', fontSizes[lineNumber] + 'px'); for(var m=1, n=3; m $().plugin('option', {...}) if ( !PluginClass.prototype.option ) { // option setter PluginClass.prototype.option = function( opts ) { // bail out if not an object if ( !$.isPlainObject( opts ) ){ return; } this.options = $.extend( true, this.options, opts ); }; } // make jQuery plugin $.fn[ namespace ] = function( arg0 /*, arg1 */ ) { if ( typeof arg0 == 'string' ) { // method call $().plugin( 'methodName', { options } ) // shift arguments by 1 var args = arraySlice.call( arguments, 1 ); return methodCall( this, arg0, args ); } // just $().plugin({ options }) plainCall( this, arg0 ); return this; }; // $().plugin('methodName') function methodCall( $elems, methodName, args ) { var returnValue; var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; $elems.each( function( i, elem ) { // get instance var instance = $.data( elem, namespace ); if ( !instance ) { logError( namespace + ' not initialized. Cannot call methods, i.e. ' + pluginMethodStr ); return; } var method = instance[ methodName ]; if ( !method || methodName.charAt(0) == '_' ) { logError( pluginMethodStr + ' is not a valid method' ); return; } // apply method, get return value var value = method.apply( instance, args ); // set return value if value is returned, use only first value returnValue = returnValue === undefined ? value : returnValue; }); return returnValue !== undefined ? returnValue : $elems; } function plainCall( $elems, options ) { $elems.each( function( i, elem ) { var instance = $.data( elem, namespace ); if ( instance ) { // set options & init instance.option( options ); instance._init(); } else { // initialize new instance instance = new PluginClass( elem, options ); $.data( elem, namespace, instance ); } }); } updateJQuery( $ ); } // ----- updateJQuery ----- // // set $.bridget for v1 backwards compatibility function updateJQuery( $ ) { if ( !$ || ( $ && $.bridget ) ) { return; } $.bridget = jQueryBridget; } updateJQuery( jQuery || window.jQuery ); // ----- ----- // return jQueryBridget; })); /** * EvEmitter v1.1.0 * Lil' event emitter * MIT License */ /* jshint unused: true, undef: true, strict: true */ ( function( global, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, window */ if ( typeof define == 'function' && define.amd ) { // AMD - RequireJS define( 'ev-emitter/ev-emitter',factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS - Browserify, Webpack module.exports = factory(); } else { // Browser globals global.EvEmitter = factory(); } }( typeof window != 'undefined' ? window : this, function() { function EvEmitter() {} var proto = EvEmitter.prototype; proto.on = function( eventName, listener ) { if ( !eventName || !listener ) { return; } // set events hash var events = this._events = this._events || {}; // set listeners array var listeners = events[ eventName ] = events[ eventName ] || []; // only add once if ( listeners.indexOf( listener ) == -1 ) { listeners.push( listener ); } return this; }; proto.once = function( eventName, listener ) { if ( !eventName || !listener ) { return; } // add event this.on( eventName, listener ); // set once flag // set onceEvents hash var onceEvents = this._onceEvents = this._onceEvents || {}; // set onceListeners object var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; // set flag onceListeners[ listener ] = true; return this; }; proto.off = function( eventName, listener ) { var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } var index = listeners.indexOf( listener ); if ( index != -1 ) { listeners.splice( index, 1 ); } return this; }; proto.emitEvent = function( eventName, args ) { var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } // copy over to avoid interference if .off() in listener listeners = listeners.slice(0); args = args || []; // once stuff var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; for ( var i=0; i < listeners.length; i++ ) { var listener = listeners[i] var isOnce = onceListeners && onceListeners[ listener ]; if ( isOnce ) { // remove listener // remove before trigger to prevent recursion this.off( eventName, listener ); // unset once flag delete onceListeners[ listener ]; } // trigger listener listener.apply( this, args ); } return this; }; proto.allOff = function() { delete this._events; delete this._onceEvents; }; return EvEmitter; })); /*! * getSize v2.0.3 * measure size of elements * MIT license */ /* jshint browser: true, strict: true, undef: true, unused: true */ /* globals console: false */ ( function( window, factory ) { /* jshint strict: false */ /* globals define, module */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'get-size/get-size',factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory(); } else { // browser global window.getSize = factory(); } })( window, function factory() { 'use strict'; // -------------------------- helpers -------------------------- // // get a number from a string, not a percentage function getStyleSize( value ) { var num = parseFloat( value ); // not a percent like '100%', and a number var isValid = value.indexOf('%') == -1 && !isNaN( num ); return isValid && num; } function noop() {} var logError = typeof console == 'undefined' ? noop : function( message ) { console.error( message ); }; // -------------------------- measurements -------------------------- // var measurements = [ 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth', 'borderBottomWidth' ]; var measurementsLength = measurements.length; function getZeroSize() { var size = { width: 0, height: 0, innerWidth: 0, innerHeight: 0, outerWidth: 0, outerHeight: 0 }; for ( var i=0; i < measurementsLength; i++ ) { var measurement = measurements[i]; size[ measurement ] = 0; } return size; } // -------------------------- getStyle -------------------------- // /** * getStyle, get style of element, check for Firefox bug * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 */ function getStyle( elem ) { var style = getComputedStyle( elem ); if ( !style ) { logError( 'Style returned ' + style + '. Are you running this code in a hidden iframe on Firefox? ' + 'See https://bit.ly/getsizebug1' ); } return style; } // -------------------------- setup -------------------------- // var isSetup = false; var isBoxSizeOuter; /** * setup * check isBoxSizerOuter * do on first getSize() rather than on page load for Firefox bug */ function setup() { // setup once if ( isSetup ) { return; } isSetup = true; // -------------------------- box sizing -------------------------- // /** * Chrome & Safari measure the outer-width on style.width on border-box elems * IE11 & Firefox<29 measures the inner-width */ var div = document.createElement('div'); div.style.width = '200px'; div.style.padding = '1px 2px 3px 4px'; div.style.borderStyle = 'solid'; div.style.borderWidth = '1px 2px 3px 4px'; div.style.boxSizing = 'border-box'; var body = document.body || document.documentElement; body.appendChild( div ); var style = getStyle( div ); // round value for browser zoom. desandro/masonry#928 isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200; getSize.isBoxSizeOuter = isBoxSizeOuter; body.removeChild( div ); } // -------------------------- getSize -------------------------- // function getSize( elem ) { setup(); // use querySeletor if elem is string if ( typeof elem == 'string' ) { elem = document.querySelector( elem ); } // do not proceed on non-objects if ( !elem || typeof elem != 'object' || !elem.nodeType ) { return; } var style = getStyle( elem ); // if hidden, everything is 0 if ( style.display == 'none' ) { return getZeroSize(); } var size = {}; size.width = elem.offsetWidth; size.height = elem.offsetHeight; var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; // get all measurements for ( var i=0; i < measurementsLength; i++ ) { var measurement = measurements[i]; var value = style[ measurement ]; var num = parseFloat( value ); // any 'auto', 'medium' value will be 0 size[ measurement ] = !isNaN( num ) ? num : 0; } var paddingWidth = size.paddingLeft + size.paddingRight; var paddingHeight = size.paddingTop + size.paddingBottom; var marginWidth = size.marginLeft + size.marginRight; var marginHeight = size.marginTop + size.marginBottom; var borderWidth = size.borderLeftWidth + size.borderRightWidth; var borderHeight = size.borderTopWidth + size.borderBottomWidth; var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; // overwrite width and height if we can get it from style var styleWidth = getStyleSize( style.width ); if ( styleWidth !== false ) { size.width = styleWidth + // add padding and border unless it's already including it ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); } var styleHeight = getStyleSize( style.height ); if ( styleHeight !== false ) { size.height = styleHeight + // add padding and border unless it's already including it ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); } size.innerWidth = size.width - ( paddingWidth + borderWidth ); size.innerHeight = size.height - ( paddingHeight + borderHeight ); size.outerWidth = size.width + marginWidth; size.outerHeight = size.height + marginHeight; return size; } return getSize; }); /** * matchesSelector v2.0.2 * matchesSelector( element, '.selector' ) * MIT license */ /*jshint browser: true, strict: true, undef: true, unused: true */ ( function( window, factory ) { /*global define: false, module: false */ 'use strict'; // universal module definition if ( typeof define == 'function' && define.amd ) { // AMD define( 'desandro-matches-selector/matches-selector',factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory(); } else { // browser global window.matchesSelector = factory(); } }( window, function factory() { 'use strict'; var matchesMethod = ( function() { var ElemProto = window.Element.prototype; // check for the standard method name first if ( ElemProto.matches ) { return 'matches'; } // check un-prefixed if ( ElemProto.matchesSelector ) { return 'matchesSelector'; } // check vendor prefixes var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; for ( var i=0; i < prefixes.length; i++ ) { var prefix = prefixes[i]; var method = prefix + 'MatchesSelector'; if ( ElemProto[ method ] ) { return method; } } })(); return function matchesSelector( elem, selector ) { return elem[ matchesMethod ]( selector ); }; })); /** * Fizzy UI utils v2.0.7 * MIT license */ /*jshint browser: true, undef: true, unused: true, strict: true */ ( function( window, factory ) { // universal module definition /*jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'fizzy-ui-utils/utils',[ 'desandro-matches-selector/matches-selector' ], function( matchesSelector ) { return factory( window, matchesSelector ); }); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, require('desandro-matches-selector') ); } else { // browser global window.fizzyUIUtils = factory( window, window.matchesSelector ); } }( window, function factory( window, matchesSelector ) { var utils = {}; // ----- extend ----- // // extends objects utils.extend = function( a, b ) { for ( var prop in b ) { a[ prop ] = b[ prop ]; } return a; }; // ----- modulo ----- // utils.modulo = function( num, div ) { return ( ( num % div ) + div ) % div; }; // ----- makeArray ----- // var arraySlice = Array.prototype.slice; // turn element or nodeList into an array utils.makeArray = function( obj ) { if ( Array.isArray( obj ) ) { // use object if already an array return obj; } // return empty array if undefined or null. #6 if ( obj === null || obj === undefined ) { return []; } var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; if ( isArrayLike ) { // convert nodeList to array return arraySlice.call( obj ); } // array of single index return [ obj ]; }; // ----- removeFrom ----- // utils.removeFrom = function( ary, obj ) { var index = ary.indexOf( obj ); if ( index != -1 ) { ary.splice( index, 1 ); } }; // ----- getParent ----- // utils.getParent = function( elem, selector ) { while ( elem.parentNode && elem != document.body ) { elem = elem.parentNode; if ( matchesSelector( elem, selector ) ) { return elem; } } }; // ----- getQueryElement ----- // // use element as selector string utils.getQueryElement = function( elem ) { if ( typeof elem == 'string' ) { return document.querySelector( elem ); } return elem; }; // ----- handleEvent ----- // // enable .ontype to trigger from .addEventListener( elem, 'type' ) utils.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; // ----- filterFindElements ----- // utils.filterFindElements = function( elems, selector ) { // make array of elems elems = utils.makeArray( elems ); var ffElems = []; elems.forEach( function( elem ) { // check that elem is an actual element // START UNCODE EDIT // if ( !( elem instanceof HTMLElement ) ) { if ( !( elem instanceof HTMLElement ) && !SiteParameters.is_frontend_editor ) { // END UNCODE EDIT return; } // add elem if no selector if ( !selector ) { ffElems.push( elem ); return; } // filter & find items if we have a selector // filter if ( matchesSelector( elem, selector ) ) { ffElems.push( elem ); } // find children var childElems = elem.querySelectorAll( selector ); // concat childElems to filterFound array for ( var i=0; i < childElems.length; i++ ) { ffElems.push( childElems[i] ); } }); return ffElems; }; // ----- debounceMethod ----- // utils.debounceMethod = function( _class, methodName, threshold ) { threshold = threshold || 100; // original method var method = _class.prototype[ methodName ]; var timeoutName = methodName + 'Timeout'; _class.prototype[ methodName ] = function() { var timeout = this[ timeoutName ]; clearTimeout( timeout ); var args = arguments; var _this = this; this[ timeoutName ] = setTimeout( function() { method.apply( _this, args ); delete _this[ timeoutName ]; }, threshold ); }; }; // ----- docReady ----- // utils.docReady = function( callback ) { var readyState = document.readyState; if ( readyState == 'complete' || readyState == 'interactive' ) { // do async to allow for other scripts to run. metafizzy/flickity#441 setTimeout( callback ); } else { document.addEventListener( 'DOMContentLoaded', callback ); } }; // ----- htmlInit ----- // // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ utils.toDashed = function( str ) { return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { return $1 + '-' + $2; }).toLowerCase(); }; var console = window.console; /** * allow user to initialize classes via [data-namespace] or .js-namespace class * htmlInit( Widget, 'widgetName' ) * options are parsed from data-namespace-options */ utils.htmlInit = function( WidgetClass, namespace ) { utils.docReady( function() { var dashedNamespace = utils.toDashed( namespace ); var dataAttr = 'data-' + dashedNamespace; var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' ); var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace ); var elems = utils.makeArray( dataAttrElems ) .concat( utils.makeArray( jsDashElems ) ); var dataOptionsAttr = dataAttr + '-options'; var jQuery = window.jQuery; elems.forEach( function( elem ) { var attr = elem.getAttribute( dataAttr ) || elem.getAttribute( dataOptionsAttr ); var options; try { options = attr && JSON.parse( attr ); } catch ( error ) { // log error, do not initialize if ( console ) { console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className + ': ' + error ); } return; } // initialize var instance = new WidgetClass( elem, options ); // make available via $().data('namespace') if ( jQuery ) { jQuery.data( elem, namespace, instance ); } }); }); }; // ----- ----- // return utils; })); /** * Outlayer Item */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD - RequireJS define( 'outlayer/item',[ 'ev-emitter/ev-emitter', 'get-size/get-size' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS - Browserify, Webpack module.exports = factory( require('ev-emitter'), require('get-size') ); } else { // browser global window.Outlayer = {}; window.Outlayer.Item = factory( window.EvEmitter, window.getSize ); } }( window, function factory( EvEmitter, getSize ) { 'use strict'; // ----- helpers ----- // function isEmptyObj( obj ) { for ( var prop in obj ) { return false; } prop = null; return true; } // -------------------------- CSS3 support -------------------------- // var docElemStyle = document.documentElement.style; var transitionProperty = typeof docElemStyle.transition == 'string' ? 'transition' : 'WebkitTransition'; var transformProperty = typeof docElemStyle.transform == 'string' ? 'transform' : 'WebkitTransform'; var transitionEndEvent = { WebkitTransition: 'webkitTransitionEnd', transition: 'transitionend' }[ transitionProperty ]; // cache all vendor properties that could have vendor prefix var vendorProperties = { transform: transformProperty, transition: transitionProperty, transitionDuration: transitionProperty + 'Duration', transitionProperty: transitionProperty + 'Property', transitionDelay: transitionProperty + 'Delay' }; // -------------------------- Item -------------------------- // function Item( element, layout ) { if ( !element ) { return; } this.element = element; // parent layout class, i.e. Masonry, Isotope, or Packery this.layout = layout; this.position = { x: 0, y: 0 }; this._create(); } // inherit EvEmitter var proto = Item.prototype = Object.create( EvEmitter.prototype ); proto.constructor = Item; proto._create = function() { // transition objects this._transn = { ingProperties: {}, clean: {}, onEnd: {} }; this.css({ position: 'absolute' }); }; // trigger specified handler for event type proto.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; proto.getSize = function() { this.size = getSize( this.element ); }; /** * apply CSS styles to element * @param {Object} style */ proto.css = function( style ) { var elemStyle = this.element.style; for ( var prop in style ) { // use vendor property if available var supportedProp = vendorProperties[ prop ] || prop; elemStyle[ supportedProp ] = style[ prop ]; } }; // measure position, and sets it proto.getPosition = function() { var style = getComputedStyle( this.element ); var isOriginLeft = this.layout._getOption('originLeft'); var isOriginTop = this.layout._getOption('originTop'); var xValue = style[ isOriginLeft ? 'left' : 'right' ]; var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; var x = parseFloat( xValue ); var y = parseFloat( yValue ); // convert percent to pixels var layoutSize = this.layout.size; if ( xValue.indexOf('%') != -1 ) { x = ( x / 100 ) * layoutSize.width; } if ( yValue.indexOf('%') != -1 ) { y = ( y / 100 ) * layoutSize.height; } // clean up 'auto' or other non-integer values x = isNaN( x ) ? 0 : x; y = isNaN( y ) ? 0 : y; // remove padding from measurement x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; this.position.x = x; this.position.y = y; }; // set settled position, apply padding proto.layoutPosition = function() { var layoutSize = this.layout.size; var style = {}; var isOriginLeft = this.layout._getOption('originLeft'); var isOriginTop = this.layout._getOption('originTop'); // x var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight'; var xProperty = isOriginLeft ? 'left' : 'right'; var xResetProperty = isOriginLeft ? 'right' : 'left'; var x = this.position.x + layoutSize[ xPadding ]; // set in percentage or pixels style[ xProperty ] = this.getXValue( x ); // reset other property style[ xResetProperty ] = ''; // y var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom'; var yProperty = isOriginTop ? 'top' : 'bottom'; var yResetProperty = isOriginTop ? 'bottom' : 'top'; var y = this.position.y + layoutSize[ yPadding ]; // set in percentage or pixels style[ yProperty ] = this.getYValue( y ); // reset other property style[ yResetProperty ] = ''; this.css( style ); this.emitEvent( 'layout', [ this ] ); }; proto.getXValue = function( x ) { var isHorizontal = this.layout._getOption('horizontal'); return this.layout.options.percentPosition && !isHorizontal ? ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; }; proto.getYValue = function( y ) { var isHorizontal = this.layout._getOption('horizontal'); return this.layout.options.percentPosition && isHorizontal ? ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; }; proto._transitionTo = function( x, y ) { this.getPosition(); // get current x & y from top/left var curX = this.position.x; var curY = this.position.y; var didNotMove = x == this.position.x && y == this.position.y; // save end position this.setPosition( x, y ); // if did not move and not transitioning, just go to layout if ( didNotMove && !this.isTransitioning ) { this.layoutPosition(); return; } var transX = x - curX; var transY = y - curY; var transitionStyle = {}; transitionStyle.transform = this.getTranslate( transX, transY ); this.transition({ to: transitionStyle, onTransitionEnd: { transform: this.layoutPosition }, isCleaning: true }); }; proto.getTranslate = function( x, y ) { // flip cooridinates if origin on right or bottom var isOriginLeft = this.layout._getOption('originLeft'); var isOriginTop = this.layout._getOption('originTop'); x = isOriginLeft ? x : -x; y = isOriginTop ? y : -y; return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; }; // non transition + transform support proto.goTo = function( x, y ) { this.setPosition( x, y ); this.layoutPosition(); }; proto.moveTo = proto._transitionTo; proto.setPosition = function( x, y ) { this.position.x = parseFloat( x ); this.position.y = parseFloat( y ); }; // ----- transition ----- // /** * @param {Object} style - CSS * @param {Function} onTransitionEnd */ // non transition, just trigger callback proto._nonTransition = function( args ) { this.css( args.to ); if ( args.isCleaning ) { this._removeStyles( args.to ); } for ( var prop in args.onTransitionEnd ) { args.onTransitionEnd[ prop ].call( this ); } }; /** * proper transition * @param {Object} args - arguments * @param {Object} to - style to transition to * @param {Object} from - style to start transition from * @param {Boolean} isCleaning - removes transition styles after transition * @param {Function} onTransitionEnd - callback */ proto.transition = function( args ) { // redirect to nonTransition if no transition duration if ( !parseFloat( this.layout.options.transitionDuration ) ) { this._nonTransition( args ); return; } var _transition = this._transn; // keep track of onTransitionEnd callback by css property for ( var prop in args.onTransitionEnd ) { _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; } // keep track of properties that are transitioning for ( prop in args.to ) { _transition.ingProperties[ prop ] = true; // keep track of properties to clean up when transition is done if ( args.isCleaning ) { _transition.clean[ prop ] = true; } } // set from styles if ( args.from ) { this.css( args.from ); // force redraw. http://blog.alexmaccaw.com/css-transitions var h = this.element.offsetHeight; // hack for JSHint to hush about unused var h = null; } // enable transition this.enableTransition( args.to ); // set styles that are transitioning this.css( args.to ); this.isTransitioning = true; }; // dash before all cap letters, including first for // WebkitTransform => -webkit-transform function toDashedAll( str ) { return str.replace( /([A-Z])/g, function( $1 ) { return '-' + $1.toLowerCase(); }); } var transitionProps = 'opacity,' + toDashedAll( transformProperty ); proto.enableTransition = function(/* style */) { // HACK changing transitionProperty during a transition // will cause transition to jump if ( this.isTransitioning ) { return; } // make `transition: foo, bar, baz` from style object // HACK un-comment this when enableTransition can work // while a transition is happening // var transitionValues = []; // for ( var prop in style ) { // // dash-ify camelCased properties like WebkitTransition // prop = vendorProperties[ prop ] || prop; // transitionValues.push( toDashedAll( prop ) ); // } // munge number to millisecond, to match stagger var duration = this.layout.options.transitionDuration; duration = typeof duration == 'number' ? duration + 'ms' : duration; // enable transition styles this.css({ transitionProperty: transitionProps, transitionDuration: duration, transitionDelay: this.staggerDelay || 0 }); // listen for transition end event this.element.addEventListener( transitionEndEvent, this, false ); }; // ----- events ----- // proto.onwebkitTransitionEnd = function( event ) { this.ontransitionend( event ); }; proto.onotransitionend = function( event ) { this.ontransitionend( event ); }; // properties that I munge to make my life easier var dashedVendorProperties = { '-webkit-transform': 'transform' }; proto.ontransitionend = function( event ) { // disregard bubbled events from children if ( event.target !== this.element ) { return; } var _transition = this._transn; // get property name of transitioned property, convert to prefix-free var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; // remove property that has completed transitioning delete _transition.ingProperties[ propertyName ]; // check if any properties are still transitioning if ( isEmptyObj( _transition.ingProperties ) ) { // all properties have completed transitioning this.disableTransition(); } // clean style if ( propertyName in _transition.clean ) { // clean up style this.element.style[ event.propertyName ] = ''; delete _transition.clean[ propertyName ]; } // trigger onTransitionEnd callback if ( propertyName in _transition.onEnd ) { var onTransitionEnd = _transition.onEnd[ propertyName ]; onTransitionEnd.call( this ); delete _transition.onEnd[ propertyName ]; } this.emitEvent( 'transitionEnd', [ this ] ); }; proto.disableTransition = function() { this.removeTransitionStyles(); this.element.removeEventListener( transitionEndEvent, this, false ); this.isTransitioning = false; }; /** * removes style property from element * @param {Object} style **/ proto._removeStyles = function( style ) { // clean up transition styles var cleanStyle = {}; for ( var prop in style ) { cleanStyle[ prop ] = ''; } this.css( cleanStyle ); }; var cleanTransitionStyle = { transitionProperty: '', transitionDuration: '', transitionDelay: '' }; proto.removeTransitionStyles = function() { // remove transition this.css( cleanTransitionStyle ); }; // ----- stagger ----- // proto.stagger = function( delay ) { delay = isNaN( delay ) ? 0 : delay; this.staggerDelay = delay + 'ms'; }; // ----- show/hide/remove ----- // // remove element from DOM proto.removeElem = function() { this.element.parentNode.removeChild( this.element ); // remove display: none this.css({ display: '' }); this.emitEvent( 'remove', [ this ] ); }; proto.remove = function() { // just remove element if no transition support or no transition if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { this.removeElem(); return; } // start transition this.once( 'transitionEnd', function() { this.removeElem(); }); this.hide(); }; proto.reveal = function() { delete this.isHidden; // remove display: none this.css({ display: '' }); var options = this.layout.options; var onTransitionEnd = {}; var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; this.transition({ from: options.hiddenStyle, to: options.visibleStyle, isCleaning: true, onTransitionEnd: onTransitionEnd }); }; proto.onRevealTransitionEnd = function() { // check if still visible // during transition, item may have been hidden if ( !this.isHidden ) { this.emitEvent('reveal'); } }; /** * get style property use for hide/reveal transition end * @param {String} styleProperty - hiddenStyle/visibleStyle * @returns {String} */ proto.getHideRevealTransitionEndProperty = function( styleProperty ) { var optionStyle = this.layout.options[ styleProperty ]; // use opacity if ( optionStyle.opacity ) { return 'opacity'; } // get first property for ( var prop in optionStyle ) { return prop; } }; proto.hide = function() { // set flag this.isHidden = true; // remove display: none this.css({ display: '' }); var options = this.layout.options; var onTransitionEnd = {}; var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; this.transition({ from: options.visibleStyle, to: options.hiddenStyle, // keep hidden stuff hidden isCleaning: true, onTransitionEnd: onTransitionEnd }); }; proto.onHideTransitionEnd = function() { // check if still hidden // during transition, item may have been un-hidden if ( this.isHidden ) { this.css({ display: 'none' }); this.emitEvent('hide'); } }; proto.destroy = function() { this.css({ position: '', left: '', right: '', top: '', bottom: '', transition: '', transform: '' }); }; return Item; })); /*! * Outlayer v2.1.1 * the brains and guts of a layout library * MIT license */ ( function( window, factory ) { 'use strict'; // universal module definition /* jshint strict: false */ /* globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD - RequireJS define( 'outlayer/outlayer',[ 'ev-emitter/ev-emitter', 'get-size/get-size', 'fizzy-ui-utils/utils', './item' ], function( EvEmitter, getSize, utils, Item ) { return factory( window, EvEmitter, getSize, utils, Item); } ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS - Browserify, Webpack module.exports = factory( window, require('ev-emitter'), require('get-size'), require('fizzy-ui-utils'), require('./item') ); } else { // browser global window.Outlayer = factory( window, window.EvEmitter, window.getSize, window.fizzyUIUtils, window.Outlayer.Item ); } }( window, function factory( window, EvEmitter, getSize, utils, Item ) { 'use strict'; // ----- vars ----- // var console = window.console; var jQuery = window.jQuery; var noop = function() {}; // -------------------------- Outlayer -------------------------- // // globally unique identifiers var GUID = 0; // internal store of all Outlayer intances var instances = {}; /** * @param {Element, String} element * @param {Object} options * @constructor */ function Outlayer( element, options ) { var queryElement = utils.getQueryElement( element ); if ( !queryElement ) { if ( console ) { console.error( 'Bad element for ' + this.constructor.namespace + ': ' + ( queryElement || element ) ); } return; } this.element = queryElement; // add jQuery if ( jQuery ) { this.$element = jQuery( this.element ); } // options this.options = utils.extend( {}, this.constructor.defaults ); this.option( options ); // add id for Outlayer.getFromElement var id = ++GUID; this.element.outlayerGUID = id; // expando instances[ id ] = this; // associate via id // kick it off this._create(); var isInitLayout = this._getOption('initLayout'); if ( isInitLayout ) { this.layout(); } } // settings are for internal use only Outlayer.namespace = 'outlayer'; Outlayer.Item = Item; // default options Outlayer.defaults = { containerStyle: { position: 'relative' }, initLayout: true, originLeft: true, originTop: true, resize: true, resizeContainer: true, // item options transitionDuration: '0.4s', hiddenStyle: { opacity: 0, transform: 'scale(0.001)' }, visibleStyle: { opacity: 1, transform: 'scale(1)' } }; var proto = Outlayer.prototype; // inherit EvEmitter utils.extend( proto, EvEmitter.prototype ); /** * set options * @param {Object} opts */ proto.option = function( opts ) { utils.extend( this.options, opts ); }; /** * get backwards compatible option value, check old name */ proto._getOption = function( option ) { var oldOption = this.constructor.compatOptions[ option ]; return oldOption && this.options[ oldOption ] !== undefined ? this.options[ oldOption ] : this.options[ option ]; }; Outlayer.compatOptions = { // currentName: oldName initLayout: 'isInitLayout', horizontal: 'isHorizontal', layoutInstant: 'isLayoutInstant', originLeft: 'isOriginLeft', originTop: 'isOriginTop', resize: 'isResizeBound', resizeContainer: 'isResizingContainer' }; proto._create = function() { // get items from children this.reloadItems(); // elements that affect layout, but are not laid out this.stamps = []; this.stamp( this.options.stamp ); // set container style utils.extend( this.element.style, this.options.containerStyle ); // bind resize method var canBindResize = this._getOption('resize'); if ( canBindResize ) { this.bindResize(); } }; // goes through all children again and gets bricks in proper order proto.reloadItems = function() { // collection of item elements this.items = this._itemize( this.element.children ); }; /** * turn elements into Outlayer.Items to be used in layout * @param {Array or NodeList or HTMLElement} elems * @returns {Array} items - collection of new Outlayer Items */ proto._itemize = function( elems ) { var itemElems = this._filterFindItemElements( elems ); var Item = this.constructor.Item; // create new Outlayer Items for collection var items = []; for ( var i=0; i < itemElems.length; i++ ) { var elem = itemElems[i]; var item = new Item( elem, this ); items.push( item ); } return items; }; /** * get item elements to be used in layout * @param {Array or NodeList or HTMLElement} elems * @returns {Array} items - item elements */ proto._filterFindItemElements = function( elems ) { return utils.filterFindElements( elems, this.options.itemSelector ); }; /** * getter method for getting item elements * @returns {Array} elems - collection of item elements */ proto.getItemElements = function() { return this.items.map( function( item ) { return item.element; }); }; // ----- init & layout ----- // /** * lays out all items */ proto.layout = function() { this._resetLayout(); this._manageStamps(); // don't animate first layout var layoutInstant = this._getOption('layoutInstant'); var isInstant = layoutInstant !== undefined ? layoutInstant : !this._isLayoutInited; this.layoutItems( this.items, isInstant ); // flag for initalized this._isLayoutInited = true; }; // _init is alias for layout proto._init = proto.layout; /** * logic before any new layout */ proto._resetLayout = function() { this.getSize(); }; proto.getSize = function() { this.size = getSize( this.element ); }; /** * get measurement from option, for columnWidth, rowHeight, gutter * if option is String -> get element from selector string, & get size of element * if option is Element -> get size of element * else use option as a number * * @param {String} measurement * @param {String} size - width or height * @private */ proto._getMeasurement = function( measurement, size ) { var option = this.options[ measurement ]; var elem; if ( !option ) { // default to 0 this[ measurement ] = 0; } else { // use option as an element if ( typeof option == 'string' ) { elem = this.element.querySelector( option ); } else if ( option instanceof HTMLElement ) { elem = option; } // use size of element, if element this[ measurement ] = elem ? getSize( elem )[ size ] : option; } }; /** * layout a collection of item elements * @api public */ proto.layoutItems = function( items, isInstant ) { items = this._getItemsForLayout( items ); this._layoutItems( items, isInstant ); this._postLayout(); }; /** * get the items to be laid out * you may want to skip over some items * @param {Array} items * @returns {Array} items */ proto._getItemsForLayout = function( items ) { return items.filter( function( item ) { return !item.isIgnored; }); }; /** * layout items * @param {Array} items * @param {Boolean} isInstant */ proto._layoutItems = function( items, isInstant ) { this._emitCompleteOnItems( 'layout', items ); if ( !items || !items.length ) { // no items, emit event with empty array return; } var queue = []; items.forEach( function( item ) { // get x/y object from method var position = this._getItemLayoutPosition( item ); // enqueue position.item = item; position.isInstant = isInstant || item.isLayoutInstant; queue.push( position ); }, this ); this._processLayoutQueue( queue ); }; /** * get item layout position * @param {Outlayer.Item} item * @returns {Object} x and y position */ proto._getItemLayoutPosition = function( /* item */ ) { return { x: 0, y: 0 }; }; /** * iterate over array and position each item * Reason being - separating this logic prevents 'layout invalidation' * thx @paul_irish * @param {Array} queue */ proto._processLayoutQueue = function( queue ) { this.updateStagger(); queue.forEach( function( obj, i ) { this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i ); }, this ); }; // set stagger from option in milliseconds number proto.updateStagger = function() { var stagger = this.options.stagger; if ( stagger === null || stagger === undefined ) { this.stagger = 0; return; } this.stagger = getMilliseconds( stagger ); return this.stagger; }; /** * Sets position of item in DOM * @param {Outlayer.Item} item * @param {Number} x - horizontal position * @param {Number} y - vertical position * @param {Boolean} isInstant - disables transitions */ proto._positionItem = function( item, x, y, isInstant, i ) { if ( isInstant ) { // if not transition, just set CSS item.goTo( x, y ); } else { item.stagger( i * this.stagger ); item.moveTo( x, y ); } }; /** * Any logic you want to do after each layout, * i.e. size the container */ proto._postLayout = function() { this.resizeContainer(); }; proto.resizeContainer = function() { var isResizingContainer = this._getOption('resizeContainer'); if ( !isResizingContainer ) { return; } var size = this._getContainerSize(); if ( size ) { this._setContainerMeasure( size.width, true ); this._setContainerMeasure( size.height, false ); } }; /** * Sets width or height of container if returned * @returns {Object} size * @param {Number} width * @param {Number} height */ proto._getContainerSize = noop; /** * @param {Number} measure - size of width or height * @param {Boolean} isWidth */ proto._setContainerMeasure = function( measure, isWidth ) { if ( measure === undefined ) { return; } var elemSize = this.size; // add padding and border width if border box if ( elemSize.isBorderBox ) { measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + elemSize.borderLeftWidth + elemSize.borderRightWidth : elemSize.paddingBottom + elemSize.paddingTop + elemSize.borderTopWidth + elemSize.borderBottomWidth; } measure = Math.max( measure, 0 ); this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; }; /** * emit eventComplete on a collection of items events * @param {String} eventName * @param {Array} items - Outlayer.Items */ proto._emitCompleteOnItems = function( eventName, items ) { var _this = this; function onComplete() { _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); } var count = items.length; if ( !items || !count ) { onComplete(); return; } var doneCount = 0; function tick() { doneCount++; if ( doneCount == count ) { onComplete(); } } // bind callback items.forEach( function( item ) { item.once( eventName, tick ); }); }; /** * emits events via EvEmitter and jQuery events * @param {String} type - name of event * @param {Event} event - original event * @param {Array} args - extra arguments */ proto.dispatchEvent = function( type, event, args ) { // add original event to arguments var emitArgs = event ? [ event ].concat( args ) : args; this.emitEvent( type, emitArgs ); if ( jQuery ) { // set this.$element this.$element = this.$element || jQuery( this.element ); if ( event ) { // create jQuery event var $event = jQuery.Event( event ); $event.type = type; this.$element.trigger( $event, args ); } else { // just trigger with type if no event available this.$element.trigger( type, args ); } } }; // -------------------------- ignore & stamps -------------------------- // /** * keep item in collection, but do not lay it out * ignored items do not get skipped in layout * @param {Element} elem */ proto.ignore = function( elem ) { var item = this.getItem( elem ); if ( item ) { item.isIgnored = true; } }; /** * return item to layout collection * @param {Element} elem */ proto.unignore = function( elem ) { var item = this.getItem( elem ); if ( item ) { delete item.isIgnored; } }; /** * adds elements to stamps * @param {NodeList, Array, Element, or String} elems */ proto.stamp = function( elems ) { elems = this._find( elems ); if ( !elems ) { return; } this.stamps = this.stamps.concat( elems ); // ignore elems.forEach( this.ignore, this ); }; /** * removes elements to stamps * @param {NodeList, Array, or Element} elems */ proto.unstamp = function( elems ) { elems = this._find( elems ); if ( !elems ){ return; } elems.forEach( function( elem ) { // filter out removed stamp elements utils.removeFrom( this.stamps, elem ); this.unignore( elem ); }, this ); }; /** * finds child elements * @param {NodeList, Array, Element, or String} elems * @returns {Array} elems */ proto._find = function( elems ) { if ( !elems ) { return; } // if string, use argument as selector string if ( typeof elems == 'string' ) { elems = this.element.querySelectorAll( elems ); } elems = utils.makeArray( elems ); return elems; }; proto._manageStamps = function() { if ( !this.stamps || !this.stamps.length ) { return; } this._getBoundingRect(); this.stamps.forEach( this._manageStamp, this ); }; // update boundingLeft / Top proto._getBoundingRect = function() { // get bounding rect for container element var boundingRect = this.element.getBoundingClientRect(); var size = this.size; this._boundingRect = { left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, top: boundingRect.top + size.paddingTop + size.borderTopWidth, right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) }; }; /** * @param {Element} stamp **/ proto._manageStamp = noop; /** * get x/y position of element relative to container element * @param {Element} elem * @returns {Object} offset - has left, top, right, bottom */ proto._getElementOffset = function( elem ) { var boundingRect = elem.getBoundingClientRect(); var thisRect = this._boundingRect; var size = getSize( elem ); var offset = { left: boundingRect.left - thisRect.left - size.marginLeft, top: boundingRect.top - thisRect.top - size.marginTop, right: thisRect.right - boundingRect.right - size.marginRight, bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom }; return offset; }; // -------------------------- resize -------------------------- // // enable event handlers for listeners // i.e. resize -> onresize proto.handleEvent = utils.handleEvent; /** * Bind layout to window resizing */ proto.bindResize = function() { window.addEventListener( 'resize', this ); this.isResizeBound = true; }; /** * Unbind layout to window resizing */ proto.unbindResize = function() { window.removeEventListener( 'resize', this ); this.isResizeBound = false; }; proto.onresize = function() { this.resize(); }; utils.debounceMethod( Outlayer, 'onresize', 100 ); proto.resize = function() { // don't trigger if size did not change // or if resize was unbound. See #9 if ( !this.isResizeBound || !this.needsResizeLayout() ) { return; } this.layout(); }; /** * check if layout is needed post layout * @returns Boolean */ proto.needsResizeLayout = function() { var size = getSize( this.element ); // check that this.size and size are there // IE8 triggers resize on body size change, so they might not be var hasSizes = this.size && size; return hasSizes && size.innerWidth !== this.size.innerWidth; }; // -------------------------- methods -------------------------- // /** * add items to Outlayer instance * @param {Array or NodeList or Element} elems * @returns {Array} items - Outlayer.Items **/ proto.addItems = function( elems ) { var items = this._itemize( elems ); // add items to collection if ( items.length ) { this.items = this.items.concat( items ); } return items; }; /** * Layout newly-appended item elements * @param {Array or NodeList or Element} elems */ proto.appended = function( elems ) { var items = this.addItems( elems ); if ( !items.length ) { return; } // layout and reveal just the new items this.layoutItems( items, true ); this.reveal( items ); }; /** * Layout prepended elements * @param {Array or NodeList or Element} elems */ proto.prepended = function( elems ) { var items = this._itemize( elems ); if ( !items.length ) { return; } // add items to beginning of collection var previousItems = this.items.slice(0); this.items = items.concat( previousItems ); // start new layout this._resetLayout(); this._manageStamps(); // layout new stuff without transition this.layoutItems( items, true ); this.reveal( items ); // layout previous items this.layoutItems( previousItems ); }; /** * reveal a collection of items * @param {Array of Outlayer.Items} items */ proto.reveal = function( items ) { this._emitCompleteOnItems( 'reveal', items ); if ( !items || !items.length ) { return; } var stagger = this.updateStagger(); items.forEach( function( item, i ) { item.stagger( i * stagger ); item.reveal(); }); }; /** * hide a collection of items * @param {Array of Outlayer.Items} items */ proto.hide = function( items ) { this._emitCompleteOnItems( 'hide', items ); if ( !items || !items.length ) { return; } var stagger = this.updateStagger(); items.forEach( function( item, i ) { item.stagger( i * stagger ); item.hide(); }); }; /** * reveal item elements * @param {Array}, {Element}, {NodeList} items */ proto.revealItemElements = function( elems ) { var items = this.getItems( elems ); this.reveal( items ); }; /** * hide item elements * @param {Array}, {Element}, {NodeList} items */ proto.hideItemElements = function( elems ) { var items = this.getItems( elems ); this.hide( items ); }; /** * get Outlayer.Item, given an Element * @param {Element} elem * @param {Function} callback * @returns {Outlayer.Item} item */ proto.getItem = function( elem ) { // loop through items to get the one that matches for ( var i=0; i < this.items.length; i++ ) { var item = this.items[i]; if ( item.element == elem ) { // return item return item; } } }; /** * get collection of Outlayer.Items, given Elements * @param {Array} elems * @returns {Array} items - Outlayer.Items */ proto.getItems = function( elems ) { elems = utils.makeArray( elems ); var items = []; elems.forEach( function( elem ) { var item = this.getItem( elem ); if ( item ) { items.push( item ); } }, this ); return items; }; /** * remove element(s) from instance and DOM * @param {Array or NodeList or Element} elems */ proto.remove = function( elems ) { var removeItems = this.getItems( elems ); this._emitCompleteOnItems( 'remove', removeItems ); // bail if no items to remove if ( !removeItems || !removeItems.length ) { return; } removeItems.forEach( function( item ) { item.remove(); // remove item from collection utils.removeFrom( this.items, item ); }, this ); }; // ----- destroy ----- // // remove and disable Outlayer instance proto.destroy = function() { // clean up dynamic styles var style = this.element.style; style.height = ''; style.position = ''; style.width = ''; // destroy items this.items.forEach( function( item ) { item.destroy(); }); this.unbindResize(); var id = this.element.outlayerGUID; delete instances[ id ]; // remove reference to instance by id delete this.element.outlayerGUID; // remove data for jQuery if ( jQuery ) { jQuery.removeData( this.element, this.constructor.namespace ); } }; // -------------------------- data -------------------------- // /** * get Outlayer instance from element * @param {Element} elem * @returns {Outlayer} */ Outlayer.data = function( elem ) { elem = utils.getQueryElement( elem ); var id = elem && elem.outlayerGUID; return id && instances[ id ]; }; // -------------------------- create Outlayer class -------------------------- // /** * create a layout class * @param {String} namespace */ Outlayer.create = function( namespace, options ) { // sub-class Outlayer var Layout = subclass( Outlayer ); // apply new options and compatOptions Layout.defaults = utils.extend( {}, Outlayer.defaults ); utils.extend( Layout.defaults, options ); Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions ); Layout.namespace = namespace; Layout.data = Outlayer.data; // sub-class Item Layout.Item = subclass( Item ); // -------------------------- declarative -------------------------- // utils.htmlInit( Layout, namespace ); // -------------------------- jQuery bridge -------------------------- // // make into jQuery plugin if ( jQuery && jQuery.bridget ) { jQuery.bridget( namespace, Layout ); } return Layout; }; function subclass( Parent ) { function SubClass() { Parent.apply( this, arguments ); } SubClass.prototype = Object.create( Parent.prototype ); SubClass.prototype.constructor = SubClass; return SubClass; } // ----- helpers ----- // // how many milliseconds are in each unit var msUnits = { ms: 1, s: 1000 }; // munge time-like parameter into millisecond number // '0.4s' -> 40 function getMilliseconds( time ) { if ( typeof time == 'number' ) { return time; } var matches = time.match( /(^\d*\.?\d*)(\w*)/ ); var num = matches && matches[1]; var unit = matches && matches[2]; if ( !num.length ) { return 0; } num = parseFloat( num ); var mult = msUnits[ unit ] || 1; return num * mult; } // ----- fin ----- // // back in global Outlayer.Item = Item; return Outlayer; })); /** * Isotope Item **/ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'isotope-layout/js/item',[ 'outlayer/outlayer' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('outlayer') ); } else { // browser global window.Isotope = window.Isotope || {}; window.Isotope.Item = factory( window.Outlayer ); } }( window, function factory( Outlayer ) { 'use strict'; // -------------------------- Item -------------------------- // // sub-class Outlayer Item function Item() { Outlayer.Item.apply( this, arguments ); } var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); var _create = proto._create; proto._create = function() { // assign id, used for original-order sorting this.id = this.layout.itemGUID++; _create.call( this ); this.sortData = {}; }; proto.updateSortData = function() { if ( this.isIgnored ) { return; } // default sorters this.sortData.id = this.id; // for backward compatibility this.sortData['original-order'] = this.id; this.sortData.random = Math.random(); // go thru getSortData obj and apply the sorters var getSortData = this.layout.options.getSortData; var sorters = this.layout._sorters; for ( var key in getSortData ) { var sorter = sorters[ key ]; this.sortData[ key ] = sorter( this.element, this ); } }; var _destroy = proto.destroy; proto.destroy = function() { // call super _destroy.apply( this, arguments ); // reset display, #741 this.css({ display: '' }); }; return Item; })); /** * Isotope LayoutMode */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'isotope-layout/js/layout-mode',[ 'get-size/get-size', 'outlayer/outlayer' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('get-size'), require('outlayer') ); } else { // browser global window.Isotope = window.Isotope || {}; window.Isotope.LayoutMode = factory( window.getSize, window.Outlayer ); } }( window, function factory( getSize, Outlayer ) { 'use strict'; // layout mode class function LayoutMode( isotope ) { this.isotope = isotope; // link properties if ( isotope ) { this.options = isotope.options[ this.namespace ]; this.element = isotope.element; this.items = isotope.filteredItems; this.size = isotope.size; } } var proto = LayoutMode.prototype; /** * some methods should just defer to default Outlayer method * and reference the Isotope instance as `this` **/ var facadeMethods = [ '_resetLayout', '_getItemLayoutPosition', '_manageStamp', '_getContainerSize', '_getElementOffset', 'needsResizeLayout', '_getOption' ]; facadeMethods.forEach( function( methodName ) { proto[ methodName ] = function() { return Outlayer.prototype[ methodName ].apply( this.isotope, arguments ); }; }); // ----- ----- // // for horizontal layout modes, check vertical size proto.needsVerticalResizeLayout = function() { // don't trigger if size did not change var size = getSize( this.isotope.element ); // check that this.size and size are there // IE8 triggers resize on body size change, so they might not be var hasSizes = this.isotope.size && size; return hasSizes && size.innerHeight != this.isotope.size.innerHeight; }; // ----- measurements ----- // proto._getMeasurement = function() { this.isotope._getMeasurement.apply( this, arguments ); }; proto.getColumnWidth = function() { this.getSegmentSize( 'column', 'Width' ); }; proto.getRowHeight = function() { this.getSegmentSize( 'row', 'Height' ); }; /** * get columnWidth or rowHeight * segment: 'column' or 'row' * size 'Width' or 'Height' **/ proto.getSegmentSize = function( segment, size ) { var segmentName = segment + size; var outerSize = 'outer' + size; // columnWidth / outerWidth // rowHeight / outerHeight this._getMeasurement( segmentName, outerSize ); // got rowHeight or columnWidth, we can chill if ( this[ segmentName ] ) { return; } // fall back to item of first element var firstItemSize = this.getFirstItemSize(); this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] || // or size of container this.isotope.size[ 'inner' + size ]; }; proto.getFirstItemSize = function() { var firstItem = this.isotope.filteredItems[0]; return firstItem && firstItem.element && getSize( firstItem.element ); }; // ----- methods that should reference isotope ----- // proto.layout = function() { this.isotope.layout.apply( this.isotope, arguments ); }; proto.getSize = function() { this.isotope.getSize(); this.size = this.isotope.size; }; // -------------------------- create -------------------------- // LayoutMode.modes = {}; LayoutMode.create = function( namespace, options ) { function Mode() { LayoutMode.apply( this, arguments ); } Mode.prototype = Object.create( proto ); Mode.prototype.constructor = Mode; // default options if ( options ) { Mode.options = options; } Mode.prototype.namespace = namespace; // register in Isotope LayoutMode.modes[ namespace ] = Mode; return Mode; }; return LayoutMode; })); /*! * Masonry v4.2.1 * Cascading grid layout library * https://masonry.desandro.com * MIT License * by David DeSandro */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'masonry-layout/masonry',[ 'outlayer/outlayer', 'get-size/get-size' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('outlayer'), require('get-size') ); } else { // browser global window.Masonry = factory( window.Outlayer, window.getSize ); } }( window, function factory( Outlayer, getSize ) { // -------------------------- masonryDefinition -------------------------- // // create an Outlayer layout class var Masonry = Outlayer.create('masonry'); // isFitWidth -> fitWidth Masonry.compatOptions.fitWidth = 'isFitWidth'; var proto = Masonry.prototype; proto._resetLayout = function() { this.getSize(); this._getMeasurement( 'columnWidth', 'outerWidth' ); this._getMeasurement( 'gutter', 'outerWidth' ); this.measureColumns(); // reset column Y this.colYs = []; for ( var i=0; i < this.cols; i++ ) { this.colYs.push( 0 ); } this.maxY = 0; this.horizontalColIndex = 0; }; proto.measureColumns = function() { this.getContainerWidth(); // if columnWidth is 0, default to outerWidth of first item if ( !this.columnWidth ) { var firstItem = this.items[0]; var firstItemElem = firstItem && firstItem.element; // columnWidth fall back to item of first element this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || // if first elem has no width, default to size of container this.containerWidth; } var columnWidth = this.columnWidth += this.gutter; // calculate columns var containerWidth = this.containerWidth + this.gutter; var cols = containerWidth / columnWidth; // fix rounding errors, typically with gutters var excess = columnWidth - containerWidth % columnWidth; // if overshoot is less than a pixel, round up, otherwise floor it var mathMethod = excess && excess < 1 ? 'round' : 'floor'; cols = Math[ mathMethod ]( cols ); this.cols = Math.max( cols, 1 ); }; proto.getContainerWidth = function() { // container is parent if fit width var isFitWidth = this._getOption('fitWidth'); var container = isFitWidth ? this.element.parentNode : this.element; // check that this.size and size are there // IE8 triggers resize on body size change, so they might not be var size = getSize( container ); this.containerWidth = size && size.innerWidth; }; proto._getItemLayoutPosition = function( item ) { item.getSize(); // how many columns does this brick span var remainder = item.size.outerWidth % this.columnWidth; var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; // round if off by 1 pixel, otherwise use ceil var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); colSpan = Math.min( colSpan, this.cols ); // use horizontal or top column position var colPosMethod = this.options.horizontalOrder ? '_getHorizontalColPosition' : '_getTopColPosition'; var colPosition = this[ colPosMethod ]( colSpan, item ); // position the brick var position = { x: this.columnWidth * colPosition.col, y: colPosition.y }; // apply setHeight to necessary columns var setHeight = colPosition.y + item.size.outerHeight; var setMax = colSpan + colPosition.col; for ( var i = colPosition.col; i < setMax; i++ ) { this.colYs[i] = setHeight; } return position; }; proto._getTopColPosition = function( colSpan ) { var colGroup = this._getTopColGroup( colSpan ); // get the minimum Y value from the columns var minimumY = Math.min.apply( Math, colGroup ); return { col: colGroup.indexOf( minimumY ), y: minimumY, }; }; /** * @param {Number} colSpan - number of columns the element spans * @returns {Array} colGroup */ proto._getTopColGroup = function( colSpan ) { if ( colSpan < 2 ) { // if brick spans only one column, use all the column Ys return this.colYs; } var colGroup = []; // how many different places could this brick fit horizontally var groupCount = this.cols + 1 - colSpan; // for each group potential horizontal position for ( var i = 0; i < groupCount; i++ ) { colGroup[i] = this._getColGroupY( i, colSpan ); } return colGroup; }; proto._getColGroupY = function( col, colSpan ) { if ( colSpan < 2 ) { return this.colYs[ col ]; } // make an array of colY values for that one group var groupColYs = this.colYs.slice( col, col + colSpan ); // and get the max value of the array return Math.max.apply( Math, groupColYs ); }; // get column position based on horizontal index. #873 proto._getHorizontalColPosition = function( colSpan, item ) { var col = this.horizontalColIndex % this.cols; var isOver = colSpan > 1 && col + colSpan > this.cols; // shift to next row if item can't fit on current row col = isOver ? 0 : col; // don't let zero-size items take up space var hasSize = item.size.outerWidth && item.size.outerHeight; this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex; return { col: col, y: this._getColGroupY( col, colSpan ), }; }; proto._manageStamp = function( stamp ) { var stampSize = getSize( stamp ); var offset = this._getElementOffset( stamp ); // get the columns that this stamp affects var isOriginLeft = this._getOption('originLeft'); var firstX = isOriginLeft ? offset.left : offset.right; var lastX = firstX + stampSize.outerWidth; var firstCol = Math.floor( firstX / this.columnWidth ); firstCol = Math.max( 0, firstCol ); var lastCol = Math.floor( lastX / this.columnWidth ); // lastCol should not go over if multiple of columnWidth #425 lastCol -= lastX % this.columnWidth ? 0 : 1; lastCol = Math.min( this.cols - 1, lastCol ); // set colYs to bottom of the stamp var isOriginTop = this._getOption('originTop'); var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) + stampSize.outerHeight; for ( var i = firstCol; i <= lastCol; i++ ) { this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); } }; proto._getContainerSize = function() { this.maxY = Math.max.apply( Math, this.colYs ); var size = { height: this.maxY }; if ( this._getOption('fitWidth') ) { size.width = this._getContainerFitWidth(); } return size; }; proto._getContainerFitWidth = function() { var unusedCols = 0; // count unused columns var i = this.cols; while ( --i ) { if ( this.colYs[i] !== 0 ) { break; } unusedCols++; } // fit container to columns that have been used return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; }; proto.needsResizeLayout = function() { var previousWidth = this.containerWidth; this.getContainerWidth(); return previousWidth != this.containerWidth; }; return Masonry; })); /*! * Masonry layout mode * sub-classes Masonry * https://masonry.desandro.com */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'isotope-layout/js/layout-modes/masonry',[ '../layout-mode', 'masonry-layout/masonry' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('../layout-mode'), require('masonry-layout') ); } else { // browser global factory( window.Isotope.LayoutMode, window.Masonry ); } }( window, function factory( LayoutMode, Masonry ) { 'use strict'; // -------------------------- masonryDefinition -------------------------- // // create an Outlayer layout class var MasonryMode = LayoutMode.create('masonry'); var proto = MasonryMode.prototype; var keepModeMethods = { _getElementOffset: true, layout: true, _getMeasurement: true }; // inherit Masonry prototype for ( var method in Masonry.prototype ) { // do not inherit mode methods if ( !keepModeMethods[ method ] ) { proto[ method ] = Masonry.prototype[ method ]; } } var measureColumns = proto.measureColumns; proto.measureColumns = function() { // set items, used if measuring first item this.items = this.isotope.filteredItems; measureColumns.call( this ); }; // point to mode options for fitWidth var _getOption = proto._getOption; proto._getOption = function( option ) { if ( option == 'fitWidth' ) { return this.options.isFitWidth !== undefined ? this.options.isFitWidth : this.options.fitWidth; } return _getOption.apply( this.isotope, arguments ); }; return MasonryMode; })); /** * fitRows layout mode */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'isotope-layout/js/layout-modes/fit-rows',[ '../layout-mode' ], factory ); } else if ( typeof exports == 'object' ) { // CommonJS module.exports = factory( require('../layout-mode') ); } else { // browser global factory( window.Isotope.LayoutMode ); } }( window, function factory( LayoutMode ) { 'use strict'; var FitRows = LayoutMode.create('fitRows'); var proto = FitRows.prototype; proto._resetLayout = function() { this.x = 0; this.y = 0; this.maxY = 0; this._getMeasurement( 'gutter', 'outerWidth' ); }; proto._getItemLayoutPosition = function( item ) { item.getSize(); var itemWidth = item.size.outerWidth + this.gutter; // if this element cannot fit in the current row var containerWidth = this.isotope.size.innerWidth + this.gutter; if ( this.x !== 0 && itemWidth + this.x > containerWidth ) { this.x = 0; this.y = this.maxY; } var position = { x: this.x, y: this.y }; this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight ); this.x += itemWidth; return position; }; proto._getContainerSize = function() { return { height: this.maxY }; }; return FitRows; })); /** * vertical layout mode */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'isotope-layout/js/layout-modes/vertical',[ '../layout-mode' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('../layout-mode') ); } else { // browser global factory( window.Isotope.LayoutMode ); } }( window, function factory( LayoutMode ) { 'use strict'; var Vertical = LayoutMode.create( 'vertical', { horizontalAlignment: 0 }); var proto = Vertical.prototype; proto._resetLayout = function() { this.y = 0; }; proto._getItemLayoutPosition = function( item ) { item.getSize(); var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) * this.options.horizontalAlignment; var y = this.y; this.y += item.size.outerHeight; return { x: x, y: y }; }; proto._getContainerSize = function() { return { height: this.y }; }; return Vertical; })); /*! * Isotope v3.0.6 * * Licensed GPLv3 for open source use * or Isotope Commercial License for commercial use * * https://isotope.metafizzy.co * Copyright 2010-2018 Metafizzy */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( [ 'outlayer/outlayer', 'get-size/get-size', 'desandro-matches-selector/matches-selector', 'fizzy-ui-utils/utils', 'isotope-layout/js/item', 'isotope-layout/js/layout-mode', // include default layout modes 'isotope-layout/js/layout-modes/masonry', 'isotope-layout/js/layout-modes/fit-rows', 'isotope-layout/js/layout-modes/vertical' ], function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ); }); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, require('outlayer'), require('get-size'), require('desandro-matches-selector'), require('fizzy-ui-utils'), require('isotope-layout/js/item'), require('isotope-layout/js/layout-mode'), // include default layout modes require('isotope-layout/js/layout-modes/masonry'), require('isotope-layout/js/layout-modes/fit-rows'), require('isotope-layout/js/layout-modes/vertical') ); } else { // browser global window.Isotope = factory( window, window.Outlayer, window.getSize, window.matchesSelector, window.fizzyUIUtils, window.Isotope.Item, window.Isotope.LayoutMode ); } }( window, function factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { // -------------------------- vars -------------------------- // var jQuery = window.jQuery; // -------------------------- helpers -------------------------- // var trim = String.prototype.trim ? function( str ) { return str.trim(); } : function( str ) { return str.replace( /^\s+|\s+$/g, '' ); }; // -------------------------- isotopeDefinition -------------------------- // // create an Outlayer layout class var Isotope = Outlayer.create( 'isotope', { layoutMode: 'masonry', isJQueryFiltering: true, sortAscending: true }); Isotope.Item = Item; Isotope.LayoutMode = LayoutMode; var proto = Isotope.prototype; proto._create = function() { this.itemGUID = 0; // functions that sort items this._sorters = {}; this._getSorters(); // call super Outlayer.prototype._create.call( this ); // create layout modes this.modes = {}; // start filteredItems with all items this.filteredItems = this.items; // keep of track of sortBys this.sortHistory = [ 'original-order' ]; // create from registered layout modes for ( var name in LayoutMode.modes ) { this._initLayoutMode( name ); } }; proto.reloadItems = function() { // reset item ID counter this.itemGUID = 0; // call super Outlayer.prototype.reloadItems.call( this ); }; proto._itemize = function() { var items = Outlayer.prototype._itemize.apply( this, arguments ); // assign ID for original-order for ( var i=0; i < items.length; i++ ) { var item = items[i]; item.id = this.itemGUID++; } this._updateItemsSortData( items ); return items; }; // -------------------------- layout -------------------------- // proto._initLayoutMode = function( name ) { var Mode = LayoutMode.modes[ name ]; // set mode options // HACK extend initial options, back-fill in default options var initialOpts = this.options[ name ] || {}; this.options[ name ] = Mode.options ? utils.extend( Mode.options, initialOpts ) : initialOpts; // init layout mode instance this.modes[ name ] = new Mode( this ); }; proto.layout = function() { // if first time doing layout, do all magic if ( !this._isLayoutInited && this._getOption('initLayout') ) { this.arrange(); return; } this._layout(); }; // private method to be used in layout() & magic() proto._layout = function() { // don't animate first layout var isInstant = this._getIsInstant(); // layout flow this._resetLayout(); this._manageStamps(); this.layoutItems( this.filteredItems, isInstant ); // flag for initalized this._isLayoutInited = true; }; // filter + sort + layout proto.arrange = function( opts ) { // set any options pass this.option( opts ); this._getIsInstant(); // filter, sort, and layout // filter var filtered = this._filter( this.items ); this.filteredItems = filtered.matches; this._bindArrangeComplete(); if ( this._isInstant ) { this._noTransition( this._hideReveal, [ filtered ] ); } else { this._hideReveal( filtered ); } this._sort(); this._layout(); }; // alias to _init for main plugin method proto._init = proto.arrange; proto._hideReveal = function( filtered ) { this.reveal( filtered.needReveal ); this.hide( filtered.needHide ); }; // HACK // Don't animate/transition first layout // Or don't animate/transition other layouts proto._getIsInstant = function() { var isLayoutInstant = this._getOption('layoutInstant'); var isInstant = isLayoutInstant !== undefined ? isLayoutInstant : !this._isLayoutInited; this._isInstant = isInstant; return isInstant; }; // listen for layoutComplete, hideComplete and revealComplete // to trigger arrangeComplete proto._bindArrangeComplete = function() { // listen for 3 events to trigger arrangeComplete var isLayoutComplete, isHideComplete, isRevealComplete; var _this = this; function arrangeParallelCallback() { if ( isLayoutComplete && isHideComplete && isRevealComplete ) { _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] ); } } this.once( 'layoutComplete', function() { isLayoutComplete = true; arrangeParallelCallback(); }); this.once( 'hideComplete', function() { isHideComplete = true; arrangeParallelCallback(); }); this.once( 'revealComplete', function() { isRevealComplete = true; arrangeParallelCallback(); }); }; // -------------------------- filter -------------------------- // proto._filter = function( items ) { var filter = this.options.filter; filter = filter || '*'; var matches = []; var hiddenMatched = []; var visibleUnmatched = []; var test = this._getFilterTest( filter ); // test each item for ( var i=0; i < items.length; i++ ) { var item = items[i]; if ( item.isIgnored ) { continue; } // add item to either matched or unmatched group var isMatched = test( item ); // item.isFilterMatched = isMatched; // add to matches if its a match if ( isMatched ) { matches.push( item ); } // add to additional group if item needs to be hidden or revealed if ( isMatched && item.isHidden ) { hiddenMatched.push( item ); } else if ( !isMatched && !item.isHidden ) { visibleUnmatched.push( item ); } } // return collections of items to be manipulated return { matches: matches, needReveal: hiddenMatched, needHide: visibleUnmatched }; }; // get a jQuery, function, or a matchesSelector test given the filter proto._getFilterTest = function( filter ) { if ( jQuery && this.options.isJQueryFiltering ) { // use jQuery return function( item ) { return jQuery( item.element ).is( filter ); }; } if ( typeof filter == 'function' ) { // use filter as function return function( item ) { return filter( item.element ); }; } // default, use filter as selector string return function( item ) { return matchesSelector( item.element, filter ); }; }; // -------------------------- sorting -------------------------- // /** * @params {Array} elems * @public */ proto.updateSortData = function( elems ) { // get items var items; if ( elems ) { elems = utils.makeArray( elems ); items = this.getItems( elems ); } else { // update all items if no elems provided items = this.items; } this._getSorters(); this._updateItemsSortData( items ); }; proto._getSorters = function() { var getSortData = this.options.getSortData; for ( var key in getSortData ) { var sorter = getSortData[ key ]; this._sorters[ key ] = mungeSorter( sorter ); } }; /** * @params {Array} items - of Isotope.Items * @private */ proto._updateItemsSortData = function( items ) { // do not update if no items var len = items && items.length; for ( var i=0; len && i < len; i++ ) { var item = items[i]; item.updateSortData(); } }; // ----- munge sorter ----- // // encapsulate this, as we just need mungeSorter // other functions in here are just for munging var mungeSorter = ( function() { // add a magic layer to sorters for convienent shorthands // `.foo-bar` will use the text of .foo-bar querySelector // `[foo-bar]` will use attribute // you can also add parser // `.foo-bar parseInt` will parse that as a number function mungeSorter( sorter ) { // if not a string, return function or whatever it is if ( typeof sorter != 'string' ) { return sorter; } // parse the sorter string var args = trim( sorter ).split(' '); var query = args[0]; // check if query looks like [an-attribute] var attrMatch = query.match( /^\[(.+)\]$/ ); var attr = attrMatch && attrMatch[1]; var getValue = getValueGetter( attr, query ); // use second argument as a parser var parser = Isotope.sortDataParsers[ args[1] ]; // parse the value, if there was a parser sorter = parser ? function( elem ) { return elem && parser( getValue( elem ) ); } : // otherwise just return value function( elem ) { return elem && getValue( elem ); }; return sorter; } // get an attribute getter, or get text of the querySelector function getValueGetter( attr, query ) { // if query looks like [foo-bar], get attribute if ( attr ) { return function getAttribute( elem ) { return elem.getAttribute( attr ); }; } // otherwise, assume its a querySelector, and get its text return function getChildText( elem ) { var child = elem.querySelector( query ); return child && child.textContent; }; } return mungeSorter; })(); // parsers used in getSortData shortcut strings Isotope.sortDataParsers = { 'parseInt': function( val ) { return parseInt( val, 10 ); }, 'parseFloat': function( val ) { return parseFloat( val ); } }; // ----- sort method ----- // // sort filteredItem order proto._sort = function() { if ( !this.options.sortBy ) { return; } // keep track of sortBy History var sortBys = utils.makeArray( this.options.sortBy ); if ( !this._getIsSameSortBy( sortBys ) ) { // concat all sortBy and sortHistory, add to front, oldest goes in last this.sortHistory = sortBys.concat( this.sortHistory ); } // sort magic var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending ); this.filteredItems.sort( itemSorter ); }; // check if sortBys is same as start of sortHistory proto._getIsSameSortBy = function( sortBys ) { for ( var i=0; i < sortBys.length; i++ ) { if ( sortBys[i] != this.sortHistory[i] ) { return false; } } return true; }; // returns a function used for sorting function getItemSorter( sortBys, sortAsc ) { return function sorter( itemA, itemB ) { // cycle through all sortKeys for ( var i = 0; i < sortBys.length; i++ ) { var sortBy = sortBys[i]; var a = itemA.sortData[ sortBy ]; var b = itemB.sortData[ sortBy ]; if ( a > b || a < b ) { // if sortAsc is an object, use the value given the sortBy key var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc; var direction = isAscending ? 1 : -1; return ( a > b ? 1 : -1 ) * direction; } } return 0; }; } // -------------------------- methods -------------------------- // // get layout mode proto._mode = function() { var layoutMode = this.options.layoutMode; var mode = this.modes[ layoutMode ]; if ( !mode ) { // TODO console.error throw new Error( 'No layout mode: ' + layoutMode ); } // HACK sync mode's options // any options set after init for layout mode need to be synced mode.options = this.options[ layoutMode ]; return mode; }; proto._resetLayout = function() { // trigger original reset layout Outlayer.prototype._resetLayout.call( this ); this._mode()._resetLayout(); }; proto._getItemLayoutPosition = function( item ) { return this._mode()._getItemLayoutPosition( item ); }; proto._manageStamp = function( stamp ) { this._mode()._manageStamp( stamp ); }; proto._getContainerSize = function() { return this._mode()._getContainerSize(); }; proto.needsResizeLayout = function() { return this._mode().needsResizeLayout(); }; // -------------------------- adding & removing -------------------------- // // HEADS UP overwrites default Outlayer appended proto.appended = function( elems ) { var items = this.addItems( elems ); if ( !items.length ) { return; } // filter, layout, reveal new items var filteredItems = this._filterRevealAdded( items ); // add to filteredItems this.filteredItems = this.filteredItems.concat( filteredItems ); }; // HEADS UP overwrites default Outlayer prepended proto.prepended = function( elems ) { var items = this._itemize( elems ); if ( !items.length ) { return; } // start new layout this._resetLayout(); this._manageStamps(); // filter, layout, reveal new items var filteredItems = this._filterRevealAdded( items ); // layout previous items this.layoutItems( this.filteredItems ); // add to items and filteredItems this.filteredItems = filteredItems.concat( this.filteredItems ); this.items = items.concat( this.items ); }; proto._filterRevealAdded = function( items ) { var filtered = this._filter( items ); this.hide( filtered.needHide ); // reveal all new items this.reveal( filtered.matches ); // layout new items, no transition this.layoutItems( filtered.matches, true ); return filtered.matches; }; /** * Filter, sort, and layout newly-appended item elements * @param {Array or NodeList or Element} elems */ proto.insert = function( elems ) { var items = this.addItems( elems ); if ( !items.length ) { return; } // append item elements var i, item; var len = items.length; for ( i=0; i < len; i++ ) { item = items[i]; this.element.appendChild( item.element ); } // filter new stuff var filteredInsertItems = this._filter( items ).matches; // set flag for ( i=0; i < len; i++ ) { items[i].isLayoutInstant = true; } this.arrange(); // reset flag for ( i=0; i < len; i++ ) { delete items[i].isLayoutInstant; } this.reveal( filteredInsertItems ); }; var _remove = proto.remove; proto.remove = function( elems ) { elems = utils.makeArray( elems ); var removeItems = this.getItems( elems ); // do regular thing _remove.call( this, elems ); // bail if no items to remove var len = removeItems && removeItems.length; // remove elems from filteredItems for ( var i=0; len && i < len; i++ ) { var item = removeItems[i]; // remove item from collection utils.removeFrom( this.filteredItems, item ); } }; proto.shuffle = function() { // update random sortData for ( var i=0; i < this.items.length; i++ ) { var item = this.items[i]; item.sortData.random = Math.random(); } this.options.sortBy = 'random'; this._sort(); this._layout(); }; /** * trigger fn without transition * kind of hacky to have this in the first place * @param {Function} fn * @param {Array} args * @returns ret * @private */ proto._noTransition = function( fn, args ) { // save transitionDuration before disabling var transitionDuration = this.options.transitionDuration; // disable transition this.options.transitionDuration = 0; // do it var returnValue = fn.apply( this, args ); // re-enable transition for reveal this.options.transitionDuration = transitionDuration; return returnValue; }; // ----- helper methods ----- // /** * getter method for getting filtered item elements * @returns {Array} elems - collection of item elements */ proto.getFilteredItemElements = function() { return this.filteredItems.map( function( item ) { return item.element; }); }; // ----- ----- // return Isotope; })); /*! * Packery layout mode PACKAGED v2.0.1 * sub-classes Packery */ /** * Rect * low-level utility class for basic geometry */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'packery/js/rect',factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory(); } else { // browser global window.Packery = window.Packery || {}; window.Packery.Rect = factory(); } }( window, function factory() { // -------------------------- Rect -------------------------- // function Rect( props ) { // extend properties from defaults for ( var prop in Rect.defaults ) { this[ prop ] = Rect.defaults[ prop ]; } for ( prop in props ) { this[ prop ] = props[ prop ]; } } Rect.defaults = { x: 0, y: 0, width: 0, height: 0 }; var proto = Rect.prototype; /** * Determines whether or not this rectangle wholly encloses another rectangle or point. * @param {Rect} rect * @returns {Boolean} **/ proto.contains = function( rect ) { // points don't have width or height var otherWidth = rect.width || 0; var otherHeight = rect.height || 0; return this.x <= rect.x && this.y <= rect.y && this.x + this.width >= rect.x + otherWidth && this.y + this.height >= rect.y + otherHeight; }; /** * Determines whether or not the rectangle intersects with another. * @param {Rect} rect * @returns {Boolean} **/ proto.overlaps = function( rect ) { var thisRight = this.x + this.width; var thisBottom = this.y + this.height; var rectRight = rect.x + rect.width; var rectBottom = rect.y + rect.height; // http://stackoverflow.com/a/306332 return this.x < rectRight && thisRight > rect.x && this.y < rectBottom && thisBottom > rect.y; }; /** * @param {Rect} rect - the overlapping rect * @returns {Array} freeRects - rects representing the area around the rect **/ proto.getMaximalFreeRects = function( rect ) { // if no intersection, return false if ( !this.overlaps( rect ) ) { return false; } var freeRects = []; var freeRect; var thisRight = this.x + this.width; var thisBottom = this.y + this.height; var rectRight = rect.x + rect.width; var rectBottom = rect.y + rect.height; // top if ( this.y < rect.y ) { freeRect = new Rect({ x: this.x, y: this.y, width: this.width, height: rect.y - this.y }); freeRects.push( freeRect ); } // right if ( thisRight > rectRight ) { freeRect = new Rect({ x: rectRight, y: this.y, width: thisRight - rectRight, height: this.height }); freeRects.push( freeRect ); } // bottom if ( thisBottom > rectBottom ) { freeRect = new Rect({ x: this.x, y: rectBottom, width: this.width, height: thisBottom - rectBottom }); freeRects.push( freeRect ); } // left if ( this.x < rect.x ) { freeRect = new Rect({ x: this.x, y: this.y, width: rect.x - this.x, height: this.height }); freeRects.push( freeRect ); } return freeRects; }; proto.canFit = function( rect ) { return this.width >= rect.width && this.height >= rect.height; }; return Rect; })); /** * Packer * bin-packing algorithm */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'packery/js/packer',[ './rect' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('./rect') ); } else { // browser global var Packery = window.Packery = window.Packery || {}; Packery.Packer = factory( Packery.Rect ); } }( window, function factory( Rect ) { // -------------------------- Packer -------------------------- // /** * @param {Number} width * @param {Number} height * @param {String} sortDirection * topLeft for vertical, leftTop for horizontal */ function Packer( width, height, sortDirection ) { this.width = width || 0; this.height = height || 0; this.sortDirection = sortDirection || 'downwardLeftToRight'; this.reset(); } var proto = Packer.prototype; proto.reset = function() { this.spaces = []; var initialSpace = new Rect({ x: 0, y: 0, width: this.width, height: this.height }); this.spaces.push( initialSpace ); // set sorter this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; }; // change x and y of rect to fit with in Packer's available spaces proto.pack = function( rect ) { for ( var i=0; i < this.spaces.length; i++ ) { var space = this.spaces[i]; if ( space.canFit( rect ) ) { this.placeInSpace( rect, space ); break; } } }; proto.columnPack = function( rect ) { for ( var i=0; i < this.spaces.length; i++ ) { var space = this.spaces[i]; var canFitInSpaceColumn = space.x <= rect.x && space.x + space.width >= rect.x + rect.width && space.height >= rect.height - 0.01; // fudge number for rounding error if ( canFitInSpaceColumn ) { rect.y = space.y; this.placed( rect ); break; } } }; proto.rowPack = function( rect ) { for ( var i=0; i < this.spaces.length; i++ ) { var space = this.spaces[i]; var canFitInSpaceRow = space.y <= rect.y && space.y + space.height >= rect.y + rect.height && space.width >= rect.width - 0.01; // fudge number for rounding error if ( canFitInSpaceRow ) { rect.x = space.x; this.placed( rect ); break; } } }; proto.placeInSpace = function( rect, space ) { // place rect in space rect.x = space.x; rect.y = space.y; this.placed( rect ); }; // update spaces with placed rect proto.placed = function( rect ) { // update spaces var revisedSpaces = []; for ( var i=0; i < this.spaces.length; i++ ) { var space = this.spaces[i]; var newSpaces = space.getMaximalFreeRects( rect ); // add either the original space or the new spaces to the revised spaces if ( newSpaces ) { revisedSpaces.push.apply( revisedSpaces, newSpaces ); } else { revisedSpaces.push( space ); } } this.spaces = revisedSpaces; this.mergeSortSpaces(); }; proto.mergeSortSpaces = function() { // remove redundant spaces Packer.mergeRects( this.spaces ); this.spaces.sort( this.sorter ); }; // add a space back proto.addSpace = function( rect ) { this.spaces.push( rect ); this.mergeSortSpaces(); }; // -------------------------- utility functions -------------------------- // /** * Remove redundant rectangle from array of rectangles * @param {Array} rects: an array of Rects * @returns {Array} rects: an array of Rects **/ Packer.mergeRects = function( rects ) { var i = 0; var rect = rects[i]; rectLoop: while ( rect ) { var j = 0; var compareRect = rects[ i + j ]; while ( compareRect ) { if ( compareRect == rect ) { j++; // next } else if ( compareRect.contains( rect ) ) { // remove rect rects.splice( i, 1 ); rect = rects[i]; // set next rect continue rectLoop; // bail on compareLoop } else if ( rect.contains( compareRect ) ) { // remove compareRect rects.splice( i + j, 1 ); } else { j++; } compareRect = rects[ i + j ]; // set next compareRect } i++; rect = rects[i]; } return rects; }; // -------------------------- sorters -------------------------- // // functions for sorting rects in order var sorters = { // top down, then left to right downwardLeftToRight: function( a, b ) { return a.y - b.y || a.x - b.x; }, // left to right, then top down rightwardTopToBottom: function( a, b ) { return a.x - b.x || a.y - b.y; } }; // -------------------------- -------------------------- // return Packer; })); /** * Packery Item Element **/ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'packery/js/item',[ 'outlayer/outlayer', './rect' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('outlayer'), require('./rect') ); } else { // browser global window.Packery.Item = factory( window.Outlayer, window.Packery.Rect ); } }( window, function factory( Outlayer, Rect ) { // -------------------------- Item -------------------------- // var docElemStyle = document.documentElement.style; var transformProperty = typeof docElemStyle.transform == 'string' ? 'transform' : 'WebkitTransform'; // sub-class Item var Item = function PackeryItem() { Outlayer.Item.apply( this, arguments ); }; var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); var __create = proto._create; proto._create = function() { // call default _create logic __create.call( this ); this.rect = new Rect(); }; var _moveTo = proto.moveTo; proto.moveTo = function( x, y ) { // don't shift 1px while dragging var dx = Math.abs( this.position.x - x ); var dy = Math.abs( this.position.y - y ); var canHackGoTo = this.layout.dragItemCount && !this.isPlacing && !this.isTransitioning && dx < 1 && dy < 1; if ( canHackGoTo ) { this.goTo( x, y ); return; } _moveTo.apply( this, arguments ); }; // -------------------------- placing -------------------------- // proto.enablePlacing = function() { this.removeTransitionStyles(); // remove transform property from transition if ( this.isTransitioning && transformProperty ) { this.element.style[ transformProperty ] = 'none'; } this.isTransitioning = false; this.getSize(); this.layout._setRectSize( this.element, this.rect ); this.isPlacing = true; }; proto.disablePlacing = function() { this.isPlacing = false; }; // ----- ----- // // remove element from DOM proto.removeElem = function() { this.element.parentNode.removeChild( this.element ); // add space back to packer this.layout.packer.addSpace( this.rect ); this.emitEvent( 'remove', [ this ] ); }; // ----- dropPlaceholder ----- // proto.showDropPlaceholder = function() { var dropPlaceholder = this.dropPlaceholder; if ( !dropPlaceholder ) { // create dropPlaceholder dropPlaceholder = this.dropPlaceholder = document.createElement('div'); dropPlaceholder.className = 'packery-drop-placeholder'; dropPlaceholder.style.position = 'absolute'; } dropPlaceholder.style.width = this.size.width + 'px'; dropPlaceholder.style.height = this.size.height + 'px'; this.positionDropPlaceholder(); this.layout.element.appendChild( dropPlaceholder ); }; proto.positionDropPlaceholder = function() { this.dropPlaceholder.style[ transformProperty ] = 'translate(' + this.rect.x + 'px, ' + this.rect.y + 'px)'; }; proto.hideDropPlaceholder = function() { this.layout.element.removeChild( this.dropPlaceholder ); }; // ----- ----- // return Item; })); /*! * Packery v2.0.0 * Gapless, draggable grid layouts * * Licensed GPLv3 for open source use * or Packery Commercial License for commercial use * * http://packery.metafizzy.co * Copyright 2016 Metafizzy */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, require */ if ( typeof define == 'function' && define.amd ) { // AMD define( 'packery/js/packery',[ 'get-size/get-size', 'outlayer/outlayer', './rect', './packer', './item' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('get-size'), require('outlayer'), require('./rect'), require('./packer'), require('./item') ); } else { // browser global window.Packery = factory( window.getSize, window.Outlayer, window.Packery.Rect, window.Packery.Packer, window.Packery.Item ); } }( window, function factory( getSize, Outlayer, Rect, Packer, Item ) { // ----- Rect ----- // // allow for pixel rounding errors IE8-IE11 & Firefox; #227 Rect.prototype.canFit = function( rect ) { return this.width >= rect.width - 1 && this.height >= rect.height - 1; }; // -------------------------- Packery -------------------------- // // create an Outlayer layout class var Packery = Outlayer.create('packery'); Packery.Item = Item; var proto = Packery.prototype; proto._create = function() { // call super Outlayer.prototype._create.call( this ); // initial properties this.packer = new Packer(); // packer for drop targets this.shiftPacker = new Packer(); this.isEnabled = true; this.dragItemCount = 0; // create drag handlers var _this = this; this.handleDraggabilly = { dragStart: function() { _this.itemDragStart( this.element ); }, dragMove: function() { _this.itemDragMove( this.element, this.position.x, this.position.y ); }, dragEnd: function() { _this.itemDragEnd( this.element ); } }; this.handleUIDraggable = { start: function handleUIDraggableStart( event, ui ) { // HTML5 may trigger dragstart, dismiss HTML5 dragging if ( !ui ) { return; } _this.itemDragStart( event.currentTarget ); }, drag: function handleUIDraggableDrag( event, ui ) { if ( !ui ) { return; } _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); }, stop: function handleUIDraggableStop( event, ui ) { if ( !ui ) { return; } _this.itemDragEnd( event.currentTarget ); } }; }; // ----- init & layout ----- // /** * logic before any new layout */ proto._resetLayout = function() { this.getSize(); this._getMeasurements(); // reset packer var width, height, sortDirection; // packer settings, if horizontal or vertical if ( this._getOption('horizontal') ) { width = Infinity; height = this.size.innerHeight + this.gutter; sortDirection = 'rightwardTopToBottom'; } else { width = this.size.innerWidth + this.gutter; height = Infinity; sortDirection = 'downwardLeftToRight'; } this.packer.width = this.shiftPacker.width = width; this.packer.height = this.shiftPacker.height = height; this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection; this.packer.reset(); // layout this.maxY = 0; this.maxX = 0; }; /** * update columnWidth, rowHeight, & gutter * @private */ proto._getMeasurements = function() { this._getMeasurement( 'columnWidth', 'width' ); this._getMeasurement( 'rowHeight', 'height' ); this._getMeasurement( 'gutter', 'width' ); }; proto._getItemLayoutPosition = function( item ) { this._setRectSize( item.element, item.rect ); if ( this.isShifting || this.dragItemCount > 0 ) { var packMethod = this._getPackMethod(); this.packer[ packMethod ]( item.rect ); } else { this.packer.pack( item.rect ); } this._setMaxXY( item.rect ); return item.rect; }; proto.shiftLayout = function() { this.isShifting = true; this.layout(); delete this.isShifting; }; proto._getPackMethod = function() { return this._getOption('horizontal') ? 'rowPack' : 'columnPack'; }; /** * set max X and Y value, for size of container * @param {Packery.Rect} rect * @private */ proto._setMaxXY = function( rect ) { this.maxX = Math.max( rect.x + rect.width, this.maxX ); this.maxY = Math.max( rect.y + rect.height, this.maxY ); }; /** * set the width and height of a rect, applying columnWidth and rowHeight * @param {Element} elem * @param {Packery.Rect} rect */ proto._setRectSize = function( elem, rect ) { var size = getSize( elem ); var w = size.outerWidth; var h = size.outerHeight; // size for columnWidth and rowHeight, if available // only check if size is non-zero, #177 if ( w || h ) { w = this._applyGridGutter( w, this.columnWidth ); h = this._applyGridGutter( h, this.rowHeight ); } // rect must fit in packer rect.width = Math.min( w, this.packer.width ); rect.height = Math.min( h, this.packer.height ); }; /** * fits item to columnWidth/rowHeight and adds gutter * @param {Number} measurement - item width or height * @param {Number} gridSize - columnWidth or rowHeight * @returns measurement */ proto._applyGridGutter = function( measurement, gridSize ) { // just add gutter if no gridSize if ( !gridSize ) { return measurement + this.gutter; } gridSize += this.gutter; // fit item to columnWidth/rowHeight var remainder = measurement % gridSize; var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; return measurement; }; proto._getContainerSize = function() { if ( this._getOption('horizontal') ) { return { width: this.maxX - this.gutter }; } else { return { height: this.maxY - this.gutter }; } }; // -------------------------- stamp -------------------------- // /** * makes space for element * @param {Element} elem */ proto._manageStamp = function( elem ) { var item = this.getItem( elem ); var rect; if ( item && item.isPlacing ) { rect = item.rect; } else { var offset = this._getElementOffset( elem ); rect = new Rect({ x: this._getOption('originLeft') ? offset.left : offset.right, y: this._getOption('originTop') ? offset.top : offset.bottom }); } this._setRectSize( elem, rect ); // save its space in the packer this.packer.placed( rect ); this._setMaxXY( rect ); }; // -------------------------- methods -------------------------- // function verticalSorter( a, b ) { return a.position.y - b.position.y || a.position.x - b.position.x; } function horizontalSorter( a, b ) { return a.position.x - b.position.x || a.position.y - b.position.y; } proto.sortItemsByPosition = function() { var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter; this.items.sort( sorter ); }; /** * Fit item element in its current position * Packery will position elements around it * useful for expanding elements * * @param {Element} elem * @param {Number} x - horizontal destination position, optional * @param {Number} y - vertical destination position, optional */ proto.fit = function( elem, x, y ) { var item = this.getItem( elem ); if ( !item ) { return; } // stamp item to get it out of layout this.stamp( item.element ); // set placing flag item.enablePlacing(); this.updateShiftTargets( item ); // fall back to current position for fitting x = x === undefined ? item.rect.x: x; y = y === undefined ? item.rect.y: y; // position it best at its destination this.shift( item, x, y ); this._bindFitEvents( item ); item.moveTo( item.rect.x, item.rect.y ); // layout everything else this.shiftLayout(); // return back to regularly scheduled programming this.unstamp( item.element ); this.sortItemsByPosition(); item.disablePlacing(); }; /** * emit event when item is fit and other items are laid out * @param {Packery.Item} item * @private */ proto._bindFitEvents = function( item ) { var _this = this; var ticks = 0; function onLayout() { ticks++; if ( ticks != 2 ) { return; } _this.dispatchEvent( 'fitComplete', null, [ item ] ); } // when item is laid out item.once( 'layout', onLayout ); // when all items are laid out this.once( 'layoutComplete', onLayout ); }; // -------------------------- resize -------------------------- // // debounced, layout on resize proto.resize = function() { // don't trigger if size did not change // or if resize was unbound. See #285, outlayer#9 if ( !this.isResizeBound || !this.needsResizeLayout() ) { return; } if ( this.options.shiftPercentResize ) { this.resizeShiftPercentLayout(); } else { this.layout(); } }; /** * check if layout is needed post layout * @returns Boolean */ proto.needsResizeLayout = function() { var size = getSize( this.element ); var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth'; return size[ innerSize ] != this.size[ innerSize ]; }; proto.resizeShiftPercentLayout = function() { var items = this._getItemsForLayout( this.items ); var isHorizontal = this._getOption('horizontal'); var coord = isHorizontal ? 'y' : 'x'; var measure = isHorizontal ? 'height' : 'width'; var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth'; // proportional re-align items var previousSegment = this[ segmentName ]; previousSegment = previousSegment && previousSegment + this.gutter; if ( previousSegment ) { this._getMeasurements(); var currentSegment = this[ segmentName ] + this.gutter; items.forEach( function( item ) { var seg = Math.round( item.rect[ coord ] / previousSegment ); item.rect[ coord ] = seg * currentSegment; }); } else { var currentSize = getSize( this.element )[ innerSize ] + this.gutter; var previousSize = this.packer[ measure ]; items.forEach( function( item ) { item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize; }); } this.shiftLayout(); }; // -------------------------- drag -------------------------- // /** * handle an item drag start event * @param {Element} elem */ proto.itemDragStart = function( elem ) { if ( !this.isEnabled ) { return; } this.stamp( elem ); // this.ignore( elem ); var item = this.getItem( elem ); if ( !item ) { return; } item.enablePlacing(); item.showDropPlaceholder(); this.dragItemCount++; this.updateShiftTargets( item ); }; proto.updateShiftTargets = function( dropItem ) { this.shiftPacker.reset(); // pack stamps this._getBoundingRect(); var isOriginLeft = this._getOption('originLeft'); var isOriginTop = this._getOption('originTop'); this.stamps.forEach( function( stamp ) { // ignore dragged item var item = this.getItem( stamp ); if ( item && item.isPlacing ) { return; } var offset = this._getElementOffset( stamp ); var rect = new Rect({ x: isOriginLeft ? offset.left : offset.right, y: isOriginTop ? offset.top : offset.bottom }); this._setRectSize( stamp, rect ); // save its space in the packer this.shiftPacker.placed( rect ); }, this ); // reset shiftTargets var isHorizontal = this._getOption('horizontal'); var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; var measure = isHorizontal ? 'height' : 'width'; this.shiftTargetKeys = []; this.shiftTargets = []; var boundsSize; var segment = this[ segmentName ]; segment = segment && segment + this.gutter; if ( segment ) { var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment ); var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment ); boundsSize = ( segs - segmentSpan ) * segment; // add targets on top for ( var i=0; i < segs; i++ ) { this._addShiftTarget( i * segment, 0, boundsSize ); } } else { boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ]; this._addShiftTarget( 0, 0, boundsSize ); } // pack each item to measure where shiftTargets are var items = this._getItemsForLayout( this.items ); var packMethod = this._getPackMethod(); items.forEach( function( item ) { var rect = item.rect; this._setRectSize( item.element, rect ); this.shiftPacker[ packMethod ]( rect ); // add top left corner this._addShiftTarget( rect.x, rect.y, boundsSize ); // add bottom left / top right corner var cornerX = isHorizontal ? rect.x + rect.width : rect.x; var cornerY = isHorizontal ? rect.y : rect.y + rect.height; this._addShiftTarget( cornerX, cornerY, boundsSize ); if ( segment ) { // add targets for each column on bottom / row on right var segSpan = Math.round( rect[ measure ] / segment ); for ( var i=1; i < segSpan; i++ ) { var segX = isHorizontal ? cornerX : rect.x + segment * i; var segY = isHorizontal ? rect.y + segment * i : cornerY; this._addShiftTarget( segX, segY, boundsSize ); } } }, this ); }; proto._addShiftTarget = function( x, y, boundsSize ) { var checkCoord = this._getOption('horizontal') ? y : x; if ( checkCoord !== 0 && checkCoord > boundsSize ) { return; } // create string for a key, easier to keep track of what targets var key = x + ',' + y; var hasKey = this.shiftTargetKeys.indexOf( key ) != -1; if ( hasKey ) { return; } this.shiftTargetKeys.push( key ); this.shiftTargets.push({ x: x, y: y }); }; // -------------------------- drop -------------------------- // proto.shift = function( item, x, y ) { var shiftPosition; var minDistance = Infinity; var position = { x: x, y: y }; this.shiftTargets.forEach( function( target ) { var distance = getDistance( target, position ); if ( distance < minDistance ) { shiftPosition = target; minDistance = distance; } }); item.rect.x = shiftPosition.x; item.rect.y = shiftPosition.y; }; function getDistance( a, b ) { var dx = b.x - a.x; var dy = b.y - a.y; return Math.sqrt( dx * dx + dy * dy ); } // -------------------------- drag move -------------------------- // var DRAG_THROTTLE_TIME = 120; /** * handle an item drag move event * @param {Element} elem * @param {Number} x - horizontal change in position * @param {Number} y - vertical change in position */ proto.itemDragMove = function( elem, x, y ) { var item = this.isEnabled && this.getItem( elem ); if ( !item ) { return; } x -= this.size.paddingLeft; y -= this.size.paddingTop; var _this = this; function onDrag() { _this.shift( item, x, y ); item.positionDropPlaceholder(); _this.layout(); } // throttle var now = new Date(); if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) { clearTimeout( this.dragTimeout ); this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME ); } else { onDrag(); this._itemDragTime = now; } }; // -------------------------- drag end -------------------------- // /** * handle an item drag end event * @param {Element} elem */ proto.itemDragEnd = function( elem ) { var item = this.isEnabled && this.getItem( elem ); if ( !item ) { return; } clearTimeout( this.dragTimeout ); item.element.classList.add('is-positioning-post-drag'); var completeCount = 0; var _this = this; function onDragEndLayoutComplete() { completeCount++; if ( completeCount != 2 ) { return; } // reset drag item item.element.classList.remove('is-positioning-post-drag'); item.hideDropPlaceholder(); _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); } item.once( 'layout', onDragEndLayoutComplete ); this.once( 'layoutComplete', onDragEndLayoutComplete ); item.moveTo( item.rect.x, item.rect.y ); this.layout(); this.dragItemCount = Math.max( 0, this.dragItemCount - 1 ); this.sortItemsByPosition(); item.disablePlacing(); this.unstamp( item.element ); }; /** * binds Draggabilly events * @param {Draggabilly} draggie */ proto.bindDraggabillyEvents = function( draggie ) { this._bindDraggabillyEvents( draggie, 'on' ); }; proto.unbindDraggabillyEvents = function( draggie ) { this._bindDraggabillyEvents( draggie, 'off' ); }; proto._bindDraggabillyEvents = function( draggie, method ) { var handlers = this.handleDraggabilly; draggie[ method ]( 'dragStart', handlers.dragStart ); draggie[ method ]( 'dragMove', handlers.dragMove ); draggie[ method ]( 'dragEnd', handlers.dragEnd ); }; /** * binds jQuery UI Draggable events * @param {jQuery} $elems */ proto.bindUIDraggableEvents = function( $elems ) { this._bindUIDraggableEvents( $elems, 'on' ); }; proto.unbindUIDraggableEvents = function( $elems ) { this._bindUIDraggableEvents( $elems, 'off' ); }; proto._bindUIDraggableEvents = function( $elems, method ) { var handlers = this.handleUIDraggable; $elems [ method ]( 'dragstart', handlers.start ) [ method ]( 'drag', handlers.drag ) [ method ]( 'dragstop', handlers.stop ); }; // ----- destroy ----- // var _destroy = proto.destroy; proto.destroy = function() { _destroy.apply( this, arguments ); // disable flag; prevent drag events from triggering. #72 this.isEnabled = false; }; // ----- ----- // Packery.Rect = Rect; Packery.Packer = Packer; return Packery; })); /*! * Packery layout mode v2.0.1 * sub-classes Packery */ /*jshint browser: true, strict: true, undef: true, unused: true */ ( function( window, factory ) { // universal module definition if ( typeof define == 'function' && define.amd ) { // AMD define( [ 'isotope-layout/js/layout-mode', 'packery/js/packery' ], factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('isotope-layout/js/layout-mode'), require('packery') ); } else { // browser global factory( window.Isotope.LayoutMode, window.Packery ); } }( window, function factor( LayoutMode, Packery ) { // create an Outlayer layout class var PackeryMode = LayoutMode.create('packery'); var proto = PackeryMode.prototype; var keepModeMethods = { _getElementOffset: true, _getMeasurement: true }; // inherit Packery prototype for ( var method in Packery.prototype ) { // do not inherit mode methods if ( !keepModeMethods[ method ] ) { proto[ method ] = Packery.prototype[ method ]; } } // set packer in _resetLayout var _resetLayout = proto._resetLayout; proto._resetLayout = function() { this.packer = this.packer || new Packery.Packer(); this.shiftPacker = this.shiftPacker || new Packery.Packer(); _resetLayout.apply( this, arguments ); }; var _getItemLayoutPosition = proto._getItemLayoutPosition; proto._getItemLayoutPosition = function( item ) { // set packery rect item.rect = item.rect || new Packery.Rect(); return _getItemLayoutPosition.call( this, item ); }; // needsResizeLayout for vertical or horizontal var _needsResizeLayout = proto.needsResizeLayout; proto.needsResizeLayout = function() { if ( this._getOption('horizontal') ) { return this.needsVerticalResizeLayout(); } else { return _needsResizeLayout.call( this ); } }; // point to mode options for horizontal var _getOption = proto._getOption; proto._getOption = function( option ) { if ( option == 'horizontal' ) { return this.options.isHorizontal !== undefined ? this.options.isHorizontal : this.options.horizontal; } return _getOption.apply( this.isotope, arguments ); }; return PackeryMode; })); /*! * cellsByRows layout mode for Isotope * v1.1.3 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html */ /*jshint browser: true, devel: false, strict: true, undef: true, unused: true */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( typeof define === 'function' && define.amd ) { // AMD define( [ 'isotope/js/layout-mode' ], factory ); } else if ( typeof exports === 'object' ) { // CommonJS module.exports = factory( require('isotope-layout/js/layout-mode') ); } else { // browser global factory( window.Isotope.LayoutMode ); } }( window, function factory( LayoutMode ) { 'use strict'; var CellsByRow = LayoutMode.create( 'cellsByRow' ); var proto = CellsByRow.prototype; proto._resetLayout = function() { // reset properties this.itemIndex = 0; // measurements this.getColumnWidth(); this.getRowHeight(); // set cols this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth ); this.cols = Math.max( this.cols, 1 ); }; proto._getItemLayoutPosition = function( item ) { item.getSize(); var col = this.itemIndex % this.cols; var row = Math.floor( this.itemIndex / this.cols ); // center item within cell var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2; var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2; this.itemIndex++; return { x: x, y: y }; }; proto._getContainerSize = function() { return { height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight }; }; return CellsByRow; })); /*global jQuery: true */ /*! -------------------------------- Infinite Scroll -------------------------------- + https://github.com/paulirish/infinite-scroll + version 2.1.0 + Copyright 2011/12 Paul Irish & Luke Shumard + Licensed under the MIT license + Documentation: http://infinite-scroll.com/ */ // Uses AMD or browser globals to create a jQuery plugin. (function (factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], factory); } else { // Browser globals factory(jQuery); } }(function ($, undefined) { 'use strict'; $.infinitescroll = function infscr(options, callback, element) { this.element = $(element); // Flag the object in the event of a failed creation if (!this._create(options, callback)) { this.failed = true; } }; $.infinitescroll.defaults = { loading: { finished: undefined, finishedMsg: "Congratulations, you've reached the end of the internet.", img: 'data:image/gif;base64,R0lGODlh3AATAPQeAPDy+MnQ6LW/4N3h8MzT6rjC4sTM5r/I5NHX7N7j8c7U6tvg8OLl8uXo9Ojr9b3G5MfP6Ovu9tPZ7PT1+vX2+tbb7vf4+8/W69jd7rC73vn5/O/x+K243ai02////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQECgD/ACwAAAAA3AATAAAF/6AnjmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEj0BAScpHLJbDqf0Kh0Sq1ar9isdioItAKGw+MAKYMFhbF63CW438f0mg1R2O8EuXj/aOPtaHx7fn96goR4hmuId4qDdX95c4+RBIGCB4yAjpmQhZN0YGYGXitdZBIVGAsLoq4BBKQDswm1CQRkcG6ytrYKubq8vbfAcMK9v7q7EMO1ycrHvsW6zcTKsczNz8HZw9vG3cjTsMIYqQkCLBwHCgsMDQ4RDAYIqfYSFxDxEfz88/X38Onr16+Bp4ADCco7eC8hQYMAEe57yNCew4IVBU7EGNDiRn8Z831cGLHhSIgdFf9chIeBg7oA7gjaWUWTVQAGE3LqBDCTlc9WOHfm7PkTqNCh54rePDqB6M+lR536hCpUqs2gVZM+xbrTqtGoWqdy1emValeXKzggYBBB5y1acFNZmEvXAoN2cGfJrTv3bl69Ffj2xZt3L1+/fw3XRVw4sGDGcR0fJhxZsF3KtBTThZxZ8mLMgC3fRatCbYMNFCzwLEqLgE4NsDWs/tvqdezZf13Hvk2A9Szdu2X3pg18N+68xXn7rh1c+PLksI/Dhe6cuO3ow3NfV92bdArTqC2Ebd3A8vjf5QWfH6Bg7Nz17c2fj69+fnq+8N2Lty+fuP78/eV2X13neIcCeBRwxorbZrA1ANoCDGrgoG8RTshahQ9iSKEEzUmYIYfNWViUhheCGJyIP5E4oom7WWjgCeBFAJNv1DVV01MAdJhhjdkplWNzO/5oXI846njjVEIqR2OS2B1pE5PVscajkxhMycqLJghQSwT40PgfAl4GqNSXYdZXJn5gSkmmmmJu1aZYb14V51do+pTOCmA40AqVCIhG5IJ9PvYnhIFOxmdqhpaI6GeHCtpooisuutmg+Eg62KOMKuqoTaXgicQWoIYq6qiklmoqFV0UoeqqrLbq6quwxirrrLTWauutJ4QAACH5BAUKABwALAcABADOAAsAAAX/IPd0D2dyRCoUp/k8gpHOKtseR9yiSmGbuBykler9XLAhkbDavXTL5k2oqFqNOxzUZPU5YYZd1XsD72rZpBjbeh52mSNnMSC8lwblKZGwi+0QfIJ8CncnCoCDgoVnBHmKfByGJimPkIwtiAeBkH6ZHJaKmCeVnKKTHIihg5KNq4uoqmEtcRUtEREMBggtEr4QDrjCuRC8h7/BwxENeicSF8DKy82pyNLMOxzWygzFmdvD2L3P0dze4+Xh1Arkyepi7dfFvvTtLQkZBC0T/FX3CRgCMOBHsJ+EHYQY7OinAGECgQsB+Lu3AOK+CewcWjwxQeJBihtNGHSoQOE+iQ3//4XkwBBhRZMcUS6YSXOAwIL8PGqEaSJCiYt9SNoCmnJPAgUVLChdaoFBURN8MAzl2PQphwQLfDFd6lTowglHve6rKpbjhK7/pG5VinZP1qkiz1rl4+tr2LRwWU64cFEihwEtZgbgR1UiHaMVvxpOSwBA37kzGz9e8G+B5MIEKLutOGEsAH2ATQwYfTmuX8aETWdGPZmiZcccNSzeTCA1Sw0bdiitC7LBWgu8jQr8HRzqgpK6gX88QbrB14z/kF+ELpwB8eVQj/JkqdylAudji/+ts3039vEEfK8Vz2dlvxZKG0CmbkKDBvllRd6fCzDvBLKBDSCeffhRJEFebFk1k/Mv9jVIoIJZSeBggwUaNeB+Qk34IE0cXlihcfRxkOAJFFhwGmKlmWDiakZhUJtnLBpnWWcnKaAZcxI0piFGGLBm1mc90kajSCveeBVWKeYEoU2wqeaQi0PetoE+rr14EpVC7oAbAUHqhYExbn2XHHsVqbcVew9tx8+XJKk5AZsqqdlddGpqAKdbAYBn1pcczmSTdWvdmZ17c1b3FZ99vnTdCRFM8OEcAhLwm1NdXnWcBBSMRWmfkWZqVlsmLIiAp/o1gGV2vpS4lalGYsUOqXrddcKCmK61aZ8SjEpUpVFVoCpTj4r661Km7kBHjrDyc1RAIQAAIfkEBQoAGwAsBwAEAM4ACwAABf/gtmUCd4goQQgFKj6PYKi0yrrbc8i4ohQt12EHcal+MNSQiCP8gigdz7iCioaCIvUmZLp8QBzW0EN2vSlCuDtFKaq4RyHzQLEKZNdiQDhRDVooCwkbfm59EAmKi4SGIm+AjIsKjhsqB4mSjT2IOIOUnICeCaB/mZKFNTSRmqVpmJqklSqskq6PfYYCDwYHDC4REQwGCBLGxxIQDsHMwhAIX8bKzcENgSLGF9PU1j3Sy9zX2NrgzQziChLk1BHWxcjf7N046tvN82715czn9Pryz6Ilc4ACj4EBOCZM8KEnAYYADBRKnACAYUMFv1wotIhCEcaJCisqwJFgAUSQGyX/kCSVUUTIdKMwJlyo0oXHlhskwrTJciZHEXsgaqS4s6PJiCAr1uzYU8kBBSgnWFqpoMJMUjGtDmUwkmfVmVypakWhEKvXsS4nhLW5wNjVroJIoc05wSzTr0PtiigpYe4EC2vj4iWrFu5euWIMRBhacaVJhYQBEFjA9jHjyQ0xEABwGceGAZYjY0YBOrRLCxUp29QM+bRkx5s7ZyYgVbTqwwti2ybJ+vLtDYpycyZbYOlptxdx0kV+V7lC5iJAyyRrwYKxAdiz82ng0/jnAdMJFz0cPi104Ec1Vj9/M6F173vKL/feXv156dw11tlqeMMnv4V5Ap53GmjQQH97nFfg+IFiucfgRX5Z8KAgbUlQ4IULIlghhhdOSB6AgX0IVn8eReghen3NRIBsRgnH4l4LuEidZBjwRpt6NM5WGwoW0KSjCwX6yJSMab2GwwAPDXfaBCtWpluRTQqC5JM5oUZAjUNS+VeOLWpJEQ7VYQANW0INJSZVDFSnZphjSikfmzE5N4EEbQI1QJmnWXCmHulRp2edwDXF43txukenJwvI9xyg9Q26Z3MzGUcBYFEChZh6DVTq34AU8Iflh51Sd+CnKFYQ6mmZkhqfBKfSxZWqA9DZanWjxmhrWwi0qtCrt/43K6WqVjjpmhIqgEGvculaGKklKstAACEAACH5BAUKABwALAcABADOAAsAAAX/ICdyQmaMYyAUqPgIBiHPxNpy79kqRXH8wAPsRmDdXpAWgWdEIYm2llCHqjVHU+jjJkwqBTecwItShMXkEfNWSh8e1NGAcLgpDGlRgk7EJ/6Ae3VKfoF/fDuFhohVeDeCfXkcCQqDVQcQhn+VNDOYmpSWaoqBlUSfmowjEA+iEAEGDRGztAwGCDcXEA60tXEiCrq8vREMEBLIyRLCxMWSHMzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/Cpk3ABwSLQkYAQwT/P309vcI7OvXr94jBQMJ/nskkGA/BQBRLNDncAIAiDcG6LsxAWOLiQzmeURBKWSLCQbv/1F0eDGinJUKR47YY1IEgQASKk7Yc7ACRwZm7mHweRJoz59BJUogisKCUaFMR0x4SlJBVBFTk8pZivTR0K73rN5wqlXEAq5Fy3IYgHbEzQ0nLy4QSoCjXLoom96VOJEeCosK5n4kkFfqXjl94wa+l1gvAcGICbewAOAxY8l/Ky/QhAGz4cUkGxu2HNozhwMGBnCUqUdBg9UuW9eUynqSwLHIBujePef1ZGQZXcM+OFuEBeBhi3OYgLyqcuaxbT9vLkf4SeqyWxSQpKGB2gQpm1KdWbu72rPRzR9Ne2Nu9Kzr/1Jqj0yD/fvqP4aXOt5sW/5qsXXVcv1Nsp8IBUAmgswGF3llGgeU1YVXXKTN1FlhWFXW3gIE+DVChApysACHHo7Q4A35lLichh+ROBmLKAzgYmYEYDAhCgxKGOOMn4WR4kkDaoBBOxJtdNKQxFmg5JIWIBnQc07GaORfUY4AEkdV6jHlCEISSZ5yTXpp1pbGZbkWmcuZmQCaE6iJ0FhjMaDjTMsgZaNEHFRAQVp3bqXnZED1qYcECOz5V6BhSWCoVJQIKuKQi2KFKEkEFAqoAo7uYSmO3jk61wUUMKmknJ4SGimBmAa0qVQBhAAAIfkEBQoAGwAsBwAEAM4ACwAABf/gJm5FmRlEqhJC+bywgK5pO4rHI0D3pii22+Mg6/0Ej96weCMAk7cDkXf7lZTTnrMl7eaYoy10JN0ZFdco0XAuvKI6qkgVFJXYNwjkIBcNBgR8TQoGfRsJCRuCYYQQiI+ICosiCoGOkIiKfSl8mJkHZ4U9kZMbKaI3pKGXmJKrngmug4WwkhA0lrCBWgYFCCMQFwoQDRHGxwwGCBLMzRLEx8iGzMMO0cYNeCMKzBDW19lnF9DXDIY/48Xg093f0Q3s1dcR8OLe8+Y91OTv5wrj7o7B+7VNQqABIoRVCMBggsOHE36kSoCBIcSH3EbFangxogJYFi8CkJhqQciLJEf/LDDJEeJIBT0GsOwYUYJGBS0fjpQAMidGmyVP6sx4Y6VQhzs9VUwkwqaCCh0tmKoFtSMDmBOf9phg4SrVrROuasRQAaxXpVUhdsU6IsECZlvX3kwLUWzRt0BHOLTbNlbZG3vZinArge5Dvn7wbqtQkSYAAgtKmnSsYKVKo2AfW048uaPmG386i4Q8EQMBAIAnfB7xBxBqvapJ9zX9WgRS2YMpnvYMGdPK3aMjt/3dUcNI4blpj7iwkMFWDXDvSmgAlijrt9RTR78+PS6z1uAJZIe93Q8g5zcsWCi/4Y+C8bah5zUv3vv89uft30QP23punGCx5954oBBwnwYaNCDY/wYrsYeggnM9B2Fpf8GG2CEUVWhbWAtGouEGDy7Y4IEJVrbSiXghqGKIo7z1IVcXIkKWWR361QOLWWnIhwERpLaaCCee5iMBGJQmJGyPFTnbkfHVZGRtIGrg5HALEJAZbu39BuUEUmq1JJQIPtZilY5hGeSWsSk52G9XqsmgljdIcABytq13HyIM6RcUA+r1qZ4EBF3WHWB29tBgAzRhEGhig8KmqKFv8SeCeo+mgsF7YFXa1qWSbkDpom/mqR1PmHCqJ3fwNRVXjC7S6CZhFVCQ2lWvZiirhQq42SACt25IK2hv8TprriUV1usGgeka7LFcNmCldMLi6qZMgFLgpw16Cipb7bC1knXsBiEAACH5BAUKABsALAcABADOAAsAAAX/4FZsJPkUmUGsLCEUTywXglFuSg7fW1xAvNWLF6sFFcPb42C8EZCj24EJdCp2yoegWsolS0Uu6fmamg8n8YYcLU2bXSiRaXMGvqV6/KAeJAh8VgZqCX+BexCFioWAYgqNi4qAR4ORhRuHY408jAeUhAmYYiuVlpiflqGZa5CWkzc5fKmbbhIpsAoQDRG8vQwQCBLCwxK6vb5qwhfGxxENahvCEA7NzskSy7vNzzzK09W/PNHF1NvX2dXcN8K55cfh69Luveol3vO8zwi4Yhj+AQwmCBw4IYclDAAJDlQggVOChAoLKkgFkSCAHDwWLKhIEOONARsDKryogFPIiAUb/95gJNIiw4wnI778GFPhzBKFOAq8qLJEhQpiNArjMcHCmlTCUDIouTKBhApELSxFWiGiVKY4E2CAekPgUphDu0742nRrVLJZnyrFSqKQ2ohoSYAMW6IoDpNJ4bLdILTnAj8KUF7UeENjAKuDyxIgOuGiOI0EBBMgLNew5AUrDTMGsFixwBIaNCQuAXJB57qNJ2OWm2Aj4skwCQCIyNkhhtMkdsIuodE0AN4LJDRgfLPtn5YDLdBlraAByuUbBgxQwICxMOnYpVOPej074OFdlfc0TqC62OIbcppHjV4o+LrieWhfT8JC/I/T6W8oCl29vQ0XjLdBaA3s1RcPBO7lFvpX8BVoG4O5jTXRQRDuJ6FDTzEWF1/BCZhgbyAKE9qICYLloQYOFtahVRsWYlZ4KQJHlwHS/IYaZ6sZd9tmu5HQm2xi1UaTbzxYwJk/wBF5g5EEYOBZeEfGZmNdFyFZmZIR4jikbLThlh5kUUVJGmRT7sekkziRWUIACABk3T4qCsedgO4xhgGcY7q5pHJ4klBBTQRJ0CeHcoYHHUh6wgfdn9uJdSdMiebGJ0zUPTcoS286FCkrZxnYoYYKWLkBowhQoBeaOlZAgVhLidrXqg2GiqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/oGFw2WZuT5oZROsSQnGaKjRvilI893MItlNOJ5v5gDcFrHhKIWcEYu/xFEqNv6B1N62aclysF7fsZYe5aOx2yL5aAUGSaT1oTYMBwQ5VGCAJgYIJCnx1gIOBhXdwiIl7d0p2iYGQUAQBjoOFSQR/lIQHnZ+Ue6OagqYzSqSJi5eTpTxGcjcSChANEbu8DBAIEsHBChe5vL13G7fFuscRDcnKuM3H0La3EA7Oz8kKEsXazr7Cw9/Gztar5uHHvte47MjktznZ2w0G1+D3BgirAqJmJMAQgMGEgwgn5Ei0gKDBhBMALGRYEOJBb5QcWlQo4cbAihZz3GgIMqFEBSM1/4ZEOWPAgpIIJXYU+PIhRG8ja1qU6VHlzZknJNQ6UanCjQkWCIGSUGEjAwVLjc44+DTqUQtPPS5gejUrTa5TJ3g9sWCr1BNUWZI161StiQUDmLYdGfesibQ3XMq1OPYthrwuA2yU2LBs2cBHIypYQPPlYAKFD5cVvNPtW8eVGbdcQADATsiNO4cFAPkvHpedPzc8kUcPgNGgZ5RNDZG05reoE9s2vSEP79MEGiQGy1qP8LA4ZcdtsJE48ONoLTBtTV0B9LsTnPceoIDBDQvS7W7vfjVY3q3eZ4A339J4eaAmKqU/sV58HvJh2RcnIBsDUw0ABqhBA5aV5V9XUFGiHfVeAiWwoFgJJrIXRH1tEMiDFV4oHoAEGlaWhgIGSGBO2nFomYY3mKjVglidaNYJGJDkWW2xxTfbjCbVaOGNqoX2GloR8ZeTaECS9pthRGJH2g0b3Agbk6hNANtteHD2GJUucfajCQBy5OOTQ25ZgUPvaVVQmbKh9510/qQpwXx3SQdfk8tZJOd5b6JJFplT3ZnmmX3qd5l1eg5q00HrtUkUn0AKaiGjClSAgKLYZcgWXwocGRcCFGCKwSB6ceqphwmYRUFYT/1WKlOdUpipmxW0mlCqHjYkAaeoZlqrqZ4qd+upQKaapn/AmgAegZ8KUtYtFAQQAgAh+QQFCgAbACwHAAQAzgALAAAF/+C2PUcmiCiZGUTrEkKBis8jQEquKwU5HyXIbEPgyX7BYa5wTNmEMwWsSXsqFbEh8DYs9mrgGjdK6GkPY5GOeU6ryz7UFopSQEzygOGhJBjoIgMDBAcBM0V/CYqLCQqFOwobiYyKjn2TlI6GKC2YjJZknouaZAcQlJUHl6eooJwKooobqoewrJSEmyKdt59NhRKFMxLEEA4RyMkMEAjDEhfGycqAG8TQx9IRDRDE3d3R2ctD1RLg0ttKEnbY5wZD3+zJ6M7X2RHi9Oby7u/r9g38UFjTh2xZJBEBMDAboogAgwkQI07IMUORwocSJwCgWDFBAIwZOaJIsOBjRogKJP8wTODw5ESVHVtm3AhzpEeQElOuNDlTZ0ycEUWKWFASqEahGwYUPbnxoAgEdlYSqDBkgoUNClAlIHbSAoOsqCRQnQHxq1axVb06FWFxLIqyaze0Tft1JVqyE+pWXMD1pF6bYl3+HTqAWNW8cRUFzmih0ZAAB2oGKukSAAGGRHWJgLiR6AylBLpuHKKUMlMCngMpDSAa9QIUggZVVvDaJobLeC3XZpvgNgCmtPcuwP3WgmXSq4do0DC6o2/guzcseECtUoO0hmcsGKDgOt7ssBd07wqesAIGZC1YIBa7PQHvb1+SFo+++HrJSQfB33xfav3i5eX3Hnb4CTJgegEq8tH/YQEOcIJzbm2G2EoYRLgBXFpVmFYDcREV4HIcnmUhiGBRouEMJGJGzHIspqgdXxK0yCKHRNXoIX4uorCdTyjkyNtdPWrA4Up82EbAbzMRxxZRR54WXVLDIRmRcag5d2R6ugl3ZXzNhTecchpMhIGVAKAYpgJjjsSklBEd99maZoo535ZvdamjBEpusJyctg3h4X8XqodBMx0tiNeg/oGJaKGABpogS40KSqiaEgBqlQWLUtqoVQnytekEjzo0hHqhRorppOZt2p923M2AAV+oBtpAnnPNoB6HaU6mAAIU+IXmi3j2mtFXuUoHKwXpzVrsjcgGOauKEjQrwq157hitGq2NoWmjh7z6Wmxb0m5w66+2VRAuXN/yFUAIACH5BAUKABsALAcABADOAAsAAAX/4CZuRiaM45MZqBgIRbs9AqTcuFLE7VHLOh7KB5ERdjJaEaU4ClO/lgKWjKKcMiJQ8KgumcieVdQMD8cbBeuAkkC6LYLhOxoQ2PF5Ys9PKPBMen17f0CCg4VSh32JV4t8jSNqEIOEgJKPlkYBlJWRInKdiJdkmQlvKAsLBxdABA4RsbIMBggtEhcQsLKxDBC2TAS6vLENdJLDxMZAubu8vjIbzcQRtMzJz79S08oQEt/guNiyy7fcvMbh4OezdAvGrakLAQwyABsELQkY9BP+//ckyPDD4J9BfAMh1GsBoImMeQUN+lMgUJ9CiRMa5msxoB9Gh/o8GmxYMZXIgxtR/yQ46S/gQAURR0pDwYDfywoyLPip5AdnCwsMFPBU4BPFhKBDi444quCmDKZOfwZ9KEGpCKgcN1jdALSpPqIYsabS+nSqvqplvYqQYAeDPgwKwjaMtiDl0oaqUAyo+3TuWwUAMPpVCfee0cEjVBGQq2ABx7oTWmQk4FglZMGN9fGVDMCuiH2AOVOu/PmyxM630gwM0CCn6q8LjVJ8GXvpa5Uwn95OTC/nNxkda1/dLSK475IjCD6dHbK1ZOa4hXP9DXs5chJ00UpVm5xo2qRpoxptwF2E4/IbJpB/SDz9+q9b1aNfQH08+p4a8uvX8B53fLP+ycAfemjsRUBgp1H20K+BghHgVgt1GXZXZpZ5lt4ECjxYR4ScUWiShEtZqBiIInRGWnERNnjiBglw+JyGnxUmGowsyiiZg189lNtPGACjV2+S9UjbU0JWF6SPvEk3QZEqsZYTk3UAaRSUnznJI5LmESCdBVSyaOWUWLK4I5gDUYVeV1T9l+FZClCAUVA09uSmRHBCKAECFEhW51ht6rnmWBXkaR+NjuHpJ40D3DmnQXt2F+ihZxlqVKOfQRACACH5BAUKABwALAcABADOAAsAAAX/ICdyUCkUo/g8mUG8MCGkKgspeC6j6XEIEBpBUeCNfECaglBcOVfJFK7YQwZHQ6JRZBUqTrSuVEuD3nI45pYjFuWKvjjSkCoRaBUMWxkwBGgJCXspQ36Bh4EEB0oKhoiBgyNLjo8Ki4QElIiWfJqHnISNEI+Ql5J9o6SgkqKkgqYihamPkW6oNBgSfiMMDQkGCBLCwxIQDhHIyQwQCGMKxsnKVyPCF9DREQ3MxMPX0cu4wt7J2uHWx9jlKd3o39MiuefYEcvNkuLt5O8c1ePI2tyELXGQwoGDAQf+iEC2xByDCRAjTlAgIUWCBRgCPJQ4AQBFXAs0coT40WLIjRxL/47AcHLkxIomRXL0CHPERZkpa4q4iVKiyp0tR/7kwHMkTUBBJR5dOCEBAVcKKtCAyOHpowXCpk7goABqBZdcvWploACpBKkpIJI1q5OD2rIWE0R1uTZu1LFwbWL9OlKuWb4c6+o9i3dEgw0RCGDUG9KlRw56gDY2qmCByZBaASi+TACA0TucAaTteCcy0ZuOK3N2vJlx58+LRQyY3Xm0ZsgjZg+oPQLi7dUcNXi0LOJw1pgNtB7XG6CBy+U75SYfPTSQAgZTNUDnQHt67wnbZyvwLgKiMN3oCZB3C76tdewpLFgIP2C88rbi4Y+QT3+8S5USMICZXWj1pkEDeUU3lOYGB3alSoEiMIjgX4WlgNF2EibIwQIXauWXSRg2SAOHIU5IIIMoZkhhWiJaiFVbKo6AQEgQXrTAazO1JhkBrBG3Y2Y6EsUhaGn95hprSN0oWpFE7rhkeaQBchGOEWnwEmc0uKWZj0LeuNV3W4Y2lZHFlQCSRjTIl8uZ+kG5HU/3sRlnTG2ytyadytnD3HrmuRcSn+0h1dycexIK1KCjYaCnjCCVqOFFJTZ5GkUUjESWaUIKU2lgCmAKKQIUjHapXRKE+t2og1VgankNYnohqKJ2CmKplso6GKz7WYCgqxeuyoF8u9IQAgA7', msg: null, msgText: 'Loading the next set of posts...', selector: null, speed: 'fast', start: undefined }, state: { isDuringAjax: false, isInvalidPage: false, isDestroyed: false, isDone: false, // For when it goes all the way through the archive. isPaused: false, isBeyondMaxPage: false, currPage: 1 }, debug: false, behavior: undefined, binder: $(window), // used to cache the selector nextSelector: 'div.navigation a:first', navSelector: 'div.navigation', contentSelector: null, // rename to pageFragment extraScrollPx: 150, itemSelector: 'div.post', animate: false, pathParse: undefined, dataType: 'html', appendCallback: true, bufferPx: 40, errorCallback: function () { }, infid: 0, //Instance ID pixelsFromNavToBottom: undefined, path: undefined, // Either parts of a URL as an array (e.g. ["/page/", "/"] or a function that takes in the page number and returns a URL prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work) }; $.infinitescroll.prototype = { /* ---------------------------- Private methods ---------------------------- */ // Bind or unbind from scroll _binding: function infscr_binding(binding) { var instance = this, opts = instance.options; opts.v = '2.0b2.120520'; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_binding_'+opts.behavior] !== undefined) { this['_binding_'+opts.behavior].call(this); return; } if (binding !== 'bind' && binding !== 'unbind') { this._debug('Binding value ' + binding + ' not valid'); return false; } if (binding === 'unbind') { (this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid); } else { (this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () { instance.scroll(); }); } this._debug('Binding', binding); }, // Fundamental aspects of the plugin are initialized _create: function infscr_create(options, callback) { // Add custom options to defaults var opts = $.extend(true, {}, $.infinitescroll.defaults, options); this.options = opts; var $window = $(window); var instance = this; // Validate selectors if (!instance._validate(options)) { return false; } // Validate page fragment path var path = $(opts.nextSelector).attr('href'); if (!path) { this._debug('Navigation selector not found'); return false; } // Set the path to be a relative URL from root. opts.path = opts.path || this._determinepath(path); // contentSelector is 'page fragment' option for .load() / .ajax() calls opts.contentSelector = opts.contentSelector || this.element; // loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector opts.loading.selector = opts.loading.selector || opts.contentSelector; // Define loading.msg opts.loading.msg = opts.loading.msg || $('
Loading...
' + opts.loading.msgText + '
'); // Preload loading.img (new Image()).src = opts.loading.img; // distance from nav links to bottom // computed as: height of the document + top offset of container - top offset of nav link if(opts.pixelsFromNavToBottom === undefined) { opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top; this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom); } var self = this; // determine loading.start actions opts.loading.start = opts.loading.start || function() { $(opts.navSelector).hide(); opts.loading.msg .appendTo(opts.loading.selector) .show(opts.loading.speed, $.proxy(function() { this.beginAjax(opts); }, self)); }; // determine loading.finished actions opts.loading.finished = opts.loading.finished || function() { if (!opts.state.isBeyondMaxPage) opts.loading.msg.fadeOut(opts.loading.speed); }; // callback loading opts.callback = function(instance, data, url) { if (!!opts.behavior && instance['_callback_'+opts.behavior] !== undefined) { instance['_callback_'+opts.behavior].call($(opts.contentSelector)[0], data, url); } if (callback) { callback.call($(opts.contentSelector)[0], data, opts, url); } if (opts.prefill) { $window.bind('resize.infinite-scroll', instance._prefill); } }; if (options.debug) { // Tell IE9 to use its built-in console if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') { ['log','info','warn','error','assert','dir','clear','profile','profileEnd'] .forEach(function (method) { console[method] = this.call(console[method], console); }, Function.prototype.bind); } } this._setup(); // Setups the prefill method for use if (opts.prefill) { this._prefill(); } // Return true to indicate successful creation return true; }, _prefill: function infscr_prefill() { var instance = this; var $window = $(window); function needsPrefill() { return ( $(instance.options.contentSelector).height() <= $window.height() ); } this._prefill = function() { if (needsPrefill()) { instance.scroll(); } $window.bind('resize.infinite-scroll', function() { if (needsPrefill()) { $window.unbind('resize.infinite-scroll'); instance.scroll(); } }); }; // Call self after setting up the new function this._prefill(); }, // Console log wrapper _debug: function infscr_debug() { if (true !== this.options.debug) { return; } if (typeof console !== 'undefined' && typeof console.log === 'function') { // Modern browsers // Single argument, which is a string if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') { console.log( (Array.prototype.slice.call(arguments)).toString() ); } else { console.log( Array.prototype.slice.call(arguments) ); } } else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') { // IE8 Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments)); } }, // find the number to increment in the path. _determinepath: function infscr_determinepath(path) { var opts = this.options; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_determinepath_'+opts.behavior] !== undefined) { return this['_determinepath_'+opts.behavior].call(this,path); } if (!!opts.pathParse) { this._debug('pathParse manual'); return opts.pathParse(path, this.options.state.currPage+1); } else if (path.match(/^(.*?)\b2\b(.*?$)/)) { path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1); // if there is any 2 in the url at all. } else if (path.match(/^(.*?)2(.*?$)/)) { // page= is used in django: // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127 if (path.match(/^(.*?page=)2(\/.*|$)/)) { path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1); return path; } path = path.match(/^(.*?)2(.*?$)/).slice(1); } else { // page= is used in drupal too but second page is page=1 not page=2: // thx Jerod Fritz, vladikoff if (path.match(/^(.*?page=)1(\/.*|$)/)) { path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1); return path; } else { this._debug("Sorry, we couldn't parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com."); // Get rid of isInvalidPage to allow permalink to state opts.state.isInvalidPage = true; //prevent it from running on this page. } } this._debug('determinePath', path); return path; }, // Custom error _error: function infscr_error(xhr) { var opts = this.options; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) { this['_error_'+opts.behavior].call(this,xhr); return; } if (xhr !== 'destroy' && xhr !== 'end') { xhr = 'unknown'; } this._debug('Error', xhr); if (xhr === 'end' || opts.state.isBeyondMaxPage) { this._showdonemsg(); } opts.state.isDone = true; opts.state.currPage = 1; // if you need to go back to this instance opts.state.isPaused = false; opts.state.isBeyondMaxPage = false; this._binding('unbind'); }, // Load Callback _loadcallback: function infscr_loadcallback(box, data, url) { var opts = this.options, callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append', frag; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) { this['_loadcallback_'+opts.behavior].call(this,box,data); return; } switch (result) { case 'done': this._showdonemsg(); return false; case 'no-append': if (opts.dataType === 'html') { data = '
' + data + '
'; data = $(data).find(opts.itemSelector); } // if it didn't return anything if (data.length === 0) { return this._error('end'); } break; case 'append': var children = box.children(); // if it didn't return anything if (children.length === 0) { return this._error('end'); } // use a documentFragment because it works when content is going into a table or UL frag = document.createDocumentFragment(); while (box[0].firstChild) { frag.appendChild(box[0].firstChild); } this._debug('contentSelector', $(opts.contentSelector)[0]); $(opts.contentSelector)[0].appendChild(frag); // previously, we would pass in the new DOM element as context for the callback // however we're now using a documentfragment, which doesn't have parents or children, // so the context is the contentContainer guy, and we pass in an array // of the elements collected as the first argument. data = children.get(); break; } // loadingEnd function opts.loading.finished.call($(opts.contentSelector)[0],opts); // smooth scroll to ease in the new content if (opts.animate) { var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px'; $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; }); } if (!opts.animate) { // once the call is done, we can allow it again. opts.state.isDuringAjax = false; } callback(this, data, url); if (opts.prefill) { this._prefill(); } }, _nearbottom: function infscr_nearbottom() { var opts = this.options, pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height(); // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) { return this['_nearbottom_'+opts.behavior].call(this); } this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom); // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom.... return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom); }, // Pause / temporarily disable plugin from firing _pausing: function infscr_pausing(pause) { var opts = this.options; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) { this['_pausing_'+opts.behavior].call(this,pause); return; } // If pause is not 'pause' or 'resume', toggle it's value if (pause !== 'pause' && pause !== 'resume' && pause !== null) { this._debug('Invalid argument. Toggling pause value instead'); } pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle'; switch (pause) { case 'pause': opts.state.isPaused = true; break; case 'resume': opts.state.isPaused = false; break; case 'toggle': opts.state.isPaused = !opts.state.isPaused; break; } this._debug('Paused', opts.state.isPaused); return false; }, // Behavior is determined // If the behavior option is undefined, it will set to default and bind to scroll _setup: function infscr_setup() { var opts = this.options; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) { this['_setup_'+opts.behavior].call(this); return; } this._binding('bind'); return false; }, // Show done message _showdonemsg: function infscr_showdonemsg() { var opts = this.options; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) { this['_showdonemsg_'+opts.behavior].call(this); return; } opts.loading.msg .find('img') .hide() .parent() .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () { $(this).parent().fadeOut(opts.loading.speed); }); // user provided callback when done opts.errorCallback.call($(opts.contentSelector)[0],'done'); }, // grab each selector option and see if any fail _validate: function infscr_validate(opts) { for (var key in opts) { if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) { this._debug('Your ' + key + ' found no elements.'); return false; } } return true; }, /* ---------------------------- Public methods ---------------------------- */ // Bind to scroll bind: function infscr_bind() { this._binding('bind'); }, // Destroy current instance of plugin destroy: function infscr_destroy() { this.options.state.isDestroyed = true; this.options.loading.finished(); return this._error('destroy'); }, // Set pause value to false pause: function infscr_pause() { this._pausing('pause'); }, // Set pause value to false resume: function infscr_resume() { this._pausing('resume'); }, beginAjax: function infscr_ajax(opts) { var instance = this, path = opts.path, box, desturl, method, condition; // increment the URL bit. e.g. /page/3/ opts.state.currPage++; // Manually control maximum page if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){ opts.state.isBeyondMaxPage = true; this.destroy(); return; } // if we're dealing with a table we can't use DIVs box = $(opts.contentSelector).is('table, tbody') ? $('') : $('
'); desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage); instance._debug('heading into ajax', desturl); method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback'; if (opts.appendCallback && opts.dataType === 'html') { method += '+callback'; } switch (method) { case 'html+callback': instance._debug('Using HTML via .load() method'); box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) { instance._loadcallback(box, responseText, desturl); }); break; case 'html': instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); $.ajax({ // params url: desturl, dataType: opts.dataType, complete: function infscr_ajax_callback(jqXHR, textStatus) { condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); if (condition) { instance._loadcallback(box, jqXHR.responseText, desturl); } else { instance._error('end'); } } }); break; case 'json': instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); $.ajax({ dataType: 'json', type: 'GET', url: desturl, success: function (data, textStatus, jqXHR) { condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); if (opts.appendCallback) { // if appendCallback is true, you must defined template in options. // note that data passed into _loadcallback is already an html (after processed in opts.template(data)). if (opts.template !== undefined) { var theData = opts.template(data); box.append(theData); if (condition) { instance._loadcallback(box, theData); } else { instance._error('end'); } } else { instance._debug('template must be defined.'); instance._error('end'); } } else { // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback. if (condition) { instance._loadcallback(box, data, desturl); } else { instance._error('end'); } } }, error: function() { instance._debug('JSON ajax request failed.'); instance._error('end'); } }); break; } }, // Retrieve next set of content items retrieve: function infscr_retrieve(pageNum) { pageNum = pageNum || null; var instance = this, opts = instance.options; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) { this['retrieve_'+opts.behavior].call(this,pageNum); return; } // for manual triggers, if destroyed, get out of here if (opts.state.isDestroyed) { this._debug('Instance is destroyed'); return false; } // we dont want to fire the ajax multiple times opts.state.isDuringAjax = true; opts.loading.start.call($(opts.contentSelector)[0],opts); }, // Check to see next page is needed scroll: function infscr_scroll() { var opts = this.options, state = opts.state; // if behavior is defined and this function is extended, call that instead of default if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) { this['scroll_'+opts.behavior].call(this); return; } if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) { return; } if (!this._nearbottom()) { return; } this.retrieve(); }, // Toggle pause value toggle: function infscr_toggle() { this._pausing(); }, // Unbind from scroll unbind: function infscr_unbind() { this._binding('unbind'); }, // update options update: function infscr_options(key) { if ($.isPlainObject(key)) { this.options = $.extend(true,this.options,key); } } }; /* ---------------------------- Infinite Scroll function ---------------------------- Borrowed logic from the following... jQuery UI - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js jCarousel - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js Masonry - https://github.com/desandro/masonry/blob/master/jquery.masonry.js */ $.fn.infinitescroll = function infscr_init(options, callback) { var thisCall = typeof options; switch (thisCall) { // method case 'string': var args = Array.prototype.slice.call(arguments, 1); this.each(function () { var instance = $.data(this, 'infinitescroll'); if (!instance) { // not setup yet // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup'); return false; } if (!$.isFunction(instance[options]) || options.charAt(0) === '_') { // return $.error('No such method ' + options + ' for Infinite Scroll'); return false; } // no errors! instance[options].apply(instance, args); }); break; // creation case 'object': this.each(function () { var instance = $.data(this, 'infinitescroll'); if (instance) { // update options of current instance instance.update(options); } else { // initialize new instance instance = new $.infinitescroll(options, callback, this); // don't attach if instantiation failed if (!instance.failed) { $.data(this, 'infinitescroll', instance); } } }); break; } return this; }; /* * smartscroll: debounced scroll event for jQuery * * https://github.com/lukeshumard/smartscroll * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js * * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. * */ var event = $.event, scrollTimeout; event.special.smartscroll = { setup: function () { $(this).bind('scroll', event.special.smartscroll.handler); }, teardown: function () { $(this).unbind('scroll', event.special.smartscroll.handler); }, handler: function (event, execAsap) { // Save the context var context = this, args = arguments; // set correct event type event.type = 'smartscroll'; if (scrollTimeout) { clearTimeout(scrollTimeout); } scrollTimeout = setTimeout(function () { $(context).trigger('smartscroll', args); }, execAsap === 'execAsap' ? 0 : 100); } }; $.fn.smartscroll = function (fn) { return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']); }; })); /*! Waypoints - 4.0.1 Copyright © 2011-2016 Caleb Troughton Licensed under the MIT license. https://github.com/imakewebthings/waypoints/blob/master/licenses.txt */ (function() { 'use strict' var keyCounter = 0 var allWaypoints = {} /* http://imakewebthings.com/waypoints/api/waypoint */ function Waypoint(options) { if (!options) { throw new Error('No options passed to Waypoint constructor') } if (!options.element) { throw new Error('No element option passed to Waypoint constructor') } if (!options.handler) { throw new Error('No handler option passed to Waypoint constructor') } this.key = 'waypoint-' + keyCounter this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) this.element = this.options.element this.adapter = new Waypoint.Adapter(this.element) this.callback = options.handler this.axis = this.options.horizontal ? 'horizontal' : 'vertical' this.enabled = this.options.enabled this.triggerPoint = null this.group = Waypoint.Group.findOrCreate({ name: this.options.group, axis: this.axis }) this.context = Waypoint.Context.findOrCreateByElement(this.options.context) if (Waypoint.offsetAliases[this.options.offset]) { this.options.offset = Waypoint.offsetAliases[this.options.offset] } this.group.add(this) this.context.add(this) allWaypoints[this.key] = this keyCounter += 1 } /* Private */ Waypoint.prototype.queueTrigger = function(direction) { this.group.queueTrigger(this, direction) } /* Private */ Waypoint.prototype.trigger = function(args) { if (!this.enabled) { return } if (this.callback) { this.callback.apply(this, args) } } /* Public */ /* http://imakewebthings.com/waypoints/api/destroy */ Waypoint.prototype.destroy = function() { this.context.remove(this) this.group.remove(this) delete allWaypoints[this.key] } /* Public */ /* http://imakewebthings.com/waypoints/api/disable */ Waypoint.prototype.disable = function() { this.enabled = false return this } /* Public */ /* http://imakewebthings.com/waypoints/api/enable */ Waypoint.prototype.enable = function() { this.context.refresh() this.enabled = true return this } /* Public */ /* http://imakewebthings.com/waypoints/api/next */ Waypoint.prototype.next = function() { return this.group.next(this) } /* Public */ /* http://imakewebthings.com/waypoints/api/previous */ Waypoint.prototype.previous = function() { return this.group.previous(this) } /* Private */ Waypoint.invokeAll = function(method) { var allWaypointsArray = [] for (var waypointKey in allWaypoints) { allWaypointsArray.push(allWaypoints[waypointKey]) } for (var i = 0, end = allWaypointsArray.length; i < end; i++) { allWaypointsArray[i][method]() } } /* Public */ /* http://imakewebthings.com/waypoints/api/destroy-all */ Waypoint.destroyAll = function() { Waypoint.invokeAll('destroy') } /* Public */ /* http://imakewebthings.com/waypoints/api/disable-all */ Waypoint.disableAll = function() { Waypoint.invokeAll('disable') } /* Public */ /* http://imakewebthings.com/waypoints/api/enable-all */ Waypoint.enableAll = function() { Waypoint.Context.refreshAll() for (var waypointKey in allWaypoints) { allWaypoints[waypointKey].enabled = true } return this } /* Public */ /* http://imakewebthings.com/waypoints/api/refresh-all */ Waypoint.refreshAll = function() { Waypoint.Context.refreshAll() } /* Public */ /* http://imakewebthings.com/waypoints/api/viewport-height */ Waypoint.viewportHeight = function() { return window.innerHeight || document.documentElement.clientHeight } /* Public */ /* http://imakewebthings.com/waypoints/api/viewport-width */ Waypoint.viewportWidth = function() { return document.documentElement.clientWidth } Waypoint.adapters = [] Waypoint.defaults = { context: window, continuous: true, enabled: true, group: 'default', horizontal: false, offset: 0 } Waypoint.offsetAliases = { 'bottom-in-view': function() { return this.context.innerHeight() - this.adapter.outerHeight() }, 'right-in-view': function() { return this.context.innerWidth() - this.adapter.outerWidth() } } window.Waypoint = Waypoint }()) ;(function() { 'use strict' function requestAnimationFrameShim(callback) { window.setTimeout(callback, 1000 / 60) } var keyCounter = 0 var contexts = {} var Waypoint = window.Waypoint var oldWindowLoad = window.onload /* http://imakewebthings.com/waypoints/api/context */ function Context(element) { this.element = element this.Adapter = Waypoint.Adapter this.adapter = new this.Adapter(element) this.key = 'waypoint-context-' + keyCounter this.didScroll = false this.didResize = false this.oldScroll = { x: this.adapter.scrollLeft(), y: this.adapter.scrollTop() } this.waypoints = { vertical: {}, horizontal: {} } element.waypointContextKey = this.key contexts[element.waypointContextKey] = this keyCounter += 1 if (!Waypoint.windowContext) { Waypoint.windowContext = true Waypoint.windowContext = new Context(window) } this.createThrottledScrollHandler() this.createThrottledResizeHandler() } /* Private */ Context.prototype.add = function(waypoint) { var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' this.waypoints[axis][waypoint.key] = waypoint this.refresh() } /* Private */ Context.prototype.checkEmpty = function() { var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) var isWindow = this.element == this.element.window if (horizontalEmpty && verticalEmpty && !isWindow) { this.adapter.off('.waypoints') delete contexts[this.key] } } /* Private */ Context.prototype.createThrottledResizeHandler = function() { var self = this function resizeHandler() { self.handleResize() self.didResize = false } this.adapter.on('resize.waypoints', function() { if (!self.didResize) { self.didResize = true Waypoint.requestAnimationFrame(resizeHandler) } }) } /* Private */ Context.prototype.createThrottledScrollHandler = function() { var self = this function scrollHandler() { self.handleScroll() self.didScroll = false } this.adapter.on('scroll.waypoints', function() { if (!self.didScroll || Waypoint.isTouch) { self.didScroll = true Waypoint.requestAnimationFrame(scrollHandler) } }) } /* Private */ Context.prototype.handleResize = function() { Waypoint.Context.refreshAll() } /* Private */ Context.prototype.handleScroll = function() { var triggeredGroups = {} var axes = { horizontal: { newScroll: this.adapter.scrollLeft(), oldScroll: this.oldScroll.x, forward: 'right', backward: 'left' }, vertical: { newScroll: this.adapter.scrollTop(), oldScroll: this.oldScroll.y, forward: 'down', backward: 'up' } } for (var axisKey in axes) { var axis = axes[axisKey] var isForward = axis.newScroll > axis.oldScroll var direction = isForward ? axis.forward : axis.backward for (var waypointKey in this.waypoints[axisKey]) { var waypoint = this.waypoints[axisKey][waypointKey] if (waypoint.triggerPoint === null) { continue } var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint if (crossedForward || crossedBackward) { waypoint.queueTrigger(direction) triggeredGroups[waypoint.group.id] = waypoint.group } } } for (var groupKey in triggeredGroups) { triggeredGroups[groupKey].flushTriggers() } this.oldScroll = { x: axes.horizontal.newScroll, y: axes.vertical.newScroll } } /* Private */ Context.prototype.innerHeight = function() { /*eslint-disable eqeqeq */ if (this.element == this.element.window) { return Waypoint.viewportHeight() } /*eslint-enable eqeqeq */ return this.adapter.innerHeight() } /* Private */ Context.prototype.remove = function(waypoint) { delete this.waypoints[waypoint.axis][waypoint.key] this.checkEmpty() } /* Private */ Context.prototype.innerWidth = function() { /*eslint-disable eqeqeq */ if (this.element == this.element.window) { return Waypoint.viewportWidth() } /*eslint-enable eqeqeq */ return this.adapter.innerWidth() } /* Public */ /* http://imakewebthings.com/waypoints/api/context-destroy */ Context.prototype.destroy = function() { var allWaypoints = [] for (var axis in this.waypoints) { for (var waypointKey in this.waypoints[axis]) { allWaypoints.push(this.waypoints[axis][waypointKey]) } } for (var i = 0, end = allWaypoints.length; i < end; i++) { allWaypoints[i].destroy() } } /* Public */ /* http://imakewebthings.com/waypoints/api/context-refresh */ Context.prototype.refresh = function() { /*eslint-disable eqeqeq */ var isWindow = this.element == this.element.window /*eslint-enable eqeqeq */ var contextOffset = isWindow ? undefined : this.adapter.offset() var triggeredGroups = {} var axes this.handleScroll() axes = { horizontal: { contextOffset: isWindow ? 0 : contextOffset.left, contextScroll: isWindow ? 0 : this.oldScroll.x, contextDimension: this.innerWidth(), oldScroll: this.oldScroll.x, forward: 'right', backward: 'left', offsetProp: 'left' }, vertical: { contextOffset: isWindow ? 0 : contextOffset.top, contextScroll: isWindow ? 0 : this.oldScroll.y, contextDimension: this.innerHeight(), oldScroll: this.oldScroll.y, forward: 'down', backward: 'up', offsetProp: 'top' } } for (var axisKey in axes) { var axis = axes[axisKey] for (var waypointKey in this.waypoints[axisKey]) { var waypoint = this.waypoints[axisKey][waypointKey] var adjustment = waypoint.options.offset var oldTriggerPoint = waypoint.triggerPoint var elementOffset = 0 var freshWaypoint = oldTriggerPoint == null var contextModifier, wasBeforeScroll, nowAfterScroll var triggeredBackward, triggeredForward if (waypoint.element !== waypoint.element.window) { elementOffset = waypoint.adapter.offset()[axis.offsetProp] } if (typeof adjustment === 'function') { adjustment = adjustment.apply(waypoint) } else if (typeof adjustment === 'string') { adjustment = parseFloat(adjustment) if (waypoint.options.offset.indexOf('%') > - 1) { adjustment = Math.ceil(axis.contextDimension * adjustment / 100) } } contextModifier = axis.contextScroll - axis.contextOffset waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment) wasBeforeScroll = oldTriggerPoint < axis.oldScroll nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll triggeredBackward = wasBeforeScroll && nowAfterScroll triggeredForward = !wasBeforeScroll && !nowAfterScroll if (!freshWaypoint && triggeredBackward) { waypoint.queueTrigger(axis.backward) triggeredGroups[waypoint.group.id] = waypoint.group } else if (!freshWaypoint && triggeredForward) { waypoint.queueTrigger(axis.forward) triggeredGroups[waypoint.group.id] = waypoint.group } else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { waypoint.queueTrigger(axis.forward) triggeredGroups[waypoint.group.id] = waypoint.group } } } Waypoint.requestAnimationFrame(function() { for (var groupKey in triggeredGroups) { triggeredGroups[groupKey].flushTriggers() } }) return this } /* Private */ Context.findOrCreateByElement = function(element) { return Context.findByElement(element) || new Context(element) } /* Private */ Context.refreshAll = function() { for (var contextId in contexts) { contexts[contextId].refresh() } } /* Public */ /* http://imakewebthings.com/waypoints/api/context-find-by-element */ Context.findByElement = function(element) { return contexts[element.waypointContextKey] } window.onload = function() { if (oldWindowLoad) { oldWindowLoad() } Context.refreshAll() } Waypoint.requestAnimationFrame = function(callback) { var requestFn = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || requestAnimationFrameShim requestFn.call(window, callback) } Waypoint.Context = Context }()) ;(function() { 'use strict' function byTriggerPoint(a, b) { return a.triggerPoint - b.triggerPoint } function byReverseTriggerPoint(a, b) { return b.triggerPoint - a.triggerPoint } var groups = { vertical: {}, horizontal: {} } var Waypoint = window.Waypoint /* http://imakewebthings.com/waypoints/api/group */ function Group(options) { this.name = options.name this.axis = options.axis this.id = this.name + '-' + this.axis this.waypoints = [] this.clearTriggerQueues() groups[this.axis][this.name] = this } /* Private */ Group.prototype.add = function(waypoint) { this.waypoints.push(waypoint) } /* Private */ Group.prototype.clearTriggerQueues = function() { this.triggerQueues = { up: [], down: [], left: [], right: [] } } /* Private */ Group.prototype.flushTriggers = function() { for (var direction in this.triggerQueues) { var waypoints = this.triggerQueues[direction] var reverse = direction === 'up' || direction === 'left' waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) for (var i = 0, end = waypoints.length; i < end; i += 1) { var waypoint = waypoints[i] if (waypoint.options.continuous || i === waypoints.length - 1) { waypoint.trigger([direction]) } } } this.clearTriggerQueues() } /* Private */ Group.prototype.next = function(waypoint) { this.waypoints.sort(byTriggerPoint) var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) var isLast = index === this.waypoints.length - 1 return isLast ? null : this.waypoints[index + 1] } /* Private */ Group.prototype.previous = function(waypoint) { this.waypoints.sort(byTriggerPoint) var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) return index ? this.waypoints[index - 1] : null } /* Private */ Group.prototype.queueTrigger = function(waypoint, direction) { this.triggerQueues[direction].push(waypoint) } /* Private */ Group.prototype.remove = function(waypoint) { var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) if (index > -1) { this.waypoints.splice(index, 1) } } /* Public */ /* http://imakewebthings.com/waypoints/api/first */ Group.prototype.first = function() { return this.waypoints[0] } /* Public */ /* http://imakewebthings.com/waypoints/api/last */ Group.prototype.last = function() { return this.waypoints[this.waypoints.length - 1] } /* Private */ Group.findOrCreate = function(options) { return groups[options.axis][options.name] || new Group(options) } Waypoint.Group = Group }()) ;(function() { 'use strict' var $ = window.jQuery var Waypoint = window.Waypoint function JQueryAdapter(element) { this.$element = $(element) } $.each([ 'innerHeight', 'innerWidth', 'off', 'offset', 'on', 'outerHeight', 'outerWidth', 'scrollLeft', 'scrollTop' ], function(i, method) { JQueryAdapter.prototype[method] = function() { var args = Array.prototype.slice.call(arguments) return this.$element[method].apply(this.$element, args) } }) $.each([ 'extend', 'inArray', 'isEmptyObject' ], function(i, method) { JQueryAdapter[method] = $[method] }) Waypoint.adapters.push({ name: 'jquery', Adapter: JQueryAdapter }) Waypoint.Adapter = JQueryAdapter }()) ;(function() { 'use strict' var Waypoint = window.Waypoint function createExtension(framework) { return function() { var waypoints = [] var overrides = arguments[0] if (framework.isFunction(arguments[0])) { overrides = framework.extend({}, arguments[1]) overrides.handler = arguments[0] } this.each(function() { var options = framework.extend({}, overrides, { element: this }) if (typeof options.context === 'string') { options.context = framework(this).closest(options.context)[0] } waypoints.push(new Waypoint(options)) }) return waypoints } } if (window.jQuery) { window.jQuery.fn.waypoint = createExtension(window.jQuery) } if (window.Zepto) { window.Zepto.fn.waypoint = createExtension(window.Zepto) } }()) ; /*! Waypoints Inview Shortcut - 4.0.1 Copyright © 2011-2016 Caleb Troughton Licensed under the MIT license. https://github.com/imakewebthings/waypoints/blob/master/licenses.txt */ (function() { 'use strict' function noop() {} var Waypoint = window.Waypoint /* http://imakewebthings.com/waypoints/shortcuts/inview */ function Inview(options) { this.options = Waypoint.Adapter.extend({}, Inview.defaults, options) this.axis = this.options.horizontal ? 'horizontal' : 'vertical' this.waypoints = [] this.element = this.options.element this.createWaypoints() } /* Private */ Inview.prototype.createWaypoints = function() { var configs = { vertical: [{ down: 'enter', up: 'exited', offset: '100%' }, { down: 'entered', up: 'exit', offset: 'bottom-in-view' }, { down: 'exit', up: 'entered', offset: 0 }, { down: 'exited', up: 'enter', offset: function() { return -this.adapter.outerHeight() } }], horizontal: [{ right: 'enter', left: 'exited', offset: '100%' }, { right: 'entered', left: 'exit', offset: 'right-in-view' }, { right: 'exit', left: 'entered', offset: 0 }, { right: 'exited', left: 'enter', offset: function() { return -this.adapter.outerWidth() } }] } for (var i = 0, end = configs[this.axis].length; i < end; i++) { var config = configs[this.axis][i] this.createWaypoint(config) } } /* Private */ Inview.prototype.createWaypoint = function(config) { var self = this this.waypoints.push(new Waypoint({ context: this.options.context, element: this.options.element, enabled: this.options.enabled, handler: (function(config) { return function(direction) { self.options[config[direction]].call(self, direction) } }(config)), offset: config.offset, horizontal: this.options.horizontal })) } /* Public */ Inview.prototype.destroy = function() { for (var i = 0, end = this.waypoints.length; i < end; i++) { this.waypoints[i].destroy() } this.waypoints = [] } Inview.prototype.disable = function() { for (var i = 0, end = this.waypoints.length; i < end; i++) { this.waypoints[i].disable() } } Inview.prototype.enable = function() { for (var i = 0, end = this.waypoints.length; i < end; i++) { this.waypoints[i].enable() } } Inview.defaults = { context: window, enabled: true, enter: noop, entered: noop, exit: noop, exited: noop } Waypoint.Inview = Inview }()) ; /* * SmartMenus jQuery v0.9.6 * http://www.smartmenus.org/ * * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd. * http://vadikom.com/ * * Released under the MIT license: * http://www.opensource.org/licenses/MIT */ (function($) { var menuTrees = [], IE = !!window.createPopup, // we need to detect it, unfortunately IElt9 = IE && !document.defaultView, IElt8 = IE && !document.querySelector, IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined', mouse = false, // optimize for touch by default - we will detect for mouse input mouseDetectionEnabled = false; // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.) function initMouseDetection(disable) { if (!mouseDetectionEnabled && !disable) { // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present // in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events) var firstTime = true, lastMove = null; $(document).bind({ 'mousemove.smartmenus_mouse': function(e) { var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() }; if (lastMove) { var deltaX = Math.abs(lastMove.x - thisMove.x), deltaY = Math.abs(lastMove.y - thisMove.y); if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) { mouse = true; // if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes if (firstTime) { var $a = $(e.target).closest('a'); if ($a.is('a')) { $.each(menuTrees, function() { if ($.contains(this.$root[0], $a[0])) { this.itemEnter({ currentTarget: $a[0] }); return false; } }); } firstTime = false; } } } lastMove = thisMove; }, 'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) { if (!/^(4|mouse|pen)$/.test(e.originalEvent.pointerType)) { mouse = false; } } }); mouseDetectionEnabled = true; } else if (mouseDetectionEnabled && disable) { $(document).unbind('.smartmenus_mouse'); mouseDetectionEnabled = false; } }; $.SmartMenus = function(elm, options) { this.$root = $(elm); this.opts = options; this.rootId = ''; // internal this.$subArrow = null; this.subMenus = []; // all sub menus in the tree (UL elms) in no particular order (only real - e.g. UL's in mega sub menus won't be counted) this.activatedItems = []; // stores last activated A's for each level this.visibleSubMenus = []; // stores visible sub menus UL's this.showTimeout = 0; this.hideTimeout = 0; this.scrollTimeout = 0; this.clickActivated = false; this.zIndexInc = 0; this.$firstLink = null; // we'll use these for some tests this.$firstSub = null; // at runtime so we'll cache them this.disabled = false; this.$disableOverlay = null; this.init(); }; $.extend($.SmartMenus, { hideAll: function() { $.each(menuTrees, function() { this.menuHideAll(); }); }, destroy: function() { while (menuTrees.length) { menuTrees[0].destroy(); } initMouseDetection(true); }, prototype: { init: function(refresh) { var self = this; if (!refresh) { menuTrees.push(this); this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, ''); if (this.$root.hasClass('sm-rtl')) { this.opts.rightToLeftSubMenus = true; } // init root (main menu) this.$root .data('smartmenus', this) .attr('data-smartmenus-id', this.rootId) .dataSM('level', 1) .bind({ 'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this), 'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this) }) .delegate('a, div.logo-container', { 'mouseenter.smartmenus': $.proxy(this.itemEnter, this), 'mouseleave.smartmenus': $.proxy(this.itemLeave, this), 'mousedown.smartmenus': $.proxy(this.itemDown, this), 'focus.smartmenus': $.proxy(this.itemFocus, this), 'blur.smartmenus': $.proxy(this.itemBlur, this), 'click.smartmenus': $.proxy(this.itemClick, this), 'touchend.smartmenus': $.proxy(this.itemTouchEnd, this) }); var eNamespace = '.smartmenus' + this.rootId; // hide menus on tap or click outside the root UL if (this.opts.hideOnClick) { $(document).on('touchstart' + eNamespace, $.proxy(this.docTouchStart, this)) .on('touchmove' + eNamespace, $.proxy(this.docTouchMove, this)) .on('touchend' + eNamespace, $.proxy(this.docTouchEnd, this)) // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too .on('click' + eNamespace, $.proxy(this.docClick, this)); } // hide sub menus on resize $(window).on('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); var $vmenu = $('body.vmenu .vmenu-container'); if ( ! $vmenu.length && UNCODE.wwidth > UNCODE.mediaQuery ) { $(window).on('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); } if (this.opts.subIndicators) { this.$subArrow = $('').addClass('sub-arrow'); if (this.opts.subIndicatorsText) { this.$subArrow.html(this.opts.subIndicatorsText); } } // make sure mouse detection is enabled initMouseDetection(); } // init sub menus this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0); this.$firstLink = this.$root.find('a').eq(0); // find current item if (this.opts.markCurrentItem) { var reDefaultDoc = /(index|default)\.[^#\?\/]*/i, reHash = /#.*/, locHref = window.location.href.replace(reDefaultDoc, ''), locHrefNoHash = locHref.replace(reHash, ''); this.$root.find('a').each(function() { var href = this.href.replace(reDefaultDoc, ''), $this = $(this); if (href == locHref || href == locHrefNoHash) { $this.addClass('current'); if (self.opts.markCurrentTree) { $this.parents('li').each(function() { var $this = $(this); if ($this.dataSM('sub')) { $this.children('a').addClass('current'); } }); } } }); } }, destroy: function() { this.menuHideAll(); this.$root .removeData('smartmenus') .removeAttr('data-smartmenus-id') .removeDataSM('level') .unbind('.smartmenus') .undelegate('.smartmenus'); var eNamespace = '.smartmenus' + this.rootId; $(document).unbind(eNamespace); $(window).unbind(eNamespace); if (this.opts.subIndicators) { this.$subArrow = null; } var self = this; $.each(this.subMenus, function() { if (this.hasClass('mega-menu')) { this.find('ul').removeDataSM('in-mega'); } if (this.dataSM('shown-before')) { if (IElt8) { this.children().css({ styleFloat: '', width: '' }); } if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) { if (!IE6) { this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap'); } else { this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', ''); } } if (this.dataSM('scroll-arrows')) { this.dataSM('scroll-arrows').remove(); } this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' }); } if (self.opts.subIndicators) { this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove(); } this.removeDataSM('shown-before') .removeDataSM('ie-shim') .removeDataSM('scroll-arrows') .removeDataSM('parent-a') .removeDataSM('level') .removeDataSM('beforefirstshowfired') .parent().removeDataSM('sub'); }); if (this.opts.markCurrentItem) { this.$root.find('a.current').removeClass('current'); } this.$root = null; this.$firstLink = null; this.$firstSub = null; if (this.$disableOverlay) { this.$disableOverlay.remove(); this.$disableOverlay = null; } menuTrees.splice($.inArray(this, menuTrees), 1); }, disable: function(noOverlay) { if (!this.disabled) { this.menuHideAll(); // display overlay over the menu to prevent interaction if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) { var pos = this.$root.offset(); this.$disableOverlay = $('
').css({ position: 'absolute', top: pos.top, left: pos.left, width: this.$root.outerWidth(), height: this.$root.outerHeight(), zIndex: this.getStartZIndex() + 1, opacity: 0 }).appendTo(document.body); } this.disabled = true; } }, docClick: function(e) { // hide on any click outside the menu or on a menu link if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) { this.menuHideAll($(e.target)); } }, docTouchEnd: function(e) { if (!this.lastTouch) { return; } if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) { if (this.hideTimeout) { clearTimeout(this.hideTimeout); this.hideTimeout = 0; } // hide with a delay to prevent triggering accidental unwanted click on some page element var self = this; this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350); } this.lastTouch = null; }, docTouchMove: function(e) { if (!this.lastTouch) { return; } var touchPoint = e.originalEvent.touches[0]; this.lastTouch.x2 = touchPoint.pageX; this.lastTouch.y2 = touchPoint.pageY; }, docTouchStart: function(e) { var touchPoint = e.originalEvent.touches[0]; this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target }; }, enable: function() { if (this.disabled) { if (this.$disableOverlay) { this.$disableOverlay.remove(); this.$disableOverlay = null; } this.disabled = false; } }, getHeight: function($elm) { return this.getOffset($elm, true); }, // returns precise width/height float values in IE9+, FF4+, recent WebKit // http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/ getOffset: function($elm, height) { var old, $win = $(window), winW = $win.width(); if ($elm.css('display') == 'none') { old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility }; $elm.css({ position: 'absolute', visibility: 'hidden' }).show(); if ( ($('body').hasClass('menu-mobile-off-canvas') && winW < 960 && $elm.closest('.main-menu-container').length) || ($('body').hasClass('vmenu-offcanvas-overlay') && winW >= 960 && $elm.closest('.main-menu-container').length && !$elm.closest('.menu-horizontal-inner').length) ) { $elm.closest('li').addClass('smartmenu-open-item'); } } var defaultView = $elm[0].ownerDocument.defaultView, compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null), val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']); if (val) { val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft']) + parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight']) + parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth']) + parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']); } else { val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth; } if (old) { $elm.hide().css(old); } return val; }, getWidth: function($elm) { return this.getOffset($elm); }, getStartZIndex: function() { var zIndex = parseInt(this.$root.css('z-index')); return !isNaN(zIndex) ? zIndex : 1; }, handleEvents: function() { return !this.disabled && this.isCSSOn(); }, handleItemEvents: function($a) { return this.handleEvents() && !this.isLinkInMegaMenu($a); }, isCollapsible: function() { return this.$firstSub.css('position') == 'static'; }, isCSSOn: function() { return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'flex' || this.$firstLink.css('display') == 'inline-flex' || this.$firstLink.css('display') == 'table-cell' || this.$firstLink.css('display') == 'inline'; }, isFixed: function() { return this.$root.css('position') == 'fixed'; }, isLinkInMegaMenu: function($a) { return !$a.parent().parent().dataSM('level'); }, isTouchMode: function() { return !mouse || this.isCollapsible(); }, itemActivate: function($a) { var $li = $a.parent(), $ul = $li.parent(), level = $ul.dataSM('level'); // if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) { var self = this; $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() { self.itemActivate($(this).dataSM('parent-a')); }); } // hide any visible deeper level sub menus if (this.visibleSubMenus.length > level) { for (var i = this.visibleSubMenus.length - 1, l = !this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level; i > l; i--) { //if ( !this.visibleSubMenus[i].closest('.menu-accordion').length ) { this.menuHide(this.visibleSubMenus[i]); //} } } // save new active item and sub menu for this level this.activatedItems[level - 1] = $a; this.visibleSubMenus[level - 1] = $ul; if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) { return; } // show the sub menu if this item has one var $sub = $li.dataSM('sub'); if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) { this.menuShow($sub); } }, itemBlur: function(e) { var $a = $(e.currentTarget); if (!this.handleItemEvents($a)) { return; } this.$root.triggerHandler('blur.smapi', $a[0]); }, itemClick: function(e) { var $a = $(e.currentTarget); if (!this.handleItemEvents($a)) { return; } $a.removeDataSM('mousedown'); if (this.$root.triggerHandler('click.smapi', $a[0]) === false) { return false; } var $sub = $a.parent().dataSM('sub'); if (this.isTouchMode()) { // undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu if ($a.dataSM('href')) { $a.attr('href', $a.dataSM('href')).removeDataSM('href'); } // if the sub is not visible if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { // try to activate the item and show the sub this.itemActivate($a); // if "itemActivate" showed the sub, prevent the click so that the link is not loaded // if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded if ($sub.is(':visible')) { return false; } } } else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) { this.clickActivated = true; this.menuShow($sub); return false; } if ($a.hasClass('disabled')) { return false; } if (this.$root.triggerHandler('select.smapi', $a[0]) === false) { return false; } }, itemDown: function(e) { var $a = $(e.currentTarget); if (!this.handleItemEvents($a)) { return; } $a.dataSM('mousedown', true); }, itemEnter: function(e) { var $a = $(e.currentTarget); if (!this.handleItemEvents($a)) { return; } if (!this.isTouchMode()) { if (this.showTimeout) { clearTimeout(this.showTimeout); this.showTimeout = 0; } var self = this; this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout); } this.$root.triggerHandler('mouseenter.smapi', $a[0]); }, itemFocus: function(e) { var $a = $(e.currentTarget); if (!this.handleItemEvents($a)) { return; } // fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) { this.itemActivate($a); } this.$root.triggerHandler('focus.smapi', $a[0]); }, itemLeave: function(e) { var $a = $(e.currentTarget); if (!this.handleItemEvents($a)) { return; } if (!this.isTouchMode()) { if ($a[0].blur) { $a[0].blur(); } if (this.showTimeout) { clearTimeout(this.showTimeout); this.showTimeout = 0; } } $a.removeDataSM('mousedown'); this.$root.triggerHandler('mouseleave.smapi', $a[0]); }, itemTouchEnd: function(e) { var $a = $(e.currentTarget); if (!this.handleItemEvents($a)) { return; } // prevent the address bar on iPhone from sliding down when expanding a sub menu var $sub = $a.parent().dataSM('sub'); if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { $a.dataSM('href', $a.attr('href')); $a.attr('href', '#'); } }, menuFixLayout: function($ul) { // fixes a menu that is being shown for the first time if (!$ul.dataSM('shown-before')) { $ul.hide().dataSM('shown-before', true); // fix the layout of the items in IE<8 if (IElt8) { $ul.children().css({ styleFloat: 'left', width: '100%' }); } } }, menuHide: function($sub) { if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) { return; } $sub.stop(true, true); if ($sub.is(':visible')) { var complete = function() { // unset z-index if (IElt9) { $sub.parent().css('z-index', ''); } else { $sub.css('z-index', ''); } }; // if sub is collapsible (mobile view) if (this.isCollapsible()) { if (this.opts.collapsibleHideFunction) { this.opts.collapsibleHideFunction.call(this, $sub, complete); } else { $sub.hide(this.opts.collapsibleHideDuration, complete); } } else { if (this.opts.hideFunction) { this.opts.hideFunction.call(this, $sub, complete); } else { $sub.hide(this.opts.hideDuration, complete); } } // remove IE iframe shim if ($sub.dataSM('ie-shim')) { $sub.dataSM('ie-shim').remove(); } // deactivate scrolling if it is activated for this sub if ($sub.dataSM('scroll')) { $sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide(); } // unhighlight parent item $sub.dataSM('parent-a').removeClass('highlighted'); var level = $sub.dataSM('level'); this.activatedItems.splice(level - 1, 1); this.visibleSubMenus.splice(level - 1, 1); this.$root.triggerHandler('hide.smapi', $sub[0]); } }, menuHideAll: function($item) { if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return; var $win = $(window), winW = $win.width(); if (this.showTimeout) { clearTimeout(this.showTimeout); this.showTimeout = 0; } // hide all subs for (var i = this.visibleSubMenus.length - 1; i > 0; i--) { if ( this.visibleSubMenus[i].closest('.smartmenu-open-item').length ) { if ( $item != undefined && $item.closest('.smartmenu-open-item').length ) { this.menuHide(this.visibleSubMenus[i]); $(this.visibleSubMenus[i]).closest('.smartmenu-open-item').removeClass('smartmenu-open-item'); } else { return; } } else { //if ( !this.visibleSubMenus[i].closest('.menu-accordion').length ) { this.menuHide(this.visibleSubMenus[i]); //} } } // hide root if it's popup if (this.opts.isPopup) { this.$root.stop(true, true); if (this.$root.is(':visible')) { if (this.opts.hideFunction) { this.opts.hideFunction.call(this, this.$root); } else { this.$root.hide(this.opts.hideDuration); } // remove IE iframe shim if (this.$root.dataSM('ie-shim')) { this.$root.dataSM('ie-shim').remove(); } } } this.activatedItems = []; this.visibleSubMenus = []; this.clickActivated = false; // reset z-index increment this.zIndexInc = 0; }, menuIframeShim: function($ul) { // create iframe shim for the menu if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) { $ul.dataSM('ie-shim', $('\n
"; }, getImgMarkup: function (index, src, altAttr, srcset, sizes, sources) { var srcsetAttr = srcset ? "srcset=\"" + srcset + "\"" : ''; var sizesAttr = sizes ? "sizes=\"" + sizes + "\"" : ''; var imgMarkup = ""; var sourceTag = ''; if (sources) { var sourceObj = typeof sources === 'string' ? JSON.parse(sources) : sources; sourceTag = sourceObj.map(function (source) { var attrs = ''; Object.keys(source).forEach(function (key) { // Do not remove the first space as it is required to separate the attributes attrs += " " + key + "=\"" + source[key] + "\""; }); return ""; }); } return "" + sourceTag + imgMarkup; }, // Get src from responsive src getResponsiveSrc: function (srcItms) { var rsWidth = []; var rsSrc = []; var src = ''; for (var i = 0; i < srcItms.length; i++) { var _src = srcItms[i].split(' '); // Manage empty space if (_src[0] === '') { _src.splice(0, 1); } rsSrc.push(_src[0]); rsWidth.push(_src[1]); } var wWidth = window.innerWidth; for (var j = 0; j < rsWidth.length; j++) { if (parseInt(rsWidth[j], 10) > wWidth) { src = rsSrc[j]; break; } } return src; }, isImageLoaded: function (img) { if (!img) return false; // During the onload event, IE correctly identifies any images that // weren’t downloaded as not complete. Others should too. Gecko-based // browsers act like NS4 in that they report this incorrectly. if (!img.complete) { return false; } // However, they do have two very useful properties: naturalWidth and // naturalHeight. These give the true size of the image. If it failed // to load, either of these should be zero. if (img.naturalWidth === 0) { return false; } // No other way of checking: assume it’s ok. return true; }, getVideoPosterMarkup: function (_poster, dummyImg, videoContStyle, playVideoString, _isVideo) { var videoClass = ''; if (_isVideo && _isVideo.youtube) { videoClass = 'lg-has-youtube'; } else if (_isVideo && _isVideo.vimeo) { videoClass = 'lg-has-vimeo'; } else { videoClass = 'lg-has-html5'; } return "
\n
\n \n " + playVideoString + "\n \n \n \n \n \n \n \n
\n " + (dummyImg || '') + "\n \n
"; }, getFocusableElements: function (container) { var elements = container.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'); var visibleElements = [].filter.call(elements, function (element) { var style = window.getComputedStyle(element); return style.display !== 'none' && style.visibility !== 'hidden'; }); return visibleElements; }, /** * @desc Create dynamic elements array from gallery items when dynamic option is false * It helps to avoid frequent DOM interaction * and avoid multiple checks for dynamic elments * * @returns {Array} dynamicEl */ getDynamicOptions: function (items, extraProps, getCaptionFromTitleOrAlt, exThumbImage) { var dynamicElements = []; var availableDynamicOptions = __spreadArrays(defaultDynamicOptions, extraProps); [].forEach.call(items, function (item) { var dynamicEl = {}; for (var i = 0; i < item.attributes.length; i++) { var attr = item.attributes[i]; if (attr.specified) { var dynamicAttr = convertToData(attr.name); var label = ''; if (availableDynamicOptions.indexOf(dynamicAttr) > -1) { label = dynamicAttr; } if (label) { dynamicEl[label] = attr.value; } } } var currentItem = $LG(item); var alt = currentItem.find('img').first().attr('alt'); var title = currentItem.attr('title'); //Uncode edit ##START## // var thumb = exThumbImage var thumb = exThumbImage && currentItem.attr(exThumbImage) //Uncode edit ##END## ? currentItem.attr(exThumbImage) : currentItem.find('img').first().attr('src'); dynamicEl.thumb = thumb; //Uncode edit ##START## if (getCaptionFromTitleOrAlt && !dynamicEl.subHtml) { // dynamicEl.subHtml = title || alt || ''; dynamicEl.subHtml = title || ''; } // dynamicEl.alt = alt || title || ''; dynamicEl.alt = title || ''; var inlineType = currentItem.attr('data-type'); dynamicEl.type = inlineType; //Uncode edit ##END## dynamicElements.push(dynamicEl); }); return dynamicElements; }, isMobile: function () { return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); }, /** * @desc Check the given src is video * @param {String} src * @return {Object} video type * Ex:{ youtube : ["//www.youtube.com/watch?v=c0asJgSyxcY", "c0asJgSyxcY"] } * * @todo - this information can be moved to dynamicEl to avoid frequent calls */ isVideo: function (src, isHTML5VIdeo, index) { if (!src || src.match(/\.(mp4|m4v|ogg|webm)$/) ) { if (isHTML5VIdeo) { return { html5: true, }; } else { console.warn('lightGallery :- data-src is not provided on slide item ' + (index + 1) + '. Please make sure the selector property is properly configured. More info - https://www.lightgalleryjs.com/demos/html-markup/'); return; } } var youtube = src.match(/\/\/(?:www\.)?youtu(?:\.be|be\.com|be-nocookie\.com)\/(?:watch\?v=|embed\/)?([a-z0-9\-\_\%]+)([\&|?][\S]*)*/i); var vimeo = src.match(/\/\/(?:www\.)?(?:player\.)?vimeo.com\/(?:video\/)?([0-9a-z\-_]+)(.*)?/i); var wistia = src.match(/https?:\/\/(.+)?(wistia\.com|wi\.st)\/(medias|embed)\/([0-9a-z\-_]+)(.*)/); if (youtube) { return { youtube: youtube, }; } else if (vimeo) { return { vimeo: vimeo, }; } else if (wistia) { return { wistia: wistia, }; } }, }; // @ref - https://stackoverflow.com/questions/3971841/how-to-resize-images-proportionally-keeping-the-aspect-ratio // @ref - https://2ality.com/2017/04/setting-up-multi-platform-packages.html // Unique id for each gallery var lgId = 0; var LightGallery = /** @class */ (function () { function LightGallery(element, options) { this.lgOpened = false; this.index = 0; // lightGallery modules this.plugins = []; // false when lightGallery load first slide content; this.lGalleryOn = false; // True when a slide animation is in progress this.lgBusy = false; this.currentItemsInDom = []; // Scroll top value before lightGallery is opened this.prevScrollTop = 0; this.bodyPaddingRight = 0; this.isDummyImageRemoved = false; this.dragOrSwipeEnabled = false; this.mediaContainerPosition = { top: 0, bottom: 0, }; if (!element) { return this; } lgId++; this.lgId = lgId; this.el = element; this.LGel = $LG(element); this.generateSettings(options); this.buildModules(); // When using dynamic mode, ensure dynamicEl is an array if (this.settings.dynamic && this.settings.dynamicEl !== undefined && !Array.isArray(this.settings.dynamicEl)) { throw 'When using dynamic mode, you must also define dynamicEl as an Array.'; } this.galleryItems = this.getItems(); this.normalizeSettings(); // Gallery items this.init(); //Uncode edit ##START## // this.validateLicense(); //Uncode edit ##END## return this; } LightGallery.prototype.generateSettings = function (options) { // lightGallery settings this.settings = __assign(__assign({}, lightGalleryCoreSettings), options); if (this.settings.isMobile && typeof this.settings.isMobile === 'function' ? this.settings.isMobile() : utils.isMobile()) { var mobileSettings = __assign(__assign({}, this.settings.mobileSettings), this.settings.mobileSettings); this.settings = __assign(__assign({}, this.settings), mobileSettings); } }; LightGallery.prototype.normalizeSettings = function () { if (this.settings.slideEndAnimation) { this.settings.hideControlOnEnd = false; } if (!this.settings.closable) { this.settings.swipeToClose = false; } // And reset it on close to get the correct value next time this.zoomFromOrigin = this.settings.zoomFromOrigin; // At the moment, Zoom from image doesn't support dynamic options // @todo add zoomFromOrigin support for dynamic images if (this.settings.dynamic) { this.zoomFromOrigin = false; } if (!this.settings.container) { this.settings.container = document.body; } // settings.preload should not be grater than $item.length this.settings.preload = Math.min(this.settings.preload, this.galleryItems.length); }; LightGallery.prototype.init = function () { var _this = this; this.addSlideVideoInfo(this.galleryItems); this.buildStructure(); this.LGel.trigger(lGEvents.init, { instance: this, }); if (this.settings.keyPress) { this.keyPress(); } setTimeout(function () { _this.enableDrag(); _this.enableSwipe(); _this.triggerPosterClick(); }, 50); this.arrow(); if (this.settings.mousewheel) { this.mousewheel(); } if (!this.settings.dynamic) { this.openGalleryOnItemClick(); } }; LightGallery.prototype.openGalleryOnItemClick = function () { var _this = this; var _loop_1 = function (index) { var element = this_1.items[index]; var $element = $LG(element); // Using different namespace for click because click event should not unbind if selector is same object('this') // @todo manage all event listners - should have namespace that represent element var uuid = lgQuery.generateUUID(); $element .attr('data-lg-id', uuid) .on("click.lgcustom-item-" + uuid, function (e) { e.preventDefault(); var currentItemIndex = _this.settings.index || index; _this.openGallery(currentItemIndex, element); }); }; var this_1 = this; // Using for loop instead of using bubbling as the items can be any html element. for (var index = 0; index < this.items.length; index++) { _loop_1(index); } }; /** * Module constructor * Modules are build incrementally. * Gallery should be opened only once all the modules are initialized. * use moduleBuildTimeout to make sure this */ LightGallery.prototype.buildModules = function () { var _this = this; this.settings.plugins.forEach(function (plugin) { _this.plugins.push(new plugin(_this, $LG)); }); }; LightGallery.prototype.validateLicense = function () { if (!this.settings.licenseKey) { console.warn('Please provide a valid license key'); } else if (this.settings.licenseKey === '0000-0000-000-0000') { console.warn("lightGallery: " + this.settings.licenseKey + " license key is not valid for production use"); } }; LightGallery.prototype.getSlideItem = function (index) { return $LG(this.getSlideItemId(index)); }; LightGallery.prototype.getSlideItemId = function (index) { return "#lg-item-" + this.lgId + "-" + index; }; LightGallery.prototype.getIdName = function (id) { return id + "-" + this.lgId; }; LightGallery.prototype.getElementById = function (id) { return $LG("#" + this.getIdName(id)); }; LightGallery.prototype.manageSingleSlideClassName = function () { if (this.galleryItems.length < 2) { this.outer.addClass('lg-single-item'); } else { this.outer.removeClass('lg-single-item'); } }; LightGallery.prototype.buildStructure = function () { var _this = this; var container = this.$container && this.$container.get(); if (container) { return; } var controls = ''; var subHtmlCont = ''; // Create controls if (this.settings.controls) { controls = "\n "; } if (this.settings.appendSubHtmlTo !== '.lg-item') { subHtmlCont = '
'; } var addClasses = ''; if (this.settings.allowMediaOverlap) { // Do not remove space before last single quote addClasses += 'lg-media-overlap '; } var ariaLabelledby = this.settings.ariaLabelledby ? 'aria-labelledby="' + this.settings.ariaLabelledby + '"' : ''; var ariaDescribedby = this.settings.ariaDescribedby ? 'aria-describedby="' + this.settings.ariaDescribedby + '"' : ''; var containerClassName = "lg-container " + this.settings.addClass + " " + (document.body !== this.settings.container ? 'lg-inline' : ''); var closeIcon = this.settings.closable && this.settings.showCloseIcon ? "" : ''; var maximizeIcon = this.settings.showMaximizeIcon ? "" : ''; var template = "\n
\n
\n\n
\n\n
\n
\n
\n " + controls + "\n
\n
\n " + maximizeIcon + "\n " + closeIcon + "\n
\n " + (this.settings.appendSubHtmlTo === '.lg-outer' ? subHtmlCont : '') + "\n
\n " + (this.settings.appendSubHtmlTo === '.lg-sub-html' ? subHtmlCont : '') + "\n
\n
\n
\n "; $LG(this.settings.container).append(template); if (document.body !== this.settings.container) { $LG(this.settings.container).css('position', 'relative'); } this.outer = this.getElementById('lg-outer'); this.$lgComponents = this.getElementById('lg-components'); this.$backdrop = this.getElementById('lg-backdrop'); this.$container = this.getElementById('lg-container'); this.$inner = this.getElementById('lg-inner'); this.$content = this.getElementById('lg-content'); this.$toolbar = this.getElementById('lg-toolbar'); this.$backdrop.css('transition-duration', this.settings.backdropDuration + 'ms'); var outerClassNames = this.settings.mode + " "; this.manageSingleSlideClassName(); if (this.settings.enableDrag) { outerClassNames += 'lg-grab '; } this.outer.addClass(outerClassNames); this.$inner.css('transition-timing-function', this.settings.easing); this.$inner.css('transition-duration', this.settings.speed + 'ms'); if (this.settings.download) { this.$toolbar.append(""); } this.counter(); $LG(window).on("resize.lg.global" + this.lgId + " orientationchange.lg.global" + this.lgId, function () { _this.refreshOnResize(); }); this.hideBars(); this.manageCloseGallery(); this.toggleMaximize(); this.initModules(); }; LightGallery.prototype.refreshOnResize = function () { if (this.lgOpened) { var currentGalleryItem = this.galleryItems[this.index]; var __slideVideoInfo = currentGalleryItem.__slideVideoInfo; this.mediaContainerPosition = this.getMediaContainerPosition(); var _a = this.mediaContainerPosition, top_1 = _a.top, bottom = _a.bottom; //Uncode edit ##START## this.currentImageSize = utils.getSize(this.items[this.index], this.outer, top_1 + bottom, __slideVideoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]); // this.currentImageSize = utils.getSize(this.items[this.index], this.outer, top_1 + bottom, __slideVideoInfo && this.settings.videoMaxSize); //Uncode edit ##END## if (__slideVideoInfo) { this.resizeVideoSlide(this.index, this.currentImageSize); } if (this.zoomFromOrigin && !this.isDummyImageRemoved) { var imgStyle = this.getDummyImgStyles(this.currentImageSize); this.outer .find('.lg-current .lg-dummy-img') .first() .attr('style', imgStyle); } this.LGel.trigger(lGEvents.containerResize); } }; LightGallery.prototype.resizeVideoSlide = function (index, imageSize) { var lgVideoStyle = this.getVideoContStyle(imageSize); var currentSlide = this.getSlideItem(index); currentSlide.find('.lg-video-cont').attr('style', lgVideoStyle); }; /** * Update slides dynamically. * Add, edit or delete slides dynamically when lightGallery is opened. * Modify the current gallery items and pass it via updateSlides method * @note * - Do not mutate existing lightGallery items directly. * - Always pass new list of gallery items * - You need to take care of thumbnails outside the gallery if any * - user this method only if you want to update slides when the gallery is opened. Otherwise, use `refresh()` method. * @param items Gallery items * @param index After the update operation, which slide gallery should navigate to * @category lGPublicMethods * @example * const plugin = lightGallery(); * * // Adding slides dynamically * let galleryItems = [ * // Access existing lightGallery items * // galleryItems are automatically generated internally from the gallery HTML markup * // or directly from galleryItems when dynamic gallery is used * ...plugin.galleryItems, * ...[ * { * src: 'img/img-1.png', * thumb: 'img/thumb1.png', * }, * ], * ]; * plugin.updateSlides( * galleryItems, * plugin.index, * ); * * * // Remove slides dynamically * galleryItems = JSON.parse( * JSON.stringify(updateSlideInstance.galleryItems), * ); * galleryItems.shift(); * updateSlideInstance.updateSlides(galleryItems, 1); * @see Demo */ LightGallery.prototype.updateSlides = function (items, index) { if (this.index > items.length - 1) { this.index = items.length - 1; } if (items.length === 1) { this.index = 0; } if (!items.length) { this.closeGallery(); return; } var currentSrc = this.galleryItems[index].src; this.galleryItems = items; this.updateControls(); this.$inner.empty(); this.currentItemsInDom = []; var _index = 0; // Find the current index based on source value of the slide this.galleryItems.some(function (galleryItem, itemIndex) { if (galleryItem.src === currentSrc) { _index = itemIndex; return true; } return false; }); this.currentItemsInDom = this.organizeSlideItems(_index, -1); this.loadContent(_index, true); this.getSlideItem(_index).addClass('lg-current'); this.index = _index; this.updateCurrentCounter(_index); this.LGel.trigger(lGEvents.updateSlides); }; // Get gallery items based on multiple conditions LightGallery.prototype.getItems = function () { // Gallery items this.items = []; if (!this.settings.dynamic) { if (this.settings.selector === 'this') { this.items.push(this.el); } else if (this.settings.selector) { if (typeof this.settings.selector === 'string') { if (this.settings.selectWithin) { var selectWithin = $LG(this.settings.selectWithin); this.items = selectWithin .find(this.settings.selector) .get(); } else { this.items = this.el.querySelectorAll(this.settings.selector); } } else { this.items = this.settings.selector; } } else { this.items = this.el.children; } return utils.getDynamicOptions(this.items, this.settings.extraProps, this.settings.getCaptionFromTitleOrAlt, this.settings.exThumbImage); } else { return this.settings.dynamicEl || []; } }; LightGallery.prototype.shouldHideScrollbar = function () { return (this.settings.hideScrollbar && document.body === this.settings.container); }; LightGallery.prototype.hideScrollbar = function () { if (!this.shouldHideScrollbar()) { return; } this.bodyPaddingRight = parseFloat($LG('body').style().paddingRight); var bodyRect = document.documentElement.getBoundingClientRect(); var scrollbarWidth = window.innerWidth - bodyRect.width; $LG(document.body).css('padding-right', scrollbarWidth + this.bodyPaddingRight + 'px'); $LG(document.body).addClass('lg-overlay-open'); }; LightGallery.prototype.resetScrollBar = function () { if (!this.shouldHideScrollbar()) { return; } $LG(document.body).css('padding-right', this.bodyPaddingRight + 'px'); $LG(document.body).removeClass('lg-overlay-open'); }; /** * Open lightGallery. * Open gallery with specific slide by passing index of the slide as parameter. * @category lGPublicMethods * @param {Number} index - index of the slide * @param {HTMLElement} element - Which image lightGallery should zoom from * * @example * const $dynamicGallery = document.getElementById('dynamic-gallery-demo'); * const dynamicGallery = lightGallery($dynamicGallery, { * dynamic: true, * dynamicEl: [ * { * src: 'img/1.jpg', * thumb: 'img/thumb-1.jpg', * subHtml: '

Image 1 title

Image 1 descriptions.

', * }, * ... * ], * }); * $dynamicGallery.addEventListener('click', function () { * // Starts with third item.(Optional). * // This is useful if you want use dynamic mode with * // custom thumbnails (thumbnails outside gallery), * dynamicGallery.openGallery(2); * }); * */ LightGallery.prototype.openGallery = function (index, element) { var _this = this; if (index === void 0) { index = this.settings.index; } // prevent accidental double execution if (this.lgOpened) return; this.lgOpened = true; this.outer.removeClass('lg-hide-items'); this.hideScrollbar(); // Add display block, but still has opacity 0 this.$container.addClass('lg-show'); var itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(index, index); this.currentItemsInDom = itemsToBeInsertedToDom; var items = ''; itemsToBeInsertedToDom.forEach(function (item) { items = items + ("
"); }); this.$inner.append(items); this.addHtml(index); var transform = ''; this.mediaContainerPosition = this.getMediaContainerPosition(); var _a = this.mediaContainerPosition, top = _a.top, bottom = _a.bottom; if (!this.settings.allowMediaOverlap) { this.setMediaContainerPosition(top, bottom); } var __slideVideoInfo = this.galleryItems[index].__slideVideoInfo; if (this.zoomFromOrigin && element) { //Uncode edit ##START## this.currentImageSize = utils.getSize(element, this.outer, top + bottom, __slideVideoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]); // this.currentImageSize = utils.getSize(element, this.outer, top + bottom, __slideVideoInfo && this.settings.videoMaxSize); //Uncode edit ##END## transform = utils.getTransform(element, this.outer, top, bottom, this.currentImageSize); } if (!this.zoomFromOrigin || !transform) { this.outer.addClass(this.settings.startClass); this.getSlideItem(index).removeClass('lg-complete'); } var timeout = this.settings.zoomFromOrigin ? 100 : this.settings.backdropDuration; setTimeout(function () { _this.outer.addClass('lg-components-open'); }, timeout); this.index = index; //Uncode edit ##START## // this.LGel.trigger(lGEvents.beforeOpen); this.LGel.trigger(lGEvents.beforeOpen, { galleryItems: this.galleryItems, items: this.items, outer: this.outer, }); //Uncode edit ##END## // add class lg-current to remove initial transition this.getSlideItem(index).addClass('lg-current'); this.lGalleryOn = false; // Store the current scroll top value to scroll back after closing the gallery.. this.prevScrollTop = $LG(window).scrollTop(); setTimeout(function () { // Need to check both zoomFromOrigin and transform values as we need to set set the // default opening animation if user missed to add the lg-size attribute if (_this.zoomFromOrigin && transform) { var currentSlide_1 = _this.getSlideItem(index); currentSlide_1.css('transform', transform); setTimeout(function () { currentSlide_1 .addClass('lg-start-progress lg-start-end-progress') .css('transition-duration', _this.settings.startAnimationDuration + 'ms'); _this.outer.addClass('lg-zoom-from-image'); }); setTimeout(function () { currentSlide_1.css('transform', 'translate3d(0, 0, 0)'); }, 100); } setTimeout(function () { _this.$backdrop.addClass('in'); _this.$container.addClass('lg-show-in'); }, 10); setTimeout(function () { if (_this.settings.trapFocus && document.body === _this.settings.container) { _this.trapFocus(); } }, _this.settings.backdropDuration + 50); // lg-visible class resets gallery opacity to 1 if (!_this.zoomFromOrigin || !transform) { setTimeout(function () { _this.outer.addClass('lg-visible'); }, _this.settings.backdropDuration); } // initiate slide function _this.slide(index, false, false, false); _this.LGel.trigger(lGEvents.afterOpen); }); if (document.body === this.settings.container) { $LG('html').addClass('lg-on'); } }; /** * Note - Changing the position of the media on every slide transition creates a flickering effect. * Therefore, The height of the caption is calculated dynamically, only once based on the first slide caption. * if you have dynamic captions for each media, * you can provide an appropriate height for the captions via allowMediaOverlap option */ LightGallery.prototype.getMediaContainerPosition = function () { if (this.settings.allowMediaOverlap) { return { top: 0, bottom: 0, }; } var top = this.$toolbar.get().clientHeight || 0; var subHtml = this.outer.find('.lg-components .lg-sub-html').get(); var captionHeight = this.settings.defaultCaptionHeight || (subHtml && subHtml.clientHeight) || 0; var thumbContainer = this.outer.find('.lg-thumb-outer').get(); var thumbHeight = thumbContainer ? thumbContainer.clientHeight : 0; var bottom = thumbHeight + captionHeight; //Uncode edit ##START## bottom = bottom < 55 ? 55 : bottom; //Uncode edit ##END## return { top: top, bottom: bottom, }; }; LightGallery.prototype.setMediaContainerPosition = function (top, bottom) { if (top === void 0) { top = 0; } if (bottom === void 0) { bottom = 0; } this.$content.css('top', top + 'px').css('bottom', bottom + 'px'); }; LightGallery.prototype.hideBars = function () { var _this = this; // Hide controllers if mouse doesn't move for some period setTimeout(function () { _this.outer.removeClass('lg-hide-items'); if (_this.settings.hideBarsDelay > 0) { _this.outer.on('mousemove.lg click.lg touchstart.lg', function () { _this.outer.removeClass('lg-hide-items'); clearTimeout(_this.hideBarTimeout); // Timeout will be cleared on each slide movement also _this.hideBarTimeout = setTimeout(function () { _this.outer.addClass('lg-hide-items'); }, _this.settings.hideBarsDelay); }); _this.outer.trigger('mousemove.lg'); } }, this.settings.showBarsAfter); }; LightGallery.prototype.initPictureFill = function ($img) { if (this.settings.supportLegacyBrowser) { try { picturefill({ elements: [$img.get()], }); } catch (e) { console.warn('lightGallery :- If you want srcset or picture tag to be supported for older browser please include picturefil javascript library in your document.'); } } }; /** * @desc Create image counter * Ex: 1/10 */ LightGallery.prototype.counter = function () { if (this.settings.counter) { var counterHtml = "
\n " + (this.index + 1) + " /\n " + this.galleryItems.length + "
"; this.outer.find(this.settings.appendCounterTo).append(counterHtml); } }; /** * @desc add sub-html into the slide * @param {Number} index - index of the slide */ LightGallery.prototype.addHtml = function (index) { var subHtml; var subHtmlUrl; if (this.galleryItems[index].subHtmlUrl) { subHtmlUrl = this.galleryItems[index].subHtmlUrl; } else { subHtml = this.galleryItems[index].subHtml; } if (!subHtmlUrl) { if (subHtml) { // get first letter of sub-html // if first letter starts with . or # get the html form the jQuery object var fL = subHtml.substring(0, 1); if (fL === '.' || fL === '#') { if (this.settings.subHtmlSelectorRelative && !this.settings.dynamic) { subHtml = $LG(this.items) .eq(index) .find(subHtml) .first() .html(); } else { subHtml = $LG(subHtml).first().html(); } } } else { subHtml = ''; } } if (this.settings.appendSubHtmlTo !== '.lg-item') { if (subHtmlUrl) { this.outer.find('.lg-sub-html').load(subHtmlUrl); } else { this.outer.find('.lg-sub-html').html(subHtml); } } else { var currentSlide = $LG(this.getSlideItemId(index)); if (subHtmlUrl) { currentSlide.load(subHtmlUrl); } else { currentSlide.append("
" + subHtml + "
"); } } // Add lg-empty-html class if title doesn't exist if (typeof subHtml !== 'undefined' && subHtml !== null) { if (subHtml === '') { this.outer .find(this.settings.appendSubHtmlTo) .addClass('lg-empty-html'); } else { this.outer .find(this.settings.appendSubHtmlTo) .removeClass('lg-empty-html'); } } this.LGel.trigger(lGEvents.afterAppendSubHtml, { index: index, }); }; /** * @desc Preload slides * @param {Number} index - index of the slide * @todo preload not working for the first slide, Also, should work for the first and last slide as well */ LightGallery.prototype.preload = function (index) { for (var i = 1; i <= this.settings.preload; i++) { if (i >= this.galleryItems.length - index) { break; } this.loadContent(index + i, false); } for (var j = 1; j <= this.settings.preload; j++) { if (index - j < 0) { break; } this.loadContent(index - j, false); } }; LightGallery.prototype.getDummyImgStyles = function (imageSize) { if (!imageSize) return ''; return "width:" + imageSize.width + "px;\n margin-left: -" + imageSize.width / 2 + "px;\n margin-top: -" + imageSize.height / 2 + "px;\n height:" + imageSize.height + "px"; }; LightGallery.prototype.getVideoContStyle = function (imageSize) { if (!imageSize) return ''; return "width:" + imageSize.width + "px;\n height:" + imageSize.height + "px"; }; LightGallery.prototype.getDummyImageContent = function ($currentSlide, index, alt) { var $currentItem; if (!this.settings.dynamic) { $currentItem = $LG(this.items).eq(index); } if ($currentItem) { var _dummyImgSrc = void 0; if (!this.settings.exThumbImage) { _dummyImgSrc = $currentItem.find('img').first().attr('src'); } else { _dummyImgSrc = $currentItem.attr(this.settings.exThumbImage); } if (!_dummyImgSrc) return ''; var imgStyle = this.getDummyImgStyles(this.currentImageSize); var dummyImgContent = ""; $currentSlide.addClass('lg-first-slide'); this.outer.addClass('lg-first-slide-loading'); return dummyImgContent; } return ''; }; LightGallery.prototype.setImgMarkup = function (src, $currentSlide, index) { var currentGalleryItem = this.galleryItems[index]; var alt = currentGalleryItem.alt, srcset = currentGalleryItem.srcset, sizes = currentGalleryItem.sizes, sources = currentGalleryItem.sources; // Use the thumbnail as dummy image which will be resized to actual image size and // displayed on top of actual image var imgContent = ''; var altAttr = alt ? 'alt="' + alt + '"' : ''; if (this.isFirstSlideWithZoomAnimation()) { imgContent = this.getDummyImageContent($currentSlide, index, altAttr); } else { imgContent = utils.getImgMarkup(index, src, altAttr, srcset, sizes, sources); } var imgMarkup = " " + imgContent + ""; $currentSlide.prepend(imgMarkup); }; LightGallery.prototype.onSlideObjectLoad = function ($slide, isHTML5VideoWithoutPoster, onLoad, onError) { var mediaObject = $slide.find('.lg-object').first(); if (utils.isImageLoaded(mediaObject.get()) || isHTML5VideoWithoutPoster) { onLoad(); } else { mediaObject.on('load.lg error.lg', function () { onLoad && onLoad(); }); mediaObject.on('error.lg', function () { onError && onError(); }); } }; /** * * @param $el Current slide item * @param index * @param delay Delay is 0 except first time * @param speed Speed is same as delay, except it is 0 if gallery is opened via hash plugin * @param isFirstSlide */ LightGallery.prototype.onLgObjectLoad = function (currentSlide, index, delay, speed, isFirstSlide, isHTML5VideoWithoutPoster) { var _this = this; //Uncode edit ##START## var $item = _this.galleryItems[index], type = $item.type; if ( typeof $item.src !== 'undefined' ) { var inline_id = $item.src.replace('#', ''), $inline = document.getElementById(inline_id), inline_html; if ( type === 'inline' && inline_id != null && typeof $inline !== 'undefined' ) { inline_html = $inline.innerHTML; } else { inline_html = ''; } } //Uncode edit ##END## this.onSlideObjectLoad(currentSlide, true, function () { _this.triggerSlideItemLoad(currentSlide, index, delay, speed, isFirstSlide); }, function () { currentSlide.addClass('lg-complete lg-complete_'); //Uncode edit ##START## // currentSlide.html('Oops... Failed to load content...'); if ( inline_html !== '' ) { currentSlide.html(inline_html); } else { currentSlide.html('Oops... Failed to load content...'); } //Uncode edit ##END## }); }; LightGallery.prototype.triggerSlideItemLoad = function ($currentSlide, index, delay, speed, isFirstSlide) { var _this = this; var currentGalleryItem = this.galleryItems[index]; // Adding delay for video slides without poster for better performance and user experience // Videos should start playing once once the gallery is completely loaded var _speed = isFirstSlide && this.getSlideType(currentGalleryItem) === 'video' && !currentGalleryItem.poster ? speed : 0; setTimeout(function () { $currentSlide.addClass('lg-complete lg-complete_'); _this.LGel.trigger(lGEvents.slideItemLoad, { index: index, delay: delay || 0, isFirstSlide: isFirstSlide, }); }, _speed); }; LightGallery.prototype.isFirstSlideWithZoomAnimation = function () { return !!(!this.lGalleryOn && this.zoomFromOrigin && this.currentImageSize); }; // Add video slideInfo LightGallery.prototype.addSlideVideoInfo = function (items) { var _this = this; items.forEach(function (element, index) { element.__slideVideoInfo = utils.isVideo(element.src, !!element.video, index); if (element.__slideVideoInfo && _this.settings.loadYouTubePoster && !element.poster && element.__slideVideoInfo.youtube) { element.poster = "//img.youtube.com/vi/" + element.__slideVideoInfo.youtube[1] + "/maxresdefault.jpg"; } }); }; /** * Load slide content into slide. * This is used to load content into slides that is not visible too * @param {Number} index - index of the slide. * @param {Boolean} rec - if true call loadcontent() function again. */ LightGallery.prototype.loadContent = function (index, rec) { var _this = this; var currentGalleryItem = this.galleryItems[index]; var $currentSlide = $LG(this.getSlideItemId(index)); var poster = currentGalleryItem.poster, srcset = currentGalleryItem.srcset, sizes = currentGalleryItem.sizes, sources = currentGalleryItem.sources; var src = currentGalleryItem.src; var video = currentGalleryItem.video; var _html5Video = video && typeof video === 'string' ? JSON.parse(video) : video; if (currentGalleryItem.responsive) { var srcDyItms = currentGalleryItem.responsive.split(','); src = utils.getResponsiveSrc(srcDyItms) || src; } var videoInfo = currentGalleryItem.__slideVideoInfo; var lgVideoStyle = ''; var iframe = !!currentGalleryItem.iframe; var isFirstSlide = !this.lGalleryOn; // delay for adding complete class. it is 0 except first time. var delay = 0; if (isFirstSlide) { if (this.zoomFromOrigin && this.currentImageSize) { delay = this.settings.startAnimationDuration + 10; } else { delay = this.settings.backdropDuration + 10; } } if (!$currentSlide.hasClass('lg-loaded')) { if (videoInfo) { var _a = this.mediaContainerPosition, top_2 = _a.top, bottom = _a.bottom; //Uncode edit ##START## var videoSize = utils.getSize(this.items[index], this.outer, top_2 + bottom, videoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]); // var videoSize = utils.getSize(this.items[index], this.outer, top_2 + bottom, videoInfo && this.settings.videoMaxSize); //Uncode edit ##END## lgVideoStyle = this.getVideoContStyle(videoSize); } if (iframe) { var markup = utils.getIframeMarkup(this.settings.iframeWidth, this.settings.iframeHeight, this.settings.iframeMaxWidth, this.settings.iframeMaxHeight, src, currentGalleryItem.iframeTitle); $currentSlide.prepend(markup); } else if (poster) { var dummyImg = ''; var hasStartAnimation = isFirstSlide && this.zoomFromOrigin && this.currentImageSize; if (hasStartAnimation) { dummyImg = this.getDummyImageContent($currentSlide, index, ''); } var markup = utils.getVideoPosterMarkup(poster, dummyImg || '', lgVideoStyle, this.settings.strings['playVideo'], videoInfo); $currentSlide.prepend(markup); } //Uncode edit ##START## // else if (videoInfo) { else if (videoInfo || this.getSlideType(currentGalleryItem) === 'audio') { if (! _html5Video) { var markup = "
"; } //Uncode edit ##END## $currentSlide.prepend(markup); } else { //Uncode edit ##START## var $item = _this.galleryItems[index], type = $item.type; if ( typeof $item.src !== 'undefined' ) { var inline_id = $item.src.replace('#', ''), $inline = document.getElementById(inline_id), inline_html; if ( type === 'inline' && inline_id != null && typeof $inline !== 'undefined' ) { inline_html = $inline.innerHTML; } else { inline_html = ''; } } if ( inline_html !== '' ) { $currentSlide.html(inline_html); } else { this.setImgMarkup(src, $currentSlide, index); if (srcset || sources) { var $img = $currentSlide.find('.lg-object'); this.initPictureFill($img); } } /*this.setImgMarkup(src, $currentSlide, index); if (srcset || sources) { var $img = $currentSlide.find('.lg-object'); this.initPictureFill($img); }*/ //Uncode edit ##END## } if (poster || videoInfo) { this.LGel.trigger(lGEvents.hasVideo, { index: index, src: src, html5Video: _html5Video, hasPoster: !!poster, }); } this.LGel.trigger(lGEvents.afterAppendSlide, { index: index }); if (this.lGalleryOn && this.settings.appendSubHtmlTo === '.lg-item') { this.addHtml(index); } } // For first time add some delay for displaying the start animation. var _speed = 0; // Do not change the delay value because it is required for zoom plugin. // If gallery opened from direct url (hash) speed value should be 0 if (delay && !$LG(document.body).hasClass('lg-from-hash')) { _speed = delay; } // Only for first slide and zoomFromOrigin is enabled if (this.isFirstSlideWithZoomAnimation()) { setTimeout(function () { $currentSlide .removeClass('lg-start-end-progress lg-start-progress') .removeAttr('style'); }, this.settings.startAnimationDuration + 100); if (!$currentSlide.hasClass('lg-loaded')) { setTimeout(function () { if (_this.getSlideType(currentGalleryItem) === 'image') { var alt = currentGalleryItem.alt; var altAttr = alt ? 'alt="' + alt + '"' : ''; $currentSlide .find('.lg-img-wrap') .append(utils.getImgMarkup(index, src, altAttr, srcset, sizes, currentGalleryItem.sources)); if (srcset || sources) { var $img = $currentSlide.find('.lg-object'); _this.initPictureFill($img); } } if (_this.getSlideType(currentGalleryItem) === 'image' || (_this.getSlideType(currentGalleryItem) === 'video' && poster)) { _this.onLgObjectLoad($currentSlide, index, delay, _speed, true, false); // load remaining slides once the slide is completely loaded _this.onSlideObjectLoad($currentSlide, !!(videoInfo && videoInfo.html5 && !poster), function () { _this.loadContentOnFirstSlideLoad(index, $currentSlide, _speed); }, function () { _this.loadContentOnFirstSlideLoad(index, $currentSlide, _speed); }); } }, this.settings.startAnimationDuration + 100); } } // SLide content has been added to dom $currentSlide.addClass('lg-loaded'); if (!this.isFirstSlideWithZoomAnimation() || (this.getSlideType(currentGalleryItem) === 'video' && !poster)) { //Uncode edit ##START## // this.onLgObjectLoad($currentSlide, index, delay, _speed, isFirstSlide, !!(videoInfo && videoInfo.html5 && !poster)); this.onLgObjectLoad($currentSlide, index, delay, _speed, isFirstSlide, !!( (videoInfo && videoInfo.html5 && !poster) || this.getSlideType(currentGalleryItem) === 'audio')); //Uncode edit ##END## } // When gallery is opened once content is loaded (second time) need to add lg-complete class for css styling if ((!this.zoomFromOrigin || !this.currentImageSize) && $currentSlide.hasClass('lg-complete_') && !this.lGalleryOn) { setTimeout(function () { $currentSlide.addClass('lg-complete'); }, this.settings.backdropDuration); } // Content loaded // Need to set lGalleryOn before calling preload function this.lGalleryOn = true; if (rec === true) { if (!$currentSlide.hasClass('lg-complete_')) { $currentSlide .find('.lg-object') .first() .on('load.lg error.lg', function () { _this.preload(index); }); } else { this.preload(index); } } }; /** * @desc Remove dummy image content and load next slides * Called only for the first time if zoomFromOrigin animation is enabled * @param index * @param $currentSlide * @param speed */ LightGallery.prototype.loadContentOnFirstSlideLoad = function (index, $currentSlide, speed) { var _this = this; setTimeout(function () { $currentSlide.find('.lg-dummy-img').remove(); $currentSlide.removeClass('lg-first-slide'); _this.outer.removeClass('lg-first-slide-loading'); _this.isDummyImageRemoved = true; _this.preload(index); }, speed + 300); }; LightGallery.prototype.getItemsToBeInsertedToDom = function (index, prevIndex, numberOfItems) { var _this = this; if (numberOfItems === void 0) { numberOfItems = 0; } var itemsToBeInsertedToDom = []; // Minimum 2 items should be there var possibleNumberOfItems = Math.max(numberOfItems, 3); possibleNumberOfItems = Math.min(possibleNumberOfItems, this.galleryItems.length); var prevIndexItem = "lg-item-" + this.lgId + "-" + prevIndex; if (this.galleryItems.length <= 3) { this.galleryItems.forEach(function (_element, index) { itemsToBeInsertedToDom.push("lg-item-" + _this.lgId + "-" + index); }); return itemsToBeInsertedToDom; } if (index < (this.galleryItems.length - 1) / 2) { for (var idx = index; idx > index - possibleNumberOfItems / 2 && idx >= 0; idx--) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + idx); } var numberOfExistingItems = itemsToBeInsertedToDom.length; for (var idx = 0; idx < possibleNumberOfItems - numberOfExistingItems; idx++) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (index + idx + 1)); } } else { for (var idx = index; idx <= this.galleryItems.length - 1 && idx < index + possibleNumberOfItems / 2; idx++) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + idx); } var numberOfExistingItems = itemsToBeInsertedToDom.length; for (var idx = 0; idx < possibleNumberOfItems - numberOfExistingItems; idx++) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (index - idx - 1)); } } if (this.settings.loop) { if (index === this.galleryItems.length - 1) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + 0); } else if (index === 0) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (this.galleryItems.length - 1)); } } if (itemsToBeInsertedToDom.indexOf(prevIndexItem) === -1) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + prevIndex); } return itemsToBeInsertedToDom; }; LightGallery.prototype.organizeSlideItems = function (index, prevIndex) { var _this = this; var itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(index, prevIndex, this.settings.numberOfSlideItemsInDom); itemsToBeInsertedToDom.forEach(function (item) { if (_this.currentItemsInDom.indexOf(item) === -1) { _this.$inner.append("
"); } }); this.currentItemsInDom.forEach(function (item) { if (itemsToBeInsertedToDom.indexOf(item) === -1) { $LG("#" + item).remove(); } }); return itemsToBeInsertedToDom; }; /** * Get previous index of the slide */ LightGallery.prototype.getPreviousSlideIndex = function () { var prevIndex = 0; try { var currentItemId = this.outer .find('.lg-current') .first() .attr('id'); prevIndex = parseInt(currentItemId.split('-')[3]) || 0; } catch (error) { prevIndex = 0; } return prevIndex; }; LightGallery.prototype.setDownloadValue = function (index) { if (this.settings.download) { var currentGalleryItem = this.galleryItems[index]; var hideDownloadBtn = currentGalleryItem.downloadUrl === false || currentGalleryItem.downloadUrl === 'false'; if (hideDownloadBtn) { this.outer.addClass('lg-hide-download'); } else { var $download = this.getElementById('lg-download'); this.outer.removeClass('lg-hide-download'); $download.attr('href', currentGalleryItem.downloadUrl || currentGalleryItem.src); if (currentGalleryItem.download) { //Uncode edit ##START## if ( typeof currentGalleryItem.video !== 'undefined' && currentGalleryItem.video ) { var currentVideo = JSON.parse( currentGalleryItem.video ), download_name = currentVideo.source[0].src; $download.attr('href', download_name).removeAttr('download'); } else { var download_url = currentGalleryItem.downloadUrl || currentGalleryItem.src, download_name = download_url.substring(download_url.lastIndexOf('/')+1); $download.attr('download', download_name); } // $download.attr('download', currentGalleryItem.download); //Uncode edit ##END## } } } }; LightGallery.prototype.makeSlideAnimation = function (direction, currentSlideItem, previousSlideItem) { var _this = this; if (this.lGalleryOn) { previousSlideItem.addClass('lg-slide-progress'); } setTimeout(function () { // remove all transitions _this.outer.addClass('lg-no-trans'); _this.outer .find('.lg-item') .removeClass('lg-prev-slide lg-next-slide'); if (direction === 'prev') { //prevslide currentSlideItem.addClass('lg-prev-slide'); previousSlideItem.addClass('lg-next-slide'); } else { // next slide currentSlideItem.addClass('lg-next-slide'); previousSlideItem.addClass('lg-prev-slide'); } // give 50 ms for browser to add/remove class setTimeout(function () { _this.outer.find('.lg-item').removeClass('lg-current'); currentSlideItem.addClass('lg-current'); // reset all transitions _this.outer.removeClass('lg-no-trans'); }, 50); }, this.lGalleryOn ? this.settings.slideDelay : 0); }; /** * Goto a specific slide. * @param {Number} index - index of the slide * @param {Boolean} fromTouch - true if slide function called via touch event or mouse drag * @param {Boolean} fromThumb - true if slide function called via thumbnail click * @param {String} direction - Direction of the slide(next/prev) * @category lGPublicMethods * @example * const plugin = lightGallery(); * // to go to 3rd slide * plugin.slide(2); * */ LightGallery.prototype.slide = function (index, fromTouch, fromThumb, direction) { var _this = this; var prevIndex = this.getPreviousSlideIndex(); this.currentItemsInDom = this.organizeSlideItems(index, prevIndex); // Prevent multiple call, Required for hsh plugin if (this.lGalleryOn && prevIndex === index) { return; } var numberOfGalleryItems = this.galleryItems.length; if (!this.lgBusy) { if (this.settings.counter) { this.updateCurrentCounter(index); } var currentSlideItem = this.getSlideItem(index); var previousSlideItem_1 = this.getSlideItem(prevIndex); var currentGalleryItem = this.galleryItems[index]; var videoInfo = currentGalleryItem.__slideVideoInfo; this.outer.attr('data-lg-slide-type', this.getSlideType(currentGalleryItem)); this.setDownloadValue(index); if (videoInfo) { var _a = this.mediaContainerPosition, top_3 = _a.top, bottom = _a.bottom; //Uncode edit ##START## var videoSize = utils.getSize(this.items[index], this.outer, top_3 + bottom, videoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]); // var videoSize = utils.getSize(this.items[index], this.outer, top_3 + bottom, videoInfo && this.settings.videoMaxSize); //Uncode edit ##END## this.resizeVideoSlide(index, videoSize); } this.LGel.trigger(lGEvents.beforeSlide, { prevIndex: prevIndex, index: index, fromTouch: !!fromTouch, fromThumb: !!fromThumb, //Uncode edit ##START## currentSlide: currentSlideItem, previousSlide: previousSlideItem_1, info: currentGalleryItem, item: this.items[index] //Uncode edit ##END## }); this.lgBusy = true; clearTimeout(this.hideBarTimeout); this.arrowDisable(index); if (!direction) { if (index < prevIndex) { direction = 'prev'; } else if (index > prevIndex) { direction = 'next'; } } if (!fromTouch) { this.makeSlideAnimation(direction, currentSlideItem, previousSlideItem_1); } else { this.outer .find('.lg-item') .removeClass('lg-prev-slide lg-current lg-next-slide'); var touchPrev = void 0; var touchNext = void 0; if (numberOfGalleryItems > 2) { touchPrev = index - 1; touchNext = index + 1; if (index === 0 && prevIndex === numberOfGalleryItems - 1) { // next slide touchNext = 0; touchPrev = numberOfGalleryItems - 1; } else if (index === numberOfGalleryItems - 1 && prevIndex === 0) { // prev slide touchNext = 0; touchPrev = numberOfGalleryItems - 1; } } else { touchPrev = 0; touchNext = 1; } if (direction === 'prev') { this.getSlideItem(touchNext).addClass('lg-next-slide'); } else { this.getSlideItem(touchPrev).addClass('lg-prev-slide'); } currentSlideItem.addClass('lg-current'); } // Do not put load content in set timeout as it needs to load immediately when the gallery is opened if (!this.lGalleryOn) { this.loadContent(index, true); } else { setTimeout(function () { _this.loadContent(index, true); // Add title if this.settings.appendSubHtmlTo === lg-sub-html if (_this.settings.appendSubHtmlTo !== '.lg-item') { _this.addHtml(index); } }, this.settings.speed + 50 + (fromTouch ? 0 : this.settings.slideDelay)); } setTimeout(function () { _this.lgBusy = false; previousSlideItem_1.removeClass('lg-slide-progress'); _this.LGel.trigger(lGEvents.afterSlide, { prevIndex: prevIndex, index: index, fromTouch: fromTouch, fromThumb: fromThumb, }); }, (this.lGalleryOn ? this.settings.speed + 100 : 100) + (fromTouch ? 0 : this.settings.slideDelay)); } this.index = index; }; LightGallery.prototype.updateCurrentCounter = function (index) { this.getElementById('lg-counter-current').html(index + 1 + ''); }; LightGallery.prototype.updateCounterTotal = function () { this.getElementById('lg-counter-all').html(this.galleryItems.length + ''); }; LightGallery.prototype.getSlideType = function (item) { if (item.__slideVideoInfo) { return 'video'; } else if (item.iframe) { return 'iframe'; } //Uncode edit ##START## else if (typeof item.src !== '' && item.src.search(/.mp3|.m4a/i) > -1) { return 'audio'; } //Uncode edit ##END## else { return 'image'; } }; LightGallery.prototype.touchMove = function (startCoords, endCoords, e) { var distanceX = endCoords.pageX - startCoords.pageX; var distanceY = endCoords.pageY - startCoords.pageY; var allowSwipe = false; if (this.swipeDirection) { allowSwipe = true; } else { if (Math.abs(distanceX) > 15) { this.swipeDirection = 'horizontal'; allowSwipe = true; } else if (Math.abs(distanceY) > 15) { this.swipeDirection = 'vertical'; allowSwipe = true; } } if (!allowSwipe) { return; } var $currentSlide = this.getSlideItem(this.index); if (this.swipeDirection === 'horizontal') { e === null || e === void 0 ? void 0 : e.preventDefault(); // reset opacity and transition duration this.outer.addClass('lg-dragging'); // move current slide this.setTranslate($currentSlide, distanceX, 0); // move next and prev slide with current slide var width = $currentSlide.get().offsetWidth; var slideWidthAmount = (width * 15) / 100; var gutter = slideWidthAmount - Math.abs((distanceX * 10) / 100); this.setTranslate(this.outer.find('.lg-prev-slide').first(), -width + distanceX - gutter, 0); this.setTranslate(this.outer.find('.lg-next-slide').first(), width + distanceX + gutter, 0); } else if (this.swipeDirection === 'vertical') { if (this.settings.swipeToClose) { e === null || e === void 0 ? void 0 : e.preventDefault(); this.$container.addClass('lg-dragging-vertical'); var opacity = 1 - Math.abs(distanceY) / window.innerHeight; this.$backdrop.css('opacity', opacity); var scale = 1 - Math.abs(distanceY) / (window.innerWidth * 2); this.setTranslate($currentSlide, 0, distanceY, scale, scale); if (Math.abs(distanceY) > 100) { this.outer .addClass('lg-hide-items') .removeClass('lg-components-open'); } } } }; LightGallery.prototype.touchEnd = function (endCoords, startCoords, event) { var _this = this; var distance; // keep slide animation for any mode while dragg/swipe if (this.settings.mode !== 'lg-slide') { this.outer.addClass('lg-slide'); } // set transition duration setTimeout(function () { _this.$container.removeClass('lg-dragging-vertical'); _this.outer .removeClass('lg-dragging lg-hide-items') .addClass('lg-components-open'); var triggerClick = true; if (_this.swipeDirection === 'horizontal') { distance = endCoords.pageX - startCoords.pageX; var distanceAbs = Math.abs(endCoords.pageX - startCoords.pageX); if (distance < 0 && distanceAbs > _this.settings.swipeThreshold) { _this.goToNextSlide(true); triggerClick = false; } else if (distance > 0 && distanceAbs > _this.settings.swipeThreshold) { _this.goToPrevSlide(true); triggerClick = false; } } else if (_this.swipeDirection === 'vertical') { distance = Math.abs(endCoords.pageY - startCoords.pageY); if (_this.settings.closable && _this.settings.swipeToClose && distance > 100) { _this.closeGallery(); return; } else { _this.$backdrop.css('opacity', 1); } } _this.outer.find('.lg-item').removeAttr('style'); if (triggerClick && Math.abs(endCoords.pageX - startCoords.pageX) < 5) { // Trigger click if distance is less than 5 pix var target = $LG(event.target); if (_this.isPosterElement(target)) { _this.LGel.trigger(lGEvents.posterClick); } } _this.swipeDirection = undefined; }); // remove slide class once drag/swipe is completed if mode is not slide setTimeout(function () { if (!_this.outer.hasClass('lg-dragging') && _this.settings.mode !== 'lg-slide') { _this.outer.removeClass('lg-slide'); } }, this.settings.speed + 100); }; LightGallery.prototype.enableSwipe = function () { var _this = this; var startCoords = {}; var endCoords = {}; var isMoved = false; var isSwiping = false; if (this.settings.enableSwipe) { this.$inner.on('touchstart.lg', function (e) { _this.dragOrSwipeEnabled = true; var $item = _this.getSlideItem(_this.index); if (($LG(e.target).hasClass('lg-item') || $item.get().contains(e.target)) && !_this.outer.hasClass('lg-zoomed') && !_this.lgBusy && e.targetTouches.length === 1) { isSwiping = true; _this.touchAction = 'swipe'; _this.manageSwipeClass(); startCoords = { pageX: e.targetTouches[0].pageX, pageY: e.targetTouches[0].pageY, }; } }); this.$inner.on('touchmove.lg', function (e) { if (isSwiping && _this.touchAction === 'swipe' && e.targetTouches.length === 1) { endCoords = { pageX: e.targetTouches[0].pageX, pageY: e.targetTouches[0].pageY, }; _this.touchMove(startCoords, endCoords, e); isMoved = true; } }); this.$inner.on('touchend.lg', function (event) { if (_this.touchAction === 'swipe') { if (isMoved) { isMoved = false; _this.touchEnd(endCoords, startCoords, event); } else if (isSwiping) { var target = $LG(event.target); if (_this.isPosterElement(target)) { _this.LGel.trigger(lGEvents.posterClick); } } _this.touchAction = undefined; isSwiping = false; } }); } }; LightGallery.prototype.enableDrag = function () { var _this = this; var startCoords = {}; var endCoords = {}; var isDraging = false; var isMoved = false; if (this.settings.enableDrag) { this.outer.on('mousedown.lg', function (e) { _this.dragOrSwipeEnabled = true; var $item = _this.getSlideItem(_this.index); if ($LG(e.target).hasClass('lg-item') || $item.get().contains(e.target)) { if (!_this.outer.hasClass('lg-zoomed') && !_this.lgBusy) { e.preventDefault(); if (!_this.lgBusy) { _this.manageSwipeClass(); startCoords = { pageX: e.pageX, pageY: e.pageY, }; isDraging = true; // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723 _this.outer.get().scrollLeft += 1; _this.outer.get().scrollLeft -= 1; // * _this.outer .removeClass('lg-grab') .addClass('lg-grabbing'); _this.LGel.trigger(lGEvents.dragStart); } } } }); $LG(window).on("mousemove.lg.global" + this.lgId, function (e) { if (isDraging && _this.lgOpened) { isMoved = true; endCoords = { pageX: e.pageX, pageY: e.pageY, }; _this.touchMove(startCoords, endCoords); _this.LGel.trigger(lGEvents.dragMove); } }); $LG(window).on("mouseup.lg.global" + this.lgId, function (event) { if (!_this.lgOpened) { return; } var target = $LG(event.target); if (isMoved) { isMoved = false; _this.touchEnd(endCoords, startCoords, event); _this.LGel.trigger(lGEvents.dragEnd); } else if (_this.isPosterElement(target)) { _this.LGel.trigger(lGEvents.posterClick); } // Prevent execution on click if (isDraging) { isDraging = false; _this.outer.removeClass('lg-grabbing').addClass('lg-grab'); } }); } }; LightGallery.prototype.triggerPosterClick = function () { var _this = this; this.$inner.on('click.lg', function (event) { if (!_this.dragOrSwipeEnabled && _this.isPosterElement($LG(event.target))) { _this.LGel.trigger(lGEvents.posterClick); } }); }; LightGallery.prototype.manageSwipeClass = function () { var _touchNext = this.index + 1; var _touchPrev = this.index - 1; if (this.settings.loop && this.galleryItems.length > 2) { if (this.index === 0) { _touchPrev = this.galleryItems.length - 1; } else if (this.index === this.galleryItems.length - 1) { _touchNext = 0; } } this.outer.find('.lg-item').removeClass('lg-next-slide lg-prev-slide'); if (_touchPrev > -1) { this.getSlideItem(_touchPrev).addClass('lg-prev-slide'); } this.getSlideItem(_touchNext).addClass('lg-next-slide'); }; /** * Go to next slide * @param {Boolean} fromTouch - true if slide function called via touch event * @category lGPublicMethods * @example * const plugin = lightGallery(); * plugin.goToNextSlide(); * @see Demo */ LightGallery.prototype.goToNextSlide = function (fromTouch) { var _this = this; var _loop = this.settings.loop; if (fromTouch && this.galleryItems.length < 3) { _loop = false; } if (!this.lgBusy) { if (this.index + 1 < this.galleryItems.length) { this.index++; this.LGel.trigger(lGEvents.beforeNextSlide, { index: this.index, }); this.slide(this.index, !!fromTouch, false, 'next'); } else { if (_loop) { this.index = 0; this.LGel.trigger(lGEvents.beforeNextSlide, { index: this.index, }); this.slide(this.index, !!fromTouch, false, 'next'); } else if (this.settings.slideEndAnimation && !fromTouch) { this.outer.addClass('lg-right-end'); setTimeout(function () { _this.outer.removeClass('lg-right-end'); }, 400); } } } }; /** * Go to previous slides * @param {Boolean} fromTouch - true if slide function called via touch event * @category lGPublicMethods * @example * const plugin = lightGallery({}); * plugin.goToPrevSlide(); * @see Demo * */ LightGallery.prototype.goToPrevSlide = function (fromTouch) { var _this = this; var _loop = this.settings.loop; if (fromTouch && this.galleryItems.length < 3) { _loop = false; } if (!this.lgBusy) { if (this.index > 0) { this.index--; this.LGel.trigger(lGEvents.beforePrevSlide, { index: this.index, fromTouch: fromTouch, }); this.slide(this.index, !!fromTouch, false, 'prev'); } else { if (_loop) { this.index = this.galleryItems.length - 1; this.LGel.trigger(lGEvents.beforePrevSlide, { index: this.index, fromTouch: fromTouch, }); this.slide(this.index, !!fromTouch, false, 'prev'); } else if (this.settings.slideEndAnimation && !fromTouch) { this.outer.addClass('lg-left-end'); setTimeout(function () { _this.outer.removeClass('lg-left-end'); }, 400); } } } }; LightGallery.prototype.keyPress = function () { var _this = this; $LG(window).on("keydown.lg.global" + this.lgId, function (e) { if (_this.lgOpened && _this.settings.escKey === true && e.keyCode === 27) { e.preventDefault(); if (_this.settings.allowMediaOverlap && _this.outer.hasClass('lg-can-toggle') && _this.outer.hasClass('lg-components-open')) { _this.outer.removeClass('lg-components-open'); } else { _this.closeGallery(); } } if (_this.lgOpened && _this.galleryItems.length > 1) { if (e.keyCode === 37) { e.preventDefault(); _this.goToPrevSlide(); } if (e.keyCode === 39) { e.preventDefault(); _this.goToNextSlide(); } } }); }; LightGallery.prototype.arrow = function () { var _this = this; this.getElementById('lg-prev').on('click.lg', function () { _this.goToPrevSlide(); }); this.getElementById('lg-next').on('click.lg', function () { _this.goToNextSlide(); }); }; LightGallery.prototype.arrowDisable = function (index) { // Disable arrows if settings.hideControlOnEnd is true if (!this.settings.loop && this.settings.hideControlOnEnd) { var $prev = this.getElementById('lg-prev'); var $next = this.getElementById('lg-next'); if (index + 1 === this.galleryItems.length) { $next.attr('disabled', 'disabled').addClass('disabled'); } else { $next.removeAttr('disabled').removeClass('disabled'); } if (index === 0) { $prev.attr('disabled', 'disabled').addClass('disabled'); } else { $prev.removeAttr('disabled').removeClass('disabled'); } } }; LightGallery.prototype.setTranslate = function ($el, xValue, yValue, scaleX, scaleY) { if (scaleX === void 0) { scaleX = 1; } if (scaleY === void 0) { scaleY = 1; } $el.css('transform', 'translate3d(' + xValue + 'px, ' + yValue + 'px, 0px) scale3d(' + scaleX + ', ' + scaleY + ', 1)'); }; LightGallery.prototype.mousewheel = function () { var _this = this; var lastCall = 0; this.outer.on('wheel.lg', function (e) { if (!e.deltaY || _this.galleryItems.length < 2) { return; } e.preventDefault(); var now = new Date().getTime(); if (now - lastCall < 1000) { return; } lastCall = now; if (e.deltaY > 0) { _this.goToNextSlide(); } else if (e.deltaY < 0) { _this.goToPrevSlide(); } }); }; LightGallery.prototype.isSlideElement = function (target) { return (target.hasClass('lg-outer') || target.hasClass('lg-item') || target.hasClass('lg-img-wrap')); }; LightGallery.prototype.isPosterElement = function (target) { var playButton = this.getSlideItem(this.index) .find('.lg-video-play-button') .get(); return (target.hasClass('lg-video-poster') || target.hasClass('lg-video-play-button') || (playButton && playButton.contains(target.get()))); }; /** * Maximize minimize inline gallery. * @category lGPublicMethods */ LightGallery.prototype.toggleMaximize = function () { var _this = this; this.getElementById('lg-maximize').on('click.lg', function () { _this.$container.toggleClass('lg-inline'); _this.refreshOnResize(); }); }; LightGallery.prototype.invalidateItems = function () { for (var index = 0; index < this.items.length; index++) { var element = this.items[index]; var $element = $LG(element); $element.off("click.lgcustom-item-" + $element.attr('data-lg-id')); } }; LightGallery.prototype.trapFocus = function () { var _this = this; this.$container.get().focus({ preventScroll: true, }); $LG(window).on("keydown.lg.global" + this.lgId, function (e) { if (!_this.lgOpened) { return; } var isTabPressed = e.key === 'Tab' || e.keyCode === 9; if (!isTabPressed) { return; } var focusableEls = utils.getFocusableElements(_this.$container.get()); var firstFocusableEl = focusableEls[0]; var lastFocusableEl = focusableEls[focusableEls.length - 1]; if (e.shiftKey) { if (document.activeElement === firstFocusableEl) { lastFocusableEl.focus(); e.preventDefault(); } } else { if (document.activeElement === lastFocusableEl) { firstFocusableEl.focus(); e.preventDefault(); } } }); }; LightGallery.prototype.manageCloseGallery = function () { var _this = this; if (!this.settings.closable) return; var mousedown = false; this.getElementById('lg-close').on('click.lg', function () { _this.closeGallery(); }); if (this.settings.closeOnTap) { // If you drag the slide and release outside gallery gets close on chrome // for preventing this check mousedown and mouseup happened on .lg-item or lg-outer this.outer.on('mousedown.lg', function (e) { var target = $LG(e.target); if (_this.isSlideElement(target)) { mousedown = true; } else { mousedown = false; } }); this.outer.on('mousemove.lg', function () { mousedown = false; }); this.outer.on('mouseup.lg', function (e) { var target = $LG(e.target); if (_this.isSlideElement(target) && mousedown) { if (!_this.outer.hasClass('lg-dragging')) { _this.closeGallery(); } } }); } }; /** * Close lightGallery if it is opened. * * @description If closable is false in the settings, you need to pass true via closeGallery method to force close gallery * @return returns the estimated time to close gallery completely including the close animation duration * @category lGPublicMethods * @example * const plugin = lightGallery(); * plugin.closeGallery(); * */ LightGallery.prototype.closeGallery = function (force) { var _this = this; if (!this.lgOpened || (!this.settings.closable && !force)) { return 0; } this.LGel.trigger(lGEvents.beforeClose); if (this.settings.resetScrollPosition && !this.settings.hideScrollbar) { $LG(window).scrollTop(this.prevScrollTop); } var currentItem = this.items[this.index]; var transform; if (this.zoomFromOrigin && currentItem) { var _a = this.mediaContainerPosition, top_4 = _a.top, bottom = _a.bottom; var _b = this.galleryItems[this.index], __slideVideoInfo = _b.__slideVideoInfo, poster = _b.poster; //Uncode edit ##START## var imageSize = utils.getSize(currentItem, this.outer, top_4 + bottom, __slideVideoInfo && poster && this.settings.videoMaxSize, this.galleryItems[this.index]); // var imageSize = utils.getSize(currentItem, this.outer, top_4 + bottom, __slideVideoInfo && poster && this.settings.videoMaxSize); //Uncode edit ##END## transform = utils.getTransform(currentItem, this.outer, top_4, bottom, imageSize); } if (this.zoomFromOrigin && transform) { this.outer.addClass('lg-closing lg-zoom-from-image'); this.getSlideItem(this.index) .addClass('lg-start-end-progress') .css('transition-duration', this.settings.startAnimationDuration + 'ms') .css('transform', transform); } else { this.outer.addClass('lg-hide-items'); // lg-zoom-from-image is used for setting the opacity to 1 if zoomFromOrigin is true // If the closing item doesn't have the lg-size attribute, remove this class to avoid the closing css conflicts this.outer.removeClass('lg-zoom-from-image'); } // Unbind all events added by lightGallery // @todo //this.$el.off('.lg.tm'); this.destroyModules(); this.lGalleryOn = false; this.isDummyImageRemoved = false; this.zoomFromOrigin = this.settings.zoomFromOrigin; clearTimeout(this.hideBarTimeout); this.hideBarTimeout = false; $LG('html').removeClass('lg-on'); this.outer.removeClass('lg-visible lg-components-open'); // Resetting opacity to 0 isd required as vertical swipe to close function adds inline opacity. this.$backdrop.removeClass('in').css('opacity', 0); var removeTimeout = this.zoomFromOrigin && transform ? Math.max(this.settings.startAnimationDuration, this.settings.backdropDuration) : this.settings.backdropDuration; this.$container.removeClass('lg-show-in'); // Once the closign animation is completed and gallery is invisible setTimeout(function () { if (_this.zoomFromOrigin && transform) { _this.outer.removeClass('lg-zoom-from-image'); } _this.$container.removeClass('lg-show'); // Reset scrollbar _this.resetScrollBar(); // Need to remove inline opacity as it is used in the stylesheet as well _this.$backdrop .removeAttr('style') .css('transition-duration', _this.settings.backdropDuration + 'ms'); _this.outer.removeClass("lg-closing " + _this.settings.startClass); _this.getSlideItem(_this.index).removeClass('lg-start-end-progress'); _this.$inner.empty(); if (_this.lgOpened) { _this.LGel.trigger(lGEvents.afterClose, { instance: _this, }); } if (_this.$container.get()) { _this.$container.get().blur(); } _this.lgOpened = false; }, removeTimeout + 100); return removeTimeout + 100; }; LightGallery.prototype.initModules = function () { this.plugins.forEach(function (module) { try { module.init(); } catch (err) { console.warn("lightGallery:- make sure lightGallery module is properly initiated"); } }); }; LightGallery.prototype.destroyModules = function (destroy) { this.plugins.forEach(function (module) { try { if (destroy) { module.destroy(); } else { module.closeGallery && module.closeGallery(); } } catch (err) { console.warn("lightGallery:- make sure lightGallery module is properly destroyed"); } }); }; /** * Refresh lightGallery with new set of children. * * @description This is useful to update the gallery when the child elements are changed without calling destroy method. * * If you are using dynamic mode, you can pass the modified array of dynamicEl as the first parameter to refresh the dynamic gallery * @see Demo * @category lGPublicMethods * @example * const plugin = lightGallery(); * // Delete or add children, then call * plugin.refresh(); * */ LightGallery.prototype.refresh = function (galleryItems) { if (!this.settings.dynamic) { this.invalidateItems(); } if (galleryItems) { this.galleryItems = galleryItems; } else { this.galleryItems = this.getItems(); } this.updateControls(); this.openGalleryOnItemClick(); this.LGel.trigger(lGEvents.updateSlides); }; LightGallery.prototype.updateControls = function () { this.addSlideVideoInfo(this.galleryItems); this.updateCounterTotal(); this.manageSingleSlideClassName(); }; /** * Destroy lightGallery. * Destroy lightGallery and its plugin instances completely * * @description This method also calls CloseGallery function internally. Returns the time takes to completely close and destroy the instance. * In case if you want to re-initialize lightGallery right after destroying it, initialize it only once the destroy process is completed. * You can use refresh method most of the times. * @category lGPublicMethods * @example * const plugin = lightGallery(); * plugin.destroy(); * */ LightGallery.prototype.destroy = function () { var _this = this; var closeTimeout = this.closeGallery(true); setTimeout(function () { _this.destroyModules(true); if (!_this.settings.dynamic) { _this.invalidateItems(); } $LG(window).off(".lg.global" + _this.lgId); _this.LGel.off('.lg'); _this.$container.remove(); }, closeTimeout); return closeTimeout; }; return LightGallery; }()); function lightGallery(el, options) { return new LightGallery(el, options); } return lightGallery; }))); /*! * lightgallery | 2.5.0 | June 13th 2022 * http://www.lightgalleryjs.com/ * Copyright (c) 2020 Sachin Neravath; * @license GPLv3 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgZoom = factory()); }(this, (function () { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var zoomSettings = { scale: 1, zoom: true, actualSize: true, showZoomInOutIcons: false, actualSizeIcons: { zoomIn: 'lg-zoom-in', zoomOut: 'lg-zoom-out', }, enableZoomAfter: 300, zoomPluginStrings: { zoomIn: 'Zoom in', zoomOut: 'Zoom out', viewActualSize: 'View actual size', }, }; /** * List of lightGallery events * All events should be documented here * Below interfaces are used to build the website documentations * */ var lGEvents = { afterAppendSlide: 'lgAfterAppendSlide', init: 'lgInit', hasVideo: 'lgHasVideo', containerResize: 'lgContainerResize', updateSlides: 'lgUpdateSlides', afterAppendSubHtml: 'lgAfterAppendSubHtml', beforeOpen: 'lgBeforeOpen', afterOpen: 'lgAfterOpen', slideItemLoad: 'lgSlideItemLoad', beforeSlide: 'lgBeforeSlide', afterSlide: 'lgAfterSlide', posterClick: 'lgPosterClick', dragStart: 'lgDragStart', dragMove: 'lgDragMove', dragEnd: 'lgDragEnd', beforeNextSlide: 'lgBeforeNextSlide', beforePrevSlide: 'lgBeforePrevSlide', beforeClose: 'lgBeforeClose', afterClose: 'lgAfterClose', rotateLeft: 'lgRotateLeft', rotateRight: 'lgRotateRight', flipHorizontal: 'lgFlipHorizontal', flipVertical: 'lgFlipVertical', autoplay: 'lgAutoplay', autoplayStart: 'lgAutoplayStart', autoplayStop: 'lgAutoplayStop', }; var Zoom = /** @class */ (function () { function Zoom(instance, $LG) { // get lightGallery core plugin instance this.core = instance; this.$LG = $LG; this.settings = __assign(__assign({}, zoomSettings), this.core.settings); return this; } // Append Zoom controls. Actual size, Zoom-in, Zoom-out Zoom.prototype.buildTemplates = function () { var zoomIcons = this.settings.showZoomInOutIcons ? "" : ''; if (this.settings.actualSize) { zoomIcons += ""; } this.core.outer.addClass('lg-use-transition-for-zoom'); this.core.$toolbar.first().append(zoomIcons); }; /** * @desc Enable zoom option only once the image is completely loaded * If zoomFromOrigin is true, Zoom is enabled once the dummy image has been inserted * * Zoom styles are defined under lg-zoomable CSS class. */ Zoom.prototype.enableZoom = function (event) { var _this = this; // delay will be 0 except first time var _speed = this.settings.enableZoomAfter + event.detail.delay; // set _speed value 0 if gallery opened from direct url and if it is first slide if (this.$LG('body').first().hasClass('lg-from-hash') && event.detail.delay) { // will execute only once _speed = 0; } else { // Remove lg-from-hash to enable starting animation. this.$LG('body').first().removeClass('lg-from-hash'); } this.zoomableTimeout = setTimeout(function () { if (!_this.isImageSlide()) { return; } _this.core.getSlideItem(event.detail.index).addClass('lg-zoomable'); if (event.detail.index === _this.core.index) { _this.setZoomEssentials(); } }, _speed + 30); }; Zoom.prototype.enableZoomOnSlideItemLoad = function () { // Add zoomable class this.core.LGel.on(lGEvents.slideItemLoad + ".zoom", this.enableZoom.bind(this)); }; Zoom.prototype.getModifier = function (rotateValue, axis, el) { var originalRotate = rotateValue; rotateValue = Math.abs(rotateValue); var transformValues = this.getCurrentTransform(el); if (!transformValues) { return 1; } var modifier = 1; if (axis === 'X') { var flipHorizontalValue = Math.sign(parseFloat(transformValues[0])); if (rotateValue === 0 || rotateValue === 180) { modifier = 1; } else if (rotateValue === 90) { if ((originalRotate === -90 && flipHorizontalValue === 1) || (originalRotate === 90 && flipHorizontalValue === -1)) { modifier = -1; } else { modifier = 1; } } modifier = modifier * flipHorizontalValue; } else { var flipVerticalValue = Math.sign(parseFloat(transformValues[3])); if (rotateValue === 0 || rotateValue === 180) { modifier = 1; } else if (rotateValue === 90) { var sinX = parseFloat(transformValues[1]); var sinMinusX = parseFloat(transformValues[2]); modifier = Math.sign(sinX * sinMinusX * originalRotate * flipVerticalValue); } modifier = modifier * flipVerticalValue; } return modifier; }; Zoom.prototype.getImageSize = function ($image, rotateValue, axis) { var imageSizes = { y: 'offsetHeight', x: 'offsetWidth', }; if (Math.abs(rotateValue) === 90) { // Swap axis if (axis === 'x') { axis = 'y'; } else { axis = 'x'; } } return $image[imageSizes[axis]]; }; Zoom.prototype.getDragCords = function (e, rotateValue) { if (rotateValue === 90) { return { x: e.pageY, y: e.pageX, }; } else { return { x: e.pageX, y: e.pageY, }; } }; Zoom.prototype.getSwipeCords = function (e, rotateValue) { var x = e.targetTouches[0].pageX; var y = e.targetTouches[0].pageY; if (rotateValue === 90) { return { x: y, y: x, }; } else { return { x: x, y: y, }; } }; Zoom.prototype.getDragAllowedAxises = function (rotateValue, scale) { scale = scale || this.scale || 1; var allowY = this.imageYSize * scale > this.containerRect.height; var allowX = this.imageXSize * scale > this.containerRect.width; if (rotateValue === 90) { return { allowX: allowY, allowY: allowX, }; } else { return { allowX: allowX, allowY: allowY, }; } }; /** * * @param {Element} el * @return matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0); * Get the current transform value */ Zoom.prototype.getCurrentTransform = function (el) { if (!el) { return; } var st = window.getComputedStyle(el, null); var tm = st.getPropertyValue('-webkit-transform') || st.getPropertyValue('-moz-transform') || st.getPropertyValue('-ms-transform') || st.getPropertyValue('-o-transform') || st.getPropertyValue('transform') || 'none'; if (tm !== 'none') { return tm.split('(')[1].split(')')[0].split(','); } return; }; Zoom.prototype.getCurrentRotation = function (el) { if (!el) { return 0; } var values = this.getCurrentTransform(el); if (values) { return Math.round(Math.atan2(parseFloat(values[1]), parseFloat(values[0])) * (180 / Math.PI)); // If you want rotate in 360 //return (angle < 0 ? angle + 360 : angle); } return 0; }; Zoom.prototype.setZoomEssentials = function () { var $image = this.core .getSlideItem(this.core.index) .find('.lg-image') .first(); var rotateEl = this.core .getSlideItem(this.core.index) .find('.lg-img-rotate') .first() .get(); this.rotateValue = this.getCurrentRotation(rotateEl); this.imageYSize = this.getImageSize($image.get(), this.rotateValue, 'y'); this.imageXSize = this.getImageSize($image.get(), this.rotateValue, 'x'); this.containerRect = this.core.outer.get().getBoundingClientRect(); this.modifierX = this.getModifier(this.rotateValue, 'X', rotateEl); this.modifierY = this.getModifier(this.rotateValue, 'Y', rotateEl); }; /** * @desc Image zoom * Translate the wrap and scale the image to get better user experience * * @param {String} scale - Zoom decrement/increment value */ Zoom.prototype.zoomImage = function (scale) { // Find offset manually to avoid issue after zoom var offsetX = (this.containerRect.width - this.imageXSize) / 2 + this.containerRect.left; var _a = this.core.mediaContainerPosition, top = _a.top, bottom = _a.bottom; var topBottomSpacing = Math.abs(top - bottom) / 2; var offsetY = (this.containerRect.height - this.imageYSize - topBottomSpacing * this.modifierX) / 2 + this.scrollTop + this.containerRect.top; var originalX; var originalY; if (scale === 1) { this.positionChanged = false; } var dragAllowedAxises = this.getDragAllowedAxises(Math.abs(this.rotateValue), scale); var allowY = dragAllowedAxises.allowY, allowX = dragAllowedAxises.allowX; if (this.positionChanged) { originalX = this.left / (this.scale - 1); originalY = this.top / (this.scale - 1); this.pageX = Math.abs(originalX) + offsetX; this.pageY = Math.abs(originalY) + offsetY; this.positionChanged = false; } var possibleSwipeCords = this.getPossibleSwipeDragCords(this.rotateValue, scale); var _x = offsetX - this.pageX; var _y = offsetY - this.pageY; var x = (scale - 1) * _x; var y = (scale - 1) * _y; if (allowX) { if (this.isBeyondPossibleLeft(x, possibleSwipeCords.minX)) { x = possibleSwipeCords.minX; } else if (this.isBeyondPossibleRight(x, possibleSwipeCords.maxX)) { x = possibleSwipeCords.maxX; } } else { if (scale > 1) { if (x < possibleSwipeCords.minX) { x = possibleSwipeCords.minX; } else if (x > possibleSwipeCords.maxX) { x = possibleSwipeCords.maxX; } } } if (allowY) { if (this.isBeyondPossibleTop(y, possibleSwipeCords.minY)) { y = possibleSwipeCords.minY; } else if (this.isBeyondPossibleBottom(y, possibleSwipeCords.maxY)) { y = possibleSwipeCords.maxY; } } else { // If the translate value based on index of beyond the viewport, utilize the available space to prevent image being cut out if (scale > 1) { //If image goes beyond viewport top, use the minim possible translate value if (y < possibleSwipeCords.minY) { y = possibleSwipeCords.minY; } else if (y > possibleSwipeCords.maxY) { y = possibleSwipeCords.maxY; } } } this.setZoomStyles({ x: x, y: y, scale: scale, }); }; /** * @desc apply scale3d to image and translate to image wrap * @param {style} X,Y and scale */ Zoom.prototype.setZoomStyles = function (style) { var $image = this.core .getSlideItem(this.core.index) .find('.lg-image') .first(); var $dummyImage = this.core.outer .find('.lg-current .lg-dummy-img') .first(); var $imageWrap = $image.parent(); this.scale = style.scale; $image.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)'); $dummyImage.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)'); var transform = 'translate3d(' + style.x + 'px, ' + style.y + 'px, 0)'; $imageWrap.css('transform', transform); this.left = style.x; this.top = style.y; }; /** * @param index - Index of the current slide * @param event - event will be available only if the function is called on clicking/taping the imags */ Zoom.prototype.setActualSize = function (index, event) { var _this = this; // Allow zoom only on image if (!this.isImageSlide() || this.core.outer.hasClass('lg-first-slide-loading')) { return; } var scale = this.getCurrentImageActualSizeScale(); if (this.core.outer.hasClass('lg-zoomed')) { this.scale = 1; } else { this.scale = this.getScale(scale); } this.setPageCords(event); this.beginZoom(this.scale); this.zoomImage(this.scale); setTimeout(function () { _this.core.outer.removeClass('lg-grabbing').addClass('lg-grab'); }, 10); }; Zoom.prototype.getNaturalWidth = function (index) { var $image = this.core.getSlideItem(index).find('.lg-image').first(); var naturalWidth = this.core.galleryItems[index].width; return naturalWidth ? parseFloat(naturalWidth) : $image.get().naturalWidth; }; Zoom.prototype.getActualSizeScale = function (naturalWidth, width) { var _scale; var scale; if (naturalWidth > width) { _scale = naturalWidth / width; scale = _scale || 2; } else { scale = 1; } return scale; }; Zoom.prototype.getCurrentImageActualSizeScale = function () { var $image = this.core .getSlideItem(this.core.index) .find('.lg-image') .first(); var width = $image.get().offsetWidth; var naturalWidth = this.getNaturalWidth(this.core.index) || width; return this.getActualSizeScale(naturalWidth, width); }; Zoom.prototype.getPageCords = function (event) { var cords = {}; if (event) { cords.x = event.pageX || event.targetTouches[0].pageX; cords.y = event.pageY || event.targetTouches[0].pageY; } else { var containerRect = this.core.outer.get().getBoundingClientRect(); cords.x = containerRect.width / 2 + containerRect.left; cords.y = containerRect.height / 2 + this.scrollTop + containerRect.top; } return cords; }; Zoom.prototype.setPageCords = function (event) { var pageCords = this.getPageCords(event); this.pageX = pageCords.x; this.pageY = pageCords.y; }; // If true, zoomed - in else zoomed out Zoom.prototype.beginZoom = function (scale) { this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging'); if (scale > 1) { this.core.outer.addClass('lg-zoomed'); var $actualSize = this.core.getElementById('lg-actual-size'); $actualSize .removeClass(this.settings.actualSizeIcons.zoomIn) .addClass(this.settings.actualSizeIcons.zoomOut); } else { this.resetZoom(); } return scale > 1; }; Zoom.prototype.getScale = function (scale) { var actualSizeScale = this.getCurrentImageActualSizeScale(); if (scale < 1) { scale = 1; } else if (scale > actualSizeScale) { scale = actualSizeScale; } return scale; }; Zoom.prototype.init = function () { var _this = this; if (!this.settings.zoom) { return; } this.buildTemplates(); this.enableZoomOnSlideItemLoad(); var tapped = null; this.core.outer.on('dblclick.lg', function (event) { if (!_this.$LG(event.target).hasClass('lg-image')) { return; } _this.setActualSize(_this.core.index, event); }); this.core.outer.on('touchstart.lg', function (event) { var $target = _this.$LG(event.target); if (event.targetTouches.length === 1 && $target.hasClass('lg-image')) { if (!tapped) { tapped = setTimeout(function () { tapped = null; }, 300); } else { clearTimeout(tapped); tapped = null; event.preventDefault(); _this.setActualSize(_this.core.index, event); } } }); // Update zoom on resize and orientationchange this.core.LGel.on(lGEvents.containerResize + ".zoom " + lGEvents.rotateRight + ".zoom " + lGEvents.rotateLeft + ".zoom " + lGEvents.flipHorizontal + ".zoom " + lGEvents.flipVertical + ".zoom", function () { if (!_this.core.lgOpened || !_this.isImageSlide()) return; _this.setPageCords(); _this.setZoomEssentials(); _this.zoomImage(_this.scale); }); // Update zoom on resize and orientationchange this.$LG(window).on("scroll.lg.zoom.global" + this.core.lgId, function () { if (!_this.core.lgOpened) return; _this.scrollTop = _this.$LG(window).scrollTop(); }); this.core.getElementById('lg-zoom-out').on('click.lg', function () { if (_this.core.outer.find('.lg-current .lg-image').get()) { _this.scale -= _this.settings.scale; _this.scale = _this.getScale(_this.scale); _this.beginZoom(_this.scale); _this.zoomImage(_this.scale); } }); this.core.getElementById('lg-zoom-in').on('click.lg', function () { _this.zoomIn(); }); this.core.getElementById('lg-actual-size').on('click.lg', function () { _this.setActualSize(_this.core.index); }); this.core.LGel.on(lGEvents.beforeOpen + ".zoom", function () { _this.core.outer.find('.lg-item').removeClass('lg-zoomable'); }); this.core.LGel.on(lGEvents.afterOpen + ".zoom", function () { _this.scrollTop = _this.$LG(window).scrollTop(); // Set the initial value center _this.pageX = _this.core.outer.width() / 2; _this.pageY = _this.core.outer.height() / 2 + _this.scrollTop; _this.scale = 1; }); // Reset zoom on slide change this.core.LGel.on(lGEvents.afterSlide + ".zoom", function (event) { var prevIndex = event.detail.prevIndex; _this.scale = 1; _this.positionChanged = false; _this.resetZoom(prevIndex); if (_this.isImageSlide()) { _this.setZoomEssentials(); } }); // Drag option after zoom this.zoomDrag(); this.pinchZoom(); this.zoomSwipe(); // Store the zoomable timeout value just to clear it while closing this.zoomableTimeout = false; this.positionChanged = false; }; Zoom.prototype.zoomIn = function (scale) { // Allow zoom only on image if (!this.isImageSlide()) { return; } if (scale) { this.scale = scale; } else { this.scale += this.settings.scale; } this.scale = this.getScale(this.scale); this.beginZoom(this.scale); this.zoomImage(this.scale); }; // Reset zoom effect Zoom.prototype.resetZoom = function (index) { this.core.outer.removeClass('lg-zoomed lg-zoom-drag-transition'); var $actualSize = this.core.getElementById('lg-actual-size'); var $item = this.core.getSlideItem(index !== undefined ? index : this.core.index); $actualSize .removeClass(this.settings.actualSizeIcons.zoomOut) .addClass(this.settings.actualSizeIcons.zoomIn); $item.find('.lg-img-wrap').first().removeAttr('style'); $item.find('.lg-image').first().removeAttr('style'); this.scale = 1; this.left = 0; this.top = 0; // Reset pagx pagy values to center this.setPageCords(); }; Zoom.prototype.getTouchDistance = function (e) { return Math.sqrt((e.targetTouches[0].pageX - e.targetTouches[1].pageX) * (e.targetTouches[0].pageX - e.targetTouches[1].pageX) + (e.targetTouches[0].pageY - e.targetTouches[1].pageY) * (e.targetTouches[0].pageY - e.targetTouches[1].pageY)); }; Zoom.prototype.pinchZoom = function () { var _this = this; var startDist = 0; var pinchStarted = false; var initScale = 1; var $item = this.core.getSlideItem(this.core.index); this.core.$inner.on('touchstart.lg', function (e) { $item = _this.core.getSlideItem(_this.core.index); if (!_this.isImageSlide()) { return; } if (e.targetTouches.length === 2 && !_this.core.outer.hasClass('lg-first-slide-loading') && (_this.$LG(e.target).hasClass('lg-item') || $item.get().contains(e.target))) { initScale = _this.scale || 1; _this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging'); _this.core.touchAction = 'pinch'; startDist = _this.getTouchDistance(e); } }); this.core.$inner.on('touchmove.lg', function (e) { if (e.targetTouches.length === 2 && _this.core.touchAction === 'pinch' && (_this.$LG(e.target).hasClass('lg-item') || $item.get().contains(e.target))) { e.preventDefault(); var endDist = _this.getTouchDistance(e); var distance = startDist - endDist; if (!pinchStarted && Math.abs(distance) > 5) { pinchStarted = true; } if (pinchStarted) { _this.scale = Math.max(1, initScale + -distance * 0.008); _this.zoomImage(_this.scale); } } }); this.core.$inner.on('touchend.lg', function (e) { if (_this.core.touchAction === 'pinch' && (_this.$LG(e.target).hasClass('lg-item') || $item.get().contains(e.target))) { pinchStarted = false; startDist = 0; if (_this.scale <= 1) { _this.resetZoom(); } else { _this.scale = _this.getScale(_this.scale); _this.zoomImage(_this.scale); _this.core.outer.addClass('lg-zoomed'); } _this.core.touchAction = undefined; } }); }; Zoom.prototype.touchendZoom = function (startCoords, endCoords, allowX, allowY, touchDuration, rotateValue) { var distanceXnew = endCoords.x - startCoords.x; var distanceYnew = endCoords.y - startCoords.y; var speedX = Math.abs(distanceXnew) / touchDuration + 1; var speedY = Math.abs(distanceYnew) / touchDuration + 1; if (speedX > 2) { speedX += 1; } if (speedY > 2) { speedY += 1; } distanceXnew = distanceXnew * speedX; distanceYnew = distanceYnew * speedY; var _LGel = this.core .getSlideItem(this.core.index) .find('.lg-img-wrap') .first(); var distance = {}; distance.x = this.left + distanceXnew * this.modifierX; distance.y = this.top + distanceYnew * this.modifierY; var possibleSwipeCords = this.getPossibleSwipeDragCords(rotateValue); if (Math.abs(distanceXnew) > 15 || Math.abs(distanceYnew) > 15) { if (allowY) { if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) { distance.y = possibleSwipeCords.minY; } else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) { distance.y = possibleSwipeCords.maxY; } } if (allowX) { if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) { distance.x = possibleSwipeCords.minX; } else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) { distance.x = possibleSwipeCords.maxX; } } if (allowY) { this.top = distance.y; } else { distance.y = this.top; } if (allowX) { this.left = distance.x; } else { distance.x = this.left; } this.setZoomSwipeStyles(_LGel, distance); this.positionChanged = true; } }; Zoom.prototype.getZoomSwipeCords = function (startCoords, endCoords, allowX, allowY, possibleSwipeCords) { var distance = {}; if (allowY) { distance.y = this.top + (endCoords.y - startCoords.y) * this.modifierY; if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) { var diffMinY = possibleSwipeCords.minY - distance.y; distance.y = possibleSwipeCords.minY - diffMinY / 6; } else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) { var diffMaxY = distance.y - possibleSwipeCords.maxY; distance.y = possibleSwipeCords.maxY + diffMaxY / 6; } } else { distance.y = this.top; } if (allowX) { distance.x = this.left + (endCoords.x - startCoords.x) * this.modifierX; if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) { var diffMinX = possibleSwipeCords.minX - distance.x; distance.x = possibleSwipeCords.minX - diffMinX / 6; } else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) { var difMaxX = distance.x - possibleSwipeCords.maxX; distance.x = possibleSwipeCords.maxX + difMaxX / 6; } } else { distance.x = this.left; } return distance; }; Zoom.prototype.isBeyondPossibleLeft = function (x, minX) { return x >= minX; }; Zoom.prototype.isBeyondPossibleRight = function (x, maxX) { return x <= maxX; }; Zoom.prototype.isBeyondPossibleTop = function (y, minY) { return y >= minY; }; Zoom.prototype.isBeyondPossibleBottom = function (y, maxY) { return y <= maxY; }; Zoom.prototype.isImageSlide = function () { var currentItem = this.core.galleryItems[this.core.index]; return this.core.getSlideType(currentItem) === 'image'; }; Zoom.prototype.getPossibleSwipeDragCords = function (rotateValue, scale) { var dataScale = scale || this.scale || 1; var elDataScale = Math.abs(dataScale); var _a = this.core.mediaContainerPosition, top = _a.top, bottom = _a.bottom; var topBottomSpacing = Math.abs(top - bottom) / 2; var minY = (this.imageYSize - this.containerRect.height) / 2 + topBottomSpacing * this.modifierX; var maxY = this.containerRect.height - this.imageYSize * elDataScale + minY; var minX = (this.imageXSize - this.containerRect.width) / 2; var maxX = this.containerRect.width - this.imageXSize * elDataScale + minX; var possibleSwipeCords = { minY: minY, maxY: maxY, minX: minX, maxX: maxX, }; if (Math.abs(rotateValue) === 90) { possibleSwipeCords = { minY: minX, maxY: maxX, minX: minY, maxX: maxY, }; } return possibleSwipeCords; }; Zoom.prototype.setZoomSwipeStyles = function (LGel, distance) { LGel.css('transform', 'translate3d(' + distance.x + 'px, ' + distance.y + 'px, 0)'); }; Zoom.prototype.zoomSwipe = function () { var _this = this; var startCoords = {}; var endCoords = {}; var isMoved = false; // Allow x direction drag var allowX = false; // Allow Y direction drag var allowY = false; var startTime = new Date(); var endTime = new Date(); var possibleSwipeCords; var _LGel; var $item = this.core.getSlideItem(this.core.index); this.core.$inner.on('touchstart.lg', function (e) { // Allow zoom only on image if (!_this.isImageSlide()) { return; } $item = _this.core.getSlideItem(_this.core.index); if ((_this.$LG(e.target).hasClass('lg-item') || $item.get().contains(e.target)) && e.targetTouches.length === 1 && _this.core.outer.hasClass('lg-zoomed')) { e.preventDefault(); startTime = new Date(); _this.core.touchAction = 'zoomSwipe'; _LGel = _this.core .getSlideItem(_this.core.index) .find('.lg-img-wrap') .first(); var dragAllowedAxises = _this.getDragAllowedAxises(Math.abs(_this.rotateValue)); allowY = dragAllowedAxises.allowY; allowX = dragAllowedAxises.allowX; if (allowX || allowY) { startCoords = _this.getSwipeCords(e, Math.abs(_this.rotateValue)); } possibleSwipeCords = _this.getPossibleSwipeDragCords(_this.rotateValue); // reset opacity and transition duration _this.core.outer.addClass('lg-zoom-dragging lg-zoom-drag-transition'); } }); this.core.$inner.on('touchmove.lg', function (e) { if (e.targetTouches.length === 1 && _this.core.touchAction === 'zoomSwipe' && (_this.$LG(e.target).hasClass('lg-item') || $item.get().contains(e.target))) { e.preventDefault(); _this.core.touchAction = 'zoomSwipe'; endCoords = _this.getSwipeCords(e, Math.abs(_this.rotateValue)); var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords); if (Math.abs(endCoords.x - startCoords.x) > 15 || Math.abs(endCoords.y - startCoords.y) > 15) { isMoved = true; _this.setZoomSwipeStyles(_LGel, distance); } } }); this.core.$inner.on('touchend.lg', function (e) { if (_this.core.touchAction === 'zoomSwipe' && (_this.$LG(e.target).hasClass('lg-item') || $item.get().contains(e.target))) { _this.core.touchAction = undefined; _this.core.outer.removeClass('lg-zoom-dragging'); if (!isMoved) { return; } isMoved = false; endTime = new Date(); var touchDuration = endTime.valueOf() - startTime.valueOf(); _this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration, _this.rotateValue); } }); }; Zoom.prototype.zoomDrag = function () { var _this = this; var startCoords = {}; var endCoords = {}; var isDragging = false; var isMoved = false; // Allow x direction drag var allowX = false; // Allow Y direction drag var allowY = false; var startTime; var endTime; var possibleSwipeCords; var _LGel; this.core.outer.on('mousedown.lg.zoom', function (e) { // Allow zoom only on image if (!_this.isImageSlide()) { return; } var $item = _this.core.getSlideItem(_this.core.index); if (_this.$LG(e.target).hasClass('lg-item') || $item.get().contains(e.target)) { startTime = new Date(); _LGel = _this.core .getSlideItem(_this.core.index) .find('.lg-img-wrap') .first(); var dragAllowedAxises = _this.getDragAllowedAxises(Math.abs(_this.rotateValue)); allowY = dragAllowedAxises.allowY; allowX = dragAllowedAxises.allowX; if (_this.core.outer.hasClass('lg-zoomed')) { if (_this.$LG(e.target).hasClass('lg-object') && (allowX || allowY)) { e.preventDefault(); startCoords = _this.getDragCords(e, Math.abs(_this.rotateValue)); possibleSwipeCords = _this.getPossibleSwipeDragCords(_this.rotateValue); isDragging = true; // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723 _this.core.outer.get().scrollLeft += 1; _this.core.outer.get().scrollLeft -= 1; _this.core.outer .removeClass('lg-grab') .addClass('lg-grabbing lg-zoom-drag-transition lg-zoom-dragging'); // reset opacity and transition duration } } } }); this.$LG(window).on("mousemove.lg.zoom.global" + this.core.lgId, function (e) { if (isDragging) { isMoved = true; endCoords = _this.getDragCords(e, Math.abs(_this.rotateValue)); var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords); _this.setZoomSwipeStyles(_LGel, distance); } }); this.$LG(window).on("mouseup.lg.zoom.global" + this.core.lgId, function (e) { if (isDragging) { endTime = new Date(); isDragging = false; _this.core.outer.removeClass('lg-zoom-dragging'); // Fix for chrome mouse move on click if (isMoved && (startCoords.x !== endCoords.x || startCoords.y !== endCoords.y)) { endCoords = _this.getDragCords(e, Math.abs(_this.rotateValue)); var touchDuration = endTime.valueOf() - startTime.valueOf(); _this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration, _this.rotateValue); } isMoved = false; } _this.core.outer.removeClass('lg-grabbing').addClass('lg-grab'); }); }; Zoom.prototype.closeGallery = function () { this.resetZoom(); }; Zoom.prototype.destroy = function () { // Unbind all events added by lightGallery zoom plugin this.$LG(window).off(".lg.zoom.global" + this.core.lgId); this.core.LGel.off('.lg.zoom'); this.core.LGel.off('.zoom'); clearTimeout(this.zoomableTimeout); this.zoomableTimeout = false; }; return Zoom; }()); return Zoom; }))); /*! * lightgallery | 2.5.0 | June 13th 2022 * http://www.lightgalleryjs.com/ * Copyright (c) 2020 Sachin Neravath; * @license GPLv3 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgFullscreen = factory()); }(this, (function () { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var fullscreenSettings = { fullScreen: true, fullscreenPluginStrings: { toggleFullscreen: 'Toggle Fullscreen', }, }; var FullScreen = /** @class */ (function () { function FullScreen(instance, $LG) { // get lightGallery core plugin instance this.core = instance; this.$LG = $LG; // extend module default settings with lightGallery core settings this.settings = __assign(__assign({}, fullscreenSettings), this.core.settings); return this; } FullScreen.prototype.init = function () { var fullScreen = ''; if (this.settings.fullScreen) { // check for fullscreen browser support if (!document.fullscreenEnabled && !document.webkitFullscreenEnabled && !document.mozFullScreenEnabled && !document.msFullscreenEnabled) { return; } else { fullScreen = ""; this.core.$toolbar.append(fullScreen); this.fullScreen(); } } }; FullScreen.prototype.isFullScreen = function () { return (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement); }; FullScreen.prototype.requestFullscreen = function () { var el = document.documentElement; if (el.requestFullscreen) { el.requestFullscreen(); } else if (el.msRequestFullscreen) { el.msRequestFullscreen(); } else if (el.mozRequestFullScreen) { el.mozRequestFullScreen(); } else if (el.webkitRequestFullscreen) { el.webkitRequestFullscreen(); } }; FullScreen.prototype.exitFullscreen = function () { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } }; // https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode FullScreen.prototype.fullScreen = function () { var _this = this; this.$LG(document).on("fullscreenchange.lg.global" + this.core.lgId + " \n webkitfullscreenchange.lg.global" + this.core.lgId + " \n mozfullscreenchange.lg.global" + this.core.lgId + " \n MSFullscreenChange.lg.global" + this.core.lgId, function () { if (!_this.core.lgOpened) return; _this.core.outer.toggleClass('lg-fullscreen-on'); }); this.core.outer .find('.lg-fullscreen') .first() .on('click.lg', function () { if (_this.isFullScreen()) { _this.exitFullscreen(); } else { _this.requestFullscreen(); } }); }; FullScreen.prototype.closeGallery = function () { // exit from fullscreen if activated if (this.isFullScreen()) { this.exitFullscreen(); } }; FullScreen.prototype.destroy = function () { this.$LG(document).off("fullscreenchange.lg.global" + this.core.lgId + " \n webkitfullscreenchange.lg.global" + this.core.lgId + " \n mozfullscreenchange.lg.global" + this.core.lgId + " \n MSFullscreenChange.lg.global" + this.core.lgId); }; return FullScreen; }()); return FullScreen; }))); /*! * lightgallery | 2.5.0 | June 13th 2022 * http://www.lightgalleryjs.com/ * Copyright (c) 2020 Sachin Neravath; * @license GPLv3 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgHash = factory()); }(this, (function () { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; /** * List of lightGallery events * All events should be documented here * Below interfaces are used to build the website documentations * */ var lGEvents = { afterAppendSlide: 'lgAfterAppendSlide', init: 'lgInit', hasVideo: 'lgHasVideo', containerResize: 'lgContainerResize', updateSlides: 'lgUpdateSlides', afterAppendSubHtml: 'lgAfterAppendSubHtml', beforeOpen: 'lgBeforeOpen', afterOpen: 'lgAfterOpen', slideItemLoad: 'lgSlideItemLoad', beforeSlide: 'lgBeforeSlide', afterSlide: 'lgAfterSlide', posterClick: 'lgPosterClick', dragStart: 'lgDragStart', dragMove: 'lgDragMove', dragEnd: 'lgDragEnd', beforeNextSlide: 'lgBeforeNextSlide', beforePrevSlide: 'lgBeforePrevSlide', beforeClose: 'lgBeforeClose', afterClose: 'lgAfterClose', rotateLeft: 'lgRotateLeft', rotateRight: 'lgRotateRight', flipHorizontal: 'lgFlipHorizontal', flipVertical: 'lgFlipVertical', autoplay: 'lgAutoplay', autoplayStart: 'lgAutoplayStart', autoplayStop: 'lgAutoplayStop', }; var hashSettings = { hash: true, galleryId: '1', customSlideName: false, }; var Hash = /** @class */ (function () { function Hash(instance, $LG) { // get lightGallery core plugin instance this.core = instance; this.$LG = $LG; // extend module default settings with lightGallery core settings this.settings = __assign(__assign({}, hashSettings), this.core.settings); return this; } Hash.prototype.init = function () { var _this = this; if (!this.settings.hash) { return; } this.oldHash = window.location.hash; setTimeout(function () { _this.buildFromHash(); }, 100); // Change hash value on after each slide transition this.core.LGel.on(lGEvents.afterSlide + ".hash", this.onAfterSlide.bind(this)); this.core.LGel.on(lGEvents.afterClose + ".hash", this.onCloseAfter.bind(this)); // Listen hash change and change the slide according to slide value this.$LG(window).on("hashchange.lg.hash.global" + this.core.lgId, this.onHashchange.bind(this)); }; Hash.prototype.onAfterSlide = function (event) { var slideName = this.core.galleryItems[event.detail.index].slideName; slideName = this.settings.customSlideName ? slideName || event.detail.index : event.detail.index; if (history.replaceState) { history.replaceState(null, '', window.location.pathname + window.location.search + '#lg=' + this.settings.galleryId + '&slide=' + slideName); } else { window.location.hash = 'lg=' + this.settings.galleryId + '&slide=' + slideName; } }; /** * Get index of the slide from custom slideName. Has to be a public method. Used in hash plugin * @param {String} hash * @returns {Number} Index of the slide. */ Hash.prototype.getIndexFromUrl = function (hash) { if (hash === void 0) { hash = window.location.hash; } var slideName = hash.split('&slide=')[1]; var _idx = 0; if (this.settings.customSlideName) { for (var index = 0; index < this.core.galleryItems.length; index++) { var dynamicEl = this.core.galleryItems[index]; if (dynamicEl.slideName === slideName) { _idx = index; break; } } } else { _idx = parseInt(slideName, 10); } return isNaN(_idx) ? 0 : _idx; }; // Build Gallery if gallery id exist in the URL Hash.prototype.buildFromHash = function () { // if dynamic option is enabled execute immediately var _hash = window.location.hash; //Uncode edit ##START## // if (_hash.indexOf('lg=' + this.settings.galleryId) > 0) { if (_hash.indexOf('lg=' + this.settings.galleryId + '&') > 0) { //Uncode edit ##END## // This class is used to remove the initial animation if galleryId present in the URL this.$LG(document.body).addClass('lg-from-hash'); var index = this.getIndexFromUrl(_hash); this.core.openGallery(index); return true; } }; Hash.prototype.onCloseAfter = function () { // Reset to old hash value if (this.oldHash && this.oldHash.indexOf('lg=' + this.settings.galleryId) < 0) { if (history.replaceState) { history.replaceState(null, '', this.oldHash); } else { window.location.hash = this.oldHash; } } else { if (history.replaceState) { history.replaceState(null, document.title, window.location.pathname + window.location.search); } else { window.location.hash = ''; } } }; Hash.prototype.onHashchange = function () { if (!this.core.lgOpened) return; var _hash = window.location.hash; var index = this.getIndexFromUrl(_hash); // it galleryId doesn't exist in the url close the gallery if (_hash.indexOf('lg=' + this.settings.galleryId) > -1) { this.core.slide(index, false, false); } else if (this.core.lGalleryOn) { this.core.closeGallery(); } }; Hash.prototype.closeGallery = function () { if (this.settings.hash) { this.$LG(document.body).removeClass('lg-from-hash'); } }; Hash.prototype.destroy = function () { this.core.LGel.off('.lg.hash'); this.core.LGel.off('.hash'); this.$LG(window).off("hashchange.lg.hash.global" + this.core.lgId); }; return Hash; }()); return Hash; }))); /*! * lightgallery | 2.5.0 | June 13th 2022 * http://www.lightgalleryjs.com/ * Copyright (c) 2020 Sachin Neravath; * @license GPLv3 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgShare = factory()); }(this, (function () { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __spreadArrays() { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; } var shareSettings = { share: true, facebook: true, facebookDropdownText: 'Facebook', twitter: true, twitterDropdownText: 'Twitter', pinterest: true, pinterestDropdownText: 'Pinterest', additionalShareOptions: [], sharePluginStrings: { share: 'Share' }, }; function getFacebookShareLink(galleryItem) { var facebookBaseUrl = '//www.facebook.com/sharer/sharer.php?u='; return (facebookBaseUrl + encodeURIComponent(galleryItem.facebookShareUrl || window.location.href)); } function getTwitterShareLink(galleryItem) { var twitterBaseUrl = '//twitter.com/intent/tweet?text='; var url = encodeURIComponent(galleryItem.twitterShareUrl || window.location.href); var text = galleryItem.tweetText; return twitterBaseUrl + text + '&url=' + url; } function getPinterestShareLink(galleryItem) { var pinterestBaseUrl = 'http://www.pinterest.com/pin/create/button/?url='; var description = galleryItem.pinterestText; var media = encodeURIComponent(galleryItem.src); var url = encodeURIComponent(galleryItem.pinterestShareUrl || window.location.href); return (pinterestBaseUrl + url + '&media=' + media + '&description=' + description); } /** * List of lightGallery events * All events should be documented here * Below interfaces are used to build the website documentations * */ var lGEvents = { afterAppendSlide: 'lgAfterAppendSlide', init: 'lgInit', hasVideo: 'lgHasVideo', containerResize: 'lgContainerResize', updateSlides: 'lgUpdateSlides', afterAppendSubHtml: 'lgAfterAppendSubHtml', beforeOpen: 'lgBeforeOpen', afterOpen: 'lgAfterOpen', slideItemLoad: 'lgSlideItemLoad', beforeSlide: 'lgBeforeSlide', afterSlide: 'lgAfterSlide', posterClick: 'lgPosterClick', dragStart: 'lgDragStart', dragMove: 'lgDragMove', dragEnd: 'lgDragEnd', beforeNextSlide: 'lgBeforeNextSlide', beforePrevSlide: 'lgBeforePrevSlide', beforeClose: 'lgBeforeClose', afterClose: 'lgAfterClose', rotateLeft: 'lgRotateLeft', rotateRight: 'lgRotateRight', flipHorizontal: 'lgFlipHorizontal', flipVertical: 'lgFlipVertical', autoplay: 'lgAutoplay', autoplayStart: 'lgAutoplayStart', autoplayStop: 'lgAutoplayStop', }; var Share = /** @class */ (function () { function Share(instance) { this.shareOptions = []; // get lightGallery core plugin instance this.core = instance; // extend module default settings with lightGallery core settings this.settings = __assign(__assign({}, shareSettings), this.core.settings); return this; } Share.prototype.init = function () { if (!this.settings.share) { return; } this.shareOptions = __spreadArrays(this.getDefaultShareOptions(), this.settings.additionalShareOptions); this.setLgShareMarkup(); this.core.outer .find('.lg-share .lg-dropdown') .append(this.getShareListHtml()); this.core.LGel.on(lGEvents.afterSlide + ".share", this.onAfterSlide.bind(this)); }; Share.prototype.getShareListHtml = function () { var shareHtml = ''; this.shareOptions.forEach(function (shareOption) { shareHtml += shareOption.dropdownHTML; }); return shareHtml; }; Share.prototype.setLgShareMarkup = function () { var _this = this; this.core.$toolbar.append(""); this.core.outer.append('
'); var $shareButton = this.core.outer.find('.lg-share'); $shareButton.first().on('click.lg', function () { _this.core.outer.toggleClass('lg-dropdown-active'); if (_this.core.outer.hasClass('lg-dropdown-active')) { _this.core.outer.attr('aria-expanded', true); } else { _this.core.outer.attr('aria-expanded', false); } }); this.core.outer .find('.lg-dropdown-overlay') .first() .on('click.lg', function () { _this.core.outer.removeClass('lg-dropdown-active'); _this.core.outer.attr('aria-expanded', false); }); }; Share.prototype.onAfterSlide = function (event) { var _this = this; var index = event.detail.index; var currentItem = this.core.galleryItems[index]; setTimeout(function () { _this.shareOptions.forEach(function (shareOption) { var selector = shareOption.selector; _this.core.outer .find(selector) .attr('href', shareOption.generateLink(currentItem)); }); }, 100); }; Share.prototype.getShareListItemHTML = function (type, text) { return "
  • " + text + "
  • "; }; Share.prototype.getDefaultShareOptions = function () { return __spreadArrays((this.settings.facebook ? [ { type: 'facebook', generateLink: getFacebookShareLink, dropdownHTML: this.getShareListItemHTML('facebook', this.settings.facebookDropdownText), selector: '.lg-share-facebook', }, ] : []), (this.settings.twitter ? [ { type: 'twitter', generateLink: getTwitterShareLink, dropdownHTML: this.getShareListItemHTML('twitter', this.settings.twitterDropdownText), selector: '.lg-share-twitter', }, ] : []), (this.settings.pinterest ? [ { type: 'pinterest', generateLink: getPinterestShareLink, dropdownHTML: this.getShareListItemHTML('pinterest', this.settings.pinterestDropdownText), selector: '.lg-share-pinterest', }, ] : [])); }; Share.prototype.destroy = function () { this.core.outer.find('.lg-dropdown-overlay').remove(); this.core.outer.find('.lg-share').remove(); this.core.LGel.off('.lg.share'); this.core.LGel.off('.share'); }; return Share; }()); return Share; }))); /*! * lightgallery | 2.5.0 | June 13th 2022 * http://www.lightgalleryjs.com/ * Copyright (c) 2020 Sachin Neravath; * @license GPLv3 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgThumbnail = factory()); }(this, (function () { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var thumbnailsSettings = { thumbnail: true, animateThumb: true, currentPagerPosition: 'middle', alignThumbnails: 'middle', thumbWidth: 100, thumbHeight: '80px', thumbMargin: 5, appendThumbnailsTo: '.lg-components', toggleThumb: false, enableThumbDrag: true, enableThumbSwipe: true, thumbnailSwipeThreshold: 10, loadYouTubeThumbnail: true, youTubeThumbSize: 1, thumbnailPluginStrings: { toggleThumbnails: 'Toggle thumbnails', }, }; /** * List of lightGallery events * All events should be documented here * Below interfaces are used to build the website documentations * */ var lGEvents = { afterAppendSlide: 'lgAfterAppendSlide', init: 'lgInit', hasVideo: 'lgHasVideo', containerResize: 'lgContainerResize', updateSlides: 'lgUpdateSlides', afterAppendSubHtml: 'lgAfterAppendSubHtml', beforeOpen: 'lgBeforeOpen', afterOpen: 'lgAfterOpen', slideItemLoad: 'lgSlideItemLoad', beforeSlide: 'lgBeforeSlide', afterSlide: 'lgAfterSlide', posterClick: 'lgPosterClick', dragStart: 'lgDragStart', dragMove: 'lgDragMove', dragEnd: 'lgDragEnd', beforeNextSlide: 'lgBeforeNextSlide', beforePrevSlide: 'lgBeforePrevSlide', beforeClose: 'lgBeforeClose', afterClose: 'lgAfterClose', rotateLeft: 'lgRotateLeft', rotateRight: 'lgRotateRight', flipHorizontal: 'lgFlipHorizontal', flipVertical: 'lgFlipVertical', autoplay: 'lgAutoplay', autoplayStart: 'lgAutoplayStart', autoplayStop: 'lgAutoplayStop', }; var Thumbnail = /** @class */ (function () { function Thumbnail(instance, $LG) { this.thumbOuterWidth = 0; this.thumbTotalWidth = 0; this.translateX = 0; this.thumbClickable = false; // get lightGallery core plugin instance this.core = instance; this.$LG = $LG; return this; } Thumbnail.prototype.init = function () { // extend module default settings with lightGallery core settings this.settings = __assign(__assign({}, thumbnailsSettings), this.core.settings); this.thumbOuterWidth = 0; this.thumbTotalWidth = this.core.galleryItems.length * (this.settings.thumbWidth + this.settings.thumbMargin); // Thumbnail animation value this.translateX = 0; this.setAnimateThumbStyles(); if (!this.core.settings.allowMediaOverlap) { this.settings.toggleThumb = false; } if (this.settings.thumbnail) { this.build(); if (this.settings.animateThumb) { if (this.settings.enableThumbDrag) { this.enableThumbDrag(); } if (this.settings.enableThumbSwipe) { this.enableThumbSwipe(); } this.thumbClickable = false; } else { this.thumbClickable = true; } this.toggleThumbBar(); this.thumbKeyPress(); } }; Thumbnail.prototype.build = function () { var _this = this; this.setThumbMarkup(); this.manageActiveClassOnSlideChange(); this.$lgThumb.first().on('click.lg touchend.lg', function (e) { var $target = _this.$LG(e.target); if (!$target.hasAttribute('data-lg-item-id')) { return; } setTimeout(function () { // In IE9 and bellow touch does not support // Go to slide if browser does not support css transitions if (_this.thumbClickable && !_this.core.lgBusy) { var index = parseInt($target.attr('data-lg-item-id')); _this.core.slide(index, false, true, false); } }, 50); }); //Uncode edit ##START## // this.core.LGel.on(lGEvents.beforeSlide + ".thumb", function (event) { this.core.LGel.on(lGEvents.beforeSlide, function (event) { //Uncode edit ##END## var index = event.detail.index; _this.animateThumb(index); }); //Uncode edit ##START## // this.core.LGel.on(lGEvents.beforeOpen + ".thumb", function () { this.core.LGel.on(lGEvents.beforeOpen, function () { //Uncode edit ##END## _this.thumbOuterWidth = _this.core.outer.get().offsetWidth; }); //Uncode edit ##START## // this.core.LGel.on(lGEvents.updateSlides + ".thumb", function () { this.core.LGel.on(lGEvents.updateSlides, function () { //Uncode edit ##END## _this.rebuildThumbnails(); }); //Uncode edit ##START## // this.core.LGel.on(lGEvents.containerResize + ".thumb", function () { this.core.LGel.on(lGEvents.containerResize, function () { //Uncode edit ##END## if (!_this.core.lgOpened) return; setTimeout(function () { _this.thumbOuterWidth = _this.core.outer.get().offsetWidth; _this.animateThumb(_this.core.index); _this.thumbOuterWidth = _this.core.outer.get().offsetWidth; }, 50); }); }; Thumbnail.prototype.setThumbMarkup = function () { var thumbOuterClassNames = 'lg-thumb-outer '; if (this.settings.alignThumbnails) { thumbOuterClassNames += "lg-thumb-align-" + this.settings.alignThumbnails; } var html = "
    \n
    \n
    \n
    "; this.core.outer.addClass('lg-has-thumb'); if (this.settings.appendThumbnailsTo === '.lg-components') { this.core.$lgComponents.append(html); } else { this.core.outer.append(html); } this.$thumbOuter = this.core.outer.find('.lg-thumb-outer').first(); this.$lgThumb = this.core.outer.find('.lg-thumb').first(); if (this.settings.animateThumb) { this.core.outer .find('.lg-thumb') .css('transition-duration', this.core.settings.speed + 'ms') .css('width', this.thumbTotalWidth + 'px') .css('position', 'relative'); } this.setThumbItemHtml(this.core.galleryItems); }; Thumbnail.prototype.enableThumbDrag = function () { var _this = this; var thumbDragUtils = { cords: { startX: 0, endX: 0, }, isMoved: false, newTranslateX: 0, startTime: new Date(), endTime: new Date(), touchMoveTime: 0, }; var isDragging = false; this.$thumbOuter.addClass('lg-grab'); this.core.outer .find('.lg-thumb') .first() .on('mousedown.lg.thumb', function (e) { if (_this.thumbTotalWidth > _this.thumbOuterWidth) { // execute only on .lg-object e.preventDefault(); thumbDragUtils.cords.startX = e.pageX; thumbDragUtils.startTime = new Date(); _this.thumbClickable = false; isDragging = true; // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723 _this.core.outer.get().scrollLeft += 1; _this.core.outer.get().scrollLeft -= 1; // * _this.$thumbOuter .removeClass('lg-grab') .addClass('lg-grabbing'); } }); this.$LG(window).on("mousemove.lg.thumb.global" + this.core.lgId, function (e) { if (!_this.core.lgOpened) return; if (isDragging) { thumbDragUtils.cords.endX = e.pageX; thumbDragUtils = _this.onThumbTouchMove(thumbDragUtils); } }); this.$LG(window).on("mouseup.lg.thumb.global" + this.core.lgId, function () { if (!_this.core.lgOpened) return; if (thumbDragUtils.isMoved) { thumbDragUtils = _this.onThumbTouchEnd(thumbDragUtils); } else { _this.thumbClickable = true; } if (isDragging) { isDragging = false; _this.$thumbOuter.removeClass('lg-grabbing').addClass('lg-grab'); } }); }; Thumbnail.prototype.enableThumbSwipe = function () { var _this = this; var thumbDragUtils = { cords: { startX: 0, endX: 0, }, isMoved: false, newTranslateX: 0, startTime: new Date(), endTime: new Date(), touchMoveTime: 0, }; this.$lgThumb.on('touchstart.lg', function (e) { if (_this.thumbTotalWidth > _this.thumbOuterWidth) { e.preventDefault(); thumbDragUtils.cords.startX = e.targetTouches[0].pageX; _this.thumbClickable = false; thumbDragUtils.startTime = new Date(); } }); this.$lgThumb.on('touchmove.lg', function (e) { if (_this.thumbTotalWidth > _this.thumbOuterWidth) { e.preventDefault(); thumbDragUtils.cords.endX = e.targetTouches[0].pageX; thumbDragUtils = _this.onThumbTouchMove(thumbDragUtils); } }); this.$lgThumb.on('touchend.lg', function () { if (thumbDragUtils.isMoved) { thumbDragUtils = _this.onThumbTouchEnd(thumbDragUtils); } else { _this.thumbClickable = true; } }); }; // Rebuild thumbnails Thumbnail.prototype.rebuildThumbnails = function () { var _this = this; // Remove transitions this.$thumbOuter.addClass('lg-rebuilding-thumbnails'); setTimeout(function () { _this.thumbTotalWidth = _this.core.galleryItems.length * (_this.settings.thumbWidth + _this.settings.thumbMargin); _this.$lgThumb.css('width', _this.thumbTotalWidth + 'px'); _this.$lgThumb.empty(); _this.setThumbItemHtml(_this.core.galleryItems); _this.animateThumb(_this.core.index); }, 50); setTimeout(function () { _this.$thumbOuter.removeClass('lg-rebuilding-thumbnails'); }, 200); }; // @ts-check Thumbnail.prototype.setTranslate = function (value) { this.$lgThumb.css('transform', 'translate3d(-' + value + 'px, 0px, 0px)'); }; Thumbnail.prototype.getPossibleTransformX = function (left) { if (left > this.thumbTotalWidth - this.thumbOuterWidth) { left = this.thumbTotalWidth - this.thumbOuterWidth; } if (left < 0) { left = 0; } return left; }; Thumbnail.prototype.animateThumb = function (index) { this.$lgThumb.css('transition-duration', this.core.settings.speed + 'ms'); if (this.settings.animateThumb) { var position = 0; switch (this.settings.currentPagerPosition) { case 'left': position = 0; break; case 'middle': position = this.thumbOuterWidth / 2 - this.settings.thumbWidth / 2; break; case 'right': position = this.thumbOuterWidth - this.settings.thumbWidth; } this.translateX = (this.settings.thumbWidth + this.settings.thumbMargin) * index - 1 - position; if (this.translateX > this.thumbTotalWidth - this.thumbOuterWidth) { this.translateX = this.thumbTotalWidth - this.thumbOuterWidth; } if (this.translateX < 0) { this.translateX = 0; } this.setTranslate(this.translateX); } }; Thumbnail.prototype.onThumbTouchMove = function (thumbDragUtils) { thumbDragUtils.newTranslateX = this.translateX; thumbDragUtils.isMoved = true; thumbDragUtils.touchMoveTime = new Date().valueOf(); thumbDragUtils.newTranslateX -= thumbDragUtils.cords.endX - thumbDragUtils.cords.startX; thumbDragUtils.newTranslateX = this.getPossibleTransformX(thumbDragUtils.newTranslateX); // move current slide this.setTranslate(thumbDragUtils.newTranslateX); this.$thumbOuter.addClass('lg-dragging'); return thumbDragUtils; }; Thumbnail.prototype.onThumbTouchEnd = function (thumbDragUtils) { thumbDragUtils.isMoved = false; thumbDragUtils.endTime = new Date(); this.$thumbOuter.removeClass('lg-dragging'); var touchDuration = thumbDragUtils.endTime.valueOf() - thumbDragUtils.startTime.valueOf(); var distanceXnew = thumbDragUtils.cords.endX - thumbDragUtils.cords.startX; var speedX = Math.abs(distanceXnew) / touchDuration; // Some magical numbers // Can be improved if (speedX > 0.15 && thumbDragUtils.endTime.valueOf() - thumbDragUtils.touchMoveTime < 30) { speedX += 1; if (speedX > 2) { speedX += 1; } speedX = speedX + speedX * (Math.abs(distanceXnew) / this.thumbOuterWidth); this.$lgThumb.css('transition-duration', Math.min(speedX - 1, 2) + 'settings'); distanceXnew = distanceXnew * speedX; this.translateX = this.getPossibleTransformX(this.translateX - distanceXnew); this.setTranslate(this.translateX); } else { this.translateX = thumbDragUtils.newTranslateX; } if (Math.abs(thumbDragUtils.cords.endX - thumbDragUtils.cords.startX) < this.settings.thumbnailSwipeThreshold) { this.thumbClickable = true; } return thumbDragUtils; }; Thumbnail.prototype.getThumbHtml = function (thumb, index) { var slideVideoInfo = this.core.galleryItems[index].__slideVideoInfo || {}; var thumbImg; if (slideVideoInfo.youtube) { if (this.settings.loadYouTubeThumbnail) { thumbImg = '//img.youtube.com/vi/' + slideVideoInfo.youtube[1] + '/' + this.settings.youTubeThumbSize + '.jpg'; } else { thumbImg = thumb; } } else { thumbImg = thumb; } return "
    \n \n
    "; }; Thumbnail.prototype.getThumbItemHtml = function (items) { var thumbList = ''; for (var i = 0; i < items.length; i++) { thumbList += this.getThumbHtml(items[i].thumb, i); } return thumbList; }; Thumbnail.prototype.setThumbItemHtml = function (items) { var thumbList = this.getThumbItemHtml(items); this.$lgThumb.html(thumbList); }; Thumbnail.prototype.setAnimateThumbStyles = function () { if (this.settings.animateThumb) { this.core.outer.addClass('lg-animate-thumb'); } }; // Manage thumbnail active calss Thumbnail.prototype.manageActiveClassOnSlideChange = function () { var _this = this; // manage active class for thumbnail //Uncode edit ##START## // this.core.LGel.on(lGEvents.beforeSlide + ".thumb", function (event) { this.core.LGel.on(lGEvents.beforeSlide, function (event) { //Uncode edit ##END## var $thumb = _this.core.outer.find('.lg-thumb-item'); var index = event.detail.index; $thumb.removeClass('active'); $thumb.eq(index).addClass('active'); }); }; // Toggle thumbnail bar Thumbnail.prototype.toggleThumbBar = function () { var _this = this; if (this.settings.toggleThumb) { this.core.outer.addClass('lg-can-toggle'); this.core.$toolbar.append(''); this.core.outer .find('.lg-toggle-thumb') .first() .on('click.lg', function () { _this.core.outer.toggleClass('lg-components-open'); }); } }; Thumbnail.prototype.thumbKeyPress = function () { var _this = this; this.$LG(window).on("keydown.lg.thumb.global" + this.core.lgId, function (e) { if (!_this.core.lgOpened || !_this.settings.toggleThumb) return; if (e.keyCode === 38) { e.preventDefault(); _this.core.outer.addClass('lg-components-open'); } else if (e.keyCode === 40) { e.preventDefault(); _this.core.outer.removeClass('lg-components-open'); } }); }; Thumbnail.prototype.destroy = function () { if (this.settings.thumbnail) { this.$LG(window).off(".lg.thumb.global" + this.core.lgId); this.core.LGel.off('.lg.thumb'); this.core.LGel.off('.thumb'); this.$thumbOuter.remove(); this.core.outer.removeClass('lg-has-thumb'); } }; return Thumbnail; }()); return Thumbnail; }))); /*! * lightgallery | 2.5.0 | June 13th 2022 * http://www.lightgalleryjs.com/ * Copyright (c) 2020 Sachin Neravath; * @license GPLv3 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgVideo = factory()); }(this, (function () { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var videoSettings = { autoplayFirstVideo: true, youTubePlayerParams: false, vimeoPlayerParams: false, wistiaPlayerParams: false, gotoNextSlideOnVideoEnd: true, autoplayVideoOnSlide: false, videojs: false, videojsTheme: '', videojsOptions: {}, }; /** * List of lightGallery events * All events should be documented here * Below interfaces are used to build the website documentations * */ var lGEvents = { afterAppendSlide: 'lgAfterAppendSlide', init: 'lgInit', hasVideo: 'lgHasVideo', containerResize: 'lgContainerResize', updateSlides: 'lgUpdateSlides', afterAppendSubHtml: 'lgAfterAppendSubHtml', beforeOpen: 'lgBeforeOpen', afterOpen: 'lgAfterOpen', slideItemLoad: 'lgSlideItemLoad', beforeSlide: 'lgBeforeSlide', afterSlide: 'lgAfterSlide', posterClick: 'lgPosterClick', dragStart: 'lgDragStart', dragMove: 'lgDragMove', dragEnd: 'lgDragEnd', beforeNextSlide: 'lgBeforeNextSlide', beforePrevSlide: 'lgBeforePrevSlide', beforeClose: 'lgBeforeClose', afterClose: 'lgAfterClose', rotateLeft: 'lgRotateLeft', rotateRight: 'lgRotateRight', flipHorizontal: 'lgFlipHorizontal', flipVertical: 'lgFlipVertical', autoplay: 'lgAutoplay', autoplayStart: 'lgAutoplayStart', autoplayStop: 'lgAutoplayStop', }; var param = function (obj) { return Object.keys(obj) .map(function (k) { return encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]); }) .join('&'); }; var getVimeoURLParams = function (defaultParams, videoInfo) { if (!videoInfo || !videoInfo.vimeo) return ''; var urlParams = videoInfo.vimeo[2] || ''; var defaultPlayerParams = defaultParams && Object.keys(defaultParams).length !== 0 ? '&' + param(defaultParams) : ''; // Support private video var urlWithHash = videoInfo.vimeo[0].split('/').pop() || ''; var urlWithHashWithParams = urlWithHash.split('?')[0] || ''; var hash = urlWithHashWithParams.split('#')[0]; var isPrivate = videoInfo.vimeo[1] !== hash; if (isPrivate) { urlParams = urlParams.replace("/" + hash, ''); } urlParams = urlParams[0] == '?' ? '&' + urlParams.slice(1) : urlParams || ''; // For vimeo last params gets priority if duplicates found // Uncode edit ##START## var vimeoPlayerParams = '?autoplay=0'; if ( videoInfo.autoplay !== '' ) { vimeoPlayerParams = vimeoPlayerParams.replace(new RegExp('([?&])autoplay=(.*?)(&|$)'), '$1$3' ); vimeoPlayerParams = vimeoPlayerParams.replace(new RegExp('([?&])autoplay(&|$)'), '$1$2' ); } else { if ( typeof SiteParameters !== 'undefined' && typeof SiteParameters.vimeoPlayerParams !== 'undefined' && SiteParameters.vimeoPlayerParams !== '' ) { vimeoPlayerParams = SiteParameters.vimeoPlayerParams; } } if ( videoInfo.muted !== '' ) { vimeoPlayerParams += '&muted=' + (videoInfo.muted === 'yes'); } else { if ( urlParams.indexOf('muted=') < 0 && vimeoPlayerParams.indexOf('muted=') < 0 ) { vimeoPlayerParams += '&muted=1'; } } // var vimeoPlayerParams = "?autoplay=0&muted=1" + (isPrivate ? "&h=" + hash : '') + defaultPlayerParams + urlParams; vimeoPlayerParams += (isPrivate ? "&h=" + hash : '') + defaultPlayerParams + urlParams; // Uncode edit ##END## return vimeoPlayerParams; }; /** * Video module for lightGallery * Supports HTML5, YouTube, Vimeo, wistia videos * * * @ref Wistia * https://wistia.com/support/integrations/wordpress(How to get url) * https://wistia.com/support/developers/embed-options#using-embed-options * https://wistia.com/support/developers/player-api * https://wistia.com/support/developers/construct-an-embed-code * http://jsfiddle.net/xvnm7xLm/ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video * https://wistia.com/support/embed-and-share/sharing-videos * https://private-sharing.wistia.com/medias/mwhrulrucj * * @ref Youtube * https://developers.google.com/youtube/player_parameters#enablejsapi * https://developers.google.com/youtube/iframe_api_reference * https://developer.chrome.com/blog/autoplay/#iframe-delegation * * @ref Vimeo * https://stackoverflow.com/questions/10488943/easy-way-to-get-vimeo-id-from-a-vimeo-url * https://vimeo.zendesk.com/hc/en-us/articles/360000121668-Starting-playback-at-a-specific-timecode * https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Using-Player-Parameters */ var Video = /** @class */ (function () { function Video(instance) { // get lightGallery core plugin instance this.core = instance; this.settings = __assign(__assign({}, videoSettings), this.core.settings); return this; } Video.prototype.init = function () { var _this = this; /** * Event triggered when video url found without poster * Append video HTML * Play if autoplayFirstVideo is true */ this.core.LGel.on(lGEvents.hasVideo + ".video", this.onHasVideo.bind(this)); this.core.LGel.on(lGEvents.posterClick + ".video", function () { var $el = _this.core.getSlideItem(_this.core.index); _this.loadVideoOnPosterClick($el); }); this.core.LGel.on(lGEvents.slideItemLoad + ".video", this.onSlideItemLoad.bind(this)); // @desc fired immediately before each slide transition. this.core.LGel.on(lGEvents.beforeSlide + ".video", this.onBeforeSlide.bind(this)); // @desc fired immediately after each slide transition. this.core.LGel.on(lGEvents.afterSlide + ".video", this.onAfterSlide.bind(this)); }; /** * @desc Event triggered when a slide is completely loaded * * @param {Event} event - lightGalley custom event */ Video.prototype.onSlideItemLoad = function (event) { var _this = this; var _a = event.detail, isFirstSlide = _a.isFirstSlide, index = _a.index; // Should check the active slide as well as user may have moved to different slide before the first slide is loaded if (this.settings.autoplayFirstVideo && isFirstSlide && index === this.core.index) { // Delay is just for the transition effect on video load setTimeout(function () { _this.loadAndPlayVideo(index); }, 200); } // Should not call on first slide. should check only if the slide is active if (!isFirstSlide && this.settings.autoplayVideoOnSlide && index === this.core.index) { setTimeout(function () { _this.loadAndPlayVideo(index); }, 500); } }; /** * @desc Event triggered when video url or poster found * Append video HTML is poster is not given * Play if autoplayFirstVideo is true * * @param {Event} event - Javascript Event object. */ Video.prototype.onHasVideo = function (event) { var _a = event.detail, index = _a.index, src = _a.src, html5Video = _a.html5Video, hasPoster = _a.hasPoster; if (!hasPoster) { // All functions are called separately if poster exist in loadVideoOnPosterClick function this.appendVideos(this.core.getSlideItem(index), { src: src, addClass: 'lg-object', index: index, html5Video: html5Video, // Uncode edit ##START## autoplay: event.target.getAttribute('data-lb-autoplay'), muted: event.target.getAttribute('data-lb-muted'), // Uncode edit ##END## }); // Automatically navigate to next slide once video reaches the end. this.gotoNextSlideOnVideoEnd(src, index); } }; /** * @desc fired immediately before each slide transition. * Pause the previous video * Hide the download button if the slide contains YouTube, Vimeo, or Wistia videos. * * @param {Event} event - Javascript Event object. * @param {number} prevIndex - Previous index of the slide. * @param {number} index - Current index of the slide */ Video.prototype.onBeforeSlide = function (event) { if (this.core.lGalleryOn) { var prevIndex = event.detail.prevIndex; this.pauseVideo(prevIndex); } // Uncode edit ##START## var _a = event.detail, index = _a.index; var $slide = this.core.getSlideItem(index); var iframe = $slide.selector.querySelector('iframe'); if ( iframe != null ) { var data_play = iframe.getAttribute('data-autoplay'); if ( typeof data_play !== 'undefined' && data_play === '1' ) { this.loadAndPlayVideo(index); var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {}, $videoElement = this.core.getSlideItem(index).find('.lg-video-object').first(); if (videoInfo.vimeo) { var vimeoPlayer = new Vimeo.Player($videoElement.get()); vimeoPlayer.on('play', function () { vimeoPlayer.setCurrentTime(0); }); } else if ( videoInfo.youtube ) { try { $videoElement.get().contentWindow.postMessage("{\"event\":\"command\",\"func\":\"seekTo\",\"args\":[0, true]}", '*'); } catch (e) { console.warn(e); } } } } // Uncode edit ##END## }; /** * @desc fired immediately after each slide transition. * Play video if autoplayVideoOnSlide option is enabled. * * @param {Event} event - Javascript Event object. * @param {number} prevIndex - Previous index of the slide. * @param {number} index - Current index of the slide * @todo should check on onSlideLoad as well if video is not loaded on after slide */ Video.prototype.onAfterSlide = function (event) { var _this = this; var _a = event.detail, index = _a.index, prevIndex = _a.prevIndex; // Do not call on first slide var $slide = this.core.getSlideItem(index); if (this.settings.autoplayVideoOnSlide && index !== prevIndex) { if ($slide.hasClass('lg-complete')) { setTimeout(function () { _this.loadAndPlayVideo(index); }, 100); } } }; Video.prototype.loadAndPlayVideo = function (index) { var $slide = this.core.getSlideItem(index); var currentGalleryItem = this.core.galleryItems[index]; if (currentGalleryItem.poster) { this.loadVideoOnPosterClick($slide, true); } else { //Uncode edit ##START## // this.playVideo(index); var iframe = $slide.selector.querySelector('iframe'); if ( iframe != null ) { var data_play = iframe.getAttribute('data-autoplay'); if ( typeof data_play !== 'undefined' ) { if ( data_play === '1' && this.core.index == index ) { this.playVideo(index); } else { this.pauseVideo(index); } } } //Uncode edit ##END## } }; /** * Play HTML5, Youtube, Vimeo or Wistia videos in a particular slide. * @param {number} index - Index of the slide */ Video.prototype.playVideo = function (index) { this.controlVideo(index, 'play'); }; /** * Pause HTML5, Youtube, Vimeo or Wistia videos in a particular slide. * @param {number} index - Index of the slide */ Video.prototype.pauseVideo = function (index) { this.controlVideo(index, 'pause'); }; // Uncode edit ##START## //Video.prototype.getVideoHtml = function (src, addClass, index, html5Video) { Video.prototype.getVideoHtml = function (src, addClass, index, html5Video, autoplay, muted) { // Uncode edit ##END## var video = ''; var videoInfo = this.core.galleryItems[index] .__slideVideoInfo || {}; var currentGalleryItem = this.core.galleryItems[index]; var videoTitle = currentGalleryItem.title || currentGalleryItem.alt; videoTitle = videoTitle ? 'title="' + videoTitle + '"' : ''; var commonIframeProps = "allowtransparency=\"true\"\n frameborder=\"0\"\n scrolling=\"no\"\n allowfullscreen\n mozallowfullscreen\n webkitallowfullscreen\n oallowfullscreen\n msallowfullscreen"; if (videoInfo.youtube) { var videoId = 'lg-youtube' + index; var slideUrlParams = videoInfo.youtube[2] ? videoInfo.youtube[2] + '&' : ''; // For youtube first parms gets priority if duplicates found // Uncode edit ##START## // var youTubePlayerParams = "?" + slideUrlParams + "wmode=opaque&autoplay=0&mute=1&enablejsapi=1"; var youTubePlayerParams = "?" + slideUrlParams + "wmode=opaque&enablejsapi=1"; if ( ( slideUrlParams.indexOf('autoplay=') < 0 && youTubePlayerParams.indexOf('autoplay=') < 0 ) ) { youTubePlayerParams += '&autoplay=0'; } if ( slideUrlParams.indexOf('mute=') < 0 && youTubePlayerParams.indexOf('mute=') < 0 ) { youTubePlayerParams += '&mute=1'; } var data_video = ''; if ( autoplay !== '' ) { //youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])autoplay=(.*?)(&|$)'), '$1autoplay=' + (autoplay === 'yes' ? 1 : 0) + '$3' ); youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])autoplay=(.*?)(&|$)'), '$1$3' ); youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])autoplay'), '$1' ); data_video = ' data-autoplay="' + (autoplay === 'yes' ? 1 : 0) + '"'; } // if ( muted !== '' ) { // youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])mute=(.*?)(&|$)'), '$1mute=' + (muted === 'yes' ? 1 : 0) + '$3' ); // } youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])mute=(.*?)(&|$)'), '$1$3' ); youTubePlayerParams = youTubePlayerParams.replace('??', '?'); // Uncode edit ##END## var playerParams = youTubePlayerParams + (this.settings.youTubePlayerParams ? '&' + param(this.settings.youTubePlayerParams) : ''); // Uncode edit ##START## // video = ""; var nocookie = typeof SiteParameters.uncode_nocookie !== 'undefined' ? SiteParameters.uncode_nocookie : ''; video = ""; var tag = document.createElement('script'); tag.src = "//www.youtube.com/player_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); // Replace the 'ytplayer' element with an "; var data_video = ''; if ( autoplay !== '' ) { data_video = ' data-autoplay="' + (autoplay === 'yes' ? 1 : 0) + '"'; } video = ""; // Uncode edit ##END## } else if (videoInfo.wistia) { var wistiaId = 'lg-wistia' + index; var playerParams = param(this.settings.wistiaPlayerParams); playerParams = playerParams ? '?' + playerParams : ''; video = ""; } else if (videoInfo.html5) { var html5VideoMarkup = ''; for (var i = 0; i < html5Video.source.length; i++) { html5VideoMarkup += ""; } if (html5Video.tracks) { var _loop_1 = function (i) { var trackAttributes = ''; var track = html5Video.tracks[i]; Object.keys(track || {}).forEach(function (key) { trackAttributes += key + "=\"" + track[key] + "\" "; }); html5VideoMarkup += ""; }; for (var i = 0; i < html5Video.tracks.length; i++) { _loop_1(i); } } var html5VideoAttrs_1 = ''; var videoAttributes_1 = html5Video.attributes || {}; Object.keys(videoAttributes_1 || {}).forEach(function (key) { html5VideoAttrs_1 += key + "=\"" + videoAttributes_1[key] + "\" "; }); video = ""; } return video; }; /** * @desc - Append videos to the slide * * @param {HTMLElement} el - slide element * @param {Object} videoParams - Video parameters, Contains src, class, index, htmlVideo */ Video.prototype.appendVideos = function (el, videoParams) { var _a; // Uncode edit ##START## // var videoHtml = this.getVideoHtml(videoParams.src, videoParams.addClass, videoParams.index, videoParams.html5Video); var videoHtml = this.getVideoHtml(videoParams.src, videoParams.addClass, videoParams.index, videoParams.html5Video, videoParams.autoplay, videoParams.muted); // Uncode edit ##END## el.find('.lg-video-cont').append(videoHtml); var $videoElement = el.find('.lg-video-object').first(); if (videoParams.html5Video) { $videoElement.on('mousedown.lg.video', function (e) { e.stopPropagation(); }); } if (this.settings.videojs && ((_a = this.core.galleryItems[videoParams.index].__slideVideoInfo) === null || _a === void 0 ? void 0 : _a.html5)) { try { return videojs($videoElement.get(), this.settings.videojsOptions); } catch (e) { console.warn('lightGallery:- Make sure you have included videojs'); } } }; Video.prototype.gotoNextSlideOnVideoEnd = function (src, index) { var _this = this; var $videoElement = this.core .getSlideItem(index) .find('.lg-video-object') .first(); var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {}; if (this.settings.gotoNextSlideOnVideoEnd) { if (videoInfo.html5) { $videoElement.on('ended', function () { _this.core.goToNextSlide(); }); } else if (videoInfo.vimeo) { try { // https://github.com/vimeo/player.js/#ended new Vimeo.Player($videoElement.get()).on('ended', function () { _this.core.goToNextSlide(); }); } catch (e) { console.warn('lightGallery:- Make sure you have included //github.com/vimeo/player.js'); } } else if (videoInfo.wistia) { try { window._wq = window._wq || []; // @todo Event is gettign triggered multiple times window._wq.push({ id: $videoElement.attr('id'), onReady: function (video) { video.bind('end', function () { _this.core.goToNextSlide(); }); }, }); } catch (e) { console.warn('lightGallery:- Make sure you have included //fast.wistia.com/assets/external/E-v1.js'); } } } }; Video.prototype.controlVideo = function (index, action) { var $videoElement = this.core .getSlideItem(index) .find('.lg-video-object') .first(); var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {}; if (!$videoElement.get()) return; if (videoInfo.youtube) { try { $videoElement.get().contentWindow.postMessage("{\"event\":\"command\",\"func\":\"" + action + "Video\",\"args\":\"\"}", '*'); } catch (e) { console.warn("lightGallery:- " + e); } } else if (videoInfo.vimeo) { try { new Vimeo.Player($videoElement.get())[action](); } catch (e) { console.warn('lightGallery:- Make sure you have included //github.com/vimeo/player.js'); } } else if (videoInfo.html5) { if (this.settings.videojs) { try { videojs($videoElement.get())[action](); } catch (e) { console.warn('lightGallery:- Make sure you have included videojs'); } } else { $videoElement.get()[action](); } } else if (videoInfo.wistia) { try { window._wq = window._wq || []; // @todo Find a way to destroy wistia player instance window._wq.push({ id: $videoElement.attr('id'), onReady: function (video) { video[action](); }, }); } catch (e) { console.warn('lightGallery:- Make sure you have included //fast.wistia.com/assets/external/E-v1.js'); } } }; Video.prototype.loadVideoOnPosterClick = function ($el, forcePlay) { var _this = this; // check slide has poster if (!$el.hasClass('lg-video-loaded')) { // check already video element present if (!$el.hasClass('lg-has-video')) { $el.addClass('lg-has-video'); var _html = void 0; var _src = this.core.galleryItems[this.core.index].src; var video = this.core.galleryItems[this.core.index].video; if (video) { _html = typeof video === 'string' ? JSON.parse(video) : video; } var videoJsPlayer_1 = this.appendVideos($el, { src: _src, addClass: '', index: this.core.index, html5Video: _html, }); this.gotoNextSlideOnVideoEnd(_src, this.core.index); var $tempImg = $el.find('.lg-object').first().get(); // @todo make sure it is working $el.find('.lg-video-cont').first().append($tempImg); $el.addClass('lg-video-loading'); videoJsPlayer_1 && videoJsPlayer_1.ready(function () { videoJsPlayer_1.on('loadedmetadata', function () { _this.onVideoLoadAfterPosterClick($el, _this.core.index); }); }); $el.find('.lg-video-object') .first() .on('load.lg error.lg loadedmetadata.lg', function () { setTimeout(function () { _this.onVideoLoadAfterPosterClick($el, _this.core.index); }, 50); }); } else { this.playVideo(this.core.index); } } else if (forcePlay) { this.playVideo(this.core.index); } }; Video.prototype.onVideoLoadAfterPosterClick = function ($el, index) { $el.addClass('lg-video-loaded'); this.playVideo(index); }; Video.prototype.destroy = function () { this.core.LGel.off('.lg.video'); this.core.LGel.off('.video'); }; return Video; }()); return Video; }))); /*! @vimeo/player v2.17.1 | (c) 2022 Vimeo | MIT License | https://github.com/vimeo/player.js */ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):((e="undefined"!=typeof globalThis?globalThis:e||self).Vimeo=e.Vimeo||{},e.Vimeo.Player=t())}(this,function(){"use strict";function r(e,t){for(var n=0;n 1 || cache.items.merge; widths[iterator] = !grid ? this._items[iterator].width() : width * merge; } this._widths = widths; } }, { filter: [ 'items', 'settings' ], run: function() { var clones = [], items = this._items, settings = this.settings, view = Math.max(settings.items * 2, 4), size = Math.ceil(items.length / 2) * 2, repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, append = '', prepend = ''; repeat /= 2; while (repeat--) { clones.push(this.normalize(clones.length / 2, true)); append = append + items[clones[clones.length - 1]][0].outerHTML; clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true)); prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; } this._clones = clones; // var appendVideo = $(append).find('.uncode-video-container'); // if (appendVideo.length) { // appendVideo.attr('data-id', Math.round(Math.random() * 100000)); // } // var prependVideo = $(prepend).find('.uncode-video-container'); // if (prependVideo.length) { // prependVideo.attr('data-id', Math.round(Math.random() * 100000)); // } $(append).addClass('cloned').appendTo(this.$stage); $(prepend).addClass('cloned').prependTo(this.$stage); } }, { filter: [ 'width', 'items', 'settings' ], run: function() { var rtl = this.settings.rtl ? 1 : -1, size = this._clones.length + this._items.length, iterator = -1, previous = 0, current = 0, coordinates = []; while (++iterator < size) { previous = coordinates[iterator - 1] || 0; current = this._widths[this.relative(iterator)] + this.settings.margin; coordinates.push(previous + current * rtl); } this._coordinates = coordinates; } }, { filter: [ 'width', 'items', 'settings' ], run: function() { var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, padding = stagePadding, coordinates = this._coordinates, css = { 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, 'padding-left': padding || '', 'padding-right': padding || '' }; this.$stage.css(css); } }, { filter: [ 'width', 'items', 'settings' ], run: function(cache) { var iterator = this._coordinates.length, grid = !this.settings.autoWidth, items = this.$stage.children(); if (grid && cache.items.merge) { while (iterator--) { cache.css.width = this._widths[this.relative(iterator)]; items.eq(iterator).css(cache.css); } } else if (grid) { cache.css.width = cache.items.width; items.css(cache.css); } } }, { filter: [ 'items' ], run: function() { this._coordinates.length < 1 && this.$stage.removeAttr('style'); } }, { filter: [ 'width', 'items', 'settings' ], run: function(cache) { cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current)); this.reset(cache.current); } }, { filter: [ 'position' ], run: function() { this.animate(this.coordinates(this._current)); } }, { filter: [ 'width', 'position', 'items', 'settings' ], run: function() { var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200, rtl = this.settings.rtl ? 1 : -1, padding = this.settings.stagePadding * 2, begin = this.coordinates(this.current()) + padding, end = begin + this.width() * rtl, inner, outer, matches = [], i, n; for (i = 0, n = this._coordinates.length; i < n; i++) { inner = this._coordinates[i - 1] || 0; outer = Math.abs(this._coordinates[i]) + padding * rtl; if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { matches.push(i); } } this.$stage.children('.active').removeClass('active'); this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active'); if (this.settings.center) { this.$stage.children('.center').removeClass('center'); this.$stage.children().eq(this.current()).addClass('center'); } } } ]; /** * Initializes the carousel. * @protected */ Owl.prototype.initialize = function() { this.enter('initializing'); this.trigger('initialize'); this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); if (this.settings.autoWidth && !this.is('pre-loading')) { var imgs, nestedSelector, width; imgs = this.$element.find('img'); nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; width = this.$element.children(nestedSelector).width(); if (imgs.length && width <= 0) { this.preloadAutoWidthImages(imgs); } } this.$element.addClass(this.options.loadingClass); // create stage this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>') .wrap('
    '); // append stage this.$element.append(this.$stage.parent()); // append content this.replace(this.$element.children().not(this.$stage.parent())); // check visibility if (this.$element.is(':visible')) { // update view this.refresh(); } else { // invalidate width this.invalidate('width'); } this.$element .removeClass(this.options.loadingClass) .addClass(this.options.loadedClass); // register event handlers this.registerEventHandlers(); this.leave('initializing'); this.trigger('initialized'); }; /** * Setups the current settings. * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? * @todo Support for media queries by using `matchMedia` would be nice. * @public */ Owl.prototype.setup = function() { var viewport = this.viewport(), overwrites = this.options.responsive, match = -1, settings = null; if (!overwrites) { settings = $.extend({}, this.options); } else { $.each(overwrites, function(breakpoint) { if (breakpoint <= viewport && breakpoint > match) { match = Number(breakpoint); } }); settings = $.extend({}, this.options, overwrites[match]); delete settings.responsive; // responsive class if (settings.responsiveClass) { this.$element.attr('class', this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match) ); } } if (this.settings === null || this._breakpoint !== match) { this.trigger('change', { property: { name: 'settings', value: settings } }); this._breakpoint = match; this.settings = settings; this.invalidate('settings'); this.trigger('changed', { property: { name: 'settings', value: this.settings } }); } }; /** * Updates option logic if necessery. * @protected */ Owl.prototype.optionsLogic = function() { if (this.settings.autoWidth) { this.settings.stagePadding = false; this.settings.merge = false; } }; /** * Prepares an item before add. * @todo Rename event parameter `content` to `item`. * @protected * @returns {jQuery|HTMLElement} - The item container. */ Owl.prototype.prepare = function(item, index) { var event = this.trigger('prepare', { content: item }); if (!event.data) { event.data = $('<' + this.settings.itemElement + '/>') .addClass(this.options.itemClass).attr('data-index', index + 1).append(item) } this.trigger('prepared', { content: event.data }); return event.data; }; /** * Updates the view. * @public */ Owl.prototype.update = function() { var i = 0, n = this._pipe.length, filter = $.proxy(function(p) { return this[p] }, this._invalidated), cache = {}; while (i < n) { if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { this._pipe[i].run(cache); } i++; } this._invalidated = {}; !this.is('valid') && this.enter('valid'); }; /** * Gets the width of the view. * @public * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. * @returns {Number} - The width of the view in pixel. */ Owl.prototype.width = function(dimension) { dimension = dimension || Owl.Width.Default; var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200; switch (dimension) { case Owl.Width.Inner: case Owl.Width.Outer: return this._width; default: return this._width - stagePadding * 2 + this.settings.margin; } }; /** * Refreshes the carousel primarily for adaptive purposes. * @public */ Owl.prototype.refresh = function() { this.enter('refreshing'); this.trigger('refresh'); this.setup(); this.optionsLogic(); this.$element.addClass(this.options.refreshClass); this.update(); this.$element.removeClass(this.options.refreshClass); this.leave('refreshing'); this.trigger('refreshed'); }; /** * Checks window `resize` event. * @protected */ Owl.prototype.onThrottledResize = function() { window.clearTimeout(this.resizeTimer); this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate); }; /** * Checks window `resize` event. * @protected */ Owl.prototype.onResize = function() { if (!this._items.length) { return false; } if (this._width === this.$element.width()) { return false; } if (!this.$element.is(':visible')) { return false; } this.enter('resizing'); if (this.trigger('resize').isDefaultPrevented()) { this.leave('resizing'); return false; } this.invalidate('width'); this.refresh(); this.leave('resizing'); this.trigger('resized'); }; /** * Registers event handlers. * @todo Check `msPointerEnabled` * @todo #261 * @protected */ Owl.prototype.registerEventHandlers = function() { if ($.support.transition) { this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this)); } if (this.settings.responsive !== false) { this.on(window, 'resize', this._handlers.onThrottledResize); } if (this.settings.mouseDrag) { this.$element.addClass(this.options.dragClass); this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this)); this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false }); } if (this.settings.touchDrag){ this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this)); this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this)); } }; /** * Handles `touchstart` and `mousedown` events. * @todo Horizontal swipe threshold as option * @todo #261 * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onDragStart = function(event) { var stage = null; if (event.which === 3) { return; } if ($.support.transform) { stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(','); stage = { x: stage[stage.length === 16 ? 12 : 4], y: stage[stage.length === 16 ? 13 : 5] }; } else { stage = this.$stage.position(); stage = { x: this.settings.rtl ? stage.left + this.$stage.width() - this.width() + this.settings.margin : stage.left, y: stage.top }; } if (this.is('animating')) { $.support.transform ? this.animate(stage.x) : this.$stage.stop() this.invalidate('position'); } this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown'); this.speed(0); this._drag.time = new Date().getTime(); this._drag.target = $(event.target); this._drag.stage.start = stage; this._drag.stage.current = stage; this._drag.pointer = this.pointer(event); $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this)); $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) { var delta = this.difference(this._drag.pointer, this.pointer(event)); $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this)); if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) { return; } event.preventDefault(); this.enter('dragging'); this.trigger('drag'); }, this)); }; /** * Handles the `touchmove` and `mousemove` events. * @todo #261 * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onDragMove = function(event) { var minimum = null, maximum = null, pull = null, delta = this.difference(this._drag.pointer, this.pointer(event)), stage = this.difference(this._drag.stage.start, delta); if (!this.is('dragging')) { return; } event.preventDefault(); if (this.settings.loop) { minimum = this.coordinates(this.minimum()); maximum = this.coordinates(this.maximum() + 1) - minimum; stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum; } else { minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0; stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); } this._drag.stage.current = stage; this.animate(stage.x); }; /** * Handles the `touchend` and `mouseup` events. * @todo #261 * @todo Threshold for click event * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onDragEnd = function(event) { var delta = this.difference(this._drag.pointer, this.pointer(event)), stage = this._drag.stage.current, direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right'; $(document).off('.owl.core'); this.$element.removeClass(this.options.grabClass); if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) { this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction)); this.invalidate('position'); this.update(); this._drag.direction = direction; if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) { this._drag.target.one('click.owl.core', function() { return false; }); } } if (!this.is('dragging')) { return; } this.leave('dragging'); this.trigger('dragged'); }; /** * Gets absolute position of the closest item for a coordinate. * @todo Setting `freeDrag` makes `closest` not reusable. See #165. * @protected * @param {Number} coordinate - The coordinate in pixel. * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. * @return {Number} - The absolute position of the closest item. */ Owl.prototype.closest = function(coordinate, direction) { var position = -1, pull = 30, width = this.width(), coordinates = this.coordinates(); if (!this.settings.freeDrag) { // check closest item $.each(coordinates, $.proxy(function(index, value) { if (coordinate > value - pull && coordinate < value + pull) { position = index; } else if (this.op(coordinate, '<', value) && this.op(coordinate, '>', coordinates[index + 1] || value - width)) { position = direction === 'left' ? index + 1 : index; } return position === -1; }, this)); } if (!this.settings.loop) { // non loop boundries if (this.op(coordinate, '>', coordinates[this.minimum()])) { position = coordinate = this.minimum(); } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { position = coordinate = this.maximum(); } } return position; }; /** * Animates the stage. * @todo #270 * @public * @param {Number} coordinate - The coordinate in pixels. */ Owl.prototype.animate = function(coordinate) { var animate = this.speed() > 0; this.is('animating') && this.onTransitionEnd(); if (animate) { this.enter('animating'); this.trigger('translate'); } if ($.support.transform3d && $.support.transition) { this.$stage.css({ transform: 'translate3d(' + coordinate + 'px,0px,0px)', transition: (this.speed() / 1000) + 's' }); } else if (animate) { this.$stage.animate({ left: coordinate + 'px' }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this)); } else { this.$stage.css({ left: coordinate + 'px' }); } }; /** * Checks whether the carousel is in a specific state or not. * @param {String} state - The state to check. * @returns {Boolean} - The flag which indicates if the carousel is busy. */ Owl.prototype.is = function(state) { return this._states.current[state] && this._states.current[state] > 0; }; /** * Sets the absolute position of the current item. * @public * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. * @returns {Number} - The absolute position of the current item. */ Owl.prototype.current = function(position) { if (position === undefined) { return this._current; } if (this._items.length === 0) { return undefined; } position = this.normalize(position); if (this._current !== position) { var event = this.trigger('change', { property: { name: 'position', value: position } }); if (event.data !== undefined) { position = this.normalize(event.data); } this._current = position; this.invalidate('position'); this.trigger('changed', { property: { name: 'position', value: this._current } }); } return this._current; }; /** * Invalidates the given part of the update routine. * @param {String} [part] - The part to invalidate. * @returns {Array.} - The invalidated parts. */ Owl.prototype.invalidate = function(part) { if ($.type(part) === 'string') { this._invalidated[part] = true; this.is('valid') && this.leave('valid'); } return $.map(this._invalidated, function(v, i) { return i }); }; /** * Resets the absolute position of the current item. * @public * @param {Number} position - The absolute position of the new item. */ Owl.prototype.reset = function(position) { position = this.normalize(position); if (position === undefined) { return; } this._speed = 0; this._current = position; this.suppress([ 'translate', 'translated' ]); this.animate(this.coordinates(position)); this.release([ 'translate', 'translated' ]); }; /** * Normalizes an absolute or a relative position of an item. * @public * @param {Number} position - The absolute or relative position to normalize. * @param {Boolean} [relative=false] - Whether the given position is relative or not. * @returns {Number} - The normalized position. */ Owl.prototype.normalize = function(position, relative) { var n = this._items.length, m = relative ? 0 : this._clones.length; if (!$.isNumeric(position) || n < 1) { position = undefined; } else if (position < 0 || position >= n + m) { position = ((position - m / 2) % n + n) % n + m / 2; } return position; }; /** * Converts an absolute position of an item into a relative one. * @public * @param {Number} position - The absolute position to convert. * @returns {Number} - The converted position. */ Owl.prototype.relative = function(position) { position -= this._clones.length / 2; return this.normalize(position, true); }; /** * Gets the maximum position for the current item. * @public * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. * @returns {Number} */ Owl.prototype.maximum = function(relative) { var settings = this.settings, maximum = this._coordinates.length, boundary = Math.abs(this._coordinates[maximum - 1]) - this._width, i = -1, j; if (settings.loop) { maximum = this._clones.length / 2 + this._items.length - 1; } else if (settings.autoWidth || settings.merge) { // binary search while (maximum - i > 1) { Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary ? i = j : maximum = j; } } else if (settings.center) { maximum = this._items.length - 1; } else { maximum = this._items.length - settings.items; } if (relative) { maximum -= this._clones.length / 2; } return Math.max(maximum, 0); }; /** * Gets the minimum position for the current item. * @public * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. * @returns {Number} */ Owl.prototype.minimum = function(relative) { return relative ? 0 : this._clones.length / 2; }; /** * Gets an item at the specified relative position. * @public * @param {Number} [position] - The relative position of the item. * @return {jQuery|Array.} - The item at the given position or all items if no position was given. */ Owl.prototype.items = function(position) { if (position === undefined) { return this._items.slice(); } position = this.normalize(position, true); return this._items[position]; }; /** * Gets an item at the specified relative position. * @public * @param {Number} [position] - The relative position of the item. * @return {jQuery|Array.} - The item at the given position or all items if no position was given. */ Owl.prototype.mergers = function(position) { if (position === undefined) { return this._mergers.slice(); } position = this.normalize(position, true); return this._mergers[position]; }; /** * Gets the absolute positions of clones for an item. * @public * @param {Number} [position] - The relative position of the item. * @returns {Array.} - The absolute positions of clones for the item or all if no position was given. */ Owl.prototype.clones = function(position) { var odd = this._clones.length / 2, even = odd + this._items.length, map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 }; if (position === undefined) { return $.map(this._clones, function(v, i) { return map(i) }); } return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); }; /** * Sets the current animation speed. * @public * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. * @returns {Number} - The current animation speed in milliseconds. */ Owl.prototype.speed = function(speed) { if (speed !== undefined) { this._speed = speed; } return this._speed; }; /** * Gets the coordinate of an item. * @todo The name of this method is missleanding. * @public * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. * @returns {Number|Array.} - The coordinate of the item in pixel or all coordinates. */ Owl.prototype.coordinates = function(position) { var coordinate = null; if (position === undefined) { return $.map(this._coordinates, $.proxy(function(coordinate, index) { return this.coordinates(index); }, this)); } if (this.settings.center) { coordinate = this._coordinates[position]; coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1); } else { coordinate = this._coordinates[position - 1] || 0; } return coordinate; }; /** * Calculates the speed for a translation. * @protected * @param {Number} from - The absolute position of the start item. * @param {Number} to - The absolute position of the target item. * @param {Number} [factor=undefined] - The time factor in milliseconds. * @returns {Number} - The time in milliseconds for the translation. */ Owl.prototype.duration = function(from, to, factor) { return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); }; /** * Slides to the specified item. * @public * @param {Number} position - The position of the item. * @param {Number} [speed] - The time in milliseconds for the transition. */ Owl.prototype.to = function(position, speed) { var current = this.current(), revert = null, distance = position - this.relative(current), direction = (distance > 0) - (distance < 0), items = this._items.length, minimum = this.minimum(), maximum = this.maximum(); if (this.settings.loop) { if (!this.settings.rewind && Math.abs(distance) > items / 2) { distance += direction * -1 * items; } position = current + distance; revert = ((position - minimum) % items + items) % items + minimum; if (revert !== position && revert - distance <= maximum && revert - distance > 0) { current = revert - distance; position = revert; this.reset(current); } } else if (this.settings.rewind) { maximum += 1; position = (position % maximum + maximum) % maximum; } else { position = Math.max(minimum, Math.min(maximum, position)); } this.speed(this.duration(current, position, speed)); this.current(position); if (this.$element.is(':visible')) { this.update(); } }; /** * Slides to the next item. * @public * @param {Number} [speed] - The time in milliseconds for the transition. */ Owl.prototype.next = function(speed) { speed = speed || false; this.to(this.relative(this.current()) + 1, speed); }; /** * Slides to the previous item. * @public * @param {Number} [speed] - The time in milliseconds for the transition. */ Owl.prototype.prev = function(speed) { speed = speed || false; this.to(this.relative(this.current()) - 1, speed); }; /** * Handles the end of an animation. * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onTransitionEnd = function(event) { // if css2 animation then event object is undefined if (event !== undefined) { event.stopPropagation(); // Catch only owl-stage transitionEnd event if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { return false; } } this.leave('animating'); this.trigger('translated'); }; /** * Gets viewport width. * @protected * @return {Number} - The width in pixel. */ Owl.prototype.viewport = function() { var width; if (this.options.responsiveBaseElement !== window) { width = $(this.options.responsiveBaseElement).width(); } else if (window.innerWidth) { width = window.innerWidth; } else if (document.documentElement && document.documentElement.clientWidth) { width = document.documentElement.clientWidth; } else { throw 'Can not detect viewport width.'; } return width; }; /** * Replaces the current content. * @public * @param {HTMLElement|jQuery|String} content - The new content. */ Owl.prototype.replace = function(content) { this.$stage.empty(); this._items = []; if (content) { content = (content instanceof jQuery) ? content : $(content); } if (this.settings.nestedItemSelector) { content = content.find('.' + this.settings.nestedItemSelector); } content.filter(function() { return this.nodeType === 1; }).each($.proxy(function(index, item) { item = this.prepare(item, index); this.$stage.append(item); this._items.push(item); this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); }, this)); this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); this.invalidate('items'); }; /** * Adds an item. * @todo Use `item` instead of `content` for the event arguments. * @public * @param {HTMLElement|jQuery|String} content - The item content to add. * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. */ Owl.prototype.add = function(content, position) { var current = this.relative(this._current); position = position === undefined ? this._items.length : this.normalize(position, true); content = content instanceof jQuery ? content : $(content); this.trigger('add', { content: content, position: position }); content = this.prepare(content, this._items[current].index()); if (this._items.length === 0 || position === this._items.length) { this._items.length === 0 && this.$stage.append(content); this._items.length !== 0 && this._items[position - 1].after(content); this._items.push(content); this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); } else { this._items[position].before(content); this._items.splice(position, 0, content); this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); } this._items[current] && this.reset(this._items[current].index()); this.invalidate('items'); this.trigger('added', { content: content, position: position }); }; /** * Removes an item by its position. * @todo Use `item` instead of `content` for the event arguments. * @public * @param {Number} position - The relative position of the item to remove. */ Owl.prototype.remove = function(position) { position = this.normalize(position, true); if (position === undefined) { return; } this.trigger('remove', { content: this._items[position], position: position }); this._items[position].remove(); this._items.splice(position, 1); this._mergers.splice(position, 1); this.invalidate('items'); this.trigger('removed', { content: null, position: position }); }; /** * Preloads images with auto width. * @todo Replace by a more generic approach * @protected */ Owl.prototype.preloadAutoWidthImages = function(images) { images.each($.proxy(function(i, element) { this.enter('pre-loading'); element = $(element); $(new Image()).one('load', $.proxy(function(e) { element.attr('src', e.target.src); element.css('opacity', 1); this.leave('pre-loading'); !this.is('pre-loading') && !this.is('initializing') && this.refresh(); }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina')); }, this)); }; /** * Destroys the carousel. * @public */ Owl.prototype.destroy = function() { this.$element.off('.owl.core'); this.$stage.off('.owl.core'); $(document).off('.owl.core'); if (this.settings.responsive !== false) { window.clearTimeout(this.resizeTimer); this.off(window, 'resize', this._handlers.onThrottledResize); } for (var i in this._plugins) { this._plugins[i].destroy(); } this.$stage.children('.cloned').remove(); this.$stage.unwrap(); this.$stage.children().contents().unwrap(); this.$stage.children().unwrap(); this.$element .removeClass(this.options.refreshClass) .removeClass(this.options.loadingClass) .removeClass(this.options.loadedClass) .removeClass(this.options.rtlClass) .removeClass(this.options.dragClass) .removeClass(this.options.grabClass) .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), '')) .removeData('owl.carousel'); }; /** * Operators to calculate right-to-left and left-to-right. * @protected * @param {Number} [a] - The left side operand. * @param {String} [o] - The operator. * @param {Number} [b] - The right side operand. */ Owl.prototype.op = function(a, o, b) { var rtl = this.settings.rtl; switch (o) { case '<': return rtl ? a > b : a < b; case '>': return rtl ? a < b : a > b; case '>=': return rtl ? a <= b : a >= b; case '<=': return rtl ? a >= b : a <= b; default: break; } }; /** * Attaches to an internal event. * @protected * @param {HTMLElement} element - The event source. * @param {String} event - The event name. * @param {Function} listener - The event handler to attach. * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. */ Owl.prototype.on = function(element, event, listener, capture) { if (element.addEventListener) { element.addEventListener(event, listener, capture); } else if (element.attachEvent) { element.attachEvent('on' + event, listener); } }; /** * Detaches from an internal event. * @protected * @param {HTMLElement} element - The event source. * @param {String} event - The event name. * @param {Function} listener - The attached event handler to detach. * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. */ Owl.prototype.off = function(element, event, listener, capture) { if (element.removeEventListener) { element.removeEventListener(event, listener, capture); } else if (element.detachEvent) { element.detachEvent('on' + event, listener); } }; /** * Triggers a public event. * @todo Remove `status`, `relatedTarget` should be used instead. * @protected * @param {String} name - The event name. * @param {*} [data=null] - The event data. * @param {String} [namespace=carousel] - The event namespace. * @param {String} [state] - The state which is associated with the event. * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. * @returns {Event} - The event arguments. */ Owl.prototype.trigger = function(name, data, namespace, state, enter) { var status = { item: { count: this._items.length, index: this.current() } }, handler = $.camelCase( $.grep([ 'on', name, namespace ], function(v) { return v }) .join('-').toLowerCase() ), event = $.Event( [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), $.extend({ relatedTarget: this }, status, data) ); if (!this._supress[name]) { $.each(this._plugins, function(name, plugin) { if (plugin.onTrigger) { plugin.onTrigger(event); } }); this.register({ type: Owl.Type.Event, name: name }); this.$element.trigger(event); if (this.settings && typeof this.settings[handler] === 'function') { this.settings[handler].call(this, event); } } return event; }; /** * Enters a state. * @param name - The state name. */ Owl.prototype.enter = function(name) { $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { if (this._states.current[name] === undefined) { this._states.current[name] = 0; } this._states.current[name]++; }, this)); }; /** * Leaves a state. * @param name - The state name. */ Owl.prototype.leave = function(name) { $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { this._states.current[name]--; }, this)); }; /** * Registers an event or state. * @public * @param {Object} object - The event or state to register. */ Owl.prototype.register = function(object) { if (object.type === Owl.Type.Event) { if (!$.event.special[object.name]) { $.event.special[object.name] = {}; } if (!$.event.special[object.name].owl) { var _default = $.event.special[object.name]._default; $.event.special[object.name]._default = function(e) { if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) { return _default.apply(this, arguments); } return e.namespace && e.namespace.indexOf('owl') > -1; }; $.event.special[object.name].owl = true; } } else if (object.type === Owl.Type.State) { if (!this._states.tags[object.name]) { this._states.tags[object.name] = object.tags; } else { this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags); } this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) { return $.inArray(tag, this._states.tags[object.name]) === i; }, this)); } }; /** * Suppresses events. * @protected * @param {Array.} events - The events to suppress. */ Owl.prototype.suppress = function(events) { $.each(events, $.proxy(function(index, event) { this._supress[event] = true; }, this)); }; /** * Releases suppressed events. * @protected * @param {Array.} events - The events to release. */ Owl.prototype.release = function(events) { $.each(events, $.proxy(function(index, event) { delete this._supress[event]; }, this)); }; /** * Gets unified pointer coordinates from event. * @todo #261 * @protected * @param {Event} - The `mousedown` or `touchstart` event. * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. */ Owl.prototype.pointer = function(event) { var result = { x: null, y: null }; event = event.originalEvent || event || window.event; event = event.touches && event.touches.length ? event.touches[0] : event.changedTouches && event.changedTouches.length ? event.changedTouches[0] : event; if (event.pageX) { result.x = event.pageX; result.y = event.pageY; } else { result.x = event.clientX; result.y = event.clientY; } return result; }; /** * Gets the difference of two vectors. * @todo #261 * @protected * @param {Object} - The first vector. * @param {Object} - The second vector. * @returns {Object} - The difference. */ Owl.prototype.difference = function(first, second) { return { x: first.x - second.x, y: first.y - second.y }; }; /** * The jQuery Plugin for the Owl Carousel * @todo Navigation plugin `next` and `prev` * @public */ $.fn.owlCarousel = function(option) { var args = Array.prototype.slice.call(arguments, 1); return this.each(function() { var $this = $(this), data = $this.data('owl.carousel'); if (!data) { data = new Owl(this, typeof option == 'object' && option); $this.data('owl.carousel', data); $.each([ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' ], function(i, event) { data.register({ type: Owl.Type.Event, name: event }); data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) { if (e.namespace && e.relatedTarget !== this) { this.suppress([ event ]); data[event].apply(this, [].slice.call(arguments, 1)); this.release([ event ]); } }, data)); }); } if (typeof option == 'string' && option.charAt(0) !== '_') { data[option].apply(data, args); } }); }; /** * The constructor for the jQuery Plugin * @public */ $.fn.owlCarousel.Constructor = Owl; })(window.Zepto || window.jQuery, window, document); /** * AutoRefresh Plugin * @version 2.0.0-beta.3 * @author Artus Kolanowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { /** * Creates the auto refresh plugin. * @class The Auto Refresh Plugin * @param {Owl} carousel - The Owl Carousel */ var AutoRefresh = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Refresh interval. * @protected * @type {number} */ this._interval = null; /** * Whether the element is currently visible or not. * @protected * @type {Boolean} */ this._visible = null; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { 'initialized.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.autoRefresh) { this.watch(); } }, this) }; // set default options this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); // register event handlers this._core.$element.on(this._handlers); }; /** * Default options. * @public */ AutoRefresh.Defaults = { autoRefresh: true, autoRefreshInterval: 500 }; /** * Watches the element. */ AutoRefresh.prototype.watch = function() { if (this._interval) { return; } this._visible = this._core.$element.is(':visible'); this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval); }; /** * Refreshes the element. */ AutoRefresh.prototype.refresh = function() { if (this._core.$element.is(':visible') === this._visible) { return; } this._visible = !this._visible; this._core.$element.toggleClass('owl-hidden', !this._visible); this._visible && (this._core.invalidate('width') && this._core.refresh()); }; /** * Destroys the plugin. */ AutoRefresh.prototype.destroy = function() { var handler, property; window.clearInterval(this._interval); for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; })(window.Zepto || window.jQuery, window, document); /** * Lazy Plugin * @version 2.0.0-beta.3 * @author Bartosz Wojciechowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { /** * Creates the lazy plugin. * @class The Lazy Plugin * @param {Owl} carousel - The Owl Carousel */ var Lazy = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Already loaded items. * @protected * @type {Array.} */ this._loaded = []; /** * Event handlers. * @protected * @type {Object} */ this._handlers = { 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) { if (!e.namespace) { return; } if (!this._core.settings || !this._core.settings.lazyLoad) { return; } if ((e.property && e.property.name == 'position') || e.type == 'initialized') { var settings = this._core.settings, n = (settings.center && Math.ceil(settings.items / 2) || settings.items), i = ((settings.center && n * -1) || 0), position = ((e.property && e.property.value) || this._core.current()) + i, clones = this._core.clones().length, load = $.proxy(function(i, v) { this.load(v) }, this); while (i++ < n) { this.load(clones / 2 + this._core.relative(position)); clones && $.each(this._core.clones(this._core.relative(position)), load); position++; } } }, this) }; // set the default options this._core.options = $.extend({}, Lazy.Defaults, this._core.options); // register event handler this._core.$element.on(this._handlers); } /** * Default options. * @public */ Lazy.Defaults = { lazyLoad: false } /** * Loads all resources of an item at the specified position. * @param {Number} position - The absolute position of the item. * @protected */ Lazy.prototype.load = function(position) { var $item = this._core.$stage.children().eq(position), $elements = $item && $item.find('.owl-lazy'); if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { return; } $elements.each($.proxy(function(index, element) { var $element = $(element), image, url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src'); this._core.trigger('load', { element: $element, url: url }, 'lazy'); if ($element.is('img')) { $element.one('load.owl.lazy', $.proxy(function() { $element.css('opacity', 1); this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); }, this)).attr('src', url); } else { image = new Image(); image.onload = $.proxy(function() { $element.css({ 'background-image': 'url(' + url + ')', 'opacity': '1' }); this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); }, this); image.src = url; } }, this)); this._loaded.push($item.get(0)); } /** * Destroys the plugin. * @public */ Lazy.prototype.destroy = function() { var handler, property; for (handler in this.handlers) { this._core.$element.off(handler, this.handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; })(window.Zepto || window.jQuery, window, document); /** * AutoHeight Plugin * @version 2.0.0-beta.3 * @author Bartosz Wojciechowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { /** * Creates the auto height plugin. * @class The Auto Height Plugin * @param {Owl} carousel - The Owl Carousel */ var AutoHeight = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.autoHeight) { this.update(); } }, this), 'changed.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){ this.update(); } }, this), 'loaded.owl.lazy': $.proxy(function(e) { if (e.namespace && this._core.settings.autoHeight && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) { this.update(); } }, this) }; // set default options this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); // register event handlers this._core.$element.on(this._handlers); }; /** * Default options. * @public */ AutoHeight.Defaults = { autoHeight: false, autoHeightClass: 'owl-height' }; /** * Updates the view. */ AutoHeight.prototype.update = function() { var start = this._core._current, end = start + this._core.settings.items, visible = this._core.$stage.children().toArray().slice(start, end); heights = [], maxheight = 0; $.each(visible, function(index, item) { heights.push($(item).height()); }); maxheight = Math.max.apply(null, heights); this._core.$stage.parent() .height(maxheight) .addClass(this._core.settings.autoHeightClass); }; AutoHeight.prototype.destroy = function() { var handler, property; for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; })(window.Zepto || window.jQuery, window, document); /** * Video Plugin * @version 2.0.0-beta.3 * @author Bartosz Wojciechowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { /** * Creates the video plugin. * @class The Video Plugin * @param {Owl} carousel - The Owl Carousel */ var Video = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Cache all video URLs. * @protected * @type {Object} */ this._videos = {}; /** * Current playing item. * @protected * @type {jQuery} */ this._playing = null; /** * All event handlers. * @todo The cloned content removale is too late * @protected * @type {Object} */ this._handlers = { 'initialized.owl.carousel': $.proxy(function(e) { if (e.namespace) { this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] }); } }, this), 'resize.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.video && this.isInFullScreen()) { e.preventDefault(); } }, this), 'refreshed.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.is('resizing')) { this._core.$stage.find('.cloned .owl-video-frame').remove(); } }, this), 'changed.owl.carousel': $.proxy(function(e) { if (e.namespace && e.property.name === 'position' && this._playing) { this.stop(); } }, this), 'prepared.owl.carousel': $.proxy(function(e) { if (!e.namespace) { return; } var $element = $(e.content).find('.owl-video'); if ($element.length) { $element.css('display', 'none'); this.fetch($element, $(e.content)); } }, this) }; // set default options this._core.options = $.extend({}, Video.Defaults, this._core.options); // register event handlers this._core.$element.on(this._handlers); this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { this.play(e); }, this)); }; /** * Default options. * @public */ Video.Defaults = { video: false, videoHeight: false, videoWidth: false }; /** * Gets the video ID and the type (YouTube/Vimeo only). * @protected * @param {jQuery} target - The target containing the video data. * @param {jQuery} item - The item containing the video. */ Video.prototype.fetch = function(target, item) { var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube', id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'), width = target.attr('data-width') || this._core.settings.videoWidth, height = target.attr('data-height') || this._core.settings.videoHeight, url = target.attr('href'); if (url) { id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/); if (id[3].indexOf('youtu') > -1) { type = 'youtube'; } else if (id[3].indexOf('vimeo') > -1) { type = 'vimeo'; } else { throw new Error('Video URL not supported.'); } id = id[6]; } else { throw new Error('Missing video URL.'); } this._videos[url] = { type: type, id: id, width: width, height: height }; item.attr('data-video', url); this.thumbnail(target, this._videos[url]); }; /** * Creates video thumbnail. * @protected * @param {jQuery} target - The target containing the video data. * @param {Object} info - The video info object. * @see `fetch` */ Video.prototype.thumbnail = function(target, video) { var tnLink, icon, path, dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', customTn = target.find('img'), srcType = 'src', lazyClass = '', settings = this._core.settings, create = function(path) { icon = '
    '; if (settings.lazyLoad) { tnLink = '
    '; } else { tnLink = '
    '; } target.after(tnLink); target.after(icon); }; // wrap video content into owl-video-wrapper div target.wrap('
    '); if (this._core.settings.lazyLoad) { srcType = 'data-src'; lazyClass = 'owl-lazy'; } // custom thumbnail if (customTn.length) { create(customTn.attr(srcType)); customTn.remove(); return false; } if (video.type === 'youtube') { path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; create(path); } else if (video.type === 'vimeo') { $.ajax({ type: 'GET', url: '//vimeo.com/api/v2/video/' + video.id + '.json', jsonp: 'callback', dataType: 'jsonp', success: function(data) { path = data[0].thumbnail_large; create(path); } }); } }; /** * Stops the current video. * @public */ Video.prototype.stop = function() { this._core.trigger('stop', null, 'video'); this._playing.find('.owl-video-frame').remove(); this._playing.removeClass('owl-video-playing'); this._playing = null; this._core.leave('playing'); this._core.trigger('stopped', null, 'video'); }; /** * Starts the current video. * @public * @param {Event} event - The event arguments. */ Video.prototype.play = function(event) { var target = $(event.target), item = target.closest('.' + this._core.settings.itemClass), video = this._videos[item.attr('data-video')], width = video.width || '100%', height = video.height || this._core.$stage.height(), html; if (this._playing) { return; } this._core.enter('playing'); this._core.trigger('play', null, 'video'); item = this._core.items(this._core.relative(item.index())); this._core.reset(item.index()); if (video.type === 'youtube') { html = ''; } else if (video.type === 'vimeo') { html = ''; } $('
    ' + html + '
    ').insertAfter(item.find('.owl-video')); this._playing = item.addClass('owl-video-playing'); }; /** * Checks whether an video is currently in full screen mode or not. * @todo Bad style because looks like a readonly method but changes members. * @protected * @returns {Boolean} */ Video.prototype.isInFullScreen = function() { var element = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement; return element && $(element).parent().hasClass('owl-video-frame'); }; /** * Destroys the plugin. */ Video.prototype.destroy = function() { var handler, property; this._core.$element.off('click.owl.video'); for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.Video = Video; })(window.Zepto || window.jQuery, window, document); /** * Animate Plugin * @version 2.0.0-beta.3 * @author Bartosz Wojciechowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { /** * Creates the animate plugin. * @class The Navigation Plugin * @param {Owl} scope - The Owl Carousel */ var Animate = function(scope) { this.core = scope; this.core.options = $.extend({}, Animate.Defaults, this.core.options); this.swapping = true; this.previous = undefined; this.next = undefined; this.handlers = { 'change.owl.carousel': $.proxy(function(e) { if (e.namespace && e.property.name == 'position') { this.previous = this.core.current(); this.next = e.property.value; } }, this), 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { if (e.namespace) { this.swapping = e.type == 'translated'; } }, this), 'translate.owl.carousel': $.proxy(function(e) { if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { this.swap(); } }, this) }; this.core.$element.on(this.handlers); }; /** * Default options. * @public */ Animate.Defaults = { animateOut: false, animateIn: false }; /** * Toggles the animation classes whenever an translations starts. * @protected * @returns {Boolean|undefined} */ Animate.prototype.swap = function() { if (this.core.settings.items !== 1) { return; } if (!$.support.animation || !$.support.transition) { return; } this.core.speed(0); var left, clear = $.proxy(this.clear, this), previous = this.core.$stage.children().eq(this.previous), next = this.core.$stage.children().eq(this.next), incoming = this.core.settings.animateIn, outgoing = this.core.settings.animateOut; if (this.core.current() === this.previous) { return; } if (outgoing) { left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); previous.css( { 'left': left + 'px' } ) .addClass('animated owl-animated-out') .addClass(outgoing) .on($.support.animation.end, clear); } if (incoming) { next.addClass('animated owl-animated-in') .addClass(incoming) .on($.support.animation.end, clear); } }; Animate.prototype.clear = function(e) { if ($(e.target).hasClass('animated')) { $(e.target).css( { 'left': '' } ) .removeClass('animated owl-animated-out owl-animated-in') .removeClass(this.core.settings.animateIn) .removeClass(this.core.settings.animateOut); this.core.onTransitionEnd(); } }; /** * Destroys the plugin. * @public */ Animate.prototype.destroy = function() { var handler, property; for (handler in this.handlers) { this.core.$element.off(handler, this.handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; })(window.Zepto || window.jQuery, window, document); /** * Autoplay Plugin * @version 2.0.0-beta.3 * @author Bartosz Wojciechowski * @author Artus Kolanowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { /** * Creates the autoplay plugin. * @class The Autoplay Plugin * @param {Owl} scope - The Owl Carousel */ var Autoplay = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * The autoplay interval. * @type {Number} */ this._interval = null; /** * Indicates whenever the autoplay is paused. * @type {Boolean} */ this._paused = false; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { 'changed.owl.carousel': $.proxy(function(e) { if (e.namespace && e.property.name === 'settings') { if (this._core.settings.autoplay) { this.play(); } else { this.stop(); } } }, this), 'initialized.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.autoplay) { this.play(); } }, this), 'play.owl.autoplay': $.proxy(function(e, t, s) { if (e.namespace) { this.play(t, s); } }, this), 'stop.owl.autoplay': $.proxy(function(e) { if (e.namespace) { this.stop(); } }, this), 'mouseover.owl.autoplay': $.proxy(function() { if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { this.pause(); } }, this), 'mouseleave.owl.autoplay': $.proxy(function() { if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { this.play(); } }, this) }; // register event handlers this._core.$element.on(this._handlers); // set default options this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); }; /** * Default options. * @public */ Autoplay.Defaults = { autoplay: false, autoplayTimeout: 5000, autoplayHoverPause: false, autoplaySpeed: false }; /** * Starts the autoplay. * @public * @param {Number} [timeout] - The interval before the next animation starts. * @param {Number} [speed] - The animation speed for the animations. */ Autoplay.prototype.play = function(timeout, speed) { this._paused = false; if (this._core.is('rotating')) { return; } this._core.enter('rotating'); this._interval = window.setInterval($.proxy(function() { if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) { return; } this._core.next(speed || this._core.settings.autoplaySpeed); }, this), timeout || this._core.settings.autoplayTimeout); }; /** * Stops the autoplay. * @public */ Autoplay.prototype.stop = function() { if (!this._core.is('rotating')) { return; } window.clearInterval(this._interval); this._core.leave('rotating'); }; /** * Stops the autoplay. * @public */ Autoplay.prototype.pause = function() { if (!this._core.is('rotating')) { return; } this._paused = true; }; /** * Destroys the plugin. */ Autoplay.prototype.destroy = function() { var handler, property; this.stop(); for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; })(window.Zepto || window.jQuery, window, document); /** * Navigation Plugin * @version 2.0.0-beta.3 * @author Artus Kolanowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { 'use strict'; /** * Creates the navigation plugin. * @class The Navigation Plugin * @param {Owl} carousel - The Owl Carousel. */ var Navigation = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Indicates whether the plugin is initialized or not. * @protected * @type {Boolean} */ this._initialized = false; /** * The current paging indexes. * @protected * @type {Array} */ this._pages = []; /** * All DOM elements of the user interface. * @protected * @type {Object} */ this._controls = {}; /** * Markup for an indicator. * @protected * @type {Array.} */ this._templates = []; /** * The carousel element. * @type {jQuery} */ this.$element = this._core.$element; /** * Overridden methods of the carousel. * @protected * @type {Object} */ this._overrides = { next: this._core.next, prev: this._core.prev, to: this._core.to }; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { 'prepared.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.dotsData) { this._templates.push('
    ' + $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '
    '); } }, this), 'added.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.dotsData) { this._templates.splice(e.position, 0, this._templates.pop()); } }, this), 'remove.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.dotsData) { this._templates.splice(e.position, 1); } }, this), 'changed.owl.carousel': $.proxy(function(e) { if (e.namespace && e.property.name == 'position') { this.draw(); } }, this), 'initialized.owl.carousel': $.proxy(function(e) { if (e.namespace && !this._initialized) { this._core.trigger('initialize', null, 'navigation'); this.initialize(); this.update(); this.draw(); this._initialized = true; this._core.trigger('initialized', null, 'navigation'); } }, this), 'refreshed.owl.carousel': $.proxy(function(e) { if (e.namespace && this._initialized) { this._core.trigger('refresh', null, 'navigation'); this.update(); this.draw(); this._core.trigger('refreshed', null, 'navigation'); } }, this) }; // set default options this._core.options = $.extend({}, Navigation.Defaults, this._core.options); // register event handlers this.$element.on(this._handlers); }; /** * Default options. * @public * @todo Rename `slideBy` to `navBy` */ Navigation.Defaults = { nav: false, navText: [ 'prev', 'next' ], navSpeed: false, navElement: 'div', navContainer: false, navContainerClass: 'owl-nav', navClass: [ 'owl-prev', 'owl-next' ], slideBy: 1, dotClass: 'owl-dot', dotsClass: 'owl-dots', dots: true, dotsEach: false, dotsData: false, dotsSpeed: false, dotsContainer: false }; /** * Initializes the layout of the plugin and extends the carousel. * @protected */ Navigation.prototype.initialize = function() { var override, settings = this._core.settings; // create DOM structure for relative navigation this._controls.$relative = (settings.navContainer ? $(settings.navContainer) : $('
    ').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); this._controls.$previous = $('<' + settings.navElement + '>') .addClass(settings.navClass[0]) .html(settings.navText[0]) .prependTo(this._controls.$relative) .on('click', $.proxy(function(e) { this.prev(settings.navSpeed); }, this)); this._controls.$next = $('<' + settings.navElement + '>') .addClass(settings.navClass[1]) .html(settings.navText[1]) .appendTo(this._controls.$relative) .on('click', $.proxy(function(e) { this.next(settings.navSpeed); }, this)); // create DOM structure for absolute navigation if (!settings.dotsData) { this._templates = [ $('
    ') .addClass(settings.dotClass) .append($('')) .prop('outerHTML') ]; } this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer) : $('
    ').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled'); this._controls.$absolute.on('click', 'div', $.proxy(function(e) { var index = $(e.target).parent().is(this._controls.$absolute) ? $(e.target).index() : $(e.target).parent().index(); e.preventDefault(); this.to(index, settings.dotsSpeed); }, this)); // override public methods of the carousel for (override in this._overrides) { this._core[override] = $.proxy(this[override], this); } }; /** * Destroys the plugin. * @protected */ Navigation.prototype.destroy = function() { var handler, control, property, override; for (handler in this._handlers) { this.$element.off(handler, this._handlers[handler]); } for (control in this._controls) { this._controls[control].remove(); } for (override in this.overides) { this._core[override] = this._overrides[override]; } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; /** * Updates the internal state. * @protected */ Navigation.prototype.update = function() { var i, j, k, lower = this._core.clones().length / 2, upper = lower + this._core.items().length, maximum = this._core.maximum(true), settings = this._core.settings, size = settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items; if (settings.slideBy !== 'page') { settings.slideBy = Math.min(settings.slideBy, settings.items); } if (settings.dots || settings.slideBy == 'page') { this._pages = []; for (i = lower, j = 0, k = 0; i < upper; i++) { if (j >= size || j === 0) { this._pages.push({ start: Math.min(maximum, i - lower), end: i - lower + size - 1 }); if (Math.min(maximum, i - lower) === maximum) { break; } j = 0, ++k; } j += this._core.mergers(this._core.relative(i)); } } }; /** * Draws the user interface. * @todo The option `dotsData` wont work. * @protected */ Navigation.prototype.draw = function() { var difference, settings = this._core.settings, disabled = this._core.items().length <= settings.items, index = this._core.relative(this._core.current()), loop = settings.loop || settings.rewind; this._controls.$relative.toggleClass('disabled', !settings.nav || disabled); if (settings.nav) { this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true)); this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true)); } this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled); if (settings.dots) { difference = this._pages.length - this._controls.$absolute.children().length; if (settings.dotsData && difference !== 0) { this._controls.$absolute.html(this._templates.join('')); } else if (difference > 0) { this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0])); } else if (difference < 0) { this._controls.$absolute.children().slice(difference).remove(); } this._controls.$absolute.find('.active').removeClass('active'); this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active'); } }; /** * Extends event data. * @protected * @param {Event} event - The event object which gets thrown. */ Navigation.prototype.onTrigger = function(event) { var settings = this._core.settings; event.page = { index: $.inArray(this.current(), this._pages), count: this._pages.length, size: settings && (settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items) }; }; /** * Gets the current page position of the carousel. * @protected * @returns {Number} */ Navigation.prototype.current = function() { var current = this._core.relative(this._core.current()); return $.grep(this._pages, $.proxy(function(page, index) { return page.start <= current && page.end >= current; }, this)).pop(); }; /** * Gets the current succesor/predecessor position. * @protected * @returns {Number} */ Navigation.prototype.getPosition = function(successor) { var position, length, settings = this._core.settings; if (settings.slideBy == 'page') { position = $.inArray(this.current(), this._pages); length = this._pages.length; successor ? ++position : --position; position = this._pages[((position % length) + length) % length].start; } else { position = this._core.relative(this._core.current()); length = this._core.items().length; successor ? position += settings.slideBy : position -= settings.slideBy; } return position; }; /** * Slides to the next item or page. * @public * @param {Number} [speed=false] - The time in milliseconds for the transition. */ Navigation.prototype.next = function(speed) { $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); }; /** * Slides to the previous item or page. * @public * @param {Number} [speed=false] - The time in milliseconds for the transition. */ Navigation.prototype.prev = function(speed) { $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); }; /** * Slides to the specified item or page. * @public * @param {Number} position - The position of the item or page. * @param {Number} [speed] - The time in milliseconds for the transition. * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. */ Navigation.prototype.to = function(position, speed, standard) { var length; if (!standard) { length = this._pages.length; $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); } else { $.proxy(this._overrides.to, this._core)(position, speed); } }; $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation; })(window.Zepto || window.jQuery, window, document); /** * Hash Plugin * @version 2.0.0-beta.3 * @author Artus Kolanowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { 'use strict'; /** * Creates the hash plugin. * @class The Hash Plugin * @param {Owl} carousel - The Owl Carousel */ var Hash = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Hash index for the items. * @protected * @type {Object} */ this._hashes = {}; /** * The carousel element. * @type {jQuery} */ this.$element = this._core.$element; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { /*'initialized.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.startPosition === 'URLHash') { $(window).trigger('hashchange.owl.navigation'); } }, this),*/ 'prepared.owl.carousel': $.proxy(function(e) { if (e.namespace) { var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash'); if (!hash) { return; } this._hashes[hash] = e.content; } }, this), 'changed.owl.carousel': $.proxy(function(e) { if (e.namespace && e.property.name === 'position') { var current = this._core.items(this._core.relative(this._core.current())), hash = $.map(this._hashes, function(item, hash) { return item === current ? hash : null; }).join(); if (!hash || window.location.hash.slice(1) === hash) { return; } window.location.hash = hash; } }, this) }; // set default options this._core.options = $.extend({}, Hash.Defaults, this._core.options); // register the event handlers this.$element.on(this._handlers); // register event listener for hash navigation /*$(window).on('hashchange.owl.navigation', $.proxy(function(e) { var hash = window.location.hash.substring(1), items = this._core.$stage.children(), position = this._hashes[hash] && items.index(this._hashes[hash]); if (position === undefined || position === this._core.current()) { return; } this._core.to(this._core.relative(position), false, true); }, this));*/ }; /** * Default options. * @public */ Hash.Defaults = { URLhashListener: false }; /** * Destroys the plugin. * @public */ Hash.prototype.destroy = function() { var handler, property; $(window).off('hashchange.owl.navigation'); for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.Hash = Hash; })(window.Zepto || window.jQuery, window, document); /** * Support Plugin * * @version 2.0.0-beta.3 * @author Vivid Planet Software GmbH * @author Artus Kolanowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { var style = $('').get(0).style, prefixes = 'Webkit Moz O ms'.split(' '), events = { transition: { end: { WebkitTransition: 'webkitTransitionEnd', MozTransition: 'transitionend', OTransition: 'oTransitionEnd', transition: 'transitionend' } }, animation: { end: { WebkitAnimation: 'webkitAnimationEnd', MozAnimation: 'animationend', OAnimation: 'oAnimationEnd', animation: 'animationend' } } }, tests = { csstransforms: function() { return !!test('transform'); }, csstransforms3d: function() { return !!test('perspective'); }, csstransitions: function() { return !!test('transition'); }, cssanimations: function() { return !!test('animation'); } }; function test(property, prefixed) { var result = false, upper = property.charAt(0).toUpperCase() + property.slice(1); $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) { if (style[property] !== undefined) { result = prefixed ? property : true; return false; } }); return result; } function prefixed(property) { return test(property, true); } if (tests.csstransitions()) { /* jshint -W053 */ $.support.transition = new String(prefixed('transition')) $.support.transition.end = events.transition.end[ $.support.transition ]; } if (tests.cssanimations()) { /* jshint -W053 */ $.support.animation = new String(prefixed('animation')) $.support.animation.end = events.animation.end[ $.support.animation ]; } if (tests.csstransforms()) { /* jshint -W053 */ $.support.transform = new String(prefixed('transform')); $.support.transform3d = tests.csstransforms3d(); } })(window.Zepto || window.jQuery, window, document); (function(window, document, undefined) { /** * Find the absolute position of an element */ var absPos = function(element) { var offsetLeft, offsetTop; offsetLeft = offsetTop = 0; if (element.offsetParent) { do { offsetLeft += element.offsetLeft; offsetTop += element.offsetTop; } while (element = element.offsetParent); } return [offsetLeft, offsetTop]; }; /** * @constructor Progress Circle class * @param params.canvas Canvas on which the circles will be drawn. * @param params.minRadius Inner radius of the innermost circle, in px. * @param params.arcWidth Width of each circle(to be more accurate, ring). * @param params.gapWidth Space between each circle. * @param params.centerX X coordinate of the center of circles. * @param params.centerY Y coordinate of the center of circles. * @param params.infoLineBaseAngle Base angle of the info line. * @param params.infoLineAngleInterval Angles between the info lines. */ var ProgressCircle = function(params) { this.canvas = params.canvas; this.minRadius = params.minRadius || 15; this.arcWidth = params.arcWidth || 5; this.gapWidth = params.gapWidth || 3; this.centerX = params.centerX || this.canvas.width / 2; this.centerY = params.centerY || this.canvas.height / 2; this.infoLineLength = params.infoLineLength || 60; this.horizLineLength = params.horizLineLength || 10; this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8; this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6; this.context = this.canvas.getContext('2d'); this.width = this.canvas.width; this.height = this.canvas.height; this.circles = []; this.runningCount = 0; }; ProgressCircle.prototype = { constructor: ProgressCircle, /** * @method Adds an progress monitor entry. * @param params.fillColor Color to fill in the circle. * @param params.outlineColor Color to outline the circle. * @param params.progressListener Callback function to fetch the progress. * @param params.infoListener Callback function to fetch the info. * @returns this */ addEntry: function(params) { this.circles.push(new Circle({ canvas: this.canvas, context: this.context, centerX: this.centerX, centerY: this.centerY, innerRadius: this.minRadius + this.circles.length * (this.gapWidth + this.arcWidth), arcWidth: this.arcWidth, infoLineLength: this.infoLineLength, horizLineLength: this.horizLineLength, id: this.circles.length, fillColor: params.fillColor, outlineColor: params.outlineColor, progressListener: params.progressListener, infoListener: params.infoListener, infoLineAngle: this.infoLineBaseAngle + this.circles.length * this.infoLineAngleInterval, })); return this; }, /** * @method Starts the monitor and updates with the given interval. * @param interval Interval between updates, in millisecond. * @returns this */ start: function(interval) { var self = this; this.timer = setInterval(function() { self._update(); }, interval || 33); return this; }, /** * @method Stop the animation. */ stop: function() { clearTimeout(this.timer); }, /** * @private * @method Call update on each circle and redraw them. * @returns this */ _update: function() { this._clear(); this.circles.forEach(function(circle, idx, array) { circle.update(); }); return this; }, /** * @private * @method Clear the canvas. * @returns this */ _clear: function() { this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); return this; }, }; /** * @private * @class Individual progress circle. * @param params.canvas Canvas on which the circle will be drawn. * @param params.context Context of the canvas. * @param params.innerRadius Inner radius of the circle, in px. * @param params.arcWidth Width of each arc(circle). * @param params.gapWidth Distance between each arc. * @param params.centerX X coordinate of the center of circles. * @param params.centerY Y coordinate of the center of circles. * @param params.fillColor Color to fill in the circle. * @param params.outlineColor Color to outline the circle. * @param params.progressListener Callback function to fetch the progress. * @param params.infoListener Callback function to fetch the info. * @param params.infoLineAngle Angle of info line. */ var Circle = function(params) { this.id = params.id; this.canvas = params.canvas; this.context = params.context; this.centerX = params.centerX; this.centerY = params.centerY; this.arcWidth = params.arcWidth; this.innerRadius = params.innerRadius || 0; this.fillColor = params.fillColor || '#fff'; this.outlineColor = params.outlineColor || this.fillColor; this.progressListener = params.progressListener; this.infoLineLength = params.infoLineLength || 250; this.horizLineLength = params.horizLineLength || 50; this.infoListener = params.infoListener; this.infoLineAngle = params.infoLineAngle; this.outerRadius = this.innerRadius + this.arcWidth; // If the info listener is not registered, then don't calculate // the related coordinates if (!this.infoListener) return; // calculate the info-line turning points var angle = this.infoLineAngle, arcDistance = (this.innerRadius + this.outerRadius) / 2, sinA = Math.sin(angle), cosA = Math.cos(angle); this.infoLineStartX = this.centerX + sinA * arcDistance; this.infoLineStartY = this.centerY - cosA * arcDistance; this.infoLineMidX = this.centerX + sinA * this.infoLineLength; this.infoLineMidY = this.centerY - cosA * this.infoLineLength; this.infoLineEndX = this.infoLineMidX + (sinA < 0 ? -this.horizLineLength : this.horizLineLength); this.infoLineEndY = this.infoLineMidY; var infoText = document.createElement('div'), style = infoText.style; style.color = this.fillColor; style.position = 'absolute'; style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px'; // style.top will be calculated in the `drawInfo` method. Since // user may want to change the size of the font, so the top offset // must be updated in each loop. infoText.className = 'ProgressCircleInfo'; // For css styling infoText.id = 'progress_circle_info_' + this.id; document.body.appendChild(infoText); this.infoText = infoText; }; Circle.prototype = { constructor: Circle, update: function() { this.progress = this.progressListener(); this._draw(); if (this.infoListener) { this.info = this.infoListener(); this._drawInfo(); } }, /** * @private * @method Draw the circle on the canvas. * @returns this */ _draw: function() { var ctx = this.context, ANGLE_OFFSET = -Math.PI / 2, startAngle = 0 + ANGLE_OFFSET, endAngle= startAngle + this.progress * Math.PI * 2, x = this.centerX, y = this.centerY, innerRadius = this.innerRadius - this.arcWidth - 1, outerRadius = this.outerRadius - this.arcWidth - 1; if ( innerRadius < 0 ) return; ctx.fillStyle = this.fillColor; ctx.strokeStyle = this.outlineColor; ctx.beginPath(); ctx.arc(x, y, innerRadius, startAngle, endAngle, false); ctx.arc(x, y, outerRadius, endAngle, startAngle, true); ctx.closePath(); ctx.stroke(); ctx.fill(); return this; }, /** * @private * @method Draw the info lines and info text. * @returns this */ _drawInfo: function() { var pointList, lineHeight; pointList = [ [this.infoLineStartX, this.infoLineStartY], [this.infoLineMidX, this.infoLineMidY], [this.infoLineEndX, this.infoLineEndY], ]; this._drawSegments(pointList, false); this.infoText.innerHTML = this.info; lineHeight = this.infoText.offsetHeight; this.infoText.style.top = this.infoLineEndY + absPos(this.canvas)[1] - lineHeight / 2 + 'px'; return this; }, /** * @private * @method Helper function to draw the segments * @param pointList An array of points in the form of [x, y]. * @param close Whether to connect the first and last point. */ _drawSegments: function(pointList, close) { var ctx = this.context; ctx.beginPath(); ctx.moveTo(pointList[0][0], pointList[0][1]); for (var i = 1; i < pointList.length; ++i) { ctx.lineTo(pointList[i][0], pointList[i][1]); } if (close) { ctx.closePath(); } ctx.stroke(); }, }; window.ProgressCircle = ProgressCircle; })(window, document); /* ========================================================= * jquery.vc_chart.js v1.0 * ========================================================= * Copyright 2013 Wpbakery * * Jquery chart plugin for the Visual Composer. * ========================================================= */ (function($){ /** * Pie chart animated. * @param element - DOM element * @param options - settings object. * @constructor */ var VcChart = function(element, options) { this.el = element; this.$el = $(this.el); var $this = this; $this.options = $.extend({ color: 'wpb_button', units: '', width: '', label_selector: '.vc_pie_chart_value', back_selector: '.vc_pie_chart_back', responsive: true }, options); $this.init(); }; VcChart.prototype = { constructor: VcChart, _progress_v: 0, animated: false, colors: { 'wpb_button': 'rgba(247, 247, 247, 1)', 'btn-primary': 'rgba(0, 136, 204, 1)', 'btn-info': 'rgba(88, 185, 218, 1)', 'btn-success': 'rgba(106, 177, 101, 1)', 'btn-warning': 'rgba(255, 153, 0, 1)', 'btn-danger': 'rgba(255, 103, 91, 1)', 'btn-inverse': 'rgba(85, 85, 85, 1)' }, init: function() { this.setupColor(); this.value = this.$el.data('pie-value')/100; this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value'); this.$wrapper = $('.vc_pie_wrapper', this.$el); this.$label = $(this.options.label_selector, this.$el); this.$back = $(this.options.back_selector, this.$el); this.$canvas = this.$el.find('canvas'); this.arcWidth = this.$el.data('pie-width') * 2; this.draw(); this.setWayPoint(); if(this.options.responsive === true) this.setResponsive(); if (UNCODE.isMobile) this._progress_v = this.value; }, setupColor: function() { // if(typeof this.colors[this.options.color] !== 'undefined') { // this.color = this.colors[this.options.color]; // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) { // this.color = this.options.color; // } else { // this.color = 'rgba(247, 247, 247, 0.2)'; // } if(typeof this.options.color !== 'undefined') { this.color = this.options.color; } else this.color = 'rgba(247, 247, 247, 0.2)'; }, setResponsive: function() { var that = this; if (!UNCODE.isMobile) { $(window).resize(function(){ if(that.animated === true) that.circle.stop(); that.draw(true); }); } }, draw: function(redraw) { var w = this.$el.addClass('vc_ready').width() * 2, border_w = this.arcWidth, radius; if(!w) w = this.$el.parents(':visible').first().width()-2; //w = Math.round(w/100*80); //if (w < 250) w = 250; radius = w/2; this.$wrapper.css({"width" : (w / 2) + "px"}); this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"}); this.$back.css({"width" : (w / 2), "height" : (w / 2)}); this.$canvas.attr({"width" : w + "px", "height" : w + "px"}); this.$el.addClass('vc_ready'); this.circle = new ProgressCircle({ canvas: this.$canvas.get(0), minRadius: radius, arcWidth: border_w }); if(redraw === true && this.animated === true) { this._progress_v = this.value; this.circle.addEntry({ fillColor: this.color, progressListener: $.proxy(this.setProgress, this) }).start(); } }, setProgress: function() { if (this._progress_v >= this.value) { this.circle.stop(); this.animated = true; this.$label.html(this.label_value + this.options.units); return this._progress_v; } this._progress_v += 0.01; if (!isNaN(this.label_value)) { var label_value = this._progress_v/this.value*this.label_value; var val = Math.round(label_value) + this.options.units; this.$label.html(val); } else this.$label.html(this.label_value + this.options.units); return this._progress_v; }, animate: function() { if(this.animated !== true) { this.circle.addEntry({ fillColor: this.color, progressListener: $.proxy(this.setProgress, this) }).start(10); } }, setWayPoint: function() { if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) { this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' }); } else { this.animate(); } } }; /** * jQuery plugin * @param option - object with settings * @return {*} */ $.fn.vcChat = function(option, value) { return this.each(function () { var $this = $(this), data = $this.data('vc_chart'), options = typeof option === 'object' ? option : { color: $this.data('pie-color'), units: $this.data('pie-units') }; if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options))); if (typeof option == 'string') data[option](value); }); }; /** * Allows users to rewrite function inside theme. */ if ( typeof window['vc_pieChart'] !== 'function' ) { window.vc_pieChart = function() { $('.vc_pie_chart:visible:not(.vc_ready)').vcChat(); } } $(document).ready(function(){ !window.vc_iframe && vc_pieChart(); /** * Tab and collapse integration. */ $('.nav-tabs a').on('shown.bs.tab', function(e){ var $cont = $(e.target).closest('.tab-container'), $active = $('.tab-pane.active', $cont); $('.vc_pie_chart:not(.vc_ready)', $active).vcChat(); }); $('.panel-collapse').on('shown.bs.collapse', function (e) { $('.vc_pie_chart:not(.vc_ready)', e.target).vcChat(); }) }); })(window.jQuery); /* Progress bar ---------------------------------------------------------- */ function uncode_progress_bar() { jQuery.each(jQuery('.vc_progress_bar'), function(index, val) { if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) { return; } if (!UNCODE.isMobile) { new Waypoint({ context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, element: val, handler: function() { var element = jQuery(this.element); element.find('.vc_single_bar').each(function(index) { var $this = jQuery(this), bar = $this.find('.vc_bar'), val = bar.data('percentage-value'); setTimeout(function() { bar.css({ "width": val + '%' }); }, index * 200); }); }, offset: '80%' }); } else { var element = jQuery(val); element.find('.vc_single_bar').each(function(index) { var $this = jQuery(this), bar = $this.find('.vc_bar'), val = bar.data('percentage-value'); setTimeout(function() { bar.css({ "width": val + '%' }); }, index * 200); }); } }); }; uncode_progress_bar(); /*! * jquery.counterup.js 1.0 * * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal * Released under the GPL v2 License * * Date: Nov 26, 2013 */ (function($) { "use strict"; $.fn.counterUp = function(options) { // Defaults var settings = $.extend({ 'time': 400, 'delay': 10 }, options); return this.each(function() { // Store the object var $this = $(this); var $settings = settings; var counterUpper = function() { var nums = []; var divisions = $settings.time / $settings.delay; var numReal = $this.attr('data-val'), num = numReal; var isComma = /[0-9]+,[0-9]+/.test(num); num = num.replace(/,/g, ''); var isInt = /^[0-9]+$/.test(num); var isFloat = /^[0-9]+\.[0-9]+$/.test(num); var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0; // Generate list of incremental numbers to display for (var i = divisions; i >= 1; i--) { // Preserve as int if input was int var newNum = parseInt(num / divisions * i); // Preserve float if input was float if (isFloat) { newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces); } // Preserve commas if input had commas if (isComma) { while (/(\d+)(\d{3})/.test(newNum.toString())) { newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2'); } } nums.unshift(newNum); } nums.push(numReal); $this.data('counterup-nums', nums); $this.text('0'); // Updates the number until we're done var f = function() { if ($this.data('counterup-nums') != null) { $this.text($this.data('counterup-nums').shift()); if ($this.data('counterup-nums').length) { setTimeout($this.data('counterup-func'), $settings.delay); } else { delete $this.data('counterup-nums'); $this.data('counterup-nums', null); $this.data('counterup-func', null); } } }; $this.data('counterup-func', f); // Start the count up setTimeout($this.data('counterup-func'), $settings.delay); }; // Perform counts when the element gets into view new Waypoint({ context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window, element: this, handler: function() { counterUpper(); if (!UNCODE.isUnmodalOpen) { this.destroy(); } }, offset: '100%' }); }); }; })(jQuery); /*! * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/) * Copyright (c) 2016 Edson Hilios * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ (function(factory) { "use strict"; if (typeof define === "function" && define.amd) { define([ "jquery" ], factory); } else { factory(jQuery); } })(function($) { "use strict"; var instances = [], matchers = [], defaultOptions = { precision: 100, elapse: false, defer: false }; matchers.push(/^[0-9]*$/.source); matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); matchers = new RegExp(matchers.join("|")); function parseDateString(dateString) { if (dateString instanceof Date) { return dateString; } if (String(dateString).match(matchers)) { if (String(dateString).match(/^[0-9]*$/)) { dateString = Number(dateString); } if (String(dateString).match(/\-/)) { dateString = String(dateString).replace(/\-/g, "/"); } return new Date(dateString); } else { throw new Error("Couldn't cast `" + dateString + "` to a date object."); } } var DIRECTIVE_KEY_MAP = { Y: "years", m: "months", n: "daysToMonth", d: "daysToWeek", w: "weeks", W: "weeksToMonth", H: "hours", M: "minutes", S: "seconds", D: "totalDays", I: "totalHours", N: "totalMinutes", T: "totalSeconds" }; function escapedRegExp(str) { var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); return new RegExp(sanitize); } function strftime(offsetObject) { return function(format) { var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); if (directives) { for (var i = 0, len = directives.length; i < len; ++i) { var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null; directive = directive[2]; if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { value = DIRECTIVE_KEY_MAP[directive]; value = Number(offsetObject[value]); } if (value !== null) { if (modifier === "!") { value = pluralize(plural, value); } if (modifier === "") { if (value < 10) { value = "0" + value.toString(); } } format = format.replace(regexp, value.toString()); } } } format = format.replace(/%%/, "%"); return format; }; } function pluralize(format, count) { var plural = "s", singular = ""; if (format) { format = format.replace(/(:|;|\s)/gi, "").split(/\,/); if (format.length === 1) { plural = format[0]; } else { singular = format[0]; plural = format[1]; } } if (Math.abs(count) > 1) { return plural; } else { return singular; } } var Countdown = function(el, finalDate, options) { this.el = el; this.$el = $(el); this.interval = null; this.offset = {}; this.options = $.extend({}, defaultOptions); this.instanceNumber = instances.length; instances.push(this); this.$el.data("countdown-instance", this.instanceNumber); if (options) { if (typeof options === "function") { this.$el.on("update.countdown", options); this.$el.on("stoped.countdown", options); this.$el.on("finish.countdown", options); } else { this.options = $.extend({}, defaultOptions, options); } } this.setFinalDate(finalDate); if (this.options.defer === false) { this.start(); } }; $.extend(Countdown.prototype, { start: function() { if (this.interval !== null) { clearInterval(this.interval); } var self = this; this.update(); this.interval = setInterval(function() { self.update.call(self); }, this.options.precision); }, stop: function() { clearInterval(this.interval); this.interval = null; this.dispatchEvent("stoped"); }, toggle: function() { if (this.interval) { this.stop(); } else { this.start(); } }, pause: function() { this.stop(); }, resume: function() { this.start(); }, remove: function() { this.stop.call(this); instances[this.instanceNumber] = null; delete this.$el.data().countdownInstance; }, setFinalDate: function(value) { this.finalDate = parseDateString(value); }, update: function() { if (this.$el.closest("html").length === 0) { this.remove(); return; } var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft; newTotalSecsLeft = this.finalDate.getTime() - now.getTime(); newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3); newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft); if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) { return; } else { this.totalSecsLeft = newTotalSecsLeft; } this.elapsed = now >= this.finalDate; this.offset = { seconds: this.totalSecsLeft % 60, minutes: Math.floor(this.totalSecsLeft / 60) % 60, hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24, days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368), weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4, months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368), years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()), totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24), totalHours: Math.floor(this.totalSecsLeft / 60 / 60), totalMinutes: Math.floor(this.totalSecsLeft / 60), totalSeconds: this.totalSecsLeft }; if (!this.options.elapse && this.totalSecsLeft === 0) { this.stop(); this.dispatchEvent("finish"); } else { this.dispatchEvent("update"); } }, dispatchEvent: function(eventName) { var event = $.Event(eventName + ".countdown"); event.finalDate = this.finalDate; event.elapsed = this.elapsed; event.offset = $.extend({}, this.offset); event.strftime = strftime(this.offset); this.$el.trigger(event); } }); $.fn.countdown = function() { var argumentsArray = Array.prototype.slice.call(arguments, 0); return this.each(function() { var instanceNumber = $(this).data("countdown-instance"); if (instanceNumber !== undefined) { var instance = instances[instanceNumber], method = argumentsArray[0]; if (Countdown.prototype.hasOwnProperty(method)) { instance[method].apply(instance, argumentsArray.slice(1)); } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { instance.setFinalDate.call(instance, method); instance.start(); } else { $.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method)); } } else { new Countdown(this, argumentsArray[0], argumentsArray[1]); } }); }; }); !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Share=e()}}(function(){var define,module,exports; function getStyles(config){ // return ""+config.selector+"{width:92px;height:20px;-webkit-touch-callout:none;-khtml-user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}"+config.selector+" [class*=social-]:before{font-family:'uncodeicon'}"+config.selector+" label{font-size:16px;cursor:pointer;margin:0;padding:5px 10px;border-radius:5px;background:#a29baa;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" label:hover{opacity:.8}"+config.selector+" label span{text-transform:uppercase;font-size:.9em;font-family:Lato,sans-serif;font-weight:700;-webkit-font-smoothing:antialiased;padding-left:6px}"+config.selector+" .social{opacity:0;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;margin-left:-15px;visibility:hidden}"+config.selector+" .social.top{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:-80px}"+config.selector+" .social.bottom{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:5px}"+config.selector+" .social.middle{margin-top:-34px}"+config.selector+" .social.middle.right{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%;margin-left:105px}"+config.selector+" .social.middle.left{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%}"+config.selector+" .social.right{margin-left:14px}"+config.selector+" .social.load{-webkit-transition:none!important;transition:none!important}"+config.selector+" .social.networks-1{width:60px}"+config.selector+" .social.networks-1.center,"+config.selector+" .social.networks-1.left{margin-left:14px}"+config.selector+" .social.networks-1.middle.left{margin-left:-70px}"+config.selector+" .social.networks-1 ul{width:60px}"+config.selector+" .social.networks-2{width:120px}"+config.selector+" .social.networks-2.center{margin-left:-13px}"+config.selector+" .social.networks-2.left{margin-left:-44px}"+config.selector+" .social.networks-2.middle.left{margin-left:-130px}"+config.selector+" .social.networks-2 ul{width:120px}"+config.selector+" .social.networks-3{width:180px}"+config.selector+" .social.networks-3.center{margin-left:-45px}"+config.selector+" .social.networks-3.left{margin-left:-102px}"+config.selector+" .social.networks-3.middle.left{margin-left:-190px}"+config.selector+" .social.networks-3 ul{width:180px}"+config.selector+" .social.networks-4{width:240px}"+config.selector+" .social.networks-4.center{margin-left:-75px}"+config.selector+" .social.networks-4.left{margin-left:162px}"+config.selector+" .social.networks-4.middle.left{margin-left:-250px}"+config.selector+" .social.networks-4 ul{width:240px}"+config.selector+" .social.networks-5{width:300px}"+config.selector+" .social.networks-5.center{margin-left:-105px}"+config.selector+" .social.networks-5.left{margin-left:-225px}"+config.selector+" .social.networks-5.middle.left{margin-left:-320px}"+config.selector+" .social.networks-5 ul{width:300px}"+config.selector+" .social.active{opacity:1;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;visibility:visible}"+config.selector+" .social.active.top{-webkit-transform:scale(1) translateY(-20px);-ms-transform:scale(1) translateY(-20px);transform:scale(1) translateY(-20px)}"+config.selector+" .social.active.bottom{-webkit-transform:scale(1) translateY(15px);-ms-transform:scale(1) translateY(15px);transform:scale(1) translateY(15px)}"+config.selector+" .social.active.middle.right{-webkit-transform:scale(1) translateX(10px);-ms-transform:scale(1) translateX(10px);transform:scale(1) translateX(10px)}"+config.selector+" .social.active.middle.left{-webkit-transform:scale(1) translateX(-20px);-ms-transform:scale(1) translateX(-20px);transform:scale(1) translateX(-20px)}"+config.selector+" .social ul{position:relative;left:0;right:0;height:46px;color:#fff;margin:auto;padding:0;list-style:none}"+config.selector+" .social ul li{font-size:20px;cursor:pointer;width:60px;margin:0;padding:12px 0;text-align:center;float:left;display:none;height:22px;position:relative;z-index:2;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" .social ul li:hover{}"+config.selector+" .social li[class*=facebook]{display:"+config.networks.facebook.display+"}"+config.selector+" .social li[class*=twitter]{display:"+config.networks.twitter.display+"}"+config.selector+" .social li[class*=gplus]{display:"+config.networks.google_plus.display+"}"+config.selector+" .social li[class*=pinterest]{display:"+config.networks.pinterest.display+"}"+config.selector+" .social li[class*=paper-plane]{display:"+config.networks.email.display+"}" }; var ShareUtils; if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") { Object.defineProperty(HTMLElement.prototype, "classList", { get: function() { var ret, self, update; update = function(fn) { return function(value) { var classes, index; classes = self.className.split(/\s+/); index = classes.indexOf(value); fn(classes, index, value); self.className = classes.join(" "); }; }; self = this; ret = { add: update(function(classes, index, value) { ~index || classes.push(value); }), remove: update(function(classes, index) { ~index && classes.splice(index, 1); }), toggle: update(function(classes, index, value) { if (~index) { classes.splice(index, 1); } else { classes.push(value); } }), contains: function(value) { return !!~self.className.split(/\s+/).indexOf(value); }, item: function(i) { return self.className.split(/\s+/)[i] || null; } }; Object.defineProperty(ret, "length", { get: function() { return self.className.split(/\s+/).length; } }); return ret; } }); } String.prototype.to_rfc3986 = function() { var tmp; tmp = encodeURIComponent(this); return tmp.replace(/[!'()*]/g, function(c) { return "%" + c.charCodeAt(0).toString(16); }); }; ShareUtils = (function() { function ShareUtils() {} ShareUtils.prototype.extend = function(to, from, overwrite) { var hasProp, prop; for (prop in from) { hasProp = to[prop] !== undefined; if (hasProp && typeof from[prop] === "object") { this.extend(to[prop], from[prop], overwrite); } else { if (overwrite || !hasProp) { to[prop] = from[prop]; } } } }; ShareUtils.prototype.hide = function(el) { return el.style.display = "none"; }; ShareUtils.prototype.show = function(el) { return el.style.display = "block"; }; ShareUtils.prototype.has_class = function(el, class_name) { return el.classList.contains(class_name); }; ShareUtils.prototype.add_class = function(el, class_name) { return el.classList.add(class_name); }; ShareUtils.prototype.remove_class = function(el, class_name) { return el.classList.remove(class_name); }; ShareUtils.prototype.is_encoded = function(str) { str = str.to_rfc3986(); return decodeURIComponent(str) !== str; }; ShareUtils.prototype.encode = function(str) { if (typeof str === "undefined" || this.is_encoded(str)) { return str; } else { return str.to_rfc3986(); } }; ShareUtils.prototype.popup = function(url, params) { var k, popup, qs, v; if (params == null) { params = {}; } popup = { width: 500, height: 350 }; popup.top = (screen.height / 2) - (popup.height / 2); popup.left = (screen.width / 2) - (popup.width / 2); qs = ((function() { var _results; _results = []; for (k in params) { v = params[k]; _results.push("" + k + "=" + (this.encode(v))); } return _results; }).call(this)).join('&'); if (qs) { qs = "?" + qs; } return window.open(url + qs, 'targetWindow', "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,left=" + popup.left + ",top=" + popup.top + ",width=" + popup.width + ",height=" + popup.height); }; return ShareUtils; })(); var Share, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; Share = (function(_super) { __extends(Share, _super); function Share(element, options) { this.element = element; this.el = { head: document.getElementsByTagName('head')[0], body: document.getElementsByTagName('body')[0] }; this.config = { enabled_networks: 0, protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//', url: window.location.href.replace("&", "%26"), caption: null, title: this.default_title(), image: this.default_image(), description: this.default_description(), ui: { flyout: 'top center', button_text: 'Share', button_font: true, icon_font: true }, networks: { twitter: { enabled: true, url: null, title: null, description: null }, facebook: { enabled: true, load_sdk: true, url: null, app_id: null, title: null, caption: null, description: null, image: null }, pinterest: { enabled: true, url: null, image: null, description: null }, reddit: { enabled: true, url: null, title: null }, linkedin: { enabled: true, url: null, title: null, description: null }, xing: { enabled: true, url: null, title: null, image: null, description: null }, whatsapp: { enabled: true, title: null, url: null }, email: { enabled: true, title: null, description: null, url: null } } }; this.setup(element, options); return this; } Share.prototype.setup = function(element, opts) { var index, instance, instances, _i, _len; instances = document.querySelectorAll(element); this.extend(this.config, opts, true); this.set_global_configuration(); this.normalize_network_configuration(); if (this.config.ui.icon_font) { this.inject_icons(); } if (this.config.ui.button_font) { this.inject_fonts(); } if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) { this.inject_facebook_sdk(); } for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) { instance = instances[index]; this.setup_instance(element, index); } }; Share.prototype.setup_instance = function(element, index) { var button, instance, label, network, networks, _i, _len, _results, _this = this; instance = document.querySelectorAll(element)[index]; this.hide(instance); this.add_class(instance, "sharer-" + index); instance = document.querySelectorAll(element)[index]; this.inject_css(instance); this.inject_html(instance); this.show(instance); label = instance.getElementsByTagName("label")[0]; button = instance.getElementsByClassName("social")[0]; networks = instance.getElementsByTagName('li'); this.add_class(button, "networks-" + this.config.enabled_networks); label.addEventListener("click", function() { return _this.event_toggle(button); }); _this = this; _results = []; for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) { network = networks[index]; _results.push(network.addEventListener("click", function() { _this.event_network(instance, this); return _this.event_close(button); })); } return _results; }; Share.prototype.event_toggle = function(button) { if (this.has_class(button, "active")) { return this.event_close(button); } else { return this.event_open(button); } }; Share.prototype.event_open = function(button) { if (this.has_class(button, "load")) { this.remove_class(button, "load"); } return this.add_class(button, "active"); }; Share.prototype.event_close = function(button) { return this.remove_class(button, "active"); }; Share.prototype.event_network = function(instance, network) { var name; name = network.getAttribute("data-network"); this.hook("before", name, instance); this["network_" + name](); return this.hook("after", name, instance); }; Share.prototype.open = function() { return this["public"]("open"); }; Share.prototype.close = function() { return this["public"]("close"); }; Share.prototype.toggle = function() { return this["public"]("toggle"); }; Share.prototype["public"] = function(action) { var button, index, instance, _i, _len, _ref, _results; _ref = document.querySelectorAll(this.element); _results = []; for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { instance = _ref[index]; button = instance.getElementsByClassName("social")[0]; _results.push(this["event_" + action](button)); } return _results; }; Share.prototype.network_facebook = function() { if (this.config.networks.facebook.load_sdk) { if (!window.FB) { return console.error("The Facebook JS SDK hasn't loaded yet."); } return FB.ui({ method: 'feed', name: this.config.networks.facebook.title, link: this.config.networks.facebook.url, picture: this.config.networks.facebook.image, caption: this.config.networks.facebook.caption, description: this.config.networks.facebook.description }); } else { return this.popup('https://www.facebook.com/sharer/sharer.php', { u: this.config.networks.facebook.url }); } }; Share.prototype.network_twitter = function() { return this.popup('https://twitter.com/intent/tweet', { text: this.config.networks.twitter.title, url: this.config.networks.twitter.url }); }; Share.prototype.network_pinterest = function() { return this.popup('https://www.pinterest.com/pin/create/button', { url: this.config.networks.pinterest.url, media: this.config.networks.pinterest.image, description: this.config.networks.pinterest.description }); }; Share.prototype.network_linkedin = function() { return this.popup('https://www.linkedin.com/shareArticle', { url: this.config.networks.linkedin.url, title: this.config.networks.linkedin.title, summary: this.config.networks.linkedin.description }); } Share.prototype.network_xing = function() { return this.popup('https://www.xing.com/spi/shares/new', { url: this.config.networks.xing.url, image: this.config.networks.xing.image, title: this.config.networks.xing.title, summary: this.config.networks.xing.description }); } Share.prototype.network_whatsapp = function() { return this.popup('https://api.whatsapp.com/send', { text: this.config.networks.whatsapp.title + '%20' + this.config.networks.whatsapp.url, }); } Share.prototype.network_email = function() { return this.popup('mailto:', { subject: this.config.networks.email.title, body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description, }); }; Share.prototype.inject_icons = function() { // return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css"); }; Share.prototype.inject_fonts = function() { // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text); }; Share.prototype.inject_stylesheet = function(url) { var link; if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) { link = document.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("href", url); return this.el.head.appendChild(link); } }; Share.prototype.inject_css = function(instance) { var css, meta, selector, style; selector = "." + (instance.getAttribute('class').split(" ").join(".")); if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) { this.config.selector = selector; css = getStyles(this.config); style = document.createElement("style"); style.type = "text/css"; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } this.el.head.appendChild(style); delete this.config.selector; meta = document.createElement("meta"); meta.setAttribute("name", "sharer" + selector); return this.el.head.appendChild(meta); } }; Share.prototype.inject_html = function(instance) { //return instance.innerHTML = ""; return instance.innerHTML = ""; }; Share.prototype.inject_facebook_sdk = function() { var fb_root, script; if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) { script = document.createElement("script"); script.text = "window.fbAsyncInit=function(){FB.init({appId:'" + this.config.networks.facebook.app_id + "',status:true,xfbml:true})};(function(e,t,n){var r,i=e.getElementsByTagName(t)[0];if(e.getElementById(n)){return}r=e.createElement(t);r.id=n;r.src='" + this.config.protocol + "connect.facebook.net/en_US/all.js';i.parentNode.insertBefore(r,i)})(document,'script','facebook-jssdk')"; fb_root = document.createElement("div"); fb_root.id = "fb-root"; this.el.body.appendChild(fb_root); return this.el.body.appendChild(script); } }; Share.prototype.hook = function(type, network, instance) { var fn, opts; fn = this.config.networks[network][type]; if (typeof fn === "function") { opts = fn.call(this.config.networks[network], instance); if (opts !== void 0) { opts = this.normalize_filter_config_updates(opts); this.extend(this.config.networks[network], opts, true); this.normalize_network_configuration(); } } }; Share.prototype.default_title = function() { var content; if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) { return encodeURIComponent(content.getAttribute('content')); } else if (content = document.querySelector('title')) { return encodeURIComponent(content.innerText); } }; Share.prototype.default_image = function() { var content; if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) { return content.getAttribute('content'); } }; Share.prototype.default_description = function() { var content; if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) { return encodeURIComponent(content.getAttribute('content')); } else { return ''; } }; Share.prototype.set_global_configuration = function() { var display, network, option, options, _ref, _results; _ref = this.config.networks; _results = []; for (network in _ref) { options = _ref[network]; for (option in options) { if (this.config.networks[network][option] == null) { this.config.networks[network][option] = this.config[option]; } } if (this.config.networks[network].enabled) { display = 'block'; this.config.enabled_networks += 1; } else { display = 'none'; } _results.push(this.config.networks[network].display = display); } return _results; }; Share.prototype.normalize_network_configuration = function() { if (!this.config.networks.facebook.app_id) { this.config.networks.facebook.load_sdk = false; } if (!this.is_encoded(this.config.networks.twitter.description)) { this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description); } if (typeof this.config.networks.facebook.app_id === 'number') { return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString(); } }; Share.prototype.normalize_filter_config_updates = function(opts) { if (this.config.networks.facebook.app_id !== opts.app_id) { console.warn("You are unable to change the Facebook app_id after the button has been initialized. Please-in-out update your Facebook filters accordingly."); delete opts.app_id; } if (this.config.networks.facebook.load_sdk !== opts.load_sdk) { console.warn("You are unable to change the Facebook load_sdk option after the button has been initialized. Please-in-out update your Facebook filters accordingly."); delete opts.app_id; } return opts; }; return Share; })(ShareUtils); return Share; }); // Generated by CoffeeScript 1.9.2 // @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net (function() { var $, win; $ = this.jQuery || window.jQuery; win = $(window); $.fn.stick_in_parent = function(opts) { var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class; if (opts == null) { opts = {}; } sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming; if (offset_top == null) { offset_top = 0; } if (parent_selector == null) { parent_selector = void 0; } if (inner_scrolling == null) { inner_scrolling = true; } if (sticky_class == null) { sticky_class = "is_stuck"; } doc = $(document); if (enable_bottoming == null) { enable_bottoming = true; } outer_width = function(el) { var _el, computed, w; if (window.getComputedStyle) { _el = el[0]; computed = window.getComputedStyle(el[0]); w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right")); if (computed.getPropertyValue("box-sizing") !== "border-box") { w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right")); } return w; } else { return el.outerWidth(true); } }; fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) { var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick; if (elm.data("sticky_kit")) { return; } elm.data("sticky_kit", true); last_scroll_height = doc.height(); parent = elm.parent(); if (parent_selector != null) { parent = parent.closest(parent_selector); } if (!parent.length) { throw "failed to find stick parent"; } fixed = false; bottomed = false; spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("
    "); if (spacer) { spacer.css('position', elm.css('position')); } recalc = function() { var border_top, padding_top, restore; if (detached) { return; } last_scroll_height = doc.height(); border_top = parseInt(parent.css("border-top-width"), 10); padding_top = parseInt(parent.css("padding-top"), 10); padding_bottom = parseInt(parent.css("padding-bottom"), 10); parent_top = parent.offset().top + border_top + padding_top; parent_height = parent.height(); if (fixed) { fixed = false; bottomed = false; if (manual_spacer == null) { elm.insertAfter(spacer); spacer.detach(); } elm.css({ position: "", top: "", width: "", bottom: "" }).removeClass(sticky_class); restore = true; } top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top; height = elm.outerHeight(true); el_float = elm.css("float"); if (spacer) { spacer.css({ width: outer_width(elm), height: height, display: elm.css("display"), "vertical-align": elm.css("vertical-align"), "float": el_float }); } if (restore) { return tick(); } }; recalc(); if (height === parent_height) { return; } last_pos = void 0; offset = offset_top; recalc_counter = recalc_every; tick = function() { var css, delta, recalced, scroll, will_bottom, win_height; if (detached) { return; } recalced = false; if (recalc_counter != null) { recalc_counter -= 1; if (recalc_counter <= 0) { recalc_counter = recalc_every; recalc(); recalced = true; } } if (!recalced && doc.height() !== last_scroll_height) { recalc(); recalced = true; } scroll = win.scrollTop(); if (last_pos != null) { delta = scroll - last_pos; } last_pos = scroll; if (fixed) { if (enable_bottoming) { will_bottom = scroll + height + offset > parent_height + parent_top; if (bottomed && !will_bottom) { bottomed = false; elm.css({ position: "fixed", bottom: "", top: offset }).trigger("sticky_kit:unbottom"); } } if (scroll < top) { fixed = false; offset = offset_top; if (manual_spacer == null) { if (el_float === "left" || el_float === "right") { elm.insertAfter(spacer); } spacer.detach(); } css = { position: "", width: "", top: "" }; elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick"); } if (inner_scrolling) { win_height = win.height(); if (height + offset_top > win_height) { if (!bottomed) { offset -= delta; offset = Math.max(win_height - height, offset); offset = Math.min(offset_top, offset); if (fixed) { elm.css({ top: offset + "px" }); } } } } } else { if (scroll > top) { fixed = true; css = { position: "fixed", top: offset }; css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px"; elm.css(css).addClass(sticky_class); if (manual_spacer == null) { elm.after(spacer); if (el_float === "left" || el_float === "right") { spacer.append(elm); } } elm.trigger("sticky_kit:stick"); } } if (fixed && enable_bottoming) { if (will_bottom == null) { will_bottom = scroll + height + offset > parent_height + parent_top; } if (!bottomed && will_bottom) { bottomed = true; if (parent.css("position") === "static") { parent.css({ position: "relative" }); } return elm.css({ position: "absolute", bottom: padding_bottom, top: "auto" }).trigger("sticky_kit:bottom"); } } }; recalc_and_tick = function() { recalc(); return tick(); }; detach = function() { detached = true; win.off("touchmove", tick); win.off("scroll", tick); win.off("resize", recalc_and_tick); $(document.body).off("sticky_kit:recalc", recalc_and_tick); elm.off("sticky_kit:detach", detach); elm.removeData("sticky_kit"); elm.css({ position: "", bottom: "", top: "", width: "" }); parent.position("position", ""); if (fixed) { if (manual_spacer == null) { if (el_float === "left" || el_float === "right") { elm.insertAfter(spacer); } spacer.remove(); } return elm.removeClass(sticky_class); } }; win.on("touchmove", tick); win.on("scroll", tick); win.on("resize", recalc_and_tick); $(document.body).on("sticky_kit:recalc", recalc_and_tick); elm.on("sticky_kit:detach", detach); return setTimeout(tick, 0); }; for (i = 0, len = this.length; i < len; i++) { elm = this[i]; fn($(elm)); } return this; }; }).call(this); /* ========================================================================== * bootstrap-tab-history.js * Author: Michael Narayan * Repository: https://github.com/mnarayan01/bootstrap-tab-history/ * ========================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ========================================================================== */ /* ========================================================================== */ /* JSHint directives */ /* */ /* global BootstrapTabHistory: true */ /* */ /* global document */ /* global jQuery */ /* global history */ /* global window */ /* ========================================================================== */ /** * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history) * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set * the `data-tab-history` attribute to true (or a string denoting a tab grouping). * * See the README for additional information. * * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes. */ BootstrapTabHistory = { options: { /** * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true. * * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`. * * @public * @type {?number} */ defaultAnchorYOffset: 0, /** * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp. * * May be overriden on a per-element basis by the attribute `data-tab-history-changer`. * * @public * @type {string} */ defaultChanger: 'replace', /** * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise, * `null` is passed as the third parameter to these calls. * * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`. * * @public * @type {boolean} */ defaultUpdateURL: false, /** * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page * load. * * @public * @type {boolean} */ showTabsBasedOnAnchor: true } }; (function () { 'use strict'; jQuery(function () { if(history && history.pushState && history.replaceState) { var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; if(bootstrapTabHistory) { showTabsBasedOnState(bootstrapTabHistory); } else { showTabsBasedOnAnchor(); } backfillHistoryState(); jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab); jQuery(window).on('popstate', onPopState); } else { showTabsBasedOnAnchor(); } }); /** * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState. * * @type {boolean} */ var showingTabsBasedOnState = false; /** * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper * `history.back` handling when `data-tab-history-update-url` is true. */ function backfillHistoryState() { var newState = null; jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode var $activeTabElement = jQuery(this); var selector = getTabSelector($activeTabElement); if(selector) { var tabGroup = getTabGroup($activeTabElement); if(tabGroup) { newState = createNewHistoryState(newState || history.state, tabGroup, selector); } } }); if(newState) { history.replaceState(newState, '', null); } } /** * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to * said bootstrapTabHistory attribute. * * @param {?object} existingState * @param {!string} tabGroup * @param {!string} selector * @returns {!object} */ function createNewHistoryState(existingState, tabGroup, selector) { // Clone history.state and ensure it has a bootstrapTabHistory entry. var newState = jQuery.extend(true, {}, existingState, { bootstrapTabHistory: {} }); newState.bootstrapTabHistory[tabGroup] = selector; return newState; } /** * @param {jQuery} $tab * @returns {?string} */ function getTabGroup($tab) { return parseTruthyAttributeValue($tab.data('tab-history')); } /** * @param {jQuery} $tab * @returns {?string} */ function getTabSelector($tab) { return $tab.data('target') || $tab.attr('href'); } /** * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate. * * @param {jQuery.Event} shownEvt */ function onShownTab(shownEvt) { if(!showingTabsBasedOnState) { var $activatedTab = jQuery(shownEvt.target); if ( $activatedTab.hasClass('panel-collapse') ) $activatedTab = $activatedTab.closest('.panel').find('a'); var selector = getTabSelector($activatedTab); if(selector) { var tabGroup = getTabGroup($activatedTab); if(tabGroup) { var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger; var newState = createNewHistoryState(history.state, tabGroup, selector); var updateURL = (function ($activatedTab) { if(selector[0] === '#') { var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url')); if(elementUpdateURLOption === undefined) { return BootstrapTabHistory.options.defaultUpdateURL; } else { return elementUpdateURLOption; } } else { return false; } })($activatedTab); switch(historyChanger) { case 'push': history.pushState(newState, '', updateURL ? selector : null); break; case 'replace': history.replaceState(newState, '', updateURL ? selector : null); break; default: throw new Error('Unknown tab-history-changer: ' + historyChanger); } } } } } /** * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate. */ function onPopState() { var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory; if(bootstrapTabHistory) { showTabsBasedOnState(bootstrapTabHistory); } } /** * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned. * * Rationale: HAML data attributes which are set to `true` are rendered as a blank string. * * @param {*} value * @returns {*} */ function parseTruthyAttributeValue(value) { if(value) { return value; } else if(value === '') { return true; } else { return value; } } /** * Show tabs based upon the anchor component of `window.location`. */ function showTabsBasedOnAnchor() { if(BootstrapTabHistory.options.showTabsBasedOnAnchor) { var anchor = window.location && window.location.hash; if(anchor) { var $tabElement = showTabForSelector(anchor); if($tabElement && window.addEventListener && window.removeEventListener) { var anchorYOffset = (function ($tabElement) { var elementSetting = $tabElement.data('tab-history-anchor-y-offset'); if(elementSetting === undefined) { return BootstrapTabHistory.options.defaultAnchorYOffset; } else { return elementSetting; } })($tabElement); // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get // here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the // `history.state` object should have been used (unless the browser did not support the modern History API). if(anchorYOffset || anchorYOffset === 0) { var scrollListener = function resetAnchorScroll () { window.removeEventListener('scroll', scrollListener); window.scrollTo(0, anchorYOffset); }; window.addEventListener('scroll', scrollListener); } } } } } /** * Show a tab which corresponds to the provided selector. * * @param {string} selector - A CSS selector. * @returns {?jQuery} - The tab which was found to show (even if said tab was already active). */ function showTabForSelector(selector) { var $tabElement = (function (selector) { var $ret = null; jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () { var $potentialTab = jQuery(this); if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) { $ret = $potentialTab; return false; } else { return null; } }); return $ret; })(selector); if($tabElement) { if ( !$tabElement.parent().hasClass('active') ) { $tabElement.trigger('click'); } //$tabElement.tab('show'); } return $tabElement; } /** * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors. * * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant. */ function showTabsBasedOnState(bootstrapTabHistory) { showingTabsBasedOnState = true; try { for(var k in bootstrapTabHistory) { if(bootstrapTabHistory.hasOwnProperty(k)) { showTabForSelector(bootstrapTabHistory[k]); } } } finally { showingTabsBasedOnState = false; } } })(); /*! * justifiedGallery - v3.8.1 * http://miromannino.github.io/Justified-Gallery/ * Copyright (c) 2020 Miro Mannino * Licensed under the MIT license. */ (function (factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], factory); } else if (typeof module === 'object' && module.exports) { // Node/CommonJS module.exports = function (root, jQuery) { if (jQuery === undefined) { // require('jQuery') returns a factory that requires window to // build a jQuery instance, we normalize how we use modules // that require this pattern but the window provided is a noop // if it's defined (how jquery works) if (typeof window !== 'undefined') { jQuery = require('jquery'); } else { jQuery = require('jquery')(root); } } factory(jQuery); return jQuery; }; } else { // Browser globals factory(jQuery); } }(function ($) { /** * Justified Gallery controller constructor * * @param $gallery the gallery to build * @param settings the settings (the defaults are in JustifiedGallery.defaults) * @constructor */ var JustifiedGallery = function ($gallery, settings) { this.settings = settings; this.checkSettings(); this.imgAnalyzerTimeout = null; this.entries = null; this.buildingRow = { entriesBuff: [], width: 0, height: 0, aspectRatio: 0 }; this.lastFetchedEntry = null; this.lastAnalyzedIndex = -1; this.yield = { every: 2, // do a flush every n flushes (must be greater than 1) flushed: 0 // flushed rows without a yield }; this.border = settings.border >= 0 ? settings.border : settings.margins; this.maxRowHeight = this.retrieveMaxRowHeight(); this.suffixRanges = this.retrieveSuffixRanges(); this.offY = this.border; this.rows = 0; this.spinner = { phase: 0, timeSlot: 150, $el: $('
    '), intervalId: null }; this.scrollBarOn = false; this.checkWidthIntervalId = null; this.galleryWidth = $gallery.width(); this.$gallery = $gallery; }; /** @returns {String} the best suffix given the width and the height */ JustifiedGallery.prototype.getSuffix = function (width, height) { var longestSide, i; longestSide = (width > height) ? width : height; for (i = 0; i < this.suffixRanges.length; i++) { if (longestSide <= this.suffixRanges[i]) { return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; } } return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; }; /** * Remove the suffix from the string * * @returns {string} a new string without the suffix */ JustifiedGallery.prototype.removeSuffix = function (str, suffix) { return str.substring(0, str.length - suffix.length); }; /** * @returns {boolean} a boolean to say if the suffix is contained in the str or not */ JustifiedGallery.prototype.endsWith = function (str, suffix) { return str.indexOf(suffix, str.length - suffix.length) !== -1; }; /** * Get the used suffix of a particular url * * @param str * @returns {String} return the used suffix */ JustifiedGallery.prototype.getUsedSuffix = function (str) { for (var si in this.settings.sizeRangeSuffixes) { if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { if (this.settings.sizeRangeSuffixes[si].length === 0) continue; if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; } } return ''; }; /** * Given an image src, with the width and the height, returns the new image src with the * best suffix to show the best quality thumbnail. * * @returns {String} the suffix to use */ JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) { var newImageSrc; if (this.settings.thumbnailPath) { newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image); } else { var matchRes = imageSrc.match(this.settings.extension); var ext = (matchRes !== null) ? matchRes[0] : ''; newImageSrc = imageSrc.replace(this.settings.extension, ''); newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc)); newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; } return newImageSrc; }; /** * Shows the images that is in the given entry * * @param $entry the entry * @param callback the callback that is called when the show animation is finished */ JustifiedGallery.prototype.showImg = function ($entry, callback) { if (this.settings.cssAnimation) { $entry.addClass('jg-entry-visible'); if (callback) callback(); } else { $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); $entry.find(this.settings.imgSelector).stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); } }; /** * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. * * @param $image the image to analyze * @returns {String} the extracted src */ JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { var imageSrc = $image.data('safe-src'); var imageSrcLoc = 'data-safe-src'; // Begin Uncode edit if (typeof imageSrc === 'undefined') { var imageCurrentSrc = $image[0].currentSrc; if (imageCurrentSrc) { imageSrc = imageCurrentSrc; } else { imageSrc = $image.attr('src'); } imageSrcLoc = 'src'; } // End Uncode edit $image.data('jg.originalSrc', imageSrc); // this is saved for the destroy method $image.data('jg.src', imageSrc); // this will change overtime $image.data('jg.originalSrcLoc', imageSrcLoc); // this is saved for the destroy method return imageSrc; }; /** @returns {jQuery} the image in the given entry */ JustifiedGallery.prototype.imgFromEntry = function ($entry) { var $img = $entry.find(this.settings.imgSelector); if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode return $img.length === 0 ? null : $img; }; /** @returns {jQuery} the caption in the given entry */ JustifiedGallery.prototype.captionFromEntry = function ($entry) { var $caption = $entry.find('> .jg-caption'); return $caption.length === 0 ? null : $caption; }; /** * Display the entry * * @param {jQuery} $entry the entry to display * @param {int} x the x position where the entry must be positioned * @param y the y position where the entry must be positioned * @param imgWidth the image width * @param imgHeight the image height * @param rowHeight the row height of the row that owns the entry */ JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { $entry.width(imgWidth); $entry.height(Math.floor(rowHeight));//hacked by Uncode $entry.css('top', Math.floor(y));//hacked by Uncode $entry.css('left', x); var $image = this.imgFromEntry($entry); if ($image !== null) { $image.css('width', imgWidth); $image.css('height', imgHeight); $image.css('margin-left', - imgWidth / 2); $image.css('margin-top', - imgHeight / 2); // Image reloading for an high quality of thumbnails var imageSrc = $image.data('jg.src'); if (imageSrc) { imageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]); $image.one('error', function () { this.resetImgSrc($image); //revert to the original thumbnail }); var loadNewImage = function () { // if (imageSrc !== newImageSrc) { $image.attr('src', imageSrc); // } }; if ($entry.data('jg.loaded') === 'skipped' && imageSrc) { this.onImageEvent(imageSrc, (function() { this.showImg($entry, loadNewImage); //load the new image after the fadeIn $entry.data('jg.loaded', true); }).bind(this)); } else { this.showImg($entry, loadNewImage); //load the new image after the fadeIn } } } else { this.showImg($entry); } this.displayEntryCaption($entry); }; /** * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' * or the 'title' attributes. * * @param {jQuery} $entry the entry to process */ JustifiedGallery.prototype.displayEntryCaption = function ($entry) { var $image = this.imgFromEntry($entry); if ($image !== null && this.settings.captions) { var $imgCaption = this.captionFromEntry($entry); // Create it if it doesn't exists if ($imgCaption === null) { var caption = $image.attr('alt'); if (!this.isValidCaption(caption)) caption = $entry.attr('title'); if (this.isValidCaption(caption)) { // Create only we found something $imgCaption = $('
    ' + caption + '
    '); $entry.append($imgCaption); $entry.data('jg.createdCaption', true); } } // Create events (we check again the $imgCaption because it can be still inexistent) if ($imgCaption !== null) { if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); this.addCaptionEventsHandlers($entry); } } else { this.removeCaptionEventsHandlers($entry); } }; /** * Validates the caption * * @param caption The caption that should be validated * @return {boolean} Validation result */ JustifiedGallery.prototype.isValidCaption = function (caption) { return (typeof caption !== 'undefined' && caption.length > 0); }; /** * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. * It shows the caption using jQuery (or using CSS if it is configured so) * * @param {Event} eventObject the event object */ JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { var $caption = this.captionFromEntry($(eventObject.currentTarget)); if (this.settings.cssAnimation) { $caption.addClass('jg-caption-visible').removeClass('jg-caption-hidden'); } else { $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, this.settings.captionSettings.visibleOpacity); } }; /** * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. * It hides the caption using jQuery (or using CSS if it is configured so) * * @param {Event} eventObject the event object */ JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { var $caption = this.captionFromEntry($(eventObject.currentTarget)); if (this.settings.cssAnimation) { $caption.removeClass('jg-caption-visible').removeClass('jg-caption-hidden'); } else { $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, this.settings.captionSettings.nonVisibleOpacity); } }; /** * Add the handlers of the entry for the caption * * @param $entry the entry to modify */ JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { var captionMouseEvents = $entry.data('jg.captionMouseEvents'); if (typeof captionMouseEvents === 'undefined') { captionMouseEvents = { mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) }; $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); $entry.data('jg.captionMouseEvents', captionMouseEvents); } }; /** * Remove the handlers of the entry for the caption * * @param $entry the entry to modify */ JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { var captionMouseEvents = $entry.data('jg.captionMouseEvents'); if (typeof captionMouseEvents !== 'undefined') { $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); $entry.removeData('jg.captionMouseEvents'); } }; /** * Clear the building row data to be used for a new row */ JustifiedGallery.prototype.clearBuildingRow = function () { this.buildingRow.entriesBuff = []; this.buildingRow.aspectRatio = 0; this.buildingRow.width = 0; }; /** * Justify the building row, preparing it to * * @param isLastRow * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row. * @returns a boolean to know if the row has been justified or not */ JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow, hiddenRow) { var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; var minHeight = 0; var availableWidth = this.galleryWidth - 2 * this.border - ( (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode var defaultRowHeight = this.settings.rowHeight; var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; //Skip the last row if we can't justify it and the lastRow == 'hide' if (hiddenRow || (isLastRow && this.settings.lastRow === 'hide' && !justifiable)) { for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { $entry = this.buildingRow.entriesBuff[i]; if (this.settings.cssAnimation) $entry.removeClass('jg-entry-visible'); else { $entry.stop().fadeTo(0, 0.1); $entry.find('> img, > a > img').fadeTo(0, 0); } } return -1; } // With lastRow = nojustify, justify if is justificable (the images will not become too big) if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') { justify = false; if (this.rows > 0) { defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows; justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold; } } for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { $entry = this.buildingRow.entriesBuff[i]; imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); if (justify) { newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; newImgH = rowHeight; } else { newImgW = defaultRowHeight * imgAspectRatio; newImgH = defaultRowHeight; } availableWidth -= Math.round(newImgW); $entry.data('jg.jwidth', Math.round(newImgW)); $entry.data('jg.jheight', Math.ceil(newImgH)); if (i === 0 || minHeight > newImgH) minHeight = newImgH; } this.buildingRow.height = minHeight; return justify; }; /** * Flush a row: justify it, modify the gallery height accordingly to the row height * * @param isLastRow * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row. */ JustifiedGallery.prototype.flushRow = function (isLastRow, hiddenRow) { var settings = this.settings; var $entry, buildingRowRes, offX = this.border, i; buildingRowRes = this.prepareBuildingRow(isLastRow, hiddenRow); if (hiddenRow || (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1)) { this.clearBuildingRow(); return; } if (this.maxRowHeight) { if (this.maxRowHeight < this.buildingRow.height) this.buildingRow.height = this.maxRowHeight; } //Align last (unjustified) row if (isLastRow && (settings.lastRow === 'center' || settings.lastRow === 'right')) { var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins; for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { $entry = this.buildingRow.entriesBuff[i]; availableWidth -= $entry.data('jg.jwidth'); } if (settings.lastRow === 'center') offX += Math.round(availableWidth / 2); else if (settings.lastRow === 'right') offX += availableWidth; } var lastEntryIdx = this.buildingRow.entriesBuff.length - 1; for (i = 0; i <= lastEntryIdx; i++) { $entry = this.buildingRow.entriesBuff[this.settings.rtl ? lastEntryIdx - i : i]; this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height); offX += $entry.data('jg.jwidth') + settings.margins; } //Gallery Height this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border; this.setGalleryTempHeight(this.galleryHeightToSet + this.getSpinnerHeight()); if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) { //Ready for a new row this.offY += this.buildingRow.height + settings.margins; this.rows += 1; this.clearBuildingRow(); this.settings.triggerEvent.call(this, 'jg.rowflush'); } }; // Scroll position not restoring: https://github.com/miromannino/Justified-Gallery/issues/221 var galleryPrevStaticHeight = 0; JustifiedGallery.prototype.rememberGalleryHeight = function () { galleryPrevStaticHeight = this.$gallery.height(); this.$gallery.height(galleryPrevStaticHeight); }; // grow only JustifiedGallery.prototype.setGalleryTempHeight = function (height) { galleryPrevStaticHeight = Math.max(height, galleryPrevStaticHeight); this.$gallery.height(galleryPrevStaticHeight); }; JustifiedGallery.prototype.setGalleryFinalHeight = function (height) { galleryPrevStaticHeight = height; this.$gallery.height(height); }; /** * Checks the width of the gallery container, to know if a new justification is needed */ JustifiedGallery.prototype.checkWidth = function () { this.checkWidthIntervalId = setInterval($.proxy(function () { // if the gallery is not currently visible, abort. if (!this.$gallery.is(":visible")) return; var galleryWidth = parseFloat(this.$gallery.width()); if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) { this.galleryWidth = galleryWidth; this.rewind(); this.rememberGalleryHeight(); // Restart to analyze this.startImgAnalyzer(true); } }, this), this.settings.refreshTime); }; /** * @returns {boolean} a boolean saying if the spinner is active or not */ JustifiedGallery.prototype.isSpinnerActive = function () { return this.spinner.intervalId !== null; }; /** * @returns {int} the spinner height */ JustifiedGallery.prototype.getSpinnerHeight = function () { return this.spinner.$el.innerHeight(); }; /** * Stops the spinner animation and modify the gallery height to exclude the spinner */ JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { clearInterval(this.spinner.intervalId); this.spinner.intervalId = null; this.setGalleryTempHeight(this.$gallery.height() - this.getSpinnerHeight()); this.spinner.$el.detach(); }; /** * Starts the spinner animation */ JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { var spinnerContext = this.spinner; var $spinnerPoints = spinnerContext.$el.find('span'); clearInterval(spinnerContext.intervalId); this.$gallery.append(spinnerContext.$el); this.setGalleryTempHeight(this.offY + this.buildingRow.height + this.getSpinnerHeight()); spinnerContext.intervalId = setInterval(function () { if (spinnerContext.phase < $spinnerPoints.length) { $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); } else { $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); } spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); }, spinnerContext.timeSlot); }; /** * Rewind the image analysis to start from the first entry. */ JustifiedGallery.prototype.rewind = function () { this.lastFetchedEntry = null; this.lastAnalyzedIndex = -1; this.offY = this.border; this.rows = 0; this.clearBuildingRow(); }; /** * @returns {String} `settings.selector` rejecting spinner element */ JustifiedGallery.prototype.getSelectorWithoutSpinner = function () { return this.settings.selector + ', div:not(.jg-spinner)'; }; /** * @returns {Array} all entries matched by `settings.selector` */ JustifiedGallery.prototype.getAllEntries = function () { var selector = this.getSelectorWithoutSpinner(); return this.$gallery.children(selector).toArray(); }; /** * Update the entries searching it from the justified gallery HTML element * * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) * @returns {boolean} true if some entries has been founded */ JustifiedGallery.prototype.updateEntries = function (norewind) { var newEntries; if (norewind && this.lastFetchedEntry != null) { var selector = this.getSelectorWithoutSpinner(); newEntries = $(this.lastFetchedEntry).nextAll(selector).toArray(); } else { this.entries = []; newEntries = this.getAllEntries(); } if (newEntries.length > 0) { // Sort or randomize if ($.isFunction(this.settings.sort)) { newEntries = this.sortArray(newEntries); } else if (this.settings.randomize) { newEntries = this.shuffleArray(newEntries); } this.lastFetchedEntry = newEntries[newEntries.length - 1]; // Filter if (this.settings.filter) { newEntries = this.filterArray(newEntries); } else { this.resetFilters(newEntries); } } this.entries = this.entries.concat(newEntries); return true; }; /** * Apply the entries order to the DOM, iterating the entries and appending the images * * @param entries the entries that has been modified and that must be re-ordered in the DOM */ JustifiedGallery.prototype.insertToGallery = function (entries) { var that = this; $.each(entries, function () { $(this).appendTo(that.$gallery); }); }; /** * Shuffle the array using the Fisher-Yates shuffle algorithm * * @param a the array to shuffle * @return the shuffled array */ JustifiedGallery.prototype.shuffleArray = function (a) { var i, j, temp; for (i = a.length - 1; i > 0; i--) { j = Math.floor(Math.random() * (i + 1)); temp = a[i]; a[i] = a[j]; a[j] = temp; } this.insertToGallery(a); return a; }; /** * Sort the array using settings.comparator as comparator * * @param a the array to sort (it is sorted) * @return the sorted array */ JustifiedGallery.prototype.sortArray = function (a) { a.sort(this.settings.sort); this.insertToGallery(a); return a; }; /** * Reset the filters removing the 'jg-filtered' class from all the entries * * @param a the array to reset */ JustifiedGallery.prototype.resetFilters = function (a) { for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); }; /** * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. * * @param a the array to filter * @return the filtered array */ JustifiedGallery.prototype.filterArray = function (a) { var settings = this.settings; if ($.type(settings.filter) === 'string') { // Filter only keeping the entries passed in the string return a.filter(function (el) { var $el = $(el); if ($el.is(settings.filter)) { $el.removeClass('jg-filtered'); return true; } else { $el.addClass('jg-filtered').removeClass('jg-visible'); return false; } }); } else if ($.isFunction(settings.filter)) { // Filter using the passed function var filteredArr = a.filter(settings.filter); for (var i = 0; i < a.length; i++) { if (filteredArr.indexOf(a[i]) === -1) { $(a[i]).addClass('jg-filtered').removeClass('jg-visible'); } else { $(a[i]).removeClass('jg-filtered'); } } return filteredArr; } }; /** * Revert the image src to the default value. */ JustifiedGallery.prototype.resetImgSrc = function ($img) { if ($img.data('jg.originalSrcLoc') === 'src') { $img.attr('src', $img.data('jg.originalSrc')); } else { $img.attr('src', ''); } }; /** * Destroy the Justified Gallery instance. * * It clears all the css properties added in the style attributes. We doesn't backup the original * values for those css attributes, because it costs (performance) and because in general one * shouldn't use the style attribute for an uniform set of images (where we suppose the use of * classes). Creating a backup is also difficult because JG could be called multiple times and * with different style attributes. */ JustifiedGallery.prototype.destroy = function () { clearInterval(this.checkWidthIntervalId); this.stopImgAnalyzerStarter(); // Get fresh entries list since filtered entries are absent in `this.entries` $.each(this.getAllEntries(), $.proxy(function (_, entry) { var $entry = $(entry); // Reset entry style $entry.css('width', ''); $entry.css('height', ''); $entry.css('top', ''); $entry.css('left', ''); $entry.data('jg.loaded', undefined); $entry.removeClass('jg-entry jg-filtered jg-entry-visible'); // Reset image style var $img = this.imgFromEntry($entry); if ($img) { $img.css('width', ''); $img.css('height', ''); $img.css('margin-left', ''); $img.css('margin-top', ''); this.resetImgSrc($img); $img.data('jg.originalSrc', undefined); $img.data('jg.originalSrcLoc', undefined); $img.data('jg.src', undefined); } // Remove caption this.removeCaptionEventsHandlers($entry); var $caption = this.captionFromEntry($entry); if ($entry.data('jg.createdCaption')) { // remove also the caption element (if created by jg) $entry.data('jg.createdCaption', undefined); if ($caption !== null) $caption.remove(); } else { if ($caption !== null) $caption.fadeTo(0, 1); } }, this)); this.$gallery.css('height', ''); this.$gallery.removeClass('justified-gallery'); this.$gallery.data('jg.controller', undefined); this.settings.triggerEvent.call(this, 'jg.destroy'); }; /** * Analyze the images and builds the rows. It returns if it found an image that is not loaded. * * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end */ JustifiedGallery.prototype.analyzeImages = function (isForResize) { for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { var $entry = $(this.entries[i]); if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { var availableWidth = this.galleryWidth - 2 * this.border - ( (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); this.buildingRow.entriesBuff.push($entry); this.buildingRow.aspectRatio += imgAspectRatio; this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; this.lastAnalyzedIndex = i; if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { this.flushRow(false, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount); if (++this.yield.flushed >= this.yield.every) { this.startImgAnalyzer(isForResize); return; } } } else if ($entry.data('jg.loaded') !== 'error') { return; } } // Last row flush (the row is not full) if (this.buildingRow.entriesBuff.length > 0) { this.flushRow(true, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount); } if (this.isSpinnerActive()) { this.stopLoadingSpinnerAnimation(); } /* Stop, if there is, the timeout to start the analyzeImages. This is because an image can be set loaded, and the timeout can be set, but this image can be analyzed yet. */ this.stopImgAnalyzerStarter(); this.setGalleryFinalHeight(this.galleryHeightToSet); //On complete callback this.settings.triggerEvent.call(this, isForResize ? 'jg.resize' : 'jg.complete'); }; /** * Stops any ImgAnalyzer starter (that has an assigned timeout) */ JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { this.yield.flushed = 0; if (this.imgAnalyzerTimeout !== null) { clearTimeout(this.imgAnalyzerTimeout); this.imgAnalyzerTimeout = null; } }; /** * Starts the image analyzer. It is not immediately called to let the browser to update the view * * @param isForResize specifies if the image analyzer must be called for resizing or not */ JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { var that = this; this.stopImgAnalyzerStarter(); this.imgAnalyzerTimeout = setTimeout(function () { that.analyzeImages(isForResize); }, 0.001); // we can't start it immediately due to a IE different behaviour }; /** * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, * because some browsers, with a 404 set complete = true. * * @param imageSrc the image src to load * @param onLoad callback that is called when the image has been loaded * @param onError callback that is called in case of an error */ JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { if (!onLoad && !onError) return; var memImage = new Image(); var $memImage = $(memImage); if (onLoad) { $memImage.one('load', function () { $memImage.off('load error'); onLoad(memImage); }); } if (onError) { $memImage.one('error', function () { $memImage.off('load error'); onError(memImage); }); } memImage.src = imageSrc; }; /** * Init of Justified Gallery controlled * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) */ JustifiedGallery.prototype.init = function () { var imagesToLoad = false, skippedImages = false, that = this; $.each(this.entries, function (index, entry) { var $entry = $(entry); var $image = that.imgFromEntry($entry); $entry.addClass('jg-entry'); if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { // Link Rel global overwrite if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); // Link Target global overwrite if (that.settings.target !== null) $entry.attr('target', that.settings.target); if ($image !== null) { // Image src var imageSrc = that.extractImgSrcFromImage($image); /* If we have the height and the width, we don't wait that the image is loaded, but we start directly with the justification */ if (that.settings.waitThumbnailsLoad === false || !imageSrc) { var width = parseFloat($image.attr('width')); var height = parseFloat($image.attr('height')); if ($image.prop('tagName') === 'svg') { width = parseFloat($image[0].getBBox().width); height = parseFloat($image[0].getBBox().height); } if (!isNaN(width) && !isNaN(height)) { $entry.data('jg.width', width); $entry.data('jg.height', height); $entry.data('jg.loaded', 'skipped'); skippedImages = true; that.startImgAnalyzer(false); return true; // continue } } $entry.data('jg.loaded', false); imagesToLoad = true; // Spinner start if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation(); that.onImageEvent(imageSrc, function (loadImg) { // image loaded $entry.data('jg.width', loadImg.width); $entry.data('jg.height', loadImg.height); $entry.data('jg.loaded', true); that.startImgAnalyzer(false); }, function () { // image load error $entry.data('jg.loaded', 'error'); that.startImgAnalyzer(false); }); } else { $entry.data('jg.loaded', true); $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1); $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1); } } }); if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); this.checkWidth(); }; /** * Checks that it is a valid number. If a string is passed it is converted to a number * * @param settingContainer the object that contains the setting (to allow the conversion) * @param settingName the setting name */ JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { if ($.type(settingContainer[settingName]) === 'string') { settingContainer[settingName] = parseFloat(settingContainer[settingName]); } if ($.type(settingContainer[settingName]) === 'number') { if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; } else { throw settingName + ' must be a number'; } }; /** * Checks the sizeRangeSuffixes and, if necessary, converts * its keys from string (e.g. old settings with 'lt100') to int. */ JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { throw 'sizeRangeSuffixes must be defined and must be an object'; } var suffixRanges = []; for (var rangeIdx in this.settings.sizeRangeSuffixes) { if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); } var newSizeRngSuffixes = { 0: '' }; for (var i = 0; i < suffixRanges.length; i++) { if ($.type(suffixRanges[i]) === 'string') { try { var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; } catch (e) { throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; } } else { newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; } } this.settings.sizeRangeSuffixes = newSizeRngSuffixes; }; /** * check and convert the maxRowHeight setting * requires rowHeight to be already set * TODO: should be always called when only rowHeight is changed * @return number or null */ JustifiedGallery.prototype.retrieveMaxRowHeight = function () { var newMaxRowHeight = null; var rowHeight = this.settings.rowHeight; if ($.type(this.settings.maxRowHeight) === 'string') { if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { newMaxRowHeight = rowHeight * parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100; } else { newMaxRowHeight = parseFloat(this.settings.maxRowHeight); } } else if ($.type(this.settings.maxRowHeight) === 'number') { newMaxRowHeight = this.settings.maxRowHeight; } else if (this.settings.maxRowHeight === false || this.settings.maxRowHeight == null) { return null; } else { throw 'maxRowHeight must be a number or a percentage'; } // check if the converted value is not a number if (isNaN(newMaxRowHeight)) throw 'invalid number for maxRowHeight'; // check values, maxRowHeight must be >= rowHeight if (newMaxRowHeight < rowHeight) newMaxRowHeight = rowHeight; return newMaxRowHeight; }; /** * Checks the settings */ JustifiedGallery.prototype.checkSettings = function () { this.checkSizeRangesSuffixes(); this.checkOrConvertNumber(this.settings, 'rowHeight'); this.checkOrConvertNumber(this.settings, 'margins'); this.checkOrConvertNumber(this.settings, 'border'); this.checkOrConvertNumber(this.settings, 'maxRowsCount'); var lastRowModes = [ 'justify', 'nojustify', 'left', 'center', 'right', 'hide' ]; if (lastRowModes.indexOf(this.settings.lastRow) === -1) { throw 'lastRow must be one of: ' + lastRowModes.join(', '); } this.checkOrConvertNumber(this.settings, 'justifyThreshold'); if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { throw 'justifyThreshold must be in the interval [0,1]'; } if ($.type(this.settings.cssAnimation) !== 'boolean') { throw 'cssAnimation must be a boolean'; } if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); if (this.settings.captionSettings.visibleOpacity < 0 || this.settings.captionSettings.visibleOpacity > 1) { throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; } this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); if (this.settings.captionSettings.nonVisibleOpacity < 0 || this.settings.captionSettings.nonVisibleOpacity > 1) { throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; } this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); this.checkOrConvertNumber(this.settings, 'refreshTime'); this.checkOrConvertNumber(this.settings, 'refreshSensitivity'); if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { throw 'sort must be false or a comparison function'; } if (this.settings.filter !== false && !$.isFunction(this.settings.filter) && $.type(this.settings.filter) !== 'string') { throw 'filter must be false, a string or a filter function'; } }; /** * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. * @returns {Array} sorted suffix ranges */ JustifiedGallery.prototype.retrieveSuffixRanges = function () { var suffixRanges = []; for (var rangeIdx in this.settings.sizeRangeSuffixes) { if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); } suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); return suffixRanges; }; /** * Update the existing settings only changing some of them * * @param newSettings the new settings (or a subgroup of them) */ JustifiedGallery.prototype.updateSettings = function (newSettings) { // In this case Justified Gallery has been called again changing only some options this.settings = $.extend({}, this.settings, newSettings); this.checkSettings(); // As reported in the settings: negative value = same as margins, 0 = disabled this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; this.maxRowHeight = this.retrieveMaxRowHeight(); this.suffixRanges = this.retrieveSuffixRanges(); }; JustifiedGallery.prototype.defaults = { sizeRangeSuffixes: {}, /* e.g. Flickr configuration { 100: '_t', // used when longest is less than 100px 240: '_m', // used when longest is between 101px and 240px 320: '_n', // ... 500: '', 640: '_z', 1024: '_b' // used as else case because it is the last } */ thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the path relative to a specific thumbnail size. The function should accept respectively three arguments: current path, width and height */ rowHeight: 120, // required? required to be > 0? maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels, // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height // can't exceed 3 * rowHeight) maxRowsCount: 0, // maximum number of rows to be displayed (0 = disabled) margins: 1, border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide' justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified * (i.e. lastRow setting is not considered) */ waitThumbnailsLoad: true, captions: true, cssAnimation: true, imagesAnimationDuration: 500, // ignored with css animations captionSettings: { // ignored with css animations animationDuration: 500, visibleOpacity: 0.7, nonVisibleOpacity: 0.0 }, rel: null, // rewrite the rel of each analyzed links target: null, // rewrite the target of all links extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image refreshTime: 200, // time interval (in ms) to check if the page changes its width refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery randomize: false, rtl: false, // right-to-left mode sort: false, /* - false: to do not sort - function: to sort them using the function as comparator (see Array.prototype.sort()) */ filter: false, /* - false, null or undefined: for a disabled filter - a string: an entry is kept if entry.is(filter string) returns true see jQuery's .is() function for further information - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. It follows the specifications of the Array.prototype.filter() function of JavaScript. */ selector: 'a', // The selector that is used to know what are the entries of the gallery imgSelector: '> img, > a > img, > svg, > a > svg', // The selector that is used to know what are the images of each entry triggerEvent: function (event) { // This is called to trigger events, the default behavior is to call $.trigger this.$gallery.trigger(event); // Consider that 'this' is this set to the JustifiedGallery object, so it can } // access to fields such as $gallery, useful to trigger events with jQuery. }; /** * Justified Gallery plugin for jQuery * * Events * - jg.complete : called when all the gallery has been created * - jg.resize : called when the gallery has been resized * - jg.rowflush : when a new row appears * * @param arg the action (or the settings) passed when the plugin is called * @returns {*} the object itself */ $.fn.justifiedGallery = function (arg) { return this.each(function (index, gallery) { var $gallery = $(gallery); $gallery.addClass('justified-gallery'); var controller = $gallery.data('jg.controller'); if (typeof controller === 'undefined') { // Create controller and assign it to the object data if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { if (arg === 'destroy') return; // Just a call to an unexisting object throw 'The argument must be an object'; } controller = new JustifiedGallery($gallery, $.extend({}, JustifiedGallery.prototype.defaults, arg)); $gallery.data('jg.controller', controller); } else if (arg === 'norewind') { // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row // ... left to be more readable } else if (arg === 'destroy') { controller.destroy(); return; } else { // In this case Justified Gallery has been called again changing only some options controller.updateSettings(arg); controller.rewind(); } // Update the entries list if (!controller.updateEntries(arg === 'norewind')) return; // Init justified gallery controller.init(); }); }; })); /*! * Customized version of iScroll.js 0.0.1 * It fixes bugs affecting its integration with fullpage.js */ /*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ (function (window, document, Math) { var rAF = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; var utils = (function () { var me = {}; var _elementStyle = document.createElement('div').style; var _vendor = (function () { var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], transform, i = 0, l = vendors.length; for ( ; i < l; i++ ) { transform = vendors[i] + 'ransform'; if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); } return false; })(); function _prefixStyle (style) { if ( _vendor === false ) return false; if ( _vendor === '' ) return style; return _vendor + style.charAt(0).toUpperCase() + style.substr(1); } me.getTime = Date.now || function getTime () { return new Date().getTime(); }; me.extend = function (target, obj) { for ( var i in obj ) { target[i] = obj[i]; } }; me.addEvent = function (el, type, fn, capture) { el.addEventListener(type, fn, !!capture); }; me.removeEvent = function (el, type, fn, capture) { el.removeEventListener(type, fn, !!capture); }; me.prefixPointerEvent = function (pointerEvent) { return window.MSPointerEvent ? 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): pointerEvent; }; me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { var distance = current - start, speed = Math.abs(distance) / time, destination, duration; deceleration = deceleration === undefined ? 0.0006 : deceleration; destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); duration = speed / deceleration; if ( destination < lowerMargin ) { destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; distance = Math.abs(destination - current); duration = distance / speed; } else if ( destination > 0 ) { destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; distance = Math.abs(current) + destination; duration = distance / speed; } return { destination: Math.round(destination), duration: duration }; }; var _transform = _prefixStyle('transform'); me.extend(me, { hasTransform: _transform !== false, hasPerspective: _prefixStyle('perspective') in _elementStyle, hasTouch: 'ontouchstart' in window, hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed hasTransition: _prefixStyle('transition') in _elementStyle }); /* This should find all Android browsers lower than build 535.19 (both stock browser and webview) - galaxy S2 is ok - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` - galaxy S3 is badAndroid (stock brower, webview) `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` - galaxy S4 is badAndroid (stock brower, webview) `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` - galaxy S5 is OK `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` - galaxy S6 is OK `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` */ me.isBadAndroid = (function() { var appVersion = window.navigator.appVersion; // Android browser is not a chrome browser. if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { return parseFloat(safariVersion[1]) < 535.19; } else { return true; } } else { return false; } })(); me.extend(me.style = {}, { transform: _transform, transitionTimingFunction: _prefixStyle('transitionTimingFunction'), transitionDuration: _prefixStyle('transitionDuration'), transitionDelay: _prefixStyle('transitionDelay'), transformOrigin: _prefixStyle('transformOrigin') }); me.hasClass = function (e, c) { var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); return re.test(e.className); }; me.addClass = function (e, c) { if ( me.hasClass(e, c) ) { return; } var newclass = e.className.split(' '); newclass.push(c); e.className = newclass.join(' '); }; me.removeClass = function (e, c) { if ( !me.hasClass(e, c) ) { return; } var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); e.className = e.className.replace(re, ' '); }; me.offset = function (el) { var left = -el.offsetLeft, top = -el.offsetTop; // jshint -W084 while (el = el.offsetParent) { left -= el.offsetLeft; top -= el.offsetTop; } // jshint +W084 return { left: left, top: top }; }; me.preventDefaultException = function (el, exceptions) { for ( var i in exceptions ) { if ( exceptions[i].test(el[i]) ) { return true; } } return false; }; me.extend(me.eventType = {}, { touchstart: 1, touchmove: 1, touchend: 1, mousedown: 2, mousemove: 2, mouseup: 2, pointerdown: 3, pointermove: 3, pointerup: 3, MSPointerDown: 3, MSPointerMove: 3, MSPointerUp: 3 }); me.extend(me.ease = {}, { quadratic: { style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', fn: function (k) { return k * ( 2 - k ); } }, circular: { style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1) fn: function (k) { return Math.sqrt( 1 - ( --k * k ) ); } }, back: { style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', fn: function (k) { var b = 4; return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; } }, bounce: { style: '', fn: function (k) { if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { return 7.5625 * k * k; } else if ( k < ( 2 / 2.75 ) ) { return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; } else if ( k < ( 2.5 / 2.75 ) ) { return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; } else { return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; } } }, elastic: { style: '', fn: function (k) { var f = 0.22, e = 0.4; if ( k === 0 ) { return 0; } if ( k == 1 ) { return 1; } return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); } } }); me.tap = function (e, eventName) { var ev = document.createEvent('Event'); ev.initEvent(eventName, true, true); ev.pageX = e.pageX; ev.pageY = e.pageY; e.target.dispatchEvent(ev); }; me.click = function (e) { var target = e.target, ev; if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent // initMouseEvent is deprecated. ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); ev.initEvent('click', true, true); ev.view = e.view || window; ev.detail = 1; ev.screenX = target.screenX || 0; ev.screenY = target.screenY || 0; ev.clientX = target.clientX || 0; ev.clientY = target.clientY || 0; ev.ctrlKey = !!e.ctrlKey; ev.altKey = !!e.altKey; ev.shiftKey = !!e.shiftKey; ev.metaKey = !!e.metaKey; ev.button = 0; ev.relatedTarget = null; ev._constructed = true; target.dispatchEvent(ev); } }; return me; })(); function IScroll (el, options) { this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; this.scroller = this.wrapper.children[0]; this.scrollerStyle = this.scroller.style; // cache style for better performance this.options = { resizeScrollbars: true, mouseWheelSpeed: 20, snapThreshold: 0.334, // INSERT POINT: OPTIONS disablePointer : !utils.hasPointer, disableTouch : utils.hasPointer || !utils.hasTouch, disableMouse : utils.hasPointer || utils.hasTouch, startX: 0, startY: 0, scrollY: true, directionLockThreshold: 5, momentum: true, bounce: true, bounceTime: 600, bounceEasing: '', preventDefault: true, preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|LABEL)$/ }, HWCompositing: true, useTransition: true, useTransform: true, bindToWrapper: typeof window.onmousedown === "undefined" }; for ( var i in options ) { this.options[i] = options[i]; } // Normalize options this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; this.options.useTransition = utils.hasTransition && this.options.useTransition; this.options.useTransform = utils.hasTransform && this.options.useTransform; this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; // If you want eventPassthrough I have to lock one of the axes this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; // With eventPassthrough we also need lockDirection mechanism this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; if ( this.options.tap === true ) { this.options.tap = 'tap'; } // https://github.com/cubiq/iscroll/issues/1029 if (!this.options.useTransition && !this.options.useTransform) { if(!(/relative|absolute/i).test(this.scrollerStyle.position)) { this.scrollerStyle.position = "relative"; } } if ( this.options.shrinkScrollbars == 'scale' ) { this.options.useTransition = false; } this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; // INSERT POINT: NORMALIZATION // Some defaults this.x = 0; this.y = 0; this.directionX = 0; this.directionY = 0; this._events = {}; // INSERT POINT: DEFAULTS this._init(); this.refresh(); this.scrollTo(this.options.startX, this.options.startY); this.enable(); } IScroll.prototype = { version: '5.2.0', _init: function () { this._initEvents(); if ( this.options.scrollbars || this.options.indicators ) { this._initIndicators(); } if ( this.options.mouseWheel ) { this._initWheel(); } if ( this.options.snap ) { this._initSnap(); } if ( this.options.keyBindings ) { this._initKeys(); } // INSERT POINT: _init }, destroy: function () { this._initEvents(true); clearTimeout(this.resizeTimeout); this.resizeTimeout = null; this._execEvent('destroy'); }, _transitionEnd: function (e) { if ( e.target != this.scroller || !this.isInTransition ) { return; } this._transitionTime(); if ( !this.resetPosition(this.options.bounceTime) ) { this.isInTransition = false; this._execEvent('scrollEnd'); } }, _start: function (e) { // React to left mouse button only if ( utils.eventType[e.type] != 1 ) { // for button property // http://unixpapa.com/js/mouse.html var button; if (!e.which) { /* IE case */ button = (e.button < 2) ? 0 : ((e.button == 4) ? 1 : 2); } else { /* All others */ button = e.button; } if ( button !== 0 ) { return; } } if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { return; } if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { e.preventDefault(); } var point = e.touches ? e.touches[0] : e, pos; this.initiated = utils.eventType[e.type]; this.moved = false; this.distX = 0; this.distY = 0; this.directionX = 0; this.directionY = 0; this.directionLocked = 0; this.startTime = utils.getTime(); if ( this.options.useTransition && this.isInTransition ) { this._transitionTime(); this.isInTransition = false; pos = this.getComputedPosition(); this._translate(Math.round(pos.x), Math.round(pos.y)); this._execEvent('scrollEnd'); } else if ( !this.options.useTransition && this.isAnimating ) { this.isAnimating = false; this._execEvent('scrollEnd'); } this.startX = this.x; this.startY = this.y; this.absStartX = this.x; this.absStartY = this.y; this.pointX = point.pageX; this.pointY = point.pageY; this._execEvent('beforeScrollStart'); }, _move: function (e) { if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { return; } if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! e.preventDefault(); } var point = e.touches ? e.touches[0] : e, deltaX = point.pageX - this.pointX, deltaY = point.pageY - this.pointY, timestamp = utils.getTime(), newX, newY, absDistX, absDistY; this.pointX = point.pageX; this.pointY = point.pageY; this.distX += deltaX; this.distY += deltaY; absDistX = Math.abs(this.distX); absDistY = Math.abs(this.distY); // We need to move at least 10 pixels for the scrolling to initiate if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { return; } // If you are scrolling in one direction lock the other if ( !this.directionLocked && !this.options.freeScroll ) { if ( absDistX > absDistY + this.options.directionLockThreshold ) { this.directionLocked = 'h'; // lock horizontally } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { this.directionLocked = 'v'; // lock vertically } else { this.directionLocked = 'n'; // no lock } } if ( this.directionLocked == 'h' ) { if ( this.options.eventPassthrough == 'vertical' ) { e.preventDefault(); } else if ( this.options.eventPassthrough == 'horizontal' ) { this.initiated = false; return; } deltaY = 0; } else if ( this.directionLocked == 'v' ) { if ( this.options.eventPassthrough == 'horizontal' ) { e.preventDefault(); } else if ( this.options.eventPassthrough == 'vertical' ) { this.initiated = false; return; } deltaX = 0; } deltaX = this.hasHorizontalScroll ? deltaX : 0; deltaY = this.hasVerticalScroll ? deltaY : 0; newX = this.x + deltaX; newY = this.y + deltaY; // Slow down if outside of the boundaries if ( newX > 0 || newX < this.maxScrollX ) { newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; } if ( newY > 0 || newY < this.maxScrollY ) { newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; } this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; if ( !this.moved ) { this._execEvent('scrollStart'); } this.moved = true; this._translate(newX, newY); /* REPLACE START: _move */ if ( timestamp - this.startTime > 300 ) { this.startTime = timestamp; this.startX = this.x; this.startY = this.y; } /* REPLACE END: _move */ }, _end: function (e) { if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { return; } if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { e.preventDefault(); } var point = e.changedTouches ? e.changedTouches[0] : e, momentumX, momentumY, duration = utils.getTime() - this.startTime, newX = Math.round(this.x), newY = Math.round(this.y), distanceX = Math.abs(newX - this.startX), distanceY = Math.abs(newY - this.startY), time = 0, easing = ''; this.isInTransition = 0; this.initiated = 0; this.endTime = utils.getTime(); // reset if we are outside of the boundaries if ( this.resetPosition(this.options.bounceTime) ) { return; } this.scrollTo(newX, newY); // ensures that the last position is rounded // we scrolled less than 10 pixels if ( !this.moved ) { if ( this.options.tap ) { utils.tap(e, this.options.tap); } if ( this.options.click ) { utils.click(e); } this._execEvent('scrollCancel'); return; } if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { this._execEvent('flick'); return; } // start momentum animation if needed if ( this.options.momentum && duration < 300 ) { momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 }; newX = momentumX.destination; newY = momentumY.destination; time = Math.max(momentumX.duration, momentumY.duration); this.isInTransition = 1; } if ( this.options.snap ) { var snap = this._nearestSnap(newX, newY); this.currentPage = snap; time = this.options.snapSpeed || Math.max( Math.max( Math.min(Math.abs(newX - snap.x), 1000), Math.min(Math.abs(newY - snap.y), 1000) ), 300); newX = snap.x; newY = snap.y; this.directionX = 0; this.directionY = 0; easing = this.options.bounceEasing; } // INSERT POINT: _end if ( newX != this.x || newY != this.y ) { // change easing function when scroller goes out of the boundaries if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { easing = utils.ease.quadratic; } this.scrollTo(newX, newY, time, easing); return; } this._execEvent('scrollEnd'); }, _resize: function () { var that = this; clearTimeout(this.resizeTimeout); this.resizeTimeout = setTimeout(function () { that.refresh(); }, this.options.resizePolling); }, resetPosition: function (time) { var x = this.x, y = this.y; time = time || 0; if ( !this.hasHorizontalScroll || this.x > 0 ) { x = 0; } else if ( this.x < this.maxScrollX ) { x = this.maxScrollX; } if ( !this.hasVerticalScroll || this.y > 0 ) { y = 0; } else if ( this.y < this.maxScrollY ) { y = this.maxScrollY; } if ( x == this.x && y == this.y ) { return false; } this.scrollTo(x, y, time, this.options.bounceEasing); return true; }, disable: function () { this.enabled = false; }, enable: function () { this.enabled = true; }, refresh: function () { var rf = this.wrapper.offsetHeight; // Force reflow this.wrapperWidth = this.wrapper.clientWidth; this.wrapperHeight = this.wrapper.clientHeight; /* REPLACE START: refresh */ this.scrollerWidth = this.scroller.offsetWidth; this.scrollerHeight = this.scroller.offsetHeight; this.maxScrollX = this.wrapperWidth - this.scrollerWidth; this.maxScrollY = this.wrapperHeight - this.scrollerHeight; /* REPLACE END: refresh */ this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; if ( !this.hasHorizontalScroll ) { this.maxScrollX = 0; this.scrollerWidth = this.wrapperWidth; } if ( !this.hasVerticalScroll ) { this.maxScrollY = 0; this.scrollerHeight = this.wrapperHeight; } this.endTime = 0; this.directionX = 0; this.directionY = 0; this.wrapperOffset = utils.offset(this.wrapper); this._execEvent('refresh'); this.resetPosition(); // INSERT POINT: _refresh }, on: function (type, fn) { if ( !this._events[type] ) { this._events[type] = []; } this._events[type].push(fn); }, off: function (type, fn) { if ( !this._events[type] ) { return; } var index = this._events[type].indexOf(fn); if ( index > -1 ) { this._events[type].splice(index, 1); } }, _execEvent: function (type) { if ( !this._events[type] ) { return; } var i = 0, l = this._events[type].length; if ( !l ) { return; } for ( ; i < l; i++ ) { this._events[type][i].apply(this, [].slice.call(arguments, 1)); } }, scrollBy: function (x, y, time, easing) { x = this.x + x; y = this.y + y; time = time || 0; this.scrollTo(x, y, time, easing); }, scrollTo: function (x, y, time, easing) { easing = easing || utils.ease.circular; this.isInTransition = this.options.useTransition && time > 0; var transitionType = this.options.useTransition && easing.style; if ( !time || transitionType ) { if(transitionType) { this._transitionTimingFunction(easing.style); this._transitionTime(time); } this._translate(x, y); } else { this._animate(x, y, time, easing.fn); } }, scrollToElement: function (el, time, offsetX, offsetY, easing) { el = el.nodeType ? el : this.scroller.querySelector(el); if ( !el ) { return; } var pos = utils.offset(el); pos.left -= this.wrapperOffset.left; pos.top -= this.wrapperOffset.top; // if offsetX/Y are true we center the element to the screen if ( offsetX === true ) { offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); } if ( offsetY === true ) { offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); } pos.left -= offsetX || 0; pos.top -= offsetY || 0; pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; this.scrollTo(pos.left, pos.top, time, easing); }, _transitionTime: function (time) { if (!this.options.useTransition) { return; } time = time || 0; var durationProp = utils.style.transitionDuration; if(!durationProp) { return; } this.scrollerStyle[durationProp] = time + 'ms'; if ( !time && utils.isBadAndroid ) { this.scrollerStyle[durationProp] = '0.0001ms'; // remove 0.0001ms var self = this; rAF(function() { if(self.scrollerStyle[durationProp] === '0.0001ms') { self.scrollerStyle[durationProp] = '0s'; } }); } if ( this.indicators ) { for ( var i = this.indicators.length; i--; ) { this.indicators[i].transitionTime(time); } } // INSERT POINT: _transitionTime }, _transitionTimingFunction: function (easing) { this.scrollerStyle[utils.style.transitionTimingFunction] = easing; if ( this.indicators ) { for ( var i = this.indicators.length; i--; ) { this.indicators[i].transitionTimingFunction(easing); } } // INSERT POINT: _transitionTimingFunction }, _translate: function (x, y) { //Uncode addition if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 ) return false; if ( this.options.useTransform ) { /* REPLACE START: _translate */ this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; /* REPLACE END: _translate */ } else { x = Math.round(x); y = Math.round(y); this.scrollerStyle.left = x + 'px'; this.scrollerStyle.top = y + 'px'; } this.x = x; this.y = y; if ( this.indicators ) { for ( var i = this.indicators.length; i--; ) { this.indicators[i].updatePosition(); } } //Uncode addition var uncodevent = new CustomEvent('fp-slide-scroll'); window.dispatchEvent(uncodevent); // INSERT POINT: _translate }, _initEvents: function (remove) { var eventType = remove ? utils.removeEvent : utils.addEvent, target = this.options.bindToWrapper ? this.wrapper : window; eventType(window, 'orientationchange', this); eventType(window, 'resize', this); if ( this.options.click ) { eventType(this.wrapper, 'click', this, true); } if ( !this.options.disableMouse ) { eventType(this.wrapper, 'mousedown', this); eventType(target, 'mousemove', this); eventType(target, 'mousecancel', this); eventType(target, 'mouseup', this); } if ( utils.hasPointer && !this.options.disablePointer ) { eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); eventType(target, utils.prefixPointerEvent('pointermove'), this); eventType(target, utils.prefixPointerEvent('pointercancel'), this); eventType(target, utils.prefixPointerEvent('pointerup'), this); } if ( utils.hasTouch && !this.options.disableTouch ) { eventType(this.wrapper, 'touchstart', this); eventType(target, 'touchmove', this); eventType(target, 'touchcancel', this); eventType(target, 'touchend', this); } eventType(this.scroller, 'transitionend', this); eventType(this.scroller, 'webkitTransitionEnd', this); eventType(this.scroller, 'oTransitionEnd', this); eventType(this.scroller, 'MSTransitionEnd', this); }, getComputedPosition: function () { var matrix = window.getComputedStyle(this.scroller, null), x, y; if ( this.options.useTransform ) { matrix = matrix[utils.style.transform].split(')')[0].split(', '); x = +(matrix[12] || matrix[4]); y = +(matrix[13] || matrix[5]); } else { x = +matrix.left.replace(/[^-\d.]/g, ''); y = +matrix.top.replace(/[^-\d.]/g, ''); } return { x: x, y: y }; }, _initIndicators: function () { var interactive = this.options.interactiveScrollbars, customStyle = typeof this.options.scrollbars != 'string', indicators = [], indicator; var that = this; this.indicators = []; if ( this.options.scrollbars ) { // Vertical scrollbar if ( this.options.scrollY ) { indicator = { el: createDefaultScrollbar('v', interactive, this.options.scrollbars), interactive: interactive, defaultScrollbars: true, customStyle: customStyle, resize: this.options.resizeScrollbars, shrink: this.options.shrinkScrollbars, fade: this.options.fadeScrollbars, listenX: false }; this.wrapper.appendChild(indicator.el); indicators.push(indicator); } // Horizontal scrollbar if ( this.options.scrollX ) { indicator = { el: createDefaultScrollbar('h', interactive, this.options.scrollbars), interactive: interactive, defaultScrollbars: true, customStyle: customStyle, resize: this.options.resizeScrollbars, shrink: this.options.shrinkScrollbars, fade: this.options.fadeScrollbars, listenY: false }; this.wrapper.appendChild(indicator.el); indicators.push(indicator); } } if ( this.options.indicators ) { // TODO: check concat compatibility indicators = indicators.concat(this.options.indicators); } for ( var i = indicators.length; i--; ) { this.indicators.push( new Indicator(this, indicators[i]) ); } // TODO: check if we can use array.map (wide compatibility and performance issues) function _indicatorsMap (fn) { if (that.indicators) { for ( var i = that.indicators.length; i--; ) { fn.call(that.indicators[i]); } } } if ( this.options.fadeScrollbars ) { this.on('scrollEnd', function () { _indicatorsMap(function () { this.fade(); }); }); this.on('scrollCancel', function () { _indicatorsMap(function () { this.fade(); }); }); this.on('scrollStart', function () { _indicatorsMap(function () { this.fade(1); }); }); this.on('beforeScrollStart', function () { _indicatorsMap(function () { this.fade(1, true); }); }); } this.on('refresh', function () { _indicatorsMap(function () { this.refresh(); }); }); this.on('destroy', function () { _indicatorsMap(function () { this.destroy(); }); delete this.indicators; }); }, _initWheel: function () { utils.addEvent(this.wrapper, 'wheel', this); utils.addEvent(this.wrapper, 'mousewheel', this); utils.addEvent(this.wrapper, 'DOMMouseScroll', this); this.on('destroy', function () { clearTimeout(this.wheelTimeout); this.wheelTimeout = null; utils.removeEvent(this.wrapper, 'wheel', this); utils.removeEvent(this.wrapper, 'mousewheel', this); utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); }); }, _wheel: function (e) { if ( !this.enabled ) { return; } var wheelDeltaX, wheelDeltaY, newX, newY, that = this; if ( this.wheelTimeout === undefined ) { that._execEvent('scrollStart'); } // Execute the scrollEnd event after 400ms the wheel stopped scrolling clearTimeout(this.wheelTimeout); this.wheelTimeout = setTimeout(function () { if(!that.options.snap) { that._execEvent('scrollEnd'); } that.wheelTimeout = undefined; }, 400); if ( 'deltaX' in e ) { if (e.deltaMode === 1) { wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; } else { wheelDeltaX = -e.deltaX; wheelDeltaY = -e.deltaY; } } else if ( 'wheelDeltaX' in e ) { wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; } else if ( 'wheelDelta' in e ) { wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; } else if ( 'detail' in e ) { wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; } else { return; } wheelDeltaX *= this.options.invertWheelDirection; wheelDeltaY *= this.options.invertWheelDirection; if ( !this.hasVerticalScroll ) { wheelDeltaX = wheelDeltaY; wheelDeltaY = 0; } if ( this.options.snap ) { newX = this.currentPage.pageX; newY = this.currentPage.pageY; if ( wheelDeltaX > 0 ) { newX--; } else if ( wheelDeltaX < 0 ) { newX++; } if ( wheelDeltaY > 0 ) { newY--; } else if ( wheelDeltaY < 0 ) { newY++; } this.goToPage(newX, newY); return; } newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; if ( newX > 0 ) { newX = 0; } else if ( newX < this.maxScrollX ) { newX = this.maxScrollX; } if ( newY > 0 ) { newY = 0; } else if ( newY < this.maxScrollY ) { newY = this.maxScrollY; } this.scrollTo(newX, newY, 0); // INSERT POINT: _wheel }, _initSnap: function () { this.currentPage = {}; if ( typeof this.options.snap == 'string' ) { this.options.snap = this.scroller.querySelectorAll(this.options.snap); } this.on('refresh', function () { var i = 0, l, m = 0, n, cx, cy, x = 0, y, stepX = this.options.snapStepX || this.wrapperWidth, stepY = this.options.snapStepY || this.wrapperHeight, el; this.pages = []; if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { return; } if ( this.options.snap === true ) { cx = Math.round( stepX / 2 ); cy = Math.round( stepY / 2 ); while ( x > -this.scrollerWidth ) { this.pages[i] = []; l = 0; y = 0; while ( y > -this.scrollerHeight ) { this.pages[i][l] = { x: Math.max(x, this.maxScrollX), y: Math.max(y, this.maxScrollY), width: stepX, height: stepY, cx: x - cx, cy: y - cy }; y -= stepY; l++; } x -= stepX; i++; } } else { el = this.options.snap; l = el.length; n = -1; for ( ; i < l; i++ ) { if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { m = 0; n++; } if ( !this.pages[m] ) { this.pages[m] = []; } x = Math.max(-el[i].offsetLeft, this.maxScrollX); y = Math.max(-el[i].offsetTop, this.maxScrollY); cx = x - Math.round(el[i].offsetWidth / 2); cy = y - Math.round(el[i].offsetHeight / 2); this.pages[m][n] = { x: x, y: y, width: el[i].offsetWidth, height: el[i].offsetHeight, cx: cx, cy: cy }; if ( x > this.maxScrollX ) { m++; } } } this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); // Update snap threshold if needed if ( this.options.snapThreshold % 1 === 0 ) { this.snapThresholdX = this.options.snapThreshold; this.snapThresholdY = this.options.snapThreshold; } else { this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); } }); this.on('flick', function () { var time = this.options.snapSpeed || Math.max( Math.max( Math.min(Math.abs(this.x - this.startX), 1000), Math.min(Math.abs(this.y - this.startY), 1000) ), 300); this.goToPage( this.currentPage.pageX + this.directionX, this.currentPage.pageY + this.directionY, time ); }); }, _nearestSnap: function (x, y) { if ( !this.pages.length ) { return { x: 0, y: 0, pageX: 0, pageY: 0 }; } var i = 0, l = this.pages.length, m = 0; // Check if we exceeded the snap threshold if ( Math.abs(x - this.absStartX) < this.snapThresholdX && Math.abs(y - this.absStartY) < this.snapThresholdY ) { return this.currentPage; } if ( x > 0 ) { x = 0; } else if ( x < this.maxScrollX ) { x = this.maxScrollX; } if ( y > 0 ) { y = 0; } else if ( y < this.maxScrollY ) { y = this.maxScrollY; } for ( ; i < l; i++ ) { if ( x >= this.pages[i][0].cx ) { x = this.pages[i][0].x; break; } } l = this.pages[i].length; for ( ; m < l; m++ ) { if ( y >= this.pages[0][m].cy ) { y = this.pages[0][m].y; break; } } if ( i == this.currentPage.pageX ) { i += this.directionX; if ( i < 0 ) { i = 0; } else if ( i >= this.pages.length ) { i = this.pages.length - 1; } x = this.pages[i][0].x; } if ( m == this.currentPage.pageY ) { m += this.directionY; if ( m < 0 ) { m = 0; } else if ( m >= this.pages[0].length ) { m = this.pages[0].length - 1; } y = this.pages[0][m].y; } return { x: x, y: y, pageX: i, pageY: m }; }, goToPage: function (x, y, time, easing) { easing = easing || this.options.bounceEasing; if ( x >= this.pages.length ) { x = this.pages.length - 1; } else if ( x < 0 ) { x = 0; } if ( y >= this.pages[x].length ) { y = this.pages[x].length - 1; } else if ( y < 0 ) { y = 0; } var posX = this.pages[x][y].x, posY = this.pages[x][y].y; time = time === undefined ? this.options.snapSpeed || Math.max( Math.max( Math.min(Math.abs(posX - this.x), 1000), Math.min(Math.abs(posY - this.y), 1000) ), 300) : time; this.currentPage = { x: posX, y: posY, pageX: x, pageY: y }; this.scrollTo(posX, posY, time, easing); }, next: function (time, easing) { var x = this.currentPage.pageX, y = this.currentPage.pageY; x++; if ( x >= this.pages.length && this.hasVerticalScroll ) { x = 0; y++; } this.goToPage(x, y, time, easing); }, prev: function (time, easing) { var x = this.currentPage.pageX, y = this.currentPage.pageY; x--; if ( x < 0 && this.hasVerticalScroll ) { x = 0; y--; } this.goToPage(x, y, time, easing); }, _initKeys: function (e) { // default key bindings var keys = { pageUp: 33, pageDown: 34, end: 35, home: 36, left: 37, up: 38, right: 39, down: 40 }; var i; // if you give me characters I give you keycode if ( typeof this.options.keyBindings == 'object' ) { for ( i in this.options.keyBindings ) { if ( typeof this.options.keyBindings[i] == 'string' ) { this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0); } } } else { this.options.keyBindings = {}; } for ( i in keys ) { this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; } utils.addEvent(window, 'keydown', this); this.on('destroy', function () { utils.removeEvent(window, 'keydown', this); }); }, _key: function (e) { if ( !this.enabled ) { return; } var snap = this.options.snap, // we are using this alot, better to cache it newX = snap ? this.currentPage.pageX : this.x, newY = snap ? this.currentPage.pageY : this.y, now = utils.getTime(), prevTime = this.keyTime || 0, acceleration = 0.250, pos; if ( this.options.useTransition && this.isInTransition ) { pos = this.getComputedPosition(); this._translate(Math.round(pos.x), Math.round(pos.y)); this.isInTransition = false; } this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; switch ( e.keyCode ) { case this.options.keyBindings.pageUp: if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { newX += snap ? 1 : this.wrapperWidth; } else { newY += snap ? 1 : this.wrapperHeight; } break; case this.options.keyBindings.pageDown: if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { newX -= snap ? 1 : this.wrapperWidth; } else { newY -= snap ? 1 : this.wrapperHeight; } break; case this.options.keyBindings.end: newX = snap ? this.pages.length-1 : this.maxScrollX; newY = snap ? this.pages[0].length-1 : this.maxScrollY; break; case this.options.keyBindings.home: newX = 0; newY = 0; break; case this.options.keyBindings.left: newX += snap ? -1 : 5 + this.keyAcceleration>>0; break; case this.options.keyBindings.up: newY += snap ? 1 : 5 + this.keyAcceleration>>0; break; case this.options.keyBindings.right: newX -= snap ? -1 : 5 + this.keyAcceleration>>0; break; case this.options.keyBindings.down: newY -= snap ? 1 : 5 + this.keyAcceleration>>0; break; default: return; } if ( snap ) { this.goToPage(newX, newY); return; } if ( newX > 0 ) { newX = 0; this.keyAcceleration = 0; } else if ( newX < this.maxScrollX ) { newX = this.maxScrollX; this.keyAcceleration = 0; } if ( newY > 0 ) { newY = 0; this.keyAcceleration = 0; } else if ( newY < this.maxScrollY ) { newY = this.maxScrollY; this.keyAcceleration = 0; } this.scrollTo(newX, newY, 0); this.keyTime = now; }, _animate: function (destX, destY, duration, easingFn) { var that = this, startX = this.x, startY = this.y, startTime = utils.getTime(), destTime = startTime + duration; function step () { var now = utils.getTime(), newX, newY, easing; if ( now >= destTime ) { that.isAnimating = false; that._translate(destX, destY); if ( !that.resetPosition(that.options.bounceTime) ) { that._execEvent('scrollEnd'); } return; } now = ( now - startTime ) / duration; easing = easingFn(now); newX = ( destX - startX ) * easing + startX; newY = ( destY - startY ) * easing + startY; that._translate(newX, newY); if ( that.isAnimating ) { rAF(step); } } this.isAnimating = true; step(); }, handleEvent: function (e) { switch ( e.type ) { case 'touchstart': case 'pointerdown': case 'MSPointerDown': case 'mousedown': this._start(e); break; case 'touchmove': case 'pointermove': case 'MSPointerMove': case 'mousemove': this._move(e); break; case 'touchend': case 'pointerup': case 'MSPointerUp': case 'mouseup': case 'touchcancel': case 'pointercancel': case 'MSPointerCancel': case 'mousecancel': this._end(e); break; case 'orientationchange': case 'resize': this._resize(); break; case 'transitionend': case 'webkitTransitionEnd': case 'oTransitionEnd': case 'MSTransitionEnd': this._transitionEnd(e); break; case 'wheel': case 'DOMMouseScroll': case 'mousewheel': this._wheel(e); break; case 'keydown': this._key(e); break; case 'click': if ( this.enabled && !e._constructed ) { e.preventDefault(); e.stopPropagation(); } break; } } }; function createDefaultScrollbar (direction, interactive, type) { var scrollbar = document.createElement('div'), indicator = document.createElement('div'); if ( type === true ) { scrollbar.style.cssText = 'position:absolute;z-index:9999'; indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px'; } indicator.className = 'iScrollIndicator'; if ( direction == 'h' ) { if ( type === true ) { scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; indicator.style.height = '100%'; } scrollbar.className = 'iScrollHorizontalScrollbar'; } else { if ( type === true ) { scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; indicator.style.width = '100%'; } scrollbar.className = 'iScrollVerticalScrollbar'; } scrollbar.style.cssText += ';overflow:hidden'; if ( !interactive ) { scrollbar.style.pointerEvents = 'none'; } scrollbar.appendChild(indicator); return scrollbar; } function Indicator (scroller, options) { this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; this.wrapperStyle = this.wrapper.style; this.indicator = this.wrapper.children[0]; this.indicatorStyle = this.indicator.style; this.scroller = scroller; this.options = { listenX: true, listenY: true, interactive: false, resize: true, defaultScrollbars: false, shrink: false, fade: false, speedRatioX: 0, speedRatioY: 0 }; for ( var i in options ) { this.options[i] = options[i]; } this.sizeRatioX = 1; this.sizeRatioY = 1; this.maxPosX = 0; this.maxPosY = 0; if ( this.options.interactive ) { if ( !this.options.disableTouch ) { utils.addEvent(this.indicator, 'touchstart', this); utils.addEvent(window, 'touchend', this); } if ( !this.options.disablePointer ) { utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); } if ( !this.options.disableMouse ) { utils.addEvent(this.indicator, 'mousedown', this); utils.addEvent(window, 'mouseup', this); } } if ( this.options.fade ) { this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; var durationProp = utils.style.transitionDuration; if(!durationProp) { return; } this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; // remove 0.0001ms var self = this; if(utils.isBadAndroid) { rAF(function() { if(self.wrapperStyle[durationProp] === '0.0001ms') { self.wrapperStyle[durationProp] = '0s'; } }); } this.wrapperStyle.opacity = '0'; } } Indicator.prototype = { handleEvent: function (e) { switch ( e.type ) { case 'touchstart': case 'pointerdown': case 'MSPointerDown': case 'mousedown': this._start(e); break; case 'touchmove': case 'pointermove': case 'MSPointerMove': case 'mousemove': this._move(e); break; case 'touchend': case 'pointerup': case 'MSPointerUp': case 'mouseup': case 'touchcancel': case 'pointercancel': case 'MSPointerCancel': case 'mousecancel': this._end(e); break; } }, destroy: function () { if ( this.options.fadeScrollbars ) { clearTimeout(this.fadeTimeout); this.fadeTimeout = null; } if ( this.options.interactive ) { utils.removeEvent(this.indicator, 'touchstart', this); utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); utils.removeEvent(this.indicator, 'mousedown', this); utils.removeEvent(window, 'touchmove', this); utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); utils.removeEvent(window, 'mousemove', this); utils.removeEvent(window, 'touchend', this); utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); utils.removeEvent(window, 'mouseup', this); } if ( this.options.defaultScrollbars ) { this.wrapper.parentNode.removeChild(this.wrapper); } }, _start: function (e) { var point = e.touches ? e.touches[0] : e; e.preventDefault(); e.stopPropagation(); this.transitionTime(); this.initiated = true; this.moved = false; this.lastPointX = point.pageX; this.lastPointY = point.pageY; this.startTime = utils.getTime(); if ( !this.options.disableTouch ) { utils.addEvent(window, 'touchmove', this); } if ( !this.options.disablePointer ) { utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); } if ( !this.options.disableMouse ) { utils.addEvent(window, 'mousemove', this); } this.scroller._execEvent('beforeScrollStart'); }, _move: function (e) { var point = e.touches ? e.touches[0] : e, deltaX, deltaY, newX, newY, timestamp = utils.getTime(); if ( !this.moved ) { this.scroller._execEvent('scrollStart'); } this.moved = true; deltaX = point.pageX - this.lastPointX; this.lastPointX = point.pageX; deltaY = point.pageY - this.lastPointY; this.lastPointY = point.pageY; newX = this.x + deltaX; newY = this.y + deltaY; this._pos(newX, newY); // INSERT POINT: indicator._move e.preventDefault(); e.stopPropagation(); }, _end: function (e) { if ( !this.initiated ) { return; } this.initiated = false; e.preventDefault(); e.stopPropagation(); utils.removeEvent(window, 'touchmove', this); utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); utils.removeEvent(window, 'mousemove', this); if ( this.scroller.options.snap ) { var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); var time = this.options.snapSpeed || Math.max( Math.max( Math.min(Math.abs(this.scroller.x - snap.x), 1000), Math.min(Math.abs(this.scroller.y - snap.y), 1000) ), 300); if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { this.scroller.directionX = 0; this.scroller.directionY = 0; this.scroller.currentPage = snap; this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); } } if ( this.moved ) { this.scroller._execEvent('scrollEnd'); } }, transitionTime: function (time) { time = time || 0; var durationProp = utils.style.transitionDuration; if(!durationProp) { return; } this.indicatorStyle[durationProp] = time + 'ms'; if ( !time && utils.isBadAndroid ) { this.indicatorStyle[durationProp] = '0.0001ms'; // remove 0.0001ms var self = this; rAF(function() { if(self.indicatorStyle[durationProp] === '0.0001ms') { self.indicatorStyle[durationProp] = '0s'; } }); } }, transitionTimingFunction: function (easing) { this.indicatorStyle[utils.style.transitionTimingFunction] = easing; }, refresh: function () { this.transitionTime(); if ( this.options.listenX && !this.options.listenY ) { this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; } else if ( this.options.listenY && !this.options.listenX ) { this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; } else { this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; } if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { utils.addClass(this.wrapper, 'iScrollBothScrollbars'); utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); if ( this.options.defaultScrollbars && this.options.customStyle ) { if ( this.options.listenX ) { this.wrapper.style.right = '8px'; } else { this.wrapper.style.bottom = '8px'; } } } else { utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); if ( this.options.defaultScrollbars && this.options.customStyle ) { if ( this.options.listenX ) { this.wrapper.style.right = '2px'; } else { this.wrapper.style.bottom = '2px'; } } } var r = this.wrapper.offsetHeight; // force refresh if ( this.options.listenX ) { this.wrapperWidth = this.wrapper.clientWidth; if ( this.options.resize ) { this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); this.indicatorStyle.width = this.indicatorWidth + 'px'; } else { this.indicatorWidth = this.indicator.clientWidth; } this.maxPosX = this.wrapperWidth - this.indicatorWidth; if ( this.options.shrink == 'clip' ) { this.minBoundaryX = -this.indicatorWidth + 8; this.maxBoundaryX = this.wrapperWidth - 8; } else { this.minBoundaryX = 0; this.maxBoundaryX = this.maxPosX; } this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); } if ( this.options.listenY ) { this.wrapperHeight = this.wrapper.clientHeight; if ( this.options.resize ) { this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); this.indicatorStyle.height = this.indicatorHeight + 'px'; } else { this.indicatorHeight = this.indicator.clientHeight; } this.maxPosY = this.wrapperHeight - this.indicatorHeight; if ( this.options.shrink == 'clip' ) { this.minBoundaryY = -this.indicatorHeight + 8; this.maxBoundaryY = this.wrapperHeight - 8; } else { this.minBoundaryY = 0; this.maxBoundaryY = this.maxPosY; } this.maxPosY = this.wrapperHeight - this.indicatorHeight; this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); } this.updatePosition(); }, updatePosition: function () { var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; if ( !this.options.ignoreBoundaries ) { if ( x < this.minBoundaryX ) { if ( this.options.shrink == 'scale' ) { this.width = Math.max(this.indicatorWidth + x, 8); this.indicatorStyle.width = this.width + 'px'; } x = this.minBoundaryX; } else if ( x > this.maxBoundaryX ) { if ( this.options.shrink == 'scale' ) { this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); this.indicatorStyle.width = this.width + 'px'; x = this.maxPosX + this.indicatorWidth - this.width; } else { x = this.maxBoundaryX; } } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { this.width = this.indicatorWidth; this.indicatorStyle.width = this.width + 'px'; } if ( y < this.minBoundaryY ) { if ( this.options.shrink == 'scale' ) { this.height = Math.max(this.indicatorHeight + y * 3, 8); this.indicatorStyle.height = this.height + 'px'; } y = this.minBoundaryY; } else if ( y > this.maxBoundaryY ) { if ( this.options.shrink == 'scale' ) { this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); this.indicatorStyle.height = this.height + 'px'; y = this.maxPosY + this.indicatorHeight - this.height; } else { y = this.maxBoundaryY; } } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { this.height = this.indicatorHeight; this.indicatorStyle.height = this.height + 'px'; } } this.x = x; this.y = y; if ( this.scroller.options.useTransform ) { this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; } else { this.indicatorStyle.left = x + 'px'; this.indicatorStyle.top = y + 'px'; } }, _pos: function (x, y) { if ( x < 0 ) { x = 0; } else if ( x > this.maxPosX ) { x = this.maxPosX; } if ( y < 0 ) { y = 0; } else if ( y > this.maxPosY ) { y = this.maxPosY; } x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; this.scroller.scrollTo(x, y); }, fade: function (val, hold) { if ( hold && !this.visible ) { return; } clearTimeout(this.fadeTimeout); this.fadeTimeout = null; var time = val ? 250 : 500, delay = val ? 0 : 300; val = val ? '1' : '0'; this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; this.fadeTimeout = setTimeout((function (val) { this.wrapperStyle.opacity = val; this.visible = +val; }).bind(this, val), delay); } }; IScroll.utils = utils; if ( typeof module != 'undefined' && module.exports ) { module.exports = IScroll; } else if ( typeof define == 'function' && define.amd ) { define( function () { return IScroll; } ); } else { window.IScroll = IScroll; } })(window, document, Math); /*! * fullPage 2.9.4 * https://github.com/alvarotrigo/fullPage.js * @license MIT licensed * * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo */ (function(global, factory) { 'use strict'; if (typeof define === 'function' && define.amd) { define(['jquery'], function($) { return factory($, global, global.document, global.Math); }); } else if (typeof exports === "object" && exports) { module.exports = factory(require('jquery'), global, global.document, global.Math); } else { factory(jQuery, global, global.document, global.Math); } })(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) { 'use strict'; // keeping central set of classnames and selectors var WRAPPER = 'fullpage-wrapper'; var WRAPPER_SEL = '.' + WRAPPER; // slimscroll var SCROLLABLE = 'fp-scrollable'; var SCROLLABLE_SEL = '.' + SCROLLABLE; // util var RESPONSIVE = 'fp-responsive'; var NO_TRANSITION = 'fp-notransition'; var DESTROYED = 'fp-destroyed'; var ENABLED = 'fp-enabled'; var VIEWING_PREFIX = 'fp-viewing'; var ACTIVE = 'active'; var ACTIVE_SEL = '.' + ACTIVE; var COMPLETELY = 'fp-completely'; var COMPLETELY_SEL = '.' + COMPLETELY; // section var SECTION_DEFAULT_SEL = '.section'; var SECTION = 'fp-section'; var SECTION_SEL = '.' + SECTION; var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; var SECTION_FIRST_SEL = SECTION_SEL + ':first'; var SECTION_LAST_SEL = SECTION_SEL + ':last'; var TABLE_CELL = 'fp-tableCell'; var TABLE_CELL_SEL = '.' + TABLE_CELL; var AUTO_HEIGHT = 'fp-auto-height'; var AUTO_HEIGHT_SEL = '.fp-auto-height'; var NORMAL_SCROLL = 'fp-normal-scroll'; var NORMAL_SCROLL_SEL = '.fp-normal-scroll'; // section nav var SECTION_NAV = 'fp-nav'; var SECTION_NAV_SEL = '#' + SECTION_NAV; var SECTION_NAV_TOOLTIP = 'fp-tooltip'; var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; // slide var SLIDE_DEFAULT_SEL = '.slide'; var SLIDE = 'fp-slide'; var SLIDE_SEL = '.' + SLIDE; var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; var SLIDES_WRAPPER = 'fp-slides'; var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; var SLIDES_CONTAINER = 'fp-slidesContainer'; var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; var TABLE = 'fp-table'; // slide nav var SLIDES_NAV = 'fp-slidesNav'; var SLIDES_NAV_SEL = '.' + SLIDES_NAV; var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; var SLIDES_ARROW = 'fp-controlArrow'; var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; var SLIDES_PREV = 'fp-prev'; var SLIDES_PREV_SEL = '.' + SLIDES_PREV; var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; var SLIDES_NEXT = 'fp-next'; var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; var $window = $(window); var $document = $(document); // Default options for iScroll.js used when using scrollOverflow var iscrollOptions = { scrollbars: true, mouseWheel: true, hideScrollbars: false, fadeScrollbars: false, disableMouse: true, interactiveScrollbars: true, bounce: false, }; $.fn.fullpage = function(options) { //only once my friend! if($('html').hasClass(ENABLED)){ displayWarnings(); return; } // common jQuery objects var $htmlBody = $('html, body'); var $body = $('body'); var FP = $.fn.fullpage; // Creating some defaults, extending them with any options that were provided options = $.extend({ //navigation menu: false, anchors:[], lockAnchors: false, navigation: false, navigationPosition: 'right', navigationTooltips: [], showActiveTooltip: false, slidesNavigation: false, slidesNavPosition: 'bottom', scrollBar: false, hybrid: false, //scrolling css3: true, scrollingSpeed: 700, autoScrolling: true, fitToSection: true, fitToSectionDelay: 1000, easing: 'easeInOutCubic', easingcss3: 'ease', loopBottom: false, loopTop: false, loopHorizontal: true, continuousVertical: false, continuousHorizontal: false, scrollHorizontally: false, interlockedSlides: false, dragAndMove: false, offsetSections: false, resetSliders: false, fadingEffect: false, normalScrollElements: null, scrollOverflow: false, scrollOverflowReset: false, scrollOverflowHandler: iscrollHandler, scrollOverflowOptions: null, touchSensitivity: 5, normalScrollElementTouchThreshold: 5, bigSectionsDestination: null, //Accessibility keyboardScrolling: true, animateAnchor: true, recordHistory: true, //design controlArrows: true, controlArrowColor: '#fff', verticalCentered: true, sectionsColor : [], paddingTop: 0, paddingBottom: 0, fixedElements: null, responsive: 0, //backwards compabitility with responsiveWiddth responsiveWidth: 0, responsiveHeight: 0, responsiveSlides: false, parallax: false, parallaxOptions: { type: 'reveal', percentage: 62, property: 'translate' }, //Custom selectors sectionSelector: SECTION_DEFAULT_SEL, slideSelector: SLIDE_DEFAULT_SEL, //events afterLoad: null, onLeave: null, afterRender: null, afterResize: null, afterReBuild: null, afterSlideLoad: null, onSlideLeave: null, afterResponsive: null, lazyLoading: true }, options); //flag to avoid very fast sliding for landscape sliders var slideMoving = false; var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); var container = $(this); var windowsHeight = $window.height(); var isResizing = false; var isWindowFocused = true; var lastScrolledDestiny; var lastScrolledSlide; var canScroll = true; var scrollings = []; var controlPressed; var startingSection; var isScrollAllowed = {}; isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m); var MSPointer = getMSPointer(); var events = { touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move, touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down }; //cheks for passive event support //added by Uncode from new fullPage updates var g_supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function() { g_supportsPassive = true; } }); window.addEventListener("testPassive", null, opts); window.removeEventListener("testPassive", null, opts); } catch (e) {} //timeouts var resizeId; var afterSectionLoadsId; var afterSlideLoadsId; var scrollId; var scrollId2; var keydownId; var originals = $.extend(true, {}, options); //deep copy //Uncode addition var $masthead = $('#masthead'); var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false; var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight; var bodyBorder = UNCODE.bodyBorder; var adminBarHeight = UNCODE.adminBarHeight; displayWarnings(); //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 iscrollOptions.click = isTouch; // see #2035 //extending iScroll options with the user custom ones iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions); //easeInOutCubic animation included in the plugin $.extend($.easing,{ easeInOutCubic: function (x, t, b, c, d) {if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;}}); /** * Sets the autoScroll option. * It changes the scroll bar visibility and the history of the site as a result. */ function setAutoScrolling(value, type){ //removing the transformation if(!value){ silentScroll(0); } setVariableState('autoScrolling', value, type); var element = $(SECTION_ACTIVE_SEL); if(options.autoScrolling && !options.scrollBar){ $htmlBody.css({ 'overflow' : 'hidden !important', 'height' : '100%' }); //Uncode addition //setRecordHistory(originals.recordHistory, 'internal'); //for IE touch devices container.css({ '-ms-touch-action': 'none', 'touch-action': 'none' }); if(element.length){ //moving the container up silentScroll(element.position().top); } }else{ $htmlBody.css({ 'overflow' : 'visible !important', 'height' : 'initial' }); //Uncode addition //setRecordHistory(false, 'internal'); //for IE touch devices container.css({ '-ms-touch-action': '', 'touch-action': '' }); //scrolling the page to the section with no animation if (element.length) { $htmlBody.scrollTop(element.position().top); } } } /** * Defines wheter to record the history for each hash change in the URL. */ function setRecordHistory(value, type){ setVariableState('recordHistory', value, type); } /** * Defines the scrolling speed */ function setScrollingSpeed(value, type){ setVariableState('scrollingSpeed', value, type); } /** * Sets fitToSection */ function setFitToSection(value, type){ setVariableState('fitToSection', value, type); } /** * Sets lockAnchors */ function setLockAnchors(value){ options.lockAnchors = value; } /** * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad. */ function setMouseWheelScrolling(value){ if(value){ addMouseWheelHandler(); addMiddleWheelHandler(); }else{ removeMouseWheelHandler(); removeMiddleWheelHandler(); } } /** * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures. * Optionally a second parameter can be used to specify the direction for which the action will be applied. * * @param directions string containing the direction or directions separated by comma. */ function setAllowScrolling(value, directions){ if(typeof directions !== 'undefined'){ directions = directions.replace(/ /g,'').split(','); $.each(directions, function (index, direction){ setIsScrollAllowed(value, direction, 'm'); }); } else if(value){ setMouseWheelScrolling(true); addTouchHandler(); }else{ setMouseWheelScrolling(false); removeTouchHandler(); } } /** * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys */ function setKeyboardScrolling(value, directions){ if(typeof directions !== 'undefined'){ directions = directions.replace(/ /g,'').split(','); $.each(directions, function (index, direction){ setIsScrollAllowed(value, direction, 'k'); }); }else{ options.keyboardScrolling = value; } } /** * Moves the page up one section. */ function moveSectionUp(){ var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL); //looping to the bottom if there's no more sections above if (!prev.length && (options.loopTop || options.continuousVertical)) { prev = $(SECTION_SEL).last(); } if (prev.length) { scrollPage(prev, null, true); } } /** * Moves the page down one section. */ function moveSectionDown(){ var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL); //looping to the top if there's no more sections below if(!next.length && (options.loopBottom || options.continuousVertical)){ next = $(SECTION_SEL).first(); } if(next.length){ scrollPage(next, null, false); } } /** * Moves the page to the given section and slide with no animation. * Anchors or index positions can be used as params. */ function silentMoveTo(sectionAnchor, slideAnchor){ setScrollingSpeed (0, 'internal'); moveTo(sectionAnchor, slideAnchor); setScrollingSpeed (originals.scrollingSpeed, 'internal'); } /** * Moves the page to the given section and slide. * Anchors or index positions can be used as params. */ function moveTo(sectionAnchor, slideAnchor){ var destiny = getSectionByAnchor(sectionAnchor); if (typeof slideAnchor !== 'undefined'){ scrollPageAndSlide(sectionAnchor, slideAnchor); }else if(destiny.length > 0){ scrollPage(destiny); } } /** * Slides right the slider of the active section. * Optional `section` param. */ function moveSlideRight(section){ moveSlide('right', section); } /** * Slides left the slider of the active section. * Optional `section` param. */ function moveSlideLeft(section){ moveSlide('left', section); } /** * When resizing is finished, we adjust the slides sizes and positions */ function reBuild(resizing){ if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed isResizing = true; windowsHeight = $window.height(); //updating global var $(SECTION_SEL).each(function(){ var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL); var slides = $(this).find(SLIDE_SEL); //adjusting the height of the table-cell for IE and Firefox if(options.verticalCentered){ $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px'); } $(this).css('height', windowsHeight + 'px'); //resizing the scrolling divs if(options.scrollOverflow){ if(slides.length){ slides.each(function(){ createScrollBar($(this)); }); }else{ createScrollBar($(this)); } } //adjusting the position fo the FULL WIDTH slides... if (slides.length > 1) { landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL)); } }); var activeSection = $(SECTION_ACTIVE_SEL); var sectionIndex = activeSection.index(SECTION_SEL); //isn't it the first section? if(sectionIndex){ //adjusting the position for the current section silentMoveTo(sectionIndex + 1); } isResizing = false; // Uncode change // $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container); $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container, getTableHeight()); $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container); } /** * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` * are smaller than the set limit values. */ function setResponsive(active){ var isResponsive = $body.hasClass(RESPONSIVE); if(active){ if(!isResponsive){ setAutoScrolling(false, 'internal'); setFitToSection(false, 'internal'); $(SECTION_NAV_SEL).hide(); $body.addClass(RESPONSIVE); $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); } } else if(isResponsive){ setAutoScrolling(originals.autoScrolling, 'internal'); setFitToSection(originals.autoScrolling, 'internal'); $(SECTION_NAV_SEL).show(); $body.removeClass(RESPONSIVE); $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active); } } if($(this).length){ //public functions FP.setAutoScrolling = setAutoScrolling; FP.setRecordHistory = setRecordHistory; FP.setScrollingSpeed = setScrollingSpeed; FP.setFitToSection = setFitToSection; FP.setLockAnchors = setLockAnchors; FP.setMouseWheelScrolling = setMouseWheelScrolling; FP.setAllowScrolling = setAllowScrolling; FP.setKeyboardScrolling = setKeyboardScrolling; FP.moveSectionUp = moveSectionUp; FP.moveSectionDown = moveSectionDown; FP.silentMoveTo = silentMoveTo; FP.moveTo = moveTo; FP.moveSlideRight = moveSlideRight; FP.moveSlideLeft = moveSlideLeft; FP.fitToSection = fitToSection; FP.reBuild = reBuild; FP.setResponsive = setResponsive; FP.destroy = destroy; init(); bindEvents(); } function init(){ //if css3 is not supported, it will use jQuery animations if(options.css3){ options.css3 = support3d(); } options.scrollBar = options.scrollBar || options.hybrid; setOptionsFromDOM(); prepareDom(); setAllowScrolling(true); setAutoScrolling(options.autoScrolling, 'internal'); responsive(); //setting the class for the body element setBodyClass(); //Uncode addition // if(document.readyState === 'complete'){ // scrollToAnchor(); // } // $window.on('load', scrollToAnchor); } function bindEvents(){ $window //when scrolling... //.on('scroll', scrollHandler) //detecting any change on the URL to scroll to the given anchor link //(a way to detect back history button as we play with the hashes on the URL) .on('hashchange', hashChangeHandler) //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. .blur(blurHandler) //when resizing the site, we adjust the heights of the sections, slimScroll... .resize(resizeHandler); $document //Sliding with arrow keys, both, vertical and horizontal .keydown(keydownHandler) //to prevent scrolling while zooming .keyup(keyUpHandler) //Scrolls to the section when clicking the navigation bullet .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler) //Scrolls the slider to the given slide destination for the given section .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler) .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler); //Scrolling horizontally when clicking on the slider controls. $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler); /** * Applying normalScroll elements. * Ignoring the scrolls over the specified selectors. */ if(options.normalScrollElements){ $document.on('mouseenter', options.normalScrollElements, function () { setMouseWheelScrolling(false); }); $document.on('mouseleave', options.normalScrollElements, function(){ setMouseWheelScrolling(true); }); } } /** * Setting options from DOM elements if they are not provided. */ function setOptionsFromDOM(){ var sections = container.find(options.sectionSelector); //no anchors option? Checking for them in the DOM attributes if(!options.anchors.length){ options.anchors = sections.filter('[data-anchor]').map(function(){ return $(this).data('anchor').toString(); }).get(); } //no tooltips option? Checking for them in the DOM attributes if(!options.navigationTooltips.length){ options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){ return $(this).data('tooltip').toString(); }).get(); } } /** * Works over the DOM structure to set it up for the current fullpage options. */ function prepareDom(){ container.css({ 'height': '100%', 'position': 'relative' }); //adding a class to recognize the container internally in the code container.addClass(WRAPPER); $('html').addClass(ENABLED); windowsHeight = $window.height(); container.removeClass(DESTROYED); //in case it was destroyed before initializing it again addInternalSelectors(); //styling the sections / slides / menu $(SECTION_SEL).each(function(index){ var section = $(this); var slides = section.find(SLIDE_SEL); var numSlides = slides.length; styleSection(section, index); styleMenu(section, index); // if there's any slide if (numSlides > 0) { styleSlides(section, slides, numSlides); }else{ if(options.verticalCentered){ addTableClass(section); } } }); //fixed elements need to be moved out of the plugin container due to problems with CSS3. if(options.fixedElements && options.css3){ $(options.fixedElements).appendTo($body); } //vertical centered of the navigation + active bullet if(options.navigation){ addVerticalNavigation(); } enableYoutubeAPI(); if(options.scrollOverflow){ if(document.readyState === 'complete'){ createScrollBarHandler(); } //after DOM and images are loaded $window.on('load', createScrollBarHandler); }else{ afterRenderActions(); } } /** * Styles the horizontal slides for a section. */ function styleSlides(section, slides, numSlides){ var sliderWidth = numSlides * 100; var slideWidth = 100 / numSlides; slides.wrapAll('
    '); slides.parent().wrap('
    '); section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%'); if(numSlides > 1){ if(options.controlArrows){ createSlideArrows(section); } if(options.slidesNavigation){ addSlidesNavigation(section, numSlides); } } slides.each(function(index) { $(this).css('width', slideWidth + '%'); if(options.verticalCentered){ addTableClass($(this)); } }); var startingSlide = section.find(SLIDE_ACTIVE_SEL); //if the slide won't be an starting point, the default will be the first one //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/slide by default. if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){ silentLandscapeScroll(startingSlide, 'internal'); }else{ slides.eq(0).addClass(ACTIVE); } } /** * Styling vertical sections */ function styleSection(section, index){ //if no active section is defined, the 1st one will be the default one if(!index && $(SECTION_ACTIVE_SEL).length === 0) { section.addClass(ACTIVE); } startingSection = $(SECTION_ACTIVE_SEL); section.css('height', windowsHeight + 'px'); if(options.paddingTop){ section.css('padding-top', options.paddingTop); } if(options.paddingBottom){ section.css('padding-bottom', options.paddingBottom); } if (typeof options.sectionsColor[index] !== 'undefined') { section.css('background-color', options.sectionsColor[index]); } if (typeof options.anchors[index] !== 'undefined') { section.attr('data-anchor', options.anchors[index]); } } /** * Sets the data-anchor attributes to the menu elements and activates the current one. */ function styleMenu(section, index){ if (typeof options.anchors[index] !== 'undefined') { //activating the menu / nav element on load if(section.hasClass(ACTIVE)){ activateMenuAndNav(options.anchors[index], index); } } //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){ $(options.menu).appendTo($body); } } /** * Adds internal classes to be able to provide customizable selectors * keeping the link with the style sheet. */ function addInternalSelectors(){ container.find(options.sectionSelector).addClass(SECTION); container.find(options.slideSelector).addClass(SLIDE); } /** * Creates the control arrows for the given section */ function createSlideArrows(section){ section.find(SLIDES_WRAPPER_SEL).after('
    '); if(options.controlArrowColor!='#fff'){ section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor); section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent'); } if(!options.loopHorizontal){ section.find(SLIDES_ARROW_PREV_SEL).hide(); } } /** * Creates a vertical navigation bar. */ function addVerticalNavigation(){ $body.append('
      '); var nav = $(SECTION_NAV_SEL); nav.addClass(function() { return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition; }); for (var i = 0; i < $(SECTION_SEL).length; i++) { var link = ''; if (options.anchors.length) { link = options.anchors[i]; } var li = '
    • '; // Only add tooltip if needed (defined by user) var tooltip = options.navigationTooltips[i]; if (typeof tooltip !== 'undefined' && tooltip !== '') { li += '
      ' + tooltip + '
      '; } li += '
    • '; nav.find('ul').append(li); } //centering it vertically $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px'); //activating the current active section $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE); } /** * Creates the slim scroll scrollbar for the sections and slides inside them. */ function createScrollBarHandler(){ $(SECTION_SEL).each(function(){ var slides = $(this).find(SLIDE_SEL); if(slides.length){ slides.each(function(){ createScrollBar($(this)); }); }else{ createScrollBar($(this)); } }); afterRenderActions(); } /* * Enables the Youtube videos API so we can control their flow if necessary. */ function enableYoutubeAPI(){ container.find('iframe[src*="youtube.com/embed/"]').each(function(){ addURLParam($(this), 'enablejsapi=1'); }); } /** * Adds a new parameter and its value to the `src` of a given element */ function addURLParam(element, newParam){ var originalSrc = element.attr('src'); element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam); } /* * Returns the prefix sign to use for a new parameter in an existen URL. * * @return {String} ? | & */ function getUrlParamSign(url){ return ( !/\?/.test( url ) ) ? '?' : '&'; } /** * Actions and callbacks to fire afterRender */ function afterRenderActions(){ var section = $(SECTION_ACTIVE_SEL); section.addClass(COMPLETELY); if(options.scrollOverflowHandler.afterRender){ options.scrollOverflowHandler.afterRender(section); } lazyLoad(section); playMedia(section); options.scrollOverflowHandler.afterLoad(); if(isDestinyTheStartingSection()){ $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1)); } // Uncode change // $.isFunction( options.afterRender ) && options.afterRender.call(container); $.isFunction( options.afterRender ) && options.afterRender.call(container, getTableHeight()); } /** * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization) */ function isDestinyTheStartingSection(){ var anchors = window.location.hash.replace('#', '').split('/'); var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0])); return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index(); } var isScrolling = false; var lastScroll = 0; //when scrolling... function scrollHandler(){ var currentSection; if(!options.autoScrolling || options.scrollBar){ var currentScroll = $window.scrollTop(); var scrollDirection = getScrollDirection(currentScroll); var visibleSectionIndex = 0; var screen_mid = currentScroll + ($window.height() / 2.0); var isAtBottom = $body.height() - $window.height() === currentScroll; var sections = document.querySelectorAll(SECTION_SEL); //when using `auto-height` for a small last section it won't be centered in the viewport if(isAtBottom){ visibleSectionIndex = sections.length - 1; } //is at top? when using `auto-height` for a small first section it won't be centered in the viewport else if(!currentScroll){ visibleSectionIndex = 0; } //taking the section which is showing more content in the viewport else{ for (var i = 0; i < sections.length; ++i) { var section = sections[i]; // Pick the the last section which passes the middle line of the screen. if (section.offsetTop <= screen_mid) { visibleSectionIndex = i; } } } if(isCompletelyInViewPort(scrollDirection)){ if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){ $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY); } } //geting the last one, the current one on the screen currentSection = $(sections).eq(visibleSectionIndex); //setting the visible section as active when manually scrolling //executing only once the first time we reach the section if(!currentSection.hasClass(ACTIVE)){ isScrolling = true; var leavingSection = $(SECTION_ACTIVE_SEL); var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1; var yMovement = getYmovement(currentSection); var anchorLink = currentSection.data('anchor'); var sectionIndex = currentSection.index(SECTION_SEL) + 1; var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL); var slideIndex; var slideAnchorLink; if(activeSlide.length){ slideAnchorLink = activeSlide.data('anchor'); slideIndex = activeSlide.index(); } if(canScroll){ currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE); $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement); $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex); stopMedia(leavingSection); lazyLoad(currentSection); playMedia(currentSection); activateMenuAndNav(anchorLink, sectionIndex - 1); if(options.anchors.length){ //needed to enter in hashChange event when using the menu with anchor links lastScrolledDestiny = anchorLink; } setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); } //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet clearTimeout(scrollId); scrollId = setTimeout(function(){ isScrolling = false; }, 100); } if(options.fitToSection){ //for the auto adjust of the viewport to fit a whole section clearTimeout(scrollId2); scrollId2 = setTimeout(function(){ //checking it again in case it changed during the delay if(options.fitToSection){ fitToSection(); } }, options.fitToSectionDelay); } } } /** * Fits the site to the nearest active section */ function fitToSection(){ //checking fitToSection again in case it was set to false before the timeout delay if(canScroll){ //allows to scroll to an active section and //if the section is already active, we prevent firing callbacks isResizing = true; scrollPage($(SECTION_ACTIVE_SEL)); isResizing = false; } } /** * Determines whether the active section has seen in its whole or not. */ function isCompletelyInViewPort(movement){ var top = $(SECTION_ACTIVE_SEL).position().top; var bottom = top + $window.height(); if(movement == 'up'){ return bottom >= ($window.scrollTop() + $window.height()); } return top <= $window.scrollTop(); } /** * Gets the directon of the the scrolling fired by the scroll event. */ function getScrollDirection(currentScroll){ var direction = currentScroll > lastScroll ? 'down' : 'up'; lastScroll = currentScroll; //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination previousDestTop = currentScroll; return direction; } /** * Determines the way of scrolling up or down: * by 'automatically' scrolling a section or by using the default and normal scrolling. */ function scrolling(type, scrollable){ if (!isScrollAllowed.m[type]){ return; } var check = (type === 'down') ? 'bottom' : 'top'; var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp; if(scrollable.length > 0 ){ //is the scrollbar at the start/end of the scroll? if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ scrollSection(); }else{ return true; } }else{ // moved up/down scrollSection(); } } /* * Preventing bouncing in iOS #2285 */ function preventBouncing(event){ var e = event.originalEvent; if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){ //preventing the easing on iOS devices event.preventDefault(); } } var touchStartY = 0; var touchStartX = 0; var touchEndY = 0; var touchEndX = 0; /* Detecting touch events * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. * This way, the touchstart and the touch moves shows an small difference between them which is the * used one to determine the direction. */ function touchMoveHandler(event){ var e = event.originalEvent; var activeSection = $(e.target).closest(SECTION_SEL); // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) { if(options.autoScrolling){ //preventing the easing on iOS devices event.preventDefault(); } var scrollable = options.scrollOverflowHandler.scrollable(activeSection); var touchEvents = getEventsPage(e); touchEndY = touchEvents.y; touchEndX = touchEvents.x; //if movement in the X axys is greater than in the Y and the currect section has slides... if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { //is the movement greater than the minimum resistance to scroll? if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) { if (touchStartX > touchEndX) { if(isScrollAllowed.m.right){ moveSlideRight(activeSection); //next } } else { if(isScrollAllowed.m.left){ moveSlideLeft(activeSection); //prev } } } } //vertical scrolling (only when autoScrolling is enabled) else if(options.autoScrolling && canScroll){ //is the movement greater than the minimum resistance to scroll? if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) { if (touchStartY > touchEndY) { scrolling('down', scrollable); } else if (touchEndY > touchStartY) { scrolling('up', scrollable); } } } } } /** * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements * Currently works well for iOS - Android might need some testing * @param {Element} el target element / jquery selector (in subsequent nodes) * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold * @return {boolean} true if there is a match to options.normalScrollElements */ function checkParentForNormalScrollElement (el, hop) { hop = hop || 0; var parent = $(el).parent(); if (hop < options.normalScrollElementTouchThreshold && parent.is(options.normalScrollElements) ) { return true; } else if (hop == options.normalScrollElementTouchThreshold) { return false; } else { return checkParentForNormalScrollElement(parent, ++hop); } } /** * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen * this way we make sure that is really a touch event what IE is detecting. */ function isReallyTouch(e){ //if is not IE || IE is detecting `touch` or `pen` return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; } /** * Handler for the touch start event. */ function touchStartHandler(event){ var e = event.originalEvent; //stopping the auto scroll to adjust to a section if(options.fitToSection){ $htmlBody.stop(); } if(isReallyTouch(e)){ var touchEvents = getEventsPage(e); touchStartY = touchEvents.y; touchStartX = touchEvents.x; } } /** * Gets the average of the last `number` elements of the given array. */ function getAverage(elements, number){ var sum = 0; //taking `number` elements from the end to make the average, if there are not enought, 1 var lastElements = elements.slice(Math.max(elements.length - number, 1)); for(var i = 0; i < lastElements.length; i++){ sum = sum + lastElements[i]; } return Math.ceil(sum/number); } /** * Detecting mousewheel scrolling * * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html * http://www.sitepoint.com/html5-javascript-mouse-wheel/ */ var prevTime = new Date().getTime(); function MouseWheelHandler(e) { var curTime = new Date().getTime(); var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL); //autoscrolling and not zooming? if(options.autoScrolling && !controlPressed && !isNormalScroll){ // cross-browser wheel delta e = e || window.event; var value = e.wheelDelta || -e.deltaY || -e.detail; var delta = Math.max(-1, Math.min(1, value)); var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); //Limiting the array to 150 (lets not waste memory!) if(scrollings.length > 149){ scrollings.shift(); } //keeping record of the previous scrollings scrollings.push(Math.abs(value)); //preventing to scroll the site on mouse wheel when scrollbar is present if(options.scrollBar){ e.preventDefault ? e.preventDefault() : e.returnValue = false; } var activeSection = $(SECTION_ACTIVE_SEL); var scrollable = options.scrollOverflowHandler.scrollable(activeSection); //time difference between the last scroll and the current one var timeDiff = curTime-prevTime; prevTime = curTime; //haven't they scrolled in a while? //(enough to be consider a different scrolling action to scroll another section) if(timeDiff > 200){ //emptying the array, we dont care about old scrollings for our averages scrollings = []; } if(canScroll){ var averageEnd = getAverage(scrollings, 10); var averageMiddle = getAverage(scrollings, 70); var isAccelerating = averageEnd >= averageMiddle; //to avoid double swipes... if(isAccelerating && isScrollingVertically){ //scrolling down? if (delta < 0) { scrolling('down', scrollable); //scrolling up? }else { scrolling('up', scrollable); } } } return false; } if(options.fitToSection){ //stopping the auto scroll to adjust to a section $htmlBody.stop(); } } /** * Slides a slider to the given direction. * Optional `section` param. */ function moveSlide(direction, section){ var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section; var slides = activeSection.find(SLIDES_WRAPPER_SEL); var numSlides = slides.find(SLIDE_SEL).length; // more than one slide needed and nothing should be sliding if (!slides.length || slideMoving || numSlides < 2) { return; } var currentSlide = slides.find(SLIDE_ACTIVE_SEL); var destiny = null; if(direction === 'left'){ destiny = currentSlide.prev(SLIDE_SEL); }else{ destiny = currentSlide.next(SLIDE_SEL); } //isn't there a next slide in the secuence? if(!destiny.length){ //respect loopHorizontal settin if (!options.loopHorizontal) return; if(direction === 'left'){ destiny = currentSlide.siblings(':last'); }else{ destiny = currentSlide.siblings(':first'); } } slideMoving = true; landscapeScroll(slides, destiny, direction); } /** * Maintains the active slides in the viewport * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical) */ function keepSlidesPosition(){ $(SLIDE_ACTIVE_SEL).each(function(){ silentLandscapeScroll($(this), 'internal'); }); } var previousDestTop = 0; /** * Returns the destination Y position based on the scrolling direction and * the height of the section. */ function getDestinationPosition(element){ var elemPosition = element.position(); //top of the desination will be at the top of the viewport var position = elemPosition.top; var isScrollingDown = elemPosition.top > previousDestTop; var sectionBottom = position - windowsHeight + element.outerHeight(); var bigSectionsDestination = options.bigSectionsDestination; //Uncode addition var containerH = container.outerHeight(); var containerPosition = container.offset(); //########### Commented by Uncode - START ########### //is the destination element bigger than the viewport? // if(element.outerHeight() > windowsHeight){ // //scrolling up? // if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ // position = sectionBottom; // } // } // //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){ // //The bottom of the destination will be at the bottom of the viewport // position = sectionBottom; // } //########### Commented by Uncode - END ########### //Uncode addition if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') ) position += 18; if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) { position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight; } /* Keeping record of the last scrolled position to determine the scrolling direction. No conventional methods can be used as the scroll bar might not be present AND the section might not be active if it is auto-height and didnt reach the middle of the viewport. */ previousDestTop = position; return position; } /** * Scrolls the site to the given element and scrolls to the slide if a callback is given. */ function scrollPage(element, callback, isMovementUp){ if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function var dtop = getDestinationPosition(element); var slideAnchorLink; var slideIndex; //local variables var v = { element: element, callback: callback, isMovementUp: isMovementUp, dtop: dtop, yMovement: getYmovement(element), anchorLink: element.data('anchor'), sectionIndex: element.index(SECTION_SEL), activeSlide: element.find(SLIDE_ACTIVE_SEL), activeSection: $(SECTION_ACTIVE_SEL), leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1, //caching the value of isResizing at the momment the function is called //because it will be checked later inside a setTimeout and the value might change localIsResizing: isResizing }; //quiting when destination scroll is the same as the current one if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; } if(v.activeSlide.length){ slideAnchorLink = v.activeSlide.data('anchor'); slideIndex = v.activeSlide.index(); } // If continuousVertical && we need to wrap around if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down v = createInfiniteSections(v); } //callback (onLeave) if the site is not just resizing and readjusting the slides if($.isFunction(options.onLeave) && !v.localIsResizing){ if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){ return; } } //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one) if(!v.localIsResizing){ stopMedia(v.activeSection); } options.scrollOverflowHandler.beforeLeave(); element.addClass(ACTIVE).siblings().removeClass(ACTIVE); lazyLoad(element); options.scrollOverflowHandler.onLeave(); //preventing from activating the MouseWheelHandler event //more than once if the page is scrolling canScroll = false; setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); performMovement(v); //flag to avoid callingn `scrollPage()` twice in case of using anchor links lastScrolledDestiny = v.anchorLink; //avoid firing it twice (as it does also on scroll) activateMenuAndNav(v.anchorLink, v.sectionIndex); } /** * Performs the vertical movement (by CSS3 or by jQuery) */ function performMovement(v){ // using CSS3 translate functionality if (options.css3 && options.autoScrolling && !options.scrollBar) { // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 // that's why we round it to 0. var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)'; transformContainer(translate3d, true); //even when the scrollingSpeed is 0 there's a little delay, which might cause the //scrollingSpeed to change in case of using silentMoveTo(); if(options.scrollingSpeed){ clearTimeout(afterSectionLoadsId); afterSectionLoadsId = setTimeout(function () { afterSectionLoads(v); }, options.scrollingSpeed); }else{ afterSectionLoads(v); } } // using jQuery animate else{ var scrollSettings = getScrollSettings(v); $(scrollSettings.element).animate( scrollSettings.options, options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body` if(options.scrollBar){ /* Hack! The timeout prevents setting the most dominant section in the viewport as "active" when the user scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. */ setTimeout(function(){ afterSectionLoads(v); },30); }else{ afterSectionLoads(v); } }); } } /** * Gets the scrolling settings depending on the plugin autoScrolling option */ function getScrollSettings(v){ var scroll = {}; if(options.autoScrolling && !options.scrollBar){ scroll.options = { 'top': -v.dtop}; scroll.element = WRAPPER_SEL; }else{ scroll.options = { 'scrollTop': v.dtop}; scroll.element = 'html, body'; } return scroll; } /** * Adds sections before or after the current one to create the infinite effect. */ function createInfiniteSections(v){ // Scrolling down if (!v.isMovementUp) { // Move all previous sections to after the active section $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse()); } else { // Scrolling up // Move all next sections to before the active section $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL)); } // Maintain the displayed position (now that we changed the element order) silentScroll($(SECTION_ACTIVE_SEL).position().top); // Maintain the active slides visible in the viewport keepSlidesPosition(); // save for later the elements that still need to be reordered v.wrapAroundElements = v.activeSection; // Recalculate animation variables v.dtop = v.element.position().top; v.yMovement = getYmovement(v.element); return v; } /** * Fix section order after continuousVertical changes have been animated */ function continuousVerticalFixSectionOrder (v) { // If continuousVertical is in effect (and autoScrolling would also be in effect then), // finish moving the elements around so the direct navigation will function more simply if (!v.wrapAroundElements || !v.wrapAroundElements.length) { return; } if (v.isMovementUp) { $(SECTION_FIRST_SEL).before(v.wrapAroundElements); } else { $(SECTION_LAST_SEL).after(v.wrapAroundElements); } silentScroll($(SECTION_ACTIVE_SEL).position().top); // Maintain the active slides visible in the viewport keepSlidesPosition(); } /** * Actions to do once the section is loaded. */ function afterSectionLoads (v){ continuousVerticalFixSectionOrder(v); //callback (afterLoad) if the site is not just resizing and readjusting the slides $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1)); options.scrollOverflowHandler.afterLoad(); if(!v.localIsResizing){ playMedia(v.element); } v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY); canScroll = true; $.isFunction(v.callback) && v.callback.call(this); } /** * Sets the value for the given attribute from the `data-` attribute with the same suffix * ie: data-srcset ==> srcset | data-src ==> src */ function setSrc(element, attribute){ element .attr(attribute, element.data(attribute)) .removeAttr('data-' + attribute); } /** * Lazy loads image, video and audio elements. */ function lazyLoad(destiny){ if (!options.lazyLoading){ return; } var panel = getSlideOrSection(destiny); var element; panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){ element = $(this); $.each(['src', 'srcset'], function(index, type){ var attribute = element.attr('data-' + type); if(typeof attribute !== 'undefined' && attribute){ setSrc(element, type); } }); if(element.is('source')){ element.closest('video').get(0).load(); } }); } /** * Plays video and audio elements. */ function playMedia(destiny){ var panel = getSlideOrSection(destiny); //playing HTML5 media elements panel.find('video, audio').each(function(){ var element = $(this).get(0); if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { element.play(); } }); //youtube videos panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ var element = $(this).get(0); if ( element.hasAttribute('data-autoplay') ){ playYoutube(element); } //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load. element.onload = function() { if ( element.hasAttribute('data-autoplay') ){ playYoutube(element); } }; }); } /** * Plays a youtube video */ function playYoutube(element){ element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); } /** * Stops video and audio elements. */ function stopMedia(destiny){ var panel = getSlideOrSection(destiny); //stopping HTML5 media elements panel.find('video, audio').each(function(){ var element = $(this).get(0); if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { element.pause(); } }); //youtube videos panel.find('iframe[src*="youtube.com/embed/"]').each(function(){ var element = $(this).get(0); if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){ $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); } }); } /** * Gets the active slide (or section) for the given section */ function getSlideOrSection(destiny){ var slide = destiny.find(SLIDE_ACTIVE_SEL); if( slide.length ) { destiny = $(slide); } return destiny; } /** * Scrolls to the anchor in the URL when loading the site */ function scrollToAnchor(){ //getting the anchor link in the URL and deleting the `#` var value = window.location.hash.replace('#', '').split('/'); var sectionAnchor = decodeURIComponent(value[0]); var slideAnchor = decodeURIComponent(value[1]); if(sectionAnchor){ //if theres any # if(options.animateAnchor){ scrollPageAndSlide(sectionAnchor, slideAnchor); }else{ silentMoveTo(sectionAnchor, slideAnchor); } } } /** * Detecting any change on the URL to scroll to the given anchor link * (a way to detect back history button as we play with the hashes on the URL) */ function hashChangeHandler(){ if(!isScrolling && !options.lockAnchors){ var value = window.location.hash.replace('#', '').split('/'); var sectionAnchor = decodeURIComponent(value[0]); var slideAnchor = decodeURIComponent(value[1]); //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving); if(sectionAnchor.length){ /*in order to call scrollpage() only once for each destination at a time It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` event is fired on every scroll too.*/ if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor )) { scrollPageAndSlide(sectionAnchor, slideAnchor); } } } } //Sliding with arrow keys, both, vertical and horizontal function keydownHandler(e) { clearTimeout(keydownId); var activeElement = $(':focus'); if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') && activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' && options.keyboardScrolling && options.autoScrolling){ var keyCode = e.which; //preventing the scroll with arrow keys & spacebar & Page Up & Down keys var keyControls = [40, 38, 32, 33, 34]; if($.inArray(keyCode, keyControls) > -1){ e.preventDefault(); } controlPressed = e.ctrlKey; keydownId = setTimeout(function(){ onkeydown(e); },150); } } function tooltipTextHandler(){ $(this).prev().trigger('click'); } //to prevent scrolling while zooming function keyUpHandler(e){ if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox controlPressed = e.ctrlKey; } } //binding the mousemove when the mouse's middle button is released function mouseDownHandler(e){ //middle button if (e.which == 2){ oldPageY = e.pageY; container.on('mousemove', mouseMoveHandler); } } //unbinding the mousemove when the mouse's middle button is released function mouseUpHandler(e){ //middle button if (e.which == 2){ container.off('mousemove'); } } //Scrolling horizontally when clicking on the slider controls. function slideArrowHandler(){ var section = $(this).closest(SECTION_SEL); if ($(this).hasClass(SLIDES_PREV)) { if(isScrollAllowed.m.left){ moveSlideLeft(section); } } else { if(isScrollAllowed.m.right){ moveSlideRight(section); } } } //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. function blurHandler(){ isWindowFocused = false; controlPressed = false; } //Scrolls to the section when clicking the navigation bullet function sectionBulletHandler(e){ e.preventDefault(); var index = $(this).parent().index(); scrollPage($(SECTION_SEL).eq(index)); } //Scrolls the slider to the given slide destination for the given section function slideBulletHandler(e){ e.preventDefault(); var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL); var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index()); landscapeScroll(slides, destiny); } /** * Keydown event */ function onkeydown(e){ var shiftPressed = e.shiftKey; //do nothing if we can not scroll or we are not using horizotnal key arrows. if(!canScroll && [37,39].indexOf(e.which) < 0){ return; } switch (e.which) { //up case 38: case 33: if(isScrollAllowed.k.up){ moveSectionUp(); } break; //down case 32: //spacebar if(shiftPressed && isScrollAllowed.k.up){ moveSectionUp(); break; } /* falls through */ case 40: case 34: if(isScrollAllowed.k.down){ moveSectionDown(); } break; //Home case 36: if(isScrollAllowed.k.up){ moveTo(1); } break; //End case 35: if(isScrollAllowed.k.down){ moveTo( $(SECTION_SEL).length ); } break; //left case 37: if(isScrollAllowed.k.left){ moveSlideLeft(); } break; //right case 39: if(isScrollAllowed.k.right){ moveSlideRight(); } break; default: return; // exit this handler for other keys } } /** * Detecting the direction of the mouse movement. * Used only for the middle button of the mouse. */ var oldPageY = 0; function mouseMoveHandler(e){ if(canScroll){ // moving up if (e.pageY < oldPageY && isScrollAllowed.m.up){ moveSectionUp(); } // moving down else if(e.pageY > oldPageY && isScrollAllowed.m.down){ moveSectionDown(); } } oldPageY = e.pageY; } /** * Scrolls horizontal sliders. */ function landscapeScroll(slides, destiny, direction){ var section = slides.closest(SECTION_SEL); var v = { slides: slides, destiny: destiny, direction: direction, destinyPos: destiny.position(), slideIndex: destiny.index(), section: section, sectionIndex: section.index(SECTION_SEL), anchorLink: section.data('anchor'), slidesNav: section.find(SLIDES_NAV_SEL), slideAnchor: getAnchor(destiny), prevSlide: section.find(SLIDE_ACTIVE_SEL), prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(), //caching the value of isResizing at the momment the function is called //because it will be checked later inside a setTimeout and the value might change localIsResizing: isResizing }; v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex); v.direction = v.direction ? v.direction : v.xMovement; //important!! Only do it when not resizing if(!v.localIsResizing){ //preventing from scrolling to the next/prev section when using scrollHorizontally canScroll = false; } if(options.onSlideLeave){ //if the site is not just resizing and readjusting the slides if(!v.localIsResizing && v.xMovement!=='none'){ if($.isFunction( options.onSlideLeave )){ if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){ slideMoving = false; return; } } } } destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); if(!v.localIsResizing){ stopMedia(v.prevSlide); lazyLoad(destiny); } if(!options.loopHorizontal && options.controlArrows){ //hidding it for the fist slide, showing for the rest section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0); //hidding it for the last slide, showing for the rest section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child')); } //only changing the URL if the slides are in the current section (not for resize re-adjusting) if(section.hasClass(ACTIVE) && !v.localIsResizing){ setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex); } performHorizontalMove(slides, v, true); } function afterSlideLoads(v){ activeSlidesNavigation(v.slidesNav, v.slideIndex); //if the site is not just resizing and readjusting the slides if(!v.localIsResizing){ $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex); //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally //and to prevent double scroll right after a windows resize canScroll = true; playMedia(v.destiny); } //letting them slide again slideMoving = false; } /** * Performs the horizontal movement. (CSS3 or jQuery) * * @param fireCallback {Bool} - determines whether or not to fire the callback */ function performHorizontalMove(slides, v, fireCallback){ var destinyPos = v.destinyPos; if(options.css3){ var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v); afterSlideLoadsId = setTimeout(function(){ fireCallback && afterSlideLoads(v); }, options.scrollingSpeed, options.easing); }else{ slides.animate({ scrollLeft : Math.round(destinyPos.left) }, options.scrollingSpeed, options.easing, function() { fireCallback && afterSlideLoads(v); }); } } /** * Sets the state for the horizontal bullet navigations. */ function activeSlidesNavigation(slidesNav, slideIndex){ slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE); slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE); } var previousHeight = windowsHeight; //when resizing the site, we adjust the heights of the sections, slimScroll... function resizeHandler(){ //checking if it needs to get responsive responsive(); // rebuild immediately on touch devices if (isTouchDevice) { var activeElement = $(document.activeElement); //if the keyboard is NOT visible if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) { var currentHeight = $window.height(); //making sure the change in the viewport size is enough to force a rebuild. (20 % of the window to avoid problems when hidding scroll bars) if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ reBuild(true); previousHeight = currentHeight; } } }else{ //in order to call the functions only when the resize is finished //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing clearTimeout(resizeId); resizeId = setTimeout(function(){ reBuild(true); }, 350); } } /** * Checks if the site needs to get responsive and disables autoScrolling if so. * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. */ function responsive(){ var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity var heightLimit = options.responsiveHeight; //only calculating what we need. Remember its called on the resize event. var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit; var isBreakingPointHeight = heightLimit && $window.height() < heightLimit; if(widthLimit && heightLimit){ setResponsive(isBreakingPointWidth || isBreakingPointHeight); } else if(widthLimit){ setResponsive(isBreakingPointWidth); } else if(heightLimit){ setResponsive(isBreakingPointHeight); } } /** * Adds transition animations for the given element */ function addAnimation(container, element){ var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; container.removeClass(NO_TRANSITION); return container.css({ '-webkit-transition': transition, 'transition': transition }); } /** * Remove transition animations for the given element */ function removeAnimation(element){ return element.addClass(NO_TRANSITION); } /** * Activating the vertical navigation bullets according to the given slide name. */ function activateNavDots(name, sectionIndex){ if(options.navigation){ $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE); if(name){ $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE); }else{ $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE); } } } /** * Activating the website main menu elements according to the given slide name. */ function activateMenuElement(name){ if(options.menu){ $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE); $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE); } } /** * Sets to active the current menu and vertical nav items. */ function activateMenuAndNav(anchor, index){ activateMenuElement(anchor); activateNavDots(anchor, index); } /** * Retuns `up` or `down` depending on the scrolling movement to reach its destination * from the current section. */ function getYmovement(destiny){ var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL); var toIndex = destiny.index(SECTION_SEL); if( fromIndex == toIndex){ return 'none'; } if(fromIndex > toIndex){ return 'up'; } return 'down'; } /** * Retuns `right` or `left` depending on the scrolling movement to reach its destination * from the current slide. */ function getXmovement(fromIndex, toIndex){ if( fromIndex == toIndex){ return 'none'; } if(fromIndex > toIndex){ return 'left'; } return 'right'; } /** * Checks if the element needs scrollbar and if the user wants to apply it. * If so it creates it. * * @param {Object} element jQuery object of the section or slide */ function createScrollBar(element){ //User doesn't want scrollbar here? Sayonara baby! if(element.hasClass('fp-noscroll')) return; //needed to make `scrollHeight` work under Opera 12 element.css('overflow', 'hidden'); var scrollOverflowHandler = options.scrollOverflowHandler; var wrap = scrollOverflowHandler.wrapContent(); //in case element is a slide var section = element.closest(SECTION_SEL); var scrollable = scrollOverflowHandler.scrollable(element); var contentHeight; //if there was scroll, the contentHeight will be the one in the scrollable section if(scrollable.length){ contentHeight = scrollOverflowHandler.scrollHeight(element); }else{ contentHeight = element.get(0).scrollHeight; if(options.verticalCentered){ contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight; } } var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top')); //needs scroll? if ( contentHeight > scrollHeight) { //did we already have an scrollbar ? Updating it if(scrollable.length){ scrollOverflowHandler.update(element, scrollHeight); } //creating the scrolling else{ if(options.verticalCentered){ element.find(TABLE_CELL_SEL).wrapInner(wrap); }else{ element.wrapInner(wrap); } scrollOverflowHandler.create(element, scrollHeight); } } //removing the scrolling when it is not necessary anymore else{ scrollOverflowHandler.remove(element); } //undo element.css('overflow', ''); } function addTableClass(element){ //In case we are styling for the 2nd time as in with reponsiveSlides if(!element.hasClass(TABLE)){ element.addClass(TABLE).wrapInner('
      '); } } function getTableHeight(element){ var sectionHeight = windowsHeight; if(options.paddingTop || options.paddingBottom){ var section = element; if(!section.hasClass(SECTION)){ section = element.closest(SECTION_SEL); } var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom')); sectionHeight = (windowsHeight - paddings); } return sectionHeight; } /** * Adds a css3 transform property to the container class with or without animation depending on the animated param. */ function transformContainer(translate3d, animated){ if(animated){ addAnimation(container); }else{ removeAnimation(container); } container.css(getTransforms(translate3d)); //syncronously removing the class after the animation has been applied. setTimeout(function(){ container.removeClass(NO_TRANSITION); },10); } /** * Gets a section by its anchor / index */ function getSectionByAnchor(sectionAnchor){ if(!sectionAnchor) return []; var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]'); if(!section.length){ section = $(SECTION_SEL).eq( sectionAnchor -1); } return section; } /** * Gets a slide inside a given section by its anchor / index */ function getSlideByAnchor(slideAnchor, section){ var slides = section.find(SLIDES_WRAPPER_SEL); var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]'); if(!slide.length){ slide = slides.find(SLIDE_SEL).eq(slideAnchor); } return slide; } /** * Scrolls to the given section and slide anchors */ function scrollPageAndSlide(destiny, slide){ var section = getSectionByAnchor(destiny); //do nothing if there's no section with the given anchor name if(!section.length) return; //default slide if (typeof slide === 'undefined') { slide = 0; } //we need to scroll to the section and then to the slide if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){ scrollPage(section, function(){ scrollSlider(section, slide); }); } //if we were already in the section else{ scrollSlider(section, slide); } } /** * Scrolls the slider to the given slide destination for the given section */ function scrollSlider(section, slideAnchor){ if(typeof slideAnchor !== 'undefined'){ var slides = section.find(SLIDES_WRAPPER_SEL); var destiny = getSlideByAnchor(slideAnchor, section); if(destiny.length){ landscapeScroll(slides, destiny); } } } /** * Creates a landscape navigation bar with dots for horizontal sliders. */ function addSlidesNavigation(section, numSlides){ section.append('
        '); var nav = section.find(SLIDES_NAV_SEL); //top or bottom nav.addClass(options.slidesNavPosition); for(var i=0; i< numSlides; i++){ nav.find('ul').append('
      • '); } //centering it nav.css('margin-left', '-' + (nav.width()/2) + 'px'); nav.find('li').first().find('a').addClass(ACTIVE); } /** * Sets the state of the website depending on the active section/slide. * It changes the URL hash when needed and updates the body class. */ function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ var sectionHash = ''; if(options.anchors.length && !options.lockAnchors){ //isn't it the first slide? if(slideIndex){ if(typeof anchorLink !== 'undefined'){ sectionHash = anchorLink; } //slide without anchor link? We take the index instead. if(typeof slideAnchor === 'undefined'){ slideAnchor = slideIndex; } lastScrolledSlide = slideAnchor; setUrlHash(sectionHash + '/' + slideAnchor); //first slide won't have slide anchor, just the section one }else if(typeof slideIndex !== 'undefined'){ lastScrolledSlide = slideAnchor; setUrlHash(anchorLink); } //section without slides else{ setUrlHash(anchorLink); } } setBodyClass(); } /** * Sets the URL hash. */ function setUrlHash(url){ //Uncode addition if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer ) return false; if(options.recordHistory){ location.hash = url; }else{ //Uncode addition //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) // if(isTouchDevice || isTouch){ // window.history.replaceState(undefined, undefined, '#' + url); // }else{ // var baseUrl = window.location.href.split('#')[0]; // window.location.replace( baseUrl + '#' + url ); // } return false; } } /** * Gets the anchor for the given slide / section. Its index will be used if there's none. */ function getAnchor(element){ var anchor = element.data('anchor'); var index = element.index(); //Slide without anchor link? We take the index instead. if(typeof anchor === 'undefined'){ anchor = index; } return anchor; } /** * Sets a class for the body of the page depending on the active section / slide */ function setBodyClass(){ var section = $(SECTION_ACTIVE_SEL); var slide = section.find(SLIDE_ACTIVE_SEL); var sectionAnchor = getAnchor(section); var slideAnchor = getAnchor(slide); var text = String(sectionAnchor); if(slide.length){ text = text + '-' + slideAnchor; } //changing slash for dash to make it a valid CSS style text = text.replace('/', '-').replace('#',''); //removing previous anchor classes var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); $body[0].className = $body[0].className.replace(classRe, ''); //adding the current anchor $body.addClass(VIEWING_PREFIX + '-' + text); } /** * Checks for translate3d support * @return boolean * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support */ function support3d() { var el = document.createElement('p'), has3d, transforms = { 'webkitTransform':'-webkit-transform', 'OTransform':'-o-transform', 'msTransform':'-ms-transform', 'MozTransform':'-moz-transform', 'transform':'transform' }; // Add it to the body to get the computed style. document.body.insertBefore(el, null); for (var t in transforms) { if (el.style[t] !== undefined) { el.style[t] = 'translate3d(1px,1px,1px)'; has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); } } document.body.removeChild(el); return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); } /** * Removes the auto scrolling action fired by the mouse wheel and trackpad. * After this function is called, the mousewheel and trackpad movements won't scroll through sections. */ function removeMouseWheelHandler(){ if (document.addEventListener) { document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox } else { document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 } } /** * Adds the auto scrolling action for the mouse wheel and trackpad. * After this function is called, the mousewheel and trackpad movements will scroll through sections * https://developer.mozilla.org/en-US/docs/Web/Events/wheel */ function addMouseWheelHandler(){ var prefix = ''; var _addEventListener; if (window.addEventListener){ _addEventListener = "addEventListener"; }else{ _addEventListener = "attachEvent"; prefix = 'on'; } // detect available wheel event var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox var passiveEvent = g_supportsPassive ? {passive: false }: false; if(support == 'DOMMouseScroll'){ document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent); } //handle MozMousePixelScroll in older Firefox else{ document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent); } } /** * Binding the mousemove when the mouse's middle button is pressed */ function addMiddleWheelHandler(){ container .on('mousedown', mouseDownHandler) .on('mouseup', mouseUpHandler); } /** * Unbinding the mousemove when the mouse's middle button is released */ function removeMiddleWheelHandler(){ container .off('mousedown', mouseDownHandler) .off('mouseup', mouseUpHandler); } /** * Adds the possibility to auto scroll through sections on touch devices. */ function addTouchHandler(){ if(isTouchDevice || isTouch){ if(options.autoScrolling){ $body.off(events.touchmove).on(events.touchmove, preventBouncing); } $(WRAPPER_SEL) .off(events.touchstart).on(events.touchstart, touchStartHandler) .off(events.touchmove).on(events.touchmove, touchMoveHandler); } } /** * Removes the auto scrolling for touch devices. */ function removeTouchHandler(){ if(isTouchDevice || isTouch){ $(WRAPPER_SEL) .off(events.touchstart) .off(events.touchmove); } } /* * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11) * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx */ function getMSPointer(){ var pointer; //IE >= 11 & rest of browsers if(window.PointerEvent){ pointer = { down: 'pointerdown', move: 'pointermove'}; } //IE < 11 else{ pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; } return pointer; } /** * Gets the pageX and pageY properties depending on the browser. * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 */ function getEventsPage(e){ var events = []; events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 if(isTouch && isReallyTouch(e) && options.scrollBar){ events.y = e.touches[0].pageY; events.x = e.touches[0].pageX; } return events; } /** * Slides silently (with no animation) the active slider to the given slide. * @param noCallback {bool} true or defined -> no callbacks */ function silentLandscapeScroll(activeSlide, noCallbacks){ setScrollingSpeed (0, 'internal'); if(typeof noCallbacks !== 'undefined'){ //preventing firing callbacks afterSlideLoad etc. isResizing = true; } landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide); if(typeof noCallbacks !== 'undefined'){ isResizing = false; } setScrollingSpeed(originals.scrollingSpeed, 'internal'); } /** * Scrolls silently (with no animation) the page to the given Y position. */ function silentScroll(top){ // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 // that's why we round it to 0. var roundedTop = Math.round(top); if (options.css3 && options.autoScrolling && !options.scrollBar){ var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)'; transformContainer(translate3d, false); } else if(options.autoScrolling && !options.scrollBar){ container.css('top', -roundedTop); } else{ $htmlBody.scrollTop(roundedTop); } } /** * Returns the cross-browser transform string. */ function getTransforms(translate3d){ return { '-webkit-transform': translate3d, '-moz-transform': translate3d, '-ms-transform':translate3d, 'transform': translate3d }; } /** * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) * @type m (mouse) or k (keyboard) */ function setIsScrollAllowed(value, direction, type){ switch (direction){ case 'up': isScrollAllowed[type].up = value; break; case 'down': isScrollAllowed[type].down = value; break; case 'left': isScrollAllowed[type].left = value; break; case 'right': isScrollAllowed[type].right = value; break; case 'all': if(type == 'm'){ setAllowScrolling(value); }else{ setKeyboardScrolling(value); } } } /* * Destroys fullpage.js plugin events and optinally its html markup and styles */ function destroy(all){ setAutoScrolling(false, 'internal'); setAllowScrolling(false); setKeyboardScrolling(false); container.addClass(DESTROYED); clearTimeout(afterSlideLoadsId); clearTimeout(afterSectionLoadsId); clearTimeout(resizeId); clearTimeout(scrollId); clearTimeout(scrollId2); $window .off('scroll', scrollHandler) .off('hashchange', hashChangeHandler) .off('resize', resizeHandler); $document .off('click touchstart', SECTION_NAV_SEL + ' a') .off('mouseenter', SECTION_NAV_SEL + ' li') .off('mouseleave', SECTION_NAV_SEL + ' li') .off('click touchstart', SLIDES_NAV_LINK_SEL) .off('mouseover', options.normalScrollElements) .off('mouseout', options.normalScrollElements); $(SECTION_SEL) .off('click touchstart', SLIDES_ARROW_SEL); clearTimeout(afterSlideLoadsId); clearTimeout(afterSectionLoadsId); //lets make a mess! if(all){ destroyStructure(); } } /* * Removes inline styles added by fullpage.js */ function destroyStructure(){ //reseting the `top` or `translate` properties to 0 silentScroll(0); //loading all the lazy load content container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ setSrc($(this), 'src'); }); container.find('img[data-srcset]').each(function(){ setSrc($(this), 'srcset'); }); $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove(); //removing inline styles $(SECTION_SEL).css( { 'height': '', 'background-color' : '', 'padding': '' }); $(SLIDE_SEL).css( { 'width': '' }); container.css({ 'height': '', 'position': '', '-ms-touch-action': '', 'touch-action': '' }); $htmlBody.css({ 'overflow': '', 'height': '' }); // remove .fp-enabled class $('html').removeClass(ENABLED); // remove .fp-responsive class $body.removeClass(RESPONSIVE); // remove all of the .fp-viewing- classes $.each($body.get(0).className.split(/\s+/), function (index, className) { if (className.indexOf(VIEWING_PREFIX) === 0) { $body.removeClass(className); } }); //removing added classes $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){ options.scrollOverflowHandler.remove($(this)); $(this).removeClass(TABLE + ' ' + ACTIVE); }); removeAnimation(container); //Unwrapping content container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){ //unwrap not being use in case there's no child element inside and its just text $(this).replaceWith(this.childNodes); }); //removing the applied transition from the fullpage wrapper container.css({ '-webkit-transition': 'none', 'transition': 'none' }); //scrolling the page to the top with no animation $htmlBody.scrollTop(0); //removing selectors var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; $.each(usedSelectors, function(index, value){ $('.' + value).removeClass(value); }); } /* * Sets the state for a variable with multiple states (original, and temporal) * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. * This function is used to keep track of both states, the original and the temporal one. * If type is not 'internal', then we assume the user is globally changing the variable. */ function setVariableState(variable, value, type){ options[variable] = value; if(type !== 'internal'){ originals[variable] = value; } } /** * Displays warnings */ function displayWarnings(){ var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax']; //UNCODE.addition // if($('html').hasClass(ENABLED)){ // showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); // return; // } // Disable mutually exclusive settings //UNCODE.addition // if (options.continuousVertical && // (options.loopTop || options.loopBottom)) { // options.continuousVertical = false; // showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); // } // if(options.scrollBar && options.scrollOverflow){ // showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); // } // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){ // options.continuousVertical = false; // showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); // } //using extensions? Wrong file! $.each(extensions, function(index, extension){ //is the option set to true? if(options[extension]){ showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension); } }); //anchors can not have the same value as any element ID or NAME $.each(options.anchors, function(index, name){ //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) var nameAttr = $document.find('[name]').filter(function() { return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase(); }); var idAttr = $document.find('[id]').filter(function() { return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase(); }); if(idAttr.length || nameAttr.length ){ showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property'); nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property'); } }); } /** * Shows a message in the console of the given type. */ function showError(type, text){ console && console[type] && console[type]('fullPage: ' + text); } }; //end of $.fn.fullpage if(typeof IScroll !== 'undefined'){ /* * Turns iScroll `mousewheel` option off dynamically * https://github.com/cubiq/iscroll/issues/1036 */ IScroll.prototype.wheelOn = function () { this.wrapper.addEventListener('wheel', this); this.wrapper.addEventListener('mousewheel', this); this.wrapper.addEventListener('DOMMouseScroll', this); }; /* * Turns iScroll `mousewheel` option on dynamically * https://github.com/cubiq/iscroll/issues/1036 */ IScroll.prototype.wheelOff = function () { this.wrapper.removeEventListener('wheel', this); this.wrapper.removeEventListener('mousewheel', this); this.wrapper.removeEventListener('DOMMouseScroll', this); }; } /** * An object to handle overflow scrolling. * This uses jquery.slimScroll to accomplish overflow scrolling. * It is possible to pass in an alternate scrollOverflowHandler * to the fullpage.js option that implements the same functions * as this handler. * * @type {Object} */ var iscrollHandler = { refreshId: null, iScrollInstances: [], // Enables or disables the mouse wheel for the active section or all slides in it toggleWheel: function(value){ var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); scrollable.each(function(){ var iScrollInstance = $(this).data('iscrollInstance'); if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ if(value){ iScrollInstance.wheelOn(); } else{ iScrollInstance.wheelOff(); } } }); }, /** * Turns off iScroll for the destination section. * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would * scroll the destination section/slide before the sections animations ends. */ onLeave: function(){ iscrollHandler.toggleWheel(false); }, // Turns off iScroll for the leaving section beforeLeave: function(){ iscrollHandler.onLeave() }, // Turns on iScroll on section load afterLoad: function(){ iscrollHandler.toggleWheel(true); }, /** * Called when overflow scrolling is needed for a section. * * @param {Object} element jQuery object containing current section * @param {Number} scrollHeight Current window height in pixels */ create: function(element, scrollHeight) { var scrollable = element.find(SCROLLABLE_SEL); scrollable.height(scrollHeight); scrollable.each(function() { var $this = $(this); var iScrollInstance = $this.data('iscrollInstance'); if (iScrollInstance) { $.each(iscrollHandler.iScrollInstances, function(){ $(this).destroy(); }); } iScrollInstance = new IScroll($this.get(0), iscrollOptions); iscrollHandler.iScrollInstances.push(iScrollInstance); //off by default until the section gets active iScrollInstance.wheelOff(); $this.data('iscrollInstance', iScrollInstance); }); }, /** * Return a boolean depending on whether the scrollable element is a * the end or at the start of the scrolling depending on the given type. * * @param {String} type Either 'top' or 'bottom' * @param {Object} scrollable jQuery object for the scrollable element * @return {Boolean} */ isScrolled: function(type, scrollable) { var scroller = scrollable.data('iscrollInstance'); //no scroller? if (!scroller) { return true; } //Uncode addition var uncode_body_borders = parseFloat($('.body-borders').attr('data-border')) || 0; //End Uncode addition if (type === 'top') { return scroller.y >= 0 && !scrollable.scrollTop(); } else if (type === 'bottom') { //Uncode change // return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; return (0 - scroller.y) + scrollable.scrollTop() + 1 + ( uncode_body_borders * 2 ) + scrollable.innerHeight() >= scrollable[0].scrollHeight; //End Uncode change } }, /** * Returns the scrollable element for the given section. * If there are landscape slides, will only return a scrollable element * if it is in the active slide. * * @param {Object} activeSection jQuery object containing current section * @return {Boolean} */ scrollable: function(activeSection){ // if there are landscape slides, we check if the scrolling bar is in the current one or not if (activeSection.find(SLIDES_WRAPPER_SEL).length) { return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); } return activeSection.find(SCROLLABLE_SEL); }, /** * Returns the scroll height of the wrapped content. * If this is larger than the window height minus section padding, * overflow scrolling is needed. * * @param {Object} element jQuery object containing current section * @return {Number} */ scrollHeight: function(element) { return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; }, /** * Called when overflow scrolling is no longer needed for a section. * * @param {Object} element jQuery object containing current section */ remove: function(element) { var scrollable = element.find(SCROLLABLE_SEL); if (scrollable.length) { var iScrollInstance = scrollable.data('iscrollInstance'); iScrollInstance.destroy(); scrollable.data('iscrollInstance', null); } element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); }, /** * Called when overflow scrolling has already been setup but the * window height has potentially changed. * * @param {Object} element jQuery object containing current section * @param {Number} scrollHeight Current window height in pixels */ update: function(element, scrollHeight) { //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a //short period of time. //it also comes on handy because iScroll requires the use of timeout when using `refresh`. clearTimeout(iscrollHandler.refreshId); iscrollHandler.refreshId = setTimeout(function(){ $.each(iscrollHandler.iScrollInstances, function(){ $(this).get(0).refresh(); }); }, 150); //updating the wrappers height element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); }, /** * Called to get any additional elements needed to wrap the section * content in order to facilitate overflow scrolling. * * @return {String|Object} Can be a string containing HTML, * a DOM element, or jQuery object. */ wrapContent: function() { return '
        '; } }; }); (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.window = global.window || {})); }(this, (function (exports) { 'use strict'; /*! * ScrollTrigger 3.8.0 * https://greensock.com * * @license Copyright 2008-2021, GreenSock. All rights reserved. * Subject to the terms at https://greensock.com/standard-license or for * Club GreenSock members, the agreement issued with that membership. * @author: Jack Doyle, jack@greensock.com */ var gsap, _coreInitted, _win, _doc, _docEl, _body, _root, _resizeDelay, _raf, _request, _toArray, _clamp, _time2, _syncInterval, _refreshing, _pointerIsDown, _transformProp, _i, _prevWidth, _prevHeight, _autoRefresh, _sort, _suppressOverwrites, _ignoreResize, _limitCallbacks, _startup = 1, _proxies = [], _scrollers = [], _getTime = Date.now, _time1 = _getTime(), _lastScrollTime = 0, _enabled = 1, _passThrough = function _passThrough(v) { return v; }, _getTarget = function _getTarget(t) { return _toArray(t)[0] || (_isString(t) ? console.warn("Element not found:", t) : null); }, _round = function _round(value) { return Math.round(value * 100000) / 100000 || 0; }, _windowExists = function _windowExists() { return typeof window !== "undefined"; }, _getGSAP = function _getGSAP() { return gsap || _windowExists() && (gsap = window.gsap) && gsap.registerPlugin && gsap; }, _isViewport = function _isViewport(e) { return !!~_root.indexOf(e); }, _getProxyProp = function _getProxyProp(element, property) { return ~_proxies.indexOf(element) && _proxies[_proxies.indexOf(element) + 1][property]; }, _getScrollFunc = function _getScrollFunc(element, _ref) { var s = _ref.s, sc = _ref.sc; var i = _scrollers.indexOf(element), offset = sc === _vertical.sc ? 1 : 2; !~i && (i = _scrollers.push(element) - 1); return _scrollers[i + offset] || (_scrollers[i + offset] = _getProxyProp(element, s) || (_isViewport(element) ? sc : function (value) { return arguments.length ? element[s] = value : element[s]; })); }, _getBoundsFunc = function _getBoundsFunc(element) { return _getProxyProp(element, "getBoundingClientRect") || (_isViewport(element) ? function () { _winOffsets.width = _win.innerWidth; _winOffsets.height = _win.innerHeight; return _winOffsets; } : function () { return _getBounds(element); }); }, _getSizeFunc = function _getSizeFunc(scroller, isViewport, _ref2) { var d = _ref2.d, d2 = _ref2.d2, a = _ref2.a; return (a = _getProxyProp(scroller, "getBoundingClientRect")) ? function () { return a()[d]; } : function () { return (isViewport ? _win["inner" + d2] : scroller["client" + d2]) || 0; }; }, _getOffsetsFunc = function _getOffsetsFunc(element, isViewport) { return !isViewport || ~_proxies.indexOf(element) ? _getBoundsFunc(element) : function () { return _winOffsets; }; }, _maxScroll = function _maxScroll(element, _ref3) { var s = _ref3.s, d2 = _ref3.d2, d = _ref3.d, a = _ref3.a; return (s = "scroll" + d2) && (a = _getProxyProp(element, s)) ? a() - _getBoundsFunc(element)()[d] : _isViewport(element) ? (_body[s] || _docEl[s]) - (_win["inner" + d2] || _docEl["client" + d2] || _body["client" + d2]) : element[s] - element["offset" + d2]; }, _iterateAutoRefresh = function _iterateAutoRefresh(func, events) { for (var i = 0; i < _autoRefresh.length; i += 3) { (!events || ~events.indexOf(_autoRefresh[i + 1])) && func(_autoRefresh[i], _autoRefresh[i + 1], _autoRefresh[i + 2]); } }, _isString = function _isString(value) { return typeof value === "string"; }, _isFunction = function _isFunction(value) { return typeof value === "function"; }, _isNumber = function _isNumber(value) { return typeof value === "number"; }, _isObject = function _isObject(value) { return typeof value === "object"; }, _callIfFunc = function _callIfFunc(value) { return _isFunction(value) && value(); }, _combineFunc = function _combineFunc(f1, f2) { return function () { var result1 = _callIfFunc(f1), result2 = _callIfFunc(f2); return function () { _callIfFunc(result1); _callIfFunc(result2); }; }; }, _endAnimation = function _endAnimation(animation, reversed, pause) { return animation && animation.progress(reversed ? 0 : 1) && pause && animation.pause(); }, _callback = function _callback(self, func) { var result = func(self); result && result.totalTime && (self.callbackAnimation = result); }, _abs = Math.abs, _scrollLeft = "scrollLeft", _scrollTop = "scrollTop", _left = "left", _top = "top", _right = "right", _bottom = "bottom", _width = "width", _height = "height", _Right = "Right", _Left = "Left", _Top = "Top", _Bottom = "Bottom", _padding = "padding", _margin = "margin", _Width = "Width", _Height = "Height", _px = "px", _horizontal = { s: _scrollLeft, p: _left, p2: _Left, os: _right, os2: _Right, d: _width, d2: _Width, a: "x", sc: function sc(value) { return arguments.length ? _win.scrollTo(value, _vertical.sc()) : _win.pageXOffset || _doc[_scrollLeft] || _docEl[_scrollLeft] || _body[_scrollLeft] || 0; } }, _vertical = { s: _scrollTop, p: _top, p2: _Top, os: _bottom, os2: _Bottom, d: _height, d2: _Height, a: "y", op: _horizontal, sc: function sc(value) { return arguments.length ? _win.scrollTo(_horizontal.sc(), value) : _win.pageYOffset || _doc[_scrollTop] || _docEl[_scrollTop] || _body[_scrollTop] || 0; } }, _getComputedStyle = function _getComputedStyle(element) { return _win.getComputedStyle(element); }, _makePositionable = function _makePositionable(element) { var position = _getComputedStyle(element).position; element.style.position = position === "absolute" || position === "fixed" ? position : "relative"; }, _setDefaults = function _setDefaults(obj, defaults) { for (var p in defaults) { p in obj || (obj[p] = defaults[p]); } return obj; }, _getBounds = function _getBounds(element, withoutTransforms) { var tween = withoutTransforms && _getComputedStyle(element)[_transformProp] !== "matrix(1, 0, 0, 1, 0, 0)" && gsap.to(element, { x: 0, y: 0, xPercent: 0, yPercent: 0, rotation: 0, rotationX: 0, rotationY: 0, scale: 1, skewX: 0, skewY: 0 }).progress(1), bounds = element.getBoundingClientRect(); tween && tween.progress(0).kill(); return bounds; }, _getSize = function _getSize(element, _ref4) { var d2 = _ref4.d2; return element["offset" + d2] || element["client" + d2] || 0; }, _getLabelRatioArray = function _getLabelRatioArray(timeline) { var a = [], labels = timeline.labels, duration = timeline.duration(), p; for (p in labels) { a.push(labels[p] / duration); } return a; }, _getClosestLabel = function _getClosestLabel(animation) { return function (value) { return gsap.utils.snap(_getLabelRatioArray(animation), value); }; }, _snapDirectional = function _snapDirectional(snapIncrementOrArray) { var snap = gsap.utils.snap(snapIncrementOrArray), a = Array.isArray(snapIncrementOrArray) && snapIncrementOrArray.slice(0).sort(function (a, b) { return a - b; }); return a ? function (value, direction) { var i; if (!direction) { return snap(value); } if (direction > 0) { value -= 1e-4; for (i = 0; i < a.length; i++) { if (a[i] >= value) { return a[i]; } } return a[i - 1]; } else { i = a.length; value += 1e-4; while (i--) { if (a[i] <= value) { return a[i]; } } } return a[0]; } : function (value, direction) { var snapped = snap(value); return !direction || Math.abs(snapped - value) < 0.001 || snapped - value < 0 === direction < 0 ? snapped : snap(direction < 0 ? value - snapIncrementOrArray : value + snapIncrementOrArray); }; }, _getLabelAtDirection = function _getLabelAtDirection(timeline) { return function (value, st) { return _snapDirectional(_getLabelRatioArray(timeline))(value, st.direction); }; }, _multiListener = function _multiListener(func, element, types, callback) { return types.split(",").forEach(function (type) { return func(element, type, callback); }); }, _addListener = function _addListener(element, type, func) { return element.addEventListener(type, func, { passive: true }); }, _removeListener = function _removeListener(element, type, func) { return element.removeEventListener(type, func); }, _markerDefaults = { startColor: "green", endColor: "red", indent: 0, fontSize: "16px", fontWeight: "normal" }, _defaults = { toggleActions: "play", anticipatePin: 0 }, _keywords = { top: 0, left: 0, center: 0.5, bottom: 1, right: 1 }, _offsetToPx = function _offsetToPx(value, size) { if (_isString(value)) { var eqIndex = value.indexOf("="), relative = ~eqIndex ? +(value.charAt(eqIndex - 1) + 1) * parseFloat(value.substr(eqIndex + 1)) : 0; if (~eqIndex) { value.indexOf("%") > eqIndex && (relative *= size / 100); value = value.substr(0, eqIndex - 1); } value = relative + (value in _keywords ? _keywords[value] * size : ~value.indexOf("%") ? parseFloat(value) * size / 100 : parseFloat(value) || 0); } return value; }, _createMarker = function _createMarker(type, name, container, direction, _ref5, offset, matchWidthEl, containerAnimation) { var startColor = _ref5.startColor, endColor = _ref5.endColor, fontSize = _ref5.fontSize, indent = _ref5.indent, fontWeight = _ref5.fontWeight; var e = _doc.createElement("div"), useFixedPosition = _isViewport(container) || _getProxyProp(container, "pinType") === "fixed", isScroller = type.indexOf("scroller") !== -1, parent = useFixedPosition ? _body : container, isStart = type.indexOf("start") !== -1, color = isStart ? startColor : endColor, css = "border-color:" + color + ";font-size:" + fontSize + ";color:" + color + ";font-weight:" + fontWeight + ";pointer-events:none;white-space:nowrap;font-family:sans-serif,Arial;z-index:1000;padding:4px 8px;border-width:0;border-style:solid;"; css += "position:" + ((isScroller || containerAnimation) && useFixedPosition ? "fixed;" : "absolute;"); (isScroller || containerAnimation || !useFixedPosition) && (css += (direction === _vertical ? _right : _bottom) + ":" + (offset + parseFloat(indent)) + "px;"); matchWidthEl && (css += "box-sizing:border-box;text-align:left;width:" + matchWidthEl.offsetWidth + "px;"); e._isStart = isStart; e.setAttribute("class", "gsap-marker-" + type + (name ? " marker-" + name : "")); e.style.cssText = css; e.innerText = name || name === 0 ? type + "-" + name : type; parent.children[0] ? parent.insertBefore(e, parent.children[0]) : parent.appendChild(e); e._offset = e["offset" + direction.op.d2]; _positionMarker(e, 0, direction, isStart); return e; }, _positionMarker = function _positionMarker(marker, start, direction, flipped) { var vars = { display: "block" }, side = direction[flipped ? "os2" : "p2"], oppositeSide = direction[flipped ? "p2" : "os2"]; marker._isFlipped = flipped; vars[direction.a + "Percent"] = flipped ? -100 : 0; vars[direction.a] = flipped ? "1px" : 0; vars["border" + side + _Width] = 1; vars["border" + oppositeSide + _Width] = 0; vars[direction.p] = start + "px"; gsap.set(marker, vars); }, _triggers = [], _ids = {}, _sync = function _sync() { return _getTime() - _lastScrollTime > 20 && _updateAll(); }, _onScroll = function _onScroll() { var time = _getTime(); if (_lastScrollTime !== time) { _updateAll(); _lastScrollTime || _dispatch("scrollStart"); _lastScrollTime = time; } else if (!_request) { _request = _raf(_updateAll); } }, _onResize = function _onResize() { return !_refreshing && !_ignoreResize && !_doc.fullscreenElement && _resizeDelay.restart(true); }, _listeners = {}, _emptyArray = [], _media = [], _creatingMedia, _lastMediaTick, _onMediaChange = function _onMediaChange(e) { var tick = gsap.ticker.frame, matches = [], i = 0, index; if (_lastMediaTick !== tick || _startup) { _revertAll(); for (; i < _media.length; i += 4) { index = _win.matchMedia(_media[i]).matches; if (index !== _media[i + 3]) { _media[i + 3] = index; index ? matches.push(i) : _revertAll(1, _media[i]) || _isFunction(_media[i + 2]) && _media[i + 2](); } } _revertRecorded(); for (i = 0; i < matches.length; i++) { index = matches[i]; _creatingMedia = _media[index]; _media[index + 2] = _media[index + 1](e); } _creatingMedia = 0; _coreInitted && _refreshAll(0, 1); _lastMediaTick = tick; _dispatch("matchMedia"); } }, _softRefresh = function _softRefresh() { return _removeListener(ScrollTrigger, "scrollEnd", _softRefresh) || _refreshAll(true); }, _dispatch = function _dispatch(type) { return _listeners[type] && _listeners[type].map(function (f) { return f(); }) || _emptyArray; }, _savedStyles = [], _revertRecorded = function _revertRecorded(media) { for (var i = 0; i < _savedStyles.length; i += 5) { if (!media || _savedStyles[i + 4] === media) { _savedStyles[i].style.cssText = _savedStyles[i + 1]; _savedStyles[i].getBBox && _savedStyles[i].setAttribute("transform", _savedStyles[i + 2] || ""); _savedStyles[i + 3].uncache = 1; } } }, _revertAll = function _revertAll(kill, media) { var trigger; for (_i = 0; _i < _triggers.length; _i++) { trigger = _triggers[_i]; if (!media || trigger.media === media) { if (kill) { trigger.kill(1); } else { trigger.revert(); } } } media && _revertRecorded(media); media || _dispatch("revert"); }, _clearScrollMemory = function _clearScrollMemory() { return _scrollers.forEach(function (obj) { return typeof obj === "function" && (obj.rec = 0); }); }, _refreshingAll, _refreshAll = function _refreshAll(force, skipRevert) { if (_lastScrollTime && !force) { _addListener(ScrollTrigger, "scrollEnd", _softRefresh); return; } _refreshingAll = true; var refreshInits = _dispatch("refreshInit"); _sort && ScrollTrigger.sort(); skipRevert || _revertAll(); _triggers.forEach(function (t) { return t.refresh(); }); refreshInits.forEach(function (result) { return result && result.render && result.render(-1); }); _clearScrollMemory(); _resizeDelay.pause(); _refreshingAll = false; _dispatch("refresh"); }, _lastScroll = 0, _direction = 1, _updateAll = function _updateAll() { if (!_refreshingAll) { var l = _triggers.length, time = _getTime(), recordVelocity = time - _time1 >= 50, scroll = l && _triggers[0].scroll(); _direction = _lastScroll > scroll ? -1 : 1; _lastScroll = scroll; if (recordVelocity) { if (_lastScrollTime && !_pointerIsDown && time - _lastScrollTime > 200) { _lastScrollTime = 0; _dispatch("scrollEnd"); } _time2 = _time1; _time1 = time; } if (_direction < 0) { _i = l; while (_i-- > 0) { _triggers[_i] && _triggers[_i].update(0, recordVelocity); } _direction = 1; } else { for (_i = 0; _i < l; _i++) { _triggers[_i] && _triggers[_i].update(0, recordVelocity); } } _request = 0; } }, _propNamesToCopy = [_left, _top, _bottom, _right, _margin + _Bottom, _margin + _Right, _margin + _Top, _margin + _Left, "display", "flexShrink", "float", "zIndex", "grid-column-start", "grid-column-end", "grid-row-start", "grid-row-end", "grid-area", "justify-self", "align-self", "place-self"], _stateProps = _propNamesToCopy.concat([_width, _height, "boxSizing", "max" + _Width, "max" + _Height, "position", _margin, _padding, _padding + _Top, _padding + _Right, _padding + _Bottom, _padding + _Left]), _swapPinOut = function _swapPinOut(pin, spacer, state) { _setState(state); var cache = pin._gsap; if (cache.spacerIsNative) { _setState(cache.spacerState); } else if (pin.parentNode === spacer) { var parent = spacer.parentNode; if (parent) { parent.insertBefore(pin, spacer); parent.removeChild(spacer); } } }, _swapPinIn = function _swapPinIn(pin, spacer, cs, spacerState) { if (pin.parentNode !== spacer) { var i = _propNamesToCopy.length, spacerStyle = spacer.style, pinStyle = pin.style, p; while (i--) { p = _propNamesToCopy[i]; spacerStyle[p] = cs[p]; } spacerStyle.position = cs.position === "absolute" ? "absolute" : "relative"; cs.display === "inline" && (spacerStyle.display = "inline-block"); pinStyle[_bottom] = pinStyle[_right] = "auto"; spacerStyle.overflow = "visible"; spacerStyle.boxSizing = "border-box"; spacerStyle[_width] = _getSize(pin, _horizontal) + _px; spacerStyle[_height] = _getSize(pin, _vertical) + _px; spacerStyle[_padding] = pinStyle[_margin] = pinStyle[_top] = pinStyle[_left] = "0"; _setState(spacerState); pinStyle[_width] = pinStyle["max" + _Width] = cs[_width]; pinStyle[_height] = pinStyle["max" + _Height] = cs[_height]; pinStyle[_padding] = cs[_padding]; pin.parentNode.insertBefore(spacer, pin); spacer.appendChild(pin); } }, _capsExp = /([A-Z])/g, _setState = function _setState(state) { if (state) { var style = state.t.style, l = state.length, i = 0, p, value; (state.t._gsap || gsap.core.getCache(state.t)).uncache = 1; for (; i < l; i += 2) { value = state[i + 1]; p = state[i]; if (value) { style[p] = value; } else if (style[p]) { style.removeProperty(p.replace(_capsExp, "-$1").toLowerCase()); } } } }, _getState = function _getState(element) { var l = _stateProps.length, style = element.style, state = [], i = 0; for (; i < l; i++) { state.push(_stateProps[i], style[_stateProps[i]]); } state.t = element; return state; }, _copyState = function _copyState(state, override, omitOffsets) { var result = [], l = state.length, i = omitOffsets ? 8 : 0, p; for (; i < l; i += 2) { p = state[i]; result.push(p, p in override ? override[p] : state[i + 1]); } result.t = state.t; return result; }, _winOffsets = { left: 0, top: 0 }, _parsePosition = function _parsePosition(value, trigger, scrollerSize, direction, scroll, marker, markerScroller, self, scrollerBounds, borderWidth, useFixedPosition, scrollerMax, containerAnimation) { _isFunction(value) && (value = value(self)); if (_isString(value) && value.substr(0, 3) === "max") { value = scrollerMax + (value.charAt(4) === "=" ? _offsetToPx("0" + value.substr(3), scrollerSize) : 0); } var time = containerAnimation ? containerAnimation.time() : 0, p1, p2, element; containerAnimation && containerAnimation.seek(0); if (!_isNumber(value)) { _isFunction(trigger) && (trigger = trigger(self)); var offsets = value.split(" "), bounds, localOffset, globalOffset, display; element = _getTarget(trigger) || _body; bounds = _getBounds(element) || {}; if ((!bounds || !bounds.left && !bounds.top) && _getComputedStyle(element).display === "none") { display = element.style.display; element.style.display = "block"; bounds = _getBounds(element); display ? element.style.display = display : element.style.removeProperty("display"); } localOffset = _offsetToPx(offsets[0], bounds[direction.d]); globalOffset = _offsetToPx(offsets[1] || "0", scrollerSize); value = bounds[direction.p] - scrollerBounds[direction.p] - borderWidth + localOffset + scroll - globalOffset; markerScroller && _positionMarker(markerScroller, globalOffset, direction, scrollerSize - globalOffset < 20 || markerScroller._isStart && globalOffset > 20); scrollerSize -= scrollerSize - globalOffset; } else if (markerScroller) { _positionMarker(markerScroller, scrollerSize, direction, true); } if (marker) { var position = value + scrollerSize, isStart = marker._isStart; p1 = "scroll" + direction.d2; _positionMarker(marker, position, direction, isStart && position > 20 || !isStart && (useFixedPosition ? Math.max(_body[p1], _docEl[p1]) : marker.parentNode[p1]) <= position + 1); if (useFixedPosition) { scrollerBounds = _getBounds(markerScroller); useFixedPosition && (marker.style[direction.op.p] = scrollerBounds[direction.op.p] - direction.op.m - marker._offset + _px); } } if (containerAnimation && element) { p1 = _getBounds(element); containerAnimation.seek(scrollerMax); p2 = _getBounds(element); containerAnimation._caScrollDist = p1[direction.p] - p2[direction.p]; value = value / containerAnimation._caScrollDist * scrollerMax; } containerAnimation && containerAnimation.seek(time); return containerAnimation ? value : Math.round(value); }, _prefixExp = /(?:webkit|moz|length|cssText|inset)/i, _reparent = function _reparent(element, parent, top, left) { if (element.parentNode !== parent) { var style = element.style, p, cs; if (parent === _body) { element._stOrig = style.cssText; cs = _getComputedStyle(element); for (p in cs) { if (!+p && !_prefixExp.test(p) && cs[p] && typeof style[p] === "string" && p !== "0") { style[p] = cs[p]; } } style.top = top; style.left = left; } else { style.cssText = element._stOrig; } gsap.core.getCache(element).uncache = 1; parent.appendChild(element); } }, _getTweenCreator = function _getTweenCreator(scroller, direction) { var getScroll = _getScrollFunc(scroller, direction), prop = "_scroll" + direction.p2, lastScroll1, lastScroll2, getTween = function getTween(scrollTo, vars, initialValue, change1, change2) { var tween = getTween.tween, onComplete = vars.onComplete, modifiers = {}; tween && tween.kill(); lastScroll1 = Math.round(initialValue); vars[prop] = scrollTo; vars.modifiers = modifiers; modifiers[prop] = function (value) { value = _round(getScroll()); if (value !== lastScroll1 && value !== lastScroll2 && Math.abs(value - lastScroll1) > 2) { tween.kill(); getTween.tween = 0; } else { value = initialValue + change1 * tween.ratio + change2 * tween.ratio * tween.ratio; } lastScroll2 = lastScroll1; return lastScroll1 = _round(value); }; vars.onComplete = function () { getTween.tween = 0; onComplete && onComplete.call(tween); }; tween = getTween.tween = gsap.to(scroller, vars); return tween; }; scroller[prop] = getScroll; scroller.addEventListener("wheel", function () { return getTween.tween && getTween.tween.kill() && (getTween.tween = 0); }, { passive: true }); return getTween; }; _horizontal.op = _vertical; var ScrollTrigger = function () { function ScrollTrigger(vars, animation) { _coreInitted || ScrollTrigger.register(gsap) || console.warn("Please gsap.registerPlugin(ScrollTrigger)"); this.init(vars, animation); } var _proto = ScrollTrigger.prototype; _proto.init = function init(vars, animation) { this.progress = this.start = 0; this.vars && this.kill(1); if (!_enabled) { this.update = this.refresh = this.kill = _passThrough; return; } vars = _setDefaults(_isString(vars) || _isNumber(vars) || vars.nodeType ? { trigger: vars } : vars, _defaults); var _vars = vars, onUpdate = _vars.onUpdate, toggleClass = _vars.toggleClass, id = _vars.id, onToggle = _vars.onToggle, onRefresh = _vars.onRefresh, scrub = _vars.scrub, trigger = _vars.trigger, pin = _vars.pin, pinSpacing = _vars.pinSpacing, invalidateOnRefresh = _vars.invalidateOnRefresh, anticipatePin = _vars.anticipatePin, onScrubComplete = _vars.onScrubComplete, onSnapComplete = _vars.onSnapComplete, once = _vars.once, snap = _vars.snap, pinReparent = _vars.pinReparent, pinSpacer = _vars.pinSpacer, containerAnimation = _vars.containerAnimation, fastScrollEnd = _vars.fastScrollEnd, preventOverlaps = _vars.preventOverlaps, direction = vars.horizontal || vars.containerAnimation && vars.horizontal !== false ? _horizontal : _vertical, isToggle = !scrub && scrub !== 0, scroller = _getTarget(vars.scroller || _win), scrollerCache = gsap.core.getCache(scroller), isViewport = _isViewport(scroller), useFixedPosition = ("pinType" in vars ? vars.pinType : _getProxyProp(scroller, "pinType") || isViewport && "fixed") === "fixed", callbacks = [vars.onEnter, vars.onLeave, vars.onEnterBack, vars.onLeaveBack], toggleActions = isToggle && vars.toggleActions.split(" "), markers = "markers" in vars ? vars.markers : _defaults.markers, borderWidth = isViewport ? 0 : parseFloat(_getComputedStyle(scroller)["border" + direction.p2 + _Width]) || 0, self = this, onRefreshInit = vars.onRefreshInit && function () { return vars.onRefreshInit(self); }, getScrollerSize = _getSizeFunc(scroller, isViewport, direction), getScrollerOffsets = _getOffsetsFunc(scroller, isViewport), lastSnap = 0, scrollFunc = _getScrollFunc(scroller, direction), tweenTo, pinCache, snapFunc, scroll1, scroll2, start, end, markerStart, markerEnd, markerStartTrigger, markerEndTrigger, markerVars, change, pinOriginalState, pinActiveState, pinState, spacer, offset, pinGetter, pinSetter, pinStart, pinChange, spacingStart, spacerState, markerStartSetter, markerEndSetter, cs, snap1, snap2, scrubTween, scrubSmooth, snapDurClamp, snapDelayedCall, prevProgress, prevScroll, prevAnimProgress, caMarkerSetter; self.media = _creatingMedia; anticipatePin *= 45; self.scroller = scroller; self.scroll = containerAnimation ? containerAnimation.time.bind(containerAnimation) : scrollFunc; scroll1 = scrollFunc(); self.vars = vars; animation = animation || vars.animation; "refreshPriority" in vars && (_sort = 1); scrollerCache.tweenScroll = scrollerCache.tweenScroll || { top: _getTweenCreator(scroller, _vertical), left: _getTweenCreator(scroller, _horizontal) }; self.tweenTo = tweenTo = scrollerCache.tweenScroll[direction.p]; if (animation) { animation.vars.lazy = false; animation._initted || animation.vars.immediateRender !== false && vars.immediateRender !== false && animation.render(0, true, true); self.animation = animation.pause(); animation.scrollTrigger = self; scrubSmooth = _isNumber(scrub) && scrub; scrubSmooth && (scrubTween = gsap.to(animation, { ease: "power3", duration: scrubSmooth, onComplete: function onComplete() { return onScrubComplete && onScrubComplete(self); } })); snap1 = 0; id || (id = animation.vars.id); } _triggers.push(self); if (snap) { if (!_isObject(snap) || snap.push) { snap = { snapTo: snap }; } "scrollBehavior" in _body.style && gsap.set(isViewport ? [_body, _docEl] : scroller, { scrollBehavior: "auto" }); snapFunc = _isFunction(snap.snapTo) ? snap.snapTo : snap.snapTo === "labels" ? _getClosestLabel(animation) : snap.snapTo === "labelsDirectional" ? _getLabelAtDirection(animation) : snap.directional !== false ? function (value, st) { return _snapDirectional(snap.snapTo)(value, st.direction); } : gsap.utils.snap(snap.snapTo); snapDurClamp = snap.duration || { min: 0.1, max: 2 }; snapDurClamp = _isObject(snapDurClamp) ? _clamp(snapDurClamp.min, snapDurClamp.max) : _clamp(snapDurClamp, snapDurClamp); snapDelayedCall = gsap.delayedCall(snap.delay || scrubSmooth / 2 || 0.1, function () { if (Math.abs(self.getVelocity()) < 10 && !_pointerIsDown && lastSnap !== scrollFunc()) { var totalProgress = animation && !isToggle ? animation.totalProgress() : self.progress, velocity = (totalProgress - snap2) / (_getTime() - _time2) * 1000 || 0, change1 = gsap.utils.clamp(-self.progress, 1 - self.progress, _abs(velocity / 2) * velocity / 0.185), naturalEnd = self.progress + (snap.inertia === false ? 0 : change1), endValue = _clamp(0, 1, snapFunc(naturalEnd, self)), scroll = scrollFunc(), endScroll = Math.round(start + endValue * change), _snap = snap, onStart = _snap.onStart, _onInterrupt = _snap.onInterrupt, _onComplete = _snap.onComplete, tween = tweenTo.tween; if (scroll <= end && scroll >= start && endScroll !== scroll) { if (tween && !tween._initted && tween.data <= _abs(endScroll - scroll)) { return; } if (snap.inertia === false) { change1 = endValue - self.progress; } tweenTo(endScroll, { duration: snapDurClamp(_abs(Math.max(_abs(naturalEnd - totalProgress), _abs(endValue - totalProgress)) * 0.185 / velocity / 0.05 || 0)), ease: snap.ease || "power3", data: _abs(endScroll - scroll), onInterrupt: function onInterrupt() { return snapDelayedCall.restart(true) && _onInterrupt && _onInterrupt(self); }, onComplete: function onComplete() { lastSnap = scrollFunc(); snap1 = snap2 = animation && !isToggle ? animation.totalProgress() : self.progress; onSnapComplete && onSnapComplete(self); _onComplete && _onComplete(self); } }, scroll, change1 * change, endScroll - scroll - change1 * change); onStart && onStart(self, tweenTo.tween); } } else if (self.isActive) { snapDelayedCall.restart(true); } }).pause(); } id && (_ids[id] = self); trigger = self.trigger = _getTarget(trigger || pin); pin = pin === true ? trigger : _getTarget(pin); _isString(toggleClass) && (toggleClass = { targets: trigger, className: toggleClass }); if (pin) { pinSpacing === false || pinSpacing === _margin || (pinSpacing = !pinSpacing && _getComputedStyle(pin.parentNode).display === "flex" ? false : _padding); self.pin = pin; vars.force3D !== false && gsap.set(pin, { force3D: true }); pinCache = gsap.core.getCache(pin); if (!pinCache.spacer) { if (pinSpacer) { pinSpacer = _getTarget(pinSpacer); pinSpacer && !pinSpacer.nodeType && (pinSpacer = pinSpacer.current || pinSpacer.nativeElement); pinCache.spacerIsNative = !!pinSpacer; pinSpacer && (pinCache.spacerState = _getState(pinSpacer)); } pinCache.spacer = spacer = pinSpacer || _doc.createElement("div"); spacer.classList.add("pin-spacer"); id && spacer.classList.add("pin-spacer-" + id); pinCache.pinState = pinOriginalState = _getState(pin); } else { pinOriginalState = pinCache.pinState; } self.spacer = spacer = pinCache.spacer; cs = _getComputedStyle(pin); spacingStart = cs[pinSpacing + direction.os2]; pinGetter = gsap.getProperty(pin); pinSetter = gsap.quickSetter(pin, direction.a, _px); _swapPinIn(pin, spacer, cs); pinState = _getState(pin); } if (markers) { markerVars = _isObject(markers) ? _setDefaults(markers, _markerDefaults) : _markerDefaults; markerStartTrigger = _createMarker("scroller-start", id, scroller, direction, markerVars, 0); markerEndTrigger = _createMarker("scroller-end", id, scroller, direction, markerVars, 0, markerStartTrigger); offset = markerStartTrigger["offset" + direction.op.d2]; markerStart = _createMarker("start", id, scroller, direction, markerVars, offset, 0, containerAnimation); markerEnd = _createMarker("end", id, scroller, direction, markerVars, offset, 0, containerAnimation); containerAnimation && (caMarkerSetter = gsap.quickSetter([markerStart, markerEnd], direction.a, _px)); if (!useFixedPosition && !(_proxies.length && _getProxyProp(scroller, "fixedMarkers") === true)) { _makePositionable(isViewport ? _body : scroller); gsap.set([markerStartTrigger, markerEndTrigger], { force3D: true }); markerStartSetter = gsap.quickSetter(markerStartTrigger, direction.a, _px); markerEndSetter = gsap.quickSetter(markerEndTrigger, direction.a, _px); } } if (containerAnimation) { var oldOnUpdate = containerAnimation.vars.onUpdate, oldParams = containerAnimation.vars.onUpdateParams; containerAnimation.eventCallback("onUpdate", function () { self.update(0, 0, 1); oldOnUpdate && oldOnUpdate.apply(oldParams || []); }); } self.previous = function () { return _triggers[_triggers.indexOf(self) - 1]; }; self.next = function () { return _triggers[_triggers.indexOf(self) + 1]; }; self.revert = function (revert) { var r = revert !== false || !self.enabled, prevRefreshing = _refreshing; if (r !== self.isReverted) { if (r) { self.scroll.rec || (self.scroll.rec = scrollFunc()); prevScroll = Math.max(scrollFunc(), self.scroll.rec || 0); prevProgress = self.progress; prevAnimProgress = animation && animation.progress(); } markerStart && [markerStart, markerEnd, markerStartTrigger, markerEndTrigger].forEach(function (m) { return m.style.display = r ? "none" : "block"; }); r && (_refreshing = 1); self.update(r); _refreshing = prevRefreshing; pin && (r ? _swapPinOut(pin, spacer, pinOriginalState) : (!pinReparent || !self.isActive) && _swapPinIn(pin, spacer, _getComputedStyle(pin), spacerState)); self.isReverted = r; } }; self.refresh = function (soft, force) { if ((_refreshing || !self.enabled) && !force) { return; } if (pin && soft && _lastScrollTime) { _addListener(ScrollTrigger, "scrollEnd", _softRefresh); return; } _refreshing = 1; scrubTween && scrubTween.pause(); invalidateOnRefresh && animation && animation.progress(0).invalidate(); self.isReverted || self.revert(); var size = getScrollerSize(), scrollerBounds = getScrollerOffsets(), max = containerAnimation ? containerAnimation.duration() : _maxScroll(scroller, direction), offset = 0, otherPinOffset = 0, parsedEnd = vars.end, parsedEndTrigger = vars.endTrigger || trigger, parsedStart = vars.start || (vars.start === 0 || !trigger ? 0 : pin ? "0 0" : "0 100%"), pinnedContainer = vars.pinnedContainer && _getTarget(vars.pinnedContainer), triggerIndex = trigger && Math.max(0, _triggers.indexOf(self)) || 0, i = triggerIndex, cs, bounds, scroll, isVertical, override, curTrigger, curPin, oppositeScroll, initted, revertedPins; while (i--) { curTrigger = _triggers[i]; curTrigger.end || curTrigger.refresh(0, 1) || (_refreshing = 1); curPin = curTrigger.pin; if (curPin && (curPin === trigger || curPin === pin) && !curTrigger.isReverted) { revertedPins || (revertedPins = []); revertedPins.unshift(curTrigger); curTrigger.revert(); } } _isFunction(parsedStart) && (parsedStart = parsedStart(self)); start = _parsePosition(parsedStart, trigger, size, direction, scrollFunc(), markerStart, markerStartTrigger, self, scrollerBounds, borderWidth, useFixedPosition, max, containerAnimation) || (pin ? -0.001 : 0); _isFunction(parsedEnd) && (parsedEnd = parsedEnd(self)); if (_isString(parsedEnd) && !parsedEnd.indexOf("+=")) { if (~parsedEnd.indexOf(" ")) { parsedEnd = (_isString(parsedStart) ? parsedStart.split(" ")[0] : "") + parsedEnd; } else { offset = _offsetToPx(parsedEnd.substr(2), size); parsedEnd = _isString(parsedStart) ? parsedStart : start + offset; parsedEndTrigger = trigger; } } end = Math.max(start, _parsePosition(parsedEnd || (parsedEndTrigger ? "100% 0" : max), parsedEndTrigger, size, direction, scrollFunc() + offset, markerEnd, markerEndTrigger, self, scrollerBounds, borderWidth, useFixedPosition, max, containerAnimation)) || -0.001; change = end - start || (start -= 0.01) && 0.001; offset = 0; i = triggerIndex; while (i--) { curTrigger = _triggers[i]; curPin = curTrigger.pin; if (curPin && curTrigger.start - curTrigger._pinPush < start && !containerAnimation) { cs = curTrigger.end - curTrigger.start; (curPin === trigger || curPin === pinnedContainer) && !_isNumber(parsedStart) && (offset += cs); curPin === pin && (otherPinOffset += cs); } } start += offset; end += offset; self._pinPush = otherPinOffset; if (markerStart && offset) { cs = {}; cs[direction.a] = "+=" + offset; pinnedContainer && (cs[direction.p] = "-=" + scrollFunc()); gsap.set([markerStart, markerEnd], cs); } if (pin) { cs = _getComputedStyle(pin); isVertical = direction === _vertical; scroll = scrollFunc(); pinStart = parseFloat(pinGetter(direction.a)) + otherPinOffset; !max && end > 1 && ((isViewport ? _body : scroller).style["overflow-" + direction.a] = "scroll"); _swapPinIn(pin, spacer, cs); pinState = _getState(pin); bounds = _getBounds(pin, true); oppositeScroll = useFixedPosition && _getScrollFunc(scroller, isVertical ? _horizontal : _vertical)(); if (pinSpacing) { spacerState = [pinSpacing + direction.os2, change + otherPinOffset + _px]; spacerState.t = spacer; i = pinSpacing === _padding ? _getSize(pin, direction) + change + otherPinOffset : 0; i && spacerState.push(direction.d, i + _px); _setState(spacerState); useFixedPosition && scrollFunc(prevScroll); } if (useFixedPosition) { override = { top: bounds.top + (isVertical ? scroll - start : oppositeScroll) + _px, left: bounds.left + (isVertical ? oppositeScroll : scroll - start) + _px, boxSizing: "border-box", position: "fixed" }; override[_width] = override["max" + _Width] = Math.ceil(bounds.width) + _px; override[_height] = override["max" + _Height] = Math.ceil(bounds.height) + _px; override[_margin] = override[_margin + _Top] = override[_margin + _Right] = override[_margin + _Bottom] = override[_margin + _Left] = "0"; override[_padding] = cs[_padding]; override[_padding + _Top] = cs[_padding + _Top]; override[_padding + _Right] = cs[_padding + _Right]; override[_padding + _Bottom] = cs[_padding + _Bottom]; override[_padding + _Left] = cs[_padding + _Left]; pinActiveState = _copyState(pinOriginalState, override, pinReparent); } if (animation) { initted = animation._initted; _suppressOverwrites(1); animation.render(animation.duration(), true, true); pinChange = pinGetter(direction.a) - pinStart + change + otherPinOffset; change !== pinChange && pinActiveState.splice(pinActiveState.length - 2, 2); animation.render(0, true, true); initted || animation.invalidate(); _suppressOverwrites(0); } else { pinChange = change; } } else if (trigger && scrollFunc() && !containerAnimation) { bounds = trigger.parentNode; while (bounds && bounds !== _body) { if (bounds._pinOffset) { start -= bounds._pinOffset; end -= bounds._pinOffset; } bounds = bounds.parentNode; } } revertedPins && revertedPins.forEach(function (t) { return t.revert(false); }); self.start = start; self.end = end; scroll1 = scroll2 = scrollFunc(); if (!containerAnimation) { scroll1 < prevScroll && scrollFunc(prevScroll); self.scroll.rec = 0; } self.revert(false); _refreshing = 0; animation && isToggle && animation._initted && animation.progress() !== prevAnimProgress && animation.progress(prevAnimProgress, true).render(animation.time(), true, true); if (prevProgress !== self.progress) { animation && !isToggle && animation.totalProgress(prevProgress, true); self.progress = prevProgress; self.update(0, 0, 1); } pin && pinSpacing && (spacer._pinOffset = Math.round(self.progress * pinChange)); onRefresh && onRefresh(self); }; self.getVelocity = function () { return (scrollFunc() - scroll2) / (_getTime() - _time2) * 1000 || 0; }; self.endAnimation = function () { _endAnimation(self.callbackAnimation); if (animation) { scrubTween ? scrubTween.progress(1) : !animation.paused() ? _endAnimation(animation, animation.reversed()) : isToggle || _endAnimation(animation, self.direction < 0, 1); } }; self.getTrailing = function (name) { var i = _triggers.indexOf(self), a = self.direction > 0 ? _triggers.slice(0, i).reverse() : _triggers.slice(i + 1); return _isString(name) ? a.filter(function (t) { return t.vars.preventOverlaps === name; }) : a; }; self.update = function (reset, recordVelocity, forceFake) { if (containerAnimation && !forceFake && !reset) { return; } var scroll = self.scroll(), p = reset ? 0 : (scroll - start) / change, clipped = p < 0 ? 0 : p > 1 ? 1 : p || 0, prevProgress = self.progress, isActive, wasActive, toggleState, action, stateChanged, toggled, isAtMax, isTakingAction; if (recordVelocity) { scroll2 = scroll1; scroll1 = containerAnimation ? scrollFunc() : scroll; if (snap) { snap2 = snap1; snap1 = animation && !isToggle ? animation.totalProgress() : clipped; } } anticipatePin && !clipped && pin && !_refreshing && !_startup && _lastScrollTime && start < scroll + (scroll - scroll2) / (_getTime() - _time2) * anticipatePin && (clipped = 0.0001); if (clipped !== prevProgress && self.enabled) { isActive = self.isActive = !!clipped && clipped < 1; wasActive = !!prevProgress && prevProgress < 1; toggled = isActive !== wasActive; stateChanged = toggled || !!clipped !== !!prevProgress; self.direction = clipped > prevProgress ? 1 : -1; self.progress = clipped; if (stateChanged && !_refreshing) { toggleState = clipped && !prevProgress ? 0 : clipped === 1 ? 1 : prevProgress === 1 ? 2 : 3; if (isToggle) { action = !toggled && toggleActions[toggleState + 1] !== "none" && toggleActions[toggleState + 1] || toggleActions[toggleState]; isTakingAction = animation && (action === "complete" || action === "reset" || action in animation); } } preventOverlaps && toggled && (isTakingAction || scrub || !animation) && (_isFunction(preventOverlaps) ? preventOverlaps(self) : self.getTrailing(preventOverlaps).forEach(function (t) { return t.endAnimation(); })); if (!isToggle) { if (scrubTween && !_refreshing && !_startup) { scrubTween.vars.totalProgress = clipped; scrubTween.invalidate().restart(); } else if (animation) { animation.totalProgress(clipped, !!_refreshing); } } if (pin) { reset && pinSpacing && (spacer.style[pinSpacing + direction.os2] = spacingStart); if (!useFixedPosition) { pinSetter(pinStart + pinChange * clipped); } else if (stateChanged) { isAtMax = !reset && clipped > prevProgress && end + 1 > scroll && scroll + 1 >= _maxScroll(scroller, direction); if (pinReparent) { if (!reset && (isActive || isAtMax)) { var bounds = _getBounds(pin, true), _offset = scroll - start; _reparent(pin, _body, bounds.top + (direction === _vertical ? _offset : 0) + _px, bounds.left + (direction === _vertical ? 0 : _offset) + _px); } else { _reparent(pin, spacer); } } _setState(isActive || isAtMax ? pinActiveState : pinState); pinChange !== change && clipped < 1 && isActive || pinSetter(pinStart + (clipped === 1 && !isAtMax ? pinChange : 0)); } } snap && !tweenTo.tween && !_refreshing && !_startup && snapDelayedCall.restart(true); toggleClass && (toggled || once && clipped && (clipped < 1 || !_limitCallbacks)) && _toArray(toggleClass.targets).forEach(function (el) { return el.classList[isActive || once ? "add" : "remove"](toggleClass.className); }); onUpdate && !isToggle && !reset && onUpdate(self); if (stateChanged && !_refreshing) { if (isToggle) { if (isTakingAction) { if (action === "complete") { animation.pause().totalProgress(1); } else if (action === "reset") { animation.restart(true).pause(); } else if (action === "restart") { animation.restart(true); } else { animation[action](); } } onUpdate && onUpdate(self); } if (toggled || !_limitCallbacks) { onToggle && toggled && _callback(self, onToggle); callbacks[toggleState] && _callback(self, callbacks[toggleState]); once && (clipped === 1 ? self.kill(false, 1) : callbacks[toggleState] = 0); if (!toggled) { toggleState = clipped === 1 ? 1 : 3; callbacks[toggleState] && _callback(self, callbacks[toggleState]); } } if (fastScrollEnd && !isActive && Math.abs(self.getVelocity()) > (_isNumber(fastScrollEnd) ? fastScrollEnd : 2500)) { _endAnimation(self.callbackAnimation); scrubTween ? scrubTween.progress(1) : _endAnimation(animation, !clipped, 1); } } else if (isToggle && onUpdate && !_refreshing) { onUpdate(self); } } if (markerEndSetter) { var n = containerAnimation ? scroll / containerAnimation.duration() * (containerAnimation._caScrollDist || 0) : scroll; markerStartSetter(n + (markerStartTrigger._isFlipped ? 1 : 0)); markerEndSetter(n); } caMarkerSetter && caMarkerSetter(-scroll / containerAnimation.duration() * (containerAnimation._caScrollDist || 0)); }; self.enable = function (reset, refresh) { if (!self.enabled) { self.enabled = true; _addListener(scroller, "resize", _onResize); _addListener(scroller, "scroll", _onScroll); onRefreshInit && _addListener(ScrollTrigger, "refreshInit", onRefreshInit); if (reset !== false) { self.progress = prevProgress = 0; scroll1 = scroll2 = lastSnap = scrollFunc(); } refresh !== false && self.refresh(); } }; self.getTween = function (snap) { return snap && tweenTo ? tweenTo.tween : scrubTween; }; self.disable = function (reset, allowAnimation) { if (self.enabled) { reset !== false && self.revert(); self.enabled = self.isActive = false; allowAnimation || scrubTween && scrubTween.pause(); prevScroll = 0; pinCache && (pinCache.uncache = 1); onRefreshInit && _removeListener(ScrollTrigger, "refreshInit", onRefreshInit); if (snapDelayedCall) { snapDelayedCall.pause(); tweenTo.tween && tweenTo.tween.kill() && (tweenTo.tween = 0); } if (!isViewport) { var i = _triggers.length; while (i--) { if (_triggers[i].scroller === scroller && _triggers[i] !== self) { return; } } _removeListener(scroller, "resize", _onResize); _removeListener(scroller, "scroll", _onScroll); } } }; self.kill = function (revert, allowAnimation) { self.disable(revert, allowAnimation); scrubTween && scrubTween.kill(); id && delete _ids[id]; var i = _triggers.indexOf(self); _triggers.splice(i, 1); i === _i && _direction > 0 && _i--; i = 0; _triggers.forEach(function (t) { return t.scroller === self.scroller && (i = 1); }); i || (self.scroll.rec = 0); if (animation) { animation.scrollTrigger = null; revert && animation.render(-1); allowAnimation || animation.kill(); } markerStart && [markerStart, markerEnd, markerStartTrigger, markerEndTrigger].forEach(function (m) { return m.parentNode && m.parentNode.removeChild(m); }); if (pin) { pinCache && (pinCache.uncache = 1); i = 0; _triggers.forEach(function (t) { return t.pin === pin && i++; }); i || (pinCache.spacer = 0); } }; self.enable(false, false); !animation || !animation.add || change ? self.refresh() : gsap.delayedCall(0.01, function () { return start || end || self.refresh(); }) && (change = 0.01) && (start = end = 0); }; ScrollTrigger.register = function register(core) { if (!_coreInitted) { gsap = core || _getGSAP(); if (_windowExists() && window.document) { _win = window; _doc = document; _docEl = _doc.documentElement; _body = _doc.body; } if (gsap) { _toArray = gsap.utils.toArray; _clamp = gsap.utils.clamp; _suppressOverwrites = gsap.core.suppressOverwrites || _passThrough; gsap.core.globals("ScrollTrigger", ScrollTrigger); if (_body) { _raf = _win.requestAnimationFrame || function (f) { return setTimeout(f, 16); }; _addListener(_win, "wheel", _onScroll); _root = [_win, _doc, _docEl, _body]; _addListener(_doc, "scroll", _onScroll); var bodyStyle = _body.style, border = bodyStyle.borderTopStyle, bounds; bodyStyle.borderTopStyle = "solid"; bounds = _getBounds(_body); _vertical.m = Math.round(bounds.top + _vertical.sc()) || 0; _horizontal.m = Math.round(bounds.left + _horizontal.sc()) || 0; border ? bodyStyle.borderTopStyle = border : bodyStyle.removeProperty("border-top-style"); _syncInterval = setInterval(_sync, 200); gsap.delayedCall(0.5, function () { return _startup = 0; }); _addListener(_doc, "touchcancel", _passThrough); _addListener(_body, "touchstart", _passThrough); _multiListener(_addListener, _doc, "pointerdown,touchstart,mousedown", function () { return _pointerIsDown = 1; }); _multiListener(_addListener, _doc, "pointerup,touchend,mouseup", function () { return _pointerIsDown = 0; }); _transformProp = gsap.utils.checkPrefix("transform"); _stateProps.push(_transformProp); _coreInitted = _getTime(); _resizeDelay = gsap.delayedCall(0.2, _refreshAll).pause(); _autoRefresh = [_doc, "visibilitychange", function () { var w = _win.innerWidth, h = _win.innerHeight; if (_doc.hidden) { _prevWidth = w; _prevHeight = h; } else if (_prevWidth !== w || _prevHeight !== h) { _onResize(); } }, _doc, "DOMContentLoaded", _refreshAll, _win, "load", function () { return _lastScrollTime || _refreshAll(); }, _win, "resize", _onResize]; _iterateAutoRefresh(_addListener); } } } return _coreInitted; }; ScrollTrigger.defaults = function defaults(config) { for (var p in config) { _defaults[p] = config[p]; } }; ScrollTrigger.kill = function kill() { _enabled = 0; _triggers.slice(0).forEach(function (trigger) { return trigger.kill(1); }); }; ScrollTrigger.config = function config(vars) { "limitCallbacks" in vars && (_limitCallbacks = !!vars.limitCallbacks); var ms = vars.syncInterval; ms && clearInterval(_syncInterval) || (_syncInterval = ms) && setInterval(_sync, ms); if ("autoRefreshEvents" in vars) { _iterateAutoRefresh(_removeListener) || _iterateAutoRefresh(_addListener, vars.autoRefreshEvents || "none"); _ignoreResize = (vars.autoRefreshEvents + "").indexOf("resize") === -1; } }; ScrollTrigger.scrollerProxy = function scrollerProxy(target, vars) { var t = _getTarget(target), i = _scrollers.indexOf(t), isViewport = _isViewport(t); if (~i) { _scrollers.splice(i, isViewport ? 6 : 2); } isViewport ? _proxies.unshift(_win, vars, _body, vars, _docEl, vars) : _proxies.unshift(t, vars); }; ScrollTrigger.matchMedia = function matchMedia(vars) { var mq, p, i, func, result; for (p in vars) { i = _media.indexOf(p); func = vars[p]; _creatingMedia = p; if (p === "all") { func(); } else { mq = _win.matchMedia(p); if (mq) { mq.matches && (result = func()); if (~i) { _media[i + 1] = _combineFunc(_media[i + 1], func); _media[i + 2] = _combineFunc(_media[i + 2], result); } else { i = _media.length; _media.push(p, func, result); mq.addListener ? mq.addListener(_onMediaChange) : mq.addEventListener("change", _onMediaChange); } _media[i + 3] = mq.matches; } } _creatingMedia = 0; } return _media; }; ScrollTrigger.clearMatchMedia = function clearMatchMedia(query) { query || (_media.length = 0); query = _media.indexOf(query); query >= 0 && _media.splice(query, 4); }; ScrollTrigger.isInViewport = function isInViewport(element, ratio, horizontal) { var bounds = (_isString(element) ? _getTarget(element) : element).getBoundingClientRect(), offset = bounds[horizontal ? _width : _height] * ratio || 0; return horizontal ? bounds.right - offset > 0 && bounds.left + offset < _win.innerWidth : bounds.bottom - offset > 0 && bounds.top + offset < _win.innerHeight; }; ScrollTrigger.positionInViewport = function positionInViewport(element, referencePoint, horizontal) { _isString(element) && (element = _getTarget(element)); var bounds = element.getBoundingClientRect(), size = bounds[horizontal ? _width : _height], offset = referencePoint == null ? size / 2 : referencePoint in _keywords ? _keywords[referencePoint] * size : ~referencePoint.indexOf("%") ? parseFloat(referencePoint) * size / 100 : parseFloat(referencePoint) || 0; return horizontal ? (bounds.left + offset) / _win.innerWidth : (bounds.top + offset) / _win.innerHeight; }; return ScrollTrigger; }(); ScrollTrigger.version = "3.8.0"; ScrollTrigger.saveStyles = function (targets) { return targets ? _toArray(targets).forEach(function (target) { if (target && target.style) { var i = _savedStyles.indexOf(target); i >= 0 && _savedStyles.splice(i, 5); _savedStyles.push(target, target.style.cssText, target.getBBox && target.getAttribute("transform"), gsap.core.getCache(target), _creatingMedia); } }) : _savedStyles; }; ScrollTrigger.revert = function (soft, media) { return _revertAll(!soft, media); }; ScrollTrigger.create = function (vars, animation) { return new ScrollTrigger(vars, animation); }; ScrollTrigger.refresh = function (safe) { return safe ? _onResize() : (_coreInitted || ScrollTrigger.register()) && _refreshAll(true); }; ScrollTrigger.update = _updateAll; ScrollTrigger.clearScrollMemory = _clearScrollMemory; ScrollTrigger.maxScroll = function (element, horizontal) { return _maxScroll(element, horizontal ? _horizontal : _vertical); }; ScrollTrigger.getScrollFunc = function (element, horizontal) { return _getScrollFunc(_getTarget(element), horizontal ? _horizontal : _vertical); }; ScrollTrigger.getById = function (id) { return _ids[id]; }; ScrollTrigger.getAll = function () { return _triggers.slice(0); }; ScrollTrigger.isScrolling = function () { return !!_lastScrollTime; }; ScrollTrigger.snapDirectional = _snapDirectional; ScrollTrigger.addEventListener = function (type, callback) { var a = _listeners[type] || (_listeners[type] = []); ~a.indexOf(callback) || a.push(callback); }; ScrollTrigger.removeEventListener = function (type, callback) { var a = _listeners[type], i = a && a.indexOf(callback); i >= 0 && a.splice(i, 1); }; ScrollTrigger.batch = function (targets, vars) { var result = [], varsCopy = {}, interval = vars.interval || 0.016, batchMax = vars.batchMax || 1e9, proxyCallback = function proxyCallback(type, callback) { var elements = [], triggers = [], delay = gsap.delayedCall(interval, function () { callback(elements, triggers); elements = []; triggers = []; }).pause(); return function (self) { elements.length || delay.restart(true); elements.push(self.trigger); triggers.push(self); batchMax <= elements.length && delay.progress(1); }; }, p; for (p in vars) { varsCopy[p] = p.substr(0, 2) === "on" && _isFunction(vars[p]) && p !== "onRefreshInit" ? proxyCallback(p, vars[p]) : vars[p]; } if (_isFunction(batchMax)) { batchMax = batchMax(); _addListener(ScrollTrigger, "refresh", function () { return batchMax = vars.batchMax(); }); } _toArray(targets).forEach(function (target) { var config = {}; for (p in varsCopy) { config[p] = varsCopy[p]; } config.trigger = target; result.push(ScrollTrigger.create(config)); }); return result; }; ScrollTrigger.sort = function (func) { return _triggers.sort(func || function (a, b) { return (a.vars.refreshPriority || 0) * -1e6 + a.start - (b.start + (b.vars.refreshPriority || 0) * -1e6); }); }; _getGSAP() && gsap.registerPlugin(ScrollTrigger); exports.ScrollTrigger = ScrollTrigger; exports.default = ScrollTrigger; Object.defineProperty(exports, '__esModule', { value: true }); }))); /* ======================================================================== * Bootstrap: collapse.js v3.1.1 * http://getbootstrap.com/javascript/#collapse * ======================================================================== * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ +function ($) { 'use strict'; // COLLAPSE PUBLIC CLASS DEFINITION // ================================ var Collapse = function (element, options) { this.$element = $(element) this.options = $.extend({}, Collapse.DEFAULTS, options) this.transitioning = null if (this.options.parent) this.$parent = $(this.options.parent) if (this.options.toggle) this.toggle() } Collapse.DEFAULTS = { toggle: true } Collapse.prototype.dimension = function () { var hasWidth = this.$element.hasClass('width') return hasWidth ? 'width' : 'height' } Collapse.prototype.show = function () { if (this.transitioning || this.$element.hasClass('in')) return var startEvent = $.Event('show.bs.collapse') this.$element.trigger(startEvent) if (startEvent.isDefaultPrevented()) return var actives = this.$parent && this.$parent.find('> .panel > .in') if (actives && actives.length) { var hasData = actives.data('bs.collapse') if (hasData && hasData.transitioning) return //START UNCODE EDIT var parentNoToggle = this.$parent.data('no-toggle') if (!parentNoToggle) { actives.collapse('hide') } //END UNCODE EDIT hasData || actives.data('bs.collapse', null) } var dimension = this.dimension() this.$element .removeClass('collapse') .addClass('collapsing')[dimension](0) this.transitioning = 1 var complete = function (e) { if (e && e.target != this.$element[0]) return this.$element .removeClass('collapsing') .addClass('collapse in')[dimension]('auto') this.transitioning = 0 this.$element.trigger('shown.bs.collapse') } if (!$.support.transition) return complete.call(this) var scrollSize = $.camelCase(['scroll', dimension].join('-')) this.$element .one($.support.transition.end, $.proxy(complete, this)) .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) } Collapse.prototype.hide = function () { if (this.transitioning || !this.$element.hasClass('in')) return var startEvent = $.Event('hide.bs.collapse') this.$element.trigger(startEvent) if (startEvent.isDefaultPrevented()) return var dimension = this.dimension() this.$element[dimension](this.$element[dimension]())[0].offsetHeight this.$element .addClass('collapsing') .removeClass('collapse') .removeClass('in') this.transitioning = 1 var complete = function (e) { if (e && e.target != this.$element[0]) return this.transitioning = 0 this.$element .trigger('hidden.bs.collapse') .removeClass('collapsing') .addClass('collapse') } if (!$.support.transition) return complete.call(this) this.$element [dimension](0) .one($.support.transition.end, $.proxy(complete, this)) .emulateTransitionEnd(350) } Collapse.prototype.toggle = function () { this[this.$element.hasClass('in') ? 'hide' : 'show']() } // COLLAPSE PLUGIN DEFINITION // ========================== var old = $.fn.collapse $.fn.collapse = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.collapse') var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data && options.toggle && option == 'show') option = !option if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.collapse.Constructor = Collapse // COLLAPSE NO CONFLICT // ==================== $.fn.collapse.noConflict = function () { $.fn.collapse = old return this } // COLLAPSE DATA-API // ================= $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { var $this = $(this), href var target = $this.attr('data-target') || e.preventDefault() || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 //Edited by Uncode to replace ID in panel [START] var _target = href.replace(/^#/, ""); if ( $('[data-id="' + _target + '"]').length ) { var $target = $('[data-id="' + _target + '"]') } else { var $target = $(target) } //Edited by Uncode to replace ID in panel [END] var data = $target.data('bs.collapse') var option = data ? 'toggle' : $this.data() var parent = $this.attr('data-parent') var $parent = parent && $(parent) if (!data || !data.transitioning) { if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') } $target.collapse(option) }) }(jQuery); /* ======================================================================== * Bootstrap: tab.js v3.1.1 * http://getbootstrap.com/javascript/#tabs * ======================================================================== * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ +function ($) { 'use strict'; // TAB CLASS DEFINITION // ==================== var Tab = function (element) { this.element = $(element) } Tab.prototype.show = function () { var $this = this.element var $ul = $this.closest('ul:not(.dropdown-menu)') var selector = $this.data('target') if (!selector) { selector = $this.attr('href') selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 } if ($this.parent('li').hasClass('active')) return var previous = $ul.find('.active:last a')[0] var e = $.Event('show.bs.tab', { relatedTarget: previous }) $this.trigger(e) if (e.isDefaultPrevented()) return //Edited by Uncode to replace ID in panel [START] var _target = selector.replace(/^#/, ""); if ( $('[data-id="' + _target + '"]').length ) var $target = $('[data-id="' + _target + '"]') else var $target = $(selector) //Edited by Uncode to replace ID in panel [END] this.activate($this.parent('li'), $ul) this.activate($target, $target.parent(), function () { $this.trigger({ type: 'shown.bs.tab', relatedTarget: previous }) }) } Tab.prototype.activate = function (element, container, callback) { var $active = container.find('> .active').add(container.find('> .active > .active')) var transition = callback && $.support.transition && $active.hasClass('fade') function next() { $active .removeClass('active') .find('> .dropdown-menu > .active') .removeClass('active') $active .find('.tab-excerpt').slideUp(); element.addClass('active') $('.tab-excerpt', element).slideDown(); //if (transition) { element[0].offsetWidth // reflow for transition element.add($active).addClass('in') /*} else { element.removeClass('fade') }*/ if (element.parent('.dropdown-menu')) { element.closest('li.dropdown').addClass('active') } callback && callback() } transition ? $active .one($.support.transition.end, next) .emulateTransitionEnd(150) : next() $active.removeClass('in') } // TAB PLUGIN DEFINITION // ===================== var old = $.fn.tab $.fn.tab = function ( option ) { return this.each(function () { var $this = $(this) var data = $this.data('bs.tab') if (!data) $this.data('bs.tab', (data = new Tab(this))) if (typeof option == 'string') data[option]() }) } $.fn.tab.Constructor = Tab // TAB NO CONFLICT // =============== $.fn.tab.noConflict = function () { $.fn.tab = old return this } // TAB DATA-API // ============ $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { e.preventDefault() $(this).tab('show') }) }(jQuery); /* ======================================================================== * Bootstrap: tooltip.js v3.1.1 * http://getbootstrap.com/javascript/#tooltip * Inspired by the original jQuery.tipsy by Jason Frame * ======================================================================== * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ +function ($) { 'use strict'; // TOOLTIP PUBLIC CLASS DEFINITION // =============================== var Tooltip = function (element, options) { this.type = this.options = this.enabled = this.timeout = this.hoverState = this.$element = null this.init('tooltip', element, options) } Tooltip.DEFAULTS = { animation: true, placement: 'top', selector: false, template: '', trigger: 'hover focus', title: '', delay: 0, html: false, container: false, viewport: { selector: 'body', padding: 0 } } Tooltip.prototype.init = function (type, element, options) { this.enabled = true this.type = type this.$element = $(element) this.options = this.getOptions(options) this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) var triggers = this.options.trigger.split(' ') for (var i = triggers.length; i--;) { var trigger = triggers[i] if (trigger == 'click') { this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) } else if (trigger != 'manual') { var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) } } this.options.selector ? (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : this.fixTitle() } Tooltip.prototype.getDefaults = function () { return Tooltip.DEFAULTS } Tooltip.prototype.getOptions = function (options) { options = $.extend({}, this.getDefaults(), this.$element.data(), options) if (options.delay && typeof options.delay == 'number') { options.delay = { show: options.delay, hide: options.delay } } return options } Tooltip.prototype.getDelegateOptions = function () { var options = {} var defaults = this.getDefaults() this._options && $.each(this._options, function (key, value) { if (defaults[key] != value) options[key] = value }) return options } Tooltip.prototype.enter = function (obj) { var self = obj instanceof this.constructor ? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) clearTimeout(self.timeout) self.hoverState = 'in' if (!self.options.delay || !self.options.delay.show) return self.show() self.timeout = setTimeout(function () { if (self.hoverState == 'in') self.show() }, self.options.delay.show) } Tooltip.prototype.leave = function (obj) { var self = obj instanceof this.constructor ? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) clearTimeout(self.timeout) self.hoverState = 'out' if (!self.options.delay || !self.options.delay.hide) return self.hide() self.timeout = setTimeout(function () { if (self.hoverState == 'out') self.hide() }, self.options.delay.hide) } Tooltip.prototype.show = function () { var e = $.Event('show.bs.' + this.type) if (this.hasContent() && this.enabled) { this.$element.trigger(e) if (e.isDefaultPrevented()) return var that = this; var $tip = this.tip() this.setContent() if (this.options.animation) $tip.addClass('fade') var placement = typeof this.options.placement == 'function' ? this.options.placement.call(this, $tip[0], this.$element[0]) : this.options.placement var autoToken = /\s?auto?\s?/i var autoPlace = autoToken.test(placement) if (autoPlace) placement = placement.replace(autoToken, '') || 'top' $tip .detach() .css({ top: 0, left: 0, display: 'block' }) .addClass(placement) this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) var pos = this.getPosition() var actualWidth = $tip[0].offsetWidth var actualHeight = $tip[0].offsetHeight if (autoPlace) { var orgPlacement = placement var $parent = this.$element.parent() var parentDim = this.getPosition($parent) placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : placement $tip .removeClass(orgPlacement) .addClass(placement) } var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) this.applyPlacement(calculatedOffset, placement) this.hoverState = null var complete = function() { that.$element.trigger('shown.bs.' + that.type) } $.support.transition && this.$tip.hasClass('fade') ? $tip .one($.support.transition.end, complete) .emulateTransitionEnd(150) : complete() } } Tooltip.prototype.applyPlacement = function (offset, placement) { var $tip = this.tip() var width = $tip[0].offsetWidth var height = $tip[0].offsetHeight // manually read margins because getBoundingClientRect includes difference var marginTop = parseInt($tip.css('margin-top'), 10) var marginLeft = parseInt($tip.css('margin-left'), 10) // we must check for NaN for ie 8/9 if (isNaN(marginTop)) marginTop = 0 if (isNaN(marginLeft)) marginLeft = 0 offset.top = offset.top + marginTop offset.left = offset.left + marginLeft // $.fn.offset doesn't round pixel values // so we use setOffset directly with our own function B-0 $.offset.setOffset($tip[0], $.extend({ using: function (props) { $tip.css({ top: Math.round(props.top), left: Math.round(props.left) }) } }, offset), 0) $tip.addClass('in') // check to see if placing tip in new offset caused the tip to resize itself var actualWidth = $tip[0].offsetWidth var actualHeight = $tip[0].offsetHeight if (placement == 'top' && actualHeight != height) { offset.top = offset.top + height - actualHeight } var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) if (delta.left) offset.left += delta.left else offset.top += delta.top var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight var arrowPosition = delta.left ? 'left' : 'top' var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' $tip.offset(offset) this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) } Tooltip.prototype.replaceArrow = function (delta, dimension, position) { this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') } Tooltip.prototype.setContent = function () { var $tip = this.tip() var title = this.getTitle() $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) $tip.removeClass('fade in top bottom left right') } Tooltip.prototype.hide = function () { var that = this var $tip = this.tip() var e = $.Event('hide.bs.' + this.type) function complete() { if (that.hoverState != 'in') $tip.detach() that.$element.trigger('hidden.bs.' + that.type) } this.$element.trigger(e) if (e.isDefaultPrevented()) return $tip.removeClass('in') $.support.transition && this.$tip.hasClass('fade') ? $tip .one($.support.transition.end, complete) .emulateTransitionEnd(150) : complete() this.hoverState = null return this } Tooltip.prototype.fixTitle = function () { var $e = this.$element if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') } } Tooltip.prototype.hasContent = function () { return this.getTitle() } Tooltip.prototype.getPosition = function ($element) { $element = $element || this.$element var el = $element[0] var isBody = el.tagName == 'BODY' return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), width: isBody ? $(window).width() : $element.outerWidth(), height: isBody ? $(window).height() : $element.outerHeight() }, isBody ? {top: 0, left: 0} : $element.offset()) } Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } } Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { var delta = { top: 0, left: 0 } if (!this.$viewport) return delta var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 var viewportDimensions = this.getPosition(this.$viewport) if (/right|left/.test(placement)) { var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight if (topEdgeOffset < viewportDimensions.top) { // top overflow delta.top = viewportDimensions.top - topEdgeOffset } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset } } else { var leftEdgeOffset = pos.left - viewportPadding var rightEdgeOffset = pos.left + viewportPadding + actualWidth if (leftEdgeOffset < viewportDimensions.left) { // left overflow delta.left = viewportDimensions.left - leftEdgeOffset } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset } } return delta } Tooltip.prototype.getTitle = function () { var title var $e = this.$element var o = this.options title = $e.attr('data-original-title') || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) return title } Tooltip.prototype.tip = function () { return this.$tip = this.$tip || $(this.options.template) } Tooltip.prototype.arrow = function () { return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') } Tooltip.prototype.validate = function () { if (!this.$element[0].parentNode) { this.hide() this.$element = null this.options = null } } Tooltip.prototype.enable = function () { this.enabled = true } Tooltip.prototype.disable = function () { this.enabled = false } Tooltip.prototype.toggleEnabled = function () { this.enabled = !this.enabled } Tooltip.prototype.toggle = function (e) { var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this self.tip().hasClass('in') ? self.leave(self) : self.enter(self) } Tooltip.prototype.destroy = function () { clearTimeout(this.timeout) this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) } // TOOLTIP PLUGIN DEFINITION // ========================= var old = $.fn.tooltip $.fn.tooltip = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.tooltip') var options = typeof option == 'object' && option if (!data && option == 'destroy') return if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.tooltip.Constructor = Tooltip // TOOLTIP NO CONFLICT // =================== $.fn.tooltip.noConflict = function () { $.fn.tooltip = old return this } }(jQuery); /* ======================================================================== * Bootstrap: transition.js v3.1.1 * http://getbootstrap.com/javascript/#transitions * ======================================================================== * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ +function ($) { 'use strict'; // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) // ============================================================ function transitionEnd() { var el = document.createElement('bootstrap') var transEndEventNames = { WebkitTransition : 'webkitTransitionEnd', MozTransition : 'transitionend', OTransition : 'oTransitionEnd otransitionend', transition : 'transitionend' } for (var name in transEndEventNames) { if (el.style[name] !== undefined) { return { end: transEndEventNames[name] } } } return false // explicit for ie8 ( ._.) } // http://blog.alexmaccaw.com/css-transitions $.fn.emulateTransitionEnd = function (duration) { var called = false, $el = this $(this).one($.support.transition.end, function () { called = true }) var callback = function () { if (!called) $($el).trigger($.support.transition.end) } setTimeout(callback, duration) return this } $(function () { $.support.transition = transitionEnd() }) }(jQuery); // ------------------------------------------ // Rellax.js // Buttery smooth parallax library // Copyright (c) 2016 Moe Amaya (@moeamaya) // MIT license // // Thanks to Paraxify.js and Jaime Cabllero // for parallax concepts // ------------------------------------------ (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], factory); } else if (typeof module === 'object' && module.exports) { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.Rellax = factory(); } }(typeof window !== "undefined" ? window : global, function () { var Rellax = function(el, options){ "use strict"; var self = Object.create(Rellax.prototype); var posY = 0; var screenY = 0; var posX = 0; var screenX = 0; var blocks = []; var pause = true; // check what requestAnimationFrame to use, and if // it's not supported, use the onscroll event var loop = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame || function(callback){ return setTimeout(callback, 1000 / 60); }; // store the id for later use var loopId = null; // Test via a getter in the options object to see if the passive property is accessed var supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function() { supportsPassive = true; } }); window.addEventListener("testPassive", null, opts); window.removeEventListener("testPassive", null, opts); } catch (e) {} // check what cancelAnimation method to use var clearLoop = window.cancelAnimationFrame || window.mozCancelAnimationFrame || clearTimeout; // check which transform property to use var transformProp = window.transformProp || (function(){ var testEl = document.createElement('div'); if (testEl.style.transform === null) { var vendors = ['Webkit', 'Moz', 'ms']; for (var vendor in vendors) { if (testEl.style[ vendors[vendor] + 'Transform' ] !== undefined) { return vendors[vendor] + 'Transform'; } } } return 'transform'; })(); // Default Settings self.options = { speed: -2, verticalSpeed: null, horizontalSpeed: null, breakpoints: [576, 768, 1201], center: false, wrapper: null, relativeToWrapper: false, round: true, vertical: true, horizontal: false, verticalScrollAxis: "y", horizontalScrollAxis: "x", callback: function() {}, }; // User defined options (might have more in the future) if (options){ Object.keys(options).forEach(function(key){ self.options[key] = options[key]; }); } function validateCustomBreakpoints () { if (self.options.breakpoints.length === 3 && Array.isArray(self.options.breakpoints)) { var isAscending = true; var isNumerical = true; var lastVal; self.options.breakpoints.forEach(function (i) { if (typeof i !== 'number') isNumerical = false; if (lastVal !== null) { if (i < lastVal) isAscending = false; } lastVal = i; }); if (isAscending && isNumerical) return; } // revert defaults if set incorrectly self.options.breakpoints = [576, 768, 1201]; console.warn("Rellax: You must pass an array of 3 numbers in ascending order to the breakpoints option. Defaults reverted"); } if (options && options.breakpoints) { validateCustomBreakpoints(); } // By default, rellax class if (!el) { el = '.rellax'; } // check if el is a className or a node var elements = typeof el === 'string' ? document.querySelectorAll(el) : [el]; // Now query selector if (elements.length > 0) { self.elems = elements; } // The elements don't exist else { console.warn("Rellax: The elements you're trying to select don't exist."); return; } // Has a wrapper and it exists if (self.options.wrapper) { if (!self.options.wrapper.nodeType) { var wrapper = document.querySelector(self.options.wrapper); if (wrapper) { self.options.wrapper = wrapper; } else { console.warn("Rellax: The wrapper you're trying to use doesn't exist."); return; } } } // set a placeholder for the current breakpoint var currentBreakpoint; // helper to determine current breakpoint var getCurrentBreakpoint = function (w) { var bp = self.options.breakpoints; if (w < bp[0]) return 'xs'; if (w >= bp[0] && w < bp[1]) return 'sm'; if (w >= bp[1] && w < bp[2]) return 'md'; return 'lg'; }; // Get and cache initial position of all elements var cacheBlocks = function() { for (var i = 0; i < self.elems.length; i++){ var block = createBlock(self.elems[i]); blocks.push(block); } }; // Let's kick this script off // Build array for cached element values var init = function() { for (var i = 0; i < blocks.length; i++){ self.elems[i].style.cssText = blocks[i].style; } blocks = []; screenY = window.innerHeight; screenX = window.innerWidth; currentBreakpoint = getCurrentBreakpoint(screenX); setPosition(); cacheBlocks(); animate(); // If paused, unpause and set listener for window resizing events if (pause) { window.addEventListener('resize', init); pause = false; // Start the loop update(); } }; // We want to cache the parallax blocks' // values: base, top, height, speed // el: is dom object, return: el cache values var createBlock = function(el) { var dataPercentage = el.getAttribute( 'data-rellax-percentage' ); var dataSpeed = el.getAttribute( 'data-rellax-speed' ); var dataXsSpeed = el.getAttribute( 'data-rellax-xs-speed' ); var dataMobileSpeed = el.getAttribute( 'data-rellax-mobile-speed' ); var dataTabletSpeed = el.getAttribute( 'data-rellax-tablet-speed' ); var dataDesktopSpeed = el.getAttribute( 'data-rellax-desktop-speed' ); var dataVerticalSpeed = el.getAttribute('data-rellax-vertical-speed'); var dataHorizontalSpeed = el.getAttribute('data-rellax-horizontal-speed'); var dataVericalScrollAxis = el.getAttribute('data-rellax-vertical-scroll-axis'); var dataHorizontalScrollAxis = el.getAttribute('data-rellax-horizontal-scroll-axis'); var dataZindex = el.getAttribute( 'data-rellax-zindex' ) || 0; var dataMin = el.getAttribute( 'data-rellax-min' ); var dataMax = el.getAttribute( 'data-rellax-max' ); var dataMinX = el.getAttribute('data-rellax-min-x'); var dataMaxX = el.getAttribute('data-rellax-max-x'); var dataMinY = el.getAttribute('data-rellax-min-y'); var dataMaxY = el.getAttribute('data-rellax-max-y'); var mapBreakpoints; var breakpoints = true; if (!dataXsSpeed && !dataMobileSpeed && !dataTabletSpeed && !dataDesktopSpeed) { breakpoints = false; } else { mapBreakpoints = { 'xs': dataXsSpeed, 'sm': dataMobileSpeed, 'md': dataTabletSpeed, 'lg': dataDesktopSpeed }; } // initializing at scrollY = 0 (top of browser), scrollX = 0 (left of browser) // ensures elements are positioned based on HTML layout. // // If the element has the percentage attribute, the posY and posX needs to be // the current scroll position's value, so that the elements are still positioned based on HTML layout var wrapperPosY = self.options.wrapper ? self.options.wrapper.scrollTop : (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); // If the option relativeToWrapper is true, use the wrappers offset to top, subtracted from the current page scroll. if (self.options.relativeToWrapper) { var scrollPosY = (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); wrapperPosY = scrollPosY - self.options.wrapper.offsetTop; } var posY = self.options.vertical ? ( dataPercentage || self.options.center ? wrapperPosY : 0 ) : 0; var posX = self.options.horizontal ? ( dataPercentage || self.options.center ? self.options.wrapper ? self.options.wrapper.scrollLeft : (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft) : 0 ) : 0; var blockTop = posY + el.getBoundingClientRect().top; var blockHeight = el.clientHeight || el.offsetHeight || el.scrollHeight; var blockLeft = posX + el.getBoundingClientRect().left; var blockWidth = el.clientWidth || el.offsetWidth || el.scrollWidth; // apparently parallax equation everyone uses var percentageY = dataPercentage ? dataPercentage : (posY - blockTop + screenY) / (blockHeight + screenY); var percentageX = dataPercentage ? dataPercentage : (posX - blockLeft + screenX) / (blockWidth + screenX); if(self.options.center){ percentageX = 0.5; percentageY = 0.5; } // Optional individual block speed as data attr, otherwise global speed var speed = (breakpoints && mapBreakpoints[currentBreakpoint] !== null) ? Number(mapBreakpoints[currentBreakpoint]) : (dataSpeed ? dataSpeed : self.options.speed); var verticalSpeed = dataVerticalSpeed ? dataVerticalSpeed : self.options.verticalSpeed; var horizontalSpeed = dataHorizontalSpeed ? dataHorizontalSpeed : self.options.horizontalSpeed; // Optional individual block movement axis direction as data attr, otherwise global movement direction var verticalScrollAxis = dataVericalScrollAxis ? dataVericalScrollAxis : self.options.verticalScrollAxis; var horizontalScrollAxis = dataHorizontalScrollAxis ? dataHorizontalScrollAxis : self.options.horizontalScrollAxis; var bases = updatePosition(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed); // ~~Store non-translate3d transforms~~ // Store inline styles and extract transforms var style = el.style.cssText; var transform = ''; // Check if there's an inline styled transform var searchResult = /transform\s*:/i.exec(style); if (searchResult) { // Get the index of the transform var index = searchResult.index; // Trim the style to the transform point and get the following semi-colon index var trimmedStyle = style.slice(index); var delimiter = trimmedStyle.indexOf(';'); // Remove "transform" string and save the attribute if (delimiter) { transform = " " + trimmedStyle.slice(11, delimiter).replace(/\s/g,''); } else { transform = " " + trimmedStyle.slice(11).replace(/\s/g,''); } } return { baseX: bases.x, baseY: bases.y, top: blockTop, left: blockLeft, height: blockHeight, width: blockWidth, speed: speed, verticalSpeed: verticalSpeed, horizontalSpeed: horizontalSpeed, verticalScrollAxis: verticalScrollAxis, horizontalScrollAxis: horizontalScrollAxis, style: style, transform: transform, zindex: dataZindex, min: dataMin, max: dataMax, minX: dataMinX, maxX: dataMaxX, minY: dataMinY, maxY: dataMaxY }; }; // set scroll position (posY, posX) // side effect method is not ideal, but okay for now // returns true if the scroll changed, false if nothing happened var setPosition = function() { var oldY = posY; var oldX = posX; posY = self.options.wrapper ? self.options.wrapper.scrollTop : (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset; posX = self.options.wrapper ? self.options.wrapper.scrollLeft : (document.documentElement || document.body.parentNode || document.body).scrollLeft || window.pageXOffset; // If option relativeToWrapper is true, use relative wrapper value instead. if (self.options.relativeToWrapper) { var scrollPosY = (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset; posY = scrollPosY - self.options.wrapper.offsetTop; } if (oldY != posY && self.options.vertical) { // scroll changed, return true return true; } if (oldX != posX && self.options.horizontal) { // scroll changed, return true return true; } // scroll did not change return false; }; // Ahh a pure function, gets new transform value // based on scrollPosition and speed // Allow for decimal pixel values var updatePosition = function(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed) { var result = {}; var valueX = ((horizontalSpeed ? horizontalSpeed : speed) * (100 * (1 - percentageX))); var valueY = ((verticalSpeed ? verticalSpeed : speed) * (100 * (1 - percentageY))); result.x = self.options.round ? Math.round(valueX) : Math.round(valueX * 100) / 100; result.y = self.options.round ? Math.round(valueY) : Math.round(valueY * 100) / 100; return result; }; // Remove event listeners and loop again var deferredUpdate = function() { window.removeEventListener('resize', deferredUpdate); window.removeEventListener('orientationchange', deferredUpdate); (self.options.wrapper ? self.options.wrapper : window).removeEventListener('scroll', deferredUpdate); (self.options.wrapper ? self.options.wrapper : document).removeEventListener('touchmove', deferredUpdate); // loop again loopId = loop(update); }; // Loop var update = function() { if (setPosition() && pause === false) { animate(); // loop again loopId = loop(update); } else { loopId = null; // Don't animate until we get a position updating event window.addEventListener('resize', deferredUpdate); window.addEventListener('orientationchange', deferredUpdate); (self.options.wrapper ? self.options.wrapper : window).addEventListener('scroll', deferredUpdate, supportsPassive ? { passive: true } : false); (self.options.wrapper ? self.options.wrapper : document).addEventListener('touchmove', deferredUpdate, supportsPassive ? { passive: true } : false); } }; // Transform3d on parallax element var animate = function() { var positions; for (var i = 0; i < self.elems.length; i++){ // Determine relevant movement directions var verticalScrollAxis = blocks[i].verticalScrollAxis.toLowerCase(); var horizontalScrollAxis = blocks[i].horizontalScrollAxis.toLowerCase(); var verticalScrollX = verticalScrollAxis.indexOf("x") != -1 ? posY : 0; var verticalScrollY = verticalScrollAxis.indexOf("y") != -1 ? posY : 0; var horizontalScrollX = horizontalScrollAxis.indexOf("x") != -1 ? posX : 0; var horizontalScrollY = horizontalScrollAxis.indexOf("y") != -1 ? posX : 0; var percentageY = ((verticalScrollY + horizontalScrollY - blocks[i].top + screenY) / (blocks[i].height + screenY)); var percentageX = ((verticalScrollX + horizontalScrollX - blocks[i].left + screenX) / (blocks[i].width + screenX)); // Subtracting initialize value, so element stays in same spot as HTML positions = updatePosition(percentageX, percentageY, blocks[i].speed, blocks[i].verticalSpeed, blocks[i].horizontalSpeed); var positionY = positions.y - blocks[i].baseY; var positionX = positions.x - blocks[i].baseX; // The next two "if" blocks go like this: // Check if a limit is defined (first "min", then "max"); // Check if we need to change the Y or the X // (Currently working only if just one of the axes is enabled) // Then, check if the new position is inside the allowed limit // If so, use new position. If not, set position to limit. // Check if a min limit is defined if (blocks[i].min !== null) { if (self.options.vertical && !self.options.horizontal) { positionY = positionY <= blocks[i].min ? blocks[i].min : positionY; } if (self.options.horizontal && !self.options.vertical) { positionX = positionX <= blocks[i].min ? blocks[i].min : positionX; } } // Check if directional min limits are defined if (blocks[i].minY != null) { positionY = positionY <= blocks[i].minY ? blocks[i].minY : positionY; } if (blocks[i].minX != null) { positionX = positionX <= blocks[i].minX ? blocks[i].minX : positionX; } // Check if a max limit is defined if (blocks[i].max !== null) { if (self.options.vertical && !self.options.horizontal) { positionY = positionY >= blocks[i].max ? blocks[i].max : positionY; } if (self.options.horizontal && !self.options.vertical) { positionX = positionX >= blocks[i].max ? blocks[i].max : positionX; } } // Check if directional max limits are defined if (blocks[i].maxY != null) { positionY = positionY >= blocks[i].maxY ? blocks[i].maxY : positionY; } if (blocks[i].maxX != null) { positionX = positionX >= blocks[i].maxX ? blocks[i].maxX : positionX; } var zindex = blocks[i].zindex; // Move that element // (Set the new translation and append initial inline transforms.) var translate = 'translate3d(' + (self.options.horizontal ? positionX : '0') + 'px,' + (self.options.vertical ? positionY : '0') + 'px,' + zindex + 'px) ' + blocks[i].transform; self.elems[i].style[transformProp] = translate; } self.options.callback(positions); }; self.destroy = function() { for (var i = 0; i < self.elems.length; i++){ self.elems[i].style.cssText = blocks[i].style; } // Remove resize event listener if not pause, and pause if (!pause) { window.removeEventListener('resize', init); pause = true; } // Clear the animation loop to prevent possible memory leak clearLoop(loopId); loopId = null; }; // Init init(); // Allow to recalculate the initial values whenever we want self.refresh = init; return self; }; return Rellax; })); /* * OKVideo by OKFocus v2.3.2 * http://okfoc.us * * Copyright 2014, OKFocus * Licensed under the MIT license. * */ var player, OKEvents, options, videoWidth, videoHeight, YTplayers, youtubePlayers = new Array(); // youtube player ready function onYouTubeIframeAPIReady() { YTplayers = new Array(); jQuery('.uncode-video-container.video').each(function() { var playerY; if (jQuery(this).attr('data-provider') == 'youtube') { var id = jQuery(this).attr('data-id'), start = jQuery(this).attr('data-start'), end = jQuery(this).attr('data-end'); start = typeof start && start !== null ? start : 0; end = typeof end && end !== null ? end : 0; options = jQuery(window).data('okoptions-' + id); if ( typeof options === 'undefined' ) { return true; } options.time = jQuery(this).attr('data-t'); playerY = new YT.Player('okplayer-' + id, { videoId: options.video ? options.video.id : null, playerVars: { 'autohide': 1, 'autoplay': jQuery(this).hasClass('is-no-control') ? options.autoplay : 0, //options.autoplay, 'disablekb': 1, 'cc_load_policy': options.captions, 'controls': 0, 'enablejsapi': 1, 'fs': 0, 'modestbranding': 1, 'origin': window.location.origin || (window.location.protocol + '//' + window.location.hostname), 'iv_load_policy': options.annotations, 'loop': options.loop, 'showinfo': 0, 'rel': 0, 'wmode': 'opaque', 'hd': options.hd, 'mute': 1, 'start': start, 'end': end }, events: { 'onReady': OKEvents.yt.ready, 'onStateChange': OKEvents.yt.onStateChange, 'onError': OKEvents.yt.error } }); YTplayers[id] = playerY; playerY.videoId = id; } }); } // vimeo player ready function vimeoPlayerReady(id) { options = jQuery(window).data('okoptions-' + id); if ( typeof options === 'undefined' ) { return true; } var jIframe = options.jobject, iframe = jIframe[0]; jIframe.attr('src', jIframe.data('src')); var playerV = new Vimeo.Player(iframe); // hide player until Vimeo hides controls... playerV.on('loaded', function(e) { OKEvents.v.onReady(iframe); var carouselContainer = jQuery(iframe).closest('.owl-carousel'); if (carouselContainer.length) { UNCODE.owlPlayVideo(carouselContainer); } // "Do not try to add listeners or call functions before receiving this event." if (OKEvents.utils.isMobile()) { // mobile devices cannot listen for play event OKEvents.v.onPlay(playerV); } else { playerV.on('play', function(){ OKEvents.v.onPlay(playerV); jQuery(window).trigger('okevents.v.play', [playerV]); }); playerV.on('pause', function(){ OKEvents.v.onPause; jQuery(window).trigger('okevents.v.pause', [playerV]); }); playerV.on('ended', function(){ OKEvents.v.onFinish jQuery(window).trigger('okevents.v.ended', [playerV]); }); } if (options.time != null) { var optsTimeStr = (options.time).replace('t=', ''), timeV = ''; if ( /[a-zA-Z]/g.test(optsTimeStr) ) { var timeArr = optsTimeStr.split(/([^\d.-])/); for ( var i = 0; i < timeArr.length; i++ ) { if ( timeArr[i] === 'h' ) { timeV += parseFloat(timeArr[i-1]) * 3600; } else if ( timeArr[i] === 'm' ) { timeV += parseFloat(timeArr[i-1]) * 60; } else if ( timeArr[i] === 's' ) { timeV += parseFloat(timeArr[i-1]); } } } else { timeV = optsTimeStr; } playerV.setCurrentTime(timeV); } playerV.setVolume(0); playerV.play(); jQuery(iframe).css({ visibility: 'visible', opacity: 1 }); jQuery(iframe).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1'); jQuery(iframe).closest('#page-header').addClass('video-started'); jQuery(iframe).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1'); jQuery(window).trigger('okevents.v.loaded', [playerV]); }); } OKEvents = { yt: { ready: function(event) { var id = event.target.videoId, $video = jQuery('#okplayer-' + id), options = jQuery(window).data('okoptions-' + id); if ( typeof options === 'undefined' ) { return true; } youtubePlayers[id] = event.target; event.target.setVolume(options.volume); if (options.autoplay === 1) { if (options.playlist.list) { player.loadPlaylist(options.playlist.list, options.playlist.index, options.playlist.startSeconds, options.playlist.suggestedQuality); } else { var inCarousel = $video.closest('.owl-item'); if (!inCarousel.length || (inCarousel.length && inCarousel.hasClass('active'))) { if (options.time != null) { event.target.seekTo(parseInt(options.time)); } event.target.playVideo(); } else { event.target.pauseVideo(); } } } OKEvents.utils.isFunction(options.onReady) && options.onReady(event.target); $video.closest('[data-provider]').on('uncode-resume', function(){ if (options.time != null) { event.target.seekTo(parseInt(options.time)).playVideo(); } else { event.target.seekTo(0).playVideo(); } }); $video.closest('[data-provider]').on('uncode-pause', function(){ if (options.time != null) { event.target.seekTo(parseInt(options.time)).pauseVideo(); } else { event.target.seekTo(0).pauseVideo(); } }); jQuery(window).trigger('okevents.y.loaded', [event]); }, onStateChange: function(event) { var id = event.target.videoId, $video = jQuery('#okplayer-' + id), options = jQuery(window).data('okoptions-' + id); if ( typeof options === 'undefined' ) { return true; } youtubePlayers[id] = event.target; event.target.setVolume(options.volume); var $fluid = $video.closest('.fluid-object'), $tmb = $video.closest('.tmb'), setTime; switch (event.data) { case -1: OKEvents.utils.isFunction(options.unstarted) && options.unstarted(); break; case 0: OKEvents.utils.isFunction(options.onFinished) && options.onFinished(); options.loop && event.target.playVideo(); break; case 1: OKEvents.utils.isFunction(options.onPlay) && options.onPlay(); setTimeout(function() { UNCODE.initVideoComponent(document.body, '.uncode-video-container.video:not(.drop-move), .uncode-video-container.self-video:not(.drop-move)'); jQuery('#okplayer-' + id).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1'); jQuery('#okplayer-' + id).closest('#page-header').addClass('video-started'); jQuery('#okplayer-' + id).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1'); }, 300); break; case 2: OKEvents.utils.isFunction(options.onPause) && options.onPause(); break; case 3: OKEvents.utils.isFunction(options.buffering) && options.buffering(); break; case 5: OKEvents.utils.isFunction(options.cued) && options.cued(); break; default: throw "OKVideo: received invalid data from YT player."; } jQuery(window).trigger('okevents.y.change', [event]); }, error: function(event) { throw event; } }, v: { onReady: function(target) { if ( typeof options === 'undefined' ) { return true; } OKEvents.utils.isFunction(options.onReady) && options.onReady(target); }, onPlay: function(player) { if ( typeof options === 'undefined' ) { return true; } if (!OKEvents.utils.isMobile()) player.setVolume(options.volume); OKEvents.utils.isFunction(options.onPlay) && options.onPlay(); jQuery(player.element).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1'); jQuery(player.element).closest('#page-header').addClass('video-started'); jQuery(player.element).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1'); }, onPause: function() { if ( typeof options === 'undefined' ) { return true; } OKEvents.utils.isFunction(options.onPause) && options.onPause(); }, onFinish: function() { if ( typeof options === 'undefined' ) { return true; } OKEvents.utils.isFunction(options.onFinish) && options.onFinish(); } }, utils: { isFunction: function(func) { if (typeof func === 'function') { return true; } else { return false; } }, isMobile: function() { if (navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/)) { return true; } else { return false; } } } }; /** * vivus - JavaScript library to make drawing animation on SVG * @version v0.4.4 * @link https://github.com/maxwellito/vivus * @license MIT */ 'use strict'; (function () { 'use strict'; /** * Pathformer * Beta version * * Take any SVG version 1.1 and transform * child elements to 'path' elements * * This code is purely forked from * https://github.com/Waest/SVGPathConverter */ /** * Class constructor * * @param {DOM|String} element Dom element of the SVG or id of it */ function Pathformer(element) { // Test params if (typeof element === 'undefined') { throw new Error('Pathformer [constructor]: "element" parameter is required'); } // Set the element if (element.constructor === String) { element = document.getElementById(element); if (!element) { throw new Error('Pathformer [constructor]: "element" parameter is not related to an existing ID'); } } if (element instanceof window.SVGElement || element instanceof window.SVGGElement || /^svg$/i.test(element.nodeName)) { this.el = element; } else { throw new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'); } // Start this.scan(element); } /** * List of tags which can be transformed * to path elements * * @type {Array} */ Pathformer.prototype.TYPES = ['line', 'ellipse', 'circle', 'polygon', 'polyline', 'rect']; /** * List of attribute names which contain * data. This array list them to check if * they contain bad values, like percentage. * * @type {Array} */ Pathformer.prototype.ATTR_WATCH = ['cx', 'cy', 'points', 'r', 'rx', 'ry', 'x', 'x1', 'x2', 'y', 'y1', 'y2']; /** * Finds the elements compatible for transform * and apply the liked method * * @param {object} options Object from the constructor */ Pathformer.prototype.scan = function (svg) { var fn, element, pathData, pathDom, elements = svg.querySelectorAll(this.TYPES.join(',')); for (var i = 0; i < elements.length; i++) { element = elements[i]; fn = this[element.tagName.toLowerCase() + 'ToPath']; pathData = fn(this.parseAttr(element.attributes)); pathDom = this.pathMaker(element, pathData); element.parentNode.replaceChild(pathDom, element); } }; /** * Read `line` element to extract and transform * data, to make it ready for a `path` object. * * @param {DOMelement} element Line element to transform * @return {object} Data for a `path` element */ Pathformer.prototype.lineToPath = function (element) { var newElement = {}, x1 = element.x1 || 0, y1 = element.y1 || 0, x2 = element.x2 || 0, y2 = element.y2 || 0; newElement.d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2; return newElement; }; /** * Read `rect` element to extract and transform * data, to make it ready for a `path` object. * The radius-border is not taken in charge yet. * (your help is more than welcomed) * * @param {DOMelement} element Rect element to transform * @return {object} Data for a `path` element */ Pathformer.prototype.rectToPath = function (element) { var newElement = {}, x = parseFloat(element.x) || 0, y = parseFloat(element.y) || 0, width = parseFloat(element.width) || 0, height = parseFloat(element.height) || 0; if (element.rx || element.ry) { var rx = parseInt(element.rx, 10) || -1, ry = parseInt(element.ry, 10) || -1; rx = Math.min(Math.max(rx < 0 ? ry : rx, 0), width/2); ry = Math.min(Math.max(ry < 0 ? rx : ry, 0), height/2); newElement.d = 'M ' + (x + rx) + ',' + y + ' ' + 'L ' + (x + width - rx) + ',' + y + ' ' + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + width) + ',' + (y + ry) + ' ' + 'L ' + (x + width) + ',' + (y + height - ry) + ' ' + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + width - rx) + ',' + (y + height) + ' ' + 'L ' + (x + rx) + ',' + (y + height) + ' ' + 'A ' + rx + ',' + ry + ',0,0,1,' + x + ',' + (y + height - ry) + ' ' + 'L ' + x + ',' + (y + ry) + ' ' + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + rx) + ',' + y; } else { newElement.d = 'M' + x + ' ' + y + ' ' + 'L' + (x + width) + ' ' + y + ' ' + 'L' + (x + width) + ' ' + (y + height) + ' ' + 'L' + x + ' ' + (y + height) + ' Z'; } return newElement; }; /** * Read `polyline` element to extract and transform * data, to make it ready for a `path` object. * * @param {DOMelement} element Polyline element to transform * @return {object} Data for a `path` element */ Pathformer.prototype.polylineToPath = function (element) { var newElement = {}, points = element.points.trim().split(' '), i, path; // Reformatting if points are defined without commas if (element.points.indexOf(',') === -1) { var formattedPoints = []; for (i = 0; i < points.length; i+=2) { formattedPoints.push(points[i] + ',' + points[i+1]); } points = formattedPoints; } // Generate the path.d value path = 'M' + points[0]; for(i = 1; i < points.length; i++) { if (points[i].indexOf(',') !== -1) { path += 'L' + points[i]; } } newElement.d = path; return newElement; }; /** * Read `polygon` element to extract and transform * data, to make it ready for a `path` object. * This method rely on polylineToPath, because the * logic is similar. The path created is just closed, * so it needs an 'Z' at the end. * * @param {DOMelement} element Polygon element to transform * @return {object} Data for a `path` element */ Pathformer.prototype.polygonToPath = function (element) { var newElement = Pathformer.prototype.polylineToPath(element); newElement.d += 'Z'; return newElement; }; /** * Read `ellipse` element to extract and transform * data, to make it ready for a `path` object. * * @param {DOMelement} element ellipse element to transform * @return {object} Data for a `path` element */ Pathformer.prototype.ellipseToPath = function (element) { var newElement = {}, rx = parseFloat(element.rx) || 0, ry = parseFloat(element.ry) || 0, cx = parseFloat(element.cx) || 0, cy = parseFloat(element.cy) || 0, startX = cx - rx, startY = cy, endX = parseFloat(cx) + parseFloat(rx), endY = cy; newElement.d = 'M' + startX + ',' + startY + 'A' + rx + ',' + ry + ' 0,1,1 ' + endX + ',' + endY + 'A' + rx + ',' + ry + ' 0,1,1 ' + startX + ',' + endY; return newElement; }; /** * Read `circle` element to extract and transform * data, to make it ready for a `path` object. * * @param {DOMelement} element Circle element to transform * @return {object} Data for a `path` element */ Pathformer.prototype.circleToPath = function (element) { var newElement = {}, r = parseFloat(element.r) || 0, cx = parseFloat(element.cx) || 0, cy = parseFloat(element.cy) || 0, startX = cx - r, startY = cy, endX = parseFloat(cx) + parseFloat(r), endY = cy; newElement.d = 'M' + startX + ',' + startY + 'A' + r + ',' + r + ' 0,1,1 ' + endX + ',' + endY + 'A' + r + ',' + r + ' 0,1,1 ' + startX + ',' + endY; return newElement; }; /** * Create `path` elements form original element * and prepared objects * * @param {DOMelement} element Original element to transform * @param {object} pathData Path data (from `toPath` methods) * @return {DOMelement} Path element */ Pathformer.prototype.pathMaker = function (element, pathData) { var i, attr, pathTag = document.createElementNS('http://www.w3.org/2000/svg','path'); for(i = 0; i < element.attributes.length; i++) { attr = element.attributes[i]; if (this.ATTR_WATCH.indexOf(attr.name) === -1) { pathTag.setAttribute(attr.name, attr.value); } } for(i in pathData) { pathTag.setAttribute(i, pathData[i]); } return pathTag; }; /** * Parse attributes of a DOM element to * get an object of attribute => value * * @param {NamedNodeMap} attributes Attributes object from DOM element to parse * @return {object} Object of attributes */ Pathformer.prototype.parseAttr = function (element) { var attr, output = {}; for (var i = 0; i < element.length; i++) { attr = element[i]; // Check if no data attribute contains '%', or the transformation is impossible if (this.ATTR_WATCH.indexOf(attr.name) !== -1 && attr.value.indexOf('%') !== -1) { throw new Error('Pathformer [parseAttr]: a SVG shape got values in percentage. This cannot be transformed into \'path\' tags. Please use \'viewBox\'.'); } output[attr.name] = attr.value; } return output; }; 'use strict'; var setupEnv, requestAnimFrame, cancelAnimFrame, parsePositiveInt; /** * Vivus * Beta version * * Take any SVG and make the animation * to give give the impression of live drawing * * This in more than just inspired from codrops * At that point, it's a pure fork. */ /** * Class constructor * option structure * type: 'delayed'|'sync'|'oneByOne'|'script' (to know if the items must be drawn synchronously or not, default: delayed) * duration: (in frames) * start: 'inViewport'|'manual'|'autostart' (start automatically the animation, default: inViewport) * delay: (delay between the drawing of first and last path) * dashGap whitespace extra margin between dashes * pathTimingFunction timing animation function for each path element of the SVG * animTimingFunction timing animation function for the complete SVG * forceRender force the browser to re-render all updated path items * selfDestroy removes all extra styling on the SVG, and leaves it as original * * The attribute 'type' is by default on 'delayed'. * - 'delayed' * all paths are draw at the same time but with a * little delay between them before start * - 'sync' * all path are start and finish at the same time * - 'oneByOne' * only one path is draw at the time * the end of the first one will trigger the draw * of the next one * * All these values can be overwritten individually * for each path item in the SVG * The value of frames will always take the advantage of * the duration value. * If you fail somewhere, an error will be thrown. * Good luck. * * @constructor * @this {Vivus} * @param {DOM|String} element Dom element of the SVG or id of it * @param {Object} options Options about the animation * @param {Function} callback Callback for the end of the animation */ function Vivus (element, options, callback) { setupEnv(); // Setup this.isReady = false; this.setElement(element, options); this.setOptions(options); this.setCallback(callback); if (this.isReady) { this.init(); } } /** * Timing functions ************************************** * * Default functions to help developers. * It always take a number as parameter (between 0 to 1) then * return a number (between 0 and 1) */ Vivus.LINEAR = function (x) {return x;}; Vivus.EASE = function (x) {return -Math.cos(x * Math.PI) / 2 + 0.5;}; Vivus.EASE_OUT = function (x) {return 1 - Math.pow(1-x, 3);}; Vivus.EASE_IN = function (x) {return Math.pow(x, 3);}; Vivus.EASE_OUT_BOUNCE = function (x) { var base = -Math.cos(x * (0.5 * Math.PI)) + 1, rate = Math.pow(base,1.5), rateR = Math.pow(1 - x, 2), progress = -Math.abs(Math.cos(rate * (2.5 * Math.PI) )) + 1; return (1- rateR) + (progress * rateR); }; /** * Setters ************************************** */ /** * Check and set the element in the instance * The method will not return anything, but will throw an * error if the parameter is invalid * * @param {DOM|String} element SVG Dom element or id of it */ Vivus.prototype.setElement = function (element, options) { var onLoad, self; // Basic check if (typeof element === 'undefined') { throw new Error('Vivus [constructor]: "element" parameter is required'); } // Set the element if (element.constructor === String) { element = document.getElementById(element); if (!element) { throw new Error('Vivus [constructor]: "element" parameter is not related to an existing ID'); } } this.parentEl = element; // Load the SVG with XMLHttpRequest and extract the SVG if (options && options.file) { var self = this; onLoad = function (e) { var domSandbox = document.createElement('div'); domSandbox.innerHTML = this.responseText; var svgTag = domSandbox.querySelector('svg'); if (!svgTag) { throw new Error('Vivus [load]: Cannot find the SVG in the loaded file : ' + options.file); } self.el = svgTag self.el.setAttribute('width', '100%'); self.el.setAttribute('height', '100%'); self.parentEl.appendChild(self.el) self.isReady = true; self.init(); self = null; } var oReq = new window.XMLHttpRequest(); oReq.addEventListener('load', onLoad); oReq.open('GET', options.file); oReq.send(); return; } switch (element.constructor) { case window.SVGSVGElement: case window.SVGElement: case window.SVGGElement: this.el = element; this.isReady = true; break; case window.HTMLObjectElement: self = this; onLoad = function (e) { if (self.isReady) { return; } self.el = element.contentDocument && element.contentDocument.querySelector('svg'); if (!self.el && e) { throw new Error('Vivus [constructor]: object loaded does not contain any SVG'); } else if (self.el) { if (element.getAttribute('built-by-vivus')) { self.parentEl.insertBefore(self.el, element); self.parentEl.removeChild(element); self.el.setAttribute('width', '100%'); self.el.setAttribute('height', '100%'); } self.isReady = true; self.init(); self = null; } }; if (!onLoad()) { element.addEventListener('load', onLoad); } break; default: throw new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'); } }; /** * Set up user option to the instance * The method will not return anything, but will throw an * error if the parameter is invalid * * @param {object} options Object from the constructor */ Vivus.prototype.setOptions = function (options) { var allowedTypes = ['delayed', 'sync', 'async', 'nsync', 'oneByOne', 'scenario', 'scenario-sync']; var allowedStarts = ['inViewport', 'manual', 'autostart']; // Basic check if (options !== undefined && options.constructor !== Object) { throw new Error('Vivus [constructor]: "options" parameter must be an object'); } else { options = options || {}; } // Set the animation type if (options.type && allowedTypes.indexOf(options.type) === -1) { throw new Error('Vivus [constructor]: ' + options.type + ' is not an existing animation `type`'); } else { this.type = options.type || allowedTypes[0]; } // Set the start type if (options.start && allowedStarts.indexOf(options.start) === -1) { throw new Error('Vivus [constructor]: ' + options.start + ' is not an existing `start` option'); } else { this.start = options.start || allowedStarts[0]; } this.isIE = (window.navigator.userAgent.indexOf('MSIE') !== -1 || window.navigator.userAgent.indexOf('Trident/') !== -1 || window.navigator.userAgent.indexOf('Edge/') !== -1 ); this.duration = parsePositiveInt(options.duration, 120); this.delay = parsePositiveInt(options.delay, null); //Uncode addition this.delayStart = parsePositiveInt(options.delayStart, null); //#END this.dashGap = parsePositiveInt(options.dashGap, 1); this.forceRender = options.hasOwnProperty('forceRender') ? !!options.forceRender : this.isIE; this.reverseStack = !!options.reverseStack; this.selfDestroy = !!options.selfDestroy; this.onReady = options.onReady; this.map = []; this.frameLength = this.currentFrame = this.delayUnit = this.speed = this.handle = null; this.ignoreInvisible = options.hasOwnProperty('ignoreInvisible') ? !!options.ignoreInvisible : false; this.animTimingFunction = options.animTimingFunction || Vivus.LINEAR; this.pathTimingFunction = options.pathTimingFunction || Vivus.LINEAR; if (this.delay >= this.duration) { throw new Error('Vivus [constructor]: delay must be shorter than duration'); } }; /** * Set up callback to the instance * The method will not return enything, but will throw an * error if the parameter is invalid * * @param {Function} callback Callback for the animation end */ Vivus.prototype.setCallback = function (callback) { // Basic check if (!!callback && callback.constructor !== Function) { throw new Error('Vivus [constructor]: "callback" parameter must be a function'); } this.callback = callback || function () {}; }; /** * Core ************************************** */ /** * Map the svg, path by path. * The method return nothing, it just fill the * `map` array. Each item in this array represent * a path element from the SVG, with informations for * the animation. * * ``` * [ * { * el: the path element * length: length of the path line * startAt: time start of the path animation (in frames) * duration: path animation duration (in frames) * }, * ... * ] * ``` * */ Vivus.prototype.mapping = function () { var i, paths, path, pAttrs, pathObj, totalLength, lengthMeter, timePoint; timePoint = totalLength = lengthMeter = 0; paths = this.el.querySelectorAll('path'); for (i = 0; i < paths.length; i++) { path = paths[i]; if (this.isInvisible(path)) { continue; } pathObj = { el: path, length: Math.ceil(path.getTotalLength()) }; // Test if the path length is correct if (isNaN(pathObj.length)) { if (window.console && console.warn) { console.warn('Vivus [mapping]: cannot retrieve a path element length', path); } continue; } this.map.push(pathObj); path.style.strokeDasharray = pathObj.length + ' ' + (pathObj.length + this.dashGap * 2); path.style.strokeDashoffset = pathObj.length + this.dashGap; pathObj.length += this.dashGap; totalLength += pathObj.length; this.renderPath(i); } totalLength = totalLength === 0 ? 1 : totalLength; this.delay = this.delay === null ? this.duration / 3 : this.delay; this.delayUnit = this.delay / (paths.length > 1 ? paths.length - 1 : 1); // Reverse stack if asked if (this.reverseStack) { this.map.reverse(); } for (i = 0; i < this.map.length; i++) { pathObj = this.map[i]; switch (this.type) { case 'delayed': pathObj.startAt = this.delayUnit * i; pathObj.duration = this.duration - this.delay; break; case 'oneByOne': pathObj.startAt = lengthMeter / totalLength * this.duration; pathObj.duration = pathObj.length / totalLength * this.duration; break; case 'sync': case 'async': case 'nsync': pathObj.startAt = 0; pathObj.duration = this.duration; break; case 'scenario-sync': path = pathObj.el; pAttrs = this.parseAttr(path); pathObj.startAt = timePoint + (parsePositiveInt(pAttrs['data-delay'], this.delayUnit) || 0); pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration); timePoint = pAttrs['data-async'] !== undefined ? pathObj.startAt : pathObj.startAt + pathObj.duration; this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration)); break; case 'scenario': path = pathObj.el; pAttrs = this.parseAttr(path); pathObj.startAt = parsePositiveInt(pAttrs['data-start'], this.delayUnit) || 0; pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration); this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration)); break; } lengthMeter += pathObj.length; this.frameLength = this.frameLength || this.duration; } }; /** * Interval method to draw the SVG from current * position of the animation. It update the value of * `currentFrame` and re-trace the SVG. * * It use this.handle to store the requestAnimationFrame * and clear it one the animation is stopped. So this * attribute can be used to know if the animation is * playing. * * Once the animation at the end, this method will * trigger the Vivus callback. * */ Vivus.prototype.drawer = function () { var self = this; this.currentFrame += this.speed; if (this.currentFrame <= 0) { this.stop(); this.reset(); } else if (this.currentFrame >= this.frameLength) { this.stop(); this.currentFrame = this.frameLength; this.trace(); if (this.selfDestroy) { this.destroy(); } } else { this.trace(); this.handle = requestAnimFrame(function () { self.drawer(); }); return; } this.callback(this); if (this.instanceCallback) { this.instanceCallback(this); this.instanceCallback = null; } }; /** * Draw the SVG at the current instant from the * `currentFrame` value. Here is where most of the magic is. * The trick is to use the `strokeDashoffset` style property. * * For optimisation reasons, a new property called `progress` * is added in each item of `map`. This one contain the current * progress of the path element. Only if the new value is different * the new value will be applied to the DOM element. This * method save a lot of resources to re-render the SVG. And could * be improved if the animation couldn't be played forward. * */ Vivus.prototype.trace = function () { var i, progress, path, currentFrame; currentFrame = this.animTimingFunction(this.currentFrame / this.frameLength) * this.frameLength; for (i = 0; i < this.map.length; i++) { path = this.map[i]; progress = (currentFrame - path.startAt) / path.duration; progress = this.pathTimingFunction(Math.max(0, Math.min(1, progress))); if (path.progress !== progress) { path.progress = progress; path.el.style.strokeDashoffset = Math.floor(path.length * (1 - progress)); this.renderPath(i); } } }; /** * Method forcing the browser to re-render a path element * from it's index in the map. Depending on the `forceRender` * value. * The trick is to replace the path element by it's clone. * This practice is not recommended because it's asking more * ressources, too much DOM manupulation.. * but it's the only way to let the magic happen on IE. * By default, this fallback is only applied on IE. * * @param {Number} index Path index */ Vivus.prototype.renderPath = function (index) { if (this.forceRender && this.map && this.map[index]) { var pathObj = this.map[index], newPath = pathObj.el.cloneNode(true); pathObj.el.parentNode.replaceChild(newPath, pathObj.el); pathObj.el = newPath; } }; /** * When the SVG object is loaded and ready, * this method will continue the initialisation. * * This this mainly due to the case of passing an * object tag in the constructor. It will wait * the end of the loading to initialise. * */ Vivus.prototype.init = function () { // Set object variables this.frameLength = 0; this.currentFrame = 0; this.map = []; // Start new Pathformer(this.el); this.mapping(); this.starter(); if (this.onReady) { this.onReady(this); } }; /** * Trigger to start of the animation. * Depending on the `start` value, a different script * will be applied. * * If the `start` value is not valid, an error will be thrown. * Even if technically, this is impossible. * */ Vivus.prototype.starter = function () { switch (this.start) { case 'manual': return; case 'autostart': this.play(); break; case 'inViewport': var self = this, listener = function () { if (self.isInViewport(self.parentEl, 1)) { self.play(); window.removeEventListener('scroll', listener); //Uncode addition window.removeEventListener('fp-slide-changed', listener); window.removeEventListener('fp-slide-scroll', listener); //#END } }; window.addEventListener('scroll', listener); //Uncode addition window.addEventListener('fp-slide-changed', listener); window.addEventListener('fp-slide-scroll', listener); //#END listener(); break; } }; /** * Controls ************************************** */ /** * Get the current status of the animation between * three different states: 'start', 'progress', 'end'. * @return {string} Instance status */ Vivus.prototype.getStatus = function () { return this.currentFrame === 0 ? 'start' : this.currentFrame === this.frameLength ? 'end' : 'progress'; }; /** * Reset the instance to the initial state : undraw * Be careful, it just reset the animation, if you're * playing the animation, this won't stop it. But just * make it start from start. * */ Vivus.prototype.reset = function () { return this.setFrameProgress(0); }; /** * Set the instance to the final state : drawn * Be careful, it just set the animation, if you're * playing the animation on rewind, this won't stop it. * But just make it start from the end. * */ Vivus.prototype.finish = function () { return this.setFrameProgress(1); }; /** * Set the level of progress of the drawing. * * @param {number} progress Level of progress to set */ Vivus.prototype.setFrameProgress = function (progress) { progress = Math.min(1, Math.max(0, progress)); this.currentFrame = Math.round(this.frameLength * progress); this.trace(); return this; }; /** * Play the animation at the desired speed. * Speed must be a valid number (no zero). * By default, the speed value is 1. * But a negative value is accepted to go forward. * * And works with float too. * But don't forget we are in JavaScript, se be nice * with him and give him a 1/2^x value. * * @param {number} speed Animation speed [optional] */ Vivus.prototype.play = function (speed, callback) { this.instanceCallback = null; if (speed && typeof speed === 'function') { this.instanceCallback = speed; // first parameter is actually the callback function speed = null; } else if (speed && typeof speed !== 'number') { throw new Error('Vivus [play]: invalid speed'); } // if the first parameter wasn't the callback, check if the seconds was if (callback && typeof(callback) === 'function' && !this.instanceCallback) { this.instanceCallback = callback; } this.speed = speed || 1; //Uncode addition if (!this.handle) { var $this = this, delay = (this.delayStart != null) ? this.delayStart : 0; setTimeout(function() { $this.drawer(); }, delay); } //#END return this; }; /** * Stop the current animation, if on progress. * Should not trigger any error. * */ Vivus.prototype.stop = function () { if (this.handle) { cancelAnimFrame(this.handle); this.handle = null; } return this; }; /** * Destroy the instance. * Remove all bad styling attributes on all * path tags * */ Vivus.prototype.destroy = function () { this.stop(); var i, path; for (i = 0; i < this.map.length; i++) { path = this.map[i]; path.el.style.strokeDashoffset = null; path.el.style.strokeDasharray = null; this.renderPath(i); } }; /** * Utils methods * include methods from Codrops ************************************** */ /** * Method to best guess if a path should added into * the animation or not. * * 1. Use the `data-vivus-ignore` attribute if set * 2. Check if the instance must ignore invisible paths * 3. Check if the path is visible * * For now the visibility checking is unstable. * It will be used for a beta phase. * * Other improvments are planned. Like detecting * is the path got a stroke or a valid opacity. */ Vivus.prototype.isInvisible = function (el) { var rect, ignoreAttr = el.getAttribute('data-ignore'); if (ignoreAttr !== null) { return ignoreAttr !== 'false'; } if (this.ignoreInvisible) { rect = el.getBoundingClientRect(); return !rect.width && !rect.height; } else { return false; } }; /** * Parse attributes of a DOM element to * get an object of {attributeName => attributeValue} * * @param {object} element DOM element to parse * @return {object} Object of attributes */ Vivus.prototype.parseAttr = function (element) { var attr, output = {}; if (element && element.attributes) { for (var i = 0; i < element.attributes.length; i++) { attr = element.attributes[i]; output[attr.name] = attr.value; } } return output; }; /** * Reply if an element is in the page viewport * * @param {object} el Element to observe * @param {number} h Percentage of height * @return {boolean} */ Vivus.prototype.isInViewport = function (el, h) { var scrolled = this.scrollY(), viewed = scrolled + this.getViewportH(), elBCR = el.getBoundingClientRect(), elHeight = elBCR.height, elTop = scrolled + elBCR.top, elBottom = elTop + elHeight; // if 0, the element is considered in the viewport as soon as it enters. // if 1, the element is considered in the viewport only when it's fully inside // value in percentage (1 >= h >= 0) h = h || 0; return (elTop + elHeight * h) <= viewed && (elBottom) >= scrolled; }; /** * Get the viewport height in pixels * * @return {integer} Viewport height */ Vivus.prototype.getViewportH = function () { var client = this.docElem.clientHeight, inner = window.innerHeight; if (client < inner) { return inner; } else { return client; } }; /** * Get the page Y offset * * @return {integer} Page Y offset */ Vivus.prototype.scrollY = function () { return window.pageYOffset || this.docElem.scrollTop; }; setupEnv = function () { if (Vivus.prototype.docElem) { return; } /** * Alias for document element * * @type {DOMelement} */ Vivus.prototype.docElem = window.document.documentElement; /** * Alias for `requestAnimationFrame` or * `setTimeout` function for deprecated browsers. * */ requestAnimFrame = (function () { return ( window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(/* function */ callback){ return window.setTimeout(callback, 1000 / 60); } ); })(); /** * Alias for `cancelAnimationFrame` or * `cancelTimeout` function for deprecated browsers. * */ cancelAnimFrame = (function () { return ( window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame || function(id){ return window.clearTimeout(id); } ); })(); }; /** * Parse string to integer. * If the number is not positive or null * the method will return the default value * or 0 if undefined * * @param {string} value String to parse * @param {*} defaultValue Value to return if the result parsed is invalid * @return {number} * */ parsePositiveInt = function (value, defaultValue) { var output = parseInt(value, 10); return (output >= 0) ? output : defaultValue; }; if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], function() { return Vivus; }); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = Vivus; } else { // Browser globals window.Vivus = Vivus; } }());