siyuan/app/src/mobile/util/touch.ts
Vanessa 1f7fc4cc8f 🚨
2023-03-31 10:48:16 +08:00

196 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {hasClosestByAttribute, hasClosestByClassName} from "../../protyle/util/hasClosest";
import {closePanel} from "./closePanel";
import {popMenu} from "../menu";
let clientX: number;
let clientY: number;
let xDiff: number;
let yDiff: number;
let time: number;
let firstDirection: "toLeft" | "toRight";
let lastClientX: number; // 和起始方向不一致时,记录最后一次的 clientX
export const handleTouchEnd = (event: TouchEvent) => {
if (window.siyuan.mobile.editor) {
document.querySelectorAll(".protyle-breadcrumb__bar--hide").forEach(item => {
item.classList.remove("protyle-breadcrumb__bar--hide");
});
window.siyuan.hideBreadcrumb = false;
}
const target = event.target as HTMLElement;
if (!clientX || !clientY || typeof yDiff === "undefined" ||
hasClosestByClassName(target, "b3-dialog") ||
hasClosestByAttribute(target, "id", "model")
) {
return;
}
// 有些事件不经过 touchstart 和 touchmove因此需设置为 null 不再继续执行
clientX = null;
// 有些事件不经过 touchmove
let scrollElement = hasClosestByAttribute(target, "data-type", "NodeCodeBlock") || hasClosestByAttribute(target, "data-type", "NodeTable");
if (scrollElement) {
scrollElement = scrollElement.classList.contains("table") ? (scrollElement.firstElementChild as HTMLElement) : (scrollElement.firstElementChild.nextElementSibling as HTMLElement);
if ((xDiff <= 0 && scrollElement.scrollLeft > 0) ||
(xDiff >= 0 && scrollElement.clientWidth + scrollElement.scrollLeft < scrollElement.scrollWidth)) {
return;
}
}
let scrollEnable = false;
if (new Date().getTime() - time < 1000) {
scrollEnable = true;
} else if (Math.abs(xDiff) > window.innerWidth / 3) {
scrollEnable = true;
}
const isXScroll = Math.abs(xDiff) > Math.abs(yDiff);
const menuElement = hasClosestByAttribute(target, "id", "menu");
if (menuElement) {
if (isXScroll) {
if (scrollEnable) {
if (xDiff <= 0) {
if (lastClientX) {
popMenu();
} else {
closePanel();
}
} else if (lastClientX) {
closePanel();
}
}
} else {
if (xDiff > 0) {
popMenu();
} else if (menuElement.style.right !== "0px") {
closePanel();
}
}
return;
}
const sideElement = hasClosestByAttribute(target, "id", "sidebar");
if (sideElement) {
if (isXScroll) {
if (scrollEnable) {
if (xDiff >= 0) {
if (lastClientX) {
document.getElementById("toolbarFile").dispatchEvent(new CustomEvent("click"));
} else {
closePanel();
}
} else if (lastClientX) {
closePanel();
}
}
} else {
if (xDiff < 0) {
document.getElementById("toolbarFile").dispatchEvent(new CustomEvent("click"));
} else if (sideElement.style.left !== "0px") {
closePanel();
}
}
return;
}
if (!scrollEnable || !isXScroll) {
closePanel();
return;
}
if (xDiff > 0) {
if (lastClientX) {
closePanel();
} else {
popMenu();
}
} else {
if (lastClientX) {
closePanel();
} else {
document.getElementById("toolbarFile").dispatchEvent(new CustomEvent("click"));
}
}
};
export const handleTouchStart = (event: TouchEvent) => {
firstDirection = null;
xDiff = undefined;
yDiff = undefined;
lastClientX = undefined;
if (navigator.userAgent.indexOf("iPhone") > -1 ||
(event.touches[0].clientX > 8 && event.touches[0].clientX < window.innerWidth - 8)) {
clientX = event.touches[0].clientX;
clientY = event.touches[0].clientY;
time = new Date().getTime();
} else {
clientX = null;
clientY = null;
time = 0;
event.stopImmediatePropagation();
}
};
let previousClientX: number;
export const handleTouchMove = (event: TouchEvent) => {
const target = event.target as HTMLElement;
if (!clientX || !clientY ||
hasClosestByClassName(target, "b3-dialog") ||
hasClosestByAttribute(target, "id", "model")) {
return;
}
xDiff = Math.floor(clientX - event.touches[0].clientX);
yDiff = Math.floor(clientY - event.touches[0].clientY);
if (!firstDirection) {
firstDirection = xDiff > 0 ? "toLeft" : "toRight";
}
if (previousClientX) {
if (firstDirection === "toRight") {
if (previousClientX > event.touches[0].clientX) {
lastClientX = event.touches[0].clientX;
} else {
lastClientX = undefined;
}
} else if (firstDirection === "toLeft") {
if (previousClientX < event.touches[0].clientX) {
lastClientX = event.touches[0].clientX;
} else {
lastClientX = undefined;
}
}
}
previousClientX = event.touches[0].clientX;
if (Math.abs(xDiff) > Math.abs(yDiff)) {
let scrollElement = hasClosestByAttribute(target, "data-type", "NodeCodeBlock") || hasClosestByAttribute(target, "data-type", "NodeTable");
if (scrollElement) {
scrollElement = scrollElement.classList.contains("table") ? (scrollElement.firstElementChild as HTMLElement) : (scrollElement.firstElementChild.nextElementSibling as HTMLElement);
if ((xDiff < 0 && scrollElement.scrollLeft > 0) ||
(xDiff > 0 && scrollElement.clientWidth + scrollElement.scrollLeft < scrollElement.scrollWidth)) {
return;
}
}
const menuElement = hasClosestByAttribute(target, "id", "menu");
if (menuElement) {
if (xDiff < 0) {
menuElement.style.right = xDiff + "px";
}
return;
}
const sideElement = hasClosestByAttribute(target, "id", "sidebar");
if (sideElement) {
if (xDiff > 0) {
sideElement.style.left = -xDiff + "px";
}
return;
}
if (firstDirection === "toRight") {
document.getElementById("sidebar").style.left = -window.innerWidth - xDiff + "px";
} else {
document.getElementById("menu").style.right = -window.innerWidth + xDiff + "px";
}
}
};