Three bugs surfaced in browser testing, plus one UX request:
1. The Uploads panel and the binary-mode editor sub-panels stayed
visible after `el.hidden = true` because their `display: flex/grid`
rules in components.css have the same specificity as the UA's
`[hidden]{display:none}` and come later in cascade. Add a targeted
`[hidden]!important` rule for the affected classes.
2. Clicking a folder toggle inside a `files` overlay did nothing.
`file-tree.js` looked for `.file-tree-children` via
`button.nextElementSibling`, but the files-overlay row template
inserts a per-row action span between the toggle and the children
div. Switch to `closest('.file-tree-row').querySelector(':scope >
.file-tree-children')` so both row variants resolve correctly.
3. Pressing Enter on the new-folder dialog did nothing — the keydown
handler was attached with `{once:true}` inside `openNewFolder`,
so the first letter the user typed consumed the listener and Enter
never fired. Move the listener to module init so it survives
subsequent keystrokes and dialog reopenings.
UX: render the overlay root as a row inside the tree (label
"(overlay root)") rather than as a separate toolbar. The root row
carries the same `+ new file · + new folder · ⬇ zip` hover-action
column as every other folder row, so drop-on-row, hover-reveal, and
data-target-path semantics are uniform across the tree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
45 lines
1.9 KiB
JavaScript
45 lines
1.9 KiB
JavaScript
// Lazy-loaded collapsible file tree on overlay detail pages.
|
|
//
|
|
// One delegated click handler on document. Each `.file-tree-toggle` button
|
|
// carries `data-files-url`. First expand fires a fetch and innerHTMLs the
|
|
// returned partial into the next `.file-tree-children`; subsequent clicks
|
|
// just toggle visibility — no re-fetch.
|
|
//
|
|
// Children-div lookup goes through the row's <li> rather than the button's
|
|
// nextElementSibling so the files-overlay variant — where a per-row action
|
|
// column sits between the toggle button and the children div — works too.
|
|
(function () {
|
|
document.addEventListener("click", function (event) {
|
|
const button = event.target.closest(".file-tree-toggle");
|
|
if (!button) return;
|
|
|
|
const row = button.closest(".file-tree-row");
|
|
const children = row ? row.querySelector(":scope > .file-tree-children") : null;
|
|
if (!children) return;
|
|
|
|
const wasExpanded = button.getAttribute("aria-expanded") === "true";
|
|
button.setAttribute("aria-expanded", wasExpanded ? "false" : "true");
|
|
children.hidden = wasExpanded;
|
|
|
|
if (wasExpanded) return; // collapsing — nothing to fetch
|
|
if (button.dataset.loaded === "1") return; // already populated
|
|
const url = button.dataset.filesUrl;
|
|
if (!url) return;
|
|
|
|
button.dataset.loaded = "1"; // optimistic — prevents duplicate fetches on rapid clicks
|
|
fetch(url, { headers: { Accept: "text/html" }, credentials: "same-origin" })
|
|
.then(function (response) {
|
|
if (!response.ok) throw new Error("HTTP " + response.status);
|
|
return response.text();
|
|
})
|
|
.then(function (html) {
|
|
children.innerHTML = html;
|
|
})
|
|
.catch(function (err) {
|
|
delete button.dataset.loaded; // allow retry
|
|
children.innerHTML =
|
|
'<p class="muted">Failed to load directory contents.</p>';
|
|
console.error("file-tree:", err);
|
|
});
|
|
});
|
|
})();
|