This repository has been archived on 2025-03-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
boilerplate/node_modules/@wailsio/runtime/dist/drag.js
2025-03-07 07:16:20 -08:00

223 lines
7.2 KiB
JavaScript

/*
_ __ _ __
| | / /___ _(_) /____
| | /| / / __ `/ / / ___/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
The electron alternative for Go
(c) Lea Anthony 2019-present
*/
import { invoke, IsWindows } from "./system.js";
import { GetFlag } from "./flags.js";
import { canTrackButtons, eventTarget } from "./utils.js";
// Setup
let canDrag = false;
let dragging = false;
let resizable = false;
let canResize = false;
let resizing = false;
let resizeEdge = "";
let defaultCursor = "auto";
let buttons = 0;
const buttonsTracked = canTrackButtons();
window._wails = window._wails || {};
window._wails.setResizable = (value) => {
resizable = value;
if (!resizable) {
// Stop resizing if in progress.
canResize = resizing = false;
setResize();
}
};
window.addEventListener('mousedown', update, { capture: true });
window.addEventListener('mousemove', update, { capture: true });
window.addEventListener('mouseup', update, { capture: true });
for (const ev of ['click', 'contextmenu', 'dblclick']) {
window.addEventListener(ev, suppressEvent, { capture: true });
}
function suppressEvent(event) {
// Suppress click events while resizing or dragging.
if (dragging || resizing) {
event.stopImmediatePropagation();
event.stopPropagation();
event.preventDefault();
}
}
// Use constants to avoid comparing strings multiple times.
const MouseDown = 0;
const MouseUp = 1;
const MouseMove = 2;
function update(event) {
// Windows suppresses mouse events at the end of dragging or resizing,
// so we need to be smart and synthesize button events.
let eventType, eventButtons = event.buttons;
switch (event.type) {
case 'mousedown':
eventType = MouseDown;
if (!buttonsTracked) {
eventButtons = buttons | (1 << event.button);
}
break;
case 'mouseup':
eventType = MouseUp;
if (!buttonsTracked) {
eventButtons = buttons & ~(1 << event.button);
}
break;
default:
eventType = MouseMove;
if (!buttonsTracked) {
eventButtons = buttons;
}
break;
}
let released = buttons & ~eventButtons;
let pressed = eventButtons & ~buttons;
buttons = eventButtons;
// Synthesize a release-press sequence if we detect a press of an already pressed button.
if (eventType === MouseDown && !(pressed & event.button)) {
released |= (1 << event.button);
pressed |= (1 << event.button);
}
// Suppress all button events during dragging and resizing,
// unless this is a mouseup event that is ending a drag action.
if (eventType !== MouseMove // Fast path for mousemove
&& resizing
|| (dragging
&& (eventType === MouseDown
|| event.button !== 0))) {
event.stopImmediatePropagation();
event.stopPropagation();
event.preventDefault();
}
// Handle releases
if (released & 1) {
primaryUp(event);
}
// Handle presses
if (pressed & 1) {
primaryDown(event);
}
// Handle mousemove
if (eventType === MouseMove) {
onMouseMove(event);
}
;
}
function primaryDown(event) {
// Reset readiness state.
canDrag = false;
canResize = false;
// Ignore repeated clicks on macOS and Linux.
if (!IsWindows()) {
if (event.type === 'mousedown' && event.button === 0 && event.detail !== 1) {
return;
}
}
if (resizeEdge) {
// Ready to resize if the primary button was pressed for the first time.
canResize = true;
// Do not start drag operations when on resize edges.
return;
}
// Retrieve target element
const target = eventTarget(event);
// Ready to drag if the primary button was pressed for the first time on a draggable element.
// Ignore clicks on the scrollbar.
const style = window.getComputedStyle(target);
canDrag = (style.getPropertyValue("--wails-draggable").trim() === "drag"
&& (event.offsetX - parseFloat(style.paddingLeft) < target.clientWidth
&& event.offsetY - parseFloat(style.paddingTop) < target.clientHeight));
}
function primaryUp(event) {
// Stop dragging and resizing.
canDrag = false;
dragging = false;
canResize = false;
resizing = false;
}
const cursorForEdge = Object.freeze({
"se-resize": "nwse-resize",
"sw-resize": "nesw-resize",
"nw-resize": "nwse-resize",
"ne-resize": "nesw-resize",
"w-resize": "ew-resize",
"n-resize": "ns-resize",
"s-resize": "ns-resize",
"e-resize": "ew-resize",
});
function setResize(edge) {
if (edge) {
if (!resizeEdge) {
defaultCursor = document.body.style.cursor;
}
document.body.style.cursor = cursorForEdge[edge];
}
else if (!edge && resizeEdge) {
document.body.style.cursor = defaultCursor;
}
resizeEdge = edge || "";
}
function onMouseMove(event) {
if (canResize && resizeEdge) {
// Start resizing.
resizing = true;
invoke("wails:resize:" + resizeEdge);
}
else if (canDrag) {
// Start dragging.
dragging = true;
invoke("wails:drag");
}
if (dragging || resizing) {
// Either drag or resize is ongoing,
// reset readiness and stop processing.
canDrag = canResize = false;
return;
}
if (!resizable || !IsWindows()) {
if (resizeEdge) {
setResize();
}
return;
}
const resizeHandleHeight = GetFlag("system.resizeHandleHeight") || 5;
const resizeHandleWidth = GetFlag("system.resizeHandleWidth") || 5;
// Extra pixels for the corner areas.
const cornerExtra = GetFlag("resizeCornerExtra") || 10;
const rightBorder = (window.outerWidth - event.clientX) < resizeHandleWidth;
const leftBorder = event.clientX < resizeHandleWidth;
const topBorder = event.clientY < resizeHandleHeight;
const bottomBorder = (window.outerHeight - event.clientY) < resizeHandleHeight;
// Adjust for corner areas.
const rightCorner = (window.outerWidth - event.clientX) < (resizeHandleWidth + cornerExtra);
const leftCorner = event.clientX < (resizeHandleWidth + cornerExtra);
const topCorner = event.clientY < (resizeHandleHeight + cornerExtra);
const bottomCorner = (window.outerHeight - event.clientY) < (resizeHandleHeight + cornerExtra);
if (!leftCorner && !topCorner && !bottomCorner && !rightCorner) {
// Optimisation: out of all corner areas implies out of borders.
setResize();
}
// Detect corners.
else if (rightCorner && bottomCorner)
setResize("se-resize");
else if (leftCorner && bottomCorner)
setResize("sw-resize");
else if (leftCorner && topCorner)
setResize("nw-resize");
else if (topCorner && rightCorner)
setResize("ne-resize");
// Detect borders.
else if (leftBorder)
setResize("w-resize");
else if (topBorder)
setResize("n-resize");
else if (bottomBorder)
setResize("s-resize");
else if (rightBorder)
setResize("e-resize");
// Out of border area.
else
setResize();
}