192 lines
6.4 KiB
JavaScript
192 lines
6.4 KiB
JavaScript
(function () {
|
|
const key = "mail-graveyard-pane-widths-v2";
|
|
const minWidths = [160, 220, 300];
|
|
const handleWidth = 6;
|
|
|
|
function panes(container) {
|
|
return Array.from(container.querySelectorAll(".pane"));
|
|
}
|
|
|
|
function widthsFromDOM(container) {
|
|
return panes(container).map((pane) => Math.round(pane.getBoundingClientRect().width));
|
|
}
|
|
|
|
function clampWidths(widths, total) {
|
|
const next = widths.map((w, i) => Math.max(minWidths[i], Math.round(w || minWidths[i])));
|
|
const max = Math.max(total - handleWidth * (next.length - 1), minWidths.reduce((a, b) => a + b, 0));
|
|
const sum = next.reduce((a, b) => a + b, 0);
|
|
if (sum > max) {
|
|
let extra = sum - max;
|
|
for (let i = next.length - 1; i >= 0 && extra > 0; i--) {
|
|
const canTake = Math.max(0, next[i] - minWidths[i]);
|
|
const take = Math.min(canTake, extra);
|
|
next[i] -= take;
|
|
extra -= take;
|
|
}
|
|
}
|
|
return next;
|
|
}
|
|
|
|
function applyWidths(container, widths) {
|
|
const total = container.getBoundingClientRect().width;
|
|
const w = clampWidths(widths, total);
|
|
container.style.gridTemplateColumns =
|
|
`${w[0]}px ${handleWidth}px ${w[1]}px ${handleWidth}px minmax(${w[2]}px, 1fr)`;
|
|
localStorage.setItem(key, JSON.stringify(w));
|
|
}
|
|
|
|
function restore(container) {
|
|
try {
|
|
const saved = JSON.parse(localStorage.getItem(key) || "null");
|
|
if (Array.isArray(saved) && saved.length === 3) {
|
|
applyWidths(container, saved);
|
|
}
|
|
} catch (_) {
|
|
localStorage.removeItem(key);
|
|
}
|
|
}
|
|
|
|
function bind(container) {
|
|
if (!container || container.dataset.resizeBound === "1") return;
|
|
container.dataset.resizeBound = "1";
|
|
restore(container);
|
|
|
|
container.querySelectorAll(".pane-resizer").forEach((handle) => {
|
|
handle.addEventListener("pointerdown", (event) => {
|
|
if (window.matchMedia("(max-width: 820px)").matches) return;
|
|
event.preventDefault();
|
|
handle.setPointerCapture(event.pointerId);
|
|
handle.classList.add("dragging");
|
|
document.body.classList.add("resizing");
|
|
|
|
const index = Number(handle.dataset.resizeIndex || 0);
|
|
const startX = event.clientX;
|
|
const start = widthsFromDOM(container);
|
|
|
|
function move(moveEvent) {
|
|
const delta = moveEvent.clientX - startX;
|
|
const next = start.slice();
|
|
const left = Math.max(minWidths[index], start[index] + delta);
|
|
const used = left - start[index];
|
|
const right = Math.max(minWidths[index + 1], start[index + 1] - used);
|
|
const actual = start[index + 1] - right;
|
|
next[index] = start[index] + actual;
|
|
next[index + 1] = right;
|
|
applyWidths(container, next);
|
|
}
|
|
|
|
function up(upEvent) {
|
|
handle.releasePointerCapture(upEvent.pointerId);
|
|
handle.classList.remove("dragging");
|
|
document.body.classList.remove("resizing");
|
|
window.removeEventListener("pointermove", move);
|
|
window.removeEventListener("pointerup", up);
|
|
}
|
|
|
|
window.addEventListener("pointermove", move);
|
|
window.addEventListener("pointerup", up);
|
|
});
|
|
});
|
|
}
|
|
|
|
window.addEventListener("DOMContentLoaded", () => bind(document.querySelector(".four-pane")));
|
|
window.addEventListener("DOMContentLoaded", () => bind(document.querySelector(".three-pane")));
|
|
})();
|
|
|
|
(function () {
|
|
function setOpen(open) {
|
|
document.body.classList.toggle("backstage-open", open);
|
|
document.querySelectorAll("[data-backstage-toggle]").forEach((button) => {
|
|
button.setAttribute("aria-expanded", open ? "true" : "false");
|
|
});
|
|
}
|
|
|
|
document.addEventListener("click", (event) => {
|
|
const toggle = event.target.closest("[data-backstage-toggle]");
|
|
if (toggle) {
|
|
setOpen(!document.body.classList.contains("backstage-open"));
|
|
return;
|
|
}
|
|
if (event.target.closest("[data-backstage-close]")) {
|
|
setOpen(false);
|
|
}
|
|
});
|
|
|
|
document.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape") setOpen(false);
|
|
});
|
|
})();
|
|
|
|
(function () {
|
|
function rowPayload(row) {
|
|
return {
|
|
source: row.dataset.source || "",
|
|
folder: row.dataset.folder || "",
|
|
index: row.dataset.index || ""
|
|
};
|
|
}
|
|
|
|
document.addEventListener("dragstart", (event) => {
|
|
const row = event.target.closest(".msg-row[draggable='true']");
|
|
if (!row || !event.dataTransfer) return;
|
|
event.dataTransfer.effectAllowed = "copy";
|
|
event.dataTransfer.setData("application/json", JSON.stringify(rowPayload(row)));
|
|
event.dataTransfer.setData("text/plain", `${row.dataset.source || ""}/${row.dataset.folder || ""}#${row.dataset.index || ""}`);
|
|
row.classList.add("dragging");
|
|
});
|
|
|
|
document.addEventListener("dragend", (event) => {
|
|
const row = event.target.closest(".msg-row");
|
|
if (row) row.classList.remove("dragging");
|
|
});
|
|
|
|
document.addEventListener("dragover", (event) => {
|
|
const zone = event.target.closest("[data-drop-target='manual-copy']");
|
|
if (!zone) return;
|
|
event.preventDefault();
|
|
zone.classList.add("drag-over");
|
|
if (event.dataTransfer) event.dataTransfer.dropEffect = "copy";
|
|
});
|
|
|
|
document.addEventListener("dragleave", (event) => {
|
|
const zone = event.target.closest("[data-drop-target='manual-copy']");
|
|
if (zone) zone.classList.remove("drag-over");
|
|
});
|
|
|
|
document.addEventListener("drop", async (event) => {
|
|
const zone = event.target.closest("[data-drop-target='manual-copy']");
|
|
if (!zone) return;
|
|
event.preventDefault();
|
|
zone.classList.remove("drag-over");
|
|
|
|
let payload = {};
|
|
try {
|
|
payload = JSON.parse(event.dataTransfer.getData("application/json") || "{}");
|
|
} catch (_) {
|
|
payload = {};
|
|
}
|
|
if (!payload.source) {
|
|
payload = {
|
|
source: zone.dataset.source || "",
|
|
folder: zone.dataset.folder || "",
|
|
index: zone.dataset.index || ""
|
|
};
|
|
}
|
|
|
|
const select = document.querySelector("#target-account-select");
|
|
const form = new URLSearchParams();
|
|
form.set("source", payload.source);
|
|
form.set("folder", payload.folder);
|
|
form.set("index", payload.index);
|
|
form.set("target_account", select ? select.value : "");
|
|
zone.textContent = "Kopiere...";
|
|
|
|
const response = await fetch("/view/manual-copy", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" },
|
|
body: form.toString()
|
|
});
|
|
const html = await response.text();
|
|
document.querySelector("#read").innerHTML = html;
|
|
});
|
|
})();
|