// fixtures/status.mjs — the editor's save line and its load-error line, // factored out of editor-entry.js so the rules are testable under plain // Node (status.test.mjs). // // The save line is estilo's savestatus (the template renders it with // every state's words from the catalog; its module, served at // static/estilo/save-status..mjs, moves it between them). Its // four states: `saved`, `saving`, `retrying` (a save is being retried — // the network, or a 5xx) and `failed` (a batch was DROPPED: the server // refused it with a 4xx, and the person's Y.Doc now holds changes the // server never will). The last two are different words on purpose: // "Offline, retrying" on a batch nobody is retrying tells a person to // wait for something that will not happen. // // A slide that would not load is not a save state — savestatus has no // word for it — so it is its own line ([slides-load-error]), said until // a slide does load, and independent of whatever the save line says. /** The save queue's status word (save-queue.mjs) as a savestatus state. */ export function queueStatusState (state) { if (state === 'ok') return 'saved' if (state === 'failed') return 'failed' return 'retrying' } /** * The state to show. A dropped batch outranks everything — it is the * one fact the person has to act on — and stays for the session; then * whatever the queue says. */ export function statusState ({ queueState = 'saved', sessionFailed = false } = {}) { if (sessionFailed) return 'failed' return queueState } /** * The editor's status: setSave is savestatus's setter, errorEl the * load-error line, errorText its words. Returns {save, drop, * loadFailed}: save(state) records the queue's state (or re-shows the * current one with no argument), drop() marks the session failed, * loadFailed(bool) says or clears the load error. */ export function createEditorStatus ({ setSave, errorEl, errorText }) { let queueState = 'saved' let sessionFailed = false function save (state) { if (state) queueState = state setSave(statusState({ queueState, sessionFailed })) } return { save, drop () { sessionFailed = true; save() }, loadFailed (failed) { if (errorEl) errorEl.textContent = failed ? (errorText || '') : '' } } } /** * Loads estilo's savestatus module (its fingerprinted URL is on the * root as data-save-status-module) and mounts it on the line. A module * that will not load leaves the load-error line saying so and rejects: * an editor whose save line cannot move is one that would say "Saved" * over changes it never saved. */ export async function mountSaveStatus (root, load = src => import(src)) { const errorEl = root.querySelector('[slides-load-error]') const errorText = root.dataset.textError try { const { mount } = await load(root.dataset.saveStatusModule) return createEditorStatus({ setSave: mount(root.querySelector('[estilo-save-status]')), errorEl, errorText }) } catch (err) { if (errorEl) errorEl.textContent = errorText || '' throw err } }