133 lines
4.4 KiB
JavaScript
133 lines
4.4 KiB
JavaScript
class TouchHandler {
|
|
constructor() {
|
|
this.reset();
|
|
}
|
|
|
|
reset() {
|
|
this.touch = {
|
|
start: { x: -1, y: -1 },
|
|
move: { x: -1, y: -1 },
|
|
element: null
|
|
};
|
|
}
|
|
|
|
calculateDistance() {
|
|
if (this.touch.start.x >= -1 && this.touch.move.x >= -1) {
|
|
let horizontalDistance = Math.abs(this.touch.move.x - this.touch.start.x);
|
|
let verticalDistance = Math.abs(this.touch.move.y - this.touch.start.y);
|
|
|
|
if (horizontalDistance > 30 && verticalDistance < 70) {
|
|
return this.touch.move.x - this.touch.start.x;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
findElement(element) {
|
|
if (element.classList.contains("touch-item")) {
|
|
return element;
|
|
}
|
|
|
|
return DomHelper.findParent(element, "touch-item");
|
|
}
|
|
|
|
onTouchStart(event) {
|
|
if (event.touches === undefined || event.touches.length !== 1) {
|
|
return;
|
|
}
|
|
|
|
this.reset();
|
|
this.touch.start.x = event.touches[0].clientX;
|
|
this.touch.start.y = event.touches[0].clientY;
|
|
this.touch.element = this.findElement(event.touches[0].target);
|
|
}
|
|
|
|
onTouchMove(event) {
|
|
if (event.touches === undefined || event.touches.length !== 1 || this.element === null) {
|
|
return;
|
|
}
|
|
|
|
this.touch.move.x = event.touches[0].clientX;
|
|
this.touch.move.y = event.touches[0].clientY;
|
|
|
|
let distance = this.calculateDistance();
|
|
let absDistance = Math.abs(distance);
|
|
|
|
if (absDistance > 0) {
|
|
let opacity = 1 - (absDistance > 75 ? 0.9 : absDistance / 75 * 0.9);
|
|
let tx = distance > 75 ? 75 : (distance < -75 ? -75 : distance);
|
|
|
|
this.touch.element.style.opacity = opacity;
|
|
this.touch.element.style.transform = "translateX(" + tx + "px)";
|
|
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
|
|
onTouchEnd(event) {
|
|
if (event.touches === undefined) {
|
|
return;
|
|
}
|
|
|
|
if (this.touch.element !== null) {
|
|
let distance = Math.abs(this.calculateDistance());
|
|
|
|
if (distance > 75) {
|
|
toggleEntryStatus(this.touch.element);
|
|
}
|
|
|
|
// If not on the unread page, undo transform of the dragged element.
|
|
if (document.URL.split("/").indexOf("unread") == -1 || distance <= 75) {
|
|
this.touch.element.style.opacity = 1;
|
|
this.touch.element.style.transform = "none";
|
|
}
|
|
}
|
|
|
|
this.reset();
|
|
}
|
|
|
|
listen() {
|
|
let elements = document.querySelectorAll(".touch-item");
|
|
let hasPassiveOption = DomHelper.hasPassiveEventListenerOption();
|
|
|
|
elements.forEach((element) => {
|
|
element.addEventListener("touchstart", (e) => this.onTouchStart(e), hasPassiveOption ? { passive: true } : false);
|
|
element.addEventListener("touchmove", (e) => this.onTouchMove(e), hasPassiveOption ? { passive: false } : false);
|
|
element.addEventListener("touchend", (e) => this.onTouchEnd(e), hasPassiveOption ? { passive: true } : false);
|
|
element.addEventListener("touchcancel", () => this.reset(), hasPassiveOption ? { passive: true } : false);
|
|
});
|
|
|
|
let entryContentElement = document.querySelector(".entry-content");
|
|
if (entryContentElement) {
|
|
let doubleTapTimers = {
|
|
previous: null,
|
|
next: null
|
|
};
|
|
|
|
const detectDoubleTap = (doubleTapTimer, event) => {
|
|
const timer = doubleTapTimers[doubleTapTimer];
|
|
if (timer === null) {
|
|
doubleTapTimers[doubleTapTimer] = setTimeout(() => {
|
|
doubleTapTimers[doubleTapTimer] = null;
|
|
}, 200);
|
|
} else {
|
|
event.preventDefault();
|
|
goToPage(doubleTapTimer);
|
|
}
|
|
};
|
|
|
|
entryContentElement.addEventListener("touchend", (e) => {
|
|
if (e.changedTouches[0].clientX >= (entryContentElement.offsetWidth / 2)) {
|
|
detectDoubleTap("next", e);
|
|
} else {
|
|
detectDoubleTap("previous", e);
|
|
}
|
|
}, hasPassiveOption ? { passive: false } : false);
|
|
|
|
entryContentElement.addEventListener("touchmove", (e) => {
|
|
Object.keys(doubleTapTimers).forEach(timer => doubleTapTimers[timer] = null);
|
|
});
|
|
}
|
|
}
|
|
}
|