# Feature Plan — Client attributes, form directives, hooks, stale-set, meson generator ## Features 1. **`stm-markdown`** — render untrusted markdown as safe HTML (all source HTML escaped first). 2. **`stm-h-demotion`** — demote child header tags by N levels (runs after `stm-html` / `stm-markdown`). 3. **Form directives** (`form-submit`, `form-reset`) — programmatically submit or reset a form by ID from a server directive. 4. **Before/after evaluation hooks** — `statum.beforeEvaluate(fn)` / `statum.afterEvaluate(fn)` JS API. 5. **Automatic `set` for stale slots** — server auto-refreshes a client's stale snapshot (when the client's `as_at` predates the slot's last update). 6. **Meson generator for `mkpstm`** — a reusable `statum_page()` helper so apps don't write a `custom_target` per page. 7. **Documentation updates** — `model.md`, `getting-started.md`. --- ## A. `stm-markdown` attribute — `js/statum.js` ### Design A built-in minimal markdown parser (no external dependencies, since the client is self-contained). The pipeline is: 1. Escape **all** HTML entities in the raw string first (`<` → `<`, etc.) so untrusted input cannot inject markup. 2. Apply markdown formatting rules that produce safe HTML tags. Supported syntax: headings (`#`–`######`), bold (`**`), italic (`*`), inline code (`` ` ``), fenced code blocks (```` ``` ````), links (`[text](url)`), unordered lists (`-`/`*`), ordered lists (`1.`), blockquotes (`>`), horizontal rules (`---`), and paragraphs (blank-line separated). ### Implementation - Add `renderMarkdown(string raw) → string html` in the client IIFE. - In `handleTextHtml`, after the `stm-text` / `stm-html` checks: ```js if (el.hasAttribute('stm-markdown')) { var md = evalExpr(el.getAttribute('stm-markdown'), scope); if (md !== undefined) el.innerHTML = renderMarkdown(md === null ? '' : String(md)); } ``` - Order matters: `stm-markdown` runs **before** `stm-h-demotion` (B) so the demotion sees the rendered headers. --- ## B. `stm-h-demotion` attribute — `js/statum.js` ### Design `stm-h-dementia="1"` demotes every `