mirror of
https://github.com/Horizontal42/summarum.git
synced 2026-11-11 01:02:01 +03:00
fix: sheet drag-and-drop showed a blocked cursor and never dropped
Tauri's window-level file-drop hook (needed for dragging a .numi file in from Explorer) intercepts WebView2's own drag-and-drop session, so native HTML5 draggable="true" elements never get a valid drop target inside the webview — the OS always shows "not allowed", confirmed with an actual mouse-drag simulation before this fix. Replaced with plain pointer tracking (mousedown/mousemove/mouseup), the same pattern already used for the results-column divider — full control over the cursor and the drag-over indicator, no dependency on the webview's native DnD stack, and it doesn't touch the unrelated OS file-drop feature at all.
This commit is contained in:
parent
7b94f6a5b0
commit
ad8e1960d7
1 changed files with 47 additions and 26 deletions
69
src/main.ts
69
src/main.ts
|
|
@ -94,15 +94,12 @@ function reorderDoc(srcId: string, targetId: string): void {
|
||||||
renderDocList();
|
renderDocList();
|
||||||
}
|
}
|
||||||
|
|
||||||
let dragSrcId: string | null = null;
|
|
||||||
|
|
||||||
function renderDocList(): void {
|
function renderDocList(): void {
|
||||||
const list = $("#doc-list");
|
const list = $("#doc-list");
|
||||||
list.replaceChildren();
|
list.replaceChildren();
|
||||||
for (const doc of data.docs) {
|
for (const doc of data.docs) {
|
||||||
const el = document.createElement("div");
|
const el = document.createElement("div");
|
||||||
el.className = "doc-item" + (doc.id === data.activeId ? " active" : "") + (doc.pinned ? " pinned" : "");
|
el.className = "doc-item" + (doc.id === data.activeId ? " active" : "") + (doc.pinned ? " pinned" : "");
|
||||||
el.draggable = true;
|
|
||||||
const name = document.createElement("span");
|
const name = document.createElement("span");
|
||||||
name.className = "doc-name";
|
name.className = "doc-name";
|
||||||
name.textContent = doc.title || t("untitled");
|
name.textContent = doc.title || t("untitled");
|
||||||
|
|
@ -119,30 +116,55 @@ function renderDocList(): void {
|
||||||
|
|
||||||
el.appendChild(mkBtn("pin-btn" + (doc.pinned ? " active" : ""), "📌", doc.pinned ? t("unpin") : t("pin"), () => pinDoc(doc.id)));
|
el.appendChild(mkBtn("pin-btn" + (doc.pinned ? " active" : ""), "📌", doc.pinned ? t("unpin") : t("pin"), () => pinDoc(doc.id)));
|
||||||
|
|
||||||
el.addEventListener("dragstart", (e) => {
|
// Reordering uses plain mouse tracking, not the native HTML5 drag API —
|
||||||
dragSrcId = doc.id;
|
// Tauri's window-level file-drop hook (dragDropEnabled, needed for
|
||||||
|
// dropping .numi files from Explorer) intercepts WebView2's own drag
|
||||||
|
// sessions, so draggable="true" elements never get a valid drop target
|
||||||
|
// and the OS always shows a "not allowed" cursor.
|
||||||
|
let dragging = false;
|
||||||
|
let suppressClick = false;
|
||||||
|
el.addEventListener("mousedown", (e) => {
|
||||||
|
if ((e.target as HTMLElement).closest("button")) return;
|
||||||
|
const startY = e.clientY;
|
||||||
|
const onMove = (ev: MouseEvent) => {
|
||||||
|
if (!dragging) {
|
||||||
|
if (Math.abs(ev.clientY - startY) < 4) return;
|
||||||
|
dragging = true;
|
||||||
|
suppressClick = true;
|
||||||
el.classList.add("dragging");
|
el.classList.add("dragging");
|
||||||
e.dataTransfer!.effectAllowed = "move";
|
document.body.style.cursor = "grabbing";
|
||||||
e.dataTransfer?.setData("text/plain", doc.id);
|
}
|
||||||
|
const items = [...list.querySelectorAll<HTMLElement>(".doc-item")];
|
||||||
|
for (const item of items) item.classList.remove("drag-over");
|
||||||
|
const over = items.find((item) => {
|
||||||
|
if (item === el) return false;
|
||||||
|
const r = item.getBoundingClientRect();
|
||||||
|
return ev.clientY >= r.top && ev.clientY <= r.bottom;
|
||||||
});
|
});
|
||||||
el.addEventListener("dragend", () => {
|
if (over) {
|
||||||
el.classList.remove("dragging");
|
const overDoc = data.docs.find((d) => d.id === over.dataset.docId);
|
||||||
dragSrcId = null;
|
if (overDoc && !!overDoc.pinned === !!doc.pinned) over.classList.add("drag-over");
|
||||||
for (const other of list.querySelectorAll(".doc-item")) other.classList.remove("drag-over");
|
}
|
||||||
|
};
|
||||||
|
const onUp = () => {
|
||||||
|
window.removeEventListener("mousemove", onMove);
|
||||||
|
window.removeEventListener("mouseup", onUp);
|
||||||
|
if (dragging) {
|
||||||
|
const target = list.querySelector<HTMLElement>(".doc-item.drag-over");
|
||||||
|
for (const item of list.querySelectorAll(".doc-item")) item.classList.remove("drag-over", "dragging");
|
||||||
|
document.body.style.cursor = "";
|
||||||
|
if (target?.dataset.docId) reorderDoc(doc.id, target.dataset.docId);
|
||||||
|
}
|
||||||
|
dragging = false;
|
||||||
|
};
|
||||||
|
window.addEventListener("mousemove", onMove);
|
||||||
|
window.addEventListener("mouseup", onUp);
|
||||||
});
|
});
|
||||||
el.addEventListener("dragover", (e) => {
|
el.addEventListener("click", () => {
|
||||||
if (!dragSrcId || dragSrcId === doc.id) return;
|
if (suppressClick) { suppressClick = false; return; }
|
||||||
const src = data.docs.find((d) => d.id === dragSrcId);
|
switchDoc(doc.id);
|
||||||
if (!src || !!src.pinned !== !!doc.pinned) return; // can't cross the pin boundary
|
|
||||||
e.preventDefault(); // allow drop
|
|
||||||
for (const other of list.querySelectorAll(".doc-item")) other.classList.remove("drag-over");
|
|
||||||
el.classList.add("drag-over");
|
|
||||||
});
|
|
||||||
el.addEventListener("drop", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
el.classList.remove("drag-over");
|
|
||||||
if (dragSrcId) reorderDoc(dragSrcId, doc.id);
|
|
||||||
});
|
});
|
||||||
|
el.dataset.docId = doc.id;
|
||||||
|
|
||||||
const del = document.createElement("button");
|
const del = document.createElement("button");
|
||||||
del.className = "del";
|
del.className = "del";
|
||||||
|
|
@ -169,7 +191,6 @@ function renderDocList(): void {
|
||||||
saveAppData(data);
|
saveAppData(data);
|
||||||
});
|
});
|
||||||
el.appendChild(del);
|
el.appendChild(del);
|
||||||
el.addEventListener("click", () => switchDoc(doc.id));
|
|
||||||
list.appendChild(el);
|
list.appendChild(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue