vscroll
Version:
Virtual scroll engine
161 lines • 5.04 kB
JavaScript
import { Direction } from '../inputs/index';
export class Routines {
constructor(element, settings) {
this.element = element;
this.settings = {
viewport: settings.viewport,
horizontal: settings.horizontal,
window: settings.windowViewport
};
// initialization
this.viewport = this.getViewportElement();
this.onInit(settings);
}
checkElement(element) {
if (!element) {
throw new Error('HTML element is not defined');
}
}
getViewportElement() {
if (this.settings.window) {
return document.documentElement;
}
if (this.settings.viewport) {
return this.settings.viewport;
}
this.checkElement(this.element);
const parent = this.element.parentElement;
this.checkElement(parent);
return parent;
}
onInit(settings) {
if (settings.windowViewport) {
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
}
if (settings.dismissOverflowAnchor) {
this.viewport.style.overflowAnchor = 'none';
}
}
findElementBySelector(element, selector) {
this.checkElement(element);
return element.querySelector(selector);
}
findPaddingElement(direction) {
return this.findElementBySelector(this.element, `[data-padding-${direction}]`);
}
findItemElement(id) {
return this.findElementBySelector(this.element, `[data-sid="${id}"]`);
}
findItemChildBySelector(id, selector) {
return this.findElementBySelector(this.element, `[data-sid="${id}"] ${selector}`);
}
getScrollPosition() {
if (this.settings.window) {
return this.settings.horizontal ? window.pageXOffset : window.pageYOffset;
}
return this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'];
}
setScrollPosition(value) {
value = Math.max(0, value);
if (this.settings.window) {
if (this.settings.horizontal) {
window.scrollTo(value, window.scrollY);
}
else {
window.scrollTo(window.scrollX, value);
}
return;
}
this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'] = value;
}
getElementParams(element) {
this.checkElement(element);
return element.getBoundingClientRect();
}
getWindowParams() {
const height = window.innerHeight;
const width = window.innerWidth;
return {
height: height,
width: width,
top: 0,
bottom: height,
left: 0,
right: width,
x: 0,
y: 0,
toJSON: () => null
};
}
getSize(element) {
return this.getElementParams(element)[this.settings.horizontal ? 'width' : 'height'];
}
getScrollerSize() {
return this.getElementParams(this.element)[this.settings.horizontal ? 'width' : 'height'];
}
getViewportSize() {
if (this.settings.window) {
return this.getWindowParams()[this.settings.horizontal ? 'width' : 'height'];
}
return this.getSize(this.viewport);
}
getSizeStyle(element) {
this.checkElement(element);
const size = element.style[this.settings.horizontal ? 'width' : 'height'];
return parseFloat(size) || 0;
}
setSizeStyle(element, value) {
this.checkElement(element);
value = Math.max(0, Math.round(value));
element.style[this.settings.horizontal ? 'width' : 'height'] = `${value}px`;
}
getEdge(element, direction) {
const { horizontal } = this.settings;
const params = this.getElementParams(element);
const isFwd = direction === Direction.forward;
return params[isFwd ? (horizontal ? 'right' : 'bottom') : horizontal ? 'left' : 'top'];
}
getViewportEdge(direction) {
const { window, horizontal } = this.settings;
if (window) {
const params = this.getWindowParams();
const isFwd = direction === Direction.forward;
return params[isFwd ? (horizontal ? 'right' : 'bottom') : horizontal ? 'left' : 'top'];
}
return this.getEdge(this.viewport, direction);
}
makeElementVisible(element) {
this.checkElement(element);
element.style.left = '';
element.style.top = '';
element.style.position = '';
}
hideElement(element) {
this.checkElement(element);
element.style.display = 'none';
}
getOffset() {
const get = (element) => (this.settings.horizontal ? element.offsetLeft : element.offsetTop) || 0;
return get(this.element) - (!this.settings.window ? get(this.viewport) : 0);
}
scrollTo(element, argument) {
this.checkElement(element);
element.scrollIntoView(argument);
}
render(cb, _params) {
const timeoutId = setTimeout(() => cb());
return () => clearTimeout(timeoutId);
}
animate(cb) {
const animationFrameId = requestAnimationFrame(() => cb());
return () => cancelAnimationFrame(animationFrameId);
}
onScroll(handler) {
const eventReceiver = this.settings.window ? window : this.viewport;
eventReceiver.addEventListener('scroll', handler);
return () => eventReceiver.removeEventListener('scroll', handler);
}
}
//# sourceMappingURL=domRoutines.js.map