Skip to content

Latest commit

 

History

History
153 lines (128 loc) · 4.57 KB

File metadata and controls

153 lines (128 loc) · 4.57 KB

/* This script enables a temporary eraser mode while using the freedraw (pen) tool. When you hold the right mouse button (or the S Pen side button) and touch the canvas in freedraw mode, the active tool immediately switches to the eraser so you can erase. When you release the button / lift the pen, the tool automatically returns to the original freedraw tool.

*/
if (!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.9.11")) {
  new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
  return;
}

const api = ea.getExcalidrawAPI();
if (!api) {
  new Notice("Excalidraw API not available.");
  return;
}

// Find Excalidraw container
let container = null;
if (ea.targetView?.excalidrawContainer) {
  container = ea.targetView.excalidrawContainer;
} else if (ea.targetView?.contentEl) {
  container =
    ea.targetView.contentEl.querySelector('[class*=\"excalidraw\"]') ||
    ea.targetView.contentEl;
}

const targetElement = container || window;

// Remove existing listeners (to avoid duplicates)
if (targetElement._rightClickEraserHandlers) {
  const handlers = targetElement._rightClickEraserHandlers;
  targetElement.removeEventListener("pointerdown", handlers.pointerdown, true);
  targetElement.removeEventListener("pointermove", handlers.pointermove, true);
  targetElement.removeEventListener("pointerup", handlers.pointerup, true);
  targetElement.removeEventListener("pointercancel", handlers.pointercancel, true);
  targetElement.removeEventListener("contextmenu", handlers.contextmenu, true);
}

// -------------------------------
// State and helper functions
// -------------------------------

let isEraserMode = false;
let originalTool = null;

// Determine whether the eraser button (secondary button) is pressed
const isEraseButtonDown = (e) => {
  // Typical buttons bitfield:
  // 1 = primary, 2 = secondary (right), 4 = middle
  return (e.buttons & 2) === 2;
};

// Check if current tool is freedraw
const isFreeDraw = () => {
  const appState = api.getAppState();
  return appState.activeTool?.type === "freedraw";
};

// Switch to eraser mode
const switchToEraser = () => {
  if (isEraserMode) return;
  if (!isFreeDraw()) return;

  const appState = api.getAppState();
  originalTool = appState.activeTool?.type || "freedraw";
  api.setActiveTool({ type: "eraser" });

  isEraserMode = true;
};

// Restore original tool
const restoreTool = () => {
  if (!isEraserMode) return;

  api.setActiveTool({ type: originalTool || "freedraw" });
  isEraserMode = false;
  originalTool = null;
};

// -------------------------------
// Event handlers
// -------------------------------

// pointerdown: handles cases where the button is already pressed at touch-down
const onPointerDown = (e) => {
  if (isEraseButtonDown(e) && isFreeDraw()) {
    e.preventDefault();
    e.stopPropagation();
    switchToEraser();
  }
};

// pointermove: detects S Pen button press even if it appears only after small movement
const onPointerMove = (e) => {
  if (isEraseButtonDown(e)) {
    if (!isEraserMode && isFreeDraw()) {
      switchToEraser();
    }
  } else {
    if (isEraserMode && e.buttons === 0) {
      restoreTool();
    }
  }
};

// pointerup: restore when all buttons are released
const onPointerUp = (e) => {
  if (isEraserMode && !isEraseButtonDown(e) && e.buttons === 0) {
    restoreTool();
  }
};

// pointercancel: gesture canceled (leaving window etc.)
const onPointerCancel = (e) => {
  if (isEraserMode) restoreTool();
};

// contextmenu: prevents browser menu + supports environments that trigger right-click only here
const onContextMenu = (e) => {
  const appState = api.getAppState();
  const currentTool = appState.activeTool?.type;

  if (currentTool === "freedraw") {
    e.preventDefault();
    e.stopPropagation();
    if (!isEraserMode) switchToEraser();
  } else if (isEraserMode) {
    e.preventDefault();
    e.stopPropagation();
  }
};

// -------------------------------
// Register listeners
// -------------------------------

targetElement._rightClickEraserHandlers = {
  pointerdown: onPointerDown,
  pointermove: onPointerMove,
  pointerup: onPointerUp,
  pointercancel: onPointerCancel,
  contextmenu: onContextMenu
};

targetElement.addEventListener("pointerdown", onPointerDown, true);
targetElement.addEventListener("pointermove", onPointerMove, true);
targetElement.addEventListener("pointerup", onPointerUp, true);
targetElement.addEventListener("pointercancel", onPointerCancel, true);
targetElement.addEventListener("contextmenu", onContextMenu, true);

new Notice("Temporary eraser on right-click / S Pen button enabled for the freedraw tool.");