Use checkbox permission editor
This commit is contained in:
+96
-16
@@ -1025,7 +1025,7 @@ function openPermissionsDialog(win, entry) {
|
||||
state.permissionsDialog = {
|
||||
winId: win.id,
|
||||
entries,
|
||||
mode: entry.permissions ? `0${entry.permissions}`.slice(-4) : '0755',
|
||||
mode: normalizeMode(entry.permissions || '0755'),
|
||||
owner: entry.owner || '',
|
||||
group: entry.group || '',
|
||||
recursive: false,
|
||||
@@ -1048,15 +1048,13 @@ function renderPermissionsDialog() {
|
||||
<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>
|
||||
<span>Berechtigungen ändern</span>
|
||||
</label>
|
||||
${permissionMatrixMarkup(dialog.mode)}
|
||||
<label class="field-row">
|
||||
<span>Numerischer Wert</span>
|
||||
<input name="mode" class="mode-input" inputmode="numeric" pattern="[0-7]{3,4}" value="${escapeAttr(dialog.mode)}" aria-label="Numerischer Wert">
|
||||
</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>
|
||||
@@ -1094,13 +1092,7 @@ function renderPermissionsDialog() {
|
||||
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;
|
||||
});
|
||||
}
|
||||
bindPermissionMatrix(form);
|
||||
form.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
applyPermissionsDialog(form).catch(showError);
|
||||
@@ -1108,6 +1100,94 @@ function renderPermissionsDialog() {
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function permissionMatrixMarkup(mode) {
|
||||
const digits = modeToDigits(mode);
|
||||
const rows = [
|
||||
['owner', 'Besitzer-Berechtigungen', digits[0]],
|
||||
['group', 'Gruppen-Berechtigungen', digits[1]],
|
||||
['public', 'Öffentliche Berechtigungen', digits[2]]
|
||||
];
|
||||
return rows.map(([scope, label, digit]) => `
|
||||
<fieldset class="permission-scope" data-scope="${scope}">
|
||||
<legend>${label}</legend>
|
||||
${permissionCheck(scope, 'read', 'Lesen', digit & 4)}
|
||||
${permissionCheck(scope, 'write', 'Schreiben', digit & 2)}
|
||||
${permissionCheck(scope, 'execute', 'Ausführen', digit & 1)}
|
||||
</fieldset>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function permissionCheck(scope, bit, label, checked) {
|
||||
return `
|
||||
<label>
|
||||
<input type="checkbox" data-permission="${scope}.${bit}" ${checked ? 'checked' : ''}>
|
||||
<span>${label}</span>
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
|
||||
function bindPermissionMatrix(form) {
|
||||
const changeMode = form.elements.changeMode;
|
||||
const modeInput = form.elements.mode;
|
||||
const permissionInputs = [...form.querySelectorAll('[data-permission]')];
|
||||
const setModeDisabled = () => {
|
||||
modeInput.disabled = !changeMode.checked;
|
||||
for (const input of permissionInputs) {
|
||||
input.disabled = !changeMode.checked;
|
||||
}
|
||||
};
|
||||
changeMode.addEventListener('change', setModeDisabled);
|
||||
for (const input of permissionInputs) {
|
||||
input.addEventListener('change', () => {
|
||||
changeMode.checked = true;
|
||||
setModeDisabled();
|
||||
modeInput.value = modeFromPermissionInputs(form);
|
||||
});
|
||||
}
|
||||
modeInput.addEventListener('input', () => {
|
||||
changeMode.checked = true;
|
||||
setModeDisabled();
|
||||
syncPermissionInputsFromMode(form, modeInput.value);
|
||||
});
|
||||
setModeDisabled();
|
||||
}
|
||||
|
||||
function modeFromPermissionInputs(form) {
|
||||
const scopes = ['owner', 'group', 'public'];
|
||||
const values = scopes.map((scope) => {
|
||||
let value = 0;
|
||||
if (form.querySelector(`[data-permission="${scope}.read"]`)?.checked) value += 4;
|
||||
if (form.querySelector(`[data-permission="${scope}.write"]`)?.checked) value += 2;
|
||||
if (form.querySelector(`[data-permission="${scope}.execute"]`)?.checked) value += 1;
|
||||
return String(value);
|
||||
});
|
||||
return values.join('');
|
||||
}
|
||||
|
||||
function syncPermissionInputsFromMode(form, mode) {
|
||||
if (!/^[0-7]{3,4}$/.test(mode)) return;
|
||||
const digits = modeToDigits(mode);
|
||||
for (const [index, scope] of ['owner', 'group', 'public'].entries()) {
|
||||
const digit = digits[index];
|
||||
const map = { read: 4, write: 2, execute: 1 };
|
||||
for (const [bit, value] of Object.entries(map)) {
|
||||
const input = form.querySelector(`[data-permission="${scope}.${bit}"]`);
|
||||
if (input) input.checked = Boolean(digit & value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeMode(mode) {
|
||||
const value = String(mode || '');
|
||||
if (!/^[0-7]{3,4}$/.test(value)) return '755';
|
||||
return value.length === 4 ? value.slice(1) : value;
|
||||
}
|
||||
|
||||
function modeToDigits(mode) {
|
||||
const normalized = normalizeMode(mode);
|
||||
return normalized.split('').slice(-3).map((digit) => Number(digit));
|
||||
}
|
||||
|
||||
function closePermissionsDialog() {
|
||||
state.permissionsDialog = null;
|
||||
render();
|
||||
|
||||
Reference in New Issue
Block a user