feat(files-editor): mount auto-language editor + dropdown override

The modal textarea opts in with data-editor-language=auto; the editor
derives the language from the filename extension on each modal open.
A dropdown lets the user override (srccfg / bash / plain). The
existing fetch-based /files/save path is unchanged — files-overlay.js
keeps reading textarea.value, which the editor mirrors.
This commit is contained in:
mwiegand 2026-05-16 20:51:35 +02:00
parent 10cf0da3d2
commit 3c882e020c
No known key found for this signature in database
2 changed files with 35 additions and 4 deletions

View file

@ -281,6 +281,16 @@
saveBtn: editorDialog.querySelector(".files-editor-save"), saveBtn: editorDialog.querySelector(".files-editor-save"),
}; };
function setEditorContent(text) {
const editor = editorEls.contentBox._codeEditor;
if (editor) {
editor.setValue(text);
editor.setLanguage("auto"); // re-derive from filename
} else {
editorEls.contentBox.value = text;
}
}
function setEditorTitle(text) { function setEditorTitle(text) {
editorEls.title.textContent = text; editorEls.title.textContent = text;
} }
@ -342,7 +352,7 @@
setEditorTitle(`${folder ? folder + "/" : ""}…new file`); setEditorTitle(`${folder ? folder + "/" : ""}…new file`);
editorEls.filename.value = ""; editorEls.filename.value = "";
editorEls.filename.disabled = false; editorEls.filename.disabled = false;
editorEls.contentBox.value = ""; setEditorContent("");
editorEls.contentBox.disabled = false; editorEls.contentBox.disabled = false;
editorEls.renameHint.hidden = true; editorEls.renameHint.hidden = true;
editorEls.textPanel.hidden = false; editorEls.textPanel.hidden = false;
@ -375,14 +385,14 @@
editor.mode = "text"; editor.mode = "text";
editorEls.textPanel.hidden = false; editorEls.textPanel.hidden = false;
editorEls.binaryPanel.hidden = true; editorEls.binaryPanel.hidden = true;
editorEls.contentBox.value = "Loading…"; setEditorContent("Loading…");
editorEls.contentBox.disabled = true; editorEls.contentBox.disabled = true;
const r = await fetchJson( const r = await fetchJson(
`${baseUrl}/files/content?path=${encodeURIComponent(path)}` `${baseUrl}/files/content?path=${encodeURIComponent(path)}`
); );
if (r.ok && r.body) { if (r.ok && r.body) {
editorEls.contentBox.value = r.body.content; setEditorContent(r.body.content);
editorEls.contentBox.disabled = false; editorEls.contentBox.disabled = false;
updateByteCount(); updateByteCount();
updateSaveEnabled(); updateSaveEnabled();
@ -407,9 +417,21 @@
setTimeout(() => editorEls.filename.focus(), 0); setTimeout(() => editorEls.filename.focus(), 0);
} }
const languageSelect = document.querySelector(".files-editor-language");
if (languageSelect) {
languageSelect.addEventListener("change", function () {
const editor = editorEls.contentBox._codeEditor;
if (editor) editor.setLanguage(languageSelect.value);
});
}
editorEls.filename.addEventListener("input", () => { editorEls.filename.addEventListener("input", () => {
updateRenameHint(); updateRenameHint();
updateSaveEnabled(); updateSaveEnabled();
const _editor = editorEls.contentBox._codeEditor;
if (_editor && languageSelect && languageSelect.value === "auto") {
_editor.setLanguage("auto");
}
}); });
editorEls.contentBox.addEventListener("input", () => { editorEls.contentBox.addEventListener("input", () => {
updateByteCount(); updateByteCount();

View file

@ -175,7 +175,16 @@
<div class="files-editor-text"> <div class="files-editor-text">
<label class="files-editor-field"> <label class="files-editor-field">
<span class="files-field-label">Content</span> <span class="files-field-label">Content</span>
<textarea class="files-editor-content" rows="14" spellcheck="false"></textarea> <textarea class="files-editor-content" rows="14" spellcheck="false" data-editor-language="auto"></textarea>
</label>
<label class="files-editor-field files-editor-language-field">
<span class="files-field-label">Language</span>
<select class="files-editor-language editor-language-select">
<option value="auto" selected>Auto (from filename)</option>
<option value="srccfg">Source config (.cfg)</option>
<option value="bash">Bash (.sh)</option>
<option value="plain">Plain text</option>
</select>
</label> </label>
<div class="files-editor-meta muted"> <div class="files-editor-meta muted">
<span class="files-editor-byte-count">UTF-8 · 0 bytes</span> <span class="files-editor-byte-count">UTF-8 · 0 bytes</span>