| 594 | } |
| 595 | |
| 596 | private submit() { |
| 597 | const out: Record<string, string> = {}; |
| 598 | const requirementsById = new Map( |
| 599 | this.requirements.map((req) => [req.id, req]), |
| 600 | ); |
| 601 | |
| 602 | // A required date whose typed text failed to parse must not slip through: |
| 603 | // without a parse error the value would be silently dropped (and the |
| 604 | // script path has no sequential re-prompt to recover it). Block Submit and |
| 605 | // point the user at the offending field instead. |
| 606 | const erroredDate = this.requirements.find( |
| 607 | (req) => |
| 608 | req.type === "date" && |
| 609 | !req.optional && |
| 610 | this.dateParseErrors.has(req.id), |
| 611 | ); |
| 612 | if (erroredDate) { |
| 613 | new Notice( |
| 614 | `QuickAdd: "${erroredDate.label}" is not a valid date. Fix it or clear it before submitting.`, |
| 615 | ); |
| 616 | return; |
| 617 | } |
| 618 | |
| 619 | // Reconcile the per-pick multi-select arrays against the final text: if the |
| 620 | // user manually edited the field after picking (so the recorded picks no |
| 621 | // longer reproduce the text), drop the array and let the consumer fall back |
| 622 | // to text parsing. Otherwise the unambiguous picked order is authoritative. |
| 623 | for (const [id, picks] of this.multiSelections) { |
| 624 | const text = (this.result.get(id) ?? "").replace(/,\s*$/, "").trim(); |
| 625 | if (picks.join(", ") !== text) this.multiSelections.delete(id); |
| 626 | } |
| 627 | |
| 628 | this.result.forEach((v, k) => { |
| 629 | const requirement = requirementsById.get(k); |
| 630 | |
| 631 | // Empty date fields: an optional date that is genuinely blank is |
| 632 | // answered-empty (""). A required blank date — or any date whose |
| 633 | // text failed to parse — is OMITTED so it stays unresolved and the |
| 634 | // sequential date prompt (with picker and aliases) still fires. |
| 635 | if (requirement?.type === "date" && v === "") { |
| 636 | const hasParseError = this.dateParseErrors.has(k); |
| 637 | if (!requirement.optional || hasParseError) return; |
| 638 | } |
| 639 | |
| 640 | // Store the field value verbatim. A textarea value used to be |
| 641 | // backslash-doubled here; nothing downstream un-doubled it (the formatter |
| 642 | // substitutes a {{VALUE}} verbatim and never linebreak-processes it), so |
| 643 | // the doubling corrupted paths/regex/code — and compounded with the |
| 644 | // |type:text YAML quoter, which escapes backslashes again. Keep it literal, |
| 645 | // matching the wide and single-line prompts. |
| 646 | out[k] = v; |
| 647 | }); |
| 648 | this.settled = true; |
| 649 | this.close(); |
| 650 | this.resolvePromise(out); |
| 651 | } |
| 652 | |
| 653 | private cancel() { |