@jinntec/fore 1.0.0-5 → 1.0.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 (63) hide show
  1. package/README.md +6 -27
  2. package/dist/fore-dev.js +43 -0
  3. package/dist/fore-dev.js.map +1 -0
  4. package/dist/fore.js +37 -0
  5. package/dist/fore.js.map +1 -0
  6. package/index.js +2 -1
  7. package/package.json +35 -39
  8. package/resources/fore.css +22 -54
  9. package/src/DependencyNotifyingDomFacade.js +5 -13
  10. package/src/ForeElementMixin.js +13 -20
  11. package/src/actions/abstract-action.js +14 -9
  12. package/src/actions/fx-action.js +6 -5
  13. package/src/actions/fx-append.js +8 -17
  14. package/src/actions/fx-confirm.js +3 -1
  15. package/src/actions/fx-delete.js +6 -3
  16. package/src/actions/fx-dispatch.js +9 -8
  17. package/src/actions/fx-hide.js +9 -6
  18. package/src/actions/fx-insert.js +27 -14
  19. package/src/actions/fx-message.js +3 -1
  20. package/src/actions/fx-refresh.js +11 -1
  21. package/src/actions/fx-replace.js +68 -0
  22. package/src/actions/fx-return.js +42 -0
  23. package/src/actions/fx-send.js +3 -1
  24. package/src/actions/fx-setvalue.js +58 -51
  25. package/src/actions/fx-show.js +8 -4
  26. package/src/actions/fx-toggle.js +13 -9
  27. package/src/actions/fx-update.js +3 -1
  28. package/src/dep_graph.js +1 -1
  29. package/src/drawdown.js +67 -82
  30. package/src/fore.js +141 -25
  31. package/src/functions/fx-function.js +11 -3
  32. package/src/fx-bind.js +39 -199
  33. package/src/fx-fore.js +101 -68
  34. package/src/fx-header.js +3 -1
  35. package/src/fx-instance.js +9 -1
  36. package/src/fx-model.js +31 -23
  37. package/src/fx-submission.js +73 -47
  38. package/src/fx-var.js +7 -4
  39. package/src/getInScopeContext.js +23 -16
  40. package/src/modelitem.js +4 -4
  41. package/src/relevance.js +65 -0
  42. package/src/ui/abstract-control.js +55 -35
  43. package/src/ui/fx-alert.js +7 -1
  44. package/src/ui/fx-case.js +3 -1
  45. package/src/ui/fx-container.js +4 -2
  46. package/src/ui/fx-control.js +283 -33
  47. package/src/ui/fx-dialog.js +50 -45
  48. package/src/ui/fx-group.js +3 -1
  49. package/src/ui/fx-hint.js +4 -1
  50. package/src/ui/fx-inspector.js +117 -17
  51. package/src/ui/fx-items.js +7 -5
  52. package/src/ui/fx-output.js +14 -5
  53. package/src/ui/fx-repeat.js +13 -26
  54. package/src/ui/fx-repeatitem.js +10 -4
  55. package/src/ui/fx-switch.js +3 -1
  56. package/src/ui/fx-trigger.js +3 -1
  57. package/src/xpath-evaluation.js +114 -102
  58. package/src/xpath-util.js +1 -5
  59. package/dist/fore-all.js +0 -140
  60. package/dist/fore-debug.js +0 -140
  61. package/src/.DS_Store +0 -0
  62. package/src/actions/.DS_Store +0 -0
  63. package/src/ui/.DS_Store +0 -0
@@ -38,6 +38,103 @@ const xhtmlNamespaceResolver = prefix => {
38
38
  return undefined;
39
39
  };
40
40
 
41
+ export function resolveId(id, sourceObject, nodeName = null) {
42
+ const allMatchingTargetObjects = fxEvaluateXPathToNodes(
43
+ 'outermost(ancestor-or-self::fx-fore[1]/(descendant::fx-fore|descendant::*[@id = $id]))[not(self::fx-fore)]',
44
+ sourceObject,
45
+ null,
46
+ { id },
47
+ { namespaceResolver: xhtmlNamespaceResolver },
48
+ );
49
+
50
+ if (allMatchingTargetObjects.length === 0) {
51
+ return null;
52
+ }
53
+
54
+ if (
55
+ allMatchingTargetObjects.length === 1 &&
56
+ fxEvaluateXPathToBoolean(
57
+ '(ancestor::fx-fore | ancestor::fx-repeat)[last()]/self::fx-fore',
58
+ allMatchingTargetObjects[0],
59
+ null,
60
+ null,
61
+ { namespaceResolver: xhtmlNamespaceResolver },
62
+ )
63
+ ) {
64
+ // If the target element is not repeated, then the search for the target object is trivial since
65
+ // there is only one associated with the target element that bears the matching ID. This is true
66
+ // regardless of whether or not the source object is repeated. However, if the target element is
67
+ // repeated, then additional information must be used to help select a target object from among
68
+ // those associated with the identified target element.
69
+ const targetObject = allMatchingTargetObjects[0];
70
+ if (nodeName && targetObject.localName !== nodeName) {
71
+ return null;
72
+ }
73
+ return targetObject;
74
+ }
75
+
76
+ // SPEC:
77
+
78
+ // 12.2.1 References to Elements within a repeat Element
79
+
80
+ // When the target element that is identified by the IDREF of a source object has one or more
81
+ // repeat elements as ancestors, then the set of ancestor repeats are partitioned into two
82
+ // subsets, those in common with the source element and those that are not in common. Any ancestor
83
+ // repeat elements of the target element not in common with the source element are descendants of
84
+ // the repeat elements that the source and target element have in common, if any.
85
+
86
+ // For the repeat elements that are in common, the desired target object exists in the same set of
87
+ // run-time objects that contains the source object. Then, for each ancestor repeat of the target
88
+ // element that is not in common with the source element, the current index of the repeat
89
+ // determines the set of run-time objects that contains the desired target object.
90
+ for (const ancestorRepeatItem of fxEvaluateXPathToNodes(
91
+ 'ancestor::fx-repeatitem => reverse()',
92
+ sourceObject,
93
+ null,
94
+ null,
95
+ { namespaceResolver: xhtmlNamespaceResolver },
96
+ )) {
97
+ const foundTargetObjects = allMatchingTargetObjects.filter(to =>
98
+ ancestorRepeatItem.contains(to),
99
+ );
100
+ switch (foundTargetObjects.length) {
101
+ case 0:
102
+ // Nothing found: ignore
103
+ break;
104
+ case 1: {
105
+ // A single one is found: the target object is directly in a common repeat
106
+ const targetObject = foundTargetObjects[0];
107
+ if (nodeName && targetObject.localName !== nodeName) {
108
+ return null;
109
+ }
110
+ return targetObject;
111
+ }
112
+ default: {
113
+ // Multiple target objects are found: they are in a repeat that is not common with the source object
114
+ // We found a target object in a common repeat! We now need to find the one that is in the repeatitem identified at the current index
115
+ const targetObject = foundTargetObjects.find(to =>
116
+ fxEvaluateXPathToNodes(
117
+ 'every $ancestor of ancestor::fx-repeatitem satisfies $ancestor is $ancestor/../child::fx-repeatitem[../@repeat-index]',
118
+ to,
119
+ null,
120
+ {},
121
+ ),
122
+ );
123
+ if (!targetObject) {
124
+ // Nothing valid found for whatever reason. This might be something dynamic?
125
+ return null;
126
+ }
127
+ if (nodeName && targetObject.localName !== nodeName) {
128
+ return null;
129
+ }
130
+ return targetObject;
131
+ }
132
+ }
133
+ }
134
+ // We found no target objects in common repeats. The id is unresolvable
135
+ return null;
136
+ }
137
+
41
138
  /**
42
139
  * Resolve a namespace. Needs a namespace prefix and the element that is most closely related to the
43
140
  * XPath in which the namespace is being resolved. The prefix will be resolved by using the
@@ -96,7 +193,7 @@ function createNamespaceResolver(xpathQuery, formElement) {
96
193
  let instance;
97
194
  if (instanceReferences[0] === 'default') {
98
195
  const actualForeElement = fxEvaluateXPathToFirstNode(
99
- 'ancestor-or-self::fx-fore',
196
+ 'ancestor-or-self::fx-fore[1]',
100
197
  formElement,
101
198
  null,
102
199
  null,
@@ -163,6 +260,10 @@ function createNamespaceResolverForNode(query, contextNode, formElement) {
163
260
  return createNamespaceResolver(query, formElement);
164
261
  }
165
262
 
263
+ // A global registry of function names that are declared in Fore by a developer using the
264
+ // `fx-function` element. These should be available without providing a prefix as well
265
+ export const globallyDeclaredFunctionLocalNames = [];
266
+
166
267
  /**
167
268
  * Implementation of the functionNameResolver passed to FontoXPath to
168
269
  * redirect function resolving for unprefixed functions to either the fn or the xf namespace
@@ -183,7 +284,12 @@ function functionNameResolver({ prefix, localName }, _arity) {
183
284
  case 'logtree':
184
285
  return { namespaceURI: XFORMS_NAMESPACE_URI, localName };
185
286
  default:
186
- if (prefix === '' || prefix === 'fn') {
287
+ if (prefix === '' && globallyDeclaredFunctionLocalNames.includes(localName)) {
288
+ // The function has been declared without a prefix and is called here without a prefix.
289
+ // Just make this work. It is the developer-friendly way
290
+ return { namespaceURI: 'http://www.w3.org/2005/xquery-local-functions', localName };
291
+ }
292
+ if (prefix === 'fn') {
187
293
  return { namespaceURI: 'http://www.w3.org/2005/xpath-functions', localName };
188
294
  }
189
295
  if (prefix === 'local') {
@@ -212,7 +318,7 @@ function getVariablesInScope(formElement) {
212
318
  }
213
319
 
214
320
  const variables = {};
215
- if(closestActualFormElement.inScopeVariables){
321
+ if (closestActualFormElement.inScopeVariables) {
216
322
  for (const key of closestActualFormElement.inScopeVariables.keys()) {
217
323
  const varElement = closestActualFormElement.inScopeVariables.get(key);
218
324
  variables[key] = varElement.value;
@@ -238,7 +344,7 @@ export function evaluateXPath(xpath, contextNode, formElement, variables = {}) {
238
344
  contextNode,
239
345
  null,
240
346
  { ...variablesInScope, ...variables },
241
- 'xs:anyType',
347
+ fxEvaluateXPath.ALL_RESULTS_TYPE,
242
348
  {
243
349
  currentContext: { formElement, variables },
244
350
  moduleImports: {
@@ -416,102 +522,6 @@ export function evaluateXPathToNumber(
416
522
  /**
417
523
  * Resolve an id in scope. Behaves like the algorithm defined on https://www.w3.org/community/xformsusers/wiki/XForms_2.0#idref-resolve
418
524
  */
419
- export function resolveId(id, sourceObject, nodeName = null) {
420
- const allMatchingTargetObjects = fxEvaluateXPathToNodes(
421
- 'outermost(ancestor-or-self::fx-fore[1]/(descendant::xf-fore|descendant::*[@id = $id]))[not(self::fx-fore)]',
422
- sourceObject,
423
- null,
424
- { id },
425
- { namespaceResolver: xhtmlNamespaceResolver },
426
- );
427
-
428
- if (allMatchingTargetObjects.length === 0) {
429
- return null;
430
- }
431
-
432
- if (
433
- allMatchingTargetObjects.length === 1 &&
434
- fxEvaluateXPathToBoolean(
435
- '(ancestor::fx-fore | ancestor::fx-repeat)[last()]/self::fx-fore',
436
- allMatchingTargetObjects[0],
437
- null,
438
- null,
439
- { namespaceResolver: xhtmlNamespaceResolver },
440
- )
441
- ) {
442
- // If the target element is not repeated, then the search for the target object is trivial since
443
- // there is only one associated with the target element that bears the matching ID. This is true
444
- // regardless of whether or not the source object is repeated. However, if the target element is
445
- // repeated, then additional information must be used to help select a target object from among
446
- // those associated with the identified target element.
447
- const targetObject = allMatchingTargetObjects[0];
448
- if (nodeName && targetObject.localName !== nodeName) {
449
- return null;
450
- }
451
- return targetObject;
452
- }
453
-
454
- // SPEC:
455
-
456
- // 12.2.1 References to Elements within a repeat Element
457
-
458
- // When the target element that is identified by the IDREF of a source object has one or more
459
- // repeat elements as ancestors, then the set of ancestor repeats are partitioned into two
460
- // subsets, those in common with the source element and those that are not in common. Any ancestor
461
- // repeat elements of the target element not in common with the source element are descendants of
462
- // the repeat elements that the source and target element have in common, if any.
463
-
464
- // For the repeat elements that are in common, the desired target object exists in the same set of
465
- // run-time objects that contains the source object. Then, for each ancestor repeat of the target
466
- // element that is not in common with the source element, the current index of the repeat
467
- // determines the set of run-time objects that contains the desired target object.
468
- for (const ancestorRepeatItem of fxEvaluateXPathToNodes(
469
- 'ancestor::fx-repeatitem => reverse()',
470
- sourceObject,
471
- null,
472
- null,
473
- { namespaceResolver: xhtmlNamespaceResolver },
474
- )) {
475
- const foundTargetObjects = allMatchingTargetObjects.filter(to =>
476
- ancestorRepeatItem.contains(to),
477
- );
478
- switch (foundTargetObjects.length) {
479
- case 0:
480
- // Nothing found: ignore
481
- break;
482
- case 1: {
483
- // A single one is found: the target object is directly in a common repeat
484
- const targetObject = foundTargetObjects[0];
485
- if (nodeName && targetObject.localName !== nodeName) {
486
- return null;
487
- }
488
- return targetObject;
489
- }
490
- default: {
491
- // Multiple target objects are found: they are in a repeat that is not common with the source object
492
- // We found a target object in a common repeat! We now need to find the one that is in the repeatitem identified at the current index
493
- const targetObject = foundTargetObjects.find(to =>
494
- fxEvaluateXPathToNodes(
495
- 'every $ancestor of ancestor::fx-repeatitem satisfies $ancestor is $ancestor/../child::fx-repeatitem[../@repeat-index]',
496
- to,
497
- null,
498
- {},
499
- ),
500
- );
501
- if (!targetObject) {
502
- // Nothing valid found for whatever reason. This might be something dynamic?
503
- return null;
504
- }
505
- if (nodeName && targetObject.localName !== nodeName) {
506
- return null;
507
- }
508
- return targetObject;
509
- }
510
- }
511
- }
512
- // We found no target objects in common repeats. The id is unresolvable
513
- return null;
514
- }
515
525
 
516
526
  const contextFunction = (dynamicContext, string) => {
517
527
  const caller = dynamicContext.currentContext.formElement;
@@ -531,7 +541,7 @@ const contextFunction = (dynamicContext, string) => {
531
541
  }
532
542
  }
533
543
  const parent = XPathUtil.getParentBindingElement(caller);
534
- const p = caller.nodeName;
544
+ // const p = caller.nodeName;
535
545
  // const p = dynamicContext.domFacade.getParentElement();
536
546
 
537
547
  if (parent) return parent;
@@ -676,7 +686,7 @@ const instance = (dynamicContext, string) => {
676
686
  // TODO: handle no string passed (null will be passed instead)
677
687
 
678
688
  const formElement = fxEvaluateXPathToFirstNode(
679
- 'ancestor-or-self::fx-fore',
689
+ 'ancestor-or-self::fx-fore[1]',
680
690
  dynamicContext.currentContext.formElement,
681
691
  null,
682
692
  null,
@@ -749,6 +759,8 @@ registerCustomXPathFunction(
749
759
  ['xs:string?'],
750
760
  'item()?',
751
761
  (dynamicContext, arg) => {
762
+ if (!dynamicContext.currentContext.variables) return [];
763
+ if (!arg) return [];
752
764
  const payload = dynamicContext.currentContext.variables[arg];
753
765
  if (payload.nodeType) {
754
766
  console.log('got some node as js object');
package/src/xpath-util.js CHANGED
@@ -29,10 +29,6 @@ export class XPathUtil {
29
29
  return path != null && (path.startsWith('/') || path.startsWith('instance('));
30
30
  }
31
31
 
32
- static isRepeated(element) {
33
- return element.parentElement.closest('fx-repeatitem');
34
- }
35
-
36
32
  static isSelfReference(ref) {
37
33
  return ref === '.' || ref === './text()' || ref === 'text()' || ref === '' || ref === null;
38
34
  }
@@ -82,7 +78,7 @@ export class XPathUtil {
82
78
 
83
79
  // todo: certainly not ideal to rely on duplicating instance id on instance document - better way later ;)
84
80
  static getPath(node) {
85
- const path = fx.evaluateXPath('path()', node);
81
+ const path = fx.evaluateXPathToString('path()', node);
86
82
  /*
87
83
  const instanceId = node.ownerDocument.firstElementChild.getAttribute('id');
88
84
  if (instanceId !== null && instanceId !== 'default') {