Wherry/frontend/js/components/opDialogs.js
2026-07-11 00:01:26 +03:00

158 lines
5.1 KiB
JavaScript

// New Folder / Rename / Delete-confirm modals — shared by local and remote
// panes, applied to whichever side is `state.opTarget`.
import { state, notify } from "../store.js";
import { t } from "../i18n.js";
import { iconMarkup } from "../icons.js";
import { doMkdir, doRename, doDelete } from "../fsActions.js";
import { escapeHtml as escapeAttr } from "../dom.js";
let overlayEl = null;
let lastSig = null;
export function openMkdir() {
state.dialog = { kind: "mkdir", value: "" };
notify();
}
export function openRename(name) {
state.dialog = { kind: "rename", oldName: name, value: name };
notify();
}
export function openDelete(names) {
// Settings → General → "Confirm before delete" off skips the modal
// entirely instead of just pre-answering it.
if (!state.settings.confirmBeforeDelete) {
doDelete(names);
return;
}
state.dialog = { kind: "delete", names };
notify();
}
export function closeDialog() {
state.dialog = null;
notify();
}
async function submit() {
const d = state.dialog;
if (!d) return;
if (d.kind === "mkdir") {
const name = d.value.trim();
if (!name) return;
closeDialog();
await doMkdir(name);
} else if (d.kind === "rename") {
const name = d.value.trim();
if (!name || name === d.oldName) {
closeDialog();
return;
}
closeDialog();
await doRename(d.oldName, name);
} else if (d.kind === "delete") {
closeDialog();
await doDelete(d.names);
}
notify();
}
function buildMkdirOrRename(d) {
const isRename = d.kind === "rename";
const overlay = document.createElement("div");
overlay.className = "overlay";
overlay.addEventListener("mousedown", (e) => {
if (e.target === overlay) closeDialog();
});
const dialog = document.createElement("div");
dialog.className = "dialog dialog-sm";
dialog.addEventListener("mousedown", (e) => e.stopPropagation());
dialog.innerHTML = `
<div class="dialog-header">
<span class="icon icon--important">${iconMarkup(isRename ? "pen" : "folderAdd", 15)}</span>
<span class="dialog-title">${isRename ? t("dialogs.renameTitle") : t("dialogs.newFolderTitle")}</span>
</div>
<div class="dialog-body">
<input class="field-input" data-field="value" type="text" value="${escapeAttr(d.value)}"
placeholder="${isRename ? t("dialogs.renamePlaceholder") : t("dialogs.newFolderPlaceholder")}" />
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-ghost" data-action="close">${t("common.cancel")}</button>
<div class="spacer"></div>
<button type="button" class="btn btn-accent" data-action="submit">${t("common.ok")}</button>
</div>
`;
overlay.appendChild(dialog);
dialog.querySelector('[data-action="close"]').addEventListener("click", closeDialog);
dialog.querySelector('[data-action="submit"]').addEventListener("click", submit);
const input = dialog.querySelector('[data-field="value"]');
input.addEventListener("input", () => {
state.dialog.value = input.value;
});
dialog.addEventListener("keydown", (e) => {
if (e.key === "Enter") submit();
});
document.body.appendChild(overlay);
setTimeout(() => {
input.focus();
if (isRename) {
const dot = input.value.lastIndexOf(".");
input.setSelectionRange(0, dot > 0 ? dot : input.value.length);
} else {
input.select();
}
}, 0);
return overlay;
}
function buildDelete(d) {
const overlay = document.createElement("div");
overlay.className = "overlay";
overlay.addEventListener("mousedown", (e) => {
if (e.target === overlay) closeDialog();
});
const dialog = document.createElement("div");
dialog.className = "dialog dialog-sm";
dialog.addEventListener("mousedown", (e) => e.stopPropagation());
const title =
d.names.length === 1
? t("dialogs.deleteTitle", { name: escapeAttr(d.names[0]) })
: t("dialogs.deleteTitleMulti", { n: d.names.length });
dialog.innerHTML = `
<div class="dialog-header">
<span class="icon text-red">${iconMarkup("dangerTriangle", 15)}</span>
<span class="dialog-title">${title}</span>
</div>
<div class="dialog-body">
<p class="dialog-text">${t("dialogs.deleteBody")}</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-ghost" data-action="close">${t("common.cancel")}</button>
<div class="spacer"></div>
<button type="button" class="btn btn-danger" data-action="submit">${t("common.delete")}</button>
</div>
`;
overlay.appendChild(dialog);
dialog.querySelector('[data-action="close"]').addEventListener("click", closeDialog);
dialog.querySelector('[data-action="submit"]').addEventListener("click", submit);
document.body.appendChild(overlay);
return overlay;
}
export function renderOpDialogs() {
const sig = JSON.stringify(
state.dialog ? { kind: state.dialog.kind, names: state.dialog.names, oldName: state.dialog.oldName } : null,
);
if (sig === lastSig) return;
lastSig = sig;
if (overlayEl) {
overlayEl.remove();
overlayEl = null;
}
if (!state.dialog) return;
overlayEl =
state.dialog.kind === "delete" ? buildDelete(state.dialog) : buildMkdirOrRename(state.dialog);
}