Add permissions editor modal

This commit is contained in:
Mikei386
2026-06-23 14:55:59 +02:00
parent 1e20799499
commit 5f014911a5
6 changed files with 216 additions and 19 deletions
+112 -16
View File
@@ -11,6 +11,7 @@ const state = {
focusedId: null,
selectedEntry: null,
contextMenu: null,
permissionsDialog: null,
draggedEntry: null,
pointerDrag: null,
suppressClickPath: null,
@@ -191,6 +192,9 @@ function render() {
if (state.contextMenu) {
workspace.appendChild(renderContextMenu());
}
if (state.permissionsDialog) {
workspace.appendChild(renderPermissionsDialog());
}
renderTransferPanel();
renderSettingsPanel();
}
@@ -1012,32 +1016,124 @@ async function promptTransfer(win, entry, type) {
await createJob(type, entry.path, `${targetDir.replace(/\/$/, '')}/${entry.name}`, []);
}
async function promptPermissions(win, entry) {
function openPermissionsDialog(win, entry) {
if (isReadOnly()) {
showError(new Error('Read-only mode ist aktiv.'));
return;
}
const entries = selectedPathSet(win).has(entry.path) ? selectedEntries(win) : [entry];
const mode = prompt('Berechtigungen als Oktalmodus, z.B. 0644 oder 0755', entry.permissions ? `0${entry.permissions}`.slice(-4) : '');
if (mode === null) return;
const owner = prompt('Besitzer ändern, leer lassen für unverändert', entry.owner || '');
if (owner === null) return;
const group = prompt('Gruppe ändern, leer lassen für unverändert', entry.group || '');
if (group === null) return;
const hasDirectory = entries.some((item) => item.type === 'directory');
const recursive = hasDirectory && confirm('Rekursiv auf Unterordner und Dateien anwenden?');
state.permissionsDialog = {
winId: win.id,
entries,
mode: entry.permissions ? `0${entry.permissions}`.slice(-4) : '0755',
owner: entry.owner || '',
group: entry.group || '',
recursive: false,
hasDirectory: entries.some((item) => item.type === 'directory')
};
render();
}
function renderPermissionsDialog() {
const dialog = state.permissionsDialog;
const overlay = document.createElement('div');
overlay.className = 'modal-overlay';
overlay.innerHTML = `
<form class="permissions-modal" aria-label="Berechtigungen ändern">
<header>
<strong>Berechtigungen ändern</strong>
<button type="button" class="icon" data-action="cancel" title="Schließen" aria-label="Schließen">×</button>
</header>
<div class="modal-body">
<p class="muted">${dialog.entries.length === 1 ? escapeHtml(dialog.entries[0].name) : `${dialog.entries.length} Objekte ausgewählt`}</p>
<label class="check-row">
<input type="checkbox" name="changeMode" checked>
<span>Modus ändern</span>
</label>
<input name="mode" inputmode="numeric" pattern="[0-7]{3,4}" value="${escapeAttr(dialog.mode)}" aria-label="Oktalmodus">
<div class="permission-presets" aria-label="Schnellauswahl">
<button type="button" data-mode="0644">0644</button>
<button type="button" data-mode="0755">0755</button>
<button type="button" data-mode="0775">0775</button>
<button type="button" data-mode="0777">0777</button>
</div>
<label class="check-row">
<input type="checkbox" name="changeOwner">
<span>Besitzer ändern</span>
</label>
<input name="owner" value="${escapeAttr(dialog.owner)}" aria-label="Besitzer" disabled>
<label class="check-row">
<input type="checkbox" name="changeGroup">
<span>Gruppe ändern</span>
</label>
<input name="group" value="${escapeAttr(dialog.group)}" aria-label="Gruppe" disabled>
<label class="check-row ${dialog.hasDirectory ? '' : 'disabled'}">
<input type="checkbox" name="recursive" ${dialog.hasDirectory ? '' : 'disabled'}>
<span>Rekursiv auf Unterordner und Dateien anwenden</span>
</label>
</div>
<footer>
<button type="button" data-action="cancel">Abbrechen</button>
<button type="submit" class="primary">Anwenden</button>
</footer>
</form>
`;
const form = overlay.querySelector('form');
form.addEventListener('click', (event) => event.stopPropagation());
overlay.addEventListener('click', () => closePermissionsDialog());
overlay.querySelectorAll('[data-action="cancel"]').forEach((button) => {
button.addEventListener('click', () => closePermissionsDialog());
});
for (const checkboxName of ['changeMode', 'changeOwner', 'changeGroup']) {
const checkbox = form.elements[checkboxName];
const inputName = checkboxName.replace('change', '').toLowerCase();
const input = form.elements[inputName];
checkbox.addEventListener('change', () => {
input.disabled = !checkbox.checked;
if (!input.disabled) input.focus();
});
}
for (const button of overlay.querySelectorAll('[data-mode]')) {
button.addEventListener('click', () => {
form.elements.changeMode.checked = true;
form.elements.mode.disabled = false;
form.elements.mode.value = button.dataset.mode;
});
}
form.addEventListener('submit', (event) => {
event.preventDefault();
applyPermissionsDialog(form).catch(showError);
});
return overlay;
}
function closePermissionsDialog() {
state.permissionsDialog = null;
render();
}
async function applyPermissionsDialog(form) {
const dialog = state.permissionsDialog;
if (!dialog) return;
const options = {
mode: mode.trim(),
owner: owner.trim(),
group: group.trim(),
recursive: recursive ? '1' : '0'
mode: form.elements.changeMode.checked ? form.elements.mode.value.trim() : '',
owner: form.elements.changeOwner.checked ? form.elements.owner.value.trim() : '',
group: form.elements.changeGroup.checked ? form.elements.group.value.trim() : '',
recursive: form.elements.recursive.checked ? '1' : '0'
};
if (!options.mode && !options.owner && !options.group) {
showError(new Error('Keine Änderung angegeben.'));
return;
}
for (const item of entries) {
await createJob('permissions', item.path, null, [win.id], options);
if (options.mode && !/^[0-7]{3,4}$/.test(options.mode)) {
showError(new Error('Berechtigungen müssen aus 3 oder 4 Oktalziffern bestehen.'));
return;
}
const win = state.windows.find((item) => item.id === dialog.winId);
closePermissionsDialog();
for (const item of dialog.entries) {
await createJob('permissions', item.path, null, [win?.id], options);
}
}
@@ -1076,7 +1172,7 @@ function renderContextMenu() {
actions.push(['Eigenschaften', () => showPropertiesForEntry(win, entry)]);
if (!isReadOnly()) {
actions.push(['Umbenennen', () => renameEntry(win, entry)]);
actions.push(['Berechtigungen...', () => promptPermissions(win, entry)]);
actions.push(['Berechtigungen...', () => openPermissionsDialog(win, entry)]);
actions.push(['Kopieren nach...', () => promptTransfer(win, entry, 'copy')]);
actions.push(['Verschieben nach...', () => promptTransfer(win, entry, 'move')]);
}