Two changes to the form tool's submit path:
- Submit button hides when /.profile/access?path=<submission dir>
reports no 'c' verb. The form-status line surfaces a short
explanation so the user knows why the button disappeared.
- 403 on POST routes through zddc.cap.handleForbidden, which
renders an error toast naming the missing verb and offers
Elevate when the path-scoped view reports an elevation grant
covering it. The existing "You are not allowed to submit here"
status line still appears as the in-form indicator.
Also guards shared/cap.js's fetchAccess against file:// URLs —
calling fetch() on a file:// page logs a browser-level error that
shows up as test-runner noise. Short-circuiting to null lets
offline tools (browse on a picked folder, form opened standalone
from a file URL) silently degrade to "no path-scoped info" and
fall back to whatever existing gate they had.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
82 lines
3 KiB
JavaScript
82 lines
3 KiB
JavaScript
(function (app) {
|
|
'use strict';
|
|
|
|
function showStatus(msg, kind) {
|
|
const el = document.getElementById('form-status');
|
|
if (!el) {
|
|
return;
|
|
}
|
|
el.textContent = msg || '';
|
|
el.hidden = !msg;
|
|
el.classList.remove('is-error', 'is-success');
|
|
if (kind === 'error') {
|
|
el.classList.add('is-error');
|
|
} else if (kind === 'success') {
|
|
el.classList.add('is-success');
|
|
}
|
|
}
|
|
|
|
async function submit() {
|
|
if (!app.context || !app.context.submitUrl) {
|
|
showStatus('No submit URL configured.', 'error');
|
|
return;
|
|
}
|
|
const data = app.modules.serialize.read();
|
|
app.modules.errors.clear();
|
|
showStatus('', '');
|
|
|
|
const submitBtn = document.getElementById('submit-btn');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = true;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch(app.context.submitUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
if (res.status === 200) {
|
|
showStatus('Saved.', 'success');
|
|
} else if (res.status === 201) {
|
|
const loc = res.headers.get('Location');
|
|
showStatus('Submitted.', 'success');
|
|
if (loc) {
|
|
// Capability URL for the new submission. Append .html to land
|
|
// on the form-rendered view of the just-saved data.
|
|
setTimeout(function () {
|
|
window.location.href = loc + '.html';
|
|
}, 400);
|
|
}
|
|
} else if (res.status === 422) {
|
|
let body = {};
|
|
try { body = await res.json(); } catch (e) { /* ignore */ }
|
|
app.modules.errors.apply(body.errors || []);
|
|
showStatus('Please correct the errors below.', 'error');
|
|
} else if (res.status === 403) {
|
|
showStatus('You are not allowed to submit here.', 'error');
|
|
if (window.zddc && window.zddc.cap) {
|
|
window.zddc.cap.handleForbidden(res, {
|
|
context: 'Submit',
|
|
path: app.context.submitUrl
|
|
});
|
|
}
|
|
} else if (res.status === 409) {
|
|
showStatus('A submission with this filename already exists.', 'error');
|
|
} else {
|
|
let detail = '';
|
|
try { detail = await res.text(); } catch (e) { /* ignore */ }
|
|
showStatus('Submission failed (' + res.status + ')' + (detail ? ': ' + detail : ''), 'error');
|
|
}
|
|
} catch (err) {
|
|
showStatus('Network error: ' + (err && err.message ? err.message : err), 'error');
|
|
} finally {
|
|
if (submitBtn) {
|
|
submitBtn.disabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
app.modules.post = { submit: submit, showStatus: showStatus };
|
|
})(window.formApp);
|