From a2529e8e99740c2979e70a2d9ea0598609afb9d0 Mon Sep 17 00:00:00 2001 From: Volker Schukai <volker.schukai@schukai.com> Date: Tue, 20 May 2025 15:20:11 +0200 Subject: [PATCH] fix: Add touch support for drag events in split-panel component - Modified `split-panel.mjs` to enhance user experience on touch devices. - Removed the "touchstart" event from the initial event type array, and added a dedicated touch event listener for handling drag movements. - Implemented touch-specific logic for resizing panels, mirroring existing mouse drag functionality. - Introduced proper touch event handling for starting, moving, and ending the drag operation, ensuring smooth interaction. These changes were made to address the lack of touch support, enabling users on mobile devices to interact with the split-panel effectively. --- source/components/layout/split-panel.mjs | 61 +++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/source/components/layout/split-panel.mjs b/source/components/layout/split-panel.mjs index bf8d771df..728f3dcf3 100644 --- a/source/components/layout/split-panel.mjs +++ b/source/components/layout/split-panel.mjs @@ -269,8 +269,7 @@ function initEventHandler() { this[internalSymbol].getSubject().isDragging = false; - // @todo: add better touch support - const eventTypes = ["dblclick", "touchstart"]; + const eventTypes = ["dblclick"]; for (const eventType of eventTypes) { this[draggerElementSymbol].addEventListener(eventType, () => { self[internalSymbol].getSubject().isDragging = false; @@ -297,6 +296,64 @@ function initEventHandler() { }); } + this[draggerElementSymbol].addEventListener("touchstart", (startEvent) => { + + startEvent.preventDefault(); + self[internalSymbol].getSubject().isDragging = true; + + const dragTouchMove = (e) => { + if (!self[internalSymbol].getSubject().isDragging) return; + + const touch = e.touches[0]; + if (!touch) return; + + // identical logic as in mousemove - but with touch.clientX/clientY + let draggerWidth = getComputedStyle(self[draggerElementSymbol]).getPropertyValue("--monster-dragger-width") || "0"; + + if (self.getOption("splitType") === TYPE_HORIZONTAL) { + const containerOffsetTop = self[splitScreenElementSymbol].offsetTop; + let newTopHeight = touch.clientY - containerOffsetTop; + + const min = this.getOption("dimension").min; + const max = this.getOption("dimension").max; + const topAsPercent = (newTopHeight / this[splitScreenElementSymbol].offsetHeight) * 100; + + if (parseInt(min) > topAsPercent) newTopHeight = min; + else if (parseInt(max) < topAsPercent) newTopHeight = max; + else newTopHeight = topAsPercent + "%"; + + const newTopHeightPx = (parseInt(newTopHeight) / 100) * this[splitScreenElementSymbol].offsetHeight; + + self[startPanelElementSymbol].style.height = `${newTopHeightPx}px`; + self[endPanelElementSymbol].style.height = `calc(100% - ${newTopHeightPx}px - ${draggerWidth})`; + } else { + const containerOffsetLeft = self[splitScreenElementSymbol].offsetLeft; + let newLeftWidth = touch.clientX - containerOffsetLeft; + + const min = this.getOption("dimension").min; + const max = this.getOption("dimension").max; + const leftAsPercent = (newLeftWidth / this[splitScreenElementSymbol].offsetWidth) * 100; + + if (parseInt(min) > leftAsPercent) newLeftWidth = min; + else if (parseInt(max) < leftAsPercent) newLeftWidth = max; + else newLeftWidth = leftAsPercent + "%"; + + self[startPanelElementSymbol].style.width = `${newLeftWidth}`; + self[endPanelElementSymbol].style.width = `calc(100% - ${newLeftWidth} - ${draggerWidth})`; + } + }; + + const dragTouchEnd = () => { + self[internalSymbol].getSubject().isDragging = false; + document.removeEventListener("touchmove", dragTouchMove); + document.removeEventListener("touchend", dragTouchEnd); + }; + + document.addEventListener("touchmove", dragTouchMove, { passive: false }); + document.addEventListener("touchend", dragTouchEnd); + }); + + let userSelectDefault = getDocument().body.style.userSelect; this[draggerElementSymbol].addEventListener("mousedown", () => { -- GitLab