@fieldia/core 0.30.0 → 0.31.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 +362 -1
- package/package.json +1 -1
- package/schema/page.schema.json +758 -1
- package/src/index.d.mts +13 -2
- package/src/index.d.ts +13 -2
- package/src/index.js +45 -2
- package/src/index.js.map +1 -1
- package/src/index.mjs +18 -2
- package/src/index.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/actions.js +3 -0
- package/src/lib/format/actions.js.map +1 -1
- package/src/lib/format/actions.mjs +3 -0
- package/src/lib/format/actions.mjs.map +1 -1
- package/src/lib/format/address-search.js +3 -0
- package/src/lib/format/address-search.js.map +1 -1
- package/src/lib/format/address-search.mjs +3 -0
- package/src/lib/format/address-search.mjs.map +1 -1
- package/src/lib/format/duplicates.js +3 -0
- package/src/lib/format/duplicates.js.map +1 -1
- package/src/lib/format/duplicates.mjs +3 -0
- package/src/lib/format/duplicates.mjs.map +1 -1
- package/src/lib/format/endings.js +3 -0
- package/src/lib/format/endings.js.map +1 -1
- package/src/lib/format/endings.mjs +3 -0
- package/src/lib/format/endings.mjs.map +1 -1
- package/src/lib/format/field.d.mts +669 -0
- package/src/lib/format/field.d.ts +669 -0
- package/src/lib/format/field.js +42 -4
- package/src/lib/format/field.js.map +1 -1
- package/src/lib/format/field.mjs +42 -4
- package/src/lib/format/field.mjs.map +1 -1
- package/src/lib/format/flow-checks.d.mts +14 -0
- package/src/lib/format/flow-checks.d.ts +14 -0
- package/src/lib/format/flow-checks.js +61 -0
- package/src/lib/format/flow-checks.js.map +1 -0
- package/src/lib/format/flow-checks.mjs +58 -0
- package/src/lib/format/flow-checks.mjs.map +1 -0
- package/src/lib/format/flow.d.mts +43 -0
- package/src/lib/format/flow.d.ts +43 -0
- package/src/lib/format/flow.js +22 -0
- package/src/lib/format/flow.js.map +1 -0
- package/src/lib/format/flow.mjs +19 -0
- package/src/lib/format/flow.mjs.map +1 -0
- package/src/lib/format/from-schema.d.mts +70 -0
- package/src/lib/format/from-schema.d.ts +70 -0
- package/src/lib/format/from-schema.js +599 -0
- package/src/lib/format/from-schema.js.map +1 -0
- package/src/lib/format/from-schema.mjs +591 -0
- package/src/lib/format/from-schema.mjs.map +1 -0
- package/src/lib/format/jitless.d.mts +1 -0
- package/src/lib/format/jitless.d.ts +1 -0
- package/src/lib/format/jitless.js +27 -0
- package/src/lib/format/jitless.js.map +1 -0
- package/src/lib/format/jitless.mjs +24 -0
- package/src/lib/format/jitless.mjs.map +1 -0
- package/src/lib/format/json-schema.js +3 -0
- package/src/lib/format/json-schema.js.map +1 -1
- package/src/lib/format/json-schema.mjs +3 -0
- package/src/lib/format/json-schema.mjs.map +1 -1
- package/src/lib/format/json.js +3 -0
- package/src/lib/format/json.js.map +1 -1
- package/src/lib/format/json.mjs +3 -0
- package/src/lib/format/json.mjs.map +1 -1
- package/src/lib/format/languages-checks.d.mts +2 -1
- package/src/lib/format/languages-checks.d.ts +2 -1
- package/src/lib/format/languages-checks.js +8 -2
- package/src/lib/format/languages-checks.js.map +1 -1
- package/src/lib/format/languages-checks.mjs +8 -2
- package/src/lib/format/languages-checks.mjs.map +1 -1
- package/src/lib/format/later-checks.d.mts +3 -1
- package/src/lib/format/later-checks.d.ts +3 -1
- package/src/lib/format/later-checks.js +3 -1
- package/src/lib/format/later-checks.js.map +1 -1
- package/src/lib/format/later-checks.mjs +3 -1
- package/src/lib/format/later-checks.mjs.map +1 -1
- package/src/lib/format/layout.d.mts +13192 -7550
- package/src/lib/format/layout.d.ts +13192 -7550
- package/src/lib/format/layout.js +61 -3
- package/src/lib/format/layout.js.map +1 -1
- package/src/lib/format/layout.mjs +59 -1
- package/src/lib/format/layout.mjs.map +1 -1
- package/src/lib/format/layout.types.d.mts +3 -1
- package/src/lib/format/layout.types.d.ts +3 -1
- package/src/lib/format/limits.js +3 -0
- package/src/lib/format/limits.js.map +1 -1
- package/src/lib/format/limits.mjs +3 -0
- package/src/lib/format/limits.mjs.map +1 -1
- package/src/lib/format/list-checks.d.mts +1 -1
- package/src/lib/format/list-checks.d.ts +1 -1
- package/src/lib/format/list-checks.js +67 -22
- package/src/lib/format/list-checks.js.map +1 -1
- package/src/lib/format/list-checks.mjs +67 -22
- package/src/lib/format/list-checks.mjs.map +1 -1
- package/src/lib/format/list-rows-checks.d.mts +11 -0
- package/src/lib/format/list-rows-checks.d.ts +11 -0
- package/src/lib/format/list-rows-checks.js +62 -0
- package/src/lib/format/list-rows-checks.js.map +1 -0
- package/src/lib/format/list-rows-checks.mjs +59 -0
- package/src/lib/format/list-rows-checks.mjs.map +1 -0
- package/src/lib/format/media-options.d.mts +84 -0
- package/src/lib/format/media-options.d.ts +84 -0
- package/src/lib/format/media-options.js +86 -0
- package/src/lib/format/media-options.js.map +1 -0
- package/src/lib/format/media-options.mjs +80 -0
- package/src/lib/format/media-options.mjs.map +1 -0
- package/src/lib/format/outbox-checks.d.mts +11 -0
- package/src/lib/format/outbox-checks.d.ts +11 -0
- package/src/lib/format/outbox-checks.js +12 -0
- package/src/lib/format/outbox-checks.js.map +1 -0
- package/src/lib/format/outbox-checks.mjs +9 -0
- package/src/lib/format/outbox-checks.mjs.map +1 -0
- package/src/lib/format/page.d.mts +3057 -966
- package/src/lib/format/page.d.ts +3057 -966
- package/src/lib/format/page.js +15 -0
- package/src/lib/format/page.js.map +1 -1
- package/src/lib/format/page.mjs +15 -0
- package/src/lib/format/page.mjs.map +1 -1
- package/src/lib/format/part-checks.d.mts +3 -0
- package/src/lib/format/part-checks.d.ts +3 -0
- package/src/lib/format/payment-checks.d.mts +13 -0
- package/src/lib/format/payment-checks.d.ts +13 -0
- package/src/lib/format/payment-checks.js +30 -0
- package/src/lib/format/payment-checks.js.map +1 -0
- package/src/lib/format/payment-checks.mjs +27 -0
- package/src/lib/format/payment-checks.mjs.map +1 -0
- package/src/lib/format/payment.d.mts +37 -0
- package/src/lib/format/payment.d.ts +37 -0
- package/src/lib/format/payment.js +15 -0
- package/src/lib/format/payment.js.map +1 -0
- package/src/lib/format/payment.mjs +12 -0
- package/src/lib/format/payment.mjs.map +1 -0
- package/src/lib/format/phone.js +3 -0
- package/src/lib/format/phone.js.map +1 -1
- package/src/lib/format/phone.mjs +3 -0
- package/src/lib/format/phone.mjs.map +1 -1
- package/src/lib/format/picker-options.d.mts +12 -0
- package/src/lib/format/picker-options.d.ts +12 -0
- package/src/lib/format/picker-options.js +21 -3
- package/src/lib/format/picker-options.js.map +1 -1
- package/src/lib/format/picker-options.mjs +20 -2
- package/src/lib/format/picker-options.mjs.map +1 -1
- package/src/lib/format/prefill-checks.d.mts +13 -0
- package/src/lib/format/prefill-checks.d.ts +13 -0
- package/src/lib/format/prefill-checks.js +35 -0
- package/src/lib/format/prefill-checks.js.map +1 -0
- package/src/lib/format/prefill-checks.mjs +32 -0
- package/src/lib/format/prefill-checks.mjs.map +1 -0
- package/src/lib/format/prefill.d.mts +33 -0
- package/src/lib/format/prefill.d.ts +33 -0
- package/src/lib/format/prefill.js +20 -0
- package/src/lib/format/prefill.js.map +1 -0
- package/src/lib/format/prefill.mjs +17 -0
- package/src/lib/format/prefill.mjs.map +1 -0
- package/src/lib/format/quiz.d.mts +58 -0
- package/src/lib/format/quiz.d.ts +58 -0
- package/src/lib/format/quiz.js +24 -0
- package/src/lib/format/quiz.js.map +1 -0
- package/src/lib/format/quiz.mjs +21 -0
- package/src/lib/format/quiz.mjs.map +1 -0
- package/src/lib/format/records.js +3 -0
- package/src/lib/format/records.js.map +1 -1
- package/src/lib/format/records.mjs +3 -0
- package/src/lib/format/records.mjs.map +1 -1
- package/src/lib/format/references.d.mts +1 -1
- package/src/lib/format/references.d.ts +1 -1
- package/src/lib/format/references.js +56 -7
- package/src/lib/format/references.js.map +1 -1
- package/src/lib/format/references.mjs +57 -8
- package/src/lib/format/references.mjs.map +1 -1
- package/src/lib/format/schedule-checks.d.mts +8 -0
- package/src/lib/format/schedule-checks.d.ts +8 -0
- package/src/lib/format/schedule-checks.js +16 -0
- package/src/lib/format/schedule-checks.js.map +1 -0
- package/src/lib/format/schedule-checks.mjs +13 -0
- package/src/lib/format/schedule-checks.mjs.map +1 -0
- package/src/lib/format/signature-checks.d.mts +8 -0
- package/src/lib/format/signature-checks.d.ts +8 -0
- package/src/lib/format/signature-checks.js +21 -0
- package/src/lib/format/signature-checks.js.map +1 -1
- package/src/lib/format/signature-checks.mjs +20 -0
- package/src/lib/format/signature-checks.mjs.map +1 -1
- package/src/lib/format/signature-options.js +3 -0
- package/src/lib/format/signature-options.js.map +1 -1
- package/src/lib/format/signature-options.mjs +3 -0
- package/src/lib/format/signature-options.mjs.map +1 -1
- package/src/lib/format/slots-options.js +3 -0
- package/src/lib/format/slots-options.js.map +1 -1
- package/src/lib/format/slots-options.mjs +3 -0
- package/src/lib/format/slots-options.mjs.map +1 -1
- package/src/lib/format/templates-checks.d.mts +6 -0
- package/src/lib/format/templates-checks.d.ts +6 -0
- package/src/lib/format/templates-checks.js +16 -0
- package/src/lib/format/templates-checks.js.map +1 -0
- package/src/lib/format/templates-checks.mjs +13 -0
- package/src/lib/format/templates-checks.mjs.map +1 -0
- package/src/lib/format/translate.d.mts +2 -0
- package/src/lib/format/translate.d.ts +2 -0
- package/src/lib/format/translate.js +6 -2
- package/src/lib/format/translate.js.map +1 -1
- package/src/lib/format/translate.mjs +4 -2
- package/src/lib/format/translate.mjs.map +1 -1
- package/src/lib/format/typed-options.d.mts +43 -0
- package/src/lib/format/typed-options.d.ts +43 -0
- package/src/lib/format/typed-options.js +50 -0
- package/src/lib/format/typed-options.js.map +1 -0
- package/src/lib/format/typed-options.mjs +46 -0
- package/src/lib/format/typed-options.mjs.map +1 -0
- package/src/lib/format/upgrade.d.mts +5 -1
- package/src/lib/format/upgrade.d.ts +5 -1
- package/src/lib/format/upgrade.js +5 -1
- package/src/lib/format/upgrade.js.map +1 -1
- package/src/lib/format/upgrade.mjs +5 -1
- package/src/lib/format/upgrade.mjs.map +1 -1
- package/src/lib/format/validate.js +3 -0
- package/src/lib/format/validate.js.map +1 -1
- package/src/lib/format/validate.mjs +3 -0
- package/src/lib/format/validate.mjs.map +1 -1
- package/src/lib/format/verify-checks.d.mts +10 -0
- package/src/lib/format/verify-checks.d.ts +10 -0
- package/src/lib/format/verify-checks.js +44 -0
- package/src/lib/format/verify-checks.js.map +1 -0
- package/src/lib/format/verify-checks.mjs +41 -0
- package/src/lib/format/verify-checks.mjs.map +1 -0
- 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/week.d.mts +18 -0
- package/src/lib/format/week.d.ts +18 -0
- package/src/lib/format/week.js +58 -0
- package/src/lib/format/week.js.map +1 -0
- package/src/lib/format/week.mjs +55 -0
- package/src/lib/format/week.mjs.map +1 -0
- package/src/lib/record/approvals-part.d.mts +1 -1
- package/src/lib/record/approvals-part.d.ts +1 -1
- package/src/lib/record/approvals-part.js +2 -2
- package/src/lib/record/approvals-part.js.map +1 -1
- package/src/lib/record/approvals-part.mjs +1 -1
- package/src/lib/record/approvals-part.mjs.map +1 -1
- package/src/lib/record/data-source.d.mts +337 -3
- package/src/lib/record/data-source.d.ts +337 -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/day-words.d.mts +22 -1
- package/src/lib/record/day-words.d.ts +22 -1
- package/src/lib/record/day-words.js +29 -2
- package/src/lib/record/day-words.js.map +1 -1
- package/src/lib/record/day-words.mjs +24 -2
- package/src/lib/record/day-words.mjs.map +1 -1
- package/src/lib/record/files-part.d.mts +1 -0
- package/src/lib/record/files-part.d.ts +1 -0
- package/src/lib/record/files-part.js +7 -1
- package/src/lib/record/files-part.js.map +1 -1
- package/src/lib/record/files-part.mjs +5 -1
- package/src/lib/record/files-part.mjs.map +1 -1
- package/src/lib/record/form-approvals.d.mts +12 -17
- package/src/lib/record/form-approvals.d.ts +12 -17
- package/src/lib/record/form-approvals.js +15 -9
- package/src/lib/record/form-approvals.js.map +1 -1
- package/src/lib/record/form-approvals.mjs +14 -8
- package/src/lib/record/form-approvals.mjs.map +1 -1
- package/src/lib/record/form-limits.d.mts +4 -28
- package/src/lib/record/form-limits.d.ts +4 -28
- package/src/lib/record/form-limits.js +8 -5
- package/src/lib/record/form-limits.js.map +1 -1
- package/src/lib/record/form-limits.mjs +8 -5
- package/src/lib/record/form-limits.mjs.map +1 -1
- package/src/lib/record/form.d.mts +125 -7
- package/src/lib/record/form.d.ts +125 -7
- package/src/lib/record/form.js +277 -77
- package/src/lib/record/form.js.map +1 -1
- package/src/lib/record/form.mjs +278 -78
- package/src/lib/record/form.mjs.map +1 -1
- package/src/lib/record/history-steps.d.mts +38 -0
- package/src/lib/record/history-steps.d.ts +38 -0
- package/src/lib/record/history-steps.js +63 -0
- package/src/lib/record/history-steps.js.map +1 -0
- package/src/lib/record/history-steps.mjs +58 -0
- package/src/lib/record/history-steps.mjs.map +1 -0
- package/src/lib/record/history.d.mts +16 -0
- package/src/lib/record/history.d.ts +16 -0
- package/src/lib/record/history.js +3 -0
- package/src/lib/record/history.js.map +1 -0
- package/src/lib/record/history.mjs +2 -0
- package/src/lib/record/history.mjs.map +1 -0
- package/src/lib/record/input-rules.d.mts +2 -0
- package/src/lib/record/input-rules.d.ts +2 -0
- package/src/lib/record/input-rules.js +4 -1
- package/src/lib/record/input-rules.js.map +1 -1
- package/src/lib/record/input-rules.mjs +2 -0
- package/src/lib/record/input-rules.mjs.map +1 -1
- package/src/lib/record/joins.d.mts +143 -0
- package/src/lib/record/joins.d.ts +143 -0
- package/src/lib/record/joins.js +28 -0
- package/src/lib/record/joins.js.map +1 -0
- package/src/lib/record/joins.mjs +24 -0
- package/src/lib/record/joins.mjs.map +1 -0
- package/src/lib/record/limits.js +7 -4
- package/src/lib/record/limits.js.map +1 -1
- package/src/lib/record/limits.mjs +8 -5
- package/src/lib/record/limits.mjs.map +1 -1
- package/src/lib/record/link-values.d.mts +31 -0
- package/src/lib/record/link-values.d.ts +31 -0
- package/src/lib/record/link-values.js +132 -0
- package/src/lib/record/link-values.js.map +1 -0
- package/src/lib/record/link-values.mjs +125 -0
- package/src/lib/record/link-values.mjs.map +1 -0
- package/src/lib/record/live-later.d.mts +15 -0
- package/src/lib/record/live-later.d.ts +15 -0
- package/src/lib/record/live-later.js +10 -0
- package/src/lib/record/live-later.js.map +1 -0
- package/src/lib/record/live-later.mjs +7 -0
- package/src/lib/record/live-later.mjs.map +1 -0
- package/src/lib/record/live-part.d.mts +6 -0
- package/src/lib/record/live-part.d.ts +6 -0
- package/src/lib/record/live-part.js +12 -0
- package/src/lib/record/live-part.js.map +1 -0
- package/src/lib/record/live-part.mjs +7 -0
- package/src/lib/record/live-part.mjs.map +1 -0
- package/src/lib/record/live.d.mts +8 -0
- package/src/lib/record/live.d.ts +8 -0
- package/src/lib/record/live.js +133 -0
- package/src/lib/record/live.js.map +1 -0
- package/src/lib/record/live.mjs +129 -0
- package/src/lib/record/live.mjs.map +1 -0
- package/src/lib/record/locales/all.d.mts +5 -5
- package/src/lib/record/locales/all.d.ts +5 -5
- package/src/lib/record/locales/all.js +3 -3
- package/src/lib/record/locales/all.js.map +1 -1
- package/src/lib/record/locales/all.mjs +3 -3
- package/src/lib/record/locales/all.mjs.map +1 -1
- package/src/lib/record/locales/ar.js +11 -1
- package/src/lib/record/locales/ar.js.map +1 -1
- package/src/lib/record/locales/ar.mjs +11 -1
- package/src/lib/record/locales/ar.mjs.map +1 -1
- package/src/lib/record/locales/de.js +11 -1
- package/src/lib/record/locales/de.js.map +1 -1
- package/src/lib/record/locales/de.mjs +11 -1
- package/src/lib/record/locales/de.mjs.map +1 -1
- package/src/lib/record/locales/es.d.mts +8 -0
- package/src/lib/record/locales/es.d.ts +8 -0
- package/src/lib/record/locales/es.js +111 -0
- package/src/lib/record/locales/es.js.map +1 -0
- package/src/lib/record/locales/es.mjs +108 -0
- package/src/lib/record/locales/es.mjs.map +1 -0
- package/src/lib/record/locales/fa.d.mts +5 -0
- package/src/lib/record/locales/fa.d.ts +5 -0
- package/src/lib/record/locales/fa.js +117 -0
- package/src/lib/record/locales/fa.js.map +1 -0
- package/src/lib/record/locales/fa.mjs +114 -0
- package/src/lib/record/locales/fa.mjs.map +1 -0
- package/src/lib/record/locales/fr.js +11 -1
- package/src/lib/record/locales/fr.js.map +1 -1
- package/src/lib/record/locales/fr.mjs +11 -1
- package/src/lib/record/locales/fr.mjs.map +1 -1
- package/src/lib/record/locales/later.d.mts +8 -0
- package/src/lib/record/locales/later.d.ts +8 -0
- package/src/lib/record/locales/later.js +16 -0
- package/src/lib/record/locales/later.js.map +1 -0
- package/src/lib/record/locales/later.mjs +13 -0
- package/src/lib/record/locales/later.mjs.map +1 -0
- package/src/lib/record/locales/tr.d.mts +6 -0
- package/src/lib/record/locales/tr.d.ts +6 -0
- package/src/lib/record/locales/tr.js +118 -0
- package/src/lib/record/locales/tr.js.map +1 -0
- package/src/lib/record/locales/tr.mjs +115 -0
- package/src/lib/record/locales/tr.mjs.map +1 -0
- package/src/lib/record/locales/ur.d.mts +9 -0
- package/src/lib/record/locales/ur.d.ts +9 -0
- package/src/lib/record/locales/ur.js +118 -0
- package/src/lib/record/locales/ur.js.map +1 -0
- package/src/lib/record/locales/ur.mjs +115 -0
- package/src/lib/record/locales/ur.mjs.map +1 -0
- package/src/lib/record/memory-approvals.d.mts +7 -4
- package/src/lib/record/memory-approvals.d.ts +7 -4
- package/src/lib/record/memory-approvals.js +54 -7
- package/src/lib/record/memory-approvals.js.map +1 -1
- package/src/lib/record/memory-approvals.mjs +54 -7
- package/src/lib/record/memory-approvals.mjs.map +1 -1
- package/src/lib/record/memory-assist.d.mts +7 -2
- package/src/lib/record/memory-assist.d.ts +7 -2
- package/src/lib/record/memory-assist.js +47 -12
- package/src/lib/record/memory-assist.js.map +1 -1
- package/src/lib/record/memory-assist.mjs +46 -12
- package/src/lib/record/memory-assist.mjs.map +1 -1
- package/src/lib/record/memory-codes.d.mts +37 -0
- package/src/lib/record/memory-codes.d.ts +37 -0
- package/src/lib/record/memory-codes.js +50 -0
- package/src/lib/record/memory-codes.js.map +1 -0
- package/src/lib/record/memory-codes.mjs +47 -0
- package/src/lib/record/memory-codes.mjs.map +1 -0
- package/src/lib/record/memory-data-source.d.mts +60 -4
- package/src/lib/record/memory-data-source.d.ts +60 -4
- package/src/lib/record/memory-data-source.js +69 -1
- package/src/lib/record/memory-data-source.js.map +1 -1
- package/src/lib/record/memory-data-source.mjs +69 -1
- package/src/lib/record/memory-data-source.mjs.map +1 -1
- package/src/lib/record/memory-kept.d.mts +3 -1
- package/src/lib/record/memory-kept.d.ts +3 -1
- package/src/lib/record/memory-kept.js +7 -2
- package/src/lib/record/memory-kept.js.map +1 -1
- package/src/lib/record/memory-kept.mjs +7 -2
- package/src/lib/record/memory-kept.mjs.map +1 -1
- package/src/lib/record/memory-later.d.mts +3 -1
- package/src/lib/record/memory-later.d.ts +3 -1
- package/src/lib/record/memory-later.js +9 -5
- package/src/lib/record/memory-later.js.map +1 -1
- package/src/lib/record/memory-later.mjs +8 -4
- package/src/lib/record/memory-later.mjs.map +1 -1
- package/src/lib/record/memory-live.d.mts +8 -0
- package/src/lib/record/memory-live.d.ts +8 -0
- package/src/lib/record/memory-live.js +70 -0
- package/src/lib/record/memory-live.js.map +1 -0
- package/src/lib/record/memory-live.mjs +67 -0
- package/src/lib/record/memory-live.mjs.map +1 -0
- package/src/lib/record/memory-views.d.mts +11 -0
- package/src/lib/record/memory-views.d.ts +11 -0
- package/src/lib/record/memory-views.js +60 -0
- package/src/lib/record/memory-views.js.map +1 -0
- package/src/lib/record/memory-views.mjs +57 -0
- package/src/lib/record/memory-views.mjs.map +1 -0
- package/src/lib/record/messages.d.mts +24 -3
- package/src/lib/record/messages.d.ts +24 -3
- package/src/lib/record/messages.js +18 -3
- package/src/lib/record/messages.js.map +1 -1
- package/src/lib/record/messages.mjs +18 -3
- package/src/lib/record/messages.mjs.map +1 -1
- package/src/lib/record/order.d.mts +21 -0
- package/src/lib/record/order.d.ts +21 -0
- package/src/lib/record/order.js +129 -0
- package/src/lib/record/order.js.map +1 -0
- package/src/lib/record/order.mjs +122 -0
- package/src/lib/record/order.mjs.map +1 -0
- package/src/lib/record/outbox-form.d.mts +79 -0
- package/src/lib/record/outbox-form.d.ts +79 -0
- package/src/lib/record/outbox-form.js +291 -0
- package/src/lib/record/outbox-form.js.map +1 -0
- package/src/lib/record/outbox-form.mjs +286 -0
- package/src/lib/record/outbox-form.mjs.map +1 -0
- package/src/lib/record/outbox-part.d.mts +6 -0
- package/src/lib/record/outbox-part.d.ts +6 -0
- package/src/lib/record/outbox-part.js +13 -0
- package/src/lib/record/outbox-part.js.map +1 -0
- package/src/lib/record/outbox-part.mjs +7 -0
- package/src/lib/record/outbox-part.mjs.map +1 -0
- package/src/lib/record/pay-part.d.mts +6 -0
- package/src/lib/record/pay-part.d.ts +6 -0
- package/src/lib/record/pay-part.js +11 -0
- package/src/lib/record/pay-part.js.map +1 -0
- package/src/lib/record/pay-part.mjs +7 -0
- package/src/lib/record/pay-part.mjs.map +1 -0
- package/src/lib/record/payment-form.d.mts +25 -0
- package/src/lib/record/payment-form.d.ts +25 -0
- package/src/lib/record/payment-form.js +98 -0
- package/src/lib/record/payment-form.js.map +1 -0
- package/src/lib/record/payment-form.mjs +95 -0
- package/src/lib/record/payment-form.mjs.map +1 -0
- package/src/lib/record/prefill-part.d.mts +7 -0
- package/src/lib/record/prefill-part.d.ts +7 -0
- package/src/lib/record/prefill-part.js +15 -0
- package/src/lib/record/prefill-part.js.map +1 -0
- package/src/lib/record/prefill-part.mjs +8 -0
- package/src/lib/record/prefill-part.mjs.map +1 -0
- package/src/lib/record/press-undo.d.mts +42 -0
- package/src/lib/record/press-undo.d.ts +42 -0
- package/src/lib/record/press-undo.js +115 -0
- package/src/lib/record/press-undo.js.map +1 -0
- package/src/lib/record/press-undo.mjs +110 -0
- package/src/lib/record/press-undo.mjs.map +1 -0
- package/src/lib/record/quiz.d.mts +36 -0
- package/src/lib/record/quiz.d.ts +36 -0
- package/src/lib/record/quiz.js +90 -0
- package/src/lib/record/quiz.js.map +1 -0
- package/src/lib/record/quiz.mjs +87 -0
- package/src/lib/record/quiz.mjs.map +1 -0
- package/src/lib/record/record-words.js +1 -1
- package/src/lib/record/record-words.js.map +1 -1
- package/src/lib/record/record-words.mjs +1 -1
- package/src/lib/record/record-words.mjs.map +1 -1
- package/src/lib/record/run.d.mts +71 -8
- package/src/lib/record/run.d.ts +71 -8
- package/src/lib/record/run.js +40 -13
- package/src/lib/record/run.js.map +1 -1
- package/src/lib/record/run.mjs +38 -12
- package/src/lib/record/run.mjs.map +1 -1
- package/src/lib/record/survey-kit.d.mts +37 -0
- package/src/lib/record/survey-kit.d.ts +37 -0
- package/src/lib/record/survey-kit.js +99 -0
- package/src/lib/record/survey-kit.js.map +1 -0
- package/src/lib/record/survey-kit.mjs +96 -0
- package/src/lib/record/survey-kit.mjs.map +1 -0
- package/src/lib/record/survey.d.mts +16 -0
- package/src/lib/record/survey.d.ts +16 -0
- package/src/lib/record/survey.js +17 -0
- package/src/lib/record/survey.js.map +1 -0
- package/src/lib/record/survey.mjs +13 -0
- package/src/lib/record/survey.mjs.map +1 -0
- package/src/lib/record/surveyflow-part.d.mts +9 -0
- package/src/lib/record/surveyflow-part.d.ts +9 -0
- package/src/lib/record/surveyflow-part.js +20 -0
- package/src/lib/record/surveyflow-part.js.map +1 -0
- package/src/lib/record/surveyflow-part.mjs +10 -0
- package/src/lib/record/surveyflow-part.mjs.map +1 -0
- package/src/lib/record/timing.d.mts +76 -0
- package/src/lib/record/timing.d.ts +76 -0
- package/src/lib/record/timing.js +112 -0
- package/src/lib/record/timing.js.map +1 -0
- package/src/lib/record/timing.mjs +104 -0
- package/src/lib/record/timing.mjs.map +1 -0
- package/src/lib/record/undo-later.d.mts +9 -0
- package/src/lib/record/undo-later.d.ts +9 -0
- package/src/lib/record/undo-later.js +10 -0
- package/src/lib/record/undo-later.js.map +1 -0
- package/src/lib/record/undo-later.mjs +7 -0
- package/src/lib/record/undo-later.mjs.map +1 -0
- package/src/lib/record/undo-part.d.mts +8 -0
- package/src/lib/record/undo-part.d.ts +8 -0
- package/src/lib/record/undo-part.js +17 -0
- package/src/lib/record/undo-part.js.map +1 -0
- package/src/lib/record/undo-part.mjs +9 -0
- package/src/lib/record/undo-part.mjs.map +1 -0
- package/src/lib/record/upload-to-later.d.mts +10 -0
- package/src/lib/record/upload-to-later.d.ts +10 -0
- package/src/lib/record/upload-to-later.js +15 -0
- package/src/lib/record/upload-to-later.js.map +1 -0
- package/src/lib/record/upload-to-later.mjs +12 -0
- package/src/lib/record/upload-to-later.mjs.map +1 -0
- package/src/lib/record/uploads.d.mts +5 -0
- package/src/lib/record/uploads.d.ts +5 -0
- package/src/lib/record/uploads.js.map +1 -1
- package/src/lib/record/uploads.mjs.map +1 -1
- package/src/lib/record/values.d.mts +6 -0
- package/src/lib/record/values.d.ts +6 -0
- package/src/lib/record/values.js.map +1 -1
- package/src/lib/record/values.mjs.map +1 -1
- package/src/lib/record/verify-form.d.mts +24 -0
- package/src/lib/record/verify-form.d.ts +24 -0
- package/src/lib/record/verify-form.js +65 -0
- package/src/lib/record/verify-form.js.map +1 -0
- package/src/lib/record/verify-form.mjs +62 -0
- package/src/lib/record/verify-form.mjs.map +1 -0
- package/src/lib/record/verify-part.d.mts +6 -0
- package/src/lib/record/verify-part.d.ts +6 -0
- package/src/lib/record/verify-part.js +11 -0
- package/src/lib/record/verify-part.js.map +1 -0
- package/src/lib/record/verify-part.mjs +7 -0
- package/src/lib/record/verify-part.mjs.map +1 -0
- package/src/lib/record/words-chunks.d.mts +37 -0
- package/src/lib/record/words-chunks.d.ts +37 -0
- package/src/lib/record/words-chunks.js +94 -0
- package/src/lib/record/words-chunks.js.map +1 -0
- package/src/lib/record/words-chunks.mjs +86 -0
- package/src/lib/record/words-chunks.mjs.map +1 -0
- package/src/runtime.d.mts +28 -6
- package/src/runtime.d.ts +28 -6
- package/src/runtime.js +35 -6
- package/src/runtime.js.map +1 -1
- package/src/runtime.mjs +15 -3
- package/src/runtime.mjs.map +1 -1
package/src/lib/record/form.mjs
CHANGED
|
@@ -22,13 +22,14 @@ import { askKey, cellOf, listedColumns, notOffered } from './line-choices.mjs';
|
|
|
22
22
|
import { loadedRecordOf, saveProblemOf, } from './data-source.mjs';
|
|
23
23
|
import { formLimitsPart, hasLimits } from './taking.mjs';
|
|
24
24
|
import { formLanguagesPart, hasLanguages } from './languages.mjs';
|
|
25
|
-
import { formApprovalsPart } from './approving.mjs';
|
|
26
25
|
import { draftRead, resumeStep } from './drafts.mjs';
|
|
27
26
|
import { waitingOn, workedOutFrom } from './waits.mjs';
|
|
28
27
|
import { createUploads, fileBytesIn, uploadGoing, withoutFileBytes } from './uploads.mjs';
|
|
29
28
|
import { hostScheduler } from './scheduler.mjs';
|
|
30
29
|
import { signedBy } from './signed.mjs';
|
|
31
|
-
import {
|
|
30
|
+
import { formJoins } from './joins.mjs';
|
|
31
|
+
import { pressUndoPart } from './undo-later.mjs';
|
|
32
|
+
import { createMoments, createRunner, takenNow } from './run.mjs';
|
|
32
33
|
import { emptyValue, initialValues, isEmpty, lineKind, structuredCopy, } from './values.mjs';
|
|
33
34
|
/**
|
|
34
35
|
* Whether leaving the record now would lose the person's work: changes not
|
|
@@ -89,7 +90,9 @@ function innerForm(options, within, place, outer) {
|
|
|
89
90
|
// A field's label small inside a message's sentence where the page asks (`lowerLabels`).
|
|
90
91
|
// …and a day written in the page's order where it says one (`look.dateOrder`): "can't be after Oct 20, 2026".
|
|
91
92
|
const dateOrder = page.look?.dateOrder;
|
|
92
|
-
|
|
93
|
+
// The page's ask over the language's messages, each read through to them as it is said: a language whose words come in a
|
|
94
|
+
// chunk of their own fills its table in place once they have come (words-chunks.ts).
|
|
95
|
+
const messages = page.lowerLabels || dateOrder ? Object.assign(Object.create(options.messages ?? MESSAGES.en), { lowerLabels: page.lowerLabels, dateOrder }) : (options.messages ?? MESSAGES.en);
|
|
93
96
|
/** One of the form's sentences in the words the page names its records by (`records`), else as the language says it plainly. */
|
|
94
97
|
const named = (noun, plain) => recordSentence(page.records, noun, plain, messages.locale);
|
|
95
98
|
/** The app's functions the page's expressions call: a name none may call is refused now. */
|
|
@@ -186,7 +189,23 @@ function innerForm(options, within, place, outer) {
|
|
|
186
189
|
placeholderOf('#title', page.layout.title);
|
|
187
190
|
/** Whether any rule only warns: without one, there are never warnings to look for. */
|
|
188
191
|
const warns = [...nodeRules.values()].some((rules) => rules.some((compiled) => compiled.rule.level === 'warning'));
|
|
189
|
-
const
|
|
192
|
+
const layoutSteps = page.layout.type === 'wizard' ? page.layout.children.map((step) => step.id) : [];
|
|
193
|
+
/** The wizard's steps in the order shown: the page's, or the order drawn for this respondent (`state.order`). */
|
|
194
|
+
let steps = layoutSteps;
|
|
195
|
+
/**
|
|
196
|
+
* The parts that join this form where its page or its source asks (`formJoins`: an offline outbox, the fields its link
|
|
197
|
+
* fills, proof by a code, a payment, a survey's flow, a record's approvals, the record made live), each made as it
|
|
198
|
+
* comes — at once where it has — and kept in their order: holes until then. While one has not come, a send waits for it
|
|
199
|
+
* (`joining`); a draft laid before one came is laid on it as it does (`laid`).
|
|
200
|
+
*/
|
|
201
|
+
const joins = [];
|
|
202
|
+
const joinParts = formJoins(page, options).filter((part) => !outer || part.name !== 'approvals');
|
|
203
|
+
let joining;
|
|
204
|
+
let laid = null;
|
|
205
|
+
/** A part's side of this form, by its name, once it came. */
|
|
206
|
+
const joined = (name) => (joins[joinParts.findIndex((part) => part.name === name)] ?? null);
|
|
207
|
+
/** Whether a part that joins the form says so of a part of the page, or of a field. */
|
|
208
|
+
const anyJoin = (says) => joins.some((join) => join && says(join));
|
|
190
209
|
const storeKey = () => `fieldia:draft:${page.id}:${state.recordId ?? 'new'}`;
|
|
191
210
|
/** Today, on the clock of the page's time zone (the browser's own when it names none). */
|
|
192
211
|
const today = () => dayIn(options.now?.() ?? new Date(), page.timeZone);
|
|
@@ -364,6 +383,9 @@ function innerForm(options, within, place, outer) {
|
|
|
364
383
|
limits: null,
|
|
365
384
|
resume: null,
|
|
366
385
|
approval: null,
|
|
386
|
+
order: null,
|
|
387
|
+
timers: {},
|
|
388
|
+
timeUp: [],
|
|
367
389
|
};
|
|
368
390
|
started = true;
|
|
369
391
|
/**
|
|
@@ -456,6 +478,8 @@ function innerForm(options, within, place, outer) {
|
|
|
456
478
|
filesChanged();
|
|
457
479
|
},
|
|
458
480
|
track,
|
|
481
|
+
// Through the parts that join the form: a photo taken without signal kept as its bytes, on a page with an outbox.
|
|
482
|
+
through,
|
|
459
483
|
});
|
|
460
484
|
/**
|
|
461
485
|
* Files on their way changed, here or in a saved form placed here: the
|
|
@@ -553,6 +577,87 @@ function innerForm(options, within, place, outer) {
|
|
|
553
577
|
const listed = listedColumns(page.fields);
|
|
554
578
|
/** Whether the values set now are a change someone made (`writeValues`), after which a line's choice no longer offered is cleared. */
|
|
555
579
|
let edit = false;
|
|
580
|
+
/**
|
|
581
|
+
* The one kit the parts that work inside the form are given of it (joins.ts): the parts that join it, its limits, the
|
|
582
|
+
* undo part's press.
|
|
583
|
+
*/
|
|
584
|
+
const inner = {
|
|
585
|
+
get form() {
|
|
586
|
+
return form;
|
|
587
|
+
},
|
|
588
|
+
page,
|
|
589
|
+
fields,
|
|
590
|
+
options,
|
|
591
|
+
messages,
|
|
592
|
+
scheduler,
|
|
593
|
+
state: () => state,
|
|
594
|
+
set,
|
|
595
|
+
reading,
|
|
596
|
+
sending: () => (page.data.kind === 'responses' ? answersSent() : sentValues()),
|
|
597
|
+
baseline: () => baseline,
|
|
598
|
+
same: (name, one, other) => sameValue(fields[name], one, other),
|
|
599
|
+
conflictOf,
|
|
600
|
+
store,
|
|
601
|
+
settled: savesSettled,
|
|
602
|
+
track,
|
|
603
|
+
shownNow,
|
|
604
|
+
generation: () => generation,
|
|
605
|
+
emit,
|
|
606
|
+
replaced,
|
|
607
|
+
clock,
|
|
608
|
+
started: () => started,
|
|
609
|
+
listened: () => listeners.size > 0,
|
|
610
|
+
disposed: () => disposed,
|
|
611
|
+
keep: () => void ((options.drafts || onServer()) && scheduleDraft()),
|
|
612
|
+
order: (list) => void (steps = list ?? layoutSteps),
|
|
613
|
+
refuse(name, message) {
|
|
614
|
+
// Said until the field changes from what it holds, as a refused save's words are.
|
|
615
|
+
serverErrors[name] = { message, value: JSON.stringify(state.values[name] ?? null) };
|
|
616
|
+
set({ errors: { ...state.errors, [name]: message } });
|
|
617
|
+
},
|
|
618
|
+
reload: () => load(true),
|
|
619
|
+
};
|
|
620
|
+
/** The person's changes to the record shown, as made (history.ts); and whether one is being taken back or made again now. */
|
|
621
|
+
let noted = [];
|
|
622
|
+
let replaying = false;
|
|
623
|
+
/**
|
|
624
|
+
* A person's change written to `field` (on `line`), noted for Undo with what it held `before`: typing on joins it
|
|
625
|
+
* (`joins`). The undo part takes them as they come, asked for with the first: in by the time the person presses Ctrl+Z.
|
|
626
|
+
*/
|
|
627
|
+
const noteChange = (field, line, before, joins) => {
|
|
628
|
+
if (replaying)
|
|
629
|
+
return;
|
|
630
|
+
noted.push([field, line, before ?? null, state.values[field] ?? null, joins]);
|
|
631
|
+
const part = pressUndoPart.loaded;
|
|
632
|
+
if (part)
|
|
633
|
+
part.takeNoted(noted, inner.same);
|
|
634
|
+
// Kept while it comes; where it cannot, the oldest let go.
|
|
635
|
+
else if (noted.length > 500)
|
|
636
|
+
noted.shift();
|
|
637
|
+
else
|
|
638
|
+
pressUndoPart.load().catch(() => undefined);
|
|
639
|
+
};
|
|
640
|
+
/**
|
|
641
|
+
* Undo (`back`) or Redo, once the undo part has come: the change taken, written as the person's own change back —
|
|
642
|
+
* the page's `change` steps and the source's onchange run as for any — once its field still holds what the change
|
|
643
|
+
* left and may be changed.
|
|
644
|
+
*/
|
|
645
|
+
function replay(back) {
|
|
646
|
+
const step = editing ? pressUndoPart.loaded?.takeStep(noted, inner.same, back, (one, left) => !form.fieldReadonly(one.field) && sameValue(fields[one.field], state.values[one.field], left)) : null;
|
|
647
|
+
if (!step)
|
|
648
|
+
return null;
|
|
649
|
+
const { value, ...taken } = step;
|
|
650
|
+
replaying = true;
|
|
651
|
+
try {
|
|
652
|
+
writeValues({ ...state.values, [taken.field]: structuredCopy(value) });
|
|
653
|
+
afterEdit(taken.field);
|
|
654
|
+
changed(taken.field, 'person', taken.line === undefined ? {} : { line: taken.line });
|
|
655
|
+
}
|
|
656
|
+
finally {
|
|
657
|
+
replaying = false;
|
|
658
|
+
}
|
|
659
|
+
return taken;
|
|
660
|
+
}
|
|
556
661
|
function set(patch) {
|
|
557
662
|
const was = state.values;
|
|
558
663
|
const choicesWas = state.choices;
|
|
@@ -586,6 +691,10 @@ function innerForm(options, within, place, outer) {
|
|
|
586
691
|
part.inner.show(inside(state.errors, part.name));
|
|
587
692
|
for (const listener of [...listeners])
|
|
588
693
|
listener(state);
|
|
694
|
+
// What the parts that join the form follow of it: the record shown, watched for changes made elsewhere and for who
|
|
695
|
+
// else has it open, asked again as that changes.
|
|
696
|
+
for (const join of joins)
|
|
697
|
+
join?.changed?.();
|
|
589
698
|
// Choices that change with a value that just changed are asked for again.
|
|
590
699
|
if (state.values !== was) {
|
|
591
700
|
// After someone's change, a choice its new choices do not offer is taken out and said, as a line's is.
|
|
@@ -625,6 +734,7 @@ function innerForm(options, within, place, outer) {
|
|
|
625
734
|
/** Another record is shown: nothing of the last one's is the person's work any more, and its files on their way stop. */
|
|
626
735
|
function newGeneration() {
|
|
627
736
|
generation++;
|
|
737
|
+
noted = [];
|
|
628
738
|
// Another record's lines ask the source anew.
|
|
629
739
|
lineAsks = new Map();
|
|
630
740
|
answers = new Map();
|
|
@@ -737,6 +847,9 @@ function innerForm(options, within, place, outer) {
|
|
|
737
847
|
return;
|
|
738
848
|
told = step;
|
|
739
849
|
emit('step', { step });
|
|
850
|
+
// A step with a time limit: its clock starts as it is first entered.
|
|
851
|
+
for (const join of joins)
|
|
852
|
+
join?.entered?.(step);
|
|
740
853
|
const list = page.on?.show?.[step];
|
|
741
854
|
if (list)
|
|
742
855
|
void track(moment(`on.show.${step}`, list, chain, true));
|
|
@@ -1108,13 +1221,13 @@ function innerForm(options, within, place, outer) {
|
|
|
1108
1221
|
if (!node)
|
|
1109
1222
|
throw new Error(`The page has no element "${id}"`);
|
|
1110
1223
|
const { context: ctx, env } = reading();
|
|
1111
|
-
const hidden = (at) => (at ? !rolesAllow(at.roles, userRoles) || at.invisible.evaluate(ctx, env) : false);
|
|
1224
|
+
const hidden = (at) => (at ? anyJoin((join) => join.hides?.(at.id)) || !rolesAllow(at.roles, userRoles) || at.invisible.evaluate(ctx, env) : false);
|
|
1112
1225
|
let invisible = hidden(node);
|
|
1113
1226
|
for (let parent = node.parent; !invisible && parent; parent = index.get(parent)?.parent ?? null) {
|
|
1114
1227
|
invisible = hidden(index.get(parent));
|
|
1115
1228
|
}
|
|
1116
|
-
// A section read-only right now makes everything inside it read-only too.
|
|
1117
|
-
let readonly = node.readonly.evaluate(ctx, env);
|
|
1229
|
+
// A section read-only right now makes everything inside it read-only too; a page's, or a step's, time run out too.
|
|
1230
|
+
let readonly = node.readonly.evaluate(ctx, env) || anyJoin((join) => join.locks?.(id));
|
|
1118
1231
|
for (let parent = node.parent; !readonly && parent; parent = index.get(parent)?.parent ?? null) {
|
|
1119
1232
|
readonly = index.get(parent)?.readonly.evaluate(ctx, env) ?? false;
|
|
1120
1233
|
}
|
|
@@ -1132,7 +1245,7 @@ function innerForm(options, within, place, outer) {
|
|
|
1132
1245
|
if (answer !== undefined && signedNow().has(answer))
|
|
1133
1246
|
readonly = true;
|
|
1134
1247
|
// A record waiting for approval: locked but for the fields the page leaves open (the approvals part).
|
|
1135
|
-
if (answer !== undefined &&
|
|
1248
|
+
if (answer !== undefined && anyJoin((join) => join.locksField?.(answer)))
|
|
1136
1249
|
readonly = true;
|
|
1137
1250
|
return {
|
|
1138
1251
|
invisible,
|
|
@@ -1274,6 +1387,9 @@ function innerForm(options, within, place, outer) {
|
|
|
1274
1387
|
const errors = {};
|
|
1275
1388
|
const seen = new Set();
|
|
1276
1389
|
for (const node of visibleFieldNodes(root)) {
|
|
1390
|
+
// The answers of a time run out go as they stood: their checks refuse nothing.
|
|
1391
|
+
if (anyJoin((join) => join.locks?.(node.id)))
|
|
1392
|
+
continue;
|
|
1277
1393
|
const name = node.field;
|
|
1278
1394
|
seen.add(name);
|
|
1279
1395
|
const end = rangeEnd(node);
|
|
@@ -1582,6 +1698,7 @@ function innerForm(options, within, place, outer) {
|
|
|
1582
1698
|
return {
|
|
1583
1699
|
values,
|
|
1584
1700
|
...(steps.length ? { step: state.step, skipped: [...state.skipped] } : {}),
|
|
1701
|
+
...Object.assign({}, ...joins.map((join) => join?.kept?.())),
|
|
1585
1702
|
...(Object.keys(state.unread).length ? { unread: structuredCopy(state.unread) } : {}),
|
|
1586
1703
|
answered: Object.keys(fields).filter((name) => state.dirty.includes(name)),
|
|
1587
1704
|
savedAt: new Date(clock()).toISOString(),
|
|
@@ -1637,6 +1754,10 @@ function innerForm(options, within, place, outer) {
|
|
|
1637
1754
|
/** A draft laid on the form: its answers as a starting point, its wizard step (or the nearest before it that applies), its text that does not read. */
|
|
1638
1755
|
function applyDraft(draft) {
|
|
1639
1756
|
found = null;
|
|
1757
|
+
// Its draw and its clocks, by the survey flow's part: now, or once it came.
|
|
1758
|
+
laid = draft;
|
|
1759
|
+
for (const join of joins)
|
|
1760
|
+
join?.lay?.(draft);
|
|
1640
1761
|
writeValues(withDraft(draft.values ?? {}), { draft: null }, true);
|
|
1641
1762
|
const known = (draft.skipped ?? []).filter((id) => steps.includes(id));
|
|
1642
1763
|
// Text typed that did not read stays as typed, said as it was, where its field is still on the page.
|
|
@@ -1731,27 +1852,8 @@ function innerForm(options, within, place, outer) {
|
|
|
1731
1852
|
function limitsMade(part) {
|
|
1732
1853
|
if (limitsKit || disposed)
|
|
1733
1854
|
return limitsKit;
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
dataSource: options.dataSource,
|
|
1737
|
-
user: options.user,
|
|
1738
|
-
messages,
|
|
1739
|
-
scheduler,
|
|
1740
|
-
state: () => state,
|
|
1741
|
-
set,
|
|
1742
|
-
clock,
|
|
1743
|
-
started: () => started,
|
|
1744
|
-
shownNow,
|
|
1745
|
-
generation: () => generation,
|
|
1746
|
-
replaced: () => named(messages.recordReplacedNoun, messages.recordReplaced),
|
|
1747
|
-
listened: () => listeners.size > 0,
|
|
1748
|
-
disposed: () => disposed,
|
|
1749
|
-
refuse(name, message) {
|
|
1750
|
-
// Said until the field changes from what it holds, as a refused save's words are.
|
|
1751
|
-
serverErrors[name] = { message, value: JSON.stringify(state.values[name] ?? null) };
|
|
1752
|
-
set({ errors: { ...state.errors, [name]: message } });
|
|
1753
|
-
},
|
|
1754
|
-
});
|
|
1855
|
+
// The one kit, made at the limits' own moment: once the form knows it keeps them (joins.ts).
|
|
1856
|
+
const kit = part.formLimits(inner);
|
|
1755
1857
|
limitsKit = kit;
|
|
1756
1858
|
kit.show();
|
|
1757
1859
|
if (kit.asks() && (state.recordId == null || loadedOnce))
|
|
@@ -1772,15 +1874,6 @@ function innerForm(options, within, place, outer) {
|
|
|
1772
1874
|
}
|
|
1773
1875
|
/** A choice of a full option, picked by the person, refused under its field: the field keeps what it held. */
|
|
1774
1876
|
const refusedFull = (name, value) => !!limitsKit?.refusedFull(name, value);
|
|
1775
|
-
// ---- a record's approvals (the approvals part: form-approvals.ts) ---------------------------------------------------
|
|
1776
|
-
/** The approvals made for this form from the approvals part, once it came: none before, nor on a page without them. */
|
|
1777
|
-
let approvalKit = null;
|
|
1778
|
-
/** Whether the form asks for approvals: a page with `approval` (a record's own, as its check says), its source telling them. */
|
|
1779
|
-
const keepsApprovals = !outer && !!page.approval && !!options.dataSource?.approvals;
|
|
1780
|
-
/** The approvals, made from their part once it came; null without them, or where it could not come. */
|
|
1781
|
-
const approvalsCode = () => keepsApprovals ? formApprovalsPart.load().then((part) => (approvalKit ??= part.formApprovals({ form, dataSource: options.dataSource, messages, set, reload: () => load(true) })), () => null) : Promise.resolve(null);
|
|
1782
|
-
/** Ask the record shown's approvals, once their part came; nothing on a page without them. */
|
|
1783
|
-
const askApprovals = () => approvalsCode().then((kit) => kit?.ask());
|
|
1784
1877
|
function scheduleAutosave() {
|
|
1785
1878
|
const autosave = options.autosave;
|
|
1786
1879
|
// A record the person may not change is never saved unasked: it would only be refused.
|
|
@@ -1857,9 +1950,24 @@ function innerForm(options, within, place, outer) {
|
|
|
1857
1950
|
}
|
|
1858
1951
|
return shown;
|
|
1859
1952
|
}
|
|
1860
|
-
|
|
1861
|
-
|
|
1953
|
+
/** A response's answers as they go: those shown, and what the parts that join the form add (a link's hidden fields). */
|
|
1954
|
+
function answersSent() {
|
|
1955
|
+
const values = shownValues();
|
|
1956
|
+
for (const join of joins)
|
|
1957
|
+
join.values?.(values);
|
|
1958
|
+
return values;
|
|
1959
|
+
}
|
|
1960
|
+
async function save(chain = [], yes) {
|
|
1961
|
+
return (await saving(chain, yes)) === null;
|
|
1962
|
+
}
|
|
1963
|
+
/** A send — a response's, a save's, an upload's — through the parts that join the form, each around the next. Null: kept, not sent. */
|
|
1964
|
+
function through(kind, sent, send) {
|
|
1965
|
+
return joins.reduce((go, join) => (join.around ? (one) => join.around(kind, one, go) : go), send)(sent);
|
|
1862
1966
|
}
|
|
1967
|
+
/** Started again, or another record opened: the parts that join the form let go of what the one before had. */
|
|
1968
|
+
const joinsReset = () => joins.forEach((join) => join.reset?.());
|
|
1969
|
+
/** The record loaded, or saved: what the parts that join the form ask again (a record's approvals). */
|
|
1970
|
+
const joinsLoaded = () => joins.forEach((join) => join.loaded?.());
|
|
1863
1971
|
/** Every value, for a source that saves whole records: those of fields hidden from the person, which they never had, left out. */
|
|
1864
1972
|
function sentValues() {
|
|
1865
1973
|
const values = structuredCopy(state.values);
|
|
@@ -1887,14 +1995,14 @@ function innerForm(options, within, place, outer) {
|
|
|
1887
1995
|
* save with the version the first got back, never as someone else's. A save
|
|
1888
1996
|
* the page's own beforeSave steps ask for runs inside the one that set them off.
|
|
1889
1997
|
*/
|
|
1890
|
-
function saving(chain) {
|
|
1998
|
+
function saving(chain, yes) {
|
|
1891
1999
|
if (chain.includes('on.beforeSave'))
|
|
1892
|
-
return savingNow(chain);
|
|
2000
|
+
return savingNow(chain, yes);
|
|
1893
2001
|
const before = saveRunning;
|
|
1894
2002
|
const mine = (async () => {
|
|
1895
2003
|
if (before)
|
|
1896
2004
|
await before;
|
|
1897
|
-
return savingNow(chain);
|
|
2005
|
+
return savingNow(chain, yes);
|
|
1898
2006
|
})();
|
|
1899
2007
|
const done = mine.then(() => undefined, () => undefined);
|
|
1900
2008
|
saveRunning = done;
|
|
@@ -1904,7 +2012,7 @@ function innerForm(options, within, place, outer) {
|
|
|
1904
2012
|
});
|
|
1905
2013
|
return mine;
|
|
1906
2014
|
}
|
|
1907
|
-
async function savingNow(chain) {
|
|
2015
|
+
async function savingNow(chain, yes) {
|
|
1908
2016
|
// A record its source does not let this person change is refused here, in its words or the form's: no source is asked.
|
|
1909
2017
|
if (page.data.kind === 'record' && state.can?.edit === false) {
|
|
1910
2018
|
const problem = { kind: 'rule', message: state.can.reason ?? named(messages.mayNotEditNoun, messages.mayNotEdit) };
|
|
@@ -1952,7 +2060,8 @@ function innerForm(options, within, place, outer) {
|
|
|
1952
2060
|
if (page.on?.beforeSave) {
|
|
1953
2061
|
// Its run stops of itself on a record shown by anything but its own steps (a `call`'s `{ record }`, a reload):
|
|
1954
2062
|
// those move the save on with it.
|
|
1955
|
-
|
|
2063
|
+
// Its questions' Yes goes on with what set the save off: its words (Submit, a button's).
|
|
2064
|
+
const before = await moment('on.beforeSave', page.on.beforeSave, chain, false, yes);
|
|
1956
2065
|
if (!before.done) {
|
|
1957
2066
|
// A check's problems, or an inner save's, are shown already; any other stop is this save's problem.
|
|
1958
2067
|
if (before.reason !== 'check' && before.reason !== 'save') {
|
|
@@ -1966,8 +2075,22 @@ function innerForm(options, within, place, outer) {
|
|
|
1966
2075
|
const refused = await stillTaking(asked);
|
|
1967
2076
|
if (refused)
|
|
1968
2077
|
return refused;
|
|
1969
|
-
//
|
|
2078
|
+
// The parts that join the form (`formJoins`), waited for where they have not come.
|
|
2079
|
+
if (joining) {
|
|
2080
|
+
await joining;
|
|
2081
|
+
if (asked !== generation)
|
|
2082
|
+
return elsewhere();
|
|
2083
|
+
}
|
|
2084
|
+
// A file that did not reach the store stops it, under its field, with the form's own checks — and what the parts that
|
|
2085
|
+
// join the form find: an email or a phone not proved by a code; a payment not taken sends nothing.
|
|
1970
2086
|
const errors = { ...collectErrors(), ...fileProblems() };
|
|
2087
|
+
for (const join of joins) {
|
|
2088
|
+
// A part that never came (a hole) has nothing to say.
|
|
2089
|
+
if ((await join?.before?.(errors)) === false)
|
|
2090
|
+
return { reason: 'save' };
|
|
2091
|
+
if (asked !== generation)
|
|
2092
|
+
return elsewhere();
|
|
2093
|
+
}
|
|
1971
2094
|
if (Object.keys(errors).length) {
|
|
1972
2095
|
set({ errors, ...unstored(errors) });
|
|
1973
2096
|
return { reason: 'save', message: Object.values(errors)[0] };
|
|
@@ -1997,13 +2120,18 @@ function innerForm(options, within, place, outer) {
|
|
|
1997
2120
|
if (page.data.kind === 'responses') {
|
|
1998
2121
|
if (!source?.submit)
|
|
1999
2122
|
throw new Error('This page has no data source to send its answers to');
|
|
2000
|
-
const sent =
|
|
2123
|
+
const sent = answersSent();
|
|
2001
2124
|
const before = state.values;
|
|
2002
2125
|
at = generation;
|
|
2003
2126
|
const resetAt = resets;
|
|
2004
2127
|
const seen = botReport();
|
|
2128
|
+
// A quiz's marking, in before the answers go: what the person sees of their results.
|
|
2005
2129
|
// What the source answered: the id it gave the response, and the values it added — what an ending reads.
|
|
2006
|
-
const
|
|
2130
|
+
const request = { pageId: page.id, values: sent, ...(seen ? { bot: seen } : {}), ...draft };
|
|
2131
|
+
// Through the parts that join the form: kept on the device where an outbox finds no signal (null), the form going
|
|
2132
|
+
// on as though it went.
|
|
2133
|
+
const got = await through('submit', request, (one) => source.submit(one));
|
|
2134
|
+
const answer = got ?? {};
|
|
2007
2135
|
// The captcha's token is spent once sent: the next send waits for a new one.
|
|
2008
2136
|
if (seen?.captcha)
|
|
2009
2137
|
bot.captcha = null;
|
|
@@ -2015,8 +2143,13 @@ function innerForm(options, within, place, outer) {
|
|
|
2015
2143
|
sentAs = before;
|
|
2016
2144
|
const added = answer.values && typeof answer.values === 'object' ? structuredCopy(answer.values) : {};
|
|
2017
2145
|
// Started again meanwhile (`reset`): a new response is on screen, and no ending is the old one's.
|
|
2018
|
-
|
|
2146
|
+
// A quiz's results: the source's marking, else the page's, on the answers as sent.
|
|
2147
|
+
const quiz = answer.quiz ?? joined('surveyflow')?.marked(sent);
|
|
2148
|
+
set({ status: 'saved', unsent: unsentNow(), ...(resets === resetAt ? { sent: { id: answer.id ?? null, values: { ...structuredCopy(sent), ...added }, ...(quiz ? { quiz } : {}) } } : {}) });
|
|
2019
2149
|
emit('send', { values: sent, ...(seen ? { bot: seen } : {}) });
|
|
2150
|
+
// Kept, not sent: its counts and its after-save steps wait for a send that went.
|
|
2151
|
+
if (got === null)
|
|
2152
|
+
return null;
|
|
2020
2153
|
// Counted again: one response fewer to take, this person's sent.
|
|
2021
2154
|
if (asksLimits())
|
|
2022
2155
|
void track(askLimits());
|
|
@@ -2029,7 +2162,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2029
2162
|
const sent = state.values;
|
|
2030
2163
|
at = generation;
|
|
2031
2164
|
const resetAt = resets;
|
|
2032
|
-
const
|
|
2165
|
+
const request = {
|
|
2033
2166
|
model: page.data.model,
|
|
2034
2167
|
id: state.recordId,
|
|
2035
2168
|
fields,
|
|
@@ -2038,7 +2171,10 @@ function innerForm(options, within, place, outer) {
|
|
|
2038
2171
|
// The version it was opened at, for a source that refuses a save over someone else's.
|
|
2039
2172
|
...(state.recordId != null && state.version ? { version: state.version } : {}),
|
|
2040
2173
|
...draft,
|
|
2041
|
-
}
|
|
2174
|
+
};
|
|
2175
|
+
const got = await through('save', request, (one) => source.save(one));
|
|
2176
|
+
// Kept on the device (null): the record as it was, its version too.
|
|
2177
|
+
const result = got ?? { id: state.recordId, version: state.version ?? undefined };
|
|
2042
2178
|
// Answered for a record no longer shown — another opened, or this one loaded again: the source has it, and the
|
|
2043
2179
|
// form lays nothing of it over the record it shows now.
|
|
2044
2180
|
if (at !== generation)
|
|
@@ -2057,11 +2193,11 @@ function innerForm(options, within, place, outer) {
|
|
|
2057
2193
|
scheduleAutosave();
|
|
2058
2194
|
}
|
|
2059
2195
|
// A save may have sent it for approval, or moved it on: its approvals asked again.
|
|
2060
|
-
|
|
2061
|
-
void track(askApprovals());
|
|
2196
|
+
joinsLoaded();
|
|
2062
2197
|
// The record as this save left it: a change made while it was on its way is no value of it.
|
|
2063
2198
|
emit('save', { recordId: state.recordId, values: baseline });
|
|
2064
|
-
|
|
2199
|
+
if (got)
|
|
2200
|
+
void track(moment('on.afterSave', page.on?.afterSave, chain, false));
|
|
2065
2201
|
return null;
|
|
2066
2202
|
}
|
|
2067
2203
|
catch (error) {
|
|
@@ -2167,7 +2303,8 @@ function innerForm(options, within, place, outer) {
|
|
|
2167
2303
|
}
|
|
2168
2304
|
function addLine(field, values, by) {
|
|
2169
2305
|
const def = lineField(field);
|
|
2170
|
-
const
|
|
2306
|
+
const before = state.values[field];
|
|
2307
|
+
const current = before ?? [];
|
|
2171
2308
|
// A key no line holds: lines given (a line's own lines, back from its form) may hold new-… keys already.
|
|
2172
2309
|
let key = `new-${++lineKeys}`;
|
|
2173
2310
|
while (current.some((line) => line.key === key))
|
|
@@ -2180,6 +2317,8 @@ function innerForm(options, within, place, outer) {
|
|
|
2180
2317
|
}
|
|
2181
2318
|
const lines = [...current, line];
|
|
2182
2319
|
writeValues({ ...state.values, [field]: lines });
|
|
2320
|
+
if (by === 'person')
|
|
2321
|
+
noteChange(field, key, before, false);
|
|
2183
2322
|
afterEdit(field);
|
|
2184
2323
|
changed(field, by, by === 'person' ? { line: key } : { keep: true });
|
|
2185
2324
|
return key;
|
|
@@ -2324,8 +2463,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2324
2463
|
if (asksLimits())
|
|
2325
2464
|
void track(askLimits());
|
|
2326
2465
|
// Its approvals: where it stands, what was decided, what this person may decide — its fields locked while it waits.
|
|
2327
|
-
|
|
2328
|
-
void track(askApprovals());
|
|
2466
|
+
joinsLoaded();
|
|
2329
2467
|
if (again)
|
|
2330
2468
|
return;
|
|
2331
2469
|
offerDraft();
|
|
@@ -2361,6 +2499,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2361
2499
|
const fresh = { dirty: [], errors: {}, warning: null, warningField: null, error: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null, version: null, can: null, conflict: null, setAside: null, unsent: [], unread: {}, takenOut: {}, resume: null, approval: null };
|
|
2362
2500
|
if (id != null) {
|
|
2363
2501
|
set({ ...fresh, recordId: id, status: 'idle' });
|
|
2502
|
+
joinsReset();
|
|
2364
2503
|
await load();
|
|
2365
2504
|
return true;
|
|
2366
2505
|
}
|
|
@@ -2368,6 +2507,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2368
2507
|
baseline = startFrom(startingValues(true, false));
|
|
2369
2508
|
const values = syncParts(structuredCopy(baseline), 'start');
|
|
2370
2509
|
set({ ...fresh, recordId: null, status: 'ready', values, warnings: withValues(values, collectWarnings) });
|
|
2510
|
+
joinsReset();
|
|
2371
2511
|
if (asksLimits())
|
|
2372
2512
|
void track(askLimits());
|
|
2373
2513
|
offerDraft();
|
|
@@ -2668,7 +2808,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2668
2808
|
});
|
|
2669
2809
|
// A moment's run is on the record it was set off on: one set off again while its run goes, and run after it, is let
|
|
2670
2810
|
// go when another record is shown by then (its steps were for that one).
|
|
2671
|
-
const moment = createMoments((key, list, chain, on) => runTop(list, { id: key, chain, generation: on }), () => generation);
|
|
2811
|
+
const moment = createMoments((key, list, chain, on, yes) => runTop(list, { id: key, chain, generation: on, yes }), () => generation);
|
|
2672
2812
|
/**
|
|
2673
2813
|
* Whether steps do something before their first save — set a status, call the app, open a page — so a record's
|
|
2674
2814
|
* button made of them saves first. Steps that start with the save (Save and close), or only check before it, need
|
|
@@ -2692,14 +2832,20 @@ function innerForm(options, within, place, outer) {
|
|
|
2692
2832
|
const builtin = 'builtin' in source && !list.length ? source.builtin : undefined;
|
|
2693
2833
|
if (builtin)
|
|
2694
2834
|
list.push({ do: builtin });
|
|
2695
|
-
|
|
2835
|
+
// Undo after it, in place of asking first: a built-in with `undo` asks nothing unless it says so.
|
|
2836
|
+
const offers = 'undo' in source ? source.undo : undefined;
|
|
2837
|
+
const asked = offers !== undefined ? undefined : builtin === 'archive' ? named(messages.archiveConfirmNoun, messages.archiveConfirm) : builtin === 'delete' ? named(messages.deleteConfirmNoun, messages.deleteConfirm) : undefined;
|
|
2696
2838
|
const confirm = 'confirm' in source && source.confirm !== undefined ? source.confirm : asked;
|
|
2839
|
+
if (offers !== undefined)
|
|
2840
|
+
scope.taken = takenNow(state.values);
|
|
2841
|
+
// Its question's Yes, and its ask steps', say what it does: its own words, else Archive or Delete.
|
|
2842
|
+
scope.yes ??= source.label || (builtin === 'archive' ? messages.archiveYes : builtin === 'delete' ? messages.deleteYes : undefined);
|
|
2697
2843
|
// On the record it was pressed on: another shown while its question is asked, it does nothing to that one.
|
|
2698
2844
|
scope.generation ??= generation;
|
|
2699
2845
|
// Pressed by the person: what is typed is read before a step reads the form or hands its values on.
|
|
2700
2846
|
scope.typed ??= 'first';
|
|
2701
2847
|
return track((async () => {
|
|
2702
|
-
if (confirm && !(await runner.ask(confirm))) {
|
|
2848
|
+
if (confirm && !(await runner.ask(confirm, scope.yes))) {
|
|
2703
2849
|
const result = { done: false, reason: 'no', message: confirm };
|
|
2704
2850
|
emit('run', { id: scope.id, steps: list, result });
|
|
2705
2851
|
return result;
|
|
@@ -2718,16 +2864,28 @@ function innerForm(options, within, place, outer) {
|
|
|
2718
2864
|
}
|
|
2719
2865
|
// Then the save first, then the steps.
|
|
2720
2866
|
if (saveFirst && (state.recordId == null || state.dirty.length > 0 || Object.keys(state.unread ?? {}).length > 0 || state.uploads.some(uploadGoing))) {
|
|
2721
|
-
const first = await saving(scope.chain);
|
|
2867
|
+
const first = await saving(scope.chain, scope.yes);
|
|
2722
2868
|
if (first) {
|
|
2723
2869
|
const result = { done: false, step: { do: 'save' }, reason: first.reason, ...(first.message !== undefined ? { message: first.message } : {}), ...(first.error !== undefined ? { error: first.error } : {}) };
|
|
2724
2870
|
emit('run', { id: scope.id, steps: list, result });
|
|
2725
2871
|
return result;
|
|
2726
2872
|
}
|
|
2727
2873
|
}
|
|
2728
|
-
|
|
2874
|
+
const result = await runTop(list, scope);
|
|
2875
|
+
if (scope.taken)
|
|
2876
|
+
offerUndo(source, scope, result, offers);
|
|
2877
|
+
return result;
|
|
2729
2878
|
})());
|
|
2730
2879
|
}
|
|
2880
|
+
/**
|
|
2881
|
+
* A press that offers Undo has ended: its words said — the last with Undo, where what it did can be taken back — by
|
|
2882
|
+
* the undo part (press-undo.ts), which a page whose buttons offer Undo asks for first; plainly where it cannot come.
|
|
2883
|
+
*/
|
|
2884
|
+
function offerUndo(source, scope, result, offers) {
|
|
2885
|
+
const taken = scope.taken;
|
|
2886
|
+
scope.taken = undefined;
|
|
2887
|
+
void track(pressUndoPart.load().then((part) => part.offerUndo(inner, { kit: runner.kit, source, scope, taken, result, offers }), () => taken.said.forEach((words) => options.host?.say(words.message, words.tone))));
|
|
2888
|
+
}
|
|
2731
2889
|
const form = {
|
|
2732
2890
|
page,
|
|
2733
2891
|
...(table ? { functions: table } : {}),
|
|
@@ -2752,7 +2910,10 @@ function innerForm(options, within, place, outer) {
|
|
|
2752
2910
|
// A choice whose places are all taken is shown, and refused when the person picks it: said under its field.
|
|
2753
2911
|
if ((how?.by ?? 'person') === 'person' && refusedFull(name, value))
|
|
2754
2912
|
return;
|
|
2913
|
+
const before = state.values[name];
|
|
2755
2914
|
writeValues({ ...state.values, [name]: structuredCopy(value) });
|
|
2915
|
+
if ((how?.by ?? 'person') === 'person')
|
|
2916
|
+
noteChange(name, undefined, before, true);
|
|
2756
2917
|
afterEdit(name);
|
|
2757
2918
|
changed(name, how?.by ?? 'person');
|
|
2758
2919
|
},
|
|
@@ -2777,7 +2938,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2777
2938
|
// Nothing of the record changed; what shows of it may have.
|
|
2778
2939
|
set({});
|
|
2779
2940
|
},
|
|
2780
|
-
fieldReadonly: (name) => lockedField(fieldDef(name)) || state.can?.edit === false || state.can?.readonlyFields?.includes(name) === true || signedNow().has(name) ||
|
|
2941
|
+
fieldReadonly: (name) => lockedField(fieldDef(name)) || state.can?.edit === false || state.can?.readonlyFields?.includes(name) === true || signedNow().has(name) || anyJoin((join) => join.locksField?.(name)),
|
|
2781
2942
|
loadChoices: (field) => loadChoices(field),
|
|
2782
2943
|
loadDefinitions,
|
|
2783
2944
|
addDefinition,
|
|
@@ -2818,8 +2979,9 @@ function innerForm(options, within, place, outer) {
|
|
|
2818
2979
|
return null;
|
|
2819
2980
|
if (state.unread[name])
|
|
2820
2981
|
return state.unread[name].message;
|
|
2821
|
-
// A property's text left unread answers for its field
|
|
2822
|
-
|
|
2982
|
+
// A property's text left unread answers for its field, and so does a box of a value drawn in parts (a repeat
|
|
2983
|
+
// rule's number, an opening hour's time: `field.part`).
|
|
2984
|
+
if (['properties', 'json', 'char'].includes(page.fields[name].type)) {
|
|
2823
2985
|
const row = Object.keys(state.unread).find((path) => path.startsWith(`${name}.`));
|
|
2824
2986
|
if (row)
|
|
2825
2987
|
return state.unread[row].message;
|
|
@@ -2833,7 +2995,9 @@ function innerForm(options, within, place, outer) {
|
|
|
2833
2995
|
const field = path.split('.')[0];
|
|
2834
2996
|
// A line's cell (`field.lineKey.subfield`), or a property (`field.property`).
|
|
2835
2997
|
const def = fieldDef(field);
|
|
2836
|
-
|
|
2998
|
+
// A line's cell, a property, or one of the boxes a value is drawn in (a repeat rule's number, an opening hour's
|
|
2999
|
+
// time: `field.part`, of a char or a json field).
|
|
3000
|
+
if (path.includes('.') && def.type !== 'properties' && !((def.type === 'json' || def.type === 'char') && path.split('.').length === 2))
|
|
2837
3001
|
lineField(field);
|
|
2838
3002
|
const had = state.unread[path];
|
|
2839
3003
|
if (!unread && !had)
|
|
@@ -2856,6 +3020,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2856
3020
|
set({ unread: next, errors });
|
|
2857
3021
|
},
|
|
2858
3022
|
boxLeft(path) {
|
|
3023
|
+
noted.push([path.split('.')[0]]);
|
|
2859
3024
|
const problem = leftProblem(path);
|
|
2860
3025
|
if (!problem || state.errors[path] === problem)
|
|
2861
3026
|
return;
|
|
@@ -2878,14 +3043,15 @@ function innerForm(options, within, place, outer) {
|
|
|
2878
3043
|
if (seen.captcha !== undefined)
|
|
2879
3044
|
bot.captcha = seen.captcha;
|
|
2880
3045
|
},
|
|
3046
|
+
joined: (name) => (joins[joinParts.findIndex((part) => part.name === name)] ?? null),
|
|
2881
3047
|
reading: () => readingNow > 0 || [...attached.values()].some((part) => part.inner.form.reading()),
|
|
2882
|
-
validate() {
|
|
3048
|
+
validate(within) {
|
|
2883
3049
|
readTyped();
|
|
2884
|
-
const errors = collectErrors();
|
|
3050
|
+
const errors = collectErrors(within);
|
|
2885
3051
|
set({ errors });
|
|
2886
3052
|
return Object.keys(errors).length === 0;
|
|
2887
3053
|
},
|
|
2888
|
-
save: () => track(save()),
|
|
3054
|
+
save: (how) => track(save([], how?.yes)),
|
|
2889
3055
|
canUpload: () => typeof options.dataSource?.upload === 'function',
|
|
2890
3056
|
today,
|
|
2891
3057
|
now: () => options.now?.() ?? new Date(),
|
|
@@ -2974,6 +3140,7 @@ function innerForm(options, within, place, outer) {
|
|
|
2974
3140
|
holding = setWhen.holding(baseline);
|
|
2975
3141
|
// The person's own Discard: nothing of theirs is left at risk, and a save on its way lands as the record it stored.
|
|
2976
3142
|
resets++;
|
|
3143
|
+
noted = [];
|
|
2977
3144
|
personal.clear();
|
|
2978
3145
|
personalLines.clear();
|
|
2979
3146
|
filed.clear();
|
|
@@ -2982,6 +3149,9 @@ function innerForm(options, within, place, outer) {
|
|
|
2982
3149
|
bot = { ...bot, honeypot: false, since: clock() };
|
|
2983
3150
|
const values = syncParts(structuredCopy(baseline), 'start');
|
|
2984
3151
|
set({ values, dirty: [], errors: {}, warnings: withValues(values, collectWarnings), warning: null, warningField: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null, conflict: null, unsent: [], unread: {}, takenOut: {}, sent: null });
|
|
3152
|
+
// Started again: a new response proves and pays its own; a new respondent is drawn anew (unless the app or the
|
|
3153
|
+
// person's id is the seed), on the first step drawn, no clock running.
|
|
3154
|
+
joinsReset();
|
|
2985
3155
|
// Started again: whether the page takes another response, and each choice's places, asked again.
|
|
2986
3156
|
if (asksLimits())
|
|
2987
3157
|
void track(askLimits());
|
|
@@ -3001,8 +3171,10 @@ function innerForm(options, within, place, outer) {
|
|
|
3001
3171
|
const def = lineField(field);
|
|
3002
3172
|
if (!def.fields[name])
|
|
3003
3173
|
throw new Error(`The lines of "${field}" have no field "${name}"`);
|
|
3004
|
-
const
|
|
3174
|
+
const before = state.values[field];
|
|
3175
|
+
const lines = (before ?? []).map((line) => line.key === key ? { ...line, values: { ...line.values, [name]: structuredCopy(value) } } : line);
|
|
3005
3176
|
writeValues({ ...state.values, [field]: lines });
|
|
3177
|
+
noteChange(field, key, before, true);
|
|
3006
3178
|
afterEdit(field);
|
|
3007
3179
|
changed(field, 'person', { line: key });
|
|
3008
3180
|
},
|
|
@@ -3032,7 +3204,9 @@ function innerForm(options, within, place, outer) {
|
|
|
3032
3204
|
const value = trusted ? (i >= low && i <= high ? pool[i - low] : line.values[sequence]) : i + 1;
|
|
3033
3205
|
return value === line.values[sequence] ? line : { ...line, values: { ...line.values, [sequence]: value } };
|
|
3034
3206
|
});
|
|
3207
|
+
const was = state.values[field];
|
|
3035
3208
|
writeValues({ ...state.values, [field]: renumbered });
|
|
3209
|
+
noteChange(field, undefined, was, false);
|
|
3036
3210
|
afterEdit(field);
|
|
3037
3211
|
changed(field, 'person');
|
|
3038
3212
|
},
|
|
@@ -3046,8 +3220,10 @@ function innerForm(options, within, place, outer) {
|
|
|
3046
3220
|
throw new Error(`The line "${key}" of "${field}" cannot be deleted now: its table's lineDelete does not hold on it`);
|
|
3047
3221
|
}
|
|
3048
3222
|
}
|
|
3049
|
-
const
|
|
3223
|
+
const before = state.values[field];
|
|
3224
|
+
const lines = (before ?? []).filter((line) => line.key !== key);
|
|
3050
3225
|
writeValues({ ...state.values, [field]: lines });
|
|
3226
|
+
noteChange(field, key, before, false);
|
|
3051
3227
|
afterEdit(field);
|
|
3052
3228
|
changed(field, 'person', { line: key });
|
|
3053
3229
|
},
|
|
@@ -3114,6 +3290,8 @@ function innerForm(options, within, place, outer) {
|
|
|
3114
3290
|
set({ step: previous, errors: {} });
|
|
3115
3291
|
return true;
|
|
3116
3292
|
},
|
|
3293
|
+
startTimer: () => joined('surveyflow')?.start(),
|
|
3294
|
+
countdown: () => joined('surveyflow')?.countdown() ?? null,
|
|
3117
3295
|
skip() {
|
|
3118
3296
|
const current = state.step;
|
|
3119
3297
|
if (!current || !optionalStep(current))
|
|
@@ -3239,7 +3417,7 @@ function innerForm(options, within, place, outer) {
|
|
|
3239
3417
|
lines: { field: source.field, keys: [...keys], ids: lines.flatMap((line) => (line.id === undefined ? [] : [line.id])), values: lines.map((line) => structuredCopy(line.values)) },
|
|
3240
3418
|
});
|
|
3241
3419
|
},
|
|
3242
|
-
run: (list, context = {}) => track(runTop(list, { id: context.id ?? 'run', chain: [], typed: 'first', ...(context.recordIds ? { recordIds: [...context.recordIds] } : {}) })),
|
|
3420
|
+
run: (list, context = {}) => track(runTop(list, { id: context.id ?? 'run', chain: [], typed: 'first', ...(context.recordIds ? { recordIds: [...context.recordIds] } : {}), yes: context.yes })),
|
|
3243
3421
|
shown(tab) {
|
|
3244
3422
|
// A wizard's steps are told by the form itself, as they are entered.
|
|
3245
3423
|
if (steps.includes(tab))
|
|
@@ -3275,14 +3453,18 @@ function innerForm(options, within, place, outer) {
|
|
|
3275
3453
|
return saved;
|
|
3276
3454
|
},
|
|
3277
3455
|
refreshLimits: () => askLimits(),
|
|
3278
|
-
refreshApprovals
|
|
3456
|
+
async refreshApprovals() {
|
|
3457
|
+
await joining;
|
|
3458
|
+
await joined('approvals')?.ask();
|
|
3459
|
+
},
|
|
3279
3460
|
async decide(level, decision, reason) {
|
|
3280
|
-
|
|
3461
|
+
await joining;
|
|
3462
|
+
const kit = joined('approvals');
|
|
3281
3463
|
if (!kit)
|
|
3282
3464
|
throw new Error('No approvals on this page');
|
|
3283
3465
|
return track(kit.decide(level, decision, reason));
|
|
3284
3466
|
},
|
|
3285
|
-
approvalLock: (name) =>
|
|
3467
|
+
approvalLock: (name) => joined('approvals')?.lockWords(name) ?? null,
|
|
3286
3468
|
async reloadTheirs() {
|
|
3287
3469
|
// A save on its way first: its answer is not dropped by the load.
|
|
3288
3470
|
const asked = shownNow();
|
|
@@ -3382,6 +3564,9 @@ function innerForm(options, within, place, outer) {
|
|
|
3382
3564
|
if (state.setAside)
|
|
3383
3565
|
set({ setAside: null });
|
|
3384
3566
|
},
|
|
3567
|
+
undo: () => replay(true),
|
|
3568
|
+
redo: () => replay(false),
|
|
3569
|
+
history: () => pressUndoPart.loaded?.nextSteps(noted, inner.same) ?? { undo: null, redo: null },
|
|
3385
3570
|
async settled() {
|
|
3386
3571
|
while (pending.size)
|
|
3387
3572
|
await Promise.allSettled([...pending]);
|
|
@@ -3448,6 +3633,8 @@ function innerForm(options, within, place, outer) {
|
|
|
3448
3633
|
dispose() {
|
|
3449
3634
|
// An answer that lands after is for no record shown.
|
|
3450
3635
|
disposed = true;
|
|
3636
|
+
for (const join of joins)
|
|
3637
|
+
join?.dispose?.();
|
|
3451
3638
|
newGeneration();
|
|
3452
3639
|
clearFiles();
|
|
3453
3640
|
if (draftTimer !== null)
|
|
@@ -3467,9 +3654,22 @@ function innerForm(options, within, place, outer) {
|
|
|
3467
3654
|
// choice's places as the source tells them: a record's own once it is loaded, its own choices not counted against it.
|
|
3468
3655
|
if (keepsLimits())
|
|
3469
3656
|
void track(limitsCode());
|
|
3470
|
-
//
|
|
3471
|
-
|
|
3472
|
-
|
|
3657
|
+
// The parts its page or its source asks to join it — a survey's draw made before a draft is laid, which lays its own
|
|
3658
|
+
// draw over it; a record's approvals ready by the time its record is loaded; the record made live — each made at once
|
|
3659
|
+
// where it has come, else as it does, a draft laid meanwhile laid on it.
|
|
3660
|
+
if (joinParts.length) {
|
|
3661
|
+
const made = (at) => (part) => {
|
|
3662
|
+
if (disposed || joins[at])
|
|
3663
|
+
return;
|
|
3664
|
+
const join = (joins[at] = part.join(inner));
|
|
3665
|
+
if (laid)
|
|
3666
|
+
join.lay?.(laid);
|
|
3667
|
+
// Its record loaded before it came: what it asks of a loaded record, asked now.
|
|
3668
|
+
if (loadedOnce)
|
|
3669
|
+
join.loaded?.();
|
|
3670
|
+
};
|
|
3671
|
+
joining = Promise.all(joinParts.map((part, at) => (part.loaded ? made(at)(part.loaded) : track(part.load().then(made(at), () => undefined)))));
|
|
3672
|
+
}
|
|
3473
3673
|
// A new form has its values now — a draft continued from its key once it is laid — and opens once whoever made it
|
|
3474
3674
|
// has had the chance to listen.
|
|
3475
3675
|
if (state.recordId == null) {
|