(function (app) { 'use strict'; async function init() { // Both apps (table + form) ship in the same bundle. Skip if // mode dispatcher said this isn't our mode — form-mode requests // are handled by formApp. if (window.zddcMode === 'form') { return; } const ctx = await app.modules.context.load(); app.context = ctx; const titleEl = document.getElementById('table-title'); if (ctx.title && titleEl) { titleEl.textContent = ctx.title; document.title = 'ZDDC — ' + ctx.title; } const descEl = document.getElementById('table-description'); if (descEl && ctx.description) { descEl.textContent = ctx.description; descEl.hidden = false; } const tableEl = document.getElementById('table-root'); const theadEl = tableEl.querySelector('thead'); const tbodyEl = tableEl.querySelector('tbody'); const emptyEl = document.getElementById('table-empty'); const countEl = document.getElementById('table-rowcount'); const clearBtn = document.getElementById('table-clear-filters'); const addRowBtn = document.getElementById('table-add-row'); // Add-row button: link to .form.html, the form-system's // empty-form URL for this table's row schema. POST creates a // new submission and the server redirects to the row's edit // URL. Hidden when we can't derive a table name from the // pathname (e.g. inline-context test harness opening tables.html // directly without a *.table.html URL). if (addRowBtn) { // Page is at /table.html; the row-creation form is at // /form.html — same directory, just swap the basename. if (/\/table\.html$/.test(location.pathname || '')) { addRowBtn.href = 'form.html'; addRowBtn.hidden = false; } } const columns = Array.isArray(ctx.columns) ? ctx.columns : []; const allRows = Array.isArray(ctx.rows) ? ctx.rows : []; const state = app.state; state.rows = allRows; state.sort = app.modules.sort.defaultsFromContext(ctx); state.filter = {}; // Seed default filters from context.defaults.filter (per-column). if (ctx.defaults && ctx.defaults.filter && typeof ctx.defaults.filter === 'object') { for (let i = 0; i < columns.length; i++) { const col = columns[i]; const seeded = ctx.defaults.filter[col.field]; if (seeded == null) { continue; } // Filter UI is uniformly text-contains. If the spec // seeds an array (legacy enum-style), coerce to a // comma-joined contains string — partial match on any // listed value still narrows the table sensibly. const seedStr = Array.isArray(seeded) ? seeded.join(',') : String(seeded); state.filter[col.field] = { kind: 'contains', value: seedStr }; } } function anyFilterActive() { const filters = app.modules.filters; const keys = Object.keys(state.filter); for (let i = 0; i < keys.length; i++) { if (!filters.isEmpty(state.filter[keys[i]])) { return true; } } return false; } function paint() { const filtered = app.modules.filters.apply(state.rows, columns, state.filter, app.modules.util.resolveField); const sorted = app.modules.sort.apply(filtered, state.sort, columns, app.modules.util); app.modules.render.header(theadEl, columns, state.sort, state.filter, onHeaderClick, onFilterChange); app.modules.render.body(tbodyEl, sorted, columns); app.modules.render.rowCount(countEl, sorted.length, state.rows.length); if (emptyEl) { emptyEl.hidden = sorted.length > 0 || state.rows.length === 0; } if (clearBtn) { clearBtn.hidden = !anyFilterActive(); } // Restore the editor's selection across re-paints so a sort // or filter change doesn't dump the user out of the cell // they were on. Selected coords clamp to the new bounds in // setSelected; if the row vanished (filter excluded it), // we land on the last valid cell instead of clearing. const editor = app.modules.editor; if (editor) { editor.attachToTable(); if (state.selected) { editor.setSelected(state.selected.row, state.selected.col, { noFocus: true }); } } } function onHeaderClick(field, shiftKey) { state.sort = app.modules.sort.cycle(state.sort, field, shiftKey); paint(); } function onFilterChange(field, value) { state.filter[field] = value; paint(); } if (clearBtn) { clearBtn.addEventListener('click', function () { state.filter = {}; paint(); }); } paint(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })(window.tablesApp);