@getodk/xforms-engine 0.12.0 → 0.13.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 (33) hide show
  1. package/dist/client/TextRange.d.ts +0 -9
  2. package/dist/index.js +227 -100
  3. package/dist/index.js.map +1 -1
  4. package/dist/instance/RankControl.d.ts +3 -2
  5. package/dist/instance/SelectControl.d.ts +3 -2
  6. package/dist/parse/body/control/ItemsetDefinition.d.ts +1 -1
  7. package/dist/parse/expression/BindComputationExpression.d.ts +1 -1
  8. package/dist/parse/expression/ItemsetNodesetExpression.d.ts +1 -2
  9. package/dist/parse/expression/TextChunkExpression.d.ts +9 -7
  10. package/dist/parse/expression/abstract/DependentExpression.d.ts +1 -15
  11. package/dist/parse/model/ModelDefinition.d.ts +6 -1
  12. package/dist/parse/model/generateItextChunks.d.ts +5 -0
  13. package/dist/parse/xpath/semantic-analysis.d.ts +1 -0
  14. package/dist/solid.js +227 -100
  15. package/dist/solid.js.map +1 -1
  16. package/package.json +2 -2
  17. package/src/client/TextRange.ts +0 -9
  18. package/src/instance/RankControl.ts +8 -2
  19. package/src/instance/SelectControl.ts +8 -2
  20. package/src/lib/reactivity/text/createTextRange.ts +30 -30
  21. package/src/parse/body/control/ItemsetDefinition.ts +2 -2
  22. package/src/parse/expression/BindComputationExpression.ts +2 -7
  23. package/src/parse/expression/ItemsetNodesetExpression.ts +2 -3
  24. package/src/parse/expression/ItemsetValueExpression.ts +1 -1
  25. package/src/parse/expression/RepeatCountControlExpression.ts +4 -4
  26. package/src/parse/expression/TextChunkExpression.ts +25 -35
  27. package/src/parse/expression/abstract/DependentExpression.ts +2 -38
  28. package/src/parse/model/ModelDefinition.ts +13 -0
  29. package/src/parse/model/generateItextChunks.ts +61 -0
  30. package/src/parse/text/ItemsetLabelDefinition.ts +4 -4
  31. package/src/parse/text/MessageDefinition.ts +4 -4
  32. package/src/parse/text/abstract/TextElementDefinition.ts +6 -7
  33. package/src/parse/xpath/semantic-analysis.ts +37 -8
@@ -47,15 +47,6 @@ import { ActiveLanguage } from './FormLanguage.ts';
47
47
  * - `h:body//hint/@ref[not(is-translation-expr())]`
48
48
  *
49
49
  * (See notes above for clarification of `is-translation-expr()`.)
50
- *
51
- * @todo It's unclear whether this will all become simpler or more compelex when
52
- * we add support for outputs in translations. In theory, the actual translation
53
- * `<text>` nodes map quite well to the `TextRange` concept (i.e. they are a
54
- * range of static and output chunks, just like labels and hints). The potential
55
- * for complications arise from XPath implementation details being largely
56
- * opaque (as in, the `jr:itext` implementation is encapsulated in the `xpath`
57
- * package, and the engine doesn't really deal with itext translations at the
58
- * node level at all).
59
50
  */
60
51
  export type TextChunkSource = 'literal' | 'output' | 'reference' | 'translation';
61
52
  /**
package/dist/index.js CHANGED
@@ -11576,7 +11576,45 @@ const nodeSet = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
11576
11576
  itext
11577
11577
  }, Symbol.toStringTag, { value: 'Module' }));
11578
11578
 
11579
- const jr$2 = new FunctionLibrary(JAVAROSA_NAMESPACE_URI, [...Object.values(nodeSet)]);
11579
+ const choiceName = new StringFunction(
11580
+ "choice-name",
11581
+ [
11582
+ { arityType: "required", typeHint: "string" },
11583
+ { arityType: "required", typeHint: "string" }
11584
+ ],
11585
+ (context, [nodeExpression, valueExpression]) => {
11586
+ const node = nodeExpression.evaluate(context).toString();
11587
+ const value = valueExpression.evaluate(context).toString();
11588
+ const [contextNode] = context.contextNodes;
11589
+ const { domProvider } = context;
11590
+ let nodes;
11591
+ if (contextNode && domProvider.isElement(contextNode)) {
11592
+ nodes = context.evaluator.evaluateNodes(value, { contextNode });
11593
+ } else {
11594
+ nodes = context.evaluator.evaluateNodes(value);
11595
+ }
11596
+ const firstNode = nodes?.[0];
11597
+ if (!firstNode) {
11598
+ return "";
11599
+ }
11600
+ if (!("getChoiceName" in firstNode)) {
11601
+ throw new Error(
11602
+ `Evaluating 'jr:choice-name' on element '${value}' which has no possible choices.`
11603
+ );
11604
+ }
11605
+ return firstNode.getChoiceName(node) ?? "";
11606
+ }
11607
+ );
11608
+
11609
+ const select$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
11610
+ __proto__: null,
11611
+ choiceName
11612
+ }, Symbol.toStringTag, { value: 'Module' }));
11613
+
11614
+ const jr$2 = new FunctionLibrary(JAVAROSA_NAMESPACE_URI, [
11615
+ ...Object.values(nodeSet),
11616
+ ...Object.values(select$1)
11617
+ ]);
11580
11618
 
11581
11619
  const booleanFromString = new BooleanFunction(
11582
11620
  "boolean-from-string",
@@ -19007,6 +19045,10 @@ const hex = /*#__PURE__*/_mergeNamespaces({
19007
19045
  default: encHex
19008
19046
  }, [encHexExports]);
19009
19047
 
19048
+ const base64Decode$1 = (base64Input) => {
19049
+ return new TextDecoder().decode(Uint8Array.from(atob(base64Input), (m) => m.charCodeAt(0)));
19050
+ };
19051
+
19010
19052
  const toStrings = (context, expressions) => {
19011
19053
  return expressions.flatMap((arg) => {
19012
19054
  const result = arg.evaluate(context);
@@ -19018,6 +19060,17 @@ const toStrings = (context, expressions) => {
19018
19060
  });
19019
19061
  };
19020
19062
 
19063
+ const base64Decode = new StringFunction(
19064
+ "base64-decode",
19065
+ [{ arityType: "required", typeHint: "string" }],
19066
+ (context, [base64Expression]) => {
19067
+ try {
19068
+ return base64Decode$1(base64Expression.evaluate(context).toString());
19069
+ } catch {
19070
+ return "";
19071
+ }
19072
+ }
19073
+ );
19021
19074
  const coalesce = new StringFunction(
19022
19075
  "coalesce",
19023
19076
  [
@@ -19107,6 +19160,23 @@ const join = new StringFunction(
19107
19160
  return strings.join(glue);
19108
19161
  }
19109
19162
  );
19163
+ const pulldata = new StringFunction(
19164
+ "pulldata",
19165
+ [
19166
+ { arityType: "required", typeHint: "string" },
19167
+ { arityType: "required", typeHint: "string" },
19168
+ { arityType: "required", typeHint: "string" },
19169
+ { arityType: "required", typeHint: "string" }
19170
+ ],
19171
+ (context, [instanceExpression, desiredElementExpression, queryElementExpression, queryExpression]) => {
19172
+ const instanceId = instanceExpression.evaluate(context).toString();
19173
+ const desiredElement = desiredElementExpression.evaluate(context).toString();
19174
+ const queryElement = queryElementExpression.evaluate(context).toString();
19175
+ const query = queryExpression.evaluate(context).toString();
19176
+ const expr = `instance('${instanceId}')/root/item[${queryElement}='${query}']/${desiredElement}`;
19177
+ return context.evaluator.evaluateString(expr);
19178
+ }
19179
+ );
19110
19180
  const regex = new BooleanFunction(
19111
19181
  "regex",
19112
19182
  [
@@ -19185,11 +19255,13 @@ const uuid = new StringFunction(
19185
19255
 
19186
19256
  const string = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
19187
19257
  __proto__: null,
19258
+ base64Decode,
19188
19259
  coalesce,
19189
19260
  concat,
19190
19261
  digest,
19191
19262
  endsWith,
19192
19263
  join,
19264
+ pulldata,
19193
19265
  regex,
19194
19266
  substr,
19195
19267
  uuid
@@ -19903,18 +19975,32 @@ const isTranslationFunctionCall = (syntaxNode) => {
19903
19975
  ANY_ARGUMENT_TYPE
19904
19976
  ]);
19905
19977
  };
19906
- const isTranslationExpression = (expression) => {
19978
+ const findFunctionPrincipalExpressionNode = (expression) => {
19907
19979
  let result;
19908
19980
  try {
19909
19981
  result = expressionParser.parse(expression);
19910
19982
  } catch {
19911
- return false;
19983
+ return null;
19912
19984
  }
19913
19985
  const functionCallNode = findTypedPrincipalExpressionNode(["function_call"], result.rootNode);
19914
19986
  if (functionCallNode == null) {
19915
- return false;
19987
+ return null;
19916
19988
  }
19917
- return isTranslationFunctionCall(functionCallNode);
19989
+ return functionCallNode;
19990
+ };
19991
+ const getTranslationExpression = (expression) => {
19992
+ const functionCallNode = findFunctionPrincipalExpressionNode(expression);
19993
+ if (!functionCallNode) {
19994
+ return null;
19995
+ }
19996
+ if (!isTranslationFunctionCall(functionCallNode)) {
19997
+ return null;
19998
+ }
19999
+ const arg = functionCallNode.children.find((child) => child.type === "argument");
20000
+ if (!arg) {
20001
+ return null;
20002
+ }
20003
+ return arg.text;
19918
20004
  };
19919
20005
  const isCurrentFunctionCall = (syntaxNode) => {
19920
20006
  return isCallToLocalNamedFunction(syntaxNode, "current") && hasCallSignature(syntaxNode, []);
@@ -20034,7 +20120,7 @@ const evaluatorMethodsByResultType = {
20034
20120
  string: "evaluateString"
20035
20121
  };
20036
20122
  class DependentExpression {
20037
- constructor(context, resultType, expression, options = {}) {
20123
+ constructor(resultType, expression) {
20038
20124
  this.resultType = resultType;
20039
20125
  this.expression = expression;
20040
20126
  if (resultType === "boolean" && isConstantTruthyExpression(expression)) {
@@ -20048,16 +20134,6 @@ class DependentExpression {
20048
20134
  this.constantExpression = null;
20049
20135
  }
20050
20136
  this.evaluatorMethod = evaluatorMethodsByResultType[resultType];
20051
- const {
20052
- semanticDependencies = {
20053
- translations: false
20054
- }
20055
- } = options;
20056
- const isTranslated = semanticDependencies.translations && isTranslationExpression(expression);
20057
- if (isTranslated) {
20058
- this.isTranslated = true;
20059
- context.isTranslated = true;
20060
- }
20061
20137
  }
20062
20138
  isTranslated = false;
20063
20139
  evaluatorMethod;
@@ -20081,33 +20157,32 @@ class TextChunkExpression extends DependentExpression {
20081
20157
  source;
20082
20158
  // Set for the literal source, blank otherwise
20083
20159
  stringValue;
20084
- constructor(context, resultType, expression, source, options = {}, literalValue = "") {
20085
- super(context, resultType, expression, {
20086
- semanticDependencies: {
20087
- translations: options.isTranslated
20088
- },
20089
- ignoreContextReference: true
20090
- });
20160
+ resourceType;
20161
+ constructor(resultType, expression, source, literalValue = "", options = {}) {
20162
+ super(resultType, expression);
20163
+ this.resourceType = options.type ?? null;
20091
20164
  this.source = source;
20092
20165
  this.stringValue = literalValue;
20093
20166
  }
20094
- static fromLiteral(context, stringValue) {
20095
- return new TextChunkExpression(context, "string", "null", "literal", {}, stringValue);
20167
+ static fromLiteral(stringValue) {
20168
+ return new TextChunkExpression("string", "null", "literal", stringValue);
20096
20169
  }
20097
- static fromReference(context, ref) {
20098
- return new TextChunkExpression(context, "string", ref, "reference");
20170
+ static fromReference(ref) {
20171
+ return new TextChunkExpression("string", ref, "reference");
20099
20172
  }
20100
- static fromOutput(context, element) {
20173
+ static fromOutput(element) {
20101
20174
  if (!isOutputElement(element)) {
20102
20175
  return null;
20103
20176
  }
20104
- return new TextChunkExpression(context, "string", element.getAttribute("value"), "output");
20177
+ return new TextChunkExpression("string", element.getAttribute("value"), "output");
20105
20178
  }
20106
- static fromTranslation(context, maybeExpression) {
20107
- if (isTranslationExpression(maybeExpression)) {
20108
- return new TextChunkExpression(context, "nodes", maybeExpression, "translation", {
20109
- isTranslated: true
20110
- });
20179
+ static fromResource(url, type) {
20180
+ return new TextChunkExpression("string", "null", "literal", url, { type });
20181
+ }
20182
+ static fromTranslation(maybeExpression) {
20183
+ const translationExpression = getTranslationExpression(maybeExpression);
20184
+ if (translationExpression) {
20185
+ return new TextChunkExpression("nodes", translationExpression, "translation");
20111
20186
  }
20112
20187
  return null;
20113
20188
  }
@@ -20354,24 +20429,23 @@ class TextElementDefinition extends TextRangeDefinition {
20354
20429
  chunks;
20355
20430
  constructor(form, owner, sourceNode) {
20356
20431
  super(form, owner, sourceNode);
20357
- const context = this;
20358
20432
  const refExpression = parseNodesetReference(owner, sourceNode, "ref");
20359
20433
  if (refExpression == null) {
20360
20434
  this.chunks = Array.from(sourceNode.childNodes).flatMap((childNode) => {
20361
20435
  if (isElementNode(childNode)) {
20362
- return TextChunkExpression.fromOutput(context, childNode) ?? [];
20436
+ return TextChunkExpression.fromOutput(childNode) ?? [];
20363
20437
  }
20364
20438
  if (isTextNode(childNode)) {
20365
- return TextChunkExpression.fromLiteral(context, childNode.data);
20439
+ return TextChunkExpression.fromLiteral(childNode.data);
20366
20440
  }
20367
20441
  return [];
20368
20442
  });
20369
20443
  } else {
20370
- const expression = TextChunkExpression.fromTranslation(context, refExpression);
20371
- if (expression != null) {
20372
- this.chunks = [expression];
20444
+ const translationChunk = TextChunkExpression.fromTranslation(refExpression);
20445
+ if (translationChunk) {
20446
+ this.chunks = [translationChunk];
20373
20447
  } else {
20374
- this.chunks = [TextChunkExpression.fromReference(context, refExpression)];
20448
+ this.chunks = [TextChunkExpression.fromReference(refExpression)];
20375
20449
  }
20376
20450
  }
20377
20451
  }
@@ -20596,14 +20670,14 @@ class RangeControlDefinition extends ControlDefinition {
20596
20670
  }
20597
20671
 
20598
20672
  class ItemsetNodesetExpression extends DependentExpression {
20599
- constructor(itemset, nodesetExpression) {
20600
- super(itemset.parent, "nodes", nodesetExpression);
20673
+ constructor(nodesetExpression) {
20674
+ super("nodes", nodesetExpression);
20601
20675
  }
20602
20676
  }
20603
20677
 
20604
20678
  class ItemsetValueExpression extends DependentExpression {
20605
20679
  constructor(itemset, expression) {
20606
- super(itemset, "string", expression);
20680
+ super("string", expression);
20607
20681
  this.itemset = itemset;
20608
20682
  }
20609
20683
  }
@@ -20624,11 +20698,11 @@ class ItemsetLabelDefinition extends TextRangeDefinition {
20624
20698
  if (refExpression == null) {
20625
20699
  throw new Error("<itemset><label> missing ref attribute");
20626
20700
  }
20627
- const expression = TextChunkExpression.fromTranslation(this, refExpression);
20628
- if (expression != null) {
20629
- this.chunks = [expression];
20701
+ const translationChunk = TextChunkExpression.fromTranslation(refExpression);
20702
+ if (translationChunk) {
20703
+ this.chunks = [translationChunk];
20630
20704
  } else {
20631
- this.chunks = [TextChunkExpression.fromReference(this, refExpression)];
20705
+ this.chunks = [TextChunkExpression.fromReference(refExpression)];
20632
20706
  }
20633
20707
  }
20634
20708
  }
@@ -20638,7 +20712,7 @@ class ItemsetDefinition extends BodyElementDefinition {
20638
20712
  super(form, parent, element);
20639
20713
  this.parent = parent;
20640
20714
  const nodesetExpression = parseNodesetReference(parent, element, "nodeset");
20641
- this.nodes = new ItemsetNodesetExpression(this, nodesetExpression);
20715
+ this.nodes = new ItemsetNodesetExpression(nodesetExpression);
20642
20716
  this.reference = nodesetExpression;
20643
20717
  const valueElement = getValueElement(element);
20644
20718
  if (valueElement == null) {
@@ -21457,6 +21531,64 @@ const parseStaticDocumentFromDOMSubtree = (subtreeRootElement, options = {}) =>
21457
21531
  });
21458
21532
  };
21459
21533
 
21534
+ const JR_RESOURCE_URL_PROTOCOL = "jr:";
21535
+ const ALL_RESOURCE_TYPES = ["image", "audio", "video"];
21536
+ const isResourceType = (string) => {
21537
+ return ALL_RESOURCE_TYPES.includes(string);
21538
+ };
21539
+ class JRResourceURL extends URL {
21540
+ static create(category, fileName) {
21541
+ return new this(`jr://${category}/${fileName}`);
21542
+ }
21543
+ static from(url) {
21544
+ return new this(url);
21545
+ }
21546
+ static isJRResourceReference(reference) {
21547
+ return reference?.startsWith(JR_RESOURCE_URL_PROTOCOL) ?? false;
21548
+ }
21549
+ constructor(url) {
21550
+ super(url);
21551
+ }
21552
+ }
21553
+
21554
+ const generateChunk = (node) => {
21555
+ if (isElementNode(node)) {
21556
+ return TextChunkExpression.fromOutput(node);
21557
+ }
21558
+ if (isTextNode(node)) {
21559
+ const formAttribute = node.parentElement.getAttribute("form");
21560
+ if (isResourceType(formAttribute)) {
21561
+ return TextChunkExpression.fromResource(node.data, formAttribute);
21562
+ }
21563
+ return TextChunkExpression.fromLiteral(node.data);
21564
+ }
21565
+ return null;
21566
+ };
21567
+ const generateChunksForValues = (valueElement) => {
21568
+ return Array.from(valueElement.childNodes).map((node) => generateChunk(node)).filter((chunk) => chunk !== null);
21569
+ };
21570
+ const generateChunksForTranslation = (textElement) => {
21571
+ return Array.from(textElement.childNodes).flatMap(
21572
+ (valueElement) => generateChunksForValues(valueElement)
21573
+ );
21574
+ };
21575
+ const generateChunksForLanguage = (translationElement) => {
21576
+ return new Map(
21577
+ Array.from(translationElement.children).map((textElement) => {
21578
+ const itextId = textElement.getAttribute("id");
21579
+ return [itextId, generateChunksForTranslation(textElement)];
21580
+ })
21581
+ );
21582
+ };
21583
+ const generateItextChunks = (translationElements) => {
21584
+ return new Map(
21585
+ translationElements.map((translationElement) => {
21586
+ const lang = translationElement.getAttribute("lang");
21587
+ return [lang, generateChunksForLanguage(translationElement)];
21588
+ })
21589
+ );
21590
+ };
21591
+
21460
21592
  const assertItextTranslationsDefinitionEntry = ([
21461
21593
  key,
21462
21594
  root
@@ -21503,8 +21635,7 @@ const bindComputationResultTypes = {
21503
21635
  saveIncomplete: "boolean"
21504
21636
  };
21505
21637
  class BindComputationExpression extends DependentExpression {
21506
- constructor(bind, computation, expression) {
21507
- const ignoreContextReference = computation === "constraint";
21638
+ constructor(computation, expression) {
21508
21639
  let isDefaultExpression;
21509
21640
  let resolvedExpression;
21510
21641
  if (expression == null) {
@@ -21517,9 +21648,7 @@ class BindComputationExpression extends DependentExpression {
21517
21648
  isDefaultExpression = false;
21518
21649
  resolvedExpression = expression;
21519
21650
  }
21520
- super(bind, bindComputationResultTypes[computation], resolvedExpression, {
21521
- ignoreContextReference
21522
- });
21651
+ super(bindComputationResultTypes[computation], resolvedExpression);
21523
21652
  this.computation = computation;
21524
21653
  this.isDefaultExpression = isDefaultExpression;
21525
21654
  }
@@ -21528,7 +21657,7 @@ class BindComputationExpression extends DependentExpression {
21528
21657
  if (expression == null) {
21529
21658
  return null;
21530
21659
  }
21531
- return new this(bind, computation, expression);
21660
+ return new this(computation, expression);
21532
21661
  }
21533
21662
  isDefaultExpression;
21534
21663
  }
@@ -21537,11 +21666,11 @@ class MessageDefinition extends TextRangeDefinition {
21537
21666
  constructor(bind, role, message) {
21538
21667
  super(bind.form, bind, null);
21539
21668
  this.role = role;
21540
- const expression = TextChunkExpression.fromTranslation(this, message);
21541
- if (expression != null) {
21542
- this.chunks = [expression];
21669
+ const translationChunk = TextChunkExpression.fromTranslation(message);
21670
+ if (translationChunk) {
21671
+ this.chunks = [translationChunk];
21543
21672
  } else {
21544
- this.chunks = [TextChunkExpression.fromLiteral(this, message)];
21673
+ this.chunks = [TextChunkExpression.fromLiteral(message)];
21545
21674
  }
21546
21675
  }
21547
21676
  static from(bind, type) {
@@ -26409,16 +26538,16 @@ class RepeatCountControlExpression extends DependentExpression {
26409
26538
  static from(bodyElement, initialCount) {
26410
26539
  const { countExpression, noAddRemoveExpression } = bodyElement;
26411
26540
  if (countExpression != null) {
26412
- return new this(bodyElement, countExpression);
26541
+ return new this(countExpression);
26413
26542
  }
26414
26543
  if (noAddRemoveExpression != null && isConstantTruthyExpression(noAddRemoveExpression)) {
26415
26544
  const fixedCountExpression = String(Math.max(initialCount, 1));
26416
- return new this(bodyElement, fixedCountExpression);
26545
+ return new this(fixedCountExpression);
26417
26546
  }
26418
26547
  return null;
26419
26548
  }
26420
- constructor(context, expression) {
26421
- super(context, "number", expression);
26549
+ constructor(expression) {
26550
+ super("number", expression);
26422
26551
  }
26423
26552
  }
26424
26553
 
@@ -26685,12 +26814,14 @@ class ModelDefinition {
26685
26814
  this.root = new RootDefinition(form, this, submission, form.body.classes);
26686
26815
  this.nodes = nodeDefinitionMap(this.root);
26687
26816
  this.itextTranslations = ItextTranslationsDefinition.from(form.xformDOM);
26817
+ this.itextChunks = generateItextChunks(form.xformDOM.itextTranslationElements);
26688
26818
  }
26689
26819
  binds;
26690
26820
  root;
26691
26821
  nodes;
26692
26822
  instance;
26693
26823
  itextTranslations;
26824
+ itextChunks;
26694
26825
  getNodeDefinition(nodeset) {
26695
26826
  const definition = this.nodes.get(nodeset);
26696
26827
  if (definition == null) {
@@ -26709,6 +26840,10 @@ class ModelDefinition {
26709
26840
  const { form, ...rest } = this;
26710
26841
  return rest;
26711
26842
  }
26843
+ getTranslationChunks(itextId, activeLanguage) {
26844
+ const languageMap = this.itextChunks.get(activeLanguage.language);
26845
+ return languageMap?.get(itextId) ?? [];
26846
+ }
26712
26847
  }
26713
26848
 
26714
26849
  class XFormDefinition {
@@ -26734,22 +26869,6 @@ class XFormDefinition {
26734
26869
  model;
26735
26870
  }
26736
26871
 
26737
- const JR_RESOURCE_URL_PROTOCOL = "jr:";
26738
- class JRResourceURL extends URL {
26739
- static create(category, fileName) {
26740
- return new this(`jr://${category}/${fileName}`);
26741
- }
26742
- static from(url) {
26743
- return new this(url);
26744
- }
26745
- static isJRResourceReference(reference) {
26746
- return reference?.startsWith(JR_RESOURCE_URL_PROTOCOL) ?? false;
26747
- }
26748
- constructor(url) {
26749
- super(url);
26750
- }
26751
- }
26752
-
26753
26872
  const assertSecondaryInstanceDefinition = ({ root }) => {
26754
26873
  const id = root.getAttributeValue("id");
26755
26874
  if (id == null) {
@@ -29454,42 +29573,42 @@ class TextRange {
29454
29573
  }
29455
29574
  }
29456
29575
 
29457
- const createTextChunks = (context, chunkExpressions) => {
29576
+ const createTextChunks = (context, definition) => {
29458
29577
  return createMemo(() => {
29459
29578
  const chunks = [];
29460
29579
  const mediaSources = {};
29580
+ let chunkExpressions;
29581
+ if (definition.chunks[0]?.source === "translation") {
29582
+ const itextId = context.evaluator.evaluateString(definition.chunks[0].toString(), {
29583
+ contextNode: context.contextNode
29584
+ });
29585
+ chunkExpressions = definition.form.model.getTranslationChunks(
29586
+ itextId,
29587
+ context.getActiveLanguage()
29588
+ );
29589
+ } else {
29590
+ chunkExpressions = definition.chunks;
29591
+ }
29461
29592
  chunkExpressions.forEach((chunkExpression) => {
29593
+ if (chunkExpression.resourceType) {
29594
+ mediaSources[chunkExpression.resourceType] = JRResourceURL.from(
29595
+ chunkExpression.stringValue
29596
+ );
29597
+ return;
29598
+ }
29462
29599
  if (chunkExpression.source === "literal") {
29463
29600
  chunks.push(new TextChunk(context, chunkExpression.source, chunkExpression.stringValue));
29464
29601
  return;
29465
29602
  }
29466
29603
  const computed = createComputedExpression(context, chunkExpression)();
29467
- if (typeof computed === "string") {
29468
- chunks.push(new TextChunk(context, chunkExpression.source, computed));
29469
- return;
29470
- } else {
29471
- computed.forEach((itextForm) => {
29472
- if (isEngineXPathElement(itextForm) && itextForm instanceof StaticElement) {
29473
- const formAttribute = itextForm.getAttributeValue("form");
29474
- if (!formAttribute) {
29475
- const defaultFormValue = itextForm.getXPathValue();
29476
- chunks.push(new TextChunk(context, chunkExpression.source, defaultFormValue));
29477
- } else if (["image", "video", "audio"].includes(formAttribute)) {
29478
- const formValue = itextForm.getXPathValue();
29479
- if (JRResourceURL.isJRResourceReference(formValue)) {
29480
- mediaSources[formAttribute] = JRResourceURL.from(formValue);
29481
- }
29482
- }
29483
- }
29484
- });
29485
- }
29604
+ chunks.push(new TextChunk(context, chunkExpression.source, computed));
29486
29605
  });
29487
29606
  return { chunks, mediaSources };
29488
29607
  });
29489
29608
  };
29490
29609
  const createTextRange = (context, role, definition) => {
29491
29610
  return context.scope.runTask(() => {
29492
- const textChunks = createTextChunks(context, definition.chunks);
29611
+ const textChunks = createTextChunks(context, definition);
29493
29612
  return createMemo(() => {
29494
29613
  const chunks = textChunks();
29495
29614
  return new TextRange("form", role, chunks.chunks, chunks.mediaSources);
@@ -30368,6 +30487,10 @@ class RankControl extends ValueNode {
30368
30487
  this.setValueState(valuesInOrder);
30369
30488
  return this.root;
30370
30489
  }
30490
+ getChoiceName(value) {
30491
+ const option = this.mapOptionsByValue().get(value);
30492
+ return option?.label?.asString ?? null;
30493
+ }
30371
30494
  }
30372
30495
 
30373
30496
  const insertAtIndex = (currentValues, insertionIndex, newValues) => {
@@ -30932,6 +31055,10 @@ class SelectControl extends ValueNode {
30932
31055
  this.setValueState(effectiveValues);
30933
31056
  return this.root;
30934
31057
  }
31058
+ getChoiceName(value) {
31059
+ const option = this.mapOptionsByValue().get(value);
31060
+ return option?.label?.asString ?? null;
31061
+ }
30935
31062
  }
30936
31063
 
30937
31064
  class Subtree extends DescendantNode {