jellyfish-web/src/libraries/navdrawer/navdrawer.js

381 lines
11 KiB
JavaScript
Raw Normal View History

/**
* NOTE: This file should not be modified.
* It is a legacy library that should be replaced at some point.
2020-08-06 20:59:14 +02:00
*/
2020-08-14 08:46:34 +02:00
import browser from '../../scripts/browser';
import dom from '../../scripts/dom';
2021-01-26 15:43:40 -05:00
import './navdrawer.scss';
import '../../styles/scrollstyles.scss';
import globalize from '../../scripts/globalize';
2022-04-11 00:47:22 +03:00
function getTouches(e) {
return e.changedTouches || e.targetTouches || e.touches;
}
function disableEvent(e) {
e.preventDefault();
e.stopPropagation();
}
class NavDrawer {
2022-04-09 03:58:07 +03:00
mask;
newPos = 0;
currentPos = 0;
startPoint = 0;
countStart = 0;
velocity = 0;
dragMode = 0;
menuTouchStartX;
menuTouchStartY;
menuTouchStartTime;
edgeContainer = document.querySelector('.mainDrawerHandle');
isPeeking = false;
backgroundTouchStartX;
backgroundTouchStartTime;
_edgeSwipeEnabled;
constructor(options) {
this.options = options;
this.defaults = {
width: 260,
handleSize: 10,
disableMask: false,
maxMaskOpacity: 0.5
};
options.target.classList.add('transition');
this.scrollContainer = options.target.querySelector('.mainDrawer-scrollContainer');
this.scrollContainer.classList.add('scrollY');
this.isVisible = false;
this.initialize();
}
2020-08-06 20:59:14 +02:00
2022-04-09 03:58:07 +03:00
setVelocity(deltaX) {
const time = new Date().getTime() - (this.menuTouchStartTime || 0);
this.velocity = Math.abs(deltaX) / time;
}
2022-04-11 00:47:22 +03:00
onMenuTouchStart = (e) => {
2022-04-09 03:58:07 +03:00
const options = this.options;
2020-08-06 20:59:14 +02:00
options.target.classList.remove('transition');
2022-04-11 00:47:22 +03:00
const touches = getTouches(e);
2020-10-07 21:12:14 +09:00
const touch = touches[0] || {};
2022-04-09 03:58:07 +03:00
this.menuTouchStartX = touch.clientX;
this.menuTouchStartY = touch.clientY;
this.menuTouchStartTime = new Date().getTime();
2022-04-11 00:47:22 +03:00
};
2020-08-06 20:59:14 +02:00
2022-04-11 00:47:22 +03:00
onMenuTouchMove = (e) => {
2022-04-09 03:58:07 +03:00
const scrollContainer = this.scrollContainer;
2020-08-06 20:59:14 +02:00
2022-04-09 03:58:07 +03:00
const isOpen = this.visible;
2022-04-11 00:47:22 +03:00
const touches = getTouches(e);
2020-10-07 21:12:14 +09:00
const touch = touches[0] || {};
const endX = touch.clientX || 0;
const endY = touch.clientY || 0;
2022-07-04 13:29:32 -04:00
let deltaX = endX - (this.menuTouchStartX || 0);
if (globalize.getIsRTL()) {
2022-07-04 13:29:32 -04:00
deltaX *= -1;
}
2022-04-09 03:58:07 +03:00
const deltaY = endY - (this.menuTouchStartY || 0);
this.setVelocity(deltaX);
2020-08-06 20:59:14 +02:00
2022-04-09 03:58:07 +03:00
if (isOpen && this.dragMode !== 1 && deltaX > 0) {
this.dragMode = 2;
2018-10-23 01:05:09 +03:00
}
2022-04-09 03:58:07 +03:00
if (this.dragMode === 0 && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) {
this.dragMode = 1;
2022-04-11 00:47:22 +03:00
scrollContainer.addEventListener('scroll', disableEvent);
2022-04-09 03:58:07 +03:00
this.showMask();
} else if (this.dragMode === 0 && Math.abs(deltaY) >= 5) {
this.dragMode = 2;
2018-10-23 01:05:09 +03:00
}
2022-04-09 03:58:07 +03:00
if (this.dragMode === 1) {
this.newPos = this.currentPos + deltaX;
this.changeMenuPos();
2018-10-23 01:05:09 +03:00
}
2022-04-11 00:47:22 +03:00
};
2020-08-06 20:59:14 +02:00
2022-04-11 00:47:22 +03:00
onMenuTouchEnd = (e) => {
2022-04-09 03:58:07 +03:00
const options = this.options;
const scrollContainer = this.scrollContainer;
2020-08-06 20:59:14 +02:00
options.target.classList.add('transition');
2022-04-11 00:47:22 +03:00
scrollContainer.removeEventListener('scroll', disableEvent);
2022-04-09 03:58:07 +03:00
this.dragMode = 0;
2022-04-11 00:47:22 +03:00
const touches = getTouches(e);
2020-10-07 21:12:14 +09:00
const touch = touches[0] || {};
const endX = touch.clientX || 0;
const endY = touch.clientY || 0;
2022-07-04 13:29:32 -04:00
let deltaX = endX - (this.menuTouchStartX || 0);
if (globalize.getIsRTL()) {
2022-07-04 13:29:32 -04:00
deltaX *= -1;
}
2022-04-09 03:58:07 +03:00
const deltaY = endY - (this.menuTouchStartY || 0);
this.currentPos = deltaX;
this.checkMenuState(deltaX, deltaY);
2022-04-11 00:47:22 +03:00
};
2022-04-09 03:58:07 +03:00
2022-04-11 00:47:22 +03:00
onEdgeTouchMove = (e) => {
2022-04-09 03:58:07 +03:00
e.preventDefault();
e.stopPropagation();
this.onEdgeTouchStart(e);
2022-04-11 00:47:22 +03:00
};
2020-08-06 20:59:14 +02:00
2022-04-11 00:47:22 +03:00
onEdgeTouchStart = (e) => {
2022-04-09 03:58:07 +03:00
const options = this.options;
if (this.isPeeking) {
this.onMenuTouchMove(e);
2020-08-06 20:59:14 +02:00
} else {
2023-07-06 13:39:48 -04:00
if ((getTouches(e)[0]?.clientX || 0) <= options.handleSize) {
2022-04-09 03:58:07 +03:00
this.isPeeking = true;
2020-08-06 20:59:14 +02:00
if (e.type === 'touchstart') {
2022-04-11 00:47:22 +03:00
dom.removeEventListener(this.edgeContainer, 'touchmove', this.onEdgeTouchMove, {});
dom.addEventListener(this.edgeContainer, 'touchmove', this.onEdgeTouchMove, {});
2020-08-06 20:59:14 +02:00
}
2018-10-23 01:05:09 +03:00
2022-04-09 03:58:07 +03:00
this.onMenuTouchStart(e);
2020-01-22 03:31:43 +03:00
}
2020-08-06 20:59:14 +02:00
}
2022-04-11 00:47:22 +03:00
};
2020-08-06 20:59:14 +02:00
2022-04-11 00:47:22 +03:00
onEdgeTouchEnd = (e) => {
2022-04-09 03:58:07 +03:00
if (this.isPeeking) {
this.isPeeking = false;
2022-04-11 00:47:22 +03:00
dom.removeEventListener(this.edgeContainer, 'touchmove', this.onEdgeTouchMove, {});
2022-04-09 03:58:07 +03:00
this.onMenuTouchEnd(e);
2020-08-06 20:59:14 +02:00
}
2022-04-11 00:47:22 +03:00
};
2020-08-06 20:59:14 +02:00
2022-04-11 00:47:22 +03:00
onBackgroundTouchStart = (e) => {
const touches = getTouches(e);
2020-10-07 21:12:14 +09:00
const touch = touches[0] || {};
2022-04-09 03:58:07 +03:00
this.backgroundTouchStartX = touch.clientX;
this.backgroundTouchStartTime = new Date().getTime();
2022-04-11 00:47:22 +03:00
};
2020-08-06 20:59:14 +02:00
2022-04-11 00:47:22 +03:00
onBackgroundTouchMove = (e) => {
2022-04-09 03:58:07 +03:00
const options = this.options;
2022-04-11 00:47:22 +03:00
const touches = getTouches(e);
2020-10-07 21:12:14 +09:00
const touch = touches[0] || {};
const endX = touch.clientX || 0;
2020-08-06 20:59:14 +02:00
2022-04-09 03:58:07 +03:00
if (endX <= options.width && this.isVisible) {
this.countStart++;
2022-07-04 13:29:32 -04:00
let deltaX = endX - (this.backgroundTouchStartX || 0);
if (globalize.getIsRTL()) {
2022-07-04 13:29:32 -04:00
deltaX *= -1;
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
if (this.countStart == 1) {
this.startPoint = deltaX;
2020-01-22 03:31:43 +03:00
}
2022-04-09 03:58:07 +03:00
if (deltaX < 0 && this.dragMode !== 2) {
this.dragMode = 1;
this.newPos = deltaX - this.startPoint + options.width;
this.changeMenuPos();
const time = new Date().getTime() - (this.backgroundTouchStartTime || 0);
this.velocity = Math.abs(deltaX) / time;
2020-01-22 03:31:43 +03:00
}
2018-10-23 01:05:09 +03:00
}
2020-08-06 20:59:14 +02:00
e.preventDefault();
e.stopPropagation();
2022-04-11 00:47:22 +03:00
};
2018-10-23 01:05:09 +03:00
2022-04-11 00:47:22 +03:00
onBackgroundTouchEnd = (e) => {
const touches = getTouches(e);
2020-10-07 21:12:14 +09:00
const touch = touches[0] || {};
const endX = touch.clientX || 0;
2022-07-04 13:29:32 -04:00
let deltaX = endX - (this.backgroundTouchStartX || 0);
if (globalize.getIsRTL()) {
2022-07-04 13:29:32 -04:00
deltaX *= -1;
}
2022-04-09 03:58:07 +03:00
this.checkMenuState(deltaX);
this.countStart = 0;
2022-04-11 00:47:22 +03:00
};
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
initElements() {
const options = this.options;
2018-10-23 01:05:09 +03:00
2020-08-06 20:59:14 +02:00
options.target.classList.add('touch-menu-la');
options.target.style.width = options.width + 'px';
2022-10-13 13:59:48 -04:00
if (globalize.getIsRTL())
options.target.style.right = -options.width + 'px';
else
options.target.style.left = -options.width + 'px';
2020-08-06 20:59:14 +02:00
if (!options.disableMask) {
2022-04-09 03:58:07 +03:00
this.mask = document.createElement('div');
this.mask.className = 'tmla-mask hide';
document.body.appendChild(this.mask);
2018-10-23 01:05:09 +03:00
}
2022-04-09 03:58:07 +03:00
}
2018-10-23 01:05:09 +03:00
2022-04-09 03:58:07 +03:00
animateToPosition(pos) {
const options = this.options;
2022-07-08 12:06:40 -04:00
const languageAwarePos = globalize.getIsRTL() ? -pos : pos;
2020-08-06 20:59:14 +02:00
requestAnimationFrame(function () {
2022-07-08 12:06:40 -04:00
options.target.style.transform = pos ? 'translateX(' + languageAwarePos + 'px)' : 'none';
2020-08-06 20:59:14 +02:00
});
2022-04-09 03:58:07 +03:00
}
2018-10-23 01:05:09 +03:00
2022-04-09 03:58:07 +03:00
changeMenuPos() {
const options = this.options;
if (this.newPos <= options.width) {
this.animateToPosition(this.newPos);
2018-10-23 01:05:09 +03:00
}
2022-04-09 03:58:07 +03:00
}
2018-10-23 01:05:09 +03:00
2022-04-09 03:58:07 +03:00
clickMaskClose() {
2022-04-11 00:47:22 +03:00
this.mask.addEventListener('click', () => {
this.close();
});
2022-04-09 03:58:07 +03:00
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
checkMenuState(deltaX, deltaY) {
if (this.velocity >= 0.4) {
2020-08-06 20:59:14 +02:00
if (deltaX >= 0 || Math.abs(deltaY || 0) >= 70) {
2022-04-09 03:58:07 +03:00
this.open();
2020-08-06 20:59:14 +02:00
} else {
2022-04-09 03:58:07 +03:00
this.close();
2020-08-06 20:59:14 +02:00
}
} else {
2022-04-09 03:58:07 +03:00
if (this.newPos >= 100) {
this.open();
2020-08-06 20:59:14 +02:00
} else {
2022-04-09 03:58:07 +03:00
if (this.newPos) {
this.close();
2018-10-23 01:05:09 +03:00
}
}
}
2022-04-09 03:58:07 +03:00
}
open() {
const options = this.options;
2018-10-23 01:05:09 +03:00
2020-08-06 20:59:14 +02:00
this.animateToPosition(options.width);
2022-04-09 03:58:07 +03:00
this.currentPos = options.width;
2020-08-06 20:59:14 +02:00
this.isVisible = true;
options.target.classList.add('drawer-open');
2022-04-09 03:58:07 +03:00
this.showMask();
this.invoke(options.onChange);
}
close() {
const options = this.options;
2018-10-23 01:05:09 +03:00
2020-08-06 20:59:14 +02:00
this.animateToPosition(0);
2022-04-09 03:58:07 +03:00
this.currentPos = 0;
this.isVisible = false;
2020-08-06 20:59:14 +02:00
options.target.classList.remove('drawer-open');
2022-04-09 03:58:07 +03:00
this.hideMask();
this.invoke(options.onChange);
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
toggle() {
if (this.isVisible) {
this.close();
2020-08-06 20:59:14 +02:00
} else {
2022-04-09 03:58:07 +03:00
this.open();
2018-10-23 01:05:09 +03:00
}
2022-04-09 03:58:07 +03:00
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
showMask() {
this.mask.classList.remove('hide');
this.mask.classList.add('backdrop');
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
hideMask() {
this.mask.classList.add('hide');
this.mask.classList.remove('backdrop');
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
invoke(fn) {
2020-08-06 20:59:14 +02:00
if (fn) {
2022-04-09 03:58:07 +03:00
fn.apply(this);
2020-08-06 20:59:14 +02:00
}
2022-04-09 03:58:07 +03:00
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
setEdgeSwipeEnabled(enabled) {
const options = this.options;
2020-01-22 03:31:43 +03:00
2022-10-03 14:22:02 -04:00
if (!options.disableEdgeSwipe && browser.touch) {
if (enabled) {
if (!this._edgeSwipeEnabled) {
this._edgeSwipeEnabled = true;
dom.addEventListener(this.edgeContainer, 'touchstart', this.onEdgeTouchStart, {
passive: true
});
dom.addEventListener(this.edgeContainer, 'touchend', this.onEdgeTouchEnd, {
passive: true
});
dom.addEventListener(this.edgeContainer, 'touchcancel', this.onEdgeTouchEnd, {
passive: true
});
}
} else {
if (this._edgeSwipeEnabled) {
this._edgeSwipeEnabled = false;
dom.removeEventListener(this.edgeContainer, 'touchstart', this.onEdgeTouchStart, {
passive: true
});
dom.removeEventListener(this.edgeContainer, 'touchend', this.onEdgeTouchEnd, {
passive: true
});
dom.removeEventListener(this.edgeContainer, 'touchcancel', this.onEdgeTouchEnd, {
passive: true
});
2020-01-22 03:31:43 +03:00
}
}
2020-08-06 20:59:14 +02:00
}
2022-04-09 03:58:07 +03:00
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
initialize() {
const options = Object.assign({}, this.defaults, this.options || {});
this.options = options;
2020-01-22 03:31:43 +03:00
2020-08-06 20:59:14 +02:00
if (browser.edge) {
options.disableEdgeSwipe = true;
}
2020-01-22 03:31:43 +03:00
2022-04-09 03:58:07 +03:00
this.initElements();
2020-01-22 03:31:43 +03:00
2020-08-06 20:59:14 +02:00
if (browser.touch) {
2022-04-11 00:47:22 +03:00
dom.addEventListener(options.target, 'touchstart', this.onMenuTouchStart, {
2020-08-06 20:59:14 +02:00
passive: true
});
2022-04-11 00:47:22 +03:00
dom.addEventListener(options.target, 'touchmove', this.onMenuTouchMove, {
2020-08-06 20:59:14 +02:00
passive: true
});
2022-04-11 00:47:22 +03:00
dom.addEventListener(options.target, 'touchend', this.onMenuTouchEnd, {
2020-08-06 20:59:14 +02:00
passive: true
});
2022-04-11 00:47:22 +03:00
dom.addEventListener(options.target, 'touchcancel', this.onMenuTouchEnd, {
2020-08-06 20:59:14 +02:00
passive: true
});
2022-04-11 00:47:22 +03:00
dom.addEventListener(this.mask, 'touchstart', this.onBackgroundTouchStart, {
2020-08-06 20:59:14 +02:00
passive: true
});
2022-04-11 00:47:22 +03:00
dom.addEventListener(this.mask, 'touchmove', this.onBackgroundTouchMove, {});
dom.addEventListener(this.mask, 'touchend', this.onBackgroundTouchEnd, {
2020-08-06 20:59:14 +02:00
passive: true
});
2022-04-11 00:47:22 +03:00
dom.addEventListener(this.mask, 'touchcancel', this.onBackgroundTouchEnd, {
2020-08-06 20:59:14 +02:00
passive: true
});
}
2020-01-22 03:31:43 +03:00
2022-04-11 00:47:22 +03:00
this.clickMaskClose();
2022-04-09 03:58:07 +03:00
}
2020-08-06 20:59:14 +02:00
}
2022-04-09 03:58:07 +03:00
export default NavDrawer;
2022-04-11 00:47:22 +03:00