2020-08-06 21:15:16 +02:00
|
|
|
/* Cleaning this file properly is not neecessary, since it's an outdated library
|
|
|
|
* and will be replaced soon by a Vue component.
|
|
|
|
*/
|
|
|
|
|
2020-08-06 23:27:26 +02:00
|
|
|
import browser from 'browser';
|
2020-08-06 21:15:16 +02:00
|
|
|
import layoutManager from 'layoutManager';
|
|
|
|
import dom from 'dom';
|
|
|
|
import focusManager from 'focusManager';
|
|
|
|
import ResizeObserver from 'ResizeObserver';
|
|
|
|
import 'scrollStyles';
|
|
|
|
|
|
|
|
/**
|
2019-01-10 15:39:37 +03:00
|
|
|
* Return type of the value.
|
|
|
|
*
|
|
|
|
* @param {Mixed} value
|
|
|
|
*
|
|
|
|
* @return {String}
|
|
|
|
*/
|
2020-08-06 21:15:16 +02:00
|
|
|
function type(value) {
|
|
|
|
if (value == null) {
|
|
|
|
return String(value);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (typeof value === 'object' || typeof value === 'function') {
|
|
|
|
return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object';
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
return typeof value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disables an event it was triggered on and unbinds itself.
|
|
|
|
*
|
|
|
|
* @param {Event} event
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
function disableOneEvent(event) {
|
|
|
|
/*jshint validthis:true */
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
this.removeEventListener(event.type, disableOneEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make sure that number is within the limits.
|
|
|
|
*
|
|
|
|
* @param {Number} number
|
|
|
|
* @param {Number} min
|
|
|
|
* @param {Number} max
|
|
|
|
*
|
|
|
|
* @return {Number}
|
|
|
|
*/
|
|
|
|
function within(number, min, max) {
|
|
|
|
return number < min ? min : number > max ? max : number;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Other global values
|
2020-10-07 21:12:14 +09:00
|
|
|
const dragMouseEvents = ['mousemove', 'mouseup'];
|
|
|
|
const dragTouchEvents = ['touchmove', 'touchend'];
|
|
|
|
const wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
|
|
|
|
const interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA'];
|
2020-08-06 21:15:16 +02:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
const scrollerFactory = function (frame, options) {
|
2020-08-06 21:15:16 +02:00
|
|
|
// Extend options
|
2020-10-07 21:12:14 +09:00
|
|
|
const o = Object.assign({}, {
|
2020-08-06 21:15:16 +02:00
|
|
|
slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
|
|
|
|
horizontal: false, // Switch to horizontal mode.
|
|
|
|
|
|
|
|
// Scrolling
|
|
|
|
mouseWheel: true,
|
|
|
|
scrollBy: 0, // Pixels or items to move per one mouse scroll. 0 to disable scrolling
|
|
|
|
|
|
|
|
// Dragging
|
|
|
|
dragSource: null, // Selector or DOM element for catching dragging events. Default is FRAME.
|
|
|
|
mouseDragging: 1, // Enable navigation by dragging the SLIDEE with mouse cursor.
|
|
|
|
touchDragging: 1, // Enable navigation by dragging the SLIDEE with touch events.
|
|
|
|
dragThreshold: 3, // Distance in pixels before Sly recognizes dragging.
|
|
|
|
intervactive: null, // Selector for special interactive elements.
|
|
|
|
|
|
|
|
// Mixed options
|
|
|
|
speed: 0 // Animations speed in milliseconds. 0 to disable animations.
|
|
|
|
|
|
|
|
}, options);
|
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
const isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style;
|
2020-08-06 21:15:16 +02:00
|
|
|
|
|
|
|
// native scroll is a must with touch input
|
|
|
|
// also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment
|
|
|
|
// in cases with firefox, if the smooth scroll api is supported then use that because their implementation is very good
|
|
|
|
if (options.allowNativeScroll === false) {
|
|
|
|
options.enableNativeScroll = false;
|
|
|
|
} else if (isSmoothScrollSupported && ((browser.firefox && !layoutManager.tv) || options.allowNativeSmoothScroll)) {
|
|
|
|
// native smooth scroll
|
|
|
|
options.enableNativeScroll = true;
|
|
|
|
} else if (options.requireAnimation && (browser.animate || browser.supportsCssAnimation())) {
|
|
|
|
// transform is the only way to guarantee animation
|
|
|
|
options.enableNativeScroll = false;
|
|
|
|
} else if (!layoutManager.tv || !browser.animate) {
|
|
|
|
options.enableNativeScroll = true;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Need this for the magic wheel. With the animated scroll the magic wheel will run off of the screen
|
|
|
|
if (browser.web0s) {
|
|
|
|
options.enableNativeScroll = true;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Private variables
|
2020-10-07 21:12:14 +09:00
|
|
|
const self = this;
|
2020-08-06 21:15:16 +02:00
|
|
|
self.options = o;
|
|
|
|
|
|
|
|
// Frame
|
2020-10-07 21:12:14 +09:00
|
|
|
const slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0];
|
2020-08-06 21:15:16 +02:00
|
|
|
self._pos = {
|
|
|
|
start: 0,
|
|
|
|
center: 0,
|
|
|
|
end: 0,
|
|
|
|
cur: 0,
|
|
|
|
dest: 0
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
const transform = !options.enableNativeScroll;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Miscellaneous
|
2020-10-07 21:12:14 +09:00
|
|
|
const scrollSource = frame;
|
|
|
|
const dragSourceElement = o.dragSource ? o.dragSource : frame;
|
|
|
|
const dragging = {
|
2020-08-06 21:15:16 +02:00
|
|
|
released: 1
|
|
|
|
};
|
2020-10-07 21:12:14 +09:00
|
|
|
const scrolling = {
|
2020-08-06 21:15:16 +02:00
|
|
|
last: 0,
|
|
|
|
delta: 0,
|
|
|
|
resetTime: 200
|
|
|
|
};
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Expose properties
|
|
|
|
self.initialized = 0;
|
|
|
|
self.slidee = slideeElement;
|
|
|
|
self.options = o;
|
|
|
|
self.dragging = dragging;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
const nativeScrollElement = frame;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function sibling(n, elem) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const matched = [];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
for (; n; n = n.nextSibling) {
|
|
|
|
if (n.nodeType === 1 && n !== elem) {
|
|
|
|
matched.push(n);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
return matched;
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
let requiresReflow = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
let frameSize = 0;
|
|
|
|
let slideeSize = 0;
|
2020-08-06 21:15:16 +02:00
|
|
|
function ensureSizeInfo() {
|
|
|
|
if (requiresReflow) {
|
|
|
|
requiresReflow = false;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Reset global variables
|
|
|
|
frameSize = o.horizontal ? (frame).offsetWidth : (frame).offsetHeight;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? 'offsetWidth' : 'offsetHeight'], slideeElement[o.horizontal ? 'scrollWidth' : 'scrollHeight']);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Set position limits & relativess
|
|
|
|
self._pos.end = Math.max(slideeSize - frameSize, 0);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Loading function.
|
|
|
|
*
|
|
|
|
* Populate arrays, set sizes, bind events, ...
|
|
|
|
*
|
|
|
|
* @param {Boolean} [isInit] Whether load is called from within self.init().
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
function load(isInit) {
|
|
|
|
requiresReflow = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (!isInit) {
|
|
|
|
ensureSizeInfo();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Fix possible overflowing
|
2020-10-07 21:12:14 +09:00
|
|
|
const pos = self._pos;
|
2020-08-06 21:15:16 +02:00
|
|
|
self.slideTo(within(pos.dest, pos.start, pos.end));
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function initFrameResizeObserver() {
|
2020-10-07 21:12:14 +09:00
|
|
|
const observerOptions = {};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.frameResizeObserver = new ResizeObserver(onResize, observerOptions);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.frameResizeObserver.observe(frame);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.reload = function () {
|
|
|
|
load();
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.getScrollEventName = function () {
|
|
|
|
return transform ? 'scrollanimate' : 'scroll';
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.getScrollSlider = function () {
|
|
|
|
return slideeElement;
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.getScrollFrame = function () {
|
|
|
|
return frame;
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function nativeScrollTo(container, pos, immediate) {
|
|
|
|
if (container.scroll) {
|
|
|
|
if (o.horizontal) {
|
|
|
|
container.scroll({
|
|
|
|
left: pos,
|
|
|
|
behavior: immediate ? 'instant' : 'smooth'
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-06 21:15:16 +02:00
|
|
|
container.scroll({
|
|
|
|
top: pos,
|
|
|
|
behavior: immediate ? 'instant' : 'smooth'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else if (!immediate && container.scrollTo) {
|
|
|
|
if (o.horizontal) {
|
2020-08-06 22:25:14 +02:00
|
|
|
container.scrollTo(Math.round(pos), 0);
|
2020-08-06 21:15:16 +02:00
|
|
|
} else {
|
2020-08-06 22:25:14 +02:00
|
|
|
container.scrollTo(0, Math.round(pos));
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (o.horizontal) {
|
2020-08-06 22:25:14 +02:00
|
|
|
container.scrollLeft = Math.round(pos);
|
2020-08-06 21:15:16 +02:00
|
|
|
} else {
|
2020-08-06 22:25:14 +02:00
|
|
|
container.scrollTop = Math.round(pos);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
let lastAnimate;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Animate to a position.
|
|
|
|
*
|
|
|
|
* @param {Int} newPos New position.
|
|
|
|
* @param {Bool} immediate Reposition immediately without an animation.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
self.slideTo = function (newPos, immediate, fullItemPos) {
|
|
|
|
ensureSizeInfo();
|
2020-10-07 21:12:14 +09:00
|
|
|
const pos = self._pos;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-26 19:53:11 +02:00
|
|
|
if (layoutManager.tv) {
|
|
|
|
newPos = within(newPos, pos.start);
|
|
|
|
} else {
|
|
|
|
newPos = within(newPos, pos.start, pos.end);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (!transform) {
|
|
|
|
nativeScrollTo(nativeScrollElement, newPos, immediate);
|
|
|
|
return;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Update the animation object
|
2020-10-07 21:12:14 +09:00
|
|
|
const from = pos.cur;
|
2020-08-06 21:15:16 +02:00
|
|
|
immediate = immediate || dragging.init || !o.speed;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
const now = new Date().getTime();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.autoImmediate) {
|
|
|
|
if (!immediate && (now - (lastAnimate || 0)) <= 50) {
|
|
|
|
immediate = true;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (!immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Start animation rendering
|
|
|
|
// NOTE the dependency was modified here to fix a scrollbutton issue
|
|
|
|
pos.dest = newPos;
|
|
|
|
renderAnimateWithTransform(from, newPos, immediate);
|
|
|
|
lastAnimate = now;
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function setStyleProperty(elem, name, value, speed, resetTransition) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const style = elem.style;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (resetTransition || browser.edge) {
|
|
|
|
style.transition = 'none';
|
|
|
|
void elem.offsetWidth;
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
style.transition = 'transform ' + speed + 'ms ease-out';
|
|
|
|
style[name] = value;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function dispatchScrollEventIfNeeded() {
|
|
|
|
if (o.dispatchScrollEvent) {
|
|
|
|
frame.dispatchEvent(new CustomEvent(self.getScrollEventName(), {
|
|
|
|
bubbles: true,
|
|
|
|
cancelable: false
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderAnimateWithTransform(fromPosition, toPosition, immediate) {
|
2020-10-07 21:12:14 +09:00
|
|
|
let speed = o.speed;
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (immediate) {
|
|
|
|
speed = o.immediateSpeed || 50;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.horizontal) {
|
|
|
|
setStyleProperty(slideeElement, 'transform', 'translateX(' + (-Math.round(toPosition)) + 'px)', speed);
|
|
|
|
} else {
|
|
|
|
setStyleProperty(slideeElement, 'transform', 'translateY(' + (-Math.round(toPosition)) + 'px)', speed);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
self._pos.cur = toPosition;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dispatchScrollEventIfNeeded();
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function getBoundingClientRect(elem) {
|
|
|
|
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
|
|
|
// If we don't have gBCR, just use 0,0 rather than error
|
|
|
|
if (elem.getBoundingClientRect) {
|
|
|
|
return elem.getBoundingClientRect();
|
|
|
|
} else {
|
|
|
|
return { top: 0, left: 0 };
|
|
|
|
}
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Returns the position object.
|
|
|
|
*
|
|
|
|
* @param {Mixed} item
|
|
|
|
*
|
|
|
|
* @return {Object}
|
|
|
|
*/
|
|
|
|
self.getPos = function (item) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const scrollElement = transform ? slideeElement : nativeScrollElement;
|
|
|
|
const slideeOffset = getBoundingClientRect(scrollElement);
|
|
|
|
const itemOffset = getBoundingClientRect(item);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
let offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
let size = o.horizontal ? itemOffset.width : itemOffset.height;
|
2020-08-06 21:15:16 +02:00
|
|
|
if (!size && size !== 0) {
|
|
|
|
size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight'];
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
let centerOffset = o.centerOffset || 0;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (!transform) {
|
|
|
|
centerOffset = 0;
|
|
|
|
if (o.horizontal) {
|
|
|
|
offset += nativeScrollElement.scrollLeft;
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-06 21:15:16 +02:00
|
|
|
offset += nativeScrollElement.scrollTop;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
ensureSizeInfo();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
const currentStart = self._pos.cur;
|
|
|
|
const currentEnd = currentStart + frameSize;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd);
|
2020-10-07 21:12:14 +09:00
|
|
|
const isVisible = offset >= currentStart && (offset + size) <= currentEnd;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
return {
|
|
|
|
start: offset,
|
|
|
|
center: offset + centerOffset - (frameSize / 2) + (size / 2),
|
|
|
|
end: offset - frameSize + size,
|
|
|
|
size: size,
|
|
|
|
isVisible: isVisible
|
2019-01-10 15:39:37 +03:00
|
|
|
};
|
2020-08-06 21:15:16 +02:00
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.getCenterPosition = function (item) {
|
|
|
|
ensureSizeInfo();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
const pos = self.getPos(item);
|
2020-08-06 21:15:16 +02:00
|
|
|
return within(pos.center, pos.start, pos.end);
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function dragInitSlidee(event) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const isTouch = event.type === 'touchstart';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Ignore when already in progress, or interactive element in non-touch navivagion
|
|
|
|
if (dragging.init || !isTouch && isInteractive(event.target)) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// SLIDEE dragging conditions
|
|
|
|
if (!(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (!isTouch) {
|
|
|
|
// prevents native image dragging in Firefox
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Reset dragging object
|
|
|
|
dragging.released = 0;
|
|
|
|
|
|
|
|
// Properties used in dragHandler
|
|
|
|
dragging.init = 0;
|
|
|
|
dragging.source = event.target;
|
|
|
|
dragging.touch = isTouch;
|
2020-10-07 21:12:14 +09:00
|
|
|
const pointer = isTouch ? event.touches[0] : event;
|
2020-08-06 21:15:16 +02:00
|
|
|
dragging.initX = pointer.pageX;
|
|
|
|
dragging.initY = pointer.pageY;
|
|
|
|
dragging.initPos = self._pos.cur;
|
|
|
|
dragging.start = +new Date();
|
|
|
|
dragging.time = 0;
|
|
|
|
dragging.path = 0;
|
|
|
|
dragging.delta = 0;
|
|
|
|
dragging.locked = 0;
|
|
|
|
dragging.pathToLock = isTouch ? 30 : 10;
|
|
|
|
|
|
|
|
// Bind dragging events
|
|
|
|
if (transform) {
|
|
|
|
if (isTouch) {
|
|
|
|
dragTouchEvents.forEach(function (eventName) {
|
|
|
|
dom.addEventListener(document, eventName, dragHandler, {
|
|
|
|
passive: true
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
2020-08-06 21:15:16 +02:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
dragMouseEvents.forEach(function (eventName) {
|
|
|
|
dom.addEventListener(document, eventName, dragHandler, {
|
|
|
|
passive: true
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
2020-08-06 21:15:16 +02:00
|
|
|
});
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Handler for dragging scrollbar handle or SLIDEE.
|
|
|
|
*
|
|
|
|
* @param {Event} event
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
function dragHandler(event) {
|
|
|
|
dragging.released = event.type === 'mouseup' || event.type === 'touchend';
|
2020-10-07 21:12:14 +09:00
|
|
|
const pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event;
|
2020-08-06 21:15:16 +02:00
|
|
|
dragging.pathX = pointer.pageX - dragging.initX;
|
|
|
|
dragging.pathY = pointer.pageY - dragging.initY;
|
|
|
|
dragging.path = Math.sqrt(Math.pow(dragging.pathX, 2) + Math.pow(dragging.pathY, 2));
|
|
|
|
dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY;
|
|
|
|
|
|
|
|
if (!dragging.released && dragging.path < 1) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// We haven't decided whether this is a drag or not...
|
|
|
|
if (!dragging.init) {
|
|
|
|
// If the drag path was very short, maybe it's not a drag?
|
|
|
|
if (dragging.path < o.dragThreshold) {
|
|
|
|
// If the pointer was released, the path will not become longer and it's
|
|
|
|
// definitely not a drag. If not released yet, decide on next iteration
|
|
|
|
return dragging.released ? dragEnd() : undefined;
|
|
|
|
} else {
|
|
|
|
// If dragging path is sufficiently long we can confidently start a drag
|
|
|
|
// if drag is in different direction than scroll, ignore it
|
|
|
|
if (o.horizontal ? Math.abs(dragging.pathX) > Math.abs(dragging.pathY) : Math.abs(dragging.pathX) < Math.abs(dragging.pathY)) {
|
|
|
|
dragging.init = 1;
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-06 21:15:16 +02:00
|
|
|
return dragEnd();
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
//event.preventDefault();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Disable click on a source element, as it is unwelcome when dragging
|
|
|
|
if (!dragging.locked && dragging.path > dragging.pathToLock) {
|
|
|
|
dragging.locked = 1;
|
|
|
|
dragging.source.addEventListener('click', disableOneEvent);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Cancel dragging on release
|
|
|
|
if (dragging.released) {
|
|
|
|
dragEnd();
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.slideTo(Math.round(dragging.initPos - dragging.delta));
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Stops dragging and cleans up after it.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
function dragEnd() {
|
|
|
|
dragging.released = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dragTouchEvents.forEach(function (eventName) {
|
|
|
|
dom.removeEventListener(document, eventName, dragHandler, {
|
|
|
|
passive: true
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
2020-08-06 21:15:16 +02:00
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dragMouseEvents.forEach(function (eventName) {
|
|
|
|
dom.removeEventListener(document, eventName, dragHandler, {
|
|
|
|
passive: true
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
2020-08-06 21:15:16 +02:00
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Make sure that disableOneEvent is not active in next tick.
|
|
|
|
setTimeout(function () {
|
|
|
|
dragging.source.removeEventListener('click', disableOneEvent);
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dragging.init = 0;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Check whether element is interactive.
|
|
|
|
*
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
|
|
|
function isInteractive(element) {
|
|
|
|
while (element) {
|
|
|
|
if (interactiveElements.indexOf(element.tagName) !== -1) {
|
|
|
|
return true;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
element = element.parentNode;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Mouse wheel delta normalization.
|
|
|
|
*
|
|
|
|
* @param {Event} event
|
|
|
|
*
|
|
|
|
* @return {Int}
|
|
|
|
*/
|
|
|
|
function normalizeWheelDelta(event) {
|
|
|
|
// JELLYFIN MOD: Only use deltaX for horizontal scroll and remove IE8 support
|
|
|
|
scrolling.curDelta = o.horizontal ? event.deltaX : event.deltaY;
|
|
|
|
// END JELLYFIN MOD
|
|
|
|
|
|
|
|
if (transform) {
|
|
|
|
scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
return scrolling.curDelta;
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Mouse scrolling handler.
|
|
|
|
*
|
|
|
|
* @param {Event} event
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
function scrollHandler(event) {
|
|
|
|
ensureSizeInfo();
|
2020-10-07 21:12:14 +09:00
|
|
|
const pos = self._pos;
|
2020-08-06 21:15:16 +02:00
|
|
|
// Ignore if there is no scrolling to be done
|
|
|
|
if (!o.scrollBy || pos.start === pos.end) {
|
|
|
|
return;
|
|
|
|
}
|
2020-10-07 21:12:14 +09:00
|
|
|
let delta = normalizeWheelDelta(event);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (transform) {
|
|
|
|
// Trap scrolling only when necessary and/or requested
|
|
|
|
if (delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) {
|
|
|
|
//stopDefault(event, 1);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.slideBy(o.scrollBy * delta);
|
|
|
|
} else {
|
|
|
|
if (isSmoothScrollSupported) {
|
|
|
|
delta *= 12;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.horizontal) {
|
|
|
|
nativeScrollElement.scrollLeft += delta;
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-06 21:15:16 +02:00
|
|
|
nativeScrollElement.scrollTop += delta;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Destroys instance and everything it created.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
self.destroy = function () {
|
|
|
|
if (self.frameResizeObserver) {
|
|
|
|
self.frameResizeObserver.disconnect();
|
|
|
|
self.frameResizeObserver = null;
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Reset native FRAME element scroll
|
|
|
|
dom.removeEventListener(frame, 'scroll', resetScroll, {
|
|
|
|
passive: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dom.removeEventListener(scrollSource, wheelEvent, scrollHandler, {
|
|
|
|
passive: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dom.removeEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
|
|
|
|
passive: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dom.removeEventListener(frame, 'click', onFrameClick, {
|
|
|
|
passive: true,
|
|
|
|
capture: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dom.removeEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
|
|
|
|
//passive: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Reset initialized status and return the instance
|
|
|
|
self.initialized = 0;
|
|
|
|
return self;
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-10-07 21:12:14 +09:00
|
|
|
let contentRect = {};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function onResize(entries) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const entry = entries[0];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (entry) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const newRect = entry.contentRect;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// handle element being hidden
|
|
|
|
if (newRect.width === 0 || newRect.height === 0) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (newRect.width !== contentRect.width || newRect.height !== contentRect.height) {
|
|
|
|
contentRect = newRect;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
load(false);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function resetScroll() {
|
|
|
|
if (o.horizontal) {
|
|
|
|
this.scrollLeft = 0;
|
|
|
|
} else {
|
|
|
|
this.scrollTop = 0;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
function onFrameClick(e) {
|
|
|
|
if (e.which === 1) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const focusableParent = focusManager.focusableParent(e.target);
|
2020-08-06 21:15:16 +02:00
|
|
|
if (focusableParent && focusableParent !== document.activeElement) {
|
|
|
|
focusableParent.focus();
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.getScrollPosition = function () {
|
|
|
|
if (transform) {
|
|
|
|
return self._pos.cur;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.horizontal) {
|
|
|
|
return nativeScrollElement.scrollLeft;
|
|
|
|
} else {
|
|
|
|
return nativeScrollElement.scrollTop;
|
|
|
|
}
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
self.getScrollSize = function () {
|
|
|
|
if (transform) {
|
|
|
|
return slideeSize;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.horizontal) {
|
|
|
|
return nativeScrollElement.scrollWidth;
|
|
|
|
} else {
|
|
|
|
return nativeScrollElement.scrollHeight;
|
|
|
|
}
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
/**
|
|
|
|
* Initialize.
|
|
|
|
*
|
|
|
|
* @return {Object}
|
|
|
|
*/
|
|
|
|
self.init = function () {
|
|
|
|
if (self.initialized) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (!transform) {
|
2019-01-10 15:39:37 +03:00
|
|
|
if (o.horizontal) {
|
2020-08-06 21:15:16 +02:00
|
|
|
if (layoutManager.desktop && !o.hideScrollbar) {
|
|
|
|
nativeScrollElement.classList.add('scrollX');
|
|
|
|
} else {
|
|
|
|
nativeScrollElement.classList.add('scrollX');
|
|
|
|
nativeScrollElement.classList.add('hiddenScrollX');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
|
|
|
|
nativeScrollElement.classList.add('smoothScrollX');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.forceHideScrollbars) {
|
|
|
|
nativeScrollElement.classList.add('hiddenScrollX-forced');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (layoutManager.desktop && !o.hideScrollbar) {
|
|
|
|
nativeScrollElement.classList.add('scrollY');
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-06 21:15:16 +02:00
|
|
|
nativeScrollElement.classList.add('scrollY');
|
|
|
|
nativeScrollElement.classList.add('hiddenScrollY');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
|
|
|
|
nativeScrollElement.classList.add('smoothScrollY');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.forceHideScrollbars) {
|
|
|
|
nativeScrollElement.classList.add('hiddenScrollY-forced');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
} else {
|
|
|
|
frame.style.overflow = 'hidden';
|
|
|
|
slideeElement.style['will-change'] = 'transform';
|
|
|
|
slideeElement.style.transition = 'transform ' + o.speed + 'ms ease-out';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.horizontal) {
|
|
|
|
slideeElement.classList.add('animatedScrollX');
|
|
|
|
} else {
|
|
|
|
slideeElement.classList.add('animatedScrollY');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-06 21:15:16 +02:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (transform || layoutManager.tv) {
|
|
|
|
// This can prevent others from being able to listen to mouse events
|
|
|
|
dom.addEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
|
|
|
|
//passive: true
|
|
|
|
});
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
initFrameResizeObserver();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (transform) {
|
|
|
|
dom.addEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
|
|
|
|
passive: true
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!o.horizontal) {
|
|
|
|
dom.addEventListener(frame, 'scroll', resetScroll, {
|
2019-01-10 15:39:37 +03:00
|
|
|
passive: true
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.mouseWheel) {
|
|
|
|
// Scrolling navigation
|
|
|
|
dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
|
|
|
|
passive: true
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else if (o.horizontal) {
|
|
|
|
// Don't bind to mouse events with vertical scroll since the mouse wheel can handle this natively
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (o.mouseWheel) {
|
|
|
|
// Scrolling navigation
|
|
|
|
dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
|
|
|
|
passive: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
dom.addEventListener(frame, 'click', onFrameClick, {
|
|
|
|
passive: true,
|
|
|
|
capture: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Mark instance as initialized
|
|
|
|
self.initialized = 1;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Load
|
|
|
|
load(true);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
// Return instance
|
|
|
|
return self;
|
2019-01-10 15:39:37 +03:00
|
|
|
};
|
2020-08-06 21:15:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Slide SLIDEE by amount of pixels.
|
|
|
|
*
|
|
|
|
* @param {Int} delta Pixels/Items. Positive means forward, negative means backward.
|
|
|
|
* @param {Bool} immediate Reposition immediately without an animation.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
scrollerFactory.prototype.slideBy = function (delta, immediate) {
|
|
|
|
if (!delta) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.slideTo(this._pos.dest + delta, immediate);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Core method for handling `toLocation` methods.
|
|
|
|
*
|
|
|
|
* @param {String} location
|
|
|
|
* @param {Mixed} item
|
|
|
|
* @param {Bool} immediate
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
scrollerFactory.prototype.to = function (location, item, immediate) {
|
|
|
|
// Optional arguments logic
|
|
|
|
if (type(item) === 'boolean') {
|
|
|
|
immediate = item;
|
|
|
|
item = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item === undefined) {
|
|
|
|
this.slideTo(this._pos[location], immediate);
|
|
|
|
} else {
|
2020-10-07 21:12:14 +09:00
|
|
|
const itemPos = this.getPos(item);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-06 21:15:16 +02:00
|
|
|
if (itemPos) {
|
|
|
|
this.slideTo(itemPos[location], immediate, itemPos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Animate element or the whole SLIDEE to the start of the frame.
|
|
|
|
*
|
|
|
|
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
|
|
|
|
* @param {Bool} immediate Reposition immediately without an animation.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
scrollerFactory.prototype.toStart = function (item, immediate) {
|
|
|
|
this.to('start', item, immediate);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Animate element or the whole SLIDEE to the end of the frame.
|
|
|
|
*
|
|
|
|
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
|
|
|
|
* @param {Bool} immediate Reposition immediately without an animation.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
scrollerFactory.prototype.toEnd = function (item, immediate) {
|
|
|
|
this.to('end', item, immediate);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Animate element or the whole SLIDEE to the center of the frame.
|
|
|
|
*
|
|
|
|
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
|
|
|
|
* @param {Bool} immediate Reposition immediately without an animation.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
|
|
|
scrollerFactory.prototype.toCenter = function (item, immediate) {
|
|
|
|
this.to('center', item, immediate);
|
|
|
|
};
|
|
|
|
|
|
|
|
scrollerFactory.create = function (frame, options) {
|
2020-10-07 21:12:14 +09:00
|
|
|
const instance = new scrollerFactory(frame, options);
|
2020-08-06 21:15:16 +02:00
|
|
|
return Promise.resolve(instance);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default scrollerFactory;
|