diff --git a/docs/reference.md b/docs/reference.md index 913c4fb..c5443de 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -34,6 +34,7 @@ The quick lookup surface: one line and a minimal snippet per construct. For rule | [task assignment](/spec/processes#task-assignment) | route a user task to a role, the record owner, or a relation walk | | [`abortOn`](/spec/processes#aborton-cancel-the-instance-on-a-terminal-status) | cancel the running instance when the document reaches a terminal status | | [`function: Attachment` / `Snapshot`](/spec/entities#attachments-and-snapshots) | a Files panel / immutable versioned printed copies | +| [a print placeholder's alternative paths](/spec/presentation#printable-documents) | several paths in one placeholder - the first non-blank one is rendered | | [`forms`](/spec/processes#forms) | task data-entry pages | | [`actions`](/spec/processes#actions-custom-buttons) | developer-defined buttons opening custom pages | | [`view`](/spec/presentation#view-calendar-range-slots) | an additional calendar / range page, or a slot-booking page | diff --git a/docs/spec/presentation.md b/docs/spec/presentation.md index b386a10..a747844 100644 --- a/docs/spec/presentation.md +++ b/docs/spec/presentation.md @@ -220,6 +220,18 @@ The template is a tree of layout tags (`page`, `header` / `footer`, `section` / {{}} a line-item field (inside a table bound to the items) ``` +A placeholder may list several paths separated by `|`, and the **first one resolving to a non-blank value** is rendered, left to right: + +```text +{{document.Customer.NameLocal|document.Customer.Name}} +``` + +This is the fallback an optional twin field needs. A partner record carries a locally registered name beside its canonical one - filled for some partners and not for others - and a template that had to name a single field printed a hole in the document for every record with the other one filled. + +::: info Normative +Every operand resolves by the same rules as a single path, including row-scope resolution inside a table. A value counts as blank when it is null, missing, or whitespace-only. The **last** operand is rendered whatever it holds, so a single path is the one-operand case of the rule and a placeholder whose operands are all blank renders empty - exactly as an unresolved single path does; an existing template is byte-identical until it adopts the syntax. Any number of operands is allowed, and no other syntax is introduced: an operand is a path, never a literal or an expression. +::: + A `table` (or a row-expanding `for`) can **filter** the collection it renders — a declarative value match, never an expression: `filter=""` keeps the rows whose path (resolved per row) is truthy, and adding `match="A | B"` keeps only the rows whose value equals one of the `|`-separated literals. The same `match` on an `if` compares its resolved `source` against the listed values instead of testing truthiness. One bound collection can this way render into several purpose-grouped tables — the two-column payslip (earnings left, deductions right), a journal entry's debit and credit sides, a VAT summary per rate: ```text