The form renderer is server-driven: zddc-server's form handler injects schema/ui/data into <script id="form-context"> on every render. Standalone form/dist/form.html opened from file:// has no context and just rendered as a blank page below the header chrome — no orientation, no submit button affordance was hidden, but nothing labelled what the user was looking at. Detect the empty-context case in form/js/main.js, render a small .form-welcome card explaining that this tool is server-driven, and hide the now-meaningless Submit button. The card uses shared tokens (--bg, --border, --font-mono, etc.) so it themes correctly. Note: the unified tables.html bundle that hosts the form via the zddcMode dispatcher is unaffected — tables always sets zddcMode='form' or 'table' before form's main.js boots, so the welcome only fires for the standalone HTML. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
3.7 KiB
JavaScript
90 lines
3.7 KiB
JavaScript
(function (app) {
|
|
'use strict';
|
|
|
|
// Friendly empty-state shown when the form is opened standalone
|
|
// (file:// or otherwise without a server-injected #form-context
|
|
// payload). The form renderer is always driven by the host —
|
|
// zddc-server's form handler injects schema+ui+data; the tool has
|
|
// no client-side picker because there's nothing it could pick from
|
|
// outside that contract.
|
|
function renderStandaloneWelcome(root) {
|
|
if (!root) return;
|
|
root.innerHTML = '';
|
|
const wrap = document.createElement('div');
|
|
wrap.className = 'form-welcome';
|
|
wrap.innerHTML = [
|
|
'<h2>ZDDC Form Renderer</h2>',
|
|
'<p>This tool renders a form spec injected by <code>zddc-server</code>',
|
|
' at <code><name>.form.html</code> URLs. There is no schema',
|
|
' to render here — most likely you opened the standalone HTML directly.</p>',
|
|
'<h3>To use it</h3>',
|
|
'<ol>',
|
|
'<li>Run <code>zddc-server</code> against an archive that contains a',
|
|
' <code><name>.form.yaml</code> spec.</li>',
|
|
'<li>Visit <code><path>/<name>.form.html</code> in the browser.</li>',
|
|
'</ol>',
|
|
'<p>See <a href="https://zddc.varasys.io/reference.html" target="_blank" rel="noopener">',
|
|
'zddc.varasys.io/reference.html</a> for the full ZDDC reference.</p>'
|
|
].join('');
|
|
root.appendChild(wrap);
|
|
|
|
const submitBtn = document.getElementById('submit-btn');
|
|
if (submitBtn) submitBtn.hidden = true;
|
|
}
|
|
|
|
function boot() {
|
|
// When this bundle is hosted by the unified tables.html, the
|
|
// mode dispatcher decides which app paints. Skip when mode is
|
|
// not "form" — table-mode requests are handled by tablesApp.
|
|
// (Standalone form/dist/form.html has no zddcMode global; treat
|
|
// undefined as form-mode for back-compat.)
|
|
if (window.zddcMode && window.zddcMode !== 'form') {
|
|
return;
|
|
}
|
|
app.context = app.modules.context.load();
|
|
|
|
if (app.context.title) {
|
|
// Standalone form.html has #form-title in its header; unified
|
|
// tables.html bundle has #table-title (shared across modes).
|
|
// Whichever exists, write to it.
|
|
const t = document.getElementById('form-title') ||
|
|
document.getElementById('table-title');
|
|
if (t) {
|
|
t.textContent = app.context.title;
|
|
}
|
|
document.title = app.context.title + ' — ZDDC';
|
|
}
|
|
|
|
const root = document.getElementById('form-root');
|
|
if (root && app.context.schema) {
|
|
app.rootWidget = app.modules.render.mount(
|
|
root,
|
|
app.context.schema,
|
|
app.context.ui || {},
|
|
app.context.data
|
|
);
|
|
} else if (root) {
|
|
// No schema — server-injected context is empty. Most common
|
|
// when the standalone form.html is opened from file:// without
|
|
// a host. Show a friendly explanation instead of a blank page.
|
|
renderStandaloneWelcome(root);
|
|
return;
|
|
}
|
|
|
|
if (app.context.errors && app.context.errors.length) {
|
|
app.modules.errors.apply(app.context.errors);
|
|
app.modules.post.showStatus('Please correct the errors below.', 'error');
|
|
}
|
|
|
|
const submitBtn = document.getElementById('submit-btn');
|
|
if (submitBtn) {
|
|
submitBtn.addEventListener('click', app.modules.post.submit);
|
|
}
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', boot, { once: true });
|
|
} else {
|
|
boot();
|
|
}
|
|
})(window.formApp);
|