Files
MajoorWaldi-ComfyUI-Majoor-…/js/features/viewer/floatingViewerPanel.js
T
Ewald a2053d0cba refactor(v2): plan V2 complet — splits JS, tests frontend, durcissement securite
Chantier F - Typage Python
- ruff S101 déplacé en per-file-ignores (pyproject.toml)
- pyrightconfig.json : mode standard confirmé

Chantier G - Assertions & bare-except
- 16 blocs except documentés dans config.py
- --cov-branch activé, seuil coverage 60→68%

Chantier H - Cache settings
- Stratégie documentée dans settings.py
- _resolve_index_dir() logguée dans config.py

Chantier I - Split gros fichiers JS
- client.js 1509L → client.js 406L + clientAuth.js + clientOps.js + fetchUtils.js
- toolbar.js 927L → toolbar.js 458L + toolbarActions.js + toolbarControls.js
- FloatingViewer.js → FloatingViewer.impl.js + floatingViewer*(8 modules)
- Viewer_impl.js → ViewerRuntime.js + viewerShell.js + viewerThemeStyles.js + viewerOverlayDismiss.js
- model3dRenderer.js → model3dRenderer.impl.js + model3dCore.js + model3dLoaders.js + model3dSupport.js
- dialogs.js → dialogs.js + DialogTemplates.js

Chantier J - Tests frontend (Phases 1-2)
- use_drag_drop.vitest.mjs : 5 tests
- use_grid_state.vitest.mjs : 18 tests
- security_client_headers, security_deep_merge, security_runtime_state, runtime_store, dialog_templates
- Total: 80 fichiers test / 350 tests vitest

Chantier K - Pinia migration
- runtimeState.js entièrement migré vers Pinia
- getOptionalRuntimeStore.js + runtimeEnrichmentState.js ajoutés

Chantier L - Durcissement sécurité
- tests/security/test_rate_limit.py : 8 tests rate-limit (state machine complète)
- clientAuth.js : docstring sessionStorage security boundary
- three.js 0.183.2 audité : 0 CVE (Snyk)

Chantier M - Simplification config
- deps.py, tool_detect.py, utils.py nettoyés

docs: PLAN_REFACTO_V2_LONG_TERME.md ajouté et clôturé
.gitignore: coverage/ ajouté
2026-04-11 09:38:41 +02:00

231 lines
8.2 KiB
JavaScript

import { MFV_RESIZE_EDGE_HIT_PX } from "./floatingViewerConstants.js";
export function getFloatingViewerResizeCursor(dir) {
const map = {
n: "ns-resize",
s: "ns-resize",
e: "ew-resize",
w: "ew-resize",
ne: "nesw-resize",
nw: "nwse-resize",
se: "nwse-resize",
sw: "nesw-resize",
};
return map[dir] || "";
}
export function getFloatingViewerResizeDirectionFromPoint(clientX, clientY, rect) {
if (!rect) return "";
const nearLeft = clientX <= rect.left + MFV_RESIZE_EDGE_HIT_PX;
const nearRight = clientX >= rect.right - MFV_RESIZE_EDGE_HIT_PX;
const nearTop = clientY <= rect.top + MFV_RESIZE_EDGE_HIT_PX;
const nearBottom = clientY >= rect.bottom - MFV_RESIZE_EDGE_HIT_PX;
if (nearTop && nearLeft) return "nw";
if (nearTop && nearRight) return "ne";
if (nearBottom && nearLeft) return "sw";
if (nearBottom && nearRight) return "se";
if (nearTop) return "n";
if (nearBottom) return "s";
if (nearLeft) return "w";
if (nearRight) return "e";
return "";
}
export function stopFloatingViewerEdgeResize(viewer) {
if (!viewer.element) return;
if (viewer._resizeState?.pointerId != null) {
try {
viewer.element.releasePointerCapture(viewer._resizeState.pointerId);
} catch (e) {
console.debug?.(e);
}
}
viewer._resizeState = null;
viewer.element.classList.remove("mjr-mfv--resizing");
viewer.element.style.cursor = "";
}
export function bindFloatingViewerPanelInteractions(viewer) {
if (!viewer.element) return;
viewer._stopEdgeResize();
try {
viewer._panelAC?.abort();
} catch (e) {
console.debug?.(e);
}
viewer._panelAC = new AbortController();
viewer._initEdgeResize(viewer.element);
viewer._initDrag(viewer.element.querySelector(".mjr-mfv-header"));
}
export function initFloatingViewerEdgeResize(viewer, el) {
if (!el) return;
const resolveDir = (e) => {
if (!viewer.element || viewer._isPopped) return "";
const rect = viewer.element.getBoundingClientRect();
return viewer._getResizeDirectionFromPoint(e.clientX, e.clientY, rect);
};
const signal = viewer._panelAC?.signal;
const onPointerDown = (e) => {
if (e.button !== 0 || !viewer.element || viewer._isPopped) return;
const dir = resolveDir(e);
if (!dir) return;
e.preventDefault();
e.stopPropagation();
const rect = viewer.element.getBoundingClientRect();
const style = window.getComputedStyle(viewer.element);
const minWidth = Math.max(120, Number.parseFloat(style.minWidth) || 0);
const minHeight = Math.max(100, Number.parseFloat(style.minHeight) || 0);
viewer._resizeState = {
pointerId: e.pointerId,
dir,
startX: e.clientX,
startY: e.clientY,
startLeft: rect.left,
startTop: rect.top,
startWidth: rect.width,
startHeight: rect.height,
minWidth,
minHeight,
};
viewer.element.style.left = `${Math.round(rect.left)}px`;
viewer.element.style.top = `${Math.round(rect.top)}px`;
viewer.element.style.right = "auto";
viewer.element.style.bottom = "auto";
viewer.element.classList.add("mjr-mfv--resizing");
viewer.element.style.cursor = viewer._resizeCursorForDirection(dir);
try {
viewer.element.setPointerCapture(e.pointerId);
} catch (err) {
console.debug?.(err);
}
};
const onPointerMove = (e) => {
if (!viewer.element || viewer._isPopped) return;
const state = viewer._resizeState;
if (!state) {
const dir = resolveDir(e);
viewer.element.style.cursor = dir ? viewer._resizeCursorForDirection(dir) : "";
return;
}
if (state.pointerId !== e.pointerId) return;
const dx = e.clientX - state.startX;
const dy = e.clientY - state.startY;
let width = state.startWidth;
let height = state.startHeight;
let left = state.startLeft;
let top = state.startTop;
if (state.dir.includes("e")) width = state.startWidth + dx;
if (state.dir.includes("s")) height = state.startHeight + dy;
if (state.dir.includes("w")) {
width = state.startWidth - dx;
left = state.startLeft + dx;
}
if (state.dir.includes("n")) {
height = state.startHeight - dy;
top = state.startTop + dy;
}
if (width < state.minWidth) {
if (state.dir.includes("w")) left -= state.minWidth - width;
width = state.minWidth;
}
if (height < state.minHeight) {
if (state.dir.includes("n")) top -= state.minHeight - height;
height = state.minHeight;
}
width = Math.min(width, Math.max(state.minWidth, window.innerWidth));
height = Math.min(height, Math.max(state.minHeight, window.innerHeight));
left = Math.min(Math.max(0, left), Math.max(0, window.innerWidth - width));
top = Math.min(Math.max(0, top), Math.max(0, window.innerHeight - height));
viewer.element.style.width = `${Math.round(width)}px`;
viewer.element.style.height = `${Math.round(height)}px`;
viewer.element.style.left = `${Math.round(left)}px`;
viewer.element.style.top = `${Math.round(top)}px`;
viewer.element.style.right = "auto";
viewer.element.style.bottom = "auto";
};
const onPointerEnd = (e) => {
if (!viewer.element || !viewer._resizeState) return;
if (viewer._resizeState.pointerId !== e.pointerId) return;
const dir = resolveDir(e);
viewer._stopEdgeResize();
if (dir) viewer.element.style.cursor = viewer._resizeCursorForDirection(dir);
};
el.addEventListener("pointerdown", onPointerDown, { capture: true, signal });
el.addEventListener("pointermove", onPointerMove, { signal });
el.addEventListener("pointerup", onPointerEnd, { signal });
el.addEventListener("pointercancel", onPointerEnd, { signal });
el.addEventListener(
"pointerleave",
() => {
if (!viewer._resizeState && viewer.element) viewer.element.style.cursor = "";
},
{ signal },
);
}
export function initFloatingViewerDrag(viewer, handle) {
if (!handle) return;
const signal = viewer._panelAC?.signal;
let dragAC = null;
handle.addEventListener(
"pointerdown",
(e) => {
if (e.button !== 0) return;
if (e.target.closest("button")) return;
if (e.target.closest("select")) return;
if (viewer._isPopped || !viewer.element) return;
const edgeDir = viewer._getResizeDirectionFromPoint(
e.clientX,
e.clientY,
viewer.element.getBoundingClientRect(),
);
if (edgeDir) return;
e.preventDefault();
handle.setPointerCapture(e.pointerId);
try {
dragAC?.abort();
} catch {}
dragAC = new AbortController();
const dragSig = dragAC.signal;
const el = viewer.element;
const rect = el.getBoundingClientRect();
const offX = e.clientX - rect.left;
const offY = e.clientY - rect.top;
const onMove = (me) => {
const x = Math.min(
window.innerWidth - el.offsetWidth,
Math.max(0, me.clientX - offX),
);
const y = Math.min(
window.innerHeight - el.offsetHeight,
Math.max(0, me.clientY - offY),
);
el.style.left = `${x}px`;
el.style.top = `${y}px`;
el.style.right = "auto";
el.style.bottom = "auto";
};
const onUp = () => {
try {
dragAC?.abort();
} catch {}
};
handle.addEventListener("pointermove", onMove, { signal: dragSig });
handle.addEventListener("pointerup", onUp, { signal: dragSig });
},
signal ? { signal } : undefined,
);
}