@optionfactory/fml 9.0.0-rc27 → 9.0.0-rc29

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.
Files changed (43) hide show
  1. package/dist/client-errors.iife.js +21 -16
  2. package/dist/client-errors.iife.js.map +1 -1
  3. package/dist/client-errors.iife.min.js +1 -1
  4. package/dist/client-errors.iife.min.js.map +1 -1
  5. package/dist/custom-elements.json +16 -16
  6. package/dist/fml.css +13 -13
  7. package/dist/fml.css.map +1 -1
  8. package/dist/fml.iife.js +871 -883
  9. package/dist/fml.iife.js.map +1 -1
  10. package/dist/fml.iife.min.js +1 -1
  11. package/dist/fml.iife.min.js.map +1 -1
  12. package/dist/ftl.d.mts +3 -3
  13. package/dist/ftl.iife.js +275 -679
  14. package/dist/ftl.iife.js.map +1 -1
  15. package/dist/ftl.iife.min.js +1 -1
  16. package/dist/ftl.iife.min.js.map +1 -1
  17. package/dist/ftl.min.mjs +1 -1
  18. package/dist/ftl.min.mjs.map +1 -1
  19. package/dist/ftl.mjs +275 -679
  20. package/dist/ftl.mjs.map +1 -1
  21. package/dist/ful.css +13 -13
  22. package/dist/ful.css.map +1 -1
  23. package/dist/ful.d.mts +195 -71
  24. package/dist/ful.iife.js +564 -189
  25. package/dist/ful.iife.js.map +1 -1
  26. package/dist/ful.iife.min.js +1 -1
  27. package/dist/ful.iife.min.js.map +1 -1
  28. package/dist/ful.min.mjs +1 -1
  29. package/dist/ful.min.mjs.map +1 -1
  30. package/dist/ful.mjs +564 -189
  31. package/dist/ful.mjs.map +1 -1
  32. package/dist/httpc.d.mts +9 -7
  33. package/dist/httpc.iife.js +32 -15
  34. package/dist/httpc.iife.js.map +1 -1
  35. package/dist/httpc.iife.min.js +1 -1
  36. package/dist/httpc.iife.min.js.map +1 -1
  37. package/dist/httpc.min.mjs +1 -1
  38. package/dist/httpc.min.mjs.map +1 -1
  39. package/dist/httpc.mjs +32 -15
  40. package/dist/httpc.mjs.map +1 -1
  41. package/dist/vscode.html-custom-data.json +13 -13
  42. package/dist/web-types.json +17 -17
  43. package/package.json +2 -2
package/dist/fml.iife.js CHANGED
@@ -71,7 +71,7 @@ var fml = (function (exports) {
71
71
  },
72
72
  };
73
73
 
74
- // @generated by Peggy 5.1.0.
74
+ // @generated by Peggy 5.1.1.
75
75
  //
76
76
  // https://peggyjs.org/
77
77
 
@@ -137,10 +137,9 @@ var fml = (function (exports) {
137
137
  return s;
138
138
  }
139
139
 
140
- function literalEscape(s) {
140
+ function escape(s, special) {
141
141
  return unicodeEscape(s
142
- .replace(/\\/g, "\\\\")
143
- .replace(/"/g, "\\\"")
142
+ .replace(special, "\\$&")
144
143
  .replace(/\0/g, "\\0")
145
144
  .replace(/\t/g, "\\t")
146
145
  .replace(/\n/g, "\\n")
@@ -149,18 +148,12 @@ var fml = (function (exports) {
149
148
  .replace(/[\x10-\x1F\x7F-\x9F]/g, ch => "\\x" + hex(ch)));
150
149
  }
151
150
 
151
+ function literalEscape(s) {
152
+ return escape(s, /[\\"]/g);
153
+ }
154
+
152
155
  function classEscape(s) {
153
- return unicodeEscape(s
154
- .replace(/\\/g, "\\\\")
155
- .replace(/\]/g, "\\]")
156
- .replace(/\^/g, "\\^")
157
- .replace(/-/g, "\\-")
158
- .replace(/\0/g, "\\0")
159
- .replace(/\t/g, "\\t")
160
- .replace(/\n/g, "\\n")
161
- .replace(/\r/g, "\\r")
162
- .replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch))
163
- .replace(/[\x10-\x1F\x7F-\x9F]/g, ch => "\\x" + hex(ch)));
156
+ return escape(s, /[\\\]^-]/g);
164
157
  }
165
158
 
166
159
  const DESCRIBE_EXPECTATION_FNS = {
@@ -278,14 +271,6 @@ var fml = (function (exports) {
278
271
  const peg$c53 = "<=";
279
272
  const peg$c54 = "<";
280
273
 
281
- const peg$r0 = /^[^\\{]/;
282
- const peg$r1 = /^[0-9]/;
283
- const peg$r2 = /^[^']/;
284
- const peg$r3 = /^[^"]/;
285
- const peg$r4 = /^[^\\`{]/;
286
- const peg$r5 = /^[a-zA-Z$_]/;
287
- const peg$r6 = /^[a-zA-Z$_0-9]/;
288
- const peg$r7 = /^[ \t\n\r]/;
289
274
 
290
275
  const peg$e0 = peg$literalExpectation("{{{{", false);
291
276
  const peg$e1 = peg$literalExpectation("}}}}", false);
@@ -443,9 +428,10 @@ var fml = (function (exports) {
443
428
  let peg$maxFailExpected = options.peg$maxFailExpected || [];
444
429
  let peg$silentFails = options.peg$silentFails | 0;
445
430
 
446
- let peg$resultsCache = {};
431
+ let peg$resultsCache = new Map();
447
432
 
448
433
  let peg$result;
434
+ let peg$charCode;
449
435
 
450
436
  if (options.startRule) {
451
437
  if (!(options.startRule in peg$startRuleFunctions)) {
@@ -564,7 +550,7 @@ var fml = (function (exports) {
564
550
  let s0, s1;
565
551
 
566
552
  const key = peg$currPos * 38 + 0;
567
- const cached = peg$resultsCache[key];
553
+ const cached = peg$resultsCache.get(key);
568
554
 
569
555
  if (cached) {
570
556
  peg$currPos = cached.nextPos;
@@ -573,13 +559,13 @@ var fml = (function (exports) {
573
559
  }
574
560
 
575
561
  s0 = [];
576
- s1 = peg$parseTemplatedExpression();
577
- while (s1 !== peg$FAILED) {
578
- s0.push(s1);
562
+ for (;;) {
579
563
  s1 = peg$parseTemplatedExpression();
564
+ if (s1 === peg$FAILED) { break; }
565
+ s0.push(s1);
580
566
  }
581
567
 
582
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
568
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
583
569
 
584
570
  return s0;
585
571
  }
@@ -588,7 +574,7 @@ var fml = (function (exports) {
588
574
  let s0, s1, s2, s3, s4;
589
575
 
590
576
  const key = peg$currPos * 38 + 1;
591
- const cached = peg$resultsCache[key];
577
+ const cached = peg$resultsCache.get(key);
592
578
 
593
579
  if (cached) {
594
580
  peg$currPos = cached.nextPos;
@@ -684,7 +670,7 @@ var fml = (function (exports) {
684
670
  }
685
671
  }
686
672
 
687
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
673
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
688
674
 
689
675
  return s0;
690
676
  }
@@ -693,7 +679,7 @@ var fml = (function (exports) {
693
679
  let s0;
694
680
 
695
681
  const key = peg$currPos * 38 + 2;
696
- const cached = peg$resultsCache[key];
682
+ const cached = peg$resultsCache.get(key);
697
683
 
698
684
  if (cached) {
699
685
  peg$currPos = cached.nextPos;
@@ -709,7 +695,7 @@ var fml = (function (exports) {
709
695
  if (peg$silentFails === 0) { peg$fail(peg$e0); }
710
696
  }
711
697
 
712
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
698
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
713
699
 
714
700
  return s0;
715
701
  }
@@ -718,7 +704,7 @@ var fml = (function (exports) {
718
704
  let s0;
719
705
 
720
706
  const key = peg$currPos * 38 + 3;
721
- const cached = peg$resultsCache[key];
707
+ const cached = peg$resultsCache.get(key);
722
708
 
723
709
  if (cached) {
724
710
  peg$currPos = cached.nextPos;
@@ -734,7 +720,7 @@ var fml = (function (exports) {
734
720
  if (peg$silentFails === 0) { peg$fail(peg$e1); }
735
721
  }
736
722
 
737
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
723
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
738
724
 
739
725
  return s0;
740
726
  }
@@ -743,7 +729,7 @@ var fml = (function (exports) {
743
729
  let s0;
744
730
 
745
731
  const key = peg$currPos * 38 + 4;
746
- const cached = peg$resultsCache[key];
732
+ const cached = peg$resultsCache.get(key);
747
733
 
748
734
  if (cached) {
749
735
  peg$currPos = cached.nextPos;
@@ -759,7 +745,7 @@ var fml = (function (exports) {
759
745
  if (peg$silentFails === 0) { peg$fail(peg$e2); }
760
746
  }
761
747
 
762
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
748
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
763
749
 
764
750
  return s0;
765
751
  }
@@ -768,7 +754,7 @@ var fml = (function (exports) {
768
754
  let s0;
769
755
 
770
756
  const key = peg$currPos * 38 + 5;
771
- const cached = peg$resultsCache[key];
757
+ const cached = peg$resultsCache.get(key);
772
758
 
773
759
  if (cached) {
774
760
  peg$currPos = cached.nextPos;
@@ -784,7 +770,7 @@ var fml = (function (exports) {
784
770
  if (peg$silentFails === 0) { peg$fail(peg$e3); }
785
771
  }
786
772
 
787
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
773
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
788
774
 
789
775
  return s0;
790
776
  }
@@ -793,7 +779,7 @@ var fml = (function (exports) {
793
779
  let s0;
794
780
 
795
781
  const key = peg$currPos * 38 + 6;
796
- const cached = peg$resultsCache[key];
782
+ const cached = peg$resultsCache.get(key);
797
783
 
798
784
  if (cached) {
799
785
  peg$currPos = cached.nextPos;
@@ -809,7 +795,7 @@ var fml = (function (exports) {
809
795
  if (peg$silentFails === 0) { peg$fail(peg$e4); }
810
796
  }
811
797
 
812
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
798
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
813
799
 
814
800
  return s0;
815
801
  }
@@ -818,7 +804,7 @@ var fml = (function (exports) {
818
804
  let s0;
819
805
 
820
806
  const key = peg$currPos * 38 + 7;
821
- const cached = peg$resultsCache[key];
807
+ const cached = peg$resultsCache.get(key);
822
808
 
823
809
  if (cached) {
824
810
  peg$currPos = cached.nextPos;
@@ -834,7 +820,7 @@ var fml = (function (exports) {
834
820
  if (peg$silentFails === 0) { peg$fail(peg$e5); }
835
821
  }
836
822
 
837
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
823
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
838
824
 
839
825
  return s0;
840
826
  }
@@ -843,7 +829,7 @@ var fml = (function (exports) {
843
829
  let s0, s1, s2, s3, s4, s5, s6;
844
830
 
845
831
  const key = peg$currPos * 38 + 8;
846
- const cached = peg$resultsCache[key];
832
+ const cached = peg$resultsCache.get(key);
847
833
 
848
834
  if (cached) {
849
835
  peg$currPos = cached.nextPos;
@@ -853,211 +839,104 @@ var fml = (function (exports) {
853
839
 
854
840
  s0 = peg$currPos;
855
841
  s1 = [];
856
- s2 = peg$currPos;
857
- s3 = [];
858
- s4 = input.charAt(peg$currPos);
859
- if (peg$r0.test(s4)) {
860
- peg$currPos++;
861
- } else {
862
- s4 = peg$FAILED;
863
- if (peg$silentFails === 0) { peg$fail(peg$e6); }
864
- }
865
- if (s4 !== peg$FAILED) {
866
- while (s4 !== peg$FAILED) {
867
- s3.push(s4);
842
+ for (;;) {
843
+ s2 = peg$currPos;
844
+ s3 = [];
845
+ for (;;) {
868
846
  s4 = input.charAt(peg$currPos);
869
- if (peg$r0.test(s4)) {
847
+ if (s4 !== "" && !(peg$charCode = s4.charCodeAt(0), peg$charCode === 92 || peg$charCode === 123)) {
870
848
  peg$currPos++;
871
849
  } else {
872
850
  s4 = peg$FAILED;
873
851
  if (peg$silentFails === 0) { peg$fail(peg$e6); }
874
852
  }
853
+ if (s4 === peg$FAILED) { break; }
854
+ s3.push(s4);
875
855
  }
876
- } else {
877
- s3 = peg$FAILED;
878
- }
879
- if (s3 !== peg$FAILED) {
880
- s2 = input.substring(s2, peg$currPos);
881
- } else {
882
- s2 = s3;
883
- }
884
- if (s2 === peg$FAILED) {
885
- s2 = peg$currPos;
886
- if (input.charCodeAt(peg$currPos) === 92) {
887
- s3 = peg$c7;
888
- peg$currPos++;
889
- } else {
856
+ if (s3.length < 1) {
890
857
  s3 = peg$FAILED;
891
- if (peg$silentFails === 0) { peg$fail(peg$e7); }
892
858
  }
893
859
  if (s3 !== peg$FAILED) {
894
- if (input.length > peg$currPos) {
895
- s4 = input.charAt(peg$currPos);
896
- peg$currPos++;
897
- } else {
898
- s4 = peg$FAILED;
899
- if (peg$silentFails === 0) { peg$fail(peg$e8); }
900
- }
901
- if (s4 !== peg$FAILED) {
902
- s2 = peg$f4(s4);
903
- } else {
904
- peg$currPos = s2;
905
- s2 = peg$FAILED;
906
- }
860
+ s2 = input.substring(s2, peg$currPos);
907
861
  } else {
908
- peg$currPos = s2;
909
- s2 = peg$FAILED;
862
+ s2 = s3;
910
863
  }
911
864
  if (s2 === peg$FAILED) {
912
865
  s2 = peg$currPos;
913
- s3 = peg$currPos;
914
- if (input.charCodeAt(peg$currPos) === 123) {
915
- s4 = peg$c9;
866
+ if (input.charCodeAt(peg$currPos) === 92) {
867
+ s3 = peg$c7;
916
868
  peg$currPos++;
917
869
  } else {
918
- s4 = peg$FAILED;
919
- if (peg$silentFails === 0) { peg$fail(peg$e9); }
870
+ s3 = peg$FAILED;
871
+ if (peg$silentFails === 0) { peg$fail(peg$e7); }
920
872
  }
921
- if (s4 !== peg$FAILED) {
922
- s5 = peg$currPos;
923
- peg$silentFails++;
924
- if (input.charCodeAt(peg$currPos) === 123) {
925
- s6 = peg$c9;
873
+ if (s3 !== peg$FAILED) {
874
+ if (input.length > peg$currPos) {
875
+ s4 = input.charAt(peg$currPos);
926
876
  peg$currPos++;
927
877
  } else {
928
- s6 = peg$FAILED;
929
- if (peg$silentFails === 0) { peg$fail(peg$e9); }
930
- }
931
- peg$silentFails--;
932
- if (s6 === peg$FAILED) {
933
- s5 = undefined;
934
- } else {
935
- peg$currPos = s5;
936
- s5 = peg$FAILED;
878
+ s4 = peg$FAILED;
879
+ if (peg$silentFails === 0) { peg$fail(peg$e8); }
937
880
  }
938
- if (s5 !== peg$FAILED) {
939
- s4 = [s4, s5];
940
- s3 = s4;
881
+ if (s4 !== peg$FAILED) {
882
+ s2 = peg$f4(s4);
941
883
  } else {
942
- peg$currPos = s3;
943
- s3 = peg$FAILED;
944
- }
945
- } else {
946
- peg$currPos = s3;
947
- s3 = peg$FAILED;
948
- }
949
- if (s3 !== peg$FAILED) {
950
- s2 = input.substring(s2, peg$currPos);
951
- } else {
952
- s2 = s3;
953
- }
954
- }
955
- }
956
- if (s2 !== peg$FAILED) {
957
- while (s2 !== peg$FAILED) {
958
- s1.push(s2);
959
- s2 = peg$currPos;
960
- s3 = [];
961
- s4 = input.charAt(peg$currPos);
962
- if (peg$r0.test(s4)) {
963
- peg$currPos++;
964
- } else {
965
- s4 = peg$FAILED;
966
- if (peg$silentFails === 0) { peg$fail(peg$e6); }
967
- }
968
- if (s4 !== peg$FAILED) {
969
- while (s4 !== peg$FAILED) {
970
- s3.push(s4);
971
- s4 = input.charAt(peg$currPos);
972
- if (peg$r0.test(s4)) {
973
- peg$currPos++;
974
- } else {
975
- s4 = peg$FAILED;
976
- if (peg$silentFails === 0) { peg$fail(peg$e6); }
977
- }
884
+ peg$currPos = s2;
885
+ s2 = peg$FAILED;
978
886
  }
979
887
  } else {
980
- s3 = peg$FAILED;
981
- }
982
- if (s3 !== peg$FAILED) {
983
- s2 = input.substring(s2, peg$currPos);
984
- } else {
985
- s2 = s3;
888
+ peg$currPos = s2;
889
+ s2 = peg$FAILED;
986
890
  }
987
891
  if (s2 === peg$FAILED) {
988
892
  s2 = peg$currPos;
989
- if (input.charCodeAt(peg$currPos) === 92) {
990
- s3 = peg$c7;
893
+ s3 = peg$currPos;
894
+ if (input.charCodeAt(peg$currPos) === 123) {
895
+ s4 = peg$c9;
991
896
  peg$currPos++;
992
897
  } else {
993
- s3 = peg$FAILED;
994
- if (peg$silentFails === 0) { peg$fail(peg$e7); }
995
- }
996
- if (s3 !== peg$FAILED) {
997
- if (input.length > peg$currPos) {
998
- s4 = input.charAt(peg$currPos);
999
- peg$currPos++;
1000
- } else {
1001
- s4 = peg$FAILED;
1002
- if (peg$silentFails === 0) { peg$fail(peg$e8); }
1003
- }
1004
- if (s4 !== peg$FAILED) {
1005
- s2 = peg$f4(s4);
1006
- } else {
1007
- peg$currPos = s2;
1008
- s2 = peg$FAILED;
1009
- }
1010
- } else {
1011
- peg$currPos = s2;
1012
- s2 = peg$FAILED;
898
+ s4 = peg$FAILED;
899
+ if (peg$silentFails === 0) { peg$fail(peg$e9); }
1013
900
  }
1014
- if (s2 === peg$FAILED) {
1015
- s2 = peg$currPos;
1016
- s3 = peg$currPos;
901
+ if (s4 !== peg$FAILED) {
902
+ s5 = peg$currPos;
903
+ peg$silentFails++;
1017
904
  if (input.charCodeAt(peg$currPos) === 123) {
1018
- s4 = peg$c9;
905
+ s6 = peg$c9;
1019
906
  peg$currPos++;
1020
907
  } else {
1021
- s4 = peg$FAILED;
908
+ s6 = peg$FAILED;
1022
909
  if (peg$silentFails === 0) { peg$fail(peg$e9); }
1023
910
  }
1024
- if (s4 !== peg$FAILED) {
1025
- s5 = peg$currPos;
1026
- peg$silentFails++;
1027
- if (input.charCodeAt(peg$currPos) === 123) {
1028
- s6 = peg$c9;
1029
- peg$currPos++;
1030
- } else {
1031
- s6 = peg$FAILED;
1032
- if (peg$silentFails === 0) { peg$fail(peg$e9); }
1033
- }
1034
- peg$silentFails--;
1035
- if (s6 === peg$FAILED) {
1036
- s5 = undefined;
1037
- } else {
1038
- peg$currPos = s5;
1039
- s5 = peg$FAILED;
1040
- }
1041
- if (s5 !== peg$FAILED) {
1042
- s4 = [s4, s5];
1043
- s3 = s4;
1044
- } else {
1045
- peg$currPos = s3;
1046
- s3 = peg$FAILED;
1047
- }
911
+ peg$silentFails--;
912
+ if (s6 === peg$FAILED) {
913
+ s5 = undefined;
1048
914
  } else {
1049
- peg$currPos = s3;
1050
- s3 = peg$FAILED;
915
+ peg$currPos = s5;
916
+ s5 = peg$FAILED;
1051
917
  }
1052
- if (s3 !== peg$FAILED) {
1053
- s2 = input.substring(s2, peg$currPos);
918
+ if (s5 !== peg$FAILED) {
919
+ s4 = [s4, s5];
920
+ s3 = s4;
1054
921
  } else {
1055
- s2 = s3;
922
+ peg$currPos = s3;
923
+ s3 = peg$FAILED;
1056
924
  }
925
+ } else {
926
+ peg$currPos = s3;
927
+ s3 = peg$FAILED;
928
+ }
929
+ if (s3 !== peg$FAILED) {
930
+ s2 = input.substring(s2, peg$currPos);
931
+ } else {
932
+ s2 = s3;
1057
933
  }
1058
934
  }
1059
935
  }
1060
- } else {
936
+ if (s2 === peg$FAILED) { break; }
937
+ s1.push(s2);
938
+ }
939
+ if (s1.length < 1) {
1061
940
  s1 = peg$FAILED;
1062
941
  }
1063
942
  if (s1 !== peg$FAILED) {
@@ -1065,7 +944,7 @@ var fml = (function (exports) {
1065
944
  }
1066
945
  s0 = s1;
1067
946
 
1068
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
947
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1069
948
 
1070
949
  return s0;
1071
950
  }
@@ -1074,7 +953,7 @@ var fml = (function (exports) {
1074
953
  let s0, s2;
1075
954
 
1076
955
  const key = peg$currPos * 38 + 9;
1077
- const cached = peg$resultsCache[key];
956
+ const cached = peg$resultsCache.get(key);
1078
957
 
1079
958
  if (cached) {
1080
959
  peg$currPos = cached.nextPos;
@@ -1093,7 +972,7 @@ var fml = (function (exports) {
1093
972
  s0 = peg$FAILED;
1094
973
  }
1095
974
 
1096
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
975
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1097
976
 
1098
977
  return s0;
1099
978
  }
@@ -1102,7 +981,7 @@ var fml = (function (exports) {
1102
981
  let s0, s1, s3, s5, s7, s9;
1103
982
 
1104
983
  const key = peg$currPos * 38 + 10;
1105
- const cached = peg$resultsCache[key];
984
+ const cached = peg$resultsCache.get(key);
1106
985
 
1107
986
  if (cached) {
1108
987
  peg$currPos = cached.nextPos;
@@ -1162,7 +1041,7 @@ var fml = (function (exports) {
1162
1041
  s0 = peg$parseElvisExpression();
1163
1042
  }
1164
1043
 
1165
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1044
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1166
1045
 
1167
1046
  return s0;
1168
1047
  }
@@ -1171,7 +1050,7 @@ var fml = (function (exports) {
1171
1050
  let s0, s1, s3, s5;
1172
1051
 
1173
1052
  const key = peg$currPos * 38 + 11;
1174
- const cached = peg$resultsCache[key];
1053
+ const cached = peg$resultsCache.get(key);
1175
1054
 
1176
1055
  if (cached) {
1177
1056
  peg$currPos = cached.nextPos;
@@ -1211,7 +1090,7 @@ var fml = (function (exports) {
1211
1090
  s0 = peg$parseNullCoalescingExpression();
1212
1091
  }
1213
1092
 
1214
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1093
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1215
1094
 
1216
1095
  return s0;
1217
1096
  }
@@ -1220,7 +1099,7 @@ var fml = (function (exports) {
1220
1099
  let s0, s1, s3, s5;
1221
1100
 
1222
1101
  const key = peg$currPos * 38 + 12;
1223
- const cached = peg$resultsCache[key];
1102
+ const cached = peg$resultsCache.get(key);
1224
1103
 
1225
1104
  if (cached) {
1226
1105
  peg$currPos = cached.nextPos;
@@ -1260,7 +1139,7 @@ var fml = (function (exports) {
1260
1139
  s0 = peg$parseOrExpression();
1261
1140
  }
1262
1141
 
1263
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1142
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1264
1143
 
1265
1144
  return s0;
1266
1145
  }
@@ -1269,7 +1148,7 @@ var fml = (function (exports) {
1269
1148
  let s0, s1, s2, s3, s5, s7;
1270
1149
 
1271
1150
  const key = peg$currPos * 38 + 13;
1272
- const cached = peg$resultsCache[key];
1151
+ const cached = peg$resultsCache.get(key);
1273
1152
 
1274
1153
  if (cached) {
1275
1154
  peg$currPos = cached.nextPos;
@@ -1281,30 +1160,7 @@ var fml = (function (exports) {
1281
1160
  s1 = peg$parseAndExpression();
1282
1161
  if (s1 !== peg$FAILED) {
1283
1162
  s2 = [];
1284
- s3 = peg$currPos;
1285
- peg$parse_();
1286
- if (input.substr(peg$currPos, 2) === peg$c22) {
1287
- s5 = peg$c22;
1288
- peg$currPos += 2;
1289
- } else {
1290
- s5 = peg$FAILED;
1291
- if (peg$silentFails === 0) { peg$fail(peg$e14); }
1292
- }
1293
- if (s5 !== peg$FAILED) {
1294
- peg$parse_();
1295
- s7 = peg$parseAndExpression();
1296
- if (s7 !== peg$FAILED) {
1297
- s3 = s7;
1298
- } else {
1299
- peg$currPos = s3;
1300
- s3 = peg$FAILED;
1301
- }
1302
- } else {
1303
- peg$currPos = s3;
1304
- s3 = peg$FAILED;
1305
- }
1306
- while (s3 !== peg$FAILED) {
1307
- s2.push(s3);
1163
+ for (;;) {
1308
1164
  s3 = peg$currPos;
1309
1165
  peg$parse_();
1310
1166
  if (input.substr(peg$currPos, 2) === peg$c22) {
@@ -1327,6 +1183,8 @@ var fml = (function (exports) {
1327
1183
  peg$currPos = s3;
1328
1184
  s3 = peg$FAILED;
1329
1185
  }
1186
+ if (s3 === peg$FAILED) { break; }
1187
+ s2.push(s3);
1330
1188
  }
1331
1189
  s0 = peg$f10(s1, s2);
1332
1190
  } else {
@@ -1334,7 +1192,7 @@ var fml = (function (exports) {
1334
1192
  s0 = peg$FAILED;
1335
1193
  }
1336
1194
 
1337
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1195
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1338
1196
 
1339
1197
  return s0;
1340
1198
  }
@@ -1343,7 +1201,7 @@ var fml = (function (exports) {
1343
1201
  let s0, s1, s2, s3, s5, s7;
1344
1202
 
1345
1203
  const key = peg$currPos * 38 + 14;
1346
- const cached = peg$resultsCache[key];
1204
+ const cached = peg$resultsCache.get(key);
1347
1205
 
1348
1206
  if (cached) {
1349
1207
  peg$currPos = cached.nextPos;
@@ -1355,30 +1213,7 @@ var fml = (function (exports) {
1355
1213
  s1 = peg$parseEqExpression();
1356
1214
  if (s1 !== peg$FAILED) {
1357
1215
  s2 = [];
1358
- s3 = peg$currPos;
1359
- peg$parse_();
1360
- if (input.substr(peg$currPos, 2) === peg$c24) {
1361
- s5 = peg$c24;
1362
- peg$currPos += 2;
1363
- } else {
1364
- s5 = peg$FAILED;
1365
- if (peg$silentFails === 0) { peg$fail(peg$e15); }
1366
- }
1367
- if (s5 !== peg$FAILED) {
1368
- peg$parse_();
1369
- s7 = peg$parseEqExpression();
1370
- if (s7 !== peg$FAILED) {
1371
- s3 = s7;
1372
- } else {
1373
- peg$currPos = s3;
1374
- s3 = peg$FAILED;
1375
- }
1376
- } else {
1377
- peg$currPos = s3;
1378
- s3 = peg$FAILED;
1379
- }
1380
- while (s3 !== peg$FAILED) {
1381
- s2.push(s3);
1216
+ for (;;) {
1382
1217
  s3 = peg$currPos;
1383
1218
  peg$parse_();
1384
1219
  if (input.substr(peg$currPos, 2) === peg$c24) {
@@ -1401,6 +1236,8 @@ var fml = (function (exports) {
1401
1236
  peg$currPos = s3;
1402
1237
  s3 = peg$FAILED;
1403
1238
  }
1239
+ if (s3 === peg$FAILED) { break; }
1240
+ s2.push(s3);
1404
1241
  }
1405
1242
  s0 = peg$f11(s1, s2);
1406
1243
  } else {
@@ -1408,7 +1245,7 @@ var fml = (function (exports) {
1408
1245
  s0 = peg$FAILED;
1409
1246
  }
1410
1247
 
1411
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1248
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1412
1249
 
1413
1250
  return s0;
1414
1251
  }
@@ -1417,7 +1254,7 @@ var fml = (function (exports) {
1417
1254
  let s0, s1, s2, s3, s5, s7;
1418
1255
 
1419
1256
  const key = peg$currPos * 38 + 15;
1420
- const cached = peg$resultsCache[key];
1257
+ const cached = peg$resultsCache.get(key);
1421
1258
 
1422
1259
  if (cached) {
1423
1260
  peg$currPos = cached.nextPos;
@@ -1429,24 +1266,7 @@ var fml = (function (exports) {
1429
1266
  s1 = peg$parseRelExpression();
1430
1267
  if (s1 !== peg$FAILED) {
1431
1268
  s2 = [];
1432
- s3 = peg$currPos;
1433
- peg$parse_();
1434
- s5 = peg$parseEqualityOp();
1435
- if (s5 !== peg$FAILED) {
1436
- peg$parse_();
1437
- s7 = peg$parseRelExpression();
1438
- if (s7 !== peg$FAILED) {
1439
- s3 = peg$f12(s1, s5, s7);
1440
- } else {
1441
- peg$currPos = s3;
1442
- s3 = peg$FAILED;
1443
- }
1444
- } else {
1445
- peg$currPos = s3;
1446
- s3 = peg$FAILED;
1447
- }
1448
- while (s3 !== peg$FAILED) {
1449
- s2.push(s3);
1269
+ for (;;) {
1450
1270
  s3 = peg$currPos;
1451
1271
  peg$parse_();
1452
1272
  s5 = peg$parseEqualityOp();
@@ -1463,6 +1283,8 @@ var fml = (function (exports) {
1463
1283
  peg$currPos = s3;
1464
1284
  s3 = peg$FAILED;
1465
1285
  }
1286
+ if (s3 === peg$FAILED) { break; }
1287
+ s2.push(s3);
1466
1288
  }
1467
1289
  s0 = peg$f13(s1, s2);
1468
1290
  } else {
@@ -1470,7 +1292,7 @@ var fml = (function (exports) {
1470
1292
  s0 = peg$FAILED;
1471
1293
  }
1472
1294
 
1473
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1295
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1474
1296
 
1475
1297
  return s0;
1476
1298
  }
@@ -1479,7 +1301,7 @@ var fml = (function (exports) {
1479
1301
  let s0, s1, s2, s3, s5, s7;
1480
1302
 
1481
1303
  const key = peg$currPos * 38 + 16;
1482
- const cached = peg$resultsCache[key];
1304
+ const cached = peg$resultsCache.get(key);
1483
1305
 
1484
1306
  if (cached) {
1485
1307
  peg$currPos = cached.nextPos;
@@ -1491,24 +1313,7 @@ var fml = (function (exports) {
1491
1313
  s1 = peg$parseNotExpression();
1492
1314
  if (s1 !== peg$FAILED) {
1493
1315
  s2 = [];
1494
- s3 = peg$currPos;
1495
- peg$parse_();
1496
- s5 = peg$parseRelationalOp();
1497
- if (s5 !== peg$FAILED) {
1498
- peg$parse_();
1499
- s7 = peg$parseNotExpression();
1500
- if (s7 !== peg$FAILED) {
1501
- s3 = peg$f14(s1, s5, s7);
1502
- } else {
1503
- peg$currPos = s3;
1504
- s3 = peg$FAILED;
1505
- }
1506
- } else {
1507
- peg$currPos = s3;
1508
- s3 = peg$FAILED;
1509
- }
1510
- while (s3 !== peg$FAILED) {
1511
- s2.push(s3);
1316
+ for (;;) {
1512
1317
  s3 = peg$currPos;
1513
1318
  peg$parse_();
1514
1319
  s5 = peg$parseRelationalOp();
@@ -1525,6 +1330,8 @@ var fml = (function (exports) {
1525
1330
  peg$currPos = s3;
1526
1331
  s3 = peg$FAILED;
1527
1332
  }
1333
+ if (s3 === peg$FAILED) { break; }
1334
+ s2.push(s3);
1528
1335
  }
1529
1336
  s0 = peg$f15(s1, s2);
1530
1337
  } else {
@@ -1532,7 +1339,7 @@ var fml = (function (exports) {
1532
1339
  s0 = peg$FAILED;
1533
1340
  }
1534
1341
 
1535
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1342
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1536
1343
 
1537
1344
  return s0;
1538
1345
  }
@@ -1541,7 +1348,7 @@ var fml = (function (exports) {
1541
1348
  let s0, s1, s3;
1542
1349
 
1543
1350
  const key = peg$currPos * 38 + 17;
1544
- const cached = peg$resultsCache[key];
1351
+ const cached = peg$resultsCache.get(key);
1545
1352
 
1546
1353
  if (cached) {
1547
1354
  peg$currPos = cached.nextPos;
@@ -1574,7 +1381,7 @@ var fml = (function (exports) {
1574
1381
  s0 = peg$parseAccess();
1575
1382
  }
1576
1383
 
1577
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1384
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1578
1385
 
1579
1386
  return s0;
1580
1387
  }
@@ -1583,7 +1390,7 @@ var fml = (function (exports) {
1583
1390
  let s0, s1, s3, s4, s5;
1584
1391
 
1585
1392
  const key = peg$currPos * 38 + 18;
1586
- const cached = peg$resultsCache[key];
1393
+ const cached = peg$resultsCache.get(key);
1587
1394
 
1588
1395
  if (cached) {
1589
1396
  peg$currPos = cached.nextPos;
@@ -1596,29 +1403,20 @@ var fml = (function (exports) {
1596
1403
  if (s1 !== peg$FAILED) {
1597
1404
  peg$parse_();
1598
1405
  s3 = [];
1599
- s4 = peg$currPos;
1600
- s5 = peg$parseAccessExpression();
1601
- if (s5 !== peg$FAILED) {
1602
- peg$parse_();
1603
- s4 = s5;
1604
- } else {
1605
- peg$currPos = s4;
1606
- s4 = peg$FAILED;
1607
- }
1608
- if (s4 !== peg$FAILED) {
1609
- while (s4 !== peg$FAILED) {
1610
- s3.push(s4);
1611
- s4 = peg$currPos;
1612
- s5 = peg$parseAccessExpression();
1613
- if (s5 !== peg$FAILED) {
1614
- peg$parse_();
1615
- s4 = s5;
1616
- } else {
1617
- peg$currPos = s4;
1618
- s4 = peg$FAILED;
1619
- }
1406
+ for (;;) {
1407
+ s4 = peg$currPos;
1408
+ s5 = peg$parseAccessExpression();
1409
+ if (s5 !== peg$FAILED) {
1410
+ peg$parse_();
1411
+ s4 = s5;
1412
+ } else {
1413
+ peg$currPos = s4;
1414
+ s4 = peg$FAILED;
1620
1415
  }
1621
- } else {
1416
+ if (s4 === peg$FAILED) { break; }
1417
+ s3.push(s4);
1418
+ }
1419
+ if (s3.length < 1) {
1622
1420
  s3 = peg$FAILED;
1623
1421
  }
1624
1422
  if (s3 !== peg$FAILED) {
@@ -1635,7 +1433,7 @@ var fml = (function (exports) {
1635
1433
  s0 = peg$parseGroupingExpression();
1636
1434
  }
1637
1435
 
1638
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1436
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1639
1437
 
1640
1438
  return s0;
1641
1439
  }
@@ -1644,7 +1442,7 @@ var fml = (function (exports) {
1644
1442
  let s0;
1645
1443
 
1646
1444
  const key = peg$currPos * 38 + 19;
1647
- const cached = peg$resultsCache[key];
1445
+ const cached = peg$resultsCache.get(key);
1648
1446
 
1649
1447
  if (cached) {
1650
1448
  peg$currPos = cached.nextPos;
@@ -1660,7 +1458,7 @@ var fml = (function (exports) {
1660
1458
  }
1661
1459
  }
1662
1460
 
1663
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1461
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1664
1462
 
1665
1463
  return s0;
1666
1464
  }
@@ -1669,7 +1467,7 @@ var fml = (function (exports) {
1669
1467
  let s0, s1, s3;
1670
1468
 
1671
1469
  const key = peg$currPos * 38 + 20;
1672
- const cached = peg$resultsCache[key];
1470
+ const cached = peg$resultsCache.get(key);
1673
1471
 
1674
1472
  if (cached) {
1675
1473
  peg$currPos = cached.nextPos;
@@ -1714,7 +1512,7 @@ var fml = (function (exports) {
1714
1512
  if (peg$silentFails === 0) { peg$fail(peg$e17); }
1715
1513
  }
1716
1514
 
1717
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1515
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1718
1516
 
1719
1517
  return s0;
1720
1518
  }
@@ -1723,7 +1521,7 @@ var fml = (function (exports) {
1723
1521
  let s0, s1, s2, s4, s6;
1724
1522
 
1725
1523
  const key = peg$currPos * 38 + 21;
1726
- const cached = peg$resultsCache[key];
1524
+ const cached = peg$resultsCache.get(key);
1727
1525
 
1728
1526
  if (cached) {
1729
1527
  peg$currPos = cached.nextPos;
@@ -1782,7 +1580,7 @@ var fml = (function (exports) {
1782
1580
  if (peg$silentFails === 0) { peg$fail(peg$e20); }
1783
1581
  }
1784
1582
 
1785
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1583
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1786
1584
 
1787
1585
  return s0;
1788
1586
  }
@@ -1791,7 +1589,7 @@ var fml = (function (exports) {
1791
1589
  let s0, s1, s2, s4, s5, s6, s7, s9;
1792
1590
 
1793
1591
  const key = peg$currPos * 38 + 22;
1794
- const cached = peg$resultsCache[key];
1592
+ const cached = peg$resultsCache.get(key);
1795
1593
 
1796
1594
  if (cached) {
1797
1595
  peg$currPos = cached.nextPos;
@@ -1833,30 +1631,7 @@ var fml = (function (exports) {
1833
1631
  s4 = null;
1834
1632
  }
1835
1633
  s5 = [];
1836
- s6 = peg$currPos;
1837
- if (input.charCodeAt(peg$currPos) === 44) {
1838
- s7 = peg$c34;
1839
- peg$currPos++;
1840
- } else {
1841
- s7 = peg$FAILED;
1842
- if (peg$silentFails === 0) { peg$fail(peg$e25); }
1843
- }
1844
- if (s7 !== peg$FAILED) {
1845
- peg$parse_();
1846
- s9 = peg$parseTernaryExpression();
1847
- if (s9 !== peg$FAILED) {
1848
- peg$parse_();
1849
- s6 = s9;
1850
- } else {
1851
- peg$currPos = s6;
1852
- s6 = peg$FAILED;
1853
- }
1854
- } else {
1855
- peg$currPos = s6;
1856
- s6 = peg$FAILED;
1857
- }
1858
- while (s6 !== peg$FAILED) {
1859
- s5.push(s6);
1634
+ for (;;) {
1860
1635
  s6 = peg$currPos;
1861
1636
  if (input.charCodeAt(peg$currPos) === 44) {
1862
1637
  s7 = peg$c34;
@@ -1879,6 +1654,8 @@ var fml = (function (exports) {
1879
1654
  peg$currPos = s6;
1880
1655
  s6 = peg$FAILED;
1881
1656
  }
1657
+ if (s6 === peg$FAILED) { break; }
1658
+ s5.push(s6);
1882
1659
  }
1883
1660
  if (input.charCodeAt(peg$currPos) === 41) {
1884
1661
  s6 = peg$c36;
@@ -1903,7 +1680,7 @@ var fml = (function (exports) {
1903
1680
  if (peg$silentFails === 0) { peg$fail(peg$e23); }
1904
1681
  }
1905
1682
 
1906
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1683
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1907
1684
 
1908
1685
  return s0;
1909
1686
  }
@@ -1912,7 +1689,7 @@ var fml = (function (exports) {
1912
1689
  let s0, s1, s3, s5;
1913
1690
 
1914
1691
  const key = peg$currPos * 38 + 23;
1915
- const cached = peg$resultsCache[key];
1692
+ const cached = peg$resultsCache.get(key);
1916
1693
 
1917
1694
  if (cached) {
1918
1695
  peg$currPos = cached.nextPos;
@@ -1964,7 +1741,7 @@ var fml = (function (exports) {
1964
1741
  }
1965
1742
  }
1966
1743
 
1967
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1744
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
1968
1745
 
1969
1746
  return s0;
1970
1747
  }
@@ -1973,7 +1750,7 @@ var fml = (function (exports) {
1973
1750
  let s0, s1, s2, s4, s5, s6, s7, s9;
1974
1751
 
1975
1752
  const key = peg$currPos * 38 + 24;
1976
- const cached = peg$resultsCache[key];
1753
+ const cached = peg$resultsCache.get(key);
1977
1754
 
1978
1755
  if (cached) {
1979
1756
  peg$currPos = cached.nextPos;
@@ -2007,30 +1784,7 @@ var fml = (function (exports) {
2007
1784
  s4 = null;
2008
1785
  }
2009
1786
  s5 = [];
2010
- s6 = peg$currPos;
2011
- if (input.charCodeAt(peg$currPos) === 44) {
2012
- s7 = peg$c34;
2013
- peg$currPos++;
2014
- } else {
2015
- s7 = peg$FAILED;
2016
- if (peg$silentFails === 0) { peg$fail(peg$e25); }
2017
- }
2018
- if (s7 !== peg$FAILED) {
2019
- peg$parse_();
2020
- s9 = peg$parseTernaryExpression();
2021
- if (s9 !== peg$FAILED) {
2022
- peg$parse_();
2023
- s6 = s9;
2024
- } else {
2025
- peg$currPos = s6;
2026
- s6 = peg$FAILED;
2027
- }
2028
- } else {
2029
- peg$currPos = s6;
2030
- s6 = peg$FAILED;
2031
- }
2032
- while (s6 !== peg$FAILED) {
2033
- s5.push(s6);
1787
+ for (;;) {
2034
1788
  s6 = peg$currPos;
2035
1789
  if (input.charCodeAt(peg$currPos) === 44) {
2036
1790
  s7 = peg$c34;
@@ -2053,6 +1807,8 @@ var fml = (function (exports) {
2053
1807
  peg$currPos = s6;
2054
1808
  s6 = peg$FAILED;
2055
1809
  }
1810
+ if (s6 === peg$FAILED) { break; }
1811
+ s5.push(s6);
2056
1812
  }
2057
1813
  if (input.charCodeAt(peg$currPos) === 41) {
2058
1814
  s6 = peg$c36;
@@ -2081,7 +1837,7 @@ var fml = (function (exports) {
2081
1837
  if (peg$silentFails === 0) { peg$fail(peg$e27); }
2082
1838
  }
2083
1839
 
2084
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1840
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2085
1841
 
2086
1842
  return s0;
2087
1843
  }
@@ -2090,7 +1846,7 @@ var fml = (function (exports) {
2090
1846
  let s0;
2091
1847
 
2092
1848
  const key = peg$currPos * 38 + 25;
2093
- const cached = peg$resultsCache[key];
1849
+ const cached = peg$resultsCache.get(key);
2094
1850
 
2095
1851
  if (cached) {
2096
1852
  peg$currPos = cached.nextPos;
@@ -2109,7 +1865,7 @@ var fml = (function (exports) {
2109
1865
  }
2110
1866
  }
2111
1867
 
2112
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
1868
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2113
1869
 
2114
1870
  return s0;
2115
1871
  }
@@ -2118,7 +1874,7 @@ var fml = (function (exports) {
2118
1874
  let s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
2119
1875
 
2120
1876
  const key = peg$currPos * 38 + 26;
2121
- const cached = peg$resultsCache[key];
1877
+ const cached = peg$resultsCache.get(key);
2122
1878
 
2123
1879
  if (cached) {
2124
1880
  peg$currPos = cached.nextPos;
@@ -2142,25 +1898,18 @@ var fml = (function (exports) {
2142
1898
  }
2143
1899
  s4 = peg$currPos;
2144
1900
  s5 = [];
2145
- s6 = input.charAt(peg$currPos);
2146
- if (peg$r1.test(s6)) {
2147
- peg$currPos++;
2148
- } else {
2149
- s6 = peg$FAILED;
2150
- if (peg$silentFails === 0) { peg$fail(peg$e30); }
2151
- }
2152
- if (s6 !== peg$FAILED) {
2153
- while (s6 !== peg$FAILED) {
2154
- s5.push(s6);
2155
- s6 = input.charAt(peg$currPos);
2156
- if (peg$r1.test(s6)) {
2157
- peg$currPos++;
2158
- } else {
2159
- s6 = peg$FAILED;
2160
- if (peg$silentFails === 0) { peg$fail(peg$e30); }
2161
- }
1901
+ for (;;) {
1902
+ s6 = input.charAt(peg$currPos);
1903
+ if ((peg$charCode = s6.charCodeAt(0), (peg$charCode >= 48 && peg$charCode <= 57))) {
1904
+ peg$currPos++;
1905
+ } else {
1906
+ s6 = peg$FAILED;
1907
+ if (peg$silentFails === 0) { peg$fail(peg$e30); }
2162
1908
  }
2163
- } else {
1909
+ if (s6 === peg$FAILED) { break; }
1910
+ s5.push(s6);
1911
+ }
1912
+ if (s5.length < 1) {
2164
1913
  s5 = peg$FAILED;
2165
1914
  }
2166
1915
  if (s5 !== peg$FAILED) {
@@ -2174,22 +1923,16 @@ var fml = (function (exports) {
2174
1923
  }
2175
1924
  if (s7 !== peg$FAILED) {
2176
1925
  s8 = [];
2177
- s9 = input.charAt(peg$currPos);
2178
- if (peg$r1.test(s9)) {
2179
- peg$currPos++;
2180
- } else {
2181
- s9 = peg$FAILED;
2182
- if (peg$silentFails === 0) { peg$fail(peg$e30); }
2183
- }
2184
- while (s9 !== peg$FAILED) {
2185
- s8.push(s9);
1926
+ for (;;) {
2186
1927
  s9 = input.charAt(peg$currPos);
2187
- if (peg$r1.test(s9)) {
1928
+ if ((peg$charCode = s9.charCodeAt(0), (peg$charCode >= 48 && peg$charCode <= 57))) {
2188
1929
  peg$currPos++;
2189
1930
  } else {
2190
1931
  s9 = peg$FAILED;
2191
1932
  if (peg$silentFails === 0) { peg$fail(peg$e30); }
2192
1933
  }
1934
+ if (s9 === peg$FAILED) { break; }
1935
+ s8.push(s9);
2193
1936
  }
2194
1937
  s7 = [s7, s8];
2195
1938
  s6 = s7;
@@ -2217,25 +1960,18 @@ var fml = (function (exports) {
2217
1960
  }
2218
1961
  if (s5 !== peg$FAILED) {
2219
1962
  s6 = [];
2220
- s7 = input.charAt(peg$currPos);
2221
- if (peg$r1.test(s7)) {
2222
- peg$currPos++;
2223
- } else {
2224
- s7 = peg$FAILED;
2225
- if (peg$silentFails === 0) { peg$fail(peg$e30); }
2226
- }
2227
- if (s7 !== peg$FAILED) {
2228
- while (s7 !== peg$FAILED) {
2229
- s6.push(s7);
2230
- s7 = input.charAt(peg$currPos);
2231
- if (peg$r1.test(s7)) {
2232
- peg$currPos++;
2233
- } else {
2234
- s7 = peg$FAILED;
2235
- if (peg$silentFails === 0) { peg$fail(peg$e30); }
2236
- }
1963
+ for (;;) {
1964
+ s7 = input.charAt(peg$currPos);
1965
+ if ((peg$charCode = s7.charCodeAt(0), (peg$charCode >= 48 && peg$charCode <= 57))) {
1966
+ peg$currPos++;
1967
+ } else {
1968
+ s7 = peg$FAILED;
1969
+ if (peg$silentFails === 0) { peg$fail(peg$e30); }
2237
1970
  }
2238
- } else {
1971
+ if (s7 === peg$FAILED) { break; }
1972
+ s6.push(s7);
1973
+ }
1974
+ if (s6.length < 1) {
2239
1975
  s6 = peg$FAILED;
2240
1976
  }
2241
1977
  if (s6 !== peg$FAILED) {
@@ -2272,7 +2008,7 @@ var fml = (function (exports) {
2272
2008
  if (peg$silentFails === 0) { peg$fail(peg$e28); }
2273
2009
  }
2274
2010
 
2275
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2011
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2276
2012
 
2277
2013
  return s0;
2278
2014
  }
@@ -2281,7 +2017,7 @@ var fml = (function (exports) {
2281
2017
  let s0, s1, s2, s3, s4;
2282
2018
 
2283
2019
  const key = peg$currPos * 38 + 27;
2284
- const cached = peg$resultsCache[key];
2020
+ const cached = peg$resultsCache.get(key);
2285
2021
 
2286
2022
  if (cached) {
2287
2023
  peg$currPos = cached.nextPos;
@@ -2301,22 +2037,16 @@ var fml = (function (exports) {
2301
2037
  if (s1 !== peg$FAILED) {
2302
2038
  s2 = peg$currPos;
2303
2039
  s3 = [];
2304
- s4 = input.charAt(peg$currPos);
2305
- if (peg$r2.test(s4)) {
2306
- peg$currPos++;
2307
- } else {
2308
- s4 = peg$FAILED;
2309
- if (peg$silentFails === 0) { peg$fail(peg$e33); }
2310
- }
2311
- while (s4 !== peg$FAILED) {
2312
- s3.push(s4);
2040
+ for (;;) {
2313
2041
  s4 = input.charAt(peg$currPos);
2314
- if (peg$r2.test(s4)) {
2042
+ if (s4 !== "" && !(peg$charCode = s4.charCodeAt(0), peg$charCode === 39)) {
2315
2043
  peg$currPos++;
2316
2044
  } else {
2317
2045
  s4 = peg$FAILED;
2318
2046
  if (peg$silentFails === 0) { peg$fail(peg$e33); }
2319
2047
  }
2048
+ if (s4 === peg$FAILED) { break; }
2049
+ s3.push(s4);
2320
2050
  }
2321
2051
  s2 = input.substring(s2, peg$currPos);
2322
2052
  if (input.charCodeAt(peg$currPos) === 39) {
@@ -2348,22 +2078,16 @@ var fml = (function (exports) {
2348
2078
  if (s1 !== peg$FAILED) {
2349
2079
  s2 = peg$currPos;
2350
2080
  s3 = [];
2351
- s4 = input.charAt(peg$currPos);
2352
- if (peg$r3.test(s4)) {
2353
- peg$currPos++;
2354
- } else {
2355
- s4 = peg$FAILED;
2356
- if (peg$silentFails === 0) { peg$fail(peg$e35); }
2357
- }
2358
- while (s4 !== peg$FAILED) {
2359
- s3.push(s4);
2081
+ for (;;) {
2360
2082
  s4 = input.charAt(peg$currPos);
2361
- if (peg$r3.test(s4)) {
2083
+ if (s4 !== "" && !(peg$charCode = s4.charCodeAt(0), peg$charCode === 34)) {
2362
2084
  peg$currPos++;
2363
2085
  } else {
2364
2086
  s4 = peg$FAILED;
2365
2087
  if (peg$silentFails === 0) { peg$fail(peg$e35); }
2366
2088
  }
2089
+ if (s4 === peg$FAILED) { break; }
2090
+ s3.push(s4);
2367
2091
  }
2368
2092
  s2 = input.substring(s2, peg$currPos);
2369
2093
  if (input.charCodeAt(peg$currPos) === 34) {
@@ -2394,16 +2118,13 @@ var fml = (function (exports) {
2394
2118
  }
2395
2119
  if (s1 !== peg$FAILED) {
2396
2120
  s2 = [];
2397
- s3 = peg$parseTemplateStringExpression();
2398
- if (s3 === peg$FAILED) {
2399
- s3 = peg$parseTemplateStringLiteral();
2400
- }
2401
- while (s3 !== peg$FAILED) {
2402
- s2.push(s3);
2121
+ for (;;) {
2403
2122
  s3 = peg$parseTemplateStringExpression();
2404
2123
  if (s3 === peg$FAILED) {
2405
2124
  s3 = peg$parseTemplateStringLiteral();
2406
2125
  }
2126
+ if (s3 === peg$FAILED) { break; }
2127
+ s2.push(s3);
2407
2128
  }
2408
2129
  if (input.charCodeAt(peg$currPos) === 96) {
2409
2130
  s3 = peg$c42;
@@ -2430,7 +2151,7 @@ var fml = (function (exports) {
2430
2151
  if (peg$silentFails === 0) { peg$fail(peg$e31); }
2431
2152
  }
2432
2153
 
2433
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2154
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2434
2155
 
2435
2156
  return s0;
2436
2157
  }
@@ -2439,7 +2160,7 @@ var fml = (function (exports) {
2439
2160
  let s0, s1, s3, s5;
2440
2161
 
2441
2162
  const key = peg$currPos * 38 + 28;
2442
- const cached = peg$resultsCache[key];
2163
+ const cached = peg$resultsCache.get(key);
2443
2164
 
2444
2165
  if (cached) {
2445
2166
  peg$currPos = cached.nextPos;
@@ -2488,7 +2209,7 @@ var fml = (function (exports) {
2488
2209
  if (peg$silentFails === 0) { peg$fail(peg$e37); }
2489
2210
  }
2490
2211
 
2491
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2212
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2492
2213
 
2493
2214
  return s0;
2494
2215
  }
@@ -2497,7 +2218,7 @@ var fml = (function (exports) {
2497
2218
  let s0, s1, s2, s3, s4;
2498
2219
 
2499
2220
  const key = peg$currPos * 38 + 29;
2500
- const cached = peg$resultsCache[key];
2221
+ const cached = peg$resultsCache.get(key);
2501
2222
 
2502
2223
  if (cached) {
2503
2224
  peg$currPos = cached.nextPos;
@@ -2508,123 +2229,60 @@ var fml = (function (exports) {
2508
2229
  peg$silentFails++;
2509
2230
  s0 = peg$currPos;
2510
2231
  s1 = [];
2511
- s2 = peg$currPos;
2512
- s3 = [];
2513
- s4 = input.charAt(peg$currPos);
2514
- if (peg$r4.test(s4)) {
2515
- peg$currPos++;
2516
- } else {
2517
- s4 = peg$FAILED;
2518
- if (peg$silentFails === 0) { peg$fail(peg$e40); }
2519
- }
2520
- if (s4 !== peg$FAILED) {
2521
- while (s4 !== peg$FAILED) {
2522
- s3.push(s4);
2232
+ for (;;) {
2233
+ s2 = peg$currPos;
2234
+ s3 = [];
2235
+ for (;;) {
2523
2236
  s4 = input.charAt(peg$currPos);
2524
- if (peg$r4.test(s4)) {
2237
+ if (s4 !== "" && !(peg$charCode = s4.charCodeAt(0), peg$charCode === 92 || peg$charCode === 96 || peg$charCode === 123)) {
2525
2238
  peg$currPos++;
2526
2239
  } else {
2527
2240
  s4 = peg$FAILED;
2528
2241
  if (peg$silentFails === 0) { peg$fail(peg$e40); }
2529
2242
  }
2243
+ if (s4 === peg$FAILED) { break; }
2244
+ s3.push(s4);
2530
2245
  }
2531
- } else {
2532
- s3 = peg$FAILED;
2533
- }
2534
- if (s3 !== peg$FAILED) {
2535
- s2 = input.substring(s2, peg$currPos);
2536
- } else {
2537
- s2 = s3;
2538
- }
2539
- if (s2 === peg$FAILED) {
2540
- s2 = peg$currPos;
2541
- if (input.charCodeAt(peg$currPos) === 92) {
2542
- s3 = peg$c7;
2543
- peg$currPos++;
2544
- } else {
2246
+ if (s3.length < 1) {
2545
2247
  s3 = peg$FAILED;
2546
- if (peg$silentFails === 0) { peg$fail(peg$e7); }
2547
2248
  }
2548
2249
  if (s3 !== peg$FAILED) {
2549
- if (input.length > peg$currPos) {
2550
- s4 = input.charAt(peg$currPos);
2551
- peg$currPos++;
2552
- } else {
2553
- s4 = peg$FAILED;
2554
- if (peg$silentFails === 0) { peg$fail(peg$e8); }
2555
- }
2556
- if (s4 !== peg$FAILED) {
2557
- s2 = peg$f28(s4);
2558
- } else {
2559
- peg$currPos = s2;
2560
- s2 = peg$FAILED;
2561
- }
2250
+ s2 = input.substring(s2, peg$currPos);
2562
2251
  } else {
2563
- peg$currPos = s2;
2564
- s2 = peg$FAILED;
2252
+ s2 = s3;
2565
2253
  }
2566
- }
2567
- if (s2 !== peg$FAILED) {
2568
- while (s2 !== peg$FAILED) {
2569
- s1.push(s2);
2254
+ if (s2 === peg$FAILED) {
2570
2255
  s2 = peg$currPos;
2571
- s3 = [];
2572
- s4 = input.charAt(peg$currPos);
2573
- if (peg$r4.test(s4)) {
2256
+ if (input.charCodeAt(peg$currPos) === 92) {
2257
+ s3 = peg$c7;
2574
2258
  peg$currPos++;
2575
- } else {
2576
- s4 = peg$FAILED;
2577
- if (peg$silentFails === 0) { peg$fail(peg$e40); }
2578
- }
2579
- if (s4 !== peg$FAILED) {
2580
- while (s4 !== peg$FAILED) {
2581
- s3.push(s4);
2582
- s4 = input.charAt(peg$currPos);
2583
- if (peg$r4.test(s4)) {
2584
- peg$currPos++;
2585
- } else {
2586
- s4 = peg$FAILED;
2587
- if (peg$silentFails === 0) { peg$fail(peg$e40); }
2588
- }
2589
- }
2590
2259
  } else {
2591
2260
  s3 = peg$FAILED;
2261
+ if (peg$silentFails === 0) { peg$fail(peg$e7); }
2592
2262
  }
2593
2263
  if (s3 !== peg$FAILED) {
2594
- s2 = input.substring(s2, peg$currPos);
2595
- } else {
2596
- s2 = s3;
2597
- }
2598
- if (s2 === peg$FAILED) {
2599
- s2 = peg$currPos;
2600
- if (input.charCodeAt(peg$currPos) === 92) {
2601
- s3 = peg$c7;
2264
+ if (input.length > peg$currPos) {
2265
+ s4 = input.charAt(peg$currPos);
2602
2266
  peg$currPos++;
2603
2267
  } else {
2604
- s3 = peg$FAILED;
2605
- if (peg$silentFails === 0) { peg$fail(peg$e7); }
2268
+ s4 = peg$FAILED;
2269
+ if (peg$silentFails === 0) { peg$fail(peg$e8); }
2606
2270
  }
2607
- if (s3 !== peg$FAILED) {
2608
- if (input.length > peg$currPos) {
2609
- s4 = input.charAt(peg$currPos);
2610
- peg$currPos++;
2611
- } else {
2612
- s4 = peg$FAILED;
2613
- if (peg$silentFails === 0) { peg$fail(peg$e8); }
2614
- }
2615
- if (s4 !== peg$FAILED) {
2616
- s2 = peg$f28(s4);
2617
- } else {
2618
- peg$currPos = s2;
2619
- s2 = peg$FAILED;
2620
- }
2271
+ if (s4 !== peg$FAILED) {
2272
+ s2 = peg$f28(s4);
2621
2273
  } else {
2622
2274
  peg$currPos = s2;
2623
2275
  s2 = peg$FAILED;
2624
2276
  }
2277
+ } else {
2278
+ peg$currPos = s2;
2279
+ s2 = peg$FAILED;
2625
2280
  }
2626
2281
  }
2627
- } else {
2282
+ if (s2 === peg$FAILED) { break; }
2283
+ s1.push(s2);
2284
+ }
2285
+ if (s1.length < 1) {
2628
2286
  s1 = peg$FAILED;
2629
2287
  }
2630
2288
  if (s1 !== peg$FAILED) {
@@ -2651,7 +2309,7 @@ var fml = (function (exports) {
2651
2309
  if (peg$silentFails === 0) { peg$fail(peg$e39); }
2652
2310
  }
2653
2311
 
2654
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2312
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2655
2313
 
2656
2314
  return s0;
2657
2315
  }
@@ -2660,7 +2318,7 @@ var fml = (function (exports) {
2660
2318
  let s0, s1, s3, s5, s6, s7, s9;
2661
2319
 
2662
2320
  const key = peg$currPos * 38 + 30;
2663
- const cached = peg$resultsCache[key];
2321
+ const cached = peg$resultsCache.get(key);
2664
2322
 
2665
2323
  if (cached) {
2666
2324
  peg$currPos = cached.nextPos;
@@ -2685,30 +2343,7 @@ var fml = (function (exports) {
2685
2343
  }
2686
2344
  peg$parse_();
2687
2345
  s5 = [];
2688
- s6 = peg$currPos;
2689
- if (input.charCodeAt(peg$currPos) === 44) {
2690
- s7 = peg$c34;
2691
- peg$currPos++;
2692
- } else {
2693
- s7 = peg$FAILED;
2694
- if (peg$silentFails === 0) { peg$fail(peg$e25); }
2695
- }
2696
- if (s7 !== peg$FAILED) {
2697
- peg$parse_();
2698
- s9 = peg$parseTernaryExpression();
2699
- if (s9 !== peg$FAILED) {
2700
- peg$parse_();
2701
- s6 = s9;
2702
- } else {
2703
- peg$currPos = s6;
2704
- s6 = peg$FAILED;
2705
- }
2706
- } else {
2707
- peg$currPos = s6;
2708
- s6 = peg$FAILED;
2709
- }
2710
- while (s6 !== peg$FAILED) {
2711
- s5.push(s6);
2346
+ for (;;) {
2712
2347
  s6 = peg$currPos;
2713
2348
  if (input.charCodeAt(peg$currPos) === 44) {
2714
2349
  s7 = peg$c34;
@@ -2731,6 +2366,8 @@ var fml = (function (exports) {
2731
2366
  peg$currPos = s6;
2732
2367
  s6 = peg$FAILED;
2733
2368
  }
2369
+ if (s6 === peg$FAILED) { break; }
2370
+ s5.push(s6);
2734
2371
  }
2735
2372
  if (input.charCodeAt(peg$currPos) === 93) {
2736
2373
  s6 = peg$c31;
@@ -2755,7 +2392,7 @@ var fml = (function (exports) {
2755
2392
  if (peg$silentFails === 0) { peg$fail(peg$e41); }
2756
2393
  }
2757
2394
 
2758
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2395
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2759
2396
 
2760
2397
  return s0;
2761
2398
  }
@@ -2764,7 +2401,7 @@ var fml = (function (exports) {
2764
2401
  let s0, s1, s3, s4, s5, s6, s7, s8, s9, s11, s13;
2765
2402
 
2766
2403
  const key = peg$currPos * 38 + 31;
2767
- const cached = peg$resultsCache[key];
2404
+ const cached = peg$resultsCache.get(key);
2768
2405
 
2769
2406
  if (cached) {
2770
2407
  peg$currPos = cached.nextPos;
@@ -2816,50 +2453,7 @@ var fml = (function (exports) {
2816
2453
  }
2817
2454
  s4 = peg$parse_();
2818
2455
  s5 = [];
2819
- s6 = peg$currPos;
2820
- if (input.charCodeAt(peg$currPos) === 44) {
2821
- s7 = peg$c34;
2822
- peg$currPos++;
2823
- } else {
2824
- s7 = peg$FAILED;
2825
- if (peg$silentFails === 0) { peg$fail(peg$e25); }
2826
- }
2827
- if (s7 !== peg$FAILED) {
2828
- s8 = peg$parse_();
2829
- s9 = peg$parseStringLiteral();
2830
- if (s9 !== peg$FAILED) {
2831
- peg$parse_();
2832
- if (input.charCodeAt(peg$currPos) === 58) {
2833
- s11 = peg$c15;
2834
- peg$currPos++;
2835
- } else {
2836
- s11 = peg$FAILED;
2837
- if (peg$silentFails === 0) { peg$fail(peg$e11); }
2838
- }
2839
- if (s11 !== peg$FAILED) {
2840
- peg$parse_();
2841
- s13 = peg$parseTernaryExpression();
2842
- if (s13 !== peg$FAILED) {
2843
- peg$parse_();
2844
- s6 = [ s9, s13 ];
2845
- } else {
2846
- peg$currPos = s6;
2847
- s6 = peg$FAILED;
2848
- }
2849
- } else {
2850
- peg$currPos = s6;
2851
- s6 = peg$FAILED;
2852
- }
2853
- } else {
2854
- peg$currPos = s6;
2855
- s6 = peg$FAILED;
2856
- }
2857
- } else {
2858
- peg$currPos = s6;
2859
- s6 = peg$FAILED;
2860
- }
2861
- while (s6 !== peg$FAILED) {
2862
- s5.push(s6);
2456
+ for (;;) {
2863
2457
  s6 = peg$currPos;
2864
2458
  if (input.charCodeAt(peg$currPos) === 44) {
2865
2459
  s7 = peg$c34;
@@ -2902,6 +2496,8 @@ var fml = (function (exports) {
2902
2496
  peg$currPos = s6;
2903
2497
  s6 = peg$FAILED;
2904
2498
  }
2499
+ if (s6 === peg$FAILED) { break; }
2500
+ s5.push(s6);
2905
2501
  }
2906
2502
  if (input.charCodeAt(peg$currPos) === 125) {
2907
2503
  s6 = peg$c43;
@@ -2926,7 +2522,7 @@ var fml = (function (exports) {
2926
2522
  if (peg$silentFails === 0) { peg$fail(peg$e42); }
2927
2523
  }
2928
2524
 
2929
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2525
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2930
2526
 
2931
2527
  return s0;
2932
2528
  }
@@ -2935,7 +2531,7 @@ var fml = (function (exports) {
2935
2531
  let s0, s1, s2, s3, s4;
2936
2532
 
2937
2533
  const key = peg$currPos * 38 + 32;
2938
- const cached = peg$resultsCache[key];
2534
+ const cached = peg$resultsCache.get(key);
2939
2535
 
2940
2536
  if (cached) {
2941
2537
  peg$currPos = cached.nextPos;
@@ -2993,7 +2589,7 @@ var fml = (function (exports) {
2993
2589
  if (peg$silentFails === 0) { peg$fail(peg$e43); }
2994
2590
  }
2995
2591
 
2996
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2592
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
2997
2593
 
2998
2594
  return s0;
2999
2595
  }
@@ -3002,7 +2598,7 @@ var fml = (function (exports) {
3002
2598
  let s0, s1, s2, s3, s4;
3003
2599
 
3004
2600
  const key = peg$currPos * 38 + 33;
3005
- const cached = peg$resultsCache[key];
2601
+ const cached = peg$resultsCache.get(key);
3006
2602
 
3007
2603
  if (cached) {
3008
2604
  peg$currPos = cached.nextPos;
@@ -3013,7 +2609,7 @@ var fml = (function (exports) {
3013
2609
  s0 = peg$currPos;
3014
2610
  s1 = peg$currPos;
3015
2611
  s2 = input.charAt(peg$currPos);
3016
- if (peg$r5.test(s2)) {
2612
+ if ((peg$charCode = s2.charCodeAt(0), (peg$charCode >= 97 && peg$charCode <= 122) || (peg$charCode >= 65 && peg$charCode <= 90) || peg$charCode === 36 || peg$charCode === 95)) {
3017
2613
  peg$currPos++;
3018
2614
  } else {
3019
2615
  s2 = peg$FAILED;
@@ -3021,22 +2617,16 @@ var fml = (function (exports) {
3021
2617
  }
3022
2618
  if (s2 !== peg$FAILED) {
3023
2619
  s3 = [];
3024
- s4 = input.charAt(peg$currPos);
3025
- if (peg$r6.test(s4)) {
3026
- peg$currPos++;
3027
- } else {
3028
- s4 = peg$FAILED;
3029
- if (peg$silentFails === 0) { peg$fail(peg$e46); }
3030
- }
3031
- while (s4 !== peg$FAILED) {
3032
- s3.push(s4);
2620
+ for (;;) {
3033
2621
  s4 = input.charAt(peg$currPos);
3034
- if (peg$r6.test(s4)) {
2622
+ if ((peg$charCode = s4.charCodeAt(0), (peg$charCode >= 97 && peg$charCode <= 122) || (peg$charCode >= 65 && peg$charCode <= 90) || peg$charCode === 36 || peg$charCode === 95 || (peg$charCode >= 48 && peg$charCode <= 57))) {
3035
2623
  peg$currPos++;
3036
2624
  } else {
3037
2625
  s4 = peg$FAILED;
3038
2626
  if (peg$silentFails === 0) { peg$fail(peg$e46); }
3039
2627
  }
2628
+ if (s4 === peg$FAILED) { break; }
2629
+ s3.push(s4);
3040
2630
  }
3041
2631
  s2 = [s2, s3];
3042
2632
  s1 = s2;
@@ -3050,7 +2640,7 @@ var fml = (function (exports) {
3050
2640
  s0 = s1;
3051
2641
  }
3052
2642
 
3053
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2643
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
3054
2644
 
3055
2645
  return s0;
3056
2646
  }
@@ -3059,7 +2649,7 @@ var fml = (function (exports) {
3059
2649
  let s0, s1;
3060
2650
 
3061
2651
  const key = peg$currPos * 38 + 34;
3062
- const cached = peg$resultsCache[key];
2652
+ const cached = peg$resultsCache.get(key);
3063
2653
 
3064
2654
  if (cached) {
3065
2655
  peg$currPos = cached.nextPos;
@@ -3080,7 +2670,7 @@ var fml = (function (exports) {
3080
2670
  if (peg$silentFails === 0) { peg$fail(peg$e47); }
3081
2671
  }
3082
2672
 
3083
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2673
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
3084
2674
 
3085
2675
  return s0;
3086
2676
  }
@@ -3089,7 +2679,7 @@ var fml = (function (exports) {
3089
2679
  let s0;
3090
2680
 
3091
2681
  const key = peg$currPos * 38 + 35;
3092
- const cached = peg$resultsCache[key];
2682
+ const cached = peg$resultsCache.get(key);
3093
2683
 
3094
2684
  if (cached) {
3095
2685
  peg$currPos = cached.nextPos;
@@ -3114,7 +2704,7 @@ var fml = (function (exports) {
3114
2704
  }
3115
2705
  }
3116
2706
 
3117
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2707
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
3118
2708
 
3119
2709
  return s0;
3120
2710
  }
@@ -3123,7 +2713,7 @@ var fml = (function (exports) {
3123
2713
  let s0;
3124
2714
 
3125
2715
  const key = peg$currPos * 38 + 36;
3126
- const cached = peg$resultsCache[key];
2716
+ const cached = peg$resultsCache.get(key);
3127
2717
 
3128
2718
  if (cached) {
3129
2719
  peg$currPos = cached.nextPos;
@@ -3166,7 +2756,7 @@ var fml = (function (exports) {
3166
2756
  }
3167
2757
  }
3168
2758
 
3169
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2759
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
3170
2760
 
3171
2761
  return s0;
3172
2762
  }
@@ -3175,7 +2765,7 @@ var fml = (function (exports) {
3175
2765
  let s0, s1;
3176
2766
 
3177
2767
  const key = peg$currPos * 38 + 37;
3178
- const cached = peg$resultsCache[key];
2768
+ const cached = peg$resultsCache.get(key);
3179
2769
 
3180
2770
  if (cached) {
3181
2771
  peg$currPos = cached.nextPos;
@@ -3185,26 +2775,20 @@ var fml = (function (exports) {
3185
2775
 
3186
2776
  peg$silentFails++;
3187
2777
  s0 = [];
3188
- s1 = input.charAt(peg$currPos);
3189
- if (peg$r7.test(s1)) {
3190
- peg$currPos++;
3191
- } else {
3192
- s1 = peg$FAILED;
3193
- if (peg$silentFails === 0) { peg$fail(peg$e54); }
3194
- }
3195
- while (s1 !== peg$FAILED) {
3196
- s0.push(s1);
2778
+ for (;;) {
3197
2779
  s1 = input.charAt(peg$currPos);
3198
- if (peg$r7.test(s1)) {
2780
+ if ((peg$charCode = s1.charCodeAt(0), peg$charCode === 32 || peg$charCode === 9 || peg$charCode === 10 || peg$charCode === 13)) {
3199
2781
  peg$currPos++;
3200
2782
  } else {
3201
2783
  s1 = peg$FAILED;
3202
2784
  if (peg$silentFails === 0) { peg$fail(peg$e54); }
3203
2785
  }
2786
+ if (s1 === peg$FAILED) { break; }
2787
+ s0.push(s1);
3204
2788
  }
3205
2789
  peg$silentFails--;
3206
2790
 
3207
- peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
2791
+ peg$resultsCache.set(key, { nextPos: peg$currPos, result: s0 });
3208
2792
 
3209
2793
  return s0;
3210
2794
  }
@@ -3717,7 +3301,7 @@ var fml = (function (exports) {
3717
3301
  el.removeAttribute('slot');
3718
3302
  return [slot, LightSlots.slotFromNode(el)];
3719
3303
  });
3720
- const slots = {};
3304
+ const slots = Object.create(null);
3721
3305
  slots.default = new DocumentFragment();
3722
3306
  slots.default.append(...el.childNodes);
3723
3307
  for (const [name, el] of namedSlots) {
@@ -3783,6 +3367,13 @@ var fml = (function (exports) {
3783
3367
  if (win === null) {
3784
3368
  return Promise.resolve();
3785
3369
  }
3370
+ // interactive spans both the deferred scripts and the time between DOMContentLoaded and load
3371
+ const [navigation] = /** @type {PerformanceNavigationTiming[]} */ (
3372
+ win.performance?.getEntriesByType('navigation') ?? []
3373
+ );
3374
+ if (navigation?.domContentLoadedEventStart > 0) {
3375
+ return Promise.resolve();
3376
+ }
3786
3377
  return new Promise((resolve) => {
3787
3378
  const done = () => {
3788
3379
  win.removeEventListener('DOMContentLoaded', done);
@@ -3799,12 +3390,12 @@ var fml = (function (exports) {
3799
3390
  * resolves once the element, or any of its ancestors, gains a next sibling,
3800
3391
  * which is the parser having moved past this subtree. The document's
3801
3392
  * DOMContentLoaded is the deadline. Resolves immediately for an element
3802
- * that is already parsed.
3393
+ * that is already parsed, or once the parser has finished the document.
3803
3394
  * @param {Element} el
3804
3395
  * @returns {Promise<Element>} the element
3805
3396
  */
3806
3397
  static waitParsed(el) {
3807
- if (Nodes.isParsed(el)) {
3398
+ if (Nodes.isParsed(el) || el.ownerDocument.readyState !== 'loading') {
3808
3399
  return Promise.resolve(el);
3809
3400
  }
3810
3401
  return new Promise((resolve) => {
@@ -3946,7 +3537,8 @@ var fml = (function (exports) {
3946
3537
  const statName = ops.popData(node, 'tplStat');
3947
3538
  const template = new Template(node, evaluator);
3948
3539
  const evaluated = evaluator.evaluateExpression(expression);
3949
- const proto = evaluated === null || typeof evaluated !== 'object' ? undefined : Object.getPrototypeOf(evaluated);
3540
+ const proto =
3541
+ evaluated === null || typeof evaluated !== 'object' ? undefined : Object.getPrototypeOf(evaluated);
3950
3542
  const plain = !evaluated?.[Symbol.iterator] && (proto === Object.prototype || proto === null);
3951
3543
  const dict = plain ? Object.entries(evaluated) : null;
3952
3544
  const keyed = evaluated instanceof Map ? [...evaluated] : dict;
@@ -4026,6 +3618,9 @@ var fml = (function (exports) {
4026
3618
  }
4027
3619
  const tuples = Array.isArray(attributesAndValues[0]) ? attributesAndValues : [attributesAndValues];
4028
3620
  tuples.forEach(([k, v]) => {
3621
+ if (v === null || v === undefined) {
3622
+ return;
3623
+ }
4029
3624
  node.setAttribute(k, v);
4030
3625
  });
4031
3626
  }
@@ -5143,7 +4738,8 @@ var fml = (function (exports) {
5143
4738
  const PLACEHOLDER = /\{(\w+)\}/g;
5144
4739
  const POSITIONAL = /\{(\d+)\}/g;
5145
4740
  /** @param {any} v @returns {v is Record<string, string>} */
5146
- const isPlainObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
4741
+ const isPlainObject = (v) =>
4742
+ typeof v === 'object' && v !== null && [Object.prototype, null].includes(Object.getPrototypeOf(v));
5147
4743
 
5148
4744
  /** @param {any} problem @returns {string|undefined} the reason, unless it is missing or blank */
5149
4745
  const reasonOf = (problem) =>
@@ -5178,8 +4774,8 @@ var fml = (function (exports) {
5178
4774
  class Localization {
5179
4775
  /**
5180
4776
  * Resolves a message from the translations and interpolates its arguments.
5181
- * A single plain object argument interpolates named placeholders
5182
- * ({name}); anything else interpolates positional ones ({0}).
4777
+ * A single plain object argument (an object literal, or one with a null
4778
+ * prototype) interpolates named placeholders ({name}); anything else interpolates positional ones ({0}).
5183
4779
  * A plural leaf selects its form through Intl.PluralRules over the
5184
4780
  * numeric {count} named argument.
5185
4781
  *
@@ -5502,12 +5098,20 @@ var fml = (function (exports) {
5502
5098
  });
5503
5099
  }
5504
5100
  /**
5505
- * @param {Iterable<number>} bytes
5101
+ * @param {Iterable<number>|ArrayBuffer|ArrayBufferView} bytes octets, or
5102
+ * a buffer or view read as its bytes
5506
5103
  * @param {boolean} [upper] uppercase digits instead of lowercase
5507
5104
  * @returns {string} two digits per byte
5508
5105
  */
5509
5106
  static encode(bytes, upper) {
5510
- return Array.from(bytes)
5107
+ let octets = /** @type {Iterable<number>} */ (bytes);
5108
+ if (bytes instanceof ArrayBuffer) {
5109
+ octets = new Uint8Array(bytes);
5110
+ }
5111
+ if (ArrayBuffer.isView(bytes)) {
5112
+ octets = new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
5113
+ }
5114
+ return Array.from(octets)
5511
5115
  .map((b) => b.toString(16))
5512
5116
  .map((b) => (upper ? b.toUpperCase() : b))
5513
5117
  .map((o) => o.padStart(2, '0'))
@@ -5610,11 +5214,12 @@ var fml = (function (exports) {
5610
5214
  /**
5611
5215
  * The failure an error response stands for, keeping its status. An
5612
5216
  * `application/failures+json` body is the problems list; an
5613
- * `application/problem+json` body contributes its `problems`, or one
5614
- * GENERIC_PROBLEM made of its title and detail. Any other body is one
5615
- * GENERIC_PROBLEM carrying the body text. A json body that does not decode,
5616
- * or decodes to the wrong shape, and a body that cannot be read at all,
5617
- * each become one GENERIC_PROBLEM saying so.
5217
+ * `application/problem+json` body contributes its non-empty `problems`
5218
+ * array, or one GENERIC_PROBLEM made of whichever of its title and detail
5219
+ * it has. Any other body is one GENERIC_PROBLEM carrying the body text. A
5220
+ * json body that does not decode, or decodes to the wrong shape or to an
5221
+ * empty failures array, and a body that cannot be read at all, each
5222
+ * become one GENERIC_PROBLEM saying so.
5618
5223
  * @param {Response} response consumed
5619
5224
  * @returns {Promise<HttpClientError>}
5620
5225
  */
@@ -5626,7 +5231,10 @@ var fml = (function (exports) {
5626
5231
  return HttpClientError.#undecodable(response);
5627
5232
  }
5628
5233
  if (!Array.isArray(data)) {
5629
- return HttpClientError.#undecodable(response, 'as a failures array');
5234
+ return HttpClientError.#undecodable(response, 'does not decode as a failures array');
5235
+ }
5236
+ if (data.length === 0) {
5237
+ return HttpClientError.#undecodable(response, 'carries no failures');
5630
5238
  }
5631
5239
  const message = `${response.status} ${response.statusText}: ${data.length} failures`;
5632
5240
  return new HttpClientError(message, response.status, data);
@@ -5637,13 +5245,18 @@ var fml = (function (exports) {
5637
5245
  return HttpClientError.#undecodable(response);
5638
5246
  }
5639
5247
  if (typeof data !== 'object' || data === null || Array.isArray(data)) {
5640
- return HttpClientError.#undecodable(response, 'as a problem object');
5248
+ return HttpClientError.#undecodable(response, 'does not decode as a problem object');
5641
5249
  }
5642
- const message = `${response.status} ${response.statusText}: ${data.title} ${data.detail}`;
5250
+ const text = [data.title, data.detail].filter((part) => part !== undefined && part !== null).join(' ');
5251
+ const message = text
5252
+ ? `${response.status} ${response.statusText}: ${text}`
5253
+ : `${response.status} ${response.statusText}`;
5643
5254
  return new HttpClientError(
5644
5255
  message,
5645
5256
  response.status,
5646
- data.problems || [HttpClientError.problem('GENERIC_PROBLEM', message)],
5257
+ Array.isArray(data.problems) && data.problems.length > 0
5258
+ ? data.problems
5259
+ : [HttpClientError.problem('GENERIC_PROBLEM', message)],
5647
5260
  );
5648
5261
  }
5649
5262
  default: {
@@ -5654,11 +5267,11 @@ var fml = (function (exports) {
5654
5267
  static #unreadable = Symbol('unreadable body');
5655
5268
  /**
5656
5269
  * @param {Response} response
5657
- * @param {string} [as] what the body does not decode as
5270
+ * @param {string} [flaw] what is wrong with the body
5658
5271
  */
5659
- static #undecodable(response, as = 'as json') {
5272
+ static #undecodable(response, flaw = 'does not decode as json') {
5660
5273
  const mediaType = MediaType.parse(response.headers.get('Content-Type')).normalized;
5661
- const message = `${response.status} ${response.statusText}: the ${mediaType} body does not decode ${as}`;
5274
+ const message = `${response.status} ${response.statusText}: the ${mediaType} body ${flaw}`;
5662
5275
  return new HttpClientError(message, response.status, [HttpClientError.problem('GENERIC_PROBLEM', message)]);
5663
5276
  }
5664
5277
  static async #generic(response) {
@@ -5755,7 +5368,7 @@ var fml = (function (exports) {
5755
5368
  }
5756
5369
  /** @returns {HttpClient} a client running the interceptors added so far */
5757
5370
  build() {
5758
- return new HttpClient(this.#interceptors);
5371
+ return new HttpClient([...this.#interceptors]);
5759
5372
  }
5760
5373
  }
5761
5374
 
@@ -6961,7 +6574,9 @@ var fml = (function (exports) {
6961
6574
  * alone and a composite field named for a prefix catches the problems of its
6962
6575
  * subtree. Each control of that name gets `setCustomValidity(reason, rest)`,
6963
6576
  * `rest` being the remainder of the path (`''` on an exact match) that a
6964
- * composite can use to route the problem to an inner control.
6577
+ * composite can use to route the problem to an inner control. Several
6578
+ * problems reaching one control with the same `rest` are joined one per
6579
+ * line into a single call.
6965
6580
  *
6966
6581
  * A control counts only when it can show a problem, through a
6967
6582
  * `setCustomValidity` of its own: a form-associated element that has none is
@@ -6976,7 +6591,8 @@ var fml = (function (exports) {
6976
6591
  * Each `ful-field-error` of the form gets `aria-live="off"` when
6977
6592
  * `scrollOnError` is set, since focusing the field announces its error, and
6978
6593
  * `aria-live="polite"` otherwise. With `scrollOnError` and at least one
6979
- * problem, the topmost `:invalid` control is focused.
6594
+ * problem, the topmost `:invalid` control is focused; a `<fieldset>`
6595
+ * matching `:invalid` for the controls it holds is not a candidate.
6980
6596
  *
6981
6597
  * A banner or `ful-field-error` belongs to the nearest enclosing form, so
6982
6598
  * those of a nested form are left alone.
@@ -7001,6 +6617,8 @@ var fml = (function (exports) {
7001
6617
  });
7002
6618
  }
7003
6619
  const unmatched = [];
6620
+ /** @type {Map<any, Map<string, string[]>>} */
6621
+ const pins = new Map();
7004
6622
  fieldErrors.forEach((e) => {
7005
6623
  const name = /** @type {string} */ (e.context).replace(/\[/g, '.').replace(/\]\./g, '.').replace(/\]/g, '');
7006
6624
  const parts = name.split('.');
@@ -7012,12 +6630,19 @@ var fml = (function (exports) {
7012
6630
  }
7013
6631
  const context = parts.slice(i).join('.');
7014
6632
  targets.forEach((input) => {
7015
- input.setCustomValidity?.(e.reason, context);
6633
+ const contexts = pins.get(input) ?? new Map();
6634
+ contexts.set(context, [...(contexts.get(context) ?? []), e.reason]);
6635
+ pins.set(input, contexts);
7016
6636
  });
7017
6637
  return;
7018
6638
  }
7019
6639
  unmatched.push(e);
7020
6640
  });
6641
+ for (const [input, contexts] of pins) {
6642
+ for (const [context, reasons] of contexts) {
6643
+ input.setCustomValidity(reasons.join('\n'), context);
6644
+ }
6645
+ }
7021
6646
  const bannered = [...globalErrors, ...unmatched];
7022
6647
  form.querySelectorAll('ful-errors').forEach((el) => {
7023
6648
  if (!ofForm(el)) {
@@ -7037,7 +6662,7 @@ var fml = (function (exports) {
7037
6662
  return;
7038
6663
  }
7039
6664
  /** @type {HTMLElement[]} */ (Array.from(form.elements))
7040
- .filter((el) => el.matches(':invalid'))
6665
+ .filter((el) => el.localName !== 'fieldset' && el.matches(':invalid'))
7041
6666
  .sort((a, b) => a.getBoundingClientRect().y - b.getBoundingClientRect().y)[0]
7042
6667
  ?.focus();
7043
6668
  }
@@ -7056,9 +6681,12 @@ var fml = (function (exports) {
7056
6681
  *
7057
6682
  * The claim setters, the validity protocol and the aria wiring all act on the
7058
6683
  * pieces, so a field with no native control returns a focusable piece of its
7059
- * own chrome as the control. The claim getters and `focus()` are the only
7060
- * members that tolerate a not yet rendered element; the other members need the
7061
- * pieces and so work only after the render.
6684
+ * own chrome as the control. The claims, `value` and `focus()` are the
6685
+ * members that tolerate a not yet rendered element: before the render the
6686
+ * `value` getter answers what the rendered field would answer from its current
6687
+ * declared state, and a value written then is held and applied by the render
6688
+ * (see `_holdValue`). The other members need the pieces and so work only after
6689
+ * the render.
7062
6690
  *
7063
6691
  * The inner controls carry `form=""`, so the host is the only element the form
7064
6692
  * sees. Enter pressed in an inner `<input>` of any type but `file`, `button`,
@@ -7094,6 +6722,8 @@ var fml = (function (exports) {
7094
6722
  #claims;
7095
6723
  #announces;
7096
6724
  #also = [];
6725
+ /** @type {{ value: any } | null} the value written before the render, which the render applies */
6726
+ #held = null;
7097
6727
  /** Sets the internals' role from the subclass's `static ROLE`. */
7098
6728
  constructor() {
7099
6729
  super();
@@ -7327,11 +6957,47 @@ var fml = (function (exports) {
7327
6957
  _interactive() {
7328
6958
  return !this.matches(':disabled') && !this.readonly;
7329
6959
  }
6960
+ /**
6961
+ * Upgrades as `ParsedElement.upgrade` does, then writes the value held by
6962
+ * `_holdValue`, if any, through the `value` setter: the value written
6963
+ * before the render wins over the declared one.
6964
+ * @returns {Promise<void>} rejecting with what the render threw
6965
+ */
6966
+ async upgrade() {
6967
+ await super.upgrade();
6968
+ if (this.#held === null) {
6969
+ return;
6970
+ }
6971
+ const { value } = this.#held;
6972
+ this.#held = null;
6973
+ this.value = value;
6974
+ }
6975
+ /**
6976
+ * Keeps a value written before the field has its control, for a subclass's
6977
+ * `value` setter to call in place of writing it: the upgrade writes it
6978
+ * through the setter once the field has rendered, over the declared one.
6979
+ * The `value` attribute is left alone, so a reset still restores it.
6980
+ * @param {any} value
6981
+ */
6982
+ _holdValue(value) {
6983
+ this.#held = { value };
6984
+ }
6985
+ /**
6986
+ * The value a subclass's `value` getter shapes before the field has its
6987
+ * control: the one `_holdValue` kept, else the declared `value` attribute
6988
+ * read through its mapper.
6989
+ * @returns {any}
6990
+ */
6991
+ _heldValue() {
6992
+ return this.#held === null ? this.declared('value') : this.#held.value;
6993
+ }
7330
6994
  /**
7331
6995
  * The field's value, `null` when empty. Every concrete field overrides the
7332
6996
  * pair with its own semantics; the form extraction, `values =` assignment,
7333
6997
  * the `change` detail and `formResetCallback` all go through it. The base
7334
- * pair reads `undefined` and ignores writes.
6998
+ * pair reads `undefined` and ignores writes. A concrete field answers and
6999
+ * takes its value before the render too, through `_heldValue` and
7000
+ * `_holdValue`.
7335
7001
  * @type {any}
7336
7002
  */
7337
7003
  get value() {
@@ -7700,6 +7366,18 @@ var fml = (function (exports) {
7700
7366
  this.addEventListener('input', (evt) => this.#touch(evt.target));
7701
7367
  this.addEventListener('change', (evt) => this.#touch(evt.target));
7702
7368
  this.addEventListener('focusin', (evt) => this.#focus(evt.target));
7369
+ this.form.addEventListener('reset', (evt) => {
7370
+ if (evt.target !== this.form) {
7371
+ return;
7372
+ }
7373
+ for (const name of new Set([...this.#saved.keys(), ...this.#snapshot().keys()])) {
7374
+ this.#edits.set(name, ++this.#sequence);
7375
+ }
7376
+ // the controls are restored only after the event, so the state is read at the next frame
7377
+ if (this.#frame === 0) {
7378
+ this.#frame = requestAnimationFrame(() => this.#refresh());
7379
+ }
7380
+ });
7703
7381
  Rendering.waitForChildren(this)
7704
7382
  .catch(() => undefined)
7705
7383
  .then(() => this.commit());
@@ -7717,7 +7395,7 @@ var fml = (function (exports) {
7717
7395
  }
7718
7396
  #submitting = false;
7719
7397
  /**
7720
- * Runs the submit pipeline, with the spinner up for its whole length:
7398
+ * Runs the submit pipeline, with the spinner up until its outcome:
7721
7399
  *
7722
7400
  * 1. builds the loader: the component the `loader` attribute names
7723
7401
  * (`loaders:form` by default), called as `create(form)`
@@ -7734,8 +7412,8 @@ var fml = (function (exports) {
7734
7412
  * 6. has the loader `submit` the request and `transform` the response
7735
7413
  * 7. under `track-changes`, commits the values extracted at step 2 (see
7736
7414
  * `commit`): an edit made while the submit was in flight stays unsaved
7737
- * 8. fires `submit:success` with `{ submitter, values, request, response }`,
7738
- * `response` being the transformed one
7415
+ * 8. releases the spinner and fires `submit:success` with `{ submitter,
7416
+ * values, request, response }`, `response` being the transformed one
7739
7417
  *
7740
7418
  * Anything thrown from step 1 on, a missing loader or a throwing mapper
7741
7419
  * included, fires `submit:failure` with `{ submitter, values, request,
@@ -7744,6 +7422,11 @@ var fml = (function (exports) {
7744
7422
  * `console.warn`. The `values` of both outcome events are the extracted
7745
7423
  * ones, not a replacement a `submit` listener put on its detail.
7746
7424
  *
7425
+ * The form settles before either outcome event (0016): its listeners see
7426
+ * the spinner released and the buttons no longer held off, the problems of
7427
+ * a `Failure` already shown, and the submit no longer in flight, so one
7428
+ * of them may submit again.
7429
+ *
7747
7430
  * A call while a submit is in flight returns at once, doing nothing.
7748
7431
  * @param {HTMLElement} [submitter] the button that submitted, if any; it is
7749
7432
  * the only button whose name and value are submitted
@@ -7759,6 +7442,7 @@ var fml = (function (exports) {
7759
7442
  this.spinner(true);
7760
7443
  let values;
7761
7444
  let request;
7445
+ let outcome;
7762
7446
  try {
7763
7447
  const loader = this.component(this.declared('loader') ?? 'loaders:form').create(this);
7764
7448
  values = Bindings.extractFrom(this.form, submitter);
@@ -7786,32 +7470,28 @@ var fml = (function (exports) {
7786
7470
  if (submitted) {
7787
7471
  this.#commitFrom(submitted.saved, submitted.upTo);
7788
7472
  }
7789
- this.dispatchEvent(
7790
- new CustomEvent('submit:success', {
7791
- bubbles: true,
7792
- cancelable: false,
7793
- detail: { submitter, values, request, response: mapped },
7794
- }),
7795
- );
7796
- return true;
7473
+ outcome = new CustomEvent('submit:success', {
7474
+ bubbles: true,
7475
+ cancelable: false,
7476
+ detail: { submitter, values, request, response: mapped },
7477
+ });
7797
7478
  } catch (e) {
7798
- this.dispatchEvent(
7799
- new CustomEvent('submit:failure', {
7800
- bubbles: true,
7801
- cancelable: false,
7802
- detail: { submitter, values, request, exception: e },
7803
- }),
7804
- );
7479
+ outcome = new CustomEvent('submit:failure', {
7480
+ bubbles: true,
7481
+ cancelable: false,
7482
+ detail: { submitter, values, request, exception: e },
7483
+ });
7805
7484
  if (e instanceof Failure) {
7806
7485
  this.errors = e.problems;
7807
7486
  } else {
7808
7487
  console.warn('failed to submit form', this, 'reason:', e);
7809
7488
  }
7810
- return false;
7811
7489
  } finally {
7812
7490
  this.#submitting = false;
7813
7491
  this.spinner(false);
7814
7492
  }
7493
+ this.dispatchEvent(outcome);
7494
+ return outcome.type === 'submit:success';
7815
7495
  }
7816
7496
  /**
7817
7497
  * Saves the unsaved edits, for a page action that would lose them, such as
@@ -7830,18 +7510,15 @@ var fml = (function (exports) {
7830
7510
  }
7831
7511
  /**
7832
7512
  * Resets the native form, each field returning to its default value. Under
7833
- * `track-changes` every control counts as edited: the form is dirty if the
7834
- * defaults differ from what was last committed.
7513
+ * `track-changes` a reset, this one or a native reset button's, counts
7514
+ * every control as edited: the form is dirty if the defaults differ from
7515
+ * what was last committed.
7835
7516
  */
7836
7517
  reset() {
7837
7518
  this.form.reset();
7838
- if (!this.#tracking) {
7839
- return;
7840
- }
7841
- for (const name of new Set([...this.#saved.keys(), ...this.#snapshot().keys()])) {
7842
- this.#edits.set(name, ++this.#sequence);
7519
+ if (this.#tracking) {
7520
+ this.#refresh();
7843
7521
  }
7844
- this.#refresh();
7845
7522
  }
7846
7523
  /** name → the serialized values the last commit recorded */
7847
7524
  #saved = new Map();
@@ -8266,6 +7943,12 @@ var fml = (function (exports) {
8266
7943
  _input;
8267
7944
  /** @type {(HTMLInputElement|HTMLTextAreaElement)[]} */
8268
7945
  #controls = [];
7946
+ /**
7947
+ * The serialized value a date or time control last reported, or held when
7948
+ * focused or written.
7949
+ * @type {string|null}
7950
+ */
7951
+ #committed = null;
8269
7952
  /**
8270
7953
  * The type the field renders, which a subclass overrides to wrap another
8271
7954
  * native type. The base answers the declared `type`, else `number` under
@@ -8345,20 +8028,18 @@ var fml = (function (exports) {
8345
8028
  });
8346
8029
  return;
8347
8030
  }
8348
- /** @type {string|null} */
8349
- let committed = null;
8350
8031
  let typed = false;
8351
8032
  const commit = () => {
8352
8033
  typed = false;
8353
8034
  const now = JSON.stringify(this.value);
8354
- if (now === committed) {
8035
+ if (now === this.#committed) {
8355
8036
  return;
8356
8037
  }
8357
- committed = now;
8038
+ this.#committed = now;
8358
8039
  this._notifyChange();
8359
8040
  };
8360
8041
  control.addEventListener('focus', () => {
8361
- committed = JSON.stringify(this.value);
8042
+ this.#committed = JSON.stringify(this.value);
8362
8043
  });
8363
8044
  control.addEventListener('keydown', (/** @type any */ evt) => {
8364
8045
  if (evt.key === 'Enter' && !evt.isComposing) {
@@ -8382,14 +8063,18 @@ var fml = (function (exports) {
8382
8063
  * `v-type="number"`, where text that does not decode is answered as it is.
8383
8064
  * Writing `null`, `undefined` or `''` empties the control; anything else is
8384
8065
  * written as its string, replacing whatever was being typed, as a native
8385
- * control's value does. Answers a `string`, a `number` or `null`; typed
8386
- * `any` because subclasses answer other values.
8066
+ * control's value does, and is not an edit: a date or time control that
8067
+ * has the focus reports no `change` for it when it is left. Answers a
8068
+ * `string`, a `number` or `null`; typed `any` because subclasses answer
8069
+ * other values. Before the render the same shaping reads the value last
8070
+ * written, or the `value` attribute, as its text, and a write is held for
8071
+ * the render to apply.
8387
8072
  * @type {any}
8388
8073
  */
8389
8074
  get value() {
8390
8075
  const uppercase = this.declared('uppercase');
8391
8076
  const trim = this.declared('trim');
8392
- const v = this._input.value;
8077
+ const v = this._input ? this._input.value : `${this._heldValue() ?? ''}`;
8393
8078
  const uppercased = uppercase ? v.toUpperCase() : v;
8394
8079
  const trimmed = trim ? uppercased.trim() : uppercased;
8395
8080
  if (trimmed === '') {
@@ -8403,7 +8088,12 @@ var fml = (function (exports) {
8403
8088
  return normalized;
8404
8089
  }
8405
8090
  set value(value) {
8091
+ if (!this._input) {
8092
+ this._holdValue(value);
8093
+ return;
8094
+ }
8406
8095
  this._input.value = value === '' || value === undefined || value === null ? '' : `${value}`;
8096
+ this.#committed = JSON.stringify(this.value);
8407
8097
  }
8408
8098
  /**
8409
8099
  * The control's placeholder, `null` when there is none. The control always
@@ -8426,6 +8116,20 @@ var fml = (function (exports) {
8426
8116
 
8427
8117
  const blankAsNull = (v) => (v === '' ? null : v);
8428
8118
 
8119
+ /**
8120
+ * The local midnight of the yyyy-mm-dd date a text names, taking a year below
8121
+ * 100 as it is and refusing a day its month does not have.
8122
+ * @param {string} text
8123
+ * @returns {Date} an invalid date when the text names no date
8124
+ */
8125
+ const localMidnight = (text) => {
8126
+ const [y, m, d] = text.split('-').map(Number);
8127
+ const date = new Date(0);
8128
+ date.setFullYear(y, m - 1, d);
8129
+ date.setHours(0, 0, 0, 0);
8130
+ return date.getFullYear() === y && date.getMonth() === m - 1 && date.getDate() === d ? date : new Date(Number.NaN);
8131
+ };
8132
+
8429
8133
  /**
8430
8134
  * Formats the yyyy-mm-dd date in its content as a numeric date, in the locale
8431
8135
  * its `locale` attribute names, else the page's, else the platform default.
@@ -8435,10 +8139,8 @@ var fml = (function (exports) {
8435
8139
  class LocalDate extends ParsedElement {
8436
8140
  static attributes = ['locale', 'default'];
8437
8141
  render() {
8438
- const content = this.textContent.trim();
8439
- const [y, m, d] = content.split('-').map(Number);
8440
- const parsed = content === '' ? null : new Date(y, m - 1, d);
8441
- if (parsed === null || Number.isNaN(parsed.getTime())) {
8142
+ const parsed = localMidnight(this.textContent.trim());
8143
+ if (Number.isNaN(parsed.getTime())) {
8442
8144
  this.replaceChildren(this.declared('default') ?? '');
8443
8145
  return;
8444
8146
  }
@@ -8477,7 +8179,7 @@ var fml = (function (exports) {
8477
8179
  );
8478
8180
  }
8479
8181
  static #parse(v) {
8480
- return /^\d{4}-\d{2}-\d{2}$/.test(v) ? new Date(`${v}T00:00:00`) : new Date(v);
8182
+ return /^\d{4}-\d{2}-\d{2}$/.test(v) ? localMidnight(v) : new Date(v);
8481
8183
  }
8482
8184
  /**
8483
8185
  * Converts an ISO instant to the `yyyy-mm-ddThh:mm:ss.sss` wall clock time
@@ -8664,14 +8366,24 @@ var fml = (function (exports) {
8664
8366
  return 'datetime-local';
8665
8367
  }
8666
8368
  /**
8667
- * The entered time as a UTC ISO instant.
8369
+ * The entered time as a UTC ISO instant. Before the render it answers the
8370
+ * value last written, or the `value` attribute, as the rendered field
8371
+ * would, and a write is held for the render to apply.
8668
8372
  * @returns {string|null} null when empty or when the input holds text that does not parse
8669
8373
  */
8670
8374
  get value() {
8375
+ if (!this._input) {
8376
+ const held = this._heldValue();
8377
+ return Instant.localToIso(held ? Instant.isoToLocal(held) : '');
8378
+ }
8671
8379
  return Instant.localToIso(this._input.value);
8672
8380
  }
8673
8381
  /** @param {string|null|undefined} v an ISO instant; a falsy value empties the input */
8674
8382
  set value(v) {
8383
+ if (!this._input) {
8384
+ this._holdValue(v);
8385
+ return;
8386
+ }
8675
8387
  super.value = v ? Instant.isoToLocal(v) : '';
8676
8388
  }
8677
8389
  /**
@@ -8851,9 +8563,14 @@ var fml = (function (exports) {
8851
8563
  this.files = InputFile.list(files);
8852
8564
  this._notifyChange();
8853
8565
  });
8854
- this._input.addEventListener('change', (e) => {
8855
- this.#update();
8856
- });
8566
+ // capture runs before the base listener notifying change, so the event carries the constrained files
8567
+ this._input.addEventListener(
8568
+ 'change',
8569
+ () => {
8570
+ this.#update();
8571
+ },
8572
+ { capture: true },
8573
+ );
8857
8574
  return { ...pieces, freeze: this.#group };
8858
8575
  }
8859
8576
  #update() {
@@ -8960,7 +8677,7 @@ var fml = (function (exports) {
8960
8677
  * @returns {boolean}
8961
8678
  */
8962
8679
  get multiple() {
8963
- return this._input.multiple;
8680
+ return this._input ? this._input.multiple : this.declared('multiple');
8964
8681
  }
8965
8682
  /** @param {boolean} v */
8966
8683
  set multiple(v) {
@@ -8968,11 +8685,11 @@ var fml = (function (exports) {
8968
8685
  this.reflectTo('multiple', v);
8969
8686
  }
8970
8687
  /**
8971
- * The selected files, after the constraints.
8688
+ * The selected files, after the constraints; none before the render.
8972
8689
  * @returns {FileList}
8973
8690
  */
8974
8691
  get files() {
8975
- return this._input.files;
8692
+ return this._input ? this._input.files : InputFile.list();
8976
8693
  }
8977
8694
  /**
8978
8695
  * Replaces the selection and runs the constraints over it, refreshing the
@@ -8999,7 +8716,7 @@ var fml = (function (exports) {
8999
8716
  }
9000
8717
  /**
9001
8718
  * The names of the selected files: an array when `multiple`, otherwise the
9002
- * one name or null.
8719
+ * one name or null. Before the render no file is selected yet.
9003
8720
  * @returns {string[]|string|null}
9004
8721
  */
9005
8722
  get value() {
@@ -9008,11 +8725,12 @@ var fml = (function (exports) {
9008
8725
  }
9009
8726
  /**
9010
8727
  * Empties the selection for a falsy value and ignores any other, since a
9011
- * file name cannot select a file.
8728
+ * file name cannot select a file. Before the render there is nothing to
8729
+ * empty, so it does nothing.
9012
8730
  * @param {any} v
9013
8731
  */
9014
8732
  set value(v) {
9015
- if (v) {
8733
+ if (v || !this._input) {
9016
8734
  return;
9017
8735
  }
9018
8736
  this.files = InputFile.list();
@@ -9296,7 +9014,8 @@ var fml = (function (exports) {
9296
9014
  * which light dismiss then closes with no script of your own. The popover
9297
9015
  * is given the generated id when it has none. A `button` or `input`
9298
9016
  * invoker gets a `popovertarget` naming it; any other element toggles it
9299
- * on click and on the Enter and Space keys
9017
+ * on click and on the Enter and Space keys; a click on it while the
9018
+ * popover is open closes the popover rather than opening it again
9300
9019
  * @param {boolean} [options.expanded] sets the invoker's `aria-expanded` to
9301
9020
  * `false` at once and keeps it in step with the popover's `toggle` events
9302
9021
  * @param {boolean} [options.stretch] in the script placement, sizes the
@@ -9320,7 +9039,21 @@ var fml = (function (exports) {
9320
9039
  if (invoker.localName === 'button' || invoker.localName === 'input') {
9321
9040
  invoker.setAttribute('popovertarget', popover.id);
9322
9041
  } else {
9323
- invoker.addEventListener('click', () => popover.togglePopover());
9042
+ let pressedOpen = false;
9043
+ invoker.addEventListener(
9044
+ 'pointerdown',
9045
+ () => {
9046
+ pressedOpen = popover.matches(':popover-open');
9047
+ },
9048
+ true,
9049
+ );
9050
+ invoker.addEventListener('click', () => {
9051
+ const dismissed = pressedOpen && !popover.matches(':popover-open');
9052
+ pressedOpen = false;
9053
+ if (!dismissed) {
9054
+ popover.togglePopover();
9055
+ }
9056
+ });
9324
9057
  invoker.addEventListener('keydown', (/** @type any */ evt) => {
9325
9058
  if (evt.key !== 'Enter' && evt.key !== ' ') {
9326
9059
  return;
@@ -9422,7 +9155,7 @@ var fml = (function (exports) {
9422
9155
  * @typedef {{ request(method: string, url: string): any }} SelectHttpClient
9423
9156
  */
9424
9157
 
9425
- const byKeys = (entries, keys) => entries.filter(({ key }) => keys.some((r) => r == key));
9158
+ const byKeys = (entries, keys) => entries.filter(({ key }) => keys.some((r) => String(r) === String(key)));
9426
9159
  const byLabel = (entries, needle) =>
9427
9160
  entries.filter(({ label }) => (label ?? '').toLowerCase().includes(needle?.toLowerCase() ?? ''));
9428
9161
 
@@ -9467,7 +9200,8 @@ var fml = (function (exports) {
9467
9200
  await this.#ensureFetched();
9468
9201
  }
9469
9202
  /**
9470
- * The entries whose key loosely equals one of the keys, in vocabulary order.
9203
+ * The entries whose key reads as the same text as one of the keys, in
9204
+ * vocabulary order.
9471
9205
  * @param {...any} keys
9472
9206
  * @returns {Promise<SelectEntry[]>}
9473
9207
  * @throws when the fetch fails, or when an invalidation supersedes it
@@ -9609,7 +9343,8 @@ var fml = (function (exports) {
9609
9343
  */
9610
9344
  async invalidate() {}
9611
9345
  /**
9612
- * The entries whose key loosely equals one of the keys, in vocabulary order.
9346
+ * The entries whose key reads as the same text as one of the keys, in
9347
+ * vocabulary order.
9613
9348
  * @param {...any} keys
9614
9349
  * @returns {SelectEntry[]}
9615
9350
  */
@@ -9828,11 +9563,10 @@ var fml = (function (exports) {
9828
9563
  this.replaceChildren(fragment);
9829
9564
  }
9830
9565
  #selected() {
9831
- return (
9832
- this.#menu?.querySelector('[selected]:not([aria-disabled="true"])') ??
9833
- this.#menu?.querySelector('li:not([aria-disabled="true"])') ??
9834
- null
9835
- );
9566
+ if (!this.#menu || this.#menu.hidden) {
9567
+ return null;
9568
+ }
9569
+ return this.#menu.querySelector('li[selected]') ?? this.#menu.querySelector('li:not([aria-disabled="true"])');
9836
9570
  }
9837
9571
  #highlight(li) {
9838
9572
  if (!li) {
@@ -9851,11 +9585,13 @@ var fml = (function (exports) {
9851
9585
  }
9852
9586
  /**
9853
9587
  * Picks the highlighted row, or the first enabled one when none is: hides
9854
- * the dropdown and dispatches `change`. Does nothing when no row is enabled.
9588
+ * the dropdown and dispatches `change`. Does nothing when the highlighted
9589
+ * row is disabled, when no row is enabled, or while a search is loading
9590
+ * and the rows are hidden.
9855
9591
  */
9856
9592
  acceptSelection() {
9857
9593
  const selected = this.#selected();
9858
- if (!selected) {
9594
+ if (!selected || selected.matches('[aria-disabled="true"]')) {
9859
9595
  return;
9860
9596
  }
9861
9597
  this.#change(selected);
@@ -9864,7 +9600,7 @@ var fml = (function (exports) {
9864
9600
  * Renders the entries as rows and highlights the first one whose key is
9865
9601
  * picked, else the row the template marked `selected`, else the first
9866
9602
  * enabled row. A row is marked `picked` and
9867
- * `aria-selected="true"` when its key loosely equals one of the keys, and
9603
+ * `aria-selected="true"` when its key reads as the same text as one of the keys, and
9868
9604
  * `aria-disabled="true"` when its `metadata.disabled` is truthy, titled with
9869
9605
  * `metadata.reason`. No entries shows the empty state instead of the menu.
9870
9606
  * @param {SelectEntry[]} values
@@ -9880,7 +9616,7 @@ var fml = (function (exports) {
9880
9616
  this.#optionstemplate.withOverlay(data).renderTo(this.#menu);
9881
9617
  for (const [index, li] of [...this.#menu.children].entries()) {
9882
9618
  const entry = values[index];
9883
- const picked = keys.some((r) => r == entry?.key);
9619
+ const picked = keys.some((r) => String(r) === String(entry?.key));
9884
9620
  li.toggleAttribute('picked', picked);
9885
9621
  li.setAttribute('aria-selected', picked ? 'true' : 'false');
9886
9622
  const disabled = !!entry?.metadata?.disabled;
@@ -9897,8 +9633,13 @@ var fml = (function (exports) {
9897
9633
  }
9898
9634
  this.#empty.toggleAttribute('hidden', values.length !== 0);
9899
9635
  this.#menu.toggleAttribute('hidden', values.length === 0);
9900
- const current = values.findIndex(({ key }) => keys.some((r) => r == key));
9901
- this.#highlight(current >= 0 ? this.#menu.children[current] : this.#selected());
9636
+ const current = values.findIndex(({ key }) => keys.some((r) => String(r) === String(key)));
9637
+ this.#highlight(
9638
+ current >= 0
9639
+ ? this.#menu.children[current]
9640
+ : (this.#menu.querySelector('li[selected]:not([aria-disabled="true"])') ??
9641
+ this.#menu.querySelector('li:not([aria-disabled="true"])')),
9642
+ );
9902
9643
  }
9903
9644
  #change(target) {
9904
9645
  const index = target.getAttribute('value');
@@ -9972,7 +9713,8 @@ var fml = (function (exports) {
9972
9713
  }
9973
9714
  /**
9974
9715
  * Moves the highlight to the next or previous enabled row when the dropdown
9975
- * is shown, staying put at the edge, and shows it otherwise.
9716
+ * is shown, staying put at the edge and while a search is loading, and
9717
+ * shows it otherwise.
9976
9718
  * @param {boolean} forward
9977
9719
  * @param {() => SelectEntry[]|Promise<SelectEntry[]>} loader used only to show
9978
9720
  * @param {any[]} [keys] the keys currently selected, used only to show
@@ -10000,10 +9742,14 @@ var fml = (function (exports) {
10000
9742
  return null;
10001
9743
  }
10002
9744
  /**
10003
- * Highlights the first enabled row, or the last one.
9745
+ * Highlights the first enabled row, or the last one. Does nothing while a
9746
+ * search is loading and the rows are hidden.
10004
9747
  * @param {boolean} first
10005
9748
  */
10006
9749
  jump(first) {
9750
+ if (this.#menu.hidden) {
9751
+ return;
9752
+ }
10007
9753
  const edge = first ? this.#menu.firstElementChild : this.#menu.lastElementChild;
10008
9754
  const target = this.#walk(edge, first);
10009
9755
  if (target) {
@@ -10013,6 +9759,7 @@ var fml = (function (exports) {
10013
9759
  /**
10014
9760
  * Moves the highlight by as many enabled rows as the menu shows at once,
10015
9761
  * one when that cannot be measured, stopping at the last enabled row.
9762
+ * Does nothing while a search is loading.
10016
9763
  * @param {boolean} forward
10017
9764
  */
10018
9765
  page(forward) {
@@ -10137,6 +9884,7 @@ var fml = (function (exports) {
10137
9884
  #control;
10138
9885
  #ddmenu;
10139
9886
  #input;
9887
+ #label;
10140
9888
  #items;
10141
9889
  #itemstemplate;
10142
9890
  #multiple;
@@ -10161,6 +9909,7 @@ var fml = (function (exports) {
10161
9909
  });
10162
9910
  const fragment = this.template().withOverlay({ slots, name }).render();
10163
9911
  this.#input = fragment.querySelector('ful-control > input');
9912
+ this.#label = fragment.querySelector('label');
10164
9913
  this.#items = fragment.querySelector('ful-item-list');
10165
9914
  this.#itemstemplate =
10166
9915
  slots.items && !Fragments.isBlank(slots.items) ? Templates.fromFragment(slots.items) : null;
@@ -10192,16 +9941,18 @@ var fml = (function (exports) {
10192
9941
  fragment,
10193
9942
  control: this.#input,
10194
9943
  error: fragment.querySelector('ful-field-error'),
10195
- label: fragment.querySelector('label'),
9944
+ label: this.#label,
10196
9945
  };
10197
9946
  }
10198
9947
  /**
10199
9948
  * Pointer interaction: the element toggles the dropdown, the item list's
10200
- * remove buttons and the control's badges drop their entry.
9949
+ * remove buttons and the control's badges drop their entry. A click on the
9950
+ * label is left to the click the browser forwards to the input, which
9951
+ * toggles once.
10201
9952
  */
10202
9953
  #wireChrome() {
10203
9954
  this.addEventListener('click', (/** @type any */ e) => {
10204
- if (!this._interactive()) {
9955
+ if (!this._interactive() || this.#label.contains(e.target)) {
10205
9956
  return;
10206
9957
  }
10207
9958
  const elsewhere = e.target.closest('button, [role="button"], a[href], input, select, textarea');
@@ -10209,6 +9960,7 @@ var fml = (function (exports) {
10209
9960
  return;
10210
9961
  }
10211
9962
  if (this.#ddmenu.shown) {
9963
+ this.#abortdload();
10212
9964
  this.#close();
10213
9965
  return;
10214
9966
  }
@@ -10291,6 +10043,7 @@ var fml = (function (exports) {
10291
10043
  #wireSelection() {
10292
10044
  this.#ddmenu.addEventListener('change', (e) => {
10293
10045
  e.stopPropagation();
10046
+ this.#abortdload();
10294
10047
  if (!this._interactive()) {
10295
10048
  this.#close();
10296
10049
  return;
@@ -10325,21 +10078,25 @@ var fml = (function (exports) {
10325
10078
  * another control needs when that control changes. A key the loader no
10326
10079
  * longer knows is dropped from the selection, so a value invalidated by the
10327
10080
  * change does not survive it, and one it still knows keeps its place with a
10328
- * fresh label. The badges and items follow, and no `change` is dispatched.
10081
+ * fresh label. The badges and items follow, an open dropdown runs its
10082
+ * search again, and no `change` is dispatched.
10329
10083
  *
10330
10084
  * Where the vocabulary lives at a different address, write `src` or call
10331
10085
  * `reconfigure`, which build the loader for the new url and reload.
10332
10086
  * @returns {Promise<void>}
10333
- * @throws what the loader's invalidate, prefetch or key lookup throws
10087
+ * @throws what the loader's invalidate, prefetch, key lookup or search
10088
+ * throws
10334
10089
  */
10335
10090
  async reload() {
10336
10091
  await this.#loader.invalidate?.();
10337
10092
  await this.#loader.prefetch?.();
10338
10093
  const keys = [...this.#values.keys()];
10339
- if (keys.length === 0) {
10340
- return;
10094
+ if (keys.length !== 0) {
10095
+ await this.#resolve(keys, this.#assignments.take());
10096
+ }
10097
+ if (this.#ddmenu.shown) {
10098
+ await this.#open();
10341
10099
  }
10342
- await this.#resolve(keys, this.#assignments.take());
10343
10100
  }
10344
10101
  /**
10345
10102
  * The url the loader asks for the vocabulary, reflected as the `src`
@@ -10530,6 +10287,7 @@ var fml = (function (exports) {
10530
10287
  return;
10531
10288
  }
10532
10289
  e.preventDefault();
10290
+ this.#abortdload();
10533
10291
  this.#editing = false;
10534
10292
  this.#display();
10535
10293
  this.#ddmenu.acceptSelection();
@@ -10554,6 +10312,7 @@ var fml = (function (exports) {
10554
10312
  if (forward && !this.#ddmenu.shown) {
10555
10313
  this.#open();
10556
10314
  } else if (!forward && this.#ddmenu.shown) {
10315
+ this.#abortdload();
10557
10316
  this.#close();
10558
10317
  }
10559
10318
  return;
@@ -10650,27 +10409,30 @@ var fml = (function (exports) {
10650
10409
  }
10651
10410
  /**
10652
10411
  * Selects the keys, coerced by `k-type`: a key, an array of keys, or null or
10653
- * undefined for none. The empty string is a key like any other. The keys
10654
- * are applied at once, each labeled by itself until the loader's `exact`
10412
+ * undefined for none. The empty string is a key like any other, and a
10413
+ * single select keeps only the first key. The keys are applied at once, each labeled by itself until the loader's `exact`
10655
10414
  * answers; a key it does not answer is then dropped, a key removed in the
10656
10415
  * meantime stays removed, and a later assignment wins over the late answer.
10657
10416
  * A failed lookup keeps the keys and surfaces as an unhandled rejection.
10658
10417
  * No `change` is dispatched. A key containing a
10659
10418
  * comma, which the value attribute cannot carry, is kept and warned about
10660
- * once per element.
10419
+ * once per element. Before the render the write is held for the render to
10420
+ * apply, over the `value` attribute, which it leaves alone.
10661
10421
  * @param {any} vs
10662
10422
  */
10663
10423
  set value(vs) {
10664
- const keys = (vs == null ? [] : Array.isArray(vs) ? vs : [vs]).map((k) => this.#coerceKey(k));
10424
+ if (!this.#control) {
10425
+ this._holdValue(vs);
10426
+ return;
10427
+ }
10428
+ const given = (vs == null ? [] : Array.isArray(vs) ? vs : [vs]).map((k) => this.#coerceKey(k));
10429
+ const keys = this.#multiple ? given : given.slice(0, 1);
10665
10430
  if (!this.#warnedComma && keys.some((k) => typeof k === 'string' && k.includes(','))) {
10666
10431
  this.#warnedComma = true;
10667
10432
  console.warn('a ful-select key cannot contain a comma: it is unexpressible in the value attribute', this);
10668
10433
  }
10669
10434
  this.#values = new Map(keys.map((k) => [k, { key: k, label: k, metadata: undefined }]));
10670
10435
  const claim = this.#assignments.take();
10671
- if (!this.#control) {
10672
- return;
10673
- }
10674
10436
  this.#syncBadges();
10675
10437
  if (keys.length === 0) {
10676
10438
  return;
@@ -10697,10 +10459,17 @@ var fml = (function (exports) {
10697
10459
  }
10698
10460
  /**
10699
10461
  * The selected keys, in selection order, for a multiple select; the one
10700
- * key, or null, for a single one.
10462
+ * key, or null, for a single one. Before the render it answers the keys
10463
+ * last written, or the `value` attribute, coerced and cut to one key as the
10464
+ * rendered select would.
10701
10465
  * @returns {any}
10702
10466
  */
10703
10467
  get value() {
10468
+ if (!this.#control) {
10469
+ const held = this._heldValue();
10470
+ const keys = [held ?? []].flat().map((k) => this.#coerceKey(k));
10471
+ return this.multiple ? keys : (keys[0] ?? null);
10472
+ }
10704
10473
  if (this.#multiple) {
10705
10474
  return [...this.#values.keys()];
10706
10475
  }
@@ -10719,20 +10488,60 @@ var fml = (function (exports) {
10719
10488
  }
10720
10489
  return selection[0] ?? null;
10721
10490
  }
10491
+ /**
10492
+ * The field's disabled claim; turning it on while the dropdown is open
10493
+ * closes it and drops a pending search.
10494
+ * @type {boolean}
10495
+ */
10496
+ get disabled() {
10497
+ return super.disabled;
10498
+ }
10499
+ set disabled(v) {
10500
+ super.disabled = v;
10501
+ if (v && this.#ddmenu?.shown) {
10502
+ this.#abortdload();
10503
+ this.#close();
10504
+ }
10505
+ }
10506
+ /**
10507
+ * The field's readonly claim; turning it on while the dropdown is open
10508
+ * closes it and drops a pending search.
10509
+ * @type {boolean}
10510
+ */
10511
+ get readonly() {
10512
+ return super.readonly;
10513
+ }
10514
+ set readonly(v) {
10515
+ super.readonly = v;
10516
+ if (v && this.#ddmenu?.shown) {
10517
+ this.#abortdload();
10518
+ this.#close();
10519
+ }
10520
+ }
10722
10521
  #useItemList;
10723
10522
  /**
10724
10523
  * Whether the select holds several keys: `value` and `entry` answer arrays,
10725
10524
  * the input stays empty and the selection shows as removable badges in the
10726
- * control.
10525
+ * control. Before the render it answers the `multiple` attribute.
10727
10526
  * @returns {boolean}
10728
10527
  */
10729
10528
  get multiple() {
10730
- return this.#multiple;
10529
+ return this.#multiple ?? this.declared('multiple');
10731
10530
  }
10732
- /** @param {boolean} v */
10531
+ /**
10532
+ * Turning it off keeps only the first selected key; either way the badges,
10533
+ * the items and the input follow at once.
10534
+ * @param {boolean} v
10535
+ */
10733
10536
  set multiple(v) {
10734
10537
  this.#multiple = v;
10735
10538
  this.reflectTo('multiple', v);
10539
+ if (!v) {
10540
+ this.#values = new Map([...this.#values].slice(0, 1));
10541
+ }
10542
+ if (this.#control) {
10543
+ this.#syncBadges();
10544
+ }
10736
10545
  }
10737
10546
  /**
10738
10547
  * Whether the selection shows as the `items` list below the control instead
@@ -10754,10 +10563,10 @@ var fml = (function (exports) {
10754
10563
  * a radio input carrying its attributes, labelled by its content; every
10755
10564
  * `input-*` attribute on the group is forwarded onto each radio as well. The
10756
10565
  * default slot is the `<legend>`, and `header` and `footer` slots frame the
10757
- * list. The radios share a name of their own (derived from `name`, or minted
10758
- * when there is none) and carry `form=""`, so the group is the only element
10759
- * the form sees. A radio's native `change` is stopped and republished as the
10760
- * group's own.
10566
+ * list. The radios share a name of their own, minted afresh for each group
10567
+ * (from `name` when there is one) so that same-named groups stay apart, and
10568
+ * carry `form=""`, so the group is the only element the form sees. A radio's
10569
+ * native `change` is stopped and republished as the group's own.
10761
10570
  *
10762
10571
  * The host carries the `radiogroup` role, `aria-readonly`, `aria-required`,
10763
10572
  * `aria-invalid` and the description. The disabled and readonly claims act on
@@ -10802,7 +10611,7 @@ var fml = (function (exports) {
10802
10611
  * `announces` pieces
10803
10612
  */
10804
10613
  _build({ slots }) {
10805
- const name = this.declared('name') ?? Attributes.uid('ful-radiogroup');
10614
+ const name = Attributes.uid(this.declared('name') ?? 'ful-radiogroup');
10806
10615
  const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));
10807
10616
  const inputsAndLabels = radioEls.map((el) => {
10808
10617
  const input = document.createElement('input');
@@ -10840,15 +10649,31 @@ var fml = (function (exports) {
10840
10649
  * The value of the checked radio, `null` when none is. Under
10841
10650
  * `type="boolean"` it answers `true` for a radio whose value is `true` and
10842
10651
  * `false` for any other. Writing a value checks the radio carrying it, and
10843
- * writing `null` or a value no radio carries clears the selection.
10652
+ * writing `null` or a value no radio carries clears the selection. Before
10653
+ * the render it answers the value last written, or the `value` attribute,
10654
+ * when a `ful-radio` carries it, and a write is held for the render to
10655
+ * apply.
10844
10656
  * @type {string | boolean | null}
10845
10657
  */
10846
10658
  get value() {
10659
+ if (!this.#fieldset) {
10660
+ const held = this._heldValue();
10661
+ const radio = held === null ? null : this.querySelector(`ful-radio[value="${CSS.escape(String(held))}"]`);
10662
+ const key = radio?.getAttribute('value') ?? null;
10663
+ if (key === null || this.declared('type') !== 'boolean') {
10664
+ return key;
10665
+ }
10666
+ return key === 'true';
10667
+ }
10847
10668
  /** @type {HTMLInputElement|null} */
10848
10669
  const checked = this.querySelector('input[type=radio]:checked');
10849
10670
  return checked ? (this.#booleanType ? checked.value === 'true' : checked.value) : null;
10850
10671
  }
10851
10672
  set value(value) {
10673
+ if (!this.#fieldset) {
10674
+ this._holdValue(value);
10675
+ return;
10676
+ }
10852
10677
  const radios = this.querySelectorAll(`input[type=radio]`);
10853
10678
  const clear = () => {
10854
10679
  radios.forEach((el) => {
@@ -10918,13 +10743,19 @@ var fml = (function (exports) {
10918
10743
  }
10919
10744
  /**
10920
10745
  * Whether the box is checked. The `value` attribute is read with the `bool`
10921
- * mapper, where only the text `true` means checked.
10746
+ * mapper, where only the text `true` means checked. Before the render it
10747
+ * answers the value last written, or the `value` attribute, and a write is
10748
+ * held for the render to apply.
10922
10749
  * @type {boolean}
10923
10750
  */
10924
10751
  get value() {
10925
- return this.#input.checked;
10752
+ return this.#input ? this.#input.checked : Boolean(this._heldValue());
10926
10753
  }
10927
10754
  set value(value) {
10755
+ if (!this.#input) {
10756
+ this._holdValue(value);
10757
+ return;
10758
+ }
10928
10759
  this.#input.checked = value;
10929
10760
  }
10930
10761
  }
@@ -11274,8 +11105,9 @@ var fml = (function (exports) {
11274
11105
  */
11275
11106
  async load(pageRequest, sortRequest, filterRequest) {
11276
11107
  const rows = this.#sorted(sortRequest);
11277
- const begin = pageRequest.page * pageRequest.size;
11278
- const end = begin + pageRequest.size;
11108
+ const size = Number(pageRequest.size);
11109
+ const begin = pageRequest.page * size;
11110
+ const end = begin + size;
11279
11111
  const page = rows.slice(begin, end);
11280
11112
  const totalElements = rows.length;
11281
11113
  return {
@@ -11408,12 +11240,17 @@ var fml = (function (exports) {
11408
11240
  * for it. Without it the table shows an initial panel until `load`,
11409
11241
  * `reload` or `resetWithFilter` is called.
11410
11242
  *
11411
- * Inside the table a `page:requested` loads that page with the current size,
11243
+ * Inside the table, and not inside a `ful-table` nested in it, a
11244
+ * `page:requested` loads that page with the current size,
11412
11245
  * sort and filters; a `sort:requested` loads the current page with the new
11413
11246
  * sort (none for a `null` order) and, once that load is the one showing, sets
11414
11247
  * the order of the sorter that asked and clears the others; a `submit:success`
11415
11248
  * of the filter form loads the first page with the submitted request as the
11416
- * filters. The loads these start, and the autoload, are not awaited by
11249
+ * filters. The first load goes through the filter form too: `reload`, and so
11250
+ * `autoload`, submits it (see `reload`), so a `submit` listener rewriting
11251
+ * `detail.request` shapes every load alike. The filters a page, a sort or a size change carries are those of
11252
+ * the last load asked for, whether it is still running, loaded or failed, so
11253
+ * they are the ones the filter form shows. The loads these start, and the autoload, are not awaited by
11417
11254
  * anything: a failure shows the error panel and its rejection is unhandled.
11418
11255
  */
11419
11256
  class Table extends ParsedElement {
@@ -11500,6 +11337,14 @@ var fml = (function (exports) {
11500
11337
  #latestRequest = { pageRequest: { page: 0, size: 10 }, sortRequest: null, filterRequest: {} };
11501
11338
  /** whether a load has been asked for, by autoload or by a caller */
11502
11339
  #loadRequested = false;
11340
+ /** the filters of the last load asked for, which page, sort and size changes carry */
11341
+ #requestedFilters = {};
11342
+ /** @type {any} the `ful-form` wrapping the `filters` slot, if any */
11343
+ #filters = null;
11344
+ /** whether a load has shown its rows, after which `reload` repeats it */
11345
+ #loaded = false;
11346
+ /** @type {Promise<void>|null} the load the last `submit:success` of the filter form started */
11347
+ #filterLoad = null;
11503
11348
  #loads = new Claims();
11504
11349
  /** @type {{ src: string|null, method: string|null }} */
11505
11350
  #builtFrom = { src: null, method: null };
@@ -11521,19 +11366,21 @@ var fml = (function (exports) {
11521
11366
  *
11522
11367
  * The reload is not awaited: a failure shows the error panel and its
11523
11368
  * rejection is unhandled.
11524
- * @param {number|null|undefined} value absent or null is the default of
11525
- * ten, so removing the attribute restores it
11369
+ * @param {number|string|null|undefined} value a number or a string of
11370
+ * one, such as a select's value; absent or null is the default of ten,
11371
+ * so removing the attribute restores it, and a value that is not a
11372
+ * number is ignored
11526
11373
  */
11527
11374
  set pageSize(value) {
11528
- const size = value ?? 10;
11529
- if (size === this.#latestRequest.pageRequest.size) {
11375
+ const size = Number(value ?? 10);
11376
+ if (Number.isNaN(size) || size === this.#latestRequest.pageRequest.size) {
11530
11377
  return;
11531
11378
  }
11532
11379
  this.#latestRequest = { ...this.#latestRequest, pageRequest: { page: 0, size } };
11533
11380
  if (!this.#loadRequested) {
11534
11381
  return;
11535
11382
  }
11536
- this.reload();
11383
+ this.load(this.#latestRequest.pageRequest, this.#latestRequest.sortRequest, this.#requestedFilters);
11537
11384
  }
11538
11385
  /**
11539
11386
  * The url the loader asks for rows, reflected as the `src` attribute.
@@ -11653,15 +11500,24 @@ var fml = (function (exports) {
11653
11500
  sortRequest: schema.sort,
11654
11501
  filterRequest: maybeForm?.values ?? {},
11655
11502
  };
11503
+ this.#requestedFilters = this.#latestRequest.filterRequest;
11504
+ this.#filters = maybeForm;
11656
11505
  maybeForm?.addEventListener('submit:success', async (evt) => {
11657
- await this.#loadPage(0, evt.detail.request);
11506
+ this.#filterLoad = this.#loadPage(0, evt.detail.request);
11507
+ await this.#filterLoad;
11658
11508
  });
11659
11509
  this.addEventListener('page:requested', async (/** @type any */ e) => {
11660
- await this.#loadPage(e.detail.value, this.#latestRequest.filterRequest);
11510
+ if (e.target.closest('ful-table') !== this) {
11511
+ return;
11512
+ }
11513
+ await this.#loadPage(e.detail.value, this.#requestedFilters);
11661
11514
  });
11662
11515
  this.addEventListener('sort:requested', async (/** @type any */ e) => {
11516
+ if (e.target.closest('ful-table') !== this) {
11517
+ return;
11518
+ }
11663
11519
  const sortRequest = e.detail.value.order ? e.detail.value : null;
11664
- await this.load(this.#latestRequest.pageRequest, sortRequest, this.#latestRequest.filterRequest);
11520
+ await this.load(this.#latestRequest.pageRequest, sortRequest, this.#requestedFilters);
11665
11521
  if (this.#latestRequest.sortRequest !== sortRequest) {
11666
11522
  return;
11667
11523
  }
@@ -11677,12 +11533,23 @@ var fml = (function (exports) {
11677
11533
 
11678
11534
  /**
11679
11535
  * Loads the last request that loaded, or, before any has, the first page
11680
- * with the declared size and sort and the values of the filters slot. A
11681
- * size written through `pageSize` since then replaces the page with the
11682
- * first one at that size.
11536
+ * with the declared size and sort. A size written through `pageSize` since
11537
+ * then replaces the page with the first one at that size.
11538
+ *
11539
+ * Before any load has loaded, a table with a `filters` slot submits its
11540
+ * filter form instead, so the first request goes through the same
11541
+ * `submit` listeners as the later ones, and the load its `submit:success`
11542
+ * starts is the one awaited. A filter submit that is cancelled, fails or
11543
+ * is dropped for one in flight loads nothing, and the promise resolves.
11683
11544
  * @returns {Promise<void>} as `load`
11684
11545
  */
11685
11546
  async reload() {
11547
+ if (this.#filters && !this.#loaded) {
11548
+ if (await this.#filters.submit()) {
11549
+ await this.#filterLoad;
11550
+ }
11551
+ return;
11552
+ }
11686
11553
  return await this.load(
11687
11554
  this.#latestRequest.pageRequest,
11688
11555
  this.#latestRequest.sortRequest,
@@ -11690,7 +11557,9 @@ var fml = (function (exports) {
11690
11557
  );
11691
11558
  }
11692
11559
  /**
11693
- * Asks the loader for a page and shows it.
11560
+ * Asks the loader for a page and shows it. Its filters are, from now on,
11561
+ * the ones a page, a sort or a size change carries, even while it runs
11562
+ * or once it failed.
11694
11563
  *
11695
11564
  * While the load runs the table carries `aria-busy="true"`, and the rows
11696
11565
  * already shown stay; the spinner panel shows only when there are none.
@@ -11698,7 +11567,8 @@ var fml = (function (exports) {
11698
11567
  * panel shows for an answer with no rows (the `empty` slot rendered with
11699
11568
  * `schema`, `pageRequest`, `filterRequest` and `pageResponse` in scope),
11700
11569
  * the request becomes the one
11701
- * `reload` repeats, `aria-busy` is removed and `load:success` is
11570
+ * `reload` repeats; once the elements of the rows and of the empty panel
11571
+ * have rendered, `aria-busy` is removed and `load:success` is
11702
11572
  * dispatched (bubbling, not cancelable) with `detail` set to
11703
11573
  * `{ pageRequest, sortRequest, filterRequest, response }`. A page beyond
11704
11574
  * the last one the answer reports is not shown: the last page is loaded
@@ -11712,7 +11582,9 @@ var fml = (function (exports) {
11712
11582
  * returned promise rejects with the same error.
11713
11583
  *
11714
11584
  * A load started after this one supersedes it: when this one's answer or
11715
- * failure arrives it changes nothing, dispatches nothing and resolves.
11585
+ * failure arrives it changes nothing, dispatches nothing and resolves;
11586
+ * superseded while its rows render, it leaves them to the newer load and
11587
+ * dispatches nothing.
11716
11588
  * @param {TablePageRequest} pageRequest
11717
11589
  * @param {TableSortRequest|null} sortRequest
11718
11590
  * @param {Record<string, any>} filterRequest
@@ -11721,6 +11593,7 @@ var fml = (function (exports) {
11721
11593
  */
11722
11594
  async load(pageRequest, sortRequest, filterRequest) {
11723
11595
  this.#loadRequested = true;
11596
+ this.#requestedFilters = filterRequest;
11724
11597
  const claim = this.#loads.take();
11725
11598
  this.#loading.toggleAttribute('hidden', this.#body.childElementCount > 0);
11726
11599
  this.#feedback.setAttribute('hidden', '');
@@ -11736,7 +11609,16 @@ var fml = (function (exports) {
11736
11609
  lastPage = Math.max(0, Math.ceil(pageResponse.size / pageRequest.size) - 1);
11737
11610
  if (pageRequest.page <= lastPage) {
11738
11611
  this.#latestRequest = { pageRequest, sortRequest, filterRequest };
11612
+ this.#loaded = true;
11739
11613
  this.#update(pageRequest, sortRequest, filterRequest, pageResponse);
11614
+ // a row element whose render fails leaves the rows shown: it does not fail the load
11615
+ await Promise.all([
11616
+ Rendering.waitForChildren(this.#body),
11617
+ Rendering.waitForChildren(this.#empty),
11618
+ ]).catch(() => undefined);
11619
+ if (claim.stale) {
11620
+ return;
11621
+ }
11740
11622
  this.removeAttribute('aria-busy');
11741
11623
  this.dispatchEvent(
11742
11624
  new CustomEvent('load:success', {
@@ -12336,7 +12218,8 @@ var fml = (function (exports) {
12336
12218
  * The operators the menu offers, narrowed to the vocabulary: an empty list,
12337
12219
  * or one where no name is known, offers all of it. A single operator pins
12338
12220
  * the button, and an assigned tuple then carries that operator whatever it
12339
- * names. An assignment made before the upgrade is held narrowed and
12221
+ * names. When the operator shown leaves the list, the first listed one is
12222
+ * shown. An assignment made before the upgrade is held narrowed and
12340
12223
  * answered back until the render, when the `operators` attribute is applied
12341
12224
  * over it, an absent attribute meaning the whole vocabulary. Assignments are
12342
12225
  * ignored while the `operator` attribute fixes the operator.
@@ -12355,27 +12238,61 @@ var fml = (function (exports) {
12355
12238
  return;
12356
12239
  }
12357
12240
  this._operator.allowed = declared;
12358
- this._syncBetween();
12241
+ if (this._operator.value !== null) {
12242
+ this._showOperator(this._operator.preferring(this._operator.value));
12243
+ }
12359
12244
  }
12360
12245
  /**
12361
12246
  * The filter's tuple, `[operator, operand]` or `[operator, from, to]` for
12362
12247
  * BETWEEN, each operand converted by `_serialize` (an ISO instant for the
12363
12248
  * instant filter). Null while any operand the operator uses is empty.
12249
+ * Before the render it answers the tuple last written, or the `value`
12250
+ * attribute, as the rendered filter would show it.
12364
12251
  * @returns {any[]|null}
12365
12252
  */
12366
12253
  get value() {
12254
+ if (!this._operator) {
12255
+ return this._shownTuple(this._heldValue());
12256
+ }
12367
12257
  return this._tuple();
12368
12258
  }
12369
12259
  /**
12370
- * Shows a tuple: the operator it names, unless a pinned or fixed operator
12371
- * replaces it, and its operands, an operand missing from a shorter tuple
12260
+ * Shows a tuple: the operator it names, or the first allowed one where the
12261
+ * whitelist, a pin or a fixed operator does not allow it, and its operands, an operand missing from a shorter tuple
12372
12262
  * leaving its input empty. Null or undefined empties both operands and
12373
- * keeps the operator.
12263
+ * keeps the operator. Before the render the tuple is held for the render
12264
+ * to apply, over the `value` attribute, which it leaves alone.
12374
12265
  * @param {any[]|null|undefined} v
12375
12266
  */
12376
12267
  set value(v) {
12268
+ if (!this._operator) {
12269
+ this._holdValue(v);
12270
+ return;
12271
+ }
12377
12272
  this._applyTuple(v);
12378
12273
  }
12274
+ /**
12275
+ * The tuple `_tuple` answers once `_applyTuple(v)` has shown `v`, read
12276
+ * from the declared `operator` and `operators` in place of the menu.
12277
+ * @param {any[]|null|undefined} v
12278
+ * @returns {any[]|null}
12279
+ */
12280
+ _shownTuple(v) {
12281
+ if (v == null) {
12282
+ return null;
12283
+ }
12284
+ const [declared, ...values] = v;
12285
+ const fixed = this.declared('operator');
12286
+ const known = this._vocabulary().includes(fixed);
12287
+ const allowed =
12288
+ fixed === null
12289
+ ? ChoiceButton.narrow(this.declared('operators'), this._vocabulary())
12290
+ : [known ? fixed : this._defaultOperator()];
12291
+ const operator = allowed.includes(declared) ? declared : allowed[0];
12292
+ const shown = [values[0], values[1]].map((o) => `${o ? this._deserialize(o) : (o ?? '')}`);
12293
+ const operands = operator === 'BETWEEN' ? shown : shown.slice(0, 1);
12294
+ return operands.some((o) => o === '') ? null : [operator, ...operands.map((o) => this._serialize(o))];
12295
+ }
12379
12296
  _tuple() {
12380
12297
  const operator = this._operator.value;
12381
12298
  const values = this.#operands();
@@ -12388,8 +12305,7 @@ var fml = (function (exports) {
12388
12305
  return;
12389
12306
  }
12390
12307
  const [declared, ...values] = v;
12391
- const operator = this._operator.pinned ? this._operator.allowed[0] : declared;
12392
- this._showOperator(operator);
12308
+ this._showOperator(this._operator.preferring(declared));
12393
12309
  this._value1.value = values[0] ? this._deserialize(values[0]) : (values[0] ?? '');
12394
12310
  this._value2.value = values[1] ? this._deserialize(values[1]) : (values[1] ?? '');
12395
12311
  }
@@ -12406,10 +12322,13 @@ var fml = (function (exports) {
12406
12322
  * them rather than as serialized: a date filter describes what is in its
12407
12323
  * control, not the ISO string it sends. Null while every one of those
12408
12324
  * operands is empty, so a BETWEEN with one bound answers that bound while
12409
- * its value is still null.
12325
+ * its value is still null, and before the filter has rendered.
12410
12326
  * @returns {FilterCriterion|null}
12411
12327
  */
12412
12328
  get criterion() {
12329
+ if (!this._operator) {
12330
+ return null;
12331
+ }
12413
12332
  return asCriterion(labelTextOf(this), this._operator.value, this.#operands());
12414
12333
  }
12415
12334
  #operands() {
@@ -12569,10 +12488,26 @@ var fml = (function (exports) {
12569
12488
  }
12570
12489
  /**
12571
12490
  * The tuple with the sensitivity after the operator, `[operator,
12572
- * sensitivity, ...operands]`. Null while any operand the operator uses is empty.
12491
+ * sensitivity, ...operands]`. Null while any operand the operator uses is
12492
+ * empty. Before the render it answers the tuple last written, or the
12493
+ * `value` attribute, as the rendered filter would show it.
12573
12494
  * @returns {any[]|null}
12574
12495
  */
12575
12496
  get value() {
12497
+ if (!this._sensitivityButton) {
12498
+ const held = this._heldValue();
12499
+ const tuple = held == null ? null : this._shownTuple([held[0], ...held.slice(2)]);
12500
+ if (tuple === null) {
12501
+ return null;
12502
+ }
12503
+ const fixed = this.declared('sensitivity');
12504
+ const allowed =
12505
+ fixed === null
12506
+ ? ChoiceButton.narrow(this.declared('sensitivities'), SENSITIVITIES)
12507
+ : [SENSITIVITIES.includes(fixed) ? fixed : 'IGNORE_CASE'];
12508
+ const kept = allowed.includes(held[1]) ? held[1] : 'IGNORE_CASE';
12509
+ return [tuple[0], allowed.includes(kept) ? kept : allowed[0], ...tuple.slice(1)];
12510
+ }
12576
12511
  const tuple = this._tuple();
12577
12512
  return tuple == null ? null : [tuple[0], this._sensitivity, ...tuple.slice(1)];
12578
12513
  }
@@ -12580,10 +12515,15 @@ var fml = (function (exports) {
12580
12515
  * Shows a tuple as the compare filter does, reading the sensitivity at
12581
12516
  * index 1. A sensitivity the whitelist does not allow leaves the current
12582
12517
  * one in place. Null or undefined empties the operands and keeps the
12583
- * operator and the sensitivity.
12518
+ * operator and the sensitivity. Before the render the tuple is held, as
12519
+ * on the compare filters.
12584
12520
  * @param {any[]|null|undefined} v
12585
12521
  */
12586
12522
  set value(v) {
12523
+ if (!this._sensitivityButton) {
12524
+ this._holdValue(v);
12525
+ return;
12526
+ }
12587
12527
  if (v == null) {
12588
12528
  this._applyTuple(v);
12589
12529
  return;
@@ -12688,7 +12628,8 @@ var fml = (function (exports) {
12688
12628
  /**
12689
12629
  * The operators the menu offers, narrowed to EQ and NEQ: an empty list, or
12690
12630
  * one where no name is known, offers both, and a single one pins the
12691
- * button. Held before the upgrade and replaced by the `operators` attribute
12631
+ * button. When the operator shown leaves the list, the first listed one is
12632
+ * shown. Held before the upgrade and replaced by the `operators` attribute
12692
12633
  * at the render, as on the compare filters.
12693
12634
  * @returns {string[]|undefined} undefined before the upgrade when nothing was assigned
12694
12635
  */
@@ -12702,30 +12643,49 @@ var fml = (function (exports) {
12702
12643
  return;
12703
12644
  }
12704
12645
  this._operator.allowed = declared;
12646
+ if (this._operator.value !== null) {
12647
+ this._operator.value = this._operator.preferring(this._operator.value);
12648
+ }
12705
12649
  }
12706
12650
  /** @returns {string[]} */
12707
12651
  _vocabulary() {
12708
12652
  return BooleanFilter.OPERATORS;
12709
12653
  }
12710
12654
  /**
12711
- * `[operator, token]`, the token being 'true' or 'false'; null while the value menu is on any.
12655
+ * `[operator, token]`, the token being 'true' or 'false'; null while the
12656
+ * value menu is on any. Before the render it answers the tuple last
12657
+ * written, or the `value` attribute, as the rendered filter would show it.
12712
12658
  * @returns {string[]|null}
12713
12659
  */
12714
12660
  get value() {
12661
+ if (!this._value) {
12662
+ const held = this._heldValue();
12663
+ const token = `${held?.[1] ?? ''}`;
12664
+ if (token === '') {
12665
+ return null;
12666
+ }
12667
+ const allowed = ChoiceButton.narrow(this.declared('operators'), this._vocabulary());
12668
+ return [allowed.includes(held[0]) ? held[0] : allowed[0], token];
12669
+ }
12715
12670
  return this._value.value === '' ? null : [this._operator.value, this._value.value];
12716
12671
  }
12717
12672
  /**
12718
- * Shows a tuple: its operator, unless a pinned operator replaces it, and its
12719
- * token, a missing token meaning any. Null or undefined sets the value menu
12720
- * back to any and keeps the operator.
12673
+ * Shows a tuple: its operator, or the first allowed one where the whitelist
12674
+ * does not allow it, and its token, a missing token meaning any. Null or undefined sets the value menu
12675
+ * back to any and keeps the operator. Before the render the tuple is held,
12676
+ * as on the compare filters.
12721
12677
  * @param {any[]|null|undefined} v
12722
12678
  */
12723
12679
  set value(v) {
12680
+ if (!this._value) {
12681
+ this._holdValue(v);
12682
+ return;
12683
+ }
12724
12684
  if (v == null) {
12725
12685
  this._value.value = '';
12726
12686
  return;
12727
12687
  }
12728
- this._operator.value = this._operator.pinned ? this._operator.allowed[0] : v[0];
12688
+ this._operator.value = this._operator.preferring(v[0]);
12729
12689
  this._value.value = v[1] ?? '';
12730
12690
  }
12731
12691
  /**
@@ -12740,10 +12700,13 @@ var fml = (function (exports) {
12740
12700
  }
12741
12701
  /**
12742
12702
  * The operator and the localized word the value menu shows, not the token.
12743
- * Null while the value menu is on any.
12703
+ * Null while the value menu is on any, and before the filter has rendered.
12744
12704
  * @returns {FilterCriterion|null}
12745
12705
  */
12746
12706
  get criterion() {
12707
+ if (!this._value) {
12708
+ return null;
12709
+ }
12747
12710
  const token = this._value.value;
12748
12711
  return asCriterion(labelTextOf(this), this._operator.value, [token === '' ? '' : booleanValueLabel(token)]);
12749
12712
  }
@@ -12785,7 +12748,8 @@ var fml = (function (exports) {
12785
12748
  * The chosen keys as an array, a single choice included, led by the
12786
12749
  * declared `operator` when there is one. Null while nothing is chosen, so
12787
12750
  * that a table drops the filter instead of sending an empty set that
12788
- * matches nothing.
12751
+ * matches nothing. Before the render it answers the keys the select answers
12752
+ * then.
12789
12753
  * @returns {any[]|null}
12790
12754
  */
12791
12755
  get value() {
@@ -12800,7 +12764,8 @@ var fml = (function (exports) {
12800
12764
  * Selects the keys of an array or a single bare key; a leading element equal
12801
12765
  * to the declared `operator` is dropped first, so the filter takes back what
12802
12766
  * it answered. A single select takes the first key. Null or undefined clears
12803
- * the selection.
12767
+ * the selection. Before the render the keys are held, as the select holds
12768
+ * them.
12804
12769
  * @param {any} v
12805
12770
  */
12806
12771
  set value(v) {
@@ -12813,7 +12778,7 @@ var fml = (function (exports) {
12813
12778
  }
12814
12779
  /**
12815
12780
  * The declared operator, or null, and the labels of the chosen entries. Null
12816
- * while nothing is chosen.
12781
+ * while nothing is chosen, as before the filter has rendered.
12817
12782
  * @returns {FilterCriterion|null}
12818
12783
  */
12819
12784
  get criterion() {
@@ -13109,7 +13074,7 @@ var fml = (function (exports) {
13109
13074
  */
13110
13075
  onSubmitted(answer) {
13111
13076
  this.#section.addEventListener('submit:success', (/** @type any */ e) => {
13112
- if (e.target !== Nodes.queryChildren(this.#section, 'ful-form')) {
13077
+ if (e.target.localName !== 'ful-form' || e.target.parentElement !== this.#section) {
13113
13078
  return;
13114
13079
  }
13115
13080
  answer(e.detail.response);
@@ -13272,10 +13237,7 @@ var fml = (function (exports) {
13272
13237
  <section data-ref="loading" hidden><ful-spinner class="centered" role="status"><span class="ful-sr-only">{{ #l10n:t('spinner.loading') }}</span></ful-spinner></section>
13273
13238
  <section data-ref="error" role="alert" hidden></section>
13274
13239
  <div data-ref="body" class="ful-dialog-body">{{{{ slots.default }}}}</div>
13275
- <footer class="ful-dialog-footer">
13276
- <button type="button" data-ref="acknowledge" data-result="acknowledged" data-tpl-if="!slots.buttons && !closeOnSubmit" data-tpl-aria-label="#l10n:t('dialog.acknowledge')">{{ #l10n:t('dialog.acknowledge') }}</button>
13277
- {{{{ slots.buttons }}}}
13278
- </footer>
13240
+ <footer class="ful-dialog-footer"><button type="button" data-ref="acknowledge" data-result="acknowledged" data-tpl-if="!slots.buttons && !closeOnSubmit" data-tpl-aria-label="#l10n:t('dialog.acknowledge')">{{ #l10n:t('dialog.acknowledge') }}</button>{{{{ slots.buttons }}}}</footer>
13279
13241
  </dialog>
13280
13242
  `;
13281
13243
  #dialog;
@@ -13305,9 +13267,9 @@ var fml = (function (exports) {
13305
13267
  this.#settle(outcome);
13306
13268
  });
13307
13269
  this.#dialog.addEventListener('click', (/** @type any */ e) => {
13308
- const result = e.target.closest('button[data-result]')?.dataset.result;
13309
- if (result !== undefined) {
13310
- this.#dialog.close(result);
13270
+ const button = e.target.closest('button[data-result]');
13271
+ if (button && button.closest('dialog') === this.#dialog) {
13272
+ this.#dialog.close(button.dataset.result);
13311
13273
  }
13312
13274
  });
13313
13275
  if (!requiresAnswer) {
@@ -13378,7 +13340,8 @@ var fml = (function (exports) {
13378
13340
  * the body and `first` true only on the first answered request), so a
13379
13341
  * listener can fill the body. A failed request is painted into the body
13380
13342
  * and does not reject. On a dialog already open nothing is shown or
13381
- * requested, and the call waits for the same ending as the calls before it.
13343
+ * requested, and the call waits for the same ending as the calls before it;
13344
+ * one the page moved while open, which is no longer modal, opens anew.
13382
13345
  * @returns {Promise<DialogOutcome>} resolving on close, or on removal from
13383
13346
  * the document with a dismissal
13384
13347
  */
@@ -13460,6 +13423,10 @@ var fml = (function (exports) {
13460
13423
  }
13461
13424
  /** @returns {boolean} whether this call is the one that opened the modal */
13462
13425
  #show() {
13426
+ //a move in the page takes an open modal out of the top layer; close() would queue a close event answering the next opening
13427
+ if (this.#dialog.open && !this.#dialog.matches(':modal')) {
13428
+ this.#dialog.removeAttribute('open');
13429
+ }
13463
13430
  if (this.#dialog.open) {
13464
13431
  return false;
13465
13432
  }
@@ -13657,9 +13624,9 @@ var fml = (function (exports) {
13657
13624
  this.dismiss('escape');
13658
13625
  });
13659
13626
  this.#dialog.addEventListener('click', (/** @type any */ e) => {
13660
- const result = e.target.closest('button[data-result]')?.dataset.result;
13661
- if (result !== undefined) {
13662
- this.close(result);
13627
+ const button = e.target.closest('button[data-result]');
13628
+ if (button && button.closest('dialog') === this.#dialog) {
13629
+ this.close(button.dataset.result);
13663
13630
  }
13664
13631
  });
13665
13632
  this.#dialog.addEventListener('close', () => {
@@ -13756,9 +13723,11 @@ var fml = (function (exports) {
13756
13723
  * the content section and `first` true only on the first answered request),
13757
13724
  * so a listener can fill the content. A failed request is painted into the
13758
13725
  * content section and does not reject. On a drawer already open nothing is
13759
- * shown or requested, except that one sliding out stops and stays open, and
13760
- * the call waits for the same ending as the calls before it, which is how
13761
- * a caller learns the outcome of the opening an `update()` made.
13726
+ * shown or requested, except that one sliding out stops and stays open,
13727
+ * forgetting the result it was closing with, and the call waits for the
13728
+ * same ending as the calls before it, which is how a caller learns the
13729
+ * outcome of the opening an `update()` made. One the page moved while open,
13730
+ * which is no longer modal, opens anew.
13762
13731
  * @returns {Promise<{ dismissed: boolean, result: string|null, response: any }>} resolving on
13763
13732
  * close, or on removal from the document with a dismissal
13764
13733
  */
@@ -13839,7 +13808,14 @@ var fml = (function (exports) {
13839
13808
  }
13840
13809
  /** @returns {boolean} whether this call is the one that opened the modal */
13841
13810
  #show() {
13811
+ if (this.#closing) {
13812
+ this.#answer = null;
13813
+ }
13842
13814
  this.#stopSlidingOut();
13815
+ //a move in the page takes an open modal out of the top layer; close() would queue a close event answering the next opening
13816
+ if (this.#dialog.open && !this.#dialog.matches(':modal')) {
13817
+ this.#dialog.removeAttribute('open');
13818
+ }
13843
13819
  if (this.#dialog.open) {
13844
13820
  return false;
13845
13821
  }
@@ -13878,6 +13854,21 @@ var fml = (function (exports) {
13878
13854
  #invoker = null;
13879
13855
  /** @type {HTMLElement|null} */
13880
13856
  #pressed = null;
13857
+ #notePress = (/** @type PointerEvent */ evt) => {
13858
+ const target = /** @type Node */ (evt.target);
13859
+ this.#pressed = this.matches(':popover-open') && this.#invoker?.contains(target) ? this.#invoker : null;
13860
+ };
13861
+ /** Upgrades the menu, and has a shared one that came back follow the presses on its invoker again. */
13862
+ connectedCallback() {
13863
+ super.connectedCallback();
13864
+ if (this.rendered && !this.declared('for')) {
13865
+ document.addEventListener('pointerdown', this.#notePress, true);
13866
+ }
13867
+ }
13868
+ /** Stops a shared menu following the presses while it is out of the document. */
13869
+ disconnectedCallback() {
13870
+ document.removeEventListener('pointerdown', this.#notePress, true);
13871
+ }
13881
13872
  /**
13882
13873
  * Gives the menu the `menu` role and an empty `popover` attribute unless
13883
13874
  * it already has one, and marks the items. With `for`, read here once, it
@@ -13963,14 +13954,7 @@ var fml = (function (exports) {
13963
13954
  return this.#mark().filter((item) => !item.hasAttribute('disabled') && !item.hasAttribute('hidden'));
13964
13955
  }
13965
13956
  #wireShared() {
13966
- document.addEventListener(
13967
- 'pointerdown',
13968
- (evt) => {
13969
- const target = /** @type Node */ (evt.target);
13970
- this.#pressed = this.matches(':popover-open') && this.#invoker?.contains(target) ? this.#invoker : null;
13971
- },
13972
- true,
13973
- );
13957
+ document.addEventListener('pointerdown', this.#notePress, true);
13974
13958
  this.addEventListener('toggle', (/** @type any */ evt) => {
13975
13959
  if (evt.newState === 'closed') {
13976
13960
  this.#invoker?.setAttribute('aria-expanded', 'false');
@@ -14298,17 +14282,21 @@ var fml = (function (exports) {
14298
14282
  #showScrollButtons() {
14299
14283
  const list = this.#tablist;
14300
14284
  const overflow = list.scrollWidth - list.clientWidth;
14301
- this.#scrollStart.hidden = list.scrollLeft <= 1;
14302
- this.#scrollEnd.hidden = list.scrollLeft >= overflow - 1;
14285
+ const scrolled = Math.abs(list.scrollLeft);
14286
+ this.#scrollStart.hidden = scrolled <= 1;
14287
+ this.#scrollEnd.hidden = scrolled >= overflow - 1;
14303
14288
  this.#scrollStart.style.blockSize = this.#scrollEnd.style.blockSize = `${list.clientHeight}px`;
14304
14289
  }
14305
14290
  /**
14306
- * The part of the tablist that no scroll button covers.
14307
- * @returns {{ start: number, end: number }}
14291
+ * The part of the tablist that no scroll button covers, in viewport
14292
+ * coordinates, the start button being on the right under rtl.
14293
+ * @returns {{ left: number, right: number }}
14308
14294
  */
14309
14295
  #visibleRange() {
14310
14296
  const view = this.#tablist.getBoundingClientRect();
14311
- return { start: view.left + this.#scrollStart.offsetWidth, end: view.right - this.#scrollEnd.offsetWidth };
14297
+ const rtl = getComputedStyle(this.#tablist).direction === 'rtl';
14298
+ const [onLeft, onRight] = rtl ? [this.#scrollEnd, this.#scrollStart] : [this.#scrollStart, this.#scrollEnd];
14299
+ return { left: view.left + onLeft.offsetWidth, right: view.right - onRight.offsetWidth };
14312
14300
  }
14313
14301
  /**
14314
14302
  * Scrolls the tablist so that the first tab cut by the side the direction
@@ -14317,11 +14305,12 @@ var fml = (function (exports) {
14317
14305
  * @returns {void}
14318
14306
  */
14319
14307
  #scrollByOneTab(direction) {
14320
- const { start, end } = this.#visibleRange();
14321
- const target =
14322
- direction > 0
14323
- ? this.#tabs.find((tab) => tab.getBoundingClientRect().right > end + 1)
14324
- : this.#tabs.findLast((tab) => tab.getBoundingClientRect().left < start - 1);
14308
+ const { left, right } = this.#visibleRange();
14309
+ const rightwards = direction > 0 !== (getComputedStyle(this.#tablist).direction === 'rtl');
14310
+ const cut = rightwards
14311
+ ? (/** @type HTMLElement */ tab) => tab.getBoundingClientRect().right > right + 1
14312
+ : (/** @type HTMLElement */ tab) => tab.getBoundingClientRect().left < left - 1;
14313
+ const target = direction > 0 ? this.#tabs.find(cut) : this.#tabs.findLast(cut);
14325
14314
  this.#bringIntoView(target, matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth');
14326
14315
  }
14327
14316
  /**
@@ -14335,11 +14324,12 @@ var fml = (function (exports) {
14335
14324
  if (!tab) {
14336
14325
  return;
14337
14326
  }
14338
- const { start, end } = this.#visibleRange();
14327
+ const { left, right } = this.#visibleRange();
14339
14328
  const box = tab.getBoundingClientRect();
14340
- const delta = box.right > end ? Math.ceil(box.right - end) : box.left < start ? Math.floor(box.left - start) : 0;
14341
- if (delta !== 0) {
14342
- this.#tablist.scrollBy({ left: delta, behavior });
14329
+ if (box.right > right) {
14330
+ this.#tablist.scrollBy({ left: Math.ceil(box.right - right), behavior });
14331
+ } else if (box.left < left) {
14332
+ this.#tablist.scrollBy({ left: Math.floor(box.left - left), behavior });
14343
14333
  }
14344
14334
  }
14345
14335
  /**
@@ -14566,14 +14556,15 @@ var fml = (function (exports) {
14566
14556
  * @returns {Promise<any[] | undefined> | undefined} a promise resolving to
14567
14557
  * the answers once they are delivered, or to undefined when nobody
14568
14558
  * listened; undefined when the section is already current, and undefined
14569
- * with a warning when no section carries `ref`
14559
+ * with a warning when no section carries `ref` or the one carrying it has
14560
+ * no step paired with it
14570
14561
  * @throws what the entered section's delivery rejected with, as the rejection
14571
14562
  * of the returned promise, after its error is painted in the section
14572
14563
  */
14573
14564
  move(ref) {
14574
14565
  const index = this.#sections.findIndex((s) => s.getAttribute('data-step') === ref);
14575
- if (index === -1) {
14576
- console.warn(`ful-wizard: no section carries data-step="${ref}"`);
14566
+ if (index === -1 || index >= this.#steps.length) {
14567
+ console.warn(`ful-wizard: no section paired with a step carries data-step="${ref}"`);
14577
14568
  return undefined;
14578
14569
  }
14579
14570
  return this.#move(index);
@@ -14586,17 +14577,14 @@ var fml = (function (exports) {
14586
14577
  * @returns {Promise<any[] | undefined> | undefined} a promise resolving to
14587
14578
  * the answers, or to undefined when nobody listened or the delivery failed
14588
14579
  * (its error painted in the section); undefined, with a warning, when `ref`
14589
- * names no section
14580
+ * names no section or one with no step paired with it
14590
14581
  */
14591
14582
  refresh(ref) {
14592
- const section =
14583
+ const index =
14593
14584
  ref instanceof Element
14594
- ? ref
14595
- : typeof ref === 'string'
14596
- ? this.#sections.find((s) => s.getAttribute('data-step') === ref)
14597
- : undefined;
14598
- const index = this.#sections.indexOf(section);
14599
- if (index === -1) {
14585
+ ? this.#sections.indexOf(ref)
14586
+ : this.#sections.findIndex((s) => s.getAttribute('data-step') === ref);
14587
+ if (index === -1 || index >= this.#steps.length) {
14600
14588
  console.warn(`ful-wizard: no section answers to "${ref}"`);
14601
14589
  return undefined;
14602
14590
  }