@olenbetong/appframe-core 2.15.1 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ this.af = this.af || {};
2
2
  this.af.common = (function(exports) {
3
3
 
4
4
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
- //#region ../../node_modules/.pnpm/mitt@3.0.1/node_modules/mitt/dist/mitt.mjs
5
+ // ../../node_modules/.pnpm/mitt@3.0.1/node_modules/mitt/dist/mitt.mjs
6
6
  function mitt_default(n) {
7
7
  return {
8
8
  all: n = n || /* @__PURE__ */ new Map(),
@@ -25,8 +25,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
25
25
  };
26
26
  }
27
27
 
28
- //#endregion
29
- //#region src/SessionHandler.ts
28
+ // src/SessionHandler.ts
30
29
  var SessionHandler = class {
31
30
  eventHandler = mitt_default();
32
31
  authenticated() {
@@ -71,8 +70,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
71
70
  }
72
71
  };
73
72
 
74
- //#endregion
75
- //#region src/UserSession.ts
73
+ // src/UserSession.ts
76
74
  var UserSession = class extends SessionHandler {
77
75
  amDesignator = "a.m.";
78
76
  dayNames = [
@@ -144,8 +142,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
144
142
  }
145
143
  };
146
144
 
147
- //#endregion
148
- //#region src/log.ts
145
+ // src/log.ts
149
146
  const article = window.af?.article?.id ?? window.window?.location.pathname.substring(1).split("/")[0];
150
147
  /**
151
148
  * Logs an activity to the website activity log
@@ -223,6 +220,30 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
223
220
  function getSessionId() {
224
221
  return crypto.randomUUID?.();
225
222
  }
223
+ /** The version in the first URL served under `/lib/@olenbetong/<name>/<version>/`. */
224
+ function libVersion(name, urls) {
225
+ let pattern = new RegExp(`/lib/@olenbetong/${name}/([^/]+)/`);
226
+ for (let url of urls) {
227
+ let match = typeof url === "string" ? pattern.exec(url) : null;
228
+ if (match) return match[1];
229
+ }
230
+ }
231
+ /**
232
+ * The synergi-chrome and synergi-platform versions the page loads on the 2026 site templates,
233
+ * read from the chrome's script tag and the platform import map rather than from the chrome
234
+ * itself, so they are known even when the chrome failed to start. Empty on other pages.
235
+ */
236
+ function getPlatformVersions() {
237
+ let versions = {};
238
+ try {
239
+ let importMap = document.querySelector("script[type=\"importmap\"]");
240
+ let platform = importMap ? libVersion("synergi-platform", Object.values(JSON.parse(importMap.textContent ?? "{}").imports ?? {})) : void 0;
241
+ if (platform) versions["synergi-platform"] = platform;
242
+ } catch {}
243
+ let chrome = libVersion("synergi-chrome", Array.from(document.scripts, (script) => script.src)) ?? window.ob?.chrome?.version;
244
+ if (chrome) versions["synergi-chrome"] = chrome;
245
+ return versions;
246
+ }
226
247
  let sessionStart = Date.now();
227
248
  let sessionId = getSessionId();
228
249
  let deviceId = "";
@@ -231,7 +252,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
231
252
  let startSession = () => logActivity("AfSessionInit", {
232
253
  "appframe-core": window.af?.common?.version,
233
254
  "appframe-data": window.af?.data?.version,
234
- "app-version": window.af?.article?.version
255
+ "app-version": window.af?.article?.version,
256
+ ...getPlatformVersions()
235
257
  });
236
258
  document.addEventListener("DOMContentLoaded", () => {
237
259
  deviceId = localStorage.getItem("_afDeviceId");
@@ -265,15 +287,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
265
287
  };
266
288
  }
267
289
 
268
- //#endregion
269
- //#region src/errorHandler.ts
290
+ // src/errorHandler.ts
270
291
  window.window?.addEventListener("error", (event) => {
271
292
  if (typeof event === "object" && "error" in event) logError(event.error);
272
293
  else if (typeof event === "object" && "message" in event) logError(event);
273
294
  });
274
295
 
275
- //#endregion
276
- //#region src/localStorage.ts
296
+ // src/localStorage.ts
277
297
  function getLocalKey(key) {
278
298
  return [
279
299
  af?.article?.id || "",
@@ -308,8 +328,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
308
328
  };
309
329
  var localStorage_default = new LocalStorage();
310
330
 
311
- //#endregion
312
- //#region src/date.ts
331
+ // src/date.ts
313
332
  function toLocalISODate(date) {
314
333
  return date ? toLocalISODateTime(date).substring(0, 10) : null;
315
334
  }
@@ -332,8 +351,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
332
351
  return date ? date.toISOString().substring(0, 16) : "";
333
352
  }
334
353
 
335
- //#endregion
336
- //#region src/downloadBlob.ts
354
+ // src/downloadBlob.ts
337
355
  function downloadBlob(blob, fileName) {
338
356
  return new Promise((resolve, reject) => {
339
357
  try {
@@ -355,8 +373,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
355
373
  });
356
374
  }
357
375
 
358
- //#endregion
359
- //#region src/invariant.ts
376
+ // src/invariant.ts
360
377
  /**
361
378
  * Throws an error if the condition is falsy. The provided message is used as the error message.
362
379
  * A function can be provided to lazily generate the message.
@@ -371,8 +388,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
371
388
  throw new Error(provided ?? "Invariant failed");
372
389
  }
373
390
 
374
- //#endregion
375
- //#region src/downloadRequest.ts
391
+ // src/downloadRequest.ts
376
392
  async function downloadRequest(request, { fileName, signal, onProgress }) {
377
393
  let bytesReceived = 0;
378
394
  onProgress?.({ status: "requested" });
@@ -426,8 +442,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
426
442
  }
427
443
  }
428
444
 
429
- //#endregion
430
- //#region src/parseFunc.ts
445
+ // src/parseFunc.ts
431
446
  const funcRegex = /^function(?:\s+([a-zA-Z$_][a-zA-Z0-9$_]*))?\s*\(((?:(?:\s*[a-zA-Z$_][a-zA-Z0-9$_]*)(?:\s*,\s*[a-zA-Z$_][a-zA-Z0-9$_]*)*)?)\s*\)\s*\{((?:.|\n|\r)*)\}$/;
432
447
  const arrowBlockRegex = /^(?:\(([^)]*)\)|([a-zA-Z$_][a-zA-Z0-9$_]*))\s*=>\s*\{([\s\S]*)\}$/;
433
448
  const arrowExpressionRegex = /^(?:\(([^)]*)\)|([a-zA-Z$_][a-zA-Z0-9$_]*))\s*=>\s*([\s\S]+)$/;
@@ -461,13 +476,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
461
476
  };
462
477
  }
463
478
 
464
- //#endregion
465
- //#region src/Namespace.ts
479
+ // src/Namespace.ts
466
480
  function Namespace() {}
467
481
  Namespace.prototype = Object.create(null);
468
482
 
469
- //#endregion
470
- //#region src/requireNamespace.ts
483
+ // src/requireNamespace.ts
471
484
  function requireNamespace(root, namespace) {
472
485
  if (typeof root === "object") {
473
486
  if (typeof namespace === "string") return requireNamespace(root, namespace.split("."));
@@ -479,8 +492,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
479
492
  }
480
493
  }
481
494
 
482
- //#endregion
483
- //#region src/expose.ts
495
+ // src/expose.ts
484
496
  /**
485
497
  * Expose a value to a potentially deeply nested global variable
486
498
  * @param name {string | object} Either a dot-separated path to the global variable, or an object to expose the value on
@@ -510,8 +522,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
510
522
  }
511
523
  }
512
524
 
513
- //#endregion
514
- //#region src/getLocalizedString.ts
525
+ // src/getLocalizedString.ts
515
526
  async function fetchLocalizedString(text, project) {
516
527
  try {
517
528
  let response = await fetch(`/api/user/localize/new/${encodeURIComponent(project)}`, {
@@ -600,8 +611,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
600
611
  };
601
612
  }
602
613
 
603
- //#endregion
604
- //#region src/filter/operators.ts
614
+ // src/filter/operators.ts
605
615
  /**
606
616
  * Operators that take no value at all.
607
617
  *
@@ -615,6 +625,26 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
615
625
  "isblank",
616
626
  "isnotblank"
617
627
  ];
628
+ /**
629
+ * Whole-period checks for dates, such as "Is last week", in the order of the
630
+ * Windows filter editor. They take no value. The framework has no operator for
631
+ * them, so a filter using one is sent as a filter string (`needsFilterString`).
632
+ */
633
+ const PERIOD_OPERATORS = [
634
+ "isbeyondthisyear",
635
+ "islaterthisyear",
636
+ "islaterthismonth",
637
+ "isnextweek",
638
+ "islaterthisweek",
639
+ "istomorrow",
640
+ "istoday",
641
+ "isyesterday",
642
+ "isearlierthisweek",
643
+ "islastweek",
644
+ "isearlierthismonth",
645
+ "isearlierthisyear",
646
+ "ispriorthisyear"
647
+ ];
618
648
  /** Operators whose value is a two element `[from, to]` array. */
619
649
  const PAIR_OPERATORS = [
620
650
  "between",
@@ -625,7 +655,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
625
655
  /** Operators whose value is an array of values. */
626
656
  const LIST_OPERATORS = ["inlist", "notinlist"];
627
657
  function getOperatorArity(operator) {
628
- if (PARAMETERLESS_OPERATORS.includes(operator)) return "none";
658
+ if (PARAMETERLESS_OPERATORS.includes(operator) || PERIOD_OPERATORS.includes(operator)) return "none";
629
659
  if (PAIR_OPERATORS.includes(operator)) return "pair";
630
660
  if (LIST_OPERATORS.includes(operator)) return "list";
631
661
  return "single";
@@ -668,7 +698,20 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
668
698
  datelessthan: "Before",
669
699
  datelessthanorequal: "Up to",
670
700
  datebetween: "Between",
671
- datenotbetween: "Not between"
701
+ datenotbetween: "Not between",
702
+ isbeyondthisyear: "Is beyond this year",
703
+ islaterthisyear: "Is later this year",
704
+ islaterthismonth: "Is later this month",
705
+ isnextweek: "Is next week",
706
+ islaterthisweek: "Is later this week",
707
+ istomorrow: "Is tomorrow",
708
+ istoday: "Is today",
709
+ isyesterday: "Is yesterday",
710
+ isearlierthisweek: "Is earlier this week",
711
+ islastweek: "Is last week",
712
+ isearlierthismonth: "Is earlier this month",
713
+ isearlierthisyear: "Is earlier this year",
714
+ ispriorthisyear: "Is prior to this year"
672
715
  };
673
716
  /** Comparison operator labels used for date and time fields. */
674
717
  const DATE_OPERATOR_LABELS = {
@@ -713,13 +756,15 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
713
756
  ...EQUALITY,
714
757
  ...LIST_CHECKS,
715
758
  ...RANGE,
716
- ...COMPARISONS
759
+ ...COMPARISONS,
760
+ ...PERIOD_OPERATORS
717
761
  ],
718
762
  datetime: [
719
763
  ...EQUALITY,
720
764
  ...LIST_CHECKS,
721
765
  ...RANGE,
722
- ...COMPARISONS
766
+ ...COMPARISONS,
767
+ ...PERIOD_OPERATORS
723
768
  ],
724
769
  number: [
725
770
  ...EQUALITY,
@@ -792,7 +837,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
792
837
  const RELATIVE_DATE_VALUES = [
793
838
  "Yesterday",
794
839
  "Today",
840
+ "Now",
795
841
  "Tomorrow",
842
+ "DayAfterTomorrow",
843
+ "TwoWeeksAway",
796
844
  "ThisWeek",
797
845
  "ThisMonth",
798
846
  "ThisYear",
@@ -807,7 +855,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
807
855
  CurrentUser: "Current user",
808
856
  Yesterday: "Yesterday",
809
857
  Today: "Today",
858
+ Now: "Now",
810
859
  Tomorrow: "Tomorrow",
860
+ DayAfterTomorrow: "Day after tomorrow",
861
+ TwoWeeksAway: "Two weeks away",
811
862
  ThisWeek: "This week",
812
863
  ThisMonth: "This month",
813
864
  ThisYear: "This year",
@@ -843,6 +894,30 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
843
894
  if (field.type === "string") return ["CurrentUser"];
844
895
  return [];
845
896
  }
897
+ /** Operators that can compare a field with another column. */
898
+ const COLUMN_OPERATORS = [
899
+ ...EQUALITY,
900
+ ...RANGE,
901
+ ...COMPARISONS
902
+ ];
903
+ /** Whether an operator can take another column as its value. */
904
+ function supportsColumnValue(operator) {
905
+ return COLUMN_OPERATORS.includes(operator);
906
+ }
907
+ /** Dates and datetimes compare with each other; other types only with their own. */
908
+ function getComparableType(type) {
909
+ return type === "datetime" ? "date" : type;
910
+ }
911
+ /**
912
+ * The columns a field can be compared with: the other fields of the same type,
913
+ * as in the Windows filter editor. Booleans have only true and false checks,
914
+ * so they get none.
915
+ */
916
+ function getColumnsForField(field, fields) {
917
+ if (field.type === "boolean") return [];
918
+ let type = getComparableType(field.type);
919
+ return fields.filter((other) => other.name !== field.name && !other.excludeFromFilter && getComparableType(other.type) === type);
920
+ }
846
921
  /**
847
922
  * Aliases for names `eOperators.ToString()` can produce that are not operators
848
923
  * in their own right. `Not` is the bare negation flag (i.e. "not equal to"),
@@ -866,8 +941,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
866
941
  return OPERATOR_ALIASES[normalized] ?? normalized;
867
942
  }
868
943
 
869
- //#endregion
870
- //#region src/filter/tree.ts
944
+ // src/filter/tree.ts
871
945
  /**
872
946
  * Creates the default empty filter: a single `and` group with no conditions.
873
947
  */
@@ -954,10 +1028,40 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
954
1028
  let arity = getOperatorArity(normalizeOperator(item.operator));
955
1029
  if (arity === "none") return true;
956
1030
  if (item.value === null || item.value === void 0 || item.value === "") return false;
957
- if (arity === "pair") return Array.isArray(item.value) && item.value.length === 2 && item.value.every((v) => v !== "" && v != null);
1031
+ if (arity === "pair") return Array.isArray(item.value) && item.value.length === 2 && item.value.every((v) => {
1032
+ let end = isRangeEnd(v) ? v.value : v;
1033
+ return end !== "" && end != null;
1034
+ });
958
1035
  if (arity === "list") return Array.isArray(item.value) && item.value.length > 0;
959
1036
  return true;
960
1037
  }
1038
+ /** Whether a range value end is a `FilterRangeEnd` rather than a plain value. */
1039
+ function isRangeEnd(value) {
1040
+ return typeof value === "object" && value !== null && !(value instanceof Date) && "valueType" in value;
1041
+ }
1042
+ /** Dynamic values the framework has no `eDynamicValue` member for. */
1043
+ const DYNAMIC_VALUES_WITHOUT_FRAMEWORK_SUPPORT = /* @__PURE__ */ new Set([
1044
+ "Now",
1045
+ "DayAfterTomorrow",
1046
+ "TwoWeeksAway"
1047
+ ]);
1048
+ function needsConversion(valueType, value) {
1049
+ if (valueType === "column") return true;
1050
+ return valueType === "special" && typeof value === "string" && DYNAMIC_VALUES_WITHOUT_FRAMEWORK_SUPPORT.has(value);
1051
+ }
1052
+ /**
1053
+ * True when the filter holds something the framework's data API cannot read
1054
+ * from a filter object: another column, a range end that is not a plain value,
1055
+ * one of the dates only the Windows editor offers, or a whole-period check. Such a filter must be
1056
+ * converted with `convertFilter` and sent as a filter string.
1057
+ */
1058
+ function needsFilterString(filter) {
1059
+ if (!filter) return false;
1060
+ if (isGroup(filter)) return filter.items.some(needsFilterString);
1061
+ if (PERIOD_OPERATORS.includes(normalizeOperator(filter.operator))) return true;
1062
+ if (needsConversion(filter.valueType, filter.value)) return true;
1063
+ return Array.isArray(filter.value) && filter.value.some((item) => isRangeEnd(item));
1064
+ }
961
1065
  /**
962
1066
  * Creates an expression for a field, using the field's default operator and an
963
1067
  * empty value of the right shape.
@@ -988,8 +1092,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
988
1092
  let previousArity = getOperatorArity(normalizeOperator(expression.operator));
989
1093
  let arity = getOperatorArity(operator);
990
1094
  let value = expression.value;
991
- if (arity !== previousArity) value = createEmptyValue(operator);
992
- let valueType = expression.valueType === "special" && arity === previousArity ? "special" : getValueType(field, operator);
1095
+ let holdsColumn = expression.valueType === "column" || Array.isArray(value) && value.some((item) => isRangeEnd(item) && item.valueType === "column");
1096
+ if (arity !== previousArity || holdsColumn && !supportsColumnValue(operator)) value = createEmptyValue(operator);
1097
+ let valueType = (expression.valueType === "special" || expression.valueType === "column") && value === expression.value ? expression.valueType : getValueType(field, operator);
993
1098
  return {
994
1099
  ...expression,
995
1100
  operator,
@@ -1055,8 +1160,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1055
1160
  return insertNodeAtPath(filter, path, createEmptyGroup(parent && isGroup(parent) && parent.mode === "and" ? "or" : "and"));
1056
1161
  }
1057
1162
 
1058
- //#endregion
1059
- //#region src/filter/convertFilter.ts
1163
+ // src/filter/convertFilter.ts
1060
1164
  const CONVERT_URL = "/api/filter/convert";
1061
1165
  /**
1062
1166
  * Converts between a structured filter and a DevExpress filter string.
@@ -1081,8 +1185,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1081
1185
  };
1082
1186
  }
1083
1187
 
1084
- //#endregion
1085
- //#region src/filter/describeFilter.ts
1188
+ // src/filter/describeFilter.ts
1086
1189
  /**
1087
1190
  * Builds a human-readable description of a filter, without contacting the
1088
1191
  * server. Use this for read-only summaries; the authoritative filter string is
@@ -1110,18 +1213,19 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1110
1213
  let label = getOperatorLabel(operator, field?.type);
1111
1214
  let arity = getOperatorArity(operator);
1112
1215
  if (arity === "none") return `[${caption}] ${label}`;
1113
- return `[${caption}] ${label} ${formatValue(expression, arity)}`;
1216
+ return `[${caption}] ${label} ${formatValue(expression, arity, fields)}`;
1114
1217
  }
1115
- function formatValue(expression, arity) {
1218
+ function formatValue(expression, arity, fields) {
1116
1219
  let { value, valueType } = expression;
1117
- if (valueType === "special" && typeof value === "string") return getDynamicValueLabel(value);
1118
1220
  if (Array.isArray(value)) {
1119
- let formatted = value.map((item) => formatScalar(item, valueType));
1221
+ let formatted = value.map((item) => isRangeEnd(item) ? formatScalar(item.value, item.valueType, fields) : formatScalar(item, valueType, fields));
1120
1222
  return arity === "pair" ? formatted.join(" - ") : `(${formatted.join(", ")})`;
1121
1223
  }
1122
- return formatScalar(value, valueType);
1224
+ return formatScalar(value, valueType, fields);
1123
1225
  }
1124
- function formatScalar(value, valueType) {
1226
+ function formatScalar(value, valueType, fields) {
1227
+ if (valueType === "special" && typeof value === "string") return getDynamicValueLabel(value);
1228
+ if (valueType === "column" && typeof value === "string") return `[${fields.get(value.toLowerCase())?.caption ?? value}]`;
1125
1229
  if (value === null || value === void 0) return "";
1126
1230
  if (value instanceof Date) return value.toISOString().slice(0, 10);
1127
1231
  if (typeof value === "number" || typeof value === "boolean") return String(value);
@@ -1129,8 +1233,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1129
1233
  return `'${String(value)}'`;
1130
1234
  }
1131
1235
 
1132
- //#endregion
1133
- //#region src/filter/fields.ts
1236
+ // src/filter/fields.ts
1134
1237
  const FIELD_TYPES = [
1135
1238
  "string",
1136
1239
  "number",
@@ -1165,8 +1268,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1165
1268
  return records.map(toFieldMetadata).filter((field) => field.name !== "" && !field.excludeFromFilter).sort((a, b) => a.name.localeCompare(b.name));
1166
1269
  }
1167
1270
 
1168
- //#endregion
1169
- //#region src/filter/standardLayout.ts
1271
+ // src/filter/standardLayout.ts
1170
1272
  /**
1171
1273
  * The "standard layout" is the simplified shape the Windows filter editor can
1172
1274
  * render in its flow view: an outer `or` group whose items are `and` groups of
@@ -1248,8 +1350,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1248
1350
  for (let child of item.items) collectExpressions(child, into);
1249
1351
  }
1250
1352
 
1251
- //#endregion
1252
- //#region src/filter/savedFilters.ts
1353
+ // src/filter/savedFilters.ts
1253
1354
  /**
1254
1355
  * `sviw_Database_MyFilters` unions in a synthetic "No Filter" row so the Windows
1255
1356
  * tree can render a "no filter" entry. It is not a real filter and must be
@@ -1348,8 +1449,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1348
1449
  */
1349
1450
  const canSetCrossDomain = canRenameSavedFilter;
1350
1451
 
1351
- //#endregion
1352
- //#region src/getUserImage.ts
1452
+ // src/getUserImage.ts
1353
1453
  const sizeMap = {
1354
1454
  xs: 64,
1355
1455
  sm: 128,
@@ -1364,8 +1464,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1364
1464
  return `/api/data/blob/EmployeesLookup/${primKeyOrOptions}/Image/${encodeURIComponent(login ?? "")}${login ? "." : ""}${encodeURIComponent(hash)}.jpg${sizePx ? `?width=${sizePx}` : ""}`;
1365
1465
  }
1366
1466
 
1367
- //#endregion
1368
- //#region src/localize.ts
1467
+ // src/localize.ts
1369
1468
  /**
1370
1469
  * Localization function for tagged templates. Replaces the arguments
1371
1470
  * with $n, where n is the index, before asking Appframe to translate
@@ -1389,8 +1488,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1389
1488
  return localized;
1390
1489
  }
1391
1490
 
1392
- //#endregion
1393
- //#region src/report/recordSource.ts
1491
+ // src/report/recordSource.ts
1394
1492
  const XML_ENTITIES = {
1395
1493
  amp: "&",
1396
1494
  lt: "<",
@@ -1476,8 +1574,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1476
1574
  };
1477
1575
  }
1478
1576
 
1479
- //#endregion
1480
- //#region src/report/parameters.ts
1577
+ // src/report/parameters.ts
1481
1578
  /**
1482
1579
  * Report parameters: mapping the metadata records onto something renderable,
1483
1580
  * and the XML the parameter values are stored as on a saved filter.
@@ -1630,8 +1727,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1630
1727
  return values;
1631
1728
  }
1632
1729
 
1633
- //#endregion
1634
- //#region src/report/parameterDefaults.ts
1730
+ // src/report/parameterDefaults.ts
1635
1731
  /**
1636
1732
  * Resolving report parameter defaults that name a stored procedure.
1637
1733
  *
@@ -1693,8 +1789,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1693
1789
  return row;
1694
1790
  }
1695
1791
 
1696
- //#endregion
1697
- //#region src/report/render.ts
1792
+ // src/report/render.ts
1698
1793
  /**
1699
1794
  * Rendering a report through the framework's report route.
1700
1795
  *
@@ -1898,8 +1993,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1898
1993
  }));
1899
1994
  }
1900
1995
 
1901
- //#endregion
1902
- //#region src/report/report.ts
1996
+ // src/report/report.ts
1903
1997
  /**
1904
1998
  * Mapping a `sviw_WinClient_MyReports` record onto the report model, including
1905
1999
  * which output formats the report offers.
@@ -1943,8 +2037,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1943
2037
  };
1944
2038
  }
1945
2039
 
1946
- //#endregion
1947
- //#region src/alert.ts
2040
+ // src/alert.ts
1948
2041
  const template = `
1949
2042
  <dialog class="alert-dialog">
1950
2043
  <form method="dialog">
@@ -2055,8 +2148,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2055
2148
  });
2056
2149
  }
2057
2150
 
2058
- //#endregion
2059
- //#region src/settings.ts
2151
+ // src/settings.ts
2060
2152
  function getKey(article) {
2061
2153
  return `${article ?? window.af?.article?.id ?? window.window?.location.pathname.substring(1).split("/")[0]}.${window.af?.userSession.login ?? "anonymous"}`;
2062
2154
  }
@@ -2076,13 +2168,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2076
2168
  localStorage.setItem(key, JSON.stringify(userSettings));
2077
2169
  }
2078
2170
 
2079
- //#endregion
2080
- //#region src/index.ts
2081
- const version = "2.15.1";
2171
+ // src/index.ts
2172
+ const version = "2.15.2";
2082
2173
 
2083
- //#endregion
2084
2174
  exports.ConfirmButtons = ConfirmButtons;
2085
2175
  exports.NO_FILTER_ID = NO_FILTER_ID;
2176
+ exports.PERIOD_OPERATORS = PERIOD_OPERATORS;
2086
2177
  exports.RELATIVE_DATE_VALUES = RELATIVE_DATE_VALUES;
2087
2178
  exports.SessionHandler = SessionHandler;
2088
2179
  exports.UserSession = UserSession;
@@ -2112,6 +2203,7 @@ exports.encodeXml = encodeXml;
2112
2203
  exports.expose = expose;
2113
2204
  exports.fetchParameterDefault = fetchParameterDefault;
2114
2205
  exports.findSavedFilter = findSavedFilter;
2206
+ exports.getColumnsForField = getColumnsForField;
2115
2207
  exports.getDefaultOperator = getDefaultOperator;
2116
2208
  exports.getDefaultParameterValues = getDefaultParameterValues;
2117
2209
  exports.getDynamicValueLabel = getDynamicValueLabel;
@@ -2137,12 +2229,14 @@ exports.isEmptyFilter = isEmptyFilter;
2137
2229
  exports.isExpression = isExpression;
2138
2230
  exports.isGroup = isGroup;
2139
2231
  exports.isProcedureDefault = isProcedureDefault;
2232
+ exports.isRangeEnd = isRangeEnd;
2140
2233
  exports.isStandardLayout = isStandardLayout;
2141
2234
  exports.localStorage = localStorage_default;
2142
2235
  exports.localize = localize;
2143
2236
  exports.logActivity = logActivity;
2144
2237
  exports.logError = logError;
2145
2238
  exports.mitt = mitt_default;
2239
+ exports.needsFilterString = needsFilterString;
2146
2240
  exports.normalizeOperator = normalizeOperator;
2147
2241
  exports.openAlertDialog = openAlertDialog;
2148
2242
  exports.openReport = openReport;
@@ -2162,6 +2256,7 @@ exports.saveSettings = saveSettings;
2162
2256
  exports.serializeParameters = serializeParameters;
2163
2257
  exports.setGroupMode = setGroupMode;
2164
2258
  exports.startActivity = startActivity;
2259
+ exports.supportsColumnValue = supportsColumnValue;
2165
2260
  exports.time = time;
2166
2261
  exports.toFieldMetadata = toFieldMetadata;
2167
2262
  exports.toFieldMetadataList = toFieldMetadataList;