@egjs/flicking
Version:
Everyday 30 million people experience. It's reliable, flexible and extendable carousel.
1,614 lines (1,324 loc) • 189 kB
JavaScript
/*
Copyright (c) 2015-present NAVER Corp.
name: @egjs/flicking
license: MIT
author: NAVER Corp.
repository: https://github.com/naver/egjs-flicking
version: 3.7.1
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@egjs/component'), require('@egjs/imready'), require('@egjs/axes')) :
typeof define === 'function' && define.amd ? define(['@egjs/component', '@egjs/imready', '@egjs/axes'], factory) :
(global = global || self, (global.eg = global.eg || {}, global.eg.Flicking = factory(global.eg.Component, global.ImReady, global.eg.Axes)));
}(this, (function (Component, ImReady, Axes) { '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.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || {
__proto__: []
} instanceof Array && function (d, b) {
d.__proto__ = b;
} || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
};
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() {
this.constructor = d;
}
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
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;
}
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
var MOVE_TYPE = {
SNAP: "snap",
FREE_SCROLL: "freeScroll"
};
var DEFAULT_MOVE_TYPE_OPTIONS = {
snap: {
type: "snap",
count: 1
},
freeScroll: {
type: "freeScroll"
}
};
var isBrowser = typeof document !== "undefined";
/**
* Default options for creating Flicking.
* @ko 플리킹을 만들 때 사용하는 기본 옵션들
* @private
* @memberof eg.Flicking
*/
var DEFAULT_OPTIONS = {
classPrefix: "eg-flick",
deceleration: 0.0075,
horizontal: true,
circular: false,
infinite: false,
infiniteThreshold: 0,
lastIndex: Infinity,
threshold: 40,
duration: 100,
panelEffect: function (x) {
return 1 - Math.pow(1 - x, 3);
},
defaultIndex: 0,
inputType: ["touch", "mouse"],
thresholdAngle: 45,
bounce: 10,
autoResize: false,
adaptive: false,
zIndex: 2000,
bound: false,
overflow: false,
hanger: "50%",
anchor: "50%",
gap: 0,
moveType: DEFAULT_MOVE_TYPE_OPTIONS.snap,
useOffset: false,
isEqualSize: false,
isConstantSize: false,
renderOnlyVisible: false,
renderExternal: false,
resizeOnContentsReady: false,
iOSEdgeSwipeThreshold: 30,
collectStatistics: true
};
var DEFAULT_VIEWPORT_CSS = {
position: "relative",
zIndex: DEFAULT_OPTIONS.zIndex,
overflow: "hidden"
};
var DEFAULT_CAMERA_CSS = {
width: "100%",
height: "100%",
willChange: "transform"
};
var DEFAULT_PANEL_CSS = {
position: "absolute"
};
var EVENTS = {
HOLD_START: "holdStart",
HOLD_END: "holdEnd",
MOVE_START: "moveStart",
MOVE: "move",
MOVE_END: "moveEnd",
CHANGE: "change",
RESTORE: "restore",
SELECT: "select",
NEED_PANEL: "needPanel",
VISIBLE_CHANGE: "visibleChange",
CONTENT_ERROR: "contentError"
};
var AXES_EVENTS = {
HOLD: "hold",
CHANGE: "change",
RELEASE: "release",
ANIMATION_END: "animationEnd",
FINISH: "finish"
};
var STATE_TYPE = {
IDLE: 0,
HOLDING: 1,
DRAGGING: 2,
ANIMATING: 3,
DISABLED: 4
};
var DIRECTION = {
PREV: "PREV",
NEXT: "NEXT"
};
var FLICKING_METHODS = {
prev: true,
next: true,
moveTo: true,
getIndex: true,
getAllPanels: true,
getCurrentPanel: true,
getElement: true,
getSize: true,
getPanel: true,
getPanelCount: true,
getStatus: true,
getVisiblePanels: true,
enableInput: true,
disableInput: true,
destroy: true,
resize: true,
setStatus: true,
isPlaying: true
}; // Check whether browser supports transform: translate3d
// https://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
var checkTranslateSupport = function () {
var transforms = {
webkitTransform: "-webkit-transform",
msTransform: "-ms-transform",
MozTransform: "-moz-transform",
OTransform: "-o-transform",
transform: "transform"
};
if (!isBrowser) {
return {
name: transforms.transform,
has3d: true
};
}
var supportedStyle = document.documentElement.style;
var transformName = "";
for (var prefixedTransform in transforms) {
if (prefixedTransform in supportedStyle) {
transformName = prefixedTransform;
}
}
if (!transformName) {
throw new Error("Browser doesn't support CSS3 2D Transforms.");
}
var el = document.createElement("div");
document.documentElement.insertBefore(el, null);
el.style[transformName] = "translate3d(1px, 1px, 1px)";
var styleVal = window.getComputedStyle(el).getPropertyValue(transforms[transformName]);
el.parentElement.removeChild(el);
var transformInfo = {
name: transformName,
has3d: styleVal.length > 0 && styleVal !== "none"
};
checkTranslateSupport = function () {
return transformInfo;
};
return transformInfo;
};
var TRANSFORM = checkTranslateSupport();
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
function merge(target) {
var srcs = [];
for (var _i = 1; _i < arguments.length; _i++) {
srcs[_i - 1] = arguments[_i];
}
srcs.forEach(function (source) {
Object.keys(source).forEach(function (key) {
var value = source[key];
target[key] = value;
});
});
return target;
}
function parseElement(element) {
if (!Array.isArray(element)) {
element = [element];
}
var elements = [];
element.forEach(function (el) {
if (isString(el)) {
var tempDiv = document.createElement("div");
tempDiv.innerHTML = el;
elements.push.apply(elements, toArray(tempDiv.children));
while (tempDiv.firstChild) {
tempDiv.removeChild(tempDiv.firstChild);
}
} else {
elements.push(el);
}
});
return elements;
}
function isString(value) {
return typeof value === "string";
} // Get class list of element as string array
function addClass(element, className) {
if (element.classList) {
element.classList.add(className);
} else {
if (!hasClass(element, className)) {
element.className = (element.className + " " + className).replace(/\s{2,}/g, " ");
}
}
}
function hasClass(element, className) {
if (element.classList) {
return element.classList.contains(className);
} else {
return element.className.split(" ").indexOf(className) >= 0;
}
}
function applyCSS(element, cssObj) {
Object.keys(cssObj).forEach(function (property) {
element.style[property] = cssObj[property];
});
}
function clamp(val, min, max) {
return Math.max(Math.min(val, max), min);
} // Min: inclusive, Max: exclusive
function isBetween(val, min, max) {
return val >= min && val <= max;
}
function toArray(iterable) {
return [].slice.call(iterable);
}
function isArray(arr) {
return arr && arr.constructor === Array;
}
function parseArithmeticExpression(cssValue, base, defaultVal) {
// Set base / 2 to default value, if it's undefined
var defaultValue = defaultVal != null ? defaultVal : base / 2;
var cssRegex = /(?:(\+|\-)\s*)?(\d+(?:\.\d+)?(%|px)?)/g;
if (typeof cssValue === "number") {
return clamp(cssValue, 0, base);
}
var idx = 0;
var calculatedValue = 0;
var matchResult = cssRegex.exec(cssValue);
while (matchResult != null) {
var sign = matchResult[1];
var value = matchResult[2];
var unit = matchResult[3];
var parsedValue = parseFloat(value);
if (idx <= 0) {
sign = sign || "+";
} // Return default value for values not in good form
if (!sign) {
return defaultValue;
}
if (unit === "%") {
parsedValue = parsedValue / 100 * base;
}
calculatedValue += sign === "+" ? parsedValue : -parsedValue; // Match next occurrence
++idx;
matchResult = cssRegex.exec(cssValue);
} // None-matched
if (idx === 0) {
return defaultValue;
} // Clamp between 0 ~ base
return clamp(calculatedValue, 0, base);
}
function getProgress(pos, range) {
// start, anchor, end
// -1 , 0 , 1
var min = range[0],
center = range[1],
max = range[2];
if (pos > center && max - center) {
// 0 ~ 1
return (pos - center) / (max - center);
} else if (pos < center && center - min) {
// -1 ~ 0
return (pos - center) / (center - min);
} else if (pos !== center && max - min) {
return (pos - min) / (max - min);
}
return 0;
}
function findIndex(iterable, callback) {
for (var i = 0; i < iterable.length; i += 1) {
var element = iterable[i];
if (element && callback(element)) {
return i;
}
}
return -1;
} // return [0, 1, ...., max - 1]
function counter(max) {
var counterArray = [];
for (var i = 0; i < max; i += 1) {
counterArray[i] = i;
}
return counterArray;
} // Circulate number between range [min, max]
/*
* "indexed" means min and max is not same, so if it's true "min - 1" should be max
* While if it's false, "min - 1" should be "max - 1"
* use `indexed: true` when it should be used for circulating integers like index
* or `indexed: false` when it should be used for something like positions.
*/
function circulate(value, min, max, indexed) {
var size = indexed ? max - min + 1 : max - min;
if (value < min) {
var offset = indexed ? (min - value - 1) % size : (min - value) % size;
value = max - offset;
} else if (value > max) {
var offset = indexed ? (value - max - 1) % size : (value - max) % size;
value = min + offset;
}
return value;
}
function restoreStyle(element, originalStyle) {
originalStyle.className ? element.setAttribute("class", originalStyle.className) : element.removeAttribute("class");
originalStyle.style ? element.setAttribute("style", originalStyle.style) : element.removeAttribute("style");
}
/**
* Decorator that makes the method of flicking available in the framework.
* @ko 프레임워크에서 플리킹의 메소드를 사용할 수 있게 하는 데코레이터.
* @memberof eg.Flicking
* @private
* @example
* ```js
* import Flicking, { withFlickingMethods } from "@egjs/flicking";
*
* class Flicking extends React.Component<Partial<FlickingProps & FlickingOptions>> {
* @withFlickingMethods
* private flicking: Flicking;
* }
* ```
*/
function withFlickingMethods(prototype, flickingName) {
Object.keys(FLICKING_METHODS).forEach(function (name) {
if (prototype[name]) {
return;
}
prototype[name] = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var result = (_a = this[flickingName])[name].apply(_a, args); // fix `this` type to return your own `flicking` instance to the instance using the decorator.
if (result === this[flickingName]) {
return this;
} else {
return result;
}
};
});
}
function getBbox(element, useOffset) {
var bbox;
if (useOffset) {
bbox = {
x: 0,
y: 0,
width: element.offsetWidth,
height: element.offsetHeight
};
} else {
var clientRect = element.getBoundingClientRect();
bbox = {
x: clientRect.left,
y: clientRect.top,
width: clientRect.width,
height: clientRect.height
};
}
return bbox;
}
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
var Panel =
/*#__PURE__*/
function () {
function Panel(element, index, viewport) {
this.viewport = viewport;
this.prevSibling = null;
this.nextSibling = null;
this.clonedPanels = [];
this.state = {
index: index,
position: 0,
relativeAnchorPosition: 0,
size: 0,
isClone: false,
isVirtual: false,
cloneIndex: -1,
originalStyle: {
className: "",
style: ""
},
cachedBbox: null
};
this.setElement(element);
}
var __proto = Panel.prototype;
__proto.resize = function (givenBbox) {
var state = this.state;
var options = this.viewport.options;
var bbox = givenBbox ? givenBbox : this.getBbox();
this.state.cachedBbox = bbox;
var prevSize = state.size;
state.size = options.horizontal ? bbox.width : bbox.height;
if (prevSize !== state.size) {
state.relativeAnchorPosition = parseArithmeticExpression(options.anchor, state.size);
}
if (!state.isClone) {
this.clonedPanels.forEach(function (panel) {
var cloneState = panel.state;
cloneState.size = state.size;
cloneState.cachedBbox = state.cachedBbox;
cloneState.relativeAnchorPosition = state.relativeAnchorPosition;
});
}
};
__proto.unCacheBbox = function () {
this.state.cachedBbox = null;
};
__proto.getProgress = function () {
var viewport = this.viewport;
var options = viewport.options;
var panelCount = viewport.panelManager.getPanelCount();
var scrollAreaSize = viewport.getScrollAreaSize();
var relativeIndex = (options.circular ? Math.floor(this.getPosition() / scrollAreaSize) * panelCount : 0) + this.getIndex();
var progress = relativeIndex - viewport.getCurrentProgress();
return progress;
};
__proto.getOutsetProgress = function () {
var viewport = this.viewport;
var outsetRange = [-this.getSize(), viewport.getRelativeHangerPosition() - this.getRelativeAnchorPosition(), viewport.getSize()];
var relativePanelPosition = this.getPosition() - viewport.getCameraPosition();
var outsetProgress = getProgress(relativePanelPosition, outsetRange);
return outsetProgress;
};
__proto.getVisibleRatio = function () {
var viewport = this.viewport;
var panelSize = this.getSize();
var relativePanelPosition = this.getPosition() - viewport.getCameraPosition();
var rightRelativePanelPosition = relativePanelPosition + panelSize;
var visibleSize = Math.min(viewport.getSize(), rightRelativePanelPosition) - Math.max(relativePanelPosition, 0);
var visibleRatio = visibleSize >= 0 ? visibleSize / panelSize : 0;
return visibleRatio;
};
__proto.focus = function (duration) {
var viewport = this.viewport;
var currentPanel = viewport.getCurrentPanel();
var hangerPosition = viewport.getHangerPosition();
var anchorPosition = this.getAnchorPosition();
if (hangerPosition === anchorPosition || !currentPanel) {
return;
}
var currentPosition = currentPanel.getPosition();
var eventType = currentPosition === this.getPosition() ? "" : EVENTS.CHANGE;
viewport.moveTo(this, viewport.findEstimatedPosition(this), eventType, null, duration);
};
__proto.update = function (updateFunction, shouldResize) {
if (updateFunction === void 0) {
updateFunction = null;
}
if (shouldResize === void 0) {
shouldResize = true;
}
var identicalPanels = this.getIdenticalPanels();
if (updateFunction) {
identicalPanels.forEach(function (eachPanel) {
updateFunction(eachPanel.getElement());
});
}
if (shouldResize) {
identicalPanels.forEach(function (eachPanel) {
eachPanel.unCacheBbox();
});
this.viewport.addVisiblePanel(this);
this.viewport.resize();
}
};
__proto.prev = function () {
var viewport = this.viewport;
var options = viewport.options;
var prevSibling = this.prevSibling;
if (!prevSibling) {
return null;
}
var currentIndex = this.getIndex();
var currentPosition = this.getPosition();
var prevPanelIndex = prevSibling.getIndex();
var prevPanelPosition = prevSibling.getPosition();
var prevPanelSize = prevSibling.getSize();
var hasEmptyPanelBetween = currentIndex - prevPanelIndex > 1;
var notYetMinPanel = options.infinite && currentIndex > 0 && prevPanelIndex > currentIndex;
if (hasEmptyPanelBetween || notYetMinPanel) {
// Empty panel exists between
return null;
}
var newPosition = currentPosition - prevPanelSize - options.gap;
var prevPanel = prevSibling;
if (prevPanelPosition !== newPosition) {
prevPanel = prevSibling.clone(prevSibling.getCloneIndex(), true);
prevPanel.setPosition(newPosition);
}
return prevPanel;
};
__proto.next = function () {
var viewport = this.viewport;
var options = viewport.options;
var nextSibling = this.nextSibling;
var lastIndex = viewport.panelManager.getLastIndex();
if (!nextSibling) {
return null;
}
var currentIndex = this.getIndex();
var currentPosition = this.getPosition();
var nextPanelIndex = nextSibling.getIndex();
var nextPanelPosition = nextSibling.getPosition();
var hasEmptyPanelBetween = nextPanelIndex - currentIndex > 1;
var notYetMaxPanel = options.infinite && currentIndex < lastIndex && nextPanelIndex < currentIndex;
if (hasEmptyPanelBetween || notYetMaxPanel) {
return null;
}
var newPosition = currentPosition + this.getSize() + options.gap;
var nextPanel = nextSibling;
if (nextPanelPosition !== newPosition) {
nextPanel = nextSibling.clone(nextSibling.getCloneIndex(), true);
nextPanel.setPosition(newPosition);
}
return nextPanel;
};
__proto.insertBefore = function (element) {
var viewport = this.viewport;
var parsedElements = parseElement(element);
var firstPanel = viewport.panelManager.firstPanel();
var prevSibling = this.prevSibling; // Finding correct inserting index
// While it should insert removing empty spaces,
// It also should have to be bigger than prevSibling' s index
var targetIndex = prevSibling && firstPanel.getIndex() !== this.getIndex() ? Math.max(prevSibling.getIndex() + 1, this.getIndex() - parsedElements.length) : Math.max(this.getIndex() - parsedElements.length, 0);
return viewport.insert(targetIndex, parsedElements);
};
__proto.insertAfter = function (element) {
return this.viewport.insert(this.getIndex() + 1, element);
};
__proto.remove = function () {
this.viewport.remove(this.getIndex());
return this;
};
__proto.destroy = function (option) {
if (!option.preserveUI) {
var originalStyle = this.state.originalStyle;
restoreStyle(this.element, originalStyle);
} // release resources
for (var x in this) {
this[x] = null;
}
};
__proto.getElement = function () {
return this.element;
};
__proto.getAnchorPosition = function () {
return this.state.position + this.state.relativeAnchorPosition;
};
__proto.getRelativeAnchorPosition = function () {
return this.state.relativeAnchorPosition;
};
__proto.getIndex = function () {
return this.state.index;
};
__proto.getPosition = function () {
return this.state.position;
};
__proto.getSize = function () {
return this.state.size;
};
__proto.getBbox = function () {
var state = this.state;
var viewport = this.viewport;
var element = this.element;
var options = viewport.options;
if (!element) {
state.cachedBbox = {
x: 0,
y: 0,
width: 0,
height: 0
};
} else if (!state.cachedBbox) {
var wasVisible = Boolean(element.parentNode);
var cameraElement = viewport.getCameraElement();
if (!wasVisible) {
cameraElement.appendChild(element);
viewport.addVisiblePanel(this);
}
state.cachedBbox = getBbox(element, options.useOffset);
if (!wasVisible && viewport.options.renderExternal) {
cameraElement.removeChild(element);
}
}
return state.cachedBbox;
};
__proto.isClone = function () {
return this.state.isClone;
};
__proto.getOverlappedClass = function (classes) {
var element = this.element;
for (var _i = 0, classes_1 = classes; _i < classes_1.length; _i++) {
var className = classes_1[_i];
if (hasClass(element, className)) {
return className;
}
}
};
__proto.getCloneIndex = function () {
return this.state.cloneIndex;
};
__proto.getClonedPanels = function () {
var state = this.state;
return state.isClone ? this.original.getClonedPanels() : this.clonedPanels;
};
__proto.getIdenticalPanels = function () {
var state = this.state;
return state.isClone ? this.original.getIdenticalPanels() : __spreadArrays([this], this.clonedPanels);
};
__proto.getOriginalPanel = function () {
return this.state.isClone ? this.original : this;
};
__proto.setIndex = function (index) {
var state = this.state;
state.index = index;
this.clonedPanels.forEach(function (panel) {
return panel.state.index = index;
});
};
__proto.setPosition = function (pos) {
this.state.position = pos;
return this;
};
__proto.setPositionCSS = function (offset) {
if (offset === void 0) {
offset = 0;
}
if (!this.element) {
return;
}
var state = this.state;
var pos = state.position;
var options = this.viewport.options;
var elementStyle = this.element.style;
var currentElementStyle = options.horizontal ? elementStyle.left : elementStyle.top;
var styleToApply = pos - offset + "px";
if (!state.isVirtual && currentElementStyle !== styleToApply) {
options.horizontal ? elementStyle.left = styleToApply : elementStyle.top = styleToApply;
}
};
__proto.clone = function (cloneIndex, isVirtual, element) {
if (isVirtual === void 0) {
isVirtual = false;
}
var state = this.state;
var viewport = this.viewport;
var cloneElement = element;
if (!cloneElement && this.element) {
cloneElement = isVirtual ? this.element : this.element.cloneNode(true);
}
var clonedPanel = new Panel(cloneElement, state.index, viewport);
var clonedState = clonedPanel.state;
clonedPanel.original = state.isClone ? this.original : this;
clonedState.isClone = true;
clonedState.isVirtual = isVirtual;
clonedState.cloneIndex = cloneIndex; // Inherit some state values
clonedState.size = state.size;
clonedState.relativeAnchorPosition = state.relativeAnchorPosition;
clonedState.originalStyle = state.originalStyle;
clonedState.cachedBbox = state.cachedBbox;
if (!isVirtual) {
this.clonedPanels.push(clonedPanel);
} else {
clonedPanel.prevSibling = this.prevSibling;
clonedPanel.nextSibling = this.nextSibling;
}
return clonedPanel;
};
__proto.removeElement = function () {
if (!this.viewport.options.renderExternal) {
var element = this.element;
element.parentNode && element.parentNode.removeChild(element);
} // Do the same thing for clones
if (!this.state.isClone) {
this.removeClonedPanelsAfter(0);
}
};
__proto.removeClonedPanelsAfter = function (start) {
var options = this.viewport.options;
var removingPanels = this.clonedPanels.splice(start);
if (!options.renderExternal) {
removingPanels.forEach(function (panel) {
panel.removeElement();
});
}
};
__proto.setElement = function (element) {
if (!element) {
return;
}
var currentElement = this.element;
if (element !== currentElement) {
var options = this.viewport.options;
if (currentElement) {
if (options.horizontal) {
element.style.left = currentElement.style.left;
} else {
element.style.top = currentElement.style.top;
}
} else {
var originalStyle = this.state.originalStyle;
originalStyle.className = element.getAttribute("class");
originalStyle.style = element.getAttribute("style");
}
this.element = element;
if (options.classPrefix) {
addClass(element, options.classPrefix + "-panel");
} // Update size info after applying panel css
applyCSS(this.element, DEFAULT_PANEL_CSS);
}
};
return Panel;
}();
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
var PanelManager =
/*#__PURE__*/
function () {
function PanelManager(cameraElement, options) {
this.cameraElement = cameraElement;
this.panels = [];
this.clones = [];
this.range = {
min: -1,
max: -1
};
this.length = 0;
this.cloneCount = 0;
this.options = options;
this.lastIndex = options.lastIndex;
}
var __proto = PanelManager.prototype;
__proto.firstPanel = function () {
return this.panels[this.range.min];
};
__proto.lastPanel = function () {
return this.panels[this.range.max];
};
__proto.allPanels = function () {
return __spreadArrays(this.panels, this.clones.reduce(function (allClones, clones) {
return __spreadArrays(allClones, clones);
}, []));
};
__proto.originalPanels = function () {
return this.panels;
};
__proto.clonedPanels = function () {
return this.clones;
};
__proto.replacePanels = function (newPanels, newClones) {
this.panels = newPanels;
this.clones = newClones;
this.range = {
min: findIndex(newPanels, function (panel) {
return Boolean(panel);
}),
max: newPanels.length - 1
};
this.length = newPanels.filter(function (panel) {
return Boolean(panel);
}).length;
};
__proto.has = function (index) {
return !!this.panels[index];
};
__proto.get = function (index) {
return this.panels[index];
};
__proto.getPanelCount = function () {
return this.length;
};
__proto.getLastIndex = function () {
return this.lastIndex;
};
__proto.getRange = function () {
return this.range;
};
__proto.getCloneCount = function () {
return this.cloneCount;
};
__proto.setLastIndex = function (lastIndex) {
this.lastIndex = lastIndex;
var firstPanel = this.firstPanel();
var lastPanel = this.lastPanel();
if (!firstPanel || !lastPanel) {
return; // no meaning of updating range & length
} // Remove panels above new last index
var range = this.range;
if (lastPanel.getIndex() > lastIndex) {
var removingPanels = this.panels.splice(lastIndex + 1);
this.length -= removingPanels.length;
var firstRemovedPanel = removingPanels.filter(function (panel) {
return !!panel;
})[0];
var possibleLastPanel = firstRemovedPanel.prevSibling;
if (possibleLastPanel) {
range.max = possibleLastPanel.getIndex();
} else {
range.min = -1;
range.max = -1;
}
if (this.shouldRender()) {
removingPanels.forEach(function (panel) {
return panel.removeElement();
});
}
}
};
__proto.setCloneCount = function (cloneCount) {
this.cloneCount = cloneCount;
}; // Insert at index
// Returns pushed elements from index, inserting at 'empty' position doesn't push elements behind it
__proto.insert = function (index, newPanels) {
var panels = this.panels;
var range = this.range;
var isCircular = this.options.circular;
var lastIndex = this.lastIndex; // Find first panel that index is greater than inserting index
var nextSibling = this.findFirstPanelFrom(index); // if it's null, element will be inserted at last position
// https://developer.mozilla.org/ko/docs/Web/API/Node/insertBefore#Syntax
var firstPanel = this.firstPanel();
var siblingElement = nextSibling ? nextSibling.getElement() : isCircular && firstPanel ? firstPanel.getClonedPanels()[0].getElement() : null; // Insert panels before sibling element
this.insertNewPanels(newPanels, siblingElement);
var pushedIndex = newPanels.length; // Like when setting index 50 while visible panels are 0, 1, 2
if (index > range.max) {
newPanels.forEach(function (panel, offset) {
panels[index + offset] = panel;
});
} else {
var panelsAfterIndex = panels.slice(index, index + newPanels.length); // Find empty from beginning
var emptyPanelCount = findIndex(panelsAfterIndex, function (panel) {
return !!panel;
});
if (emptyPanelCount < 0) {
// All empty
emptyPanelCount = panelsAfterIndex.length;
}
pushedIndex = newPanels.length - emptyPanelCount; // Insert removing empty panels
panels.splice.apply(panels, __spreadArrays([index, emptyPanelCount], newPanels)); // Remove panels after last index
if (panels.length > lastIndex + 1) {
var removedPanels = panels.splice(lastIndex + 1).filter(function (panel) {
return Boolean(panel);
});
this.length -= removedPanels.length; // Find first
var newLastIndex = lastIndex - findIndex(this.panels.concat().reverse(), function (panel) {
return !!panel;
}); // Can be filled with empty after newLastIndex
this.panels.splice(newLastIndex + 1);
this.range.max = newLastIndex;
if (this.shouldRender()) {
removedPanels.forEach(function (panel) {
return panel.removeElement();
});
}
}
} // Update index of previous panels
if (pushedIndex > 0) {
panels.slice(index + newPanels.length).forEach(function (panel) {
panel.setIndex(panel.getIndex() + pushedIndex);
});
} // Update state
this.length += newPanels.length;
this.updateIndex(index);
if (isCircular) {
this.addNewClones(index, newPanels, newPanels.length - pushedIndex, nextSibling);
var clones = this.clones;
var panelCount_1 = this.panels.length;
if (clones[0] && clones[0].length > lastIndex + 1) {
clones.forEach(function (cloneSet) {
cloneSet.splice(panelCount_1);
});
}
}
return pushedIndex;
};
__proto.replace = function (index, newPanels) {
var panels = this.panels;
var range = this.range;
var options = this.options;
var isCircular = options.circular; // Find first panel that index is greater than inserting index
var nextSibling = this.findFirstPanelFrom(index + newPanels.length); // if it's null, element will be inserted at last position
// https://developer.mozilla.org/ko/docs/Web/API/Node/insertBefore#Syntax
var firstPanel = this.firstPanel();
var siblingElement = nextSibling ? nextSibling.getElement() : isCircular && firstPanel ? firstPanel.getClonedPanels()[0].getElement() : null; // Insert panels before sibling element
this.insertNewPanels(newPanels, siblingElement);
if (index > range.max) {
// Temporarily insert null at index to use splice()
panels[index] = null;
}
var replacedPanels = panels.splice.apply(panels, __spreadArrays([index, newPanels.length], newPanels));
var wasNonEmptyCount = replacedPanels.filter(function (panel) {
return Boolean(panel);
}).length; // Suppose inserting [1, 2, 3] at 0 position when there were [empty, 1]
// So length should be increased by 3(inserting panels) - 1(non-empty panels)
this.length += newPanels.length - wasNonEmptyCount;
this.updateIndex(index);
if (isCircular) {
this.addNewClones(index, newPanels, newPanels.length, nextSibling);
}
if (this.shouldRender()) {
replacedPanels.forEach(function (panel) {
return panel && panel.removeElement();
});
}
return replacedPanels;
};
__proto.remove = function (index, deleteCount) {
if (deleteCount === void 0) {
deleteCount = 1;
}
var isCircular = this.options.circular;
var panels = this.panels;
var clones = this.clones; // Delete count should be equal or larger than 0
deleteCount = Math.max(deleteCount, 0);
var deletedPanels = panels.splice(index, deleteCount).filter(function (panel) {
return !!panel;
});
if (this.shouldRender()) {
deletedPanels.forEach(function (panel) {
return panel.removeElement();
});
}
if (isCircular) {
clones.forEach(function (cloneSet) {
cloneSet.splice(index, deleteCount);
});
} // Update indexes
panels.slice(index).forEach(function (panel) {
panel.setIndex(panel.getIndex() - deleteCount);
}); // Check last panel is empty
var lastIndex = panels.length - 1;
if (!panels[lastIndex]) {
var reversedPanels = panels.concat().reverse();
var nonEmptyIndexFromLast = findIndex(reversedPanels, function (panel) {
return !!panel;
});
lastIndex = nonEmptyIndexFromLast < 0 ? -1 // All empty
: lastIndex - nonEmptyIndexFromLast; // Remove all empty panels from last
panels.splice(lastIndex + 1);
if (isCircular) {
clones.forEach(function (cloneSet) {
cloneSet.splice(lastIndex + 1);
});
}
} // Update range & length
this.range = {
min: findIndex(panels, function (panel) {
return !!panel;
}),
max: lastIndex
};
this.length -= deletedPanels.length;
if (this.length <= 0) {
// Reset clones
this.clones = [];
this.cloneCount = 0;
}
return deletedPanels;
};
__proto.chainAllPanels = function () {
var allPanels = this.allPanels().filter(function (panel) {
return !!panel;
});
var allPanelsCount = allPanels.length;
if (allPanelsCount <= 1) {
return;
}
allPanels.slice(1, allPanels.length - 1).forEach(function (panel, idx) {
var prevPanel = allPanels[idx];
var nextPanel = allPanels[idx + 2];
panel.prevSibling = prevPanel;
panel.nextSibling = nextPanel;
});
var firstPanel = allPanels[0];
var lastPanel = allPanels[allPanelsCount - 1];
firstPanel.prevSibling = null;
firstPanel.nextSibling = allPanels[1];
lastPanel.prevSibling = allPanels[allPanelsCount - 2];
lastPanel.nextSibling = null;
if (this.options.circular) {
firstPanel.prevSibling = lastPanel;
lastPanel.nextSibling = firstPanel;
}
};
__proto.insertClones = function (cloneIndex, index, clonedPanels, deleteCount) {
if (deleteCount === void 0) {
deleteCount = 0;
}
var clones = this.clones;
var lastIndex = this.lastIndex;
if (!clones[cloneIndex]) {
var newClones_1 = [];
clonedPanels.forEach(function (panel, offset) {
newClones_1[index + offset] = panel;
});
clones[cloneIndex] = newClones_1;
} else {
var insertTarget_1 = clones[cloneIndex];
if (index >= insertTarget_1.length) {
clonedPanels.forEach(function (panel, offset) {
insertTarget_1[index + offset] = panel;
});
} else {
insertTarget_1.splice.apply(insertTarget_1, __spreadArrays([index, deleteCount], clonedPanels)); // Remove panels after last index
if (clonedPanels.length > lastIndex + 1) {
clonedPanels.splice(lastIndex + 1);
}
}
}
}; // clones are operating in set
__proto.removeClonesAfter = function (cloneIndex) {
var panels = this.panels;
panels.forEach(function (panel) {
panel.removeClonedPanelsAfter(cloneIndex);
});
this.clones.splice(cloneIndex);
};
__proto.findPanelOf = function (element) {
var allPanels = this.allPanels();
for (var _i = 0, allPanels_1 = allPanels; _i < allPanels_1.length; _i++) {
var panel = allPanels_1[_i];
if (!panel) {
continue;
}
var panelElement = panel.getElement();
if (panelElement.contains(element)) {
return panel;
}
}
};
__proto.findFirstPanelFrom = function (index) {
for (var _i = 0, _a = this.panels.slice(index); _i < _a.length; _i++) {
var panel = _a[_i];
if (panel && panel.getIndex() >= index && panel.getElement().parentNode) {
return panel;
}
}
};
__proto.addNewClones = function (index, originalPanels, deleteCount, nextSibling) {
var _this = this;
var cameraElement = this.cameraElement;
var cloneCount = this.getCloneCount();
var lastPanel = this.lastPanel();
var lastPanelClones = lastPanel ? lastPanel.getClonedPanels() : [];
var nextSiblingClones = nextSibling ? nextSibling.getClonedPanels() : [];
var _loop_1 = function (cloneIndex) {
var cloneNextSibling = nextSiblingClones[cloneIndex];
var lastPanelSibling = lastPanelClones[cloneIndex];
var cloneSiblingElement = cloneNextSibling ? cloneNextSibling.getElement() : lastPanelSibling ? lastPanelSibling.getElement().nextElementSibling : null;
var newClones = originalPanels.map(function (panel) {
var clone = panel.clone(cloneIndex);
if (_this.shouldRender()) {
cameraElement.insertBefore(clone.getElement(), cloneSiblingElement);
}
return clone;
});
this_1.insertClones(cloneIndex, index, newClones, deleteCount);
};
var this_1 = this;
for (var _i = 0, _a = counter(cloneCount); _i < _a.length; _i++) {
var cloneIndex = _a[_i];
_loop_1(cloneIndex);
}
};
__proto.updateIndex = function (insertingIndex) {
var panels = this.panels;
var range = this.range;
var newLastIndex = panels.length - 1;
if (newLastIndex > range.max) {
range.max = newLastIndex;
}
if (insertingIndex < range.min || range.min < 0) {
range.min = insertingIndex;
}
};
__proto.insertNewPanels = function (newPanels, siblingElement) {
if (this.shouldRender()) {
var fragment_1 = document.createDocumentFragment();
newPanels.forEach(function (panel) {
return fragment_1.appendChild(panel.getElement());
});
this.cameraElement.insertBefore(fragment_1, siblingElement);
}
};
__proto.shouldRender = function () {
var options = this.options;
return !options.renderExternal && !options.renderOnlyVisible;
};
return PanelManager;
}();
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
var State =
/*#__PURE__*/
function () {
function State() {
this.delta = 0;
this.direction = null;
this.targetPanel = null;
this.lastPosition = 0;
}
var __proto = State.prototype;
__proto.onEnter = function (prevState) {
this.delta = prevState.delta;
this.direction = prevState.direction;
this.targetPanel = prevState.targetPanel;
this.lastPosition = prevState.lastPosition;
};
__proto.onExit = function (nextState) {// DO NOTHING
};
__proto.onHold = function (e, context) {// DO NOTHING
};
__proto.onChange = function (e, context) {// DO NOTHING
};
__proto.onRelease = function (e, context) {// DO NOTHING
};
__proto.onAnimationEnd = function (e, context) {// DO NOTHING
};
__proto.onFinish = function (e, context) {// DO NOTHING
};
return State;
}();
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
var IdleState =
/*#__PURE__*/
function (_super) {
__extends(IdleState, _super);
function IdleState() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = STATE_TYPE.IDLE;
_this.holding = false;
_this.playing = false;
return _this;
}
var __proto = IdleState.prototype;
__proto.onEnter = function () {
this.direction = null;
this.targetPanel = null;
this.delta = 0;
this.lastPosition = 0;
};
__proto.onHold = function (e, _a) {
var flicking = _a.flicking,
viewport = _a.viewport,
triggerEvent = _a.triggerEvent,
transitTo = _a.transitTo; // Shouldn't do any action until any panels on flicking area
if (flicking.getPanelCount() <= 0) {
if (viewport.options.infinite) {
viewport.moveCamera(viewport.getCameraPosition(), e);
}
transitTo(STATE_TYPE.DISABLED);
return;
}
this.lastPosition = viewport.getCameraPosition();
triggerEvent(EVENTS.HOLD_START, e, true).onSuccess(function () {
transitTo(STATE_TYPE.HOLDING);
}).onStopped(function () {
transitTo(STATE_TYPE.DISABLED);
});
}; // By methods call
__proto.onChange = function (e, context) {
var triggerEvent = context.triggerEvent,
transitTo = context.transitTo;
triggerEvent(EVENTS.MOVE_START, e, false).onSuccess(function () {
// Trigger AnimatingState's onChange, to trigger "move" event immediately
transitTo(STATE_TYPE.ANIMATING).onChange(e, context);
}).onStopped(function () {
transitTo(STATE_TYPE.DISABLED);
});
};
return IdleState;
}(State);
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
var HoldingState =
/*#__PURE__*/
function (_super) {
__extends(HoldingState, _super);
function HoldingState() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = STATE_TYPE.HOLDING;
_this.holding = true;
_this.playing = true;
_this.releaseEvent = null;
return _this;
}
var __proto = HoldingState.prototype;
__proto.onChange = function (e, context) {
var flicking = context.flicking,
triggerEvent = context.triggerEvent,
transitTo = context.transitTo;
var offset = flicking.options.horizontal ? e.inputEvent.offsetX : e.inputEvent.offsetY;
this.direction = offset < 0 ? DIRECTION.NEXT : DIRECTION.PREV;
triggerEvent(EVENTS.MOVE_START, e, true).onSuccess(function () {
// Trigger DraggingState's onChange, to trigger "move" event immediately
transitTo(STATE_TYPE.DRAGGING).onChange(e, context);
}).onStopped(function () {
transitTo(STATE_TYPE.DISABLED);
});
};
__proto.onRelease = function (e, context) {
var viewport = context.viewport,
triggerEvent = context.triggerEvent,
transitTo = context.transitTo;
triggerEvent(EVENTS.HOLD_END, e, true);
if (e.delta.flick !== 0) {
// Sometimes "release" event on axes triggered before "change" event
// Especially if user flicked panel fast in really short amount of time
// if delta is not zero, that means above case happened.
// Event flow should be HOLD_START -> MOVE_START -> MOVE -> HOLD_END
// At least one move event should be included between holdStart and holdEnd
e.setTo({
flick: viewport.getCameraPosition()
}, 0);
transitTo(STATE_TYPE.IDLE);
return;
} // Can't handle select event here,
// As "finish" axes event happens
this.releaseEvent = e;
};
__proto.onFinish = function (e, _a) {
var viewport = _a.viewport,
triggerEvent = _a.triggerEvent,
transitTo = _a.transitTo; // Should transite to IDLE state before select event
// As user expects hold is already finished
transitTo(STATE_TYPE.IDLE);
if (!this.releaseEvent) {
return;
} // Handle release event here
// To prevent finish event called twice
var releaseEvent = this.releaseEvent; // Static click
var srcEvent = releaseEvent.inputEvent.srcEvent;
var clickedElement;
if (srcEvent.type === "touchend") {
var touchEvent = srcEvent;
var touch = touchEvent.changedTouches[0];
clickedElement = document.elementFromPoint(touch.clientX, touch.clientY);
} else {
clickedElement = srcEvent.target;
}
var clickedPanel = viewport.panelManager.findPanelOf(clickedElement);
var cameraPosition = viewport.getCameraPosition();
if (clickedPanel) {
var clickedPanelPosition = clickedPanel.getPosition();
var direction = clickedPanelPosition > cameraPosition ? DIRECTION.NEXT : clickedPanelPosition < cameraPosition ? DIRECTION.PREV : null; // Don't provide axes event, to use axes instance instead
triggerEvent(EVENTS.SELECT, null, true, {
direc