@fieldia/core 0.26.1 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +307 -3
- package/package.json +1 -1
- package/schema/page.schema.json +227 -23
- package/src/index.d.mts +8 -2
- package/src/index.d.ts +8 -2
- package/src/index.js +22 -1
- package/src/index.js.map +1 -1
- package/src/index.mjs +9 -2
- package/src/index.mjs.map +1 -1
- package/src/lib/expression/app-functions.d.mts +47 -0
- package/src/lib/expression/app-functions.d.ts +47 -0
- package/src/lib/expression/app-functions.js +64 -0
- package/src/lib/expression/app-functions.js.map +1 -0
- package/src/lib/expression/app-functions.mjs +58 -0
- package/src/lib/expression/app-functions.mjs.map +1 -0
- package/src/lib/expression/dates.d.mts +21 -0
- package/src/lib/expression/dates.d.ts +21 -0
- package/src/lib/expression/dates.js +73 -0
- package/src/lib/expression/dates.js.map +1 -0
- package/src/lib/expression/dates.mjs +67 -0
- package/src/lib/expression/dates.mjs.map +1 -0
- package/src/lib/expression/evaluator.js +12 -6
- package/src/lib/expression/evaluator.js.map +1 -1
- package/src/lib/expression/evaluator.mjs +12 -6
- package/src/lib/expression/evaluator.mjs.map +1 -1
- package/src/lib/expression/expression.d.mts +7 -3
- package/src/lib/expression/expression.d.ts +7 -3
- package/src/lib/expression/expression.js +8 -2
- package/src/lib/expression/expression.js.map +1 -1
- package/src/lib/expression/expression.mjs +7 -2
- package/src/lib/expression/expression.mjs.map +1 -1
- package/src/lib/expression/functions-part.d.mts +7 -0
- package/src/lib/expression/functions-part.d.ts +7 -0
- package/src/lib/expression/functions-part.js +13 -0
- package/src/lib/expression/functions-part.js.map +1 -0
- package/src/lib/expression/functions-part.mjs +8 -0
- package/src/lib/expression/functions-part.mjs.map +1 -0
- package/src/lib/expression/functions.d.mts +60 -3
- package/src/lib/expression/functions.d.ts +60 -3
- package/src/lib/expression/functions.js +109 -15
- package/src/lib/expression/functions.js.map +1 -1
- package/src/lib/expression/functions.mjs +103 -16
- package/src/lib/expression/functions.mjs.map +1 -1
- package/src/lib/expression/kinds.d.mts +31 -0
- package/src/lib/expression/kinds.d.ts +31 -0
- package/src/lib/expression/kinds.js +159 -0
- package/src/lib/expression/kinds.js.map +1 -0
- package/src/lib/expression/kinds.mjs +151 -0
- package/src/lib/expression/kinds.mjs.map +1 -0
- package/src/lib/expression/modifier.d.mts +4 -3
- package/src/lib/expression/modifier.d.ts +4 -3
- package/src/lib/expression/modifier.js +4 -3
- package/src/lib/expression/modifier.js.map +1 -1
- package/src/lib/expression/modifier.mjs +4 -3
- package/src/lib/expression/modifier.mjs.map +1 -1
- package/src/lib/expression/more-functions.d.mts +8 -0
- package/src/lib/expression/more-functions.d.ts +8 -0
- package/src/lib/expression/more-functions.js +235 -0
- package/src/lib/expression/more-functions.js.map +1 -0
- package/src/lib/expression/more-functions.mjs +230 -0
- package/src/lib/expression/more-functions.mjs.map +1 -0
- package/src/lib/expression/parser.d.mts +4 -1
- package/src/lib/expression/parser.d.ts +4 -1
- package/src/lib/expression/parser.js +6 -3
- package/src/lib/expression/parser.js.map +1 -1
- package/src/lib/expression/parser.mjs +6 -3
- package/src/lib/expression/parser.mjs.map +1 -1
- package/src/lib/expression/reads.d.mts +2 -2
- package/src/lib/expression/reads.d.ts +2 -2
- package/src/lib/expression/reads.js +6 -4
- package/src/lib/expression/reads.js.map +1 -1
- package/src/lib/expression/reads.mjs +6 -4
- package/src/lib/expression/reads.mjs.map +1 -1
- package/src/lib/format/actions.d.mts +16 -16
- package/src/lib/format/actions.d.ts +16 -16
- package/src/lib/format/check-page.d.mts +7 -2
- package/src/lib/format/check-page.d.ts +7 -2
- package/src/lib/format/check-page.js +10 -4
- package/src/lib/format/check-page.js.map +1 -1
- package/src/lib/format/check-page.mjs +10 -4
- package/src/lib/format/check-page.mjs.map +1 -1
- package/src/lib/format/choice-options.d.mts +34 -0
- package/src/lib/format/choice-options.d.ts +34 -0
- package/src/lib/format/choice-options.js +60 -0
- package/src/lib/format/choice-options.js.map +1 -0
- package/src/lib/format/choice-options.mjs +51 -0
- package/src/lib/format/choice-options.mjs.map +1 -0
- package/src/lib/format/endings-checks.d.mts +8 -0
- package/src/lib/format/endings-checks.d.ts +8 -0
- package/src/lib/format/endings-checks.js +23 -0
- package/src/lib/format/endings-checks.js.map +1 -0
- package/src/lib/format/endings-checks.mjs +20 -0
- package/src/lib/format/endings-checks.mjs.map +1 -0
- package/src/lib/format/endings.d.mts +40 -0
- package/src/lib/format/endings.d.ts +40 -0
- package/src/lib/format/endings.js +15 -0
- package/src/lib/format/endings.js.map +1 -0
- package/src/lib/format/endings.mjs +12 -0
- package/src/lib/format/endings.mjs.map +1 -0
- package/src/lib/format/field.d.mts +151 -16
- package/src/lib/format/field.d.ts +151 -16
- package/src/lib/format/field.js +64 -11
- package/src/lib/format/field.js.map +1 -1
- package/src/lib/format/field.mjs +63 -10
- package/src/lib/format/field.mjs.map +1 -1
- package/src/lib/format/head-checks.d.mts +2 -0
- package/src/lib/format/head-checks.d.ts +2 -0
- package/src/lib/format/head-checks.js +2 -59
- package/src/lib/format/head-checks.js.map +1 -1
- package/src/lib/format/head-checks.mjs +1 -58
- package/src/lib/format/head-checks.mjs.map +1 -1
- package/src/lib/format/later-checks.d.mts +17 -0
- package/src/lib/format/later-checks.d.ts +17 -0
- package/src/lib/format/later-checks.js +20 -0
- package/src/lib/format/later-checks.js.map +1 -0
- package/src/lib/format/later-checks.mjs +17 -0
- package/src/lib/format/later-checks.mjs.map +1 -0
- package/src/lib/format/layout.d.mts +241 -188
- package/src/lib/format/layout.d.ts +241 -188
- package/src/lib/format/layout.js +33 -28
- package/src/lib/format/layout.js.map +1 -1
- package/src/lib/format/layout.mjs +13 -3
- package/src/lib/format/layout.mjs.map +1 -1
- package/src/lib/format/layout.types.d.mts +2 -1
- package/src/lib/format/layout.types.d.ts +2 -1
- package/src/lib/format/limits-checks.d.mts +14 -0
- package/src/lib/format/limits-checks.d.ts +14 -0
- package/src/lib/format/limits-checks.js +36 -0
- package/src/lib/format/limits-checks.js.map +1 -0
- package/src/lib/format/limits-checks.mjs +33 -0
- package/src/lib/format/limits-checks.mjs.map +1 -0
- package/src/lib/format/limits.d.mts +24 -0
- package/src/lib/format/limits.d.ts +24 -0
- package/src/lib/format/limits.js +35 -0
- package/src/lib/format/limits.js.map +1 -0
- package/src/lib/format/limits.mjs +32 -0
- package/src/lib/format/limits.mjs.map +1 -0
- package/src/lib/format/list-checks.d.mts +44 -0
- package/src/lib/format/list-checks.d.ts +44 -0
- package/src/lib/format/list-checks.js +340 -0
- package/src/lib/format/list-checks.js.map +1 -0
- package/src/lib/format/list-checks.mjs +336 -0
- package/src/lib/format/list-checks.mjs.map +1 -0
- package/src/lib/format/map-checks.d.mts +33 -0
- package/src/lib/format/map-checks.d.ts +33 -0
- package/src/lib/format/map-checks.js +180 -0
- package/src/lib/format/map-checks.js.map +1 -0
- package/src/lib/format/map-checks.mjs +175 -0
- package/src/lib/format/map-checks.mjs.map +1 -0
- package/src/lib/format/mapchecks-part.d.mts +5 -0
- package/src/lib/format/mapchecks-part.d.ts +5 -0
- package/src/lib/format/mapchecks-part.js +11 -0
- package/src/lib/format/mapchecks-part.js.map +1 -0
- package/src/lib/format/mapchecks-part.mjs +6 -0
- package/src/lib/format/mapchecks-part.mjs.map +1 -0
- package/src/lib/format/option-checks.d.mts +16 -0
- package/src/lib/format/option-checks.d.ts +16 -0
- package/src/lib/format/option-checks.js +39 -0
- package/src/lib/format/option-checks.js.map +1 -0
- package/src/lib/format/option-checks.mjs +36 -0
- package/src/lib/format/option-checks.mjs.map +1 -0
- package/src/lib/format/options-part.d.mts +6 -0
- package/src/lib/format/options-part.d.ts +6 -0
- package/src/lib/format/options-part.js +11 -0
- package/src/lib/format/options-part.js.map +1 -0
- package/src/lib/format/options-part.mjs +7 -0
- package/src/lib/format/options-part.mjs.map +1 -0
- package/src/lib/format/page.d.mts +147 -71
- package/src/lib/format/page.d.ts +147 -71
- package/src/lib/format/page.js +5 -0
- package/src/lib/format/page.js.map +1 -1
- package/src/lib/format/page.mjs +5 -0
- package/src/lib/format/page.mjs.map +1 -1
- package/src/lib/format/part-checks.d.mts +20 -0
- package/src/lib/format/part-checks.d.ts +20 -0
- package/src/lib/format/part-checks.js +3 -0
- package/src/lib/format/part-checks.js.map +1 -0
- package/src/lib/format/part-checks.mjs +2 -0
- package/src/lib/format/part-checks.mjs.map +1 -0
- package/src/lib/format/references.d.mts +71 -65
- package/src/lib/format/references.d.ts +71 -65
- package/src/lib/format/references.js +194 -631
- package/src/lib/format/references.js.map +1 -1
- package/src/lib/format/references.mjs +194 -631
- package/src/lib/format/references.mjs.map +1 -1
- package/src/lib/format/seats-checks.d.mts +3 -0
- package/src/lib/format/seats-checks.d.ts +3 -0
- package/src/lib/format/seats-checks.js +13 -0
- package/src/lib/format/seats-checks.js.map +1 -0
- package/src/lib/format/seats-checks.mjs +10 -0
- package/src/lib/format/seats-checks.mjs.map +1 -0
- package/src/lib/format/sheet-head-checks.d.mts +4 -0
- package/src/lib/format/sheet-head-checks.d.ts +4 -0
- package/src/lib/format/sheet-head-checks.js +68 -0
- package/src/lib/format/sheet-head-checks.js.map +1 -0
- package/src/lib/format/sheet-head-checks.mjs +65 -0
- package/src/lib/format/sheet-head-checks.mjs.map +1 -0
- package/src/lib/format/signature-checks.d.mts +7 -0
- package/src/lib/format/signature-checks.d.ts +7 -0
- package/src/lib/format/signature-checks.js +32 -0
- package/src/lib/format/signature-checks.js.map +1 -0
- package/src/lib/format/signature-checks.mjs +29 -0
- package/src/lib/format/signature-checks.mjs.map +1 -0
- package/src/lib/format/signature-options.d.mts +24 -0
- package/src/lib/format/signature-options.d.ts +24 -0
- package/src/lib/format/signature-options.js +30 -0
- package/src/lib/format/signature-options.js.map +1 -0
- package/src/lib/format/signature-options.mjs +26 -0
- package/src/lib/format/signature-options.mjs.map +1 -0
- package/src/lib/format/slots-checks.d.mts +4 -0
- package/src/lib/format/slots-checks.d.ts +4 -0
- package/src/lib/format/slots-checks.js +21 -0
- package/src/lib/format/slots-checks.js.map +1 -0
- package/src/lib/format/slots-checks.mjs +18 -0
- package/src/lib/format/slots-checks.mjs.map +1 -0
- package/src/lib/format/statusbar-checks.d.mts +8 -0
- package/src/lib/format/statusbar-checks.d.ts +8 -0
- package/src/lib/format/statusbar-checks.js +35 -0
- package/src/lib/format/statusbar-checks.js.map +1 -0
- package/src/lib/format/statusbar-checks.mjs +32 -0
- package/src/lib/format/statusbar-checks.mjs.map +1 -0
- package/src/lib/format/table-checks.d.mts +21 -0
- package/src/lib/format/table-checks.d.ts +21 -0
- package/src/lib/format/table-checks.js +86 -0
- package/src/lib/format/table-checks.js.map +1 -0
- package/src/lib/format/table-checks.mjs +82 -0
- package/src/lib/format/table-checks.mjs.map +1 -0
- package/src/lib/format/translate.js +2 -2
- package/src/lib/format/translate.js.map +1 -1
- package/src/lib/format/translate.mjs +2 -2
- package/src/lib/format/translate.mjs.map +1 -1
- package/src/lib/format/upgrade.d.mts +6 -3
- package/src/lib/format/upgrade.d.ts +6 -3
- package/src/lib/format/upgrade.js +6 -3
- package/src/lib/format/upgrade.js.map +1 -1
- package/src/lib/format/upgrade.mjs +6 -3
- package/src/lib/format/upgrade.mjs.map +1 -1
- package/src/lib/format/validate.d.mts +18 -2
- package/src/lib/format/validate.d.ts +18 -2
- package/src/lib/format/validate.js +36 -3
- package/src/lib/format/validate.js.map +1 -1
- package/src/lib/format/validate.mjs +35 -3
- package/src/lib/format/validate.mjs.map +1 -1
- package/src/lib/format/version.d.mts +2 -2
- package/src/lib/format/version.d.ts +2 -2
- package/src/lib/format/version.js +2 -2
- package/src/lib/format/version.js.map +1 -1
- package/src/lib/format/version.mjs +2 -2
- package/src/lib/format/version.mjs.map +1 -1
- package/src/lib/format/words.d.mts +6 -2
- package/src/lib/format/words.d.ts +6 -2
- package/src/lib/format/words.js +13 -7
- package/src/lib/format/words.js.map +1 -1
- package/src/lib/format/words.mjs +13 -7
- package/src/lib/format/words.mjs.map +1 -1
- package/src/lib/parts.d.mts +45 -0
- package/src/lib/parts.d.ts +45 -0
- package/src/lib/parts.js +60 -0
- package/src/lib/parts.js.map +1 -0
- package/src/lib/parts.mjs +53 -0
- package/src/lib/parts.mjs.map +1 -0
- package/src/lib/record/cells.d.mts +3 -3
- package/src/lib/record/cells.d.ts +3 -3
- package/src/lib/record/cells.js +16 -15
- package/src/lib/record/cells.js.map +1 -1
- package/src/lib/record/cells.mjs +16 -15
- package/src/lib/record/cells.mjs.map +1 -1
- package/src/lib/record/compute.d.mts +16 -5
- package/src/lib/record/compute.d.ts +16 -5
- package/src/lib/record/compute.js +57 -16
- package/src/lib/record/compute.js.map +1 -1
- package/src/lib/record/compute.mjs +57 -16
- package/src/lib/record/compute.mjs.map +1 -1
- package/src/lib/record/data-source.d.mts +140 -3
- package/src/lib/record/data-source.d.ts +140 -3
- package/src/lib/record/data-source.js.map +1 -1
- package/src/lib/record/data-source.mjs.map +1 -1
- package/src/lib/record/drafts.d.mts +19 -0
- package/src/lib/record/drafts.d.ts +19 -0
- package/src/lib/record/drafts.js +35 -0
- package/src/lib/record/drafts.js.map +1 -0
- package/src/lib/record/drafts.mjs +31 -0
- package/src/lib/record/drafts.mjs.map +1 -0
- package/src/lib/record/env.d.mts +5 -1
- package/src/lib/record/env.d.ts +5 -1
- package/src/lib/record/env.js +9 -1
- package/src/lib/record/env.js.map +1 -1
- package/src/lib/record/env.mjs +8 -1
- package/src/lib/record/env.mjs.map +1 -1
- package/src/lib/record/form-limits.d.mts +81 -0
- package/src/lib/record/form-limits.d.ts +81 -0
- package/src/lib/record/form-limits.js +231 -0
- package/src/lib/record/form-limits.js.map +1 -0
- package/src/lib/record/form-limits.mjs +224 -0
- package/src/lib/record/form-limits.mjs.map +1 -0
- package/src/lib/record/form.d.mts +173 -4
- package/src/lib/record/form.d.ts +173 -4
- package/src/lib/record/form.js +792 -88
- package/src/lib/record/form.js.map +1 -1
- package/src/lib/record/form.mjs +792 -88
- package/src/lib/record/form.mjs.map +1 -1
- package/src/lib/record/limits-part.d.mts +6 -0
- package/src/lib/record/limits-part.d.ts +6 -0
- package/src/lib/record/limits-part.js +12 -0
- package/src/lib/record/limits-part.js.map +1 -0
- package/src/lib/record/limits-part.mjs +7 -0
- package/src/lib/record/limits-part.mjs.map +1 -0
- package/src/lib/record/line-choices.d.mts +30 -0
- package/src/lib/record/line-choices.d.ts +30 -0
- package/src/lib/record/line-choices.js +42 -0
- package/src/lib/record/line-choices.js.map +1 -0
- package/src/lib/record/line-choices.mjs +36 -0
- package/src/lib/record/line-choices.mjs.map +1 -0
- package/src/lib/record/locales/ar.js +10 -0
- package/src/lib/record/locales/ar.js.map +1 -1
- package/src/lib/record/locales/ar.mjs +10 -0
- package/src/lib/record/locales/ar.mjs.map +1 -1
- package/src/lib/record/locales/de.js +10 -0
- package/src/lib/record/locales/de.js.map +1 -1
- package/src/lib/record/locales/de.mjs +10 -0
- package/src/lib/record/locales/de.mjs.map +1 -1
- package/src/lib/record/locales/fr.js +10 -0
- package/src/lib/record/locales/fr.js.map +1 -1
- package/src/lib/record/locales/fr.mjs +10 -0
- package/src/lib/record/locales/fr.mjs.map +1 -1
- package/src/lib/record/memory-data-source.d.mts +44 -3
- package/src/lib/record/memory-data-source.d.ts +44 -3
- package/src/lib/record/memory-data-source.js +102 -40
- package/src/lib/record/memory-data-source.js.map +1 -1
- package/src/lib/record/memory-data-source.mjs +101 -40
- package/src/lib/record/memory-data-source.mjs.map +1 -1
- package/src/lib/record/memory-kept.d.mts +20 -0
- package/src/lib/record/memory-kept.d.ts +20 -0
- package/src/lib/record/memory-kept.js +46 -0
- package/src/lib/record/memory-kept.js.map +1 -0
- package/src/lib/record/memory-kept.mjs +43 -0
- package/src/lib/record/memory-kept.mjs.map +1 -0
- package/src/lib/record/memory-later.d.mts +19 -0
- package/src/lib/record/memory-later.d.ts +19 -0
- package/src/lib/record/memory-later.js +39 -0
- package/src/lib/record/memory-later.js.map +1 -0
- package/src/lib/record/memory-later.mjs +35 -0
- package/src/lib/record/memory-later.mjs.map +1 -0
- package/src/lib/record/memory-part.d.mts +7 -0
- package/src/lib/record/memory-part.d.ts +7 -0
- package/src/lib/record/memory-part.js +13 -0
- package/src/lib/record/memory-part.js.map +1 -0
- package/src/lib/record/memory-part.mjs +8 -0
- package/src/lib/record/memory-part.mjs.map +1 -0
- package/src/lib/record/messages.d.mts +17 -0
- package/src/lib/record/messages.d.ts +17 -0
- package/src/lib/record/messages.js +10 -0
- package/src/lib/record/messages.js.map +1 -1
- package/src/lib/record/messages.mjs +10 -0
- package/src/lib/record/messages.mjs.map +1 -1
- package/src/lib/record/option-rules.d.mts +50 -0
- package/src/lib/record/option-rules.d.ts +50 -0
- package/src/lib/record/option-rules.js +137 -0
- package/src/lib/record/option-rules.js.map +1 -0
- package/src/lib/record/option-rules.mjs +134 -0
- package/src/lib/record/option-rules.mjs.map +1 -0
- package/src/lib/record/rules.d.mts +2 -2
- package/src/lib/record/rules.d.ts +2 -2
- package/src/lib/record/rules.js +3 -3
- package/src/lib/record/rules.js.map +1 -1
- package/src/lib/record/rules.mjs +3 -3
- package/src/lib/record/rules.mjs.map +1 -1
- package/src/lib/record/run.js +9 -7
- package/src/lib/record/run.js.map +1 -1
- package/src/lib/record/run.mjs +9 -7
- package/src/lib/record/run.mjs.map +1 -1
- package/src/lib/record/search.d.mts +12 -2
- package/src/lib/record/search.d.ts +12 -2
- package/src/lib/record/search.js +29 -4
- package/src/lib/record/search.js.map +1 -1
- package/src/lib/record/search.mjs +29 -4
- package/src/lib/record/search.mjs.map +1 -1
- package/src/lib/record/set-when.d.mts +3 -3
- package/src/lib/record/set-when.d.ts +3 -3
- package/src/lib/record/set-when.js +9 -9
- package/src/lib/record/set-when.js.map +1 -1
- package/src/lib/record/set-when.mjs +9 -9
- package/src/lib/record/set-when.mjs.map +1 -1
- package/src/lib/record/signed.d.mts +21 -0
- package/src/lib/record/signed.d.ts +21 -0
- package/src/lib/record/signed.js +62 -0
- package/src/lib/record/signed.js.map +1 -0
- package/src/lib/record/signed.mjs +57 -0
- package/src/lib/record/signed.mjs.map +1 -0
- package/src/lib/record/taking.d.mts +60 -0
- package/src/lib/record/taking.d.ts +60 -0
- package/src/lib/record/taking.js +58 -0
- package/src/lib/record/taking.js.map +1 -0
- package/src/lib/record/taking.mjs +50 -0
- package/src/lib/record/taking.mjs.map +1 -0
- package/src/lib/record/value-map.js +11 -4
- package/src/lib/record/value-map.js.map +1 -1
- package/src/lib/record/value-map.mjs +11 -4
- package/src/lib/record/value-map.mjs.map +1 -1
- package/src/lib/record/values.d.mts +20 -0
- package/src/lib/record/values.d.ts +20 -0
- package/src/lib/record/values.js.map +1 -1
- package/src/lib/record/values.mjs.map +1 -1
- package/src/lib/record/waits.d.mts +6 -1
- package/src/lib/record/waits.d.ts +6 -1
- package/src/lib/record/waits.js +2 -2
- package/src/lib/record/waits.js.map +1 -1
- package/src/lib/record/waits.mjs +2 -2
- package/src/lib/record/waits.mjs.map +1 -1
- package/src/runtime.d.mts +16 -5
- package/src/runtime.d.ts +16 -5
- package/src/runtime.js +41 -3
- package/src/runtime.js.map +1 -1
- package/src/runtime.mjs +13 -0
- package/src/runtime.mjs.map +1 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { choiceOptions, optionsField, optionsList } from '../format/choice-options.mjs';
|
|
2
|
+
import { fill } from './messages.mjs';
|
|
3
|
+
import { countsAsked, dayAlone, limitInstant, seatedFields } from './taking.mjs';
|
|
4
|
+
import { isOwnZone } from './zones.mjs';
|
|
5
|
+
/** What a form tells of its limits now: from the page, the clock, the options it shows and the source's last answer. */
|
|
6
|
+
export function limitsNow(page, now, told, asking, optionsOf) {
|
|
7
|
+
const limits = page.data.kind === 'responses' ? page.limits : undefined;
|
|
8
|
+
const seats = {};
|
|
9
|
+
for (const [field, counted] of Object.entries(told?.perChoice ?? {})) {
|
|
10
|
+
const places = {};
|
|
11
|
+
for (const option of optionsOf(field)) {
|
|
12
|
+
if (option.seats === undefined)
|
|
13
|
+
continue;
|
|
14
|
+
const taken = Math.max(0, Number(counted?.[String(option.value)] ?? 0) || 0);
|
|
15
|
+
places[String(option.value)] = { seats: option.seats, taken, left: Math.max(0, option.seats - taken) };
|
|
16
|
+
}
|
|
17
|
+
if (Object.keys(places).length)
|
|
18
|
+
seats[field] = places;
|
|
19
|
+
}
|
|
20
|
+
if (!limits && !Object.keys(seats).length)
|
|
21
|
+
return null;
|
|
22
|
+
const opens = limits?.opens ? limitInstant(limits.opens, page.timeZone) : null;
|
|
23
|
+
const closes = limits?.closes ? limitInstant(limits.closes, page.timeZone, true) : null;
|
|
24
|
+
const max = limits?.maxResponses;
|
|
25
|
+
const responses = told?.responses;
|
|
26
|
+
const left = max !== undefined && typeof responses === 'number' ? Math.max(0, max - responses) : undefined;
|
|
27
|
+
const state = opens !== null && now < opens ? 'soon'
|
|
28
|
+
: closes !== null && now >= closes ? 'closed'
|
|
29
|
+
: asking ? 'asking'
|
|
30
|
+
: left === 0 ? 'full'
|
|
31
|
+
: limits?.onePerPerson && (told?.mine ?? 0) >= 1 ? 'sent'
|
|
32
|
+
: 'open';
|
|
33
|
+
return {
|
|
34
|
+
state,
|
|
35
|
+
...(opens !== null ? { opens: new Date(opens).toISOString() } : {}),
|
|
36
|
+
...(closes !== null ? { closes: new Date(closes).toISOString() } : {}),
|
|
37
|
+
...(limits?.message ? { message: limits.message } : {}),
|
|
38
|
+
...(left !== undefined ? { left } : {}),
|
|
39
|
+
seats,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** The values a choice holds: one, several (a choice of many), or none. */
|
|
43
|
+
const chosenOf = (value) => (Array.isArray(value) ? value : value === null || value === undefined ? [] : [value]);
|
|
44
|
+
/**
|
|
45
|
+
* The options of a choice's value that are full now, in the order they are held: those `before` held too left out
|
|
46
|
+
* when given — a choice made now, not one held already.
|
|
47
|
+
*/
|
|
48
|
+
export function fullChosen(field, places, value, before) {
|
|
49
|
+
if (!places || field?.type !== 'selection')
|
|
50
|
+
return [];
|
|
51
|
+
const held = new Set(chosenOf(before).map(String));
|
|
52
|
+
return chosenOf(value)
|
|
53
|
+
.filter((one) => !(before !== undefined && held.has(String(one))) && places[String(one)]?.left === 0)
|
|
54
|
+
.map((one) => (field.options ?? []).find((option) => String(option.value) === String(one)) ?? { value: String(one), label: String(one) });
|
|
55
|
+
}
|
|
56
|
+
/** A form's limits: what it tells of them, and what it asks and refuses by them. */
|
|
57
|
+
export function formLimits(host) {
|
|
58
|
+
const { page, scheduler, messages } = host;
|
|
59
|
+
/** The source's last answer to `limits`: null until it told. */
|
|
60
|
+
let counted = null;
|
|
61
|
+
let timer = null;
|
|
62
|
+
/** The choice fields whose own options have places. */
|
|
63
|
+
const seated = seatedFields(page);
|
|
64
|
+
/** A choice's options as shown: its own, or its app's list's once loaded. */
|
|
65
|
+
const optionsOf = (name) => {
|
|
66
|
+
const def = page.fields[name];
|
|
67
|
+
if (def?.type !== 'selection')
|
|
68
|
+
return [];
|
|
69
|
+
if (optionsList(def.optionsFrom))
|
|
70
|
+
return (host.started() ? host.state().choices[name]?.options : null) ?? [];
|
|
71
|
+
// Carried from an earlier question: its options, and the choice's own after them.
|
|
72
|
+
return optionsField(def.optionsFrom) ? choiceOptions(page.fields, name) : (def.options ?? []);
|
|
73
|
+
};
|
|
74
|
+
/** The choice fields with places now: those of the page's own, and of the app's lists whose options loaded with them. */
|
|
75
|
+
const seatedNow = () => [...seated, ...Object.keys(host.started() ? host.state().choices : {}).filter((name) => !seated.includes(name) && optionsOf(name).some((option) => option.seats !== undefined))];
|
|
76
|
+
const asks = () => !!host.dataSource?.limits && (countsAsked(page) || seatedNow().length > 0);
|
|
77
|
+
/** The page's counts asked as it opens and not told yet: nothing is typed meanwhile. */
|
|
78
|
+
let askingFirst = asks() && countsAsked(page);
|
|
79
|
+
const limitsHere = () => limitsNow(page, host.clock(), counted, askingFirst, optionsOf);
|
|
80
|
+
function show() {
|
|
81
|
+
const limits = limitsHere();
|
|
82
|
+
if (JSON.stringify(limits) !== JSON.stringify(host.state().limits ?? null))
|
|
83
|
+
host.set({ limits });
|
|
84
|
+
if (timer !== null)
|
|
85
|
+
scheduler.clearTimeout(timer);
|
|
86
|
+
timer = null;
|
|
87
|
+
const next = [limits?.opens, limits?.closes].map((at) => (at ? Date.parse(at) - host.clock() : -1)).filter((ms) => ms > 0).sort((a, b) => a - b)[0];
|
|
88
|
+
// Within the longest wait a timer keeps (24 days), while something listens: a page left open as it opens or closes
|
|
89
|
+
// says so then. (A form no one listens to keeps no timer that would hold a process open.)
|
|
90
|
+
if (next !== undefined && next < 2 ** 31 - 1 && !host.disposed() && host.listened())
|
|
91
|
+
timer = scheduler.setTimeout(show, next + 50);
|
|
92
|
+
}
|
|
93
|
+
async function ask() {
|
|
94
|
+
const source = host.dataSource;
|
|
95
|
+
if (!asks() || !source?.limits)
|
|
96
|
+
return show();
|
|
97
|
+
const shown = host.shownNow();
|
|
98
|
+
const user = host.user ? { user: { id: host.user.id, ...(host.user.name ? { name: host.user.name } : {}) } } : {};
|
|
99
|
+
// A source that never answers keeps no one from the questions for long: past 10 seconds they show, and its submit decides.
|
|
100
|
+
const waited = askingFirst
|
|
101
|
+
? scheduler.setTimeout(() => {
|
|
102
|
+
if (!askingFirst || !shown())
|
|
103
|
+
return;
|
|
104
|
+
askingFirst = false;
|
|
105
|
+
show();
|
|
106
|
+
}, 10000)
|
|
107
|
+
: null;
|
|
108
|
+
try {
|
|
109
|
+
const told = await source.limits({ pageId: page.id, model: page.data.kind === 'record' ? page.data.model : '', recordId: host.state().recordId, fields: seatedNow(), ...user });
|
|
110
|
+
if (!shown())
|
|
111
|
+
return;
|
|
112
|
+
counted = told ?? {};
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Not told: the page keeps to its dates alone, and the source's submit refuses as it would.
|
|
116
|
+
if (!shown())
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
if (waited !== null)
|
|
121
|
+
scheduler.clearTimeout(waited);
|
|
122
|
+
}
|
|
123
|
+
askingFirst = false;
|
|
124
|
+
show();
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
show,
|
|
128
|
+
ask,
|
|
129
|
+
asks,
|
|
130
|
+
uncounted: (name) => !counted?.perChoice?.[name],
|
|
131
|
+
async stillTaking(asked) {
|
|
132
|
+
if (!page.limits && !seatedNow().length)
|
|
133
|
+
return null;
|
|
134
|
+
await ask();
|
|
135
|
+
if (asked !== host.generation())
|
|
136
|
+
return { reason: 'save', message: host.replaced() };
|
|
137
|
+
const limits = limitsHere();
|
|
138
|
+
const why = limits && limits.state !== 'open' && limits.state !== 'asking' ? takingWords(page, limits, messages) : null;
|
|
139
|
+
if (!why)
|
|
140
|
+
return null;
|
|
141
|
+
const problem = { kind: 'rule', message: why };
|
|
142
|
+
host.set({ status: 'error', error: why, saveProblem: problem, conflict: null, limits });
|
|
143
|
+
return { reason: 'save', message: why };
|
|
144
|
+
},
|
|
145
|
+
refusedFull(name, value) {
|
|
146
|
+
const state = host.state();
|
|
147
|
+
const full = fullChosen(page.fields[name], state.limits?.seats[name], value, state.values[name]);
|
|
148
|
+
if (!full.length)
|
|
149
|
+
return false;
|
|
150
|
+
host.refuse(name, fill(messages.choiceFull, { option: full.map((option) => option.label).join(', ') }));
|
|
151
|
+
return true;
|
|
152
|
+
},
|
|
153
|
+
fullErrors(seen, errors) {
|
|
154
|
+
const state = host.state();
|
|
155
|
+
const found = {};
|
|
156
|
+
for (const [name, places] of Object.entries(state.limits?.seats ?? {})) {
|
|
157
|
+
const full = seen.has(name) && !errors[name] ? fullChosen(page.fields[name], places, state.values[name]) : [];
|
|
158
|
+
if (full.length)
|
|
159
|
+
found[name] = fill(messages.choiceFilled, { option: full.map((option) => option.label).join(', ') });
|
|
160
|
+
}
|
|
161
|
+
return found;
|
|
162
|
+
},
|
|
163
|
+
heard(listening) {
|
|
164
|
+
if (listening) {
|
|
165
|
+
const limits = host.state().limits;
|
|
166
|
+
if (timer === null && (limits?.opens || limits?.closes))
|
|
167
|
+
show();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (timer === null)
|
|
171
|
+
return;
|
|
172
|
+
scheduler.clearTimeout(timer);
|
|
173
|
+
timer = null;
|
|
174
|
+
},
|
|
175
|
+
dispose() {
|
|
176
|
+
if (timer !== null)
|
|
177
|
+
scheduler.clearTimeout(timer);
|
|
178
|
+
timer = null;
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* A day or a day and a time in words, in the messages' language, on the page's clock: "20 November 2026", "1 November
|
|
184
|
+
* 2026 at 09:00" — with the zone's short name where it is not the browser's own ("09:00 GMT+2").
|
|
185
|
+
*/
|
|
186
|
+
export function whenWords(written, at, messages, zone) {
|
|
187
|
+
if (dayAlone(written)) {
|
|
188
|
+
const [y, m, d] = written.split('-').map(Number);
|
|
189
|
+
return new Intl.DateTimeFormat(messages.locale, { year: 'numeric', month: 'long', day: 'numeric', timeZone: 'UTC', numberingSystem: 'latn' }).format(Date.UTC(y, m - 1, d));
|
|
190
|
+
}
|
|
191
|
+
const elsewhere = !!zone && !isOwnZone(zone);
|
|
192
|
+
return new Intl.DateTimeFormat(messages.locale, {
|
|
193
|
+
year: 'numeric',
|
|
194
|
+
month: 'long',
|
|
195
|
+
day: 'numeric',
|
|
196
|
+
hour: '2-digit',
|
|
197
|
+
minute: '2-digit',
|
|
198
|
+
hourCycle: 'h23',
|
|
199
|
+
numberingSystem: 'latn',
|
|
200
|
+
...(zone ? { timeZone: zone } : {}),
|
|
201
|
+
...(elsewhere ? { timeZoneName: 'short' } : {}),
|
|
202
|
+
}).format(at);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Why a page takes no answers now, in the messages' words — "This form opens on 1 November 2026 at 09:00.", "This form
|
|
206
|
+
* closed on 20 November 2026.", "This form has all the responses it takes.", "You have sent your answers to this form
|
|
207
|
+
* already." — or null while it takes them (or still asks).
|
|
208
|
+
*/
|
|
209
|
+
export function takingWords(page, limits, messages) {
|
|
210
|
+
const written = page.limits;
|
|
211
|
+
switch (limits?.state) {
|
|
212
|
+
case 'soon':
|
|
213
|
+
return written?.opens && limits.opens ? fill(messages.formOpens, { when: whenWords(written.opens, Date.parse(limits.opens), messages, page.timeZone) }) : null;
|
|
214
|
+
case 'closed':
|
|
215
|
+
return written?.closes && limits.closes ? fill(messages.formClosed, { when: whenWords(written.closes, Date.parse(limits.closes), messages, page.timeZone) }) : null;
|
|
216
|
+
case 'full':
|
|
217
|
+
return messages.formFull;
|
|
218
|
+
case 'sent':
|
|
219
|
+
return messages.formSent;
|
|
220
|
+
default:
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=form-limits.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-limits.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/record/form-limits.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import type { ActionStep } from '../format/actions.mjs';
|
|
2
2
|
import type { Field, LineField, Option, PropertyDefinition } from '../format/field.mjs';
|
|
3
3
|
import type { Page } from '../format/page.mjs';
|
|
4
|
+
import type { PageEnding } from '../format/endings.mjs';
|
|
4
5
|
import type { JsonValue } from '../format/json.mjs';
|
|
6
|
+
import { type FunctionTable } from '../expression/functions.mjs';
|
|
7
|
+
import { type AppFunctions } from '../expression/app-functions.mjs';
|
|
8
|
+
import { type AskedFor } from './compute.mjs';
|
|
5
9
|
import { type FieldTone, type LineState } from './cells.mjs';
|
|
6
10
|
import { type Messages } from './messages.mjs';
|
|
7
|
-
import { type DataSource, type RecordChanges, type RecordPermissions, type RecordVersion, type ResolvedFilter, type SaveProblem, type BotReport, type SlotsResult, type UploadFile, type DuplicateMatch, type MergeResult } from './data-source.mjs';
|
|
11
|
+
import { type DataSource, type RecordChanges, type RecordPermissions, type RecordVersion, type ResolvedFilter, type SaveProblem, type BotReport, type SlotsResult, type UploadFile, type DuplicateMatch, type MergeResult, type SavedDraft } from './data-source.mjs';
|
|
12
|
+
import { type FormLimits } from './taking.mjs';
|
|
8
13
|
import { type WaitsFor } from './waits.mjs';
|
|
9
14
|
import { type FileUpload, type UploadHow } from './uploads.mjs';
|
|
10
15
|
import { type Scheduler } from './scheduler.mjs';
|
|
@@ -40,7 +45,10 @@ export interface FormState {
|
|
|
40
45
|
readonly skipped: readonly string[];
|
|
41
46
|
/** Why the last save was refused, until the next one starts or the form is reset. */
|
|
42
47
|
readonly saveProblem: SaveProblem | null;
|
|
43
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* The choices loaded from the app's lists: those of a selection with `optionsFrom`, once asked for — by field, and a
|
|
50
|
+
* table line's by its cell's path (`field.lineKey.subfield`).
|
|
51
|
+
*/
|
|
44
52
|
readonly choices: Readonly<Record<string, Choices>>;
|
|
45
53
|
/** The definitions loaded for a properties field with `definitionsFrom`, by field, once asked for. */
|
|
46
54
|
readonly definitions: Readonly<Record<string, Definitions>>;
|
|
@@ -81,6 +89,47 @@ export interface FormState {
|
|
|
81
89
|
* value it held as the box was entered; validate and save refuse with the words until the text is fixed.
|
|
82
90
|
*/
|
|
83
91
|
readonly unread: Readonly<Record<string, UnreadText>>;
|
|
92
|
+
/**
|
|
93
|
+
* A page of responses sent: the answers as they went, with what the app's source answered — the id it gave the
|
|
94
|
+
* response and the values it added (`SubmitResult`). What its ending reads (`form.ending()`, `{id}`). Null until a
|
|
95
|
+
* send, and again once the form starts a new response (`reset`).
|
|
96
|
+
*/
|
|
97
|
+
readonly sent?: SentResponse | null;
|
|
98
|
+
/**
|
|
99
|
+
* Values worked out from an app's function that asks its server (`functions`) with no answer yet, by path (a
|
|
100
|
+
* line's `field.lineKey.subfield`): waiting for it (`{}`) — the value empty meanwhile, a save waiting for it — or
|
|
101
|
+
* why it did not come (`failed`), which a save asks again and, failing, is stopped by under its field.
|
|
102
|
+
*/
|
|
103
|
+
readonly asked: Readonly<Record<string, AskedFor>>;
|
|
104
|
+
/**
|
|
105
|
+
* Words said under a choice whose chosen options a change of other answers no longer offers — hidden by their
|
|
106
|
+
* condition, no longer picked where they are carried from, or no longer in the app's list as a field it changes with
|
|
107
|
+
* changed — by path (a field, or a table line's `field.lineKey.subfield`): they were taken out of its answer. Until
|
|
108
|
+
* that value is written again, its line goes, or another record is shown.
|
|
109
|
+
*/
|
|
110
|
+
readonly takenOut: Readonly<Record<string, string>>;
|
|
111
|
+
/**
|
|
112
|
+
* When the page takes answers and each choice's places, as its `limits`, its options' `seats`, the form's clock and
|
|
113
|
+
* the data source's `limits` tell: whether it takes them now (`state`), when it opens and closes, the responses it
|
|
114
|
+
* takes still, and each choice's places left. Null on a page with neither.
|
|
115
|
+
*/
|
|
116
|
+
readonly limits?: FormLimits | null;
|
|
117
|
+
/**
|
|
118
|
+
* The draft kept on the app's server (`saveDraft`) that these answers continue: its `key`, once the source gave one
|
|
119
|
+
* (the viewer's `resume`, or the first draft kept); `missing` when the key the form was given named no draft — it
|
|
120
|
+
* starts empty. Null while none is.
|
|
121
|
+
*/
|
|
122
|
+
readonly resume?: {
|
|
123
|
+
readonly key: string;
|
|
124
|
+
readonly missing?: boolean;
|
|
125
|
+
} | null;
|
|
126
|
+
}
|
|
127
|
+
/** A response sent, as `FormState.sent` keeps it. */
|
|
128
|
+
export interface SentResponse {
|
|
129
|
+
/** The id the app's source gave the response ("B-1043"), or null where it gave none. */
|
|
130
|
+
readonly id: RecordId | null;
|
|
131
|
+
/** The answers as they were sent, with the values the source added (`SubmitResult.values`) laid over them. */
|
|
132
|
+
readonly values: Readonly<Values>;
|
|
84
133
|
}
|
|
85
134
|
/** How a search for a link's records is asked (`form.search`, `form.searchLine`). */
|
|
86
135
|
export interface SearchOptions {
|
|
@@ -235,6 +284,16 @@ export interface FormEvents {
|
|
|
235
284
|
recordId: RecordId | null;
|
|
236
285
|
message: PostedMessage;
|
|
237
286
|
};
|
|
287
|
+
/**
|
|
288
|
+
* A draft was kept on the app's server (`saveDraft`): its key — what a link to continue from carries — and whether the
|
|
289
|
+
* person pressed "Continue later" (`later`), with the source's answer.
|
|
290
|
+
*/
|
|
291
|
+
draft: {
|
|
292
|
+
key: string;
|
|
293
|
+
savedAt: string;
|
|
294
|
+
later: boolean;
|
|
295
|
+
saved: SavedDraft;
|
|
296
|
+
};
|
|
238
297
|
}
|
|
239
298
|
export interface FormOptions {
|
|
240
299
|
page: Page;
|
|
@@ -254,11 +313,24 @@ export interface FormOptions {
|
|
|
254
313
|
host?: ActionHost;
|
|
255
314
|
/** How a question is asked when there is no host. Without either, a question goes on as though answered Yes. */
|
|
256
315
|
confirm?: (message: string) => boolean | Promise<boolean>;
|
|
316
|
+
/**
|
|
317
|
+
* Keep what is typed as a draft, offered again the next time the page opens: in `store` (the browser's localStorage
|
|
318
|
+
* fits) — or, on a page with `continueLater` whose data source has `saveDraft` and `loadDraft`, on the app's server,
|
|
319
|
+
* the store keeping only its key (such a page keeps its drafts there without this too). A draft keeps the wizard's
|
|
320
|
+
* step and text typed that does not read yet. `restore`: `ask` (the default) offers it, `auto` lays it at once.
|
|
321
|
+
*/
|
|
257
322
|
drafts?: {
|
|
258
323
|
store: DraftStore;
|
|
259
324
|
restore?: 'auto' | 'ask';
|
|
260
325
|
delayMs?: number;
|
|
261
326
|
};
|
|
327
|
+
/**
|
|
328
|
+
* The key of a draft kept on the app's server (`saveDraft`) to continue from — what the link the app made after
|
|
329
|
+
* "Continue later" carries: loaded through the source's `loadDraft` as the form opens, its answers, its wizard step
|
|
330
|
+
* and its text typed that does not read laid as they were. A key that names none starts the form empty
|
|
331
|
+
* (`resume.missing`). Without the source's `loadDraft`, it is let be.
|
|
332
|
+
*/
|
|
333
|
+
resume?: string;
|
|
262
334
|
autosave?: {
|
|
263
335
|
delayMs: number;
|
|
264
336
|
};
|
|
@@ -294,6 +366,21 @@ export interface FormOptions {
|
|
|
294
366
|
fields: Readonly<Record<string, Field | LineField>>;
|
|
295
367
|
id?: RecordId | null;
|
|
296
368
|
};
|
|
369
|
+
/**
|
|
370
|
+
* How a field's value reads inside the page's own words — a `{field}` in a label, a help, a choice, a step's title, a
|
|
371
|
+
* button, an ending — and so inside the form's messages that name a label ("How was your visit to Zamalek? is
|
|
372
|
+
* required"). The viewer gives its own, as each field shows its value at rest: a choice by its label, money with its
|
|
373
|
+
* currency, a day in the page's order. Left out, a choice by its label, a link by its name, a yes or no as Yes or No,
|
|
374
|
+
* anything else as it is held.
|
|
375
|
+
*/
|
|
376
|
+
valueWords?: (field: Field, value: Value | undefined, values: Readonly<Values>) => string;
|
|
377
|
+
/**
|
|
378
|
+
* The app's own functions, which the page's expressions call by name besides Fieldia's: `vatRate(country)`. Each a
|
|
379
|
+
* plain function, or `{ call, takes, values, gives, tip }`. One that asks the app's server gives a promise: a value
|
|
380
|
+
* worked out from it waits while it is asked — once for the same values, for the record shown — and a save waits
|
|
381
|
+
* for it; a condition reading it does not hold meanwhile. A name a page cannot call is refused as the form is made.
|
|
382
|
+
*/
|
|
383
|
+
functions?: AppFunctions;
|
|
297
384
|
}
|
|
298
385
|
/** The person using a form, as the app knows them. */
|
|
299
386
|
export interface FormUser {
|
|
@@ -304,6 +391,16 @@ export interface FormUser {
|
|
|
304
391
|
}
|
|
305
392
|
export interface Form {
|
|
306
393
|
readonly page: Page;
|
|
394
|
+
/** The app's own functions as the page's expressions call them (`FormOptions.functions`): for what reads its conditions apart. */
|
|
395
|
+
readonly functions?: FunctionTable;
|
|
396
|
+
/**
|
|
397
|
+
* A table line's cell's form (@fieldia/widgets' `lineForm`): the table and the line it is the form of, whose values,
|
|
398
|
+
* choices and words taken out of them are the line's own. Left out of a record's own form.
|
|
399
|
+
*/
|
|
400
|
+
readonly line?: {
|
|
401
|
+
readonly field: string;
|
|
402
|
+
readonly key: string;
|
|
403
|
+
};
|
|
307
404
|
getState(): FormState;
|
|
308
405
|
subscribe(listener: (state: FormState) => void): () => void;
|
|
309
406
|
load(): Promise<void>;
|
|
@@ -324,7 +421,10 @@ export interface Form {
|
|
|
324
421
|
node(id: string): NodeState;
|
|
325
422
|
/** Whether the record is being edited, as conditions read `editing`: a view that locks it to be read says false, and parts follow. */
|
|
326
423
|
setEditing(editing: boolean): void;
|
|
327
|
-
/**
|
|
424
|
+
/**
|
|
425
|
+
* Whether a field is read-only whatever the conditions say: by its definition, for this person by what the record's
|
|
426
|
+
* source said (`can`), or signed by a signature kept (`FileValue.signed`).
|
|
427
|
+
*/
|
|
328
428
|
fieldReadonly(name: string): boolean;
|
|
329
429
|
/** What a field would be told if the form were checked now, or null when it passes. Nothing is shown. */
|
|
330
430
|
problem(field: string): string | null;
|
|
@@ -381,6 +481,20 @@ export interface Form {
|
|
|
381
481
|
validate(): boolean;
|
|
382
482
|
save(): Promise<boolean>;
|
|
383
483
|
reset(): void;
|
|
484
|
+
/**
|
|
485
|
+
* Words of the page's with each `{field}` showing the value the form holds now, as `valueWords` writes it — a label's,
|
|
486
|
+
* a help's, a step's title, a button's: "How was your visit to {branch}?" reads "How was your visit to Zamalek?". A
|
|
487
|
+
* name that is no field of the page shows nothing.
|
|
488
|
+
*/
|
|
489
|
+
words(text: string): string;
|
|
490
|
+
/**
|
|
491
|
+
* The ending a page of responses shows now its answers are sent (`FormState.sent`): the first of the page's
|
|
492
|
+
* `endings` whose `when` holds on the answers as sent, with what the source added and the response's `id`, else the
|
|
493
|
+
* first with no `when`; null before a send, on a page with none, or where none holds.
|
|
494
|
+
*/
|
|
495
|
+
ending(): PageEnding | null;
|
|
496
|
+
/** An ending's words, its `{field}`s and `{id}` filled in from the response sent (`FormState.sent`), as `words` writes them. */
|
|
497
|
+
endingWords(text: string): string;
|
|
384
498
|
changes(): RecordChanges;
|
|
385
499
|
addLine(field: string, values?: Values): string;
|
|
386
500
|
updateLine(field: string, key: string, name: string, value: Value): void;
|
|
@@ -448,9 +562,32 @@ export interface Form {
|
|
|
448
562
|
/**
|
|
449
563
|
* Load, or load again, the choices of a selection whose options come from
|
|
450
564
|
* the app's list (`optionsFrom`). Once loaded, they load again by themselves
|
|
451
|
-
* when a field they change with changes; the latest answer wins
|
|
565
|
+
* when a field they change with changes; the latest answer wins, and a
|
|
566
|
+
* choice it no longer offers after the person, a step or the app changed
|
|
567
|
+
* that field is taken out and said (`FormState.takenOut`). A value a record
|
|
568
|
+
* comes in with is kept, and its save says why. A table line's, by its
|
|
569
|
+
* cell's path (`field.lineKey.subfield`), are asked by the line's values and
|
|
570
|
+
* shared with every line where the columns they change with hold the same,
|
|
571
|
+
* for the record shown; once loaded, they follow those columns on that line.
|
|
452
572
|
*/
|
|
453
573
|
loadChoices(field: string): void;
|
|
574
|
+
/**
|
|
575
|
+
* A table line's choices from the app's list, as they are asked for that line, with `values` laid over it — a row
|
|
576
|
+
* pasted on it, its connection read first. `key` null: a line not added yet, by the values one added now starts with.
|
|
577
|
+
*/
|
|
578
|
+
lineChoices(field: string, key: string | null, subfield: string, values?: Values): Promise<Option[]>;
|
|
579
|
+
/**
|
|
580
|
+
* The options a choice offers now: its own — or those its list gave (`optionsFrom.list`), or those picked in the
|
|
581
|
+
* question they are carried from (`optionsFrom.field`), its own after them — less those whose condition hides them
|
|
582
|
+
* (`options[].invisible`). A table line's by its cell's path (`field.lineKey.subfield`), its conditions read on that
|
|
583
|
+
* line. Null for a field that is no choice.
|
|
584
|
+
*/
|
|
585
|
+
offered(field: string): readonly Option[] | null;
|
|
586
|
+
/**
|
|
587
|
+
* Whether a choice's options change with the record's answers: a condition on one, or carried from another question.
|
|
588
|
+
* A table line's by its cell's path: a condition on one of its column's options.
|
|
589
|
+
*/
|
|
590
|
+
offersChange(field: string): boolean;
|
|
454
591
|
/**
|
|
455
592
|
* Load, or load again, the definitions of a properties field whose
|
|
456
593
|
* definitions come from a linked record (`definitionsFrom`). Once loaded,
|
|
@@ -543,6 +680,19 @@ export interface Form {
|
|
|
543
680
|
on<E extends keyof FormEvents>(event: E, listener: (event: FormEvents[E]) => void): () => void;
|
|
544
681
|
restoreDraft(): void;
|
|
545
682
|
discardDraft(): void;
|
|
683
|
+
/** Whether the page offers "Continue later": it says `continueLater`, and its data source has `saveDraft`. */
|
|
684
|
+
canContinueLater(): boolean;
|
|
685
|
+
/**
|
|
686
|
+
* "Continue later": what is typed read first (`settle`), then the answers so far — their wizard step, text that does
|
|
687
|
+
* not read kept as typed — kept on the app's server through `saveDraft` (`later: true`): its answer, the key, and the
|
|
688
|
+
* link the app made to continue from and its words. Rejects where the source refused, or has no `saveDraft`.
|
|
689
|
+
*/
|
|
690
|
+
continueLater(): Promise<SavedDraft>;
|
|
691
|
+
/**
|
|
692
|
+
* Ask the data source's `limits` again — how many responses the page took, this person's, each choice's takers — and
|
|
693
|
+
* show what it tells (`limits`). The form asks it itself as it opens, before its answers go, and after they went.
|
|
694
|
+
*/
|
|
695
|
+
refreshLimits(): Promise<void>;
|
|
546
696
|
/**
|
|
547
697
|
* Whether a file picked for a file or picture field is stored at once,
|
|
548
698
|
* through the data source's `upload`. False without one: a file then
|
|
@@ -551,6 +701,16 @@ export interface Form {
|
|
|
551
701
|
canUpload(): boolean;
|
|
552
702
|
/** Today, as 2026-10-15, on the clock of the page's time zone — the browser's own where it names none — by the form's clock (`now`). */
|
|
553
703
|
today(): string;
|
|
704
|
+
/** Now, by the form's clock (`now`): the computer's own where the app gave none. A signature's when. */
|
|
705
|
+
now(): Date;
|
|
706
|
+
/** The person using the form, as the app named them (`user`); null where it named none. */
|
|
707
|
+
user(): FormUser | null;
|
|
708
|
+
/**
|
|
709
|
+
* The answers shown now, by field, in the page's order: a field placed on the page — or a saved form's answers, by its
|
|
710
|
+
* name — not hidden by its condition, its roles or the record's source, nor in a step passed over with Skip. What a
|
|
711
|
+
* signature that signs every answer signs.
|
|
712
|
+
*/
|
|
713
|
+
shownFields(): string[];
|
|
554
714
|
/**
|
|
555
715
|
* A record of the page's model as conditions read it, the form's own way: its values (a link as its id), its `id`,
|
|
556
716
|
* the person using the form (`user`), the app's `context`, and `editing` false — for what reads conditions on records
|
|
@@ -581,6 +741,15 @@ export interface Form {
|
|
|
581
741
|
* record shown as it was asked (`recordShown`).
|
|
582
742
|
*/
|
|
583
743
|
findDuplicates(): Promise<DuplicateMatch[]>;
|
|
744
|
+
/** Whether the source keeps "It's someone new" itself, on the app's server: it has `notDuplicates` and `markNotDuplicate`, both. */
|
|
745
|
+
keepsNotDuplicates(): boolean;
|
|
746
|
+
/**
|
|
747
|
+
* The records said to be someone else for the record shown, asked of the source's `notDuplicates`: none while it is
|
|
748
|
+
* new. Rejects where the source has no `notDuplicates`. Its answer is for the record shown as it was asked.
|
|
749
|
+
*/
|
|
750
|
+
notDuplicates(): Promise<RecordId[]>;
|
|
751
|
+
/** Keep that `matchId` is someone else for the record shown, through the source's `markNotDuplicate`: refused while it is new. */
|
|
752
|
+
markNotDuplicate(matchId: RecordId): Promise<void>;
|
|
584
753
|
/** Whether records of the page's model can be merged: its source has `merge`, and `load` to read the others. */
|
|
585
754
|
canMerge(): boolean;
|
|
586
755
|
/** Another record of the page's model, as its source loads it, its values alone: the form is left as it is. For a merge's screen. */
|