@getodk/xforms-engine 0.9.0 → 0.10.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.
Files changed (37) hide show
  1. package/dist/client/SelectNode.d.ts +1 -0
  2. package/dist/client/TextRange.d.ts +4 -0
  3. package/dist/index.js +125 -133
  4. package/dist/index.js.map +1 -1
  5. package/dist/instance/SelectControl.d.ts +1 -0
  6. package/dist/instance/text/TextRange.d.ts +11 -1
  7. package/dist/lib/reactivity/text/createTextRange.d.ts +1 -2
  8. package/dist/parse/expression/TextChunkExpression.d.ts +16 -0
  9. package/dist/parse/text/ItemsetLabelDefinition.d.ts +2 -4
  10. package/dist/parse/text/MessageDefinition.d.ts +3 -7
  11. package/dist/parse/text/abstract/TextElementDefinition.d.ts +2 -8
  12. package/dist/parse/text/abstract/TextRangeDefinition.d.ts +2 -2
  13. package/dist/solid.js +125 -133
  14. package/dist/solid.js.map +1 -1
  15. package/package.json +2 -2
  16. package/src/client/SelectNode.ts +2 -0
  17. package/src/client/TextRange.ts +5 -1
  18. package/src/instance/SelectControl.ts +6 -0
  19. package/src/instance/text/TextRange.ts +21 -1
  20. package/src/lib/reactivity/text/createTextRange.ts +56 -43
  21. package/src/lib/reactivity/validation/createValidation.ts +1 -3
  22. package/src/parse/expression/TextChunkExpression.ts +78 -0
  23. package/src/parse/text/ItemsetLabelDefinition.ts +8 -12
  24. package/src/parse/text/MessageDefinition.ts +9 -16
  25. package/src/parse/text/abstract/TextElementDefinition.ts +10 -26
  26. package/src/parse/text/abstract/TextRangeDefinition.ts +2 -2
  27. package/src/parse/xpath/semantic-analysis.ts +7 -2
  28. package/dist/parse/expression/TextLiteralExpression.d.ts +0 -9
  29. package/dist/parse/expression/TextOutputExpression.d.ts +0 -7
  30. package/dist/parse/expression/TextReferenceExpression.d.ts +0 -7
  31. package/dist/parse/expression/TextTranslationExpression.d.ts +0 -8
  32. package/dist/parse/expression/abstract/TextChunkExpression.d.ts +0 -17
  33. package/src/parse/expression/TextLiteralExpression.ts +0 -19
  34. package/src/parse/expression/TextOutputExpression.ts +0 -25
  35. package/src/parse/expression/TextReferenceExpression.ts +0 -14
  36. package/src/parse/expression/TextTranslationExpression.ts +0 -38
  37. package/src/parse/expression/abstract/TextChunkExpression.ts +0 -38
@@ -22,6 +22,7 @@ interface SelectControlStateSpec extends ValueNodeStateSpec<readonly string[]> {
22
22
  readonly label: Accessor<TextRange<'label'> | null>;
23
23
  readonly hint: Accessor<TextRange<'hint'> | null>;
24
24
  readonly valueOptions: Accessor<SelectValueOptions>;
25
+ readonly isSelectWithImages: Accessor<boolean>;
25
26
  }
26
27
  export declare class SelectControl extends ValueNode<'string', SelectDefinition<'string'>, readonly string[], readonly string[]> implements SelectNode, XFormsXPathElement, EvaluationContext, ValidationContext, ClientReactiveSerializableValueNode {
27
28
  static from(parent: GeneralParentNode, instanceNode: StaticLeafElement | null, definition: SelectDefinition): SelectControl;
@@ -1,10 +1,20 @@
1
+ import { JRResourceURL } from '../../../../common/src/jr-resources/JRResourceURL.ts';
1
2
  import { TextRange as ClientTextRange, TextChunk, TextOrigin, TextRole } from '../../client/TextRange.ts';
3
+ export interface MediaSources {
4
+ image?: JRResourceURL;
5
+ video?: JRResourceURL;
6
+ audio?: JRResourceURL;
7
+ }
2
8
  export declare class TextRange<Role extends TextRole, Origin extends TextOrigin> implements ClientTextRange<Role, Origin> {
3
9
  readonly origin: Origin;
4
10
  readonly role: Role;
5
11
  protected readonly chunks: readonly TextChunk[];
12
+ protected readonly mediaSources?: MediaSources | undefined;
6
13
  [Symbol.iterator](): Generator<TextChunk, void, unknown>;
7
14
  get formatted(): Record<PropertyKey, unknown>;
8
15
  get asString(): string;
9
- constructor(origin: Origin, role: Role, chunks: readonly TextChunk[]);
16
+ get imageSource(): JRResourceURL | undefined;
17
+ get audioSource(): JRResourceURL | undefined;
18
+ get videoSource(): JRResourceURL | undefined;
19
+ constructor(origin: Origin, role: Role, chunks: readonly TextChunk[], mediaSources?: MediaSources | undefined);
10
20
  }
@@ -5,8 +5,7 @@ import { TextRange } from '../../../instance/text/TextRange.ts';
5
5
  import { TextRangeDefinition } from '../../../parse/text/abstract/TextRangeDefinition.ts';
6
6
  type ComputedFormTextRange<Role extends TextRole> = Accessor<TextRange<Role, 'form'>>;
7
7
  /**
8
- * Creates a text range (e.g. label or hint) from the provided definition,
9
- * reactive to:
8
+ * Creates a text range (e.g. label or hint) from the provided definition, reactive to:
10
9
  *
11
10
  * - The form's current language (e.g. `<label ref="jr:itext('text-id')" />`)
12
11
  * - Direct `<output>` references within the label's children
@@ -0,0 +1,16 @@
1
+ import { TextChunkSource } from '../../client/TextRange.ts';
2
+ import { AnyTextRangeDefinition } from '../text/abstract/TextRangeDefinition.ts';
3
+ import { DependentExpression } from './abstract/DependentExpression.ts';
4
+ interface TextChunkExpressionOptions {
5
+ readonly isTranslated?: true;
6
+ }
7
+ export declare class TextChunkExpression<T extends 'nodes' | 'string'> extends DependentExpression<T> {
8
+ readonly source: TextChunkSource;
9
+ readonly stringValue: string;
10
+ constructor(context: AnyTextRangeDefinition, resultType: T, expression: string, source: TextChunkSource, options?: TextChunkExpressionOptions, literalValue?: string);
11
+ static fromLiteral(context: AnyTextRangeDefinition, stringValue: string): TextChunkExpression<'string'>;
12
+ static fromReference(context: AnyTextRangeDefinition, ref: string): TextChunkExpression<'string'>;
13
+ static fromOutput(context: AnyTextRangeDefinition, element: Element): TextChunkExpression<'string'> | null;
14
+ static fromTranslation(context: AnyTextRangeDefinition, maybeExpression: string): TextChunkExpression<'nodes'> | null;
15
+ }
16
+ export {};
@@ -1,12 +1,10 @@
1
1
  import { XFormDefinition } from '../../parse/XFormDefinition.ts';
2
- import { ItemDefinition } from '../body/control/ItemDefinition.ts';
3
2
  import { ItemsetDefinition } from '../body/control/ItemsetDefinition.ts';
4
- import { RefAttributeChunk } from './abstract/TextElementDefinition.ts';
3
+ import { TextChunkExpression } from '../expression/TextChunkExpression.ts';
5
4
  import { TextRangeDefinition } from './abstract/TextRangeDefinition.ts';
6
- export type ItemLabelOwner = ItemDefinition | ItemsetDefinition;
7
5
  export declare class ItemsetLabelDefinition extends TextRangeDefinition<'item-label'> {
8
6
  static from(form: XFormDefinition, owner: ItemsetDefinition): ItemsetLabelDefinition | null;
9
7
  readonly role = "item-label";
10
- readonly chunks: readonly [RefAttributeChunk];
8
+ readonly chunks: ReadonlyArray<TextChunkExpression<'nodes' | 'string'>>;
11
9
  private constructor();
12
10
  }
@@ -1,14 +1,10 @@
1
- import { TextLiteralExpression } from '../expression/TextLiteralExpression.ts';
2
- import { TextTranslationExpression } from '../expression/TextTranslationExpression.ts';
1
+ import { TextChunkExpression } from '../expression/TextChunkExpression.ts';
3
2
  import { BindDefinition } from '../model/BindDefinition.ts';
4
- import { TextBindAttributeLocalName, TextSourceNode, TextRangeDefinition } from './abstract/TextRangeDefinition.ts';
5
- export type MessageSourceNode = TextSourceNode<TextBindAttributeLocalName>;
6
- type MessageChunk = TextLiteralExpression | TextTranslationExpression;
3
+ import { TextBindAttributeLocalName, TextRangeDefinition } from './abstract/TextRangeDefinition.ts';
7
4
  export declare class MessageDefinition<Type extends TextBindAttributeLocalName> extends TextRangeDefinition<Type> {
8
5
  readonly role: Type;
9
6
  static from<Type extends TextBindAttributeLocalName>(bind: BindDefinition, type: Type): MessageDefinition<Type> | null;
10
- readonly chunks: readonly [MessageChunk];
7
+ readonly chunks: ReadonlyArray<TextChunkExpression<'nodes' | 'string'>>;
11
8
  private constructor();
12
9
  }
13
10
  export type AnyMessageDefinition = MessageDefinition<TextBindAttributeLocalName>;
14
- export {};
@@ -1,21 +1,15 @@
1
1
  import { ElementTextRole } from '../../../client/TextRange.ts';
2
2
  import { XFormDefinition } from '../../../parse/XFormDefinition.ts';
3
3
  import { ItemDefinition } from '../../body/control/ItemDefinition.ts';
4
- import { TextLiteralExpression } from '../../expression/TextLiteralExpression.ts';
5
- import { TextOutputExpression } from '../../expression/TextOutputExpression.ts';
6
- import { TextReferenceExpression } from '../../expression/TextReferenceExpression.ts';
7
- import { TextTranslationExpression } from '../../expression/TextTranslationExpression.ts';
4
+ import { TextChunkExpression } from '../../expression/TextChunkExpression.ts';
8
5
  import { HintDefinition } from '../HintDefinition.ts';
9
6
  import { ItemLabelDefinition } from '../ItemLabelDefinition.ts';
10
7
  import { ItemsetLabelDefinition } from '../ItemsetLabelDefinition.ts';
11
8
  import { LabelDefinition, LabelOwner } from '../LabelDefinition.ts';
12
9
  import { TextSourceNode, TextRangeDefinition } from './TextRangeDefinition.ts';
13
- export type RefAttributeChunk = TextReferenceExpression | TextTranslationExpression;
14
- type TextElementChildChunk = TextLiteralExpression | TextOutputExpression;
15
- type TextElementChunks = readonly [RefAttributeChunk] | readonly TextElementChildChunk[];
16
10
  type TextElementOwner = ItemDefinition | LabelOwner;
17
11
  export declare abstract class TextElementDefinition<Role extends ElementTextRole> extends TextRangeDefinition<Role> {
18
- readonly chunks: TextElementChunks;
12
+ readonly chunks: ReadonlyArray<TextChunkExpression<'nodes' | 'string'>>;
19
13
  constructor(form: XFormDefinition, owner: TextElementOwner, sourceNode: TextSourceNode<Role>);
20
14
  }
21
15
  export type AnyTextElementDefinition = HintDefinition | ItemLabelDefinition | ItemsetLabelDefinition | LabelDefinition;
@@ -2,7 +2,7 @@ import { LocalNamedElement } from '../../../../../common/types/dom.ts';
2
2
  import { TextRole } from '../../../client/TextRange.ts';
3
3
  import { XFormDefinition } from '../../../parse/XFormDefinition.ts';
4
4
  import { DependencyContext } from '../../expression/abstract/DependencyContext.ts';
5
- import { AnyTextChunkExpression } from '../../expression/abstract/TextChunkExpression.ts';
5
+ import { TextChunkExpression } from '../../expression/TextChunkExpression.ts';
6
6
  import { AnyMessageDefinition } from '../MessageDefinition.ts';
7
7
  import { AnyTextElementDefinition } from './TextElementDefinition.ts';
8
8
  export type TextBindAttributeLocalName = 'constraintMsg' | 'requiredMsg';
@@ -22,7 +22,7 @@ export declare abstract class TextRangeDefinition<Role extends TextRole> extends
22
22
  abstract readonly role: Role;
23
23
  readonly parentReference: string | null;
24
24
  readonly reference: string | null;
25
- abstract readonly chunks: readonly AnyTextChunkExpression[];
25
+ abstract readonly chunks: ReadonlyArray<TextChunkExpression<'nodes' | 'string'>>;
26
26
  get isTranslated(): boolean;
27
27
  set isTranslated(value: true);
28
28
  protected constructor(form: XFormDefinition, ownerContext: DependencyContext, sourceNode: TextSourceNode<Role>);
package/dist/solid.js CHANGED
@@ -9402,7 +9402,7 @@ const substring = new StringFunction(
9402
9402
  return string2.substring(start, end);
9403
9403
  }
9404
9404
  );
9405
- const string$2 = new StringFunction(
9405
+ const string$1 = new StringFunction(
9406
9406
  "string",
9407
9407
  [{ arityType: "optional" }],
9408
9408
  (context, [expression]) => (expression?.evaluate(context) ?? context).toString()
@@ -9435,13 +9435,13 @@ const translate = new StringFunction(
9435
9435
  }
9436
9436
  );
9437
9437
 
9438
- const string$3 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
9438
+ const string$2 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
9439
9439
  __proto__: null,
9440
9440
  concat: concat$1,
9441
9441
  contains,
9442
9442
  normalizeSpace,
9443
9443
  startsWith,
9444
- string: string$2,
9444
+ string: string$1,
9445
9445
  stringLength,
9446
9446
  substring,
9447
9447
  substringAfter,
@@ -9453,7 +9453,7 @@ const fn$2 = new FunctionLibrary(FN_NAMESPACE_URI, [
9453
9453
  ...Object.values(boolean$2),
9454
9454
  ...Object.values(nodeset$1),
9455
9455
  ...Object.values(number$3),
9456
- ...Object.values(string$3)
9456
+ ...Object.values(string$2)
9457
9457
  ]);
9458
9458
 
9459
9459
  class BaseStep {
@@ -11233,21 +11233,21 @@ const enk = new FunctionLibrary(ENKETO_NAMESPACE_URI, [
11233
11233
  new FunctionAlias("format-date", formatDateTime)
11234
11234
  ]);
11235
11235
 
11236
- const itext = new StringFunction(
11236
+ const itext = new NodeSetFunction(
11237
11237
  "itext",
11238
11238
  [{ arityType: "required", typeHint: "string" }],
11239
11239
  (context, [itextIDExpression]) => {
11240
11240
  const itextID = itextIDExpression.evaluate(context).toString();
11241
- return XFormsXPathEvaluator.getDefaultTranslationText(context, itextID);
11241
+ return XFormsXPathEvaluator.getTranslationValues(context, itextID) ?? [];
11242
11242
  }
11243
11243
  );
11244
11244
 
11245
- const string$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
11245
+ const nodeSet = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
11246
11246
  __proto__: null,
11247
11247
  itext
11248
11248
  }, Symbol.toStringTag, { value: 'Module' }));
11249
11249
 
11250
- const jr$2 = new FunctionLibrary(JAVAROSA_NAMESPACE_URI, [...Object.values(string$1)]);
11250
+ const jr$2 = new FunctionLibrary(JAVAROSA_NAMESPACE_URI, [...Object.values(nodeSet)]);
11251
11251
 
11252
11252
  const booleanFromString = new BooleanFunction(
11253
11253
  "boolean-from-string",
@@ -18950,46 +18950,39 @@ class XFormsItextTranslations {
18950
18950
  return textMap.get(itextID) ?? null;
18951
18951
  }
18952
18952
  /**
18953
+ * Retrieves all translation value elements for a given Itext in the active language.
18954
+ *
18953
18955
  * @package
18954
18956
  *
18955
- * Here, "default" is meant as more precise language than "regular" as
18956
- * {@link https://getodk.github.io/xforms-spec/#languages | specified by ODK XForms}. In other words, this is equivalent to the following hypothetical XPath pseudo-code (whitespace added to improve structural clarity):
18957
+ * This method fetches the `text` element matching `itextID` and returns its child `value` elements,
18958
+ * which may have an optional `@form` attribute.
18959
+ *
18960
+ * The operation is conceptually similar to the following XPath query:
18957
18961
  *
18958
18962
  * ```xpath
18959
- * string(
18960
- * imaginary:itext-translation(
18961
- * xpath3-fn:environment-variable('activeLanguage')
18962
- * )
18963
- * /text[@id = $itextID]
18964
- * /value[not(@form)]
18963
+ * imaginary:itext-translation(
18964
+ * xpath3-fn:environment-variable('activeLanguage')
18965
18965
  * )
18966
+ * /text[@id = $itextID]
18967
+ * /value
18966
18968
  * ```
18967
18969
  *
18968
18970
  * Or alternately:
18969
18971
  *
18970
18972
  * ```xpath
18971
- * string(
18972
- * imaginary:itext-root()
18973
- * /translation[@lang = xpath3-fn:environment-variable('activeLanguage')]
18974
- * /text[@id = $itextID]
18975
- * /value[not(@form)]
18976
- * )
18973
+ * imaginary:itext-root()
18974
+ * /translation[@lang = xpath3-fn:environment-variable('activeLanguage')]
18975
+ * /text[@id = $itextID]
18976
+ * /value
18977
18977
  * ```
18978
- *
18979
- * @todo The above really feels like it adds some helpful clarity to how `jr:itext()` is designed to work, and the kinds of structures, state and input involved. Since there's already some discomfort around that API as specified, it's worth considering
18978
+ * Returns an array of `XFormsItextTranslationValueElement<T>`
18980
18979
  */
18981
- getDefaultTranslationText(itextID) {
18980
+ getTranslationValues(itextID) {
18982
18981
  const textElement = this.getTranslationTextElement(itextID);
18983
18982
  if (textElement == null) {
18984
- return "";
18985
- }
18986
- const { domProvider } = this;
18987
- for (const valueElement of domProvider.getChildrenByLocalName(textElement, "value")) {
18988
- if (!domProvider.hasLocalNamedAttribute(valueElement, "form")) {
18989
- return domProvider.getNodeValue(valueElement);
18990
- }
18983
+ return [];
18991
18984
  }
18992
- return "";
18985
+ return [...this.domProvider.getChildrenByLocalName(textElement, "value")];
18993
18986
  }
18994
18987
  getLanguages() {
18995
18988
  return this.languages;
@@ -19026,9 +19019,9 @@ class XFormsXPathEvaluator extends Evaluator {
19026
19019
  assertInternalXFormsXPathEvaluatorContext(context);
19027
19020
  return context.evaluator.secondaryInstancesById.get(id) ?? null;
19028
19021
  }
19029
- static getDefaultTranslationText(context, itextID) {
19022
+ static getTranslationValues(context, itextID) {
19030
19023
  assertInternalXFormsXPathEvaluatorContext(context);
19031
- return context.evaluator.itextTranslations.getDefaultTranslationText(itextID);
19024
+ return context.evaluator.itextTranslations.getTranslationValues(itextID);
19032
19025
  }
19033
19026
  rootNode;
19034
19027
  /**
@@ -19582,8 +19575,13 @@ const isTranslationFunctionCall = (syntaxNode) => {
19582
19575
  ]);
19583
19576
  };
19584
19577
  const isTranslationExpression = (expression) => {
19585
- const { rootNode } = expressionParser.parse(expression);
19586
- const functionCallNode = findTypedPrincipalExpressionNode(["function_call"], rootNode);
19578
+ let result;
19579
+ try {
19580
+ result = expressionParser.parse(expression);
19581
+ } catch {
19582
+ return false;
19583
+ }
19584
+ const functionCallNode = findTypedPrincipalExpressionNode(["function_call"], result.rootNode);
19587
19585
  if (functionCallNode == null) {
19588
19586
  return false;
19589
19587
  }
@@ -19747,77 +19745,43 @@ class DependentExpression {
19747
19745
  }
19748
19746
  }
19749
19747
 
19748
+ const isOutputElement = (element) => {
19749
+ return element.localName === "output" && element.hasAttribute("value");
19750
+ };
19750
19751
  class TextChunkExpression extends DependentExpression {
19752
+ source;
19753
+ // Set for the literal source, blank otherwise
19751
19754
  stringValue;
19752
- constructor(context, expression, options = {}) {
19753
- super(context, "string", expression, {
19755
+ constructor(context, resultType, expression, source, options = {}, literalValue = "") {
19756
+ super(context, resultType, expression, {
19754
19757
  semanticDependencies: {
19755
19758
  translations: options.isTranslated
19756
19759
  },
19757
19760
  ignoreContextReference: true
19758
19761
  });
19762
+ this.source = source;
19763
+ this.stringValue = literalValue;
19759
19764
  }
19760
- }
19761
-
19762
- class TextLiteralExpression extends TextChunkExpression {
19763
- constructor(context, stringValue) {
19764
- super(context, "null");
19765
- this.stringValue = stringValue;
19766
- }
19767
- static from(context, stringValue) {
19768
- return new this(context, stringValue);
19769
- }
19770
- source = "literal";
19771
- }
19772
-
19773
- const isOutputElement = (element) => {
19774
- return element.localName === "output" && element.hasAttribute("value");
19775
- };
19776
- class TextOutputExpression extends TextChunkExpression {
19777
- static from(context, element) {
19778
- if (isOutputElement(element)) {
19779
- return new this(context, element);
19780
- }
19781
- return null;
19782
- }
19783
- source = "output";
19784
- constructor(context, element) {
19785
- super(context, element.getAttribute("value"));
19786
- }
19787
- }
19788
-
19789
- class TextReferenceExpression extends TextChunkExpression {
19790
- static from(context, refExpression) {
19791
- return new this(context, refExpression);
19765
+ static fromLiteral(context, stringValue) {
19766
+ return new TextChunkExpression(context, "string", "null", "literal", {}, stringValue);
19792
19767
  }
19793
- source = "reference";
19794
- constructor(context, refExpression) {
19795
- super(context, refExpression);
19768
+ static fromReference(context, ref) {
19769
+ return new TextChunkExpression(context, "string", ref, "reference");
19796
19770
  }
19797
- }
19798
-
19799
- class TextTranslationExpression extends TextChunkExpression {
19800
- static fromMessage(context, maybeExpression) {
19801
- try {
19802
- expressionParser.parse(maybeExpression);
19803
- } catch {
19771
+ static fromOutput(context, element) {
19772
+ if (!isOutputElement(element)) {
19804
19773
  return null;
19805
19774
  }
19806
- if (isTranslationExpression(maybeExpression)) {
19807
- return new this(context, maybeExpression);
19808
- }
19809
- return null;
19775
+ return new TextChunkExpression(context, "string", element.getAttribute("value"), "output");
19810
19776
  }
19811
- static from(context, maybeExpression) {
19777
+ static fromTranslation(context, maybeExpression) {
19812
19778
  if (isTranslationExpression(maybeExpression)) {
19813
- return new this(context, maybeExpression);
19779
+ return new TextChunkExpression(context, "nodes", maybeExpression, "translation", {
19780
+ isTranslated: true
19781
+ });
19814
19782
  }
19815
19783
  return null;
19816
19784
  }
19817
- source = "translation";
19818
- constructor(context, expression) {
19819
- super(context, expression, { isTranslated: true });
19820
- }
19821
19785
  }
19822
19786
 
19823
19787
  const absolutePathNodeList = (pathNode) => {
@@ -20066,16 +20030,20 @@ class TextElementDefinition extends TextRangeDefinition {
20066
20030
  if (refExpression == null) {
20067
20031
  this.chunks = Array.from(sourceNode.childNodes).flatMap((childNode) => {
20068
20032
  if (isElementNode(childNode)) {
20069
- return TextOutputExpression.from(context, childNode) ?? [];
20033
+ return TextChunkExpression.fromOutput(context, childNode) ?? [];
20070
20034
  }
20071
20035
  if (isTextNode(childNode)) {
20072
- return TextLiteralExpression.from(context, childNode.data);
20036
+ return TextChunkExpression.fromLiteral(context, childNode.data);
20073
20037
  }
20074
20038
  return [];
20075
20039
  });
20076
20040
  } else {
20077
- const refChunk = TextTranslationExpression.from(context, refExpression) ?? TextReferenceExpression.from(context, refExpression);
20078
- this.chunks = [refChunk];
20041
+ const expression = TextChunkExpression.fromTranslation(context, refExpression);
20042
+ if (expression != null) {
20043
+ this.chunks = [expression];
20044
+ } else {
20045
+ this.chunks = [TextChunkExpression.fromReference(context, refExpression)];
20046
+ }
20079
20047
  }
20080
20048
  }
20081
20049
  }
@@ -20327,8 +20295,12 @@ class ItemsetLabelDefinition extends TextRangeDefinition {
20327
20295
  if (refExpression == null) {
20328
20296
  throw new Error("<itemset><label> missing ref attribute");
20329
20297
  }
20330
- const refChunk = TextTranslationExpression.from(this, refExpression) ?? TextReferenceExpression.from(this, refExpression);
20331
- this.chunks = [refChunk];
20298
+ const expression = TextChunkExpression.fromTranslation(this, refExpression);
20299
+ if (expression != null) {
20300
+ this.chunks = [expression];
20301
+ } else {
20302
+ this.chunks = [TextChunkExpression.fromReference(this, refExpression)];
20303
+ }
20332
20304
  }
20333
20305
  }
20334
20306
 
@@ -21236,8 +21208,12 @@ class MessageDefinition extends TextRangeDefinition {
21236
21208
  constructor(bind, role, message) {
21237
21209
  super(bind.form, bind, null);
21238
21210
  this.role = role;
21239
- const chunk = TextTranslationExpression.fromMessage(this, message) ?? TextLiteralExpression.from(this, message);
21240
- this.chunks = [chunk];
21211
+ const expression = TextChunkExpression.fromTranslation(this, message);
21212
+ if (expression != null) {
21213
+ this.chunks = [expression];
21214
+ } else {
21215
+ this.chunks = [TextChunkExpression.fromLiteral(this, message)];
21216
+ }
21241
21217
  }
21242
21218
  static from(bind, type) {
21243
21219
  const message = bind.bindElement.getAttributeNS(JAVAROSA_NAMESPACE_URI$1, type);
@@ -29122,10 +29098,11 @@ class TextChunk {
29122
29098
  }
29123
29099
 
29124
29100
  class TextRange {
29125
- constructor(origin, role, chunks) {
29101
+ constructor(origin, role, chunks, mediaSources) {
29126
29102
  this.origin = origin;
29127
29103
  this.role = role;
29128
29104
  this.chunks = chunks;
29105
+ this.mediaSources = mediaSources;
29129
29106
  }
29130
29107
  *[Symbol.iterator]() {
29131
29108
  yield* this.chunks;
@@ -29136,44 +29113,56 @@ class TextRange {
29136
29113
  get asString() {
29137
29114
  return this.chunks.map((chunk) => chunk.asString).join("");
29138
29115
  }
29116
+ get imageSource() {
29117
+ return this.mediaSources?.image;
29118
+ }
29119
+ get audioSource() {
29120
+ return this.mediaSources?.audio;
29121
+ }
29122
+ get videoSource() {
29123
+ return this.mediaSources?.video;
29124
+ }
29139
29125
  }
29140
29126
 
29141
- const createComputedTextChunk = (context, textSource) => {
29142
- const { source } = textSource;
29143
- if (source === "literal") {
29144
- const { stringValue } = textSource;
29145
- return {
29146
- source,
29147
- getText: () => stringValue
29148
- };
29149
- }
29150
- return context.scope.runTask(() => {
29151
- const getText = createComputedExpression(context, textSource, {
29152
- defaultValue: ""
29153
- });
29154
- return {
29155
- source,
29156
- getText
29157
- };
29158
- });
29159
- };
29160
- const createTextChunks = (context, textSources) => {
29161
- return context.scope.runTask(() => {
29162
- const chunkComputations = textSources.map((textSource) => {
29163
- return createComputedTextChunk(context, textSource);
29164
- });
29165
- return createMemo(() => {
29166
- return chunkComputations.map(({ source, getText }) => {
29167
- return new TextChunk(context, source, getText());
29168
- });
29127
+ const createTextChunks = (context, chunkExpressions) => {
29128
+ return createMemo(() => {
29129
+ const chunks = [];
29130
+ const mediaSources = {};
29131
+ chunkExpressions.forEach((chunkExpression) => {
29132
+ if (chunkExpression.source === "literal") {
29133
+ chunks.push(new TextChunk(context, chunkExpression.source, chunkExpression.stringValue));
29134
+ return;
29135
+ }
29136
+ const computed = createComputedExpression(context, chunkExpression)();
29137
+ if (typeof computed === "string") {
29138
+ chunks.push(new TextChunk(context, chunkExpression.source, computed));
29139
+ return;
29140
+ } else {
29141
+ computed.forEach((itextForm) => {
29142
+ if (isEngineXPathElement(itextForm) && itextForm instanceof StaticElement) {
29143
+ const formAttribute = itextForm.getAttributeValue("form");
29144
+ if (!formAttribute) {
29145
+ const defaultFormValue = itextForm.getXPathValue();
29146
+ chunks.push(new TextChunk(context, chunkExpression.source, defaultFormValue));
29147
+ } else if (["image", "video", "audio"].includes(formAttribute)) {
29148
+ const formValue = itextForm.getXPathValue();
29149
+ if (JRResourceURL.isJRResourceReference(formValue)) {
29150
+ mediaSources[formAttribute] = JRResourceURL.from(formValue);
29151
+ }
29152
+ }
29153
+ }
29154
+ });
29155
+ }
29169
29156
  });
29157
+ return { chunks, mediaSources };
29170
29158
  });
29171
29159
  };
29172
29160
  const createTextRange = (context, role, definition) => {
29173
29161
  return context.scope.runTask(() => {
29174
- const getTextChunks = createTextChunks(context, definition.chunks);
29162
+ const textChunks = createTextChunks(context, definition.chunks);
29175
29163
  return createMemo(() => {
29176
- return new TextRange("form", role, getTextChunks());
29164
+ const chunks = textChunks();
29165
+ return new TextRange("form", role, chunks.chunks, chunks.mediaSources);
29177
29166
  });
29178
29167
  });
29179
29168
  };
@@ -29340,8 +29329,7 @@ const createInstanceValueState = (context) => {
29340
29329
  const engineViolationMessage = (context, role) => {
29341
29330
  const messageText = VALIDATION_TEXT[role];
29342
29331
  const chunk = new TextChunk(context, "literal", messageText);
29343
- const message = new TextRange("engine", role, [chunk]);
29344
- return () => message;
29332
+ return () => new TextRange("engine", role, [chunk]);
29345
29333
  };
29346
29334
  const createViolationMessage = (context, role, definition) => {
29347
29335
  if (definition == null) {
@@ -30518,6 +30506,9 @@ class SelectControl extends ValueNode {
30518
30506
  this.appearances = definition.bodyElement.appearances;
30519
30507
  this.selectType = definition.bodyElement.type;
30520
30508
  const valueOptions = createItemCollection(this);
30509
+ const isSelectWithImages = this.scope.runTask(() => {
30510
+ return createMemo(() => valueOptions().some((item) => !!item.label.imageSource));
30511
+ });
30521
30512
  const mapOptionsByValue = this.scope.runTask(() => {
30522
30513
  return createMemo(() => {
30523
30514
  return new Map(valueOptions().map((item) => [item.value, item]));
@@ -30552,7 +30543,8 @@ class SelectControl extends ValueNode {
30552
30543
  children: null,
30553
30544
  valueOptions,
30554
30545
  value: valueState,
30555
- instanceValue: this.getInstanceValue
30546
+ instanceValue: this.getInstanceValue,
30547
+ isSelectWithImages
30556
30548
  },
30557
30549
  this.instanceConfig
30558
30550
  );