@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.
- package/README.md +6 -27
- package/dist/fore-dev.js +43 -0
- package/dist/fore-dev.js.map +1 -0
- package/dist/fore.js +37 -0
- package/dist/fore.js.map +1 -0
- package/index.js +2 -1
- package/package.json +35 -39
- package/resources/fore.css +22 -54
- package/src/DependencyNotifyingDomFacade.js +5 -13
- package/src/ForeElementMixin.js +13 -20
- package/src/actions/abstract-action.js +14 -9
- package/src/actions/fx-action.js +6 -5
- package/src/actions/fx-append.js +8 -17
- package/src/actions/fx-confirm.js +3 -1
- package/src/actions/fx-delete.js +6 -3
- package/src/actions/fx-dispatch.js +9 -8
- package/src/actions/fx-hide.js +9 -6
- package/src/actions/fx-insert.js +27 -14
- package/src/actions/fx-message.js +3 -1
- package/src/actions/fx-refresh.js +11 -1
- package/src/actions/fx-replace.js +68 -0
- package/src/actions/fx-return.js +42 -0
- package/src/actions/fx-send.js +3 -1
- package/src/actions/fx-setvalue.js +58 -51
- package/src/actions/fx-show.js +8 -4
- package/src/actions/fx-toggle.js +13 -9
- package/src/actions/fx-update.js +3 -1
- package/src/dep_graph.js +1 -1
- package/src/drawdown.js +67 -82
- package/src/fore.js +141 -25
- package/src/functions/fx-function.js +11 -3
- package/src/fx-bind.js +39 -199
- package/src/fx-fore.js +101 -68
- package/src/fx-header.js +3 -1
- package/src/fx-instance.js +9 -1
- package/src/fx-model.js +31 -23
- package/src/fx-submission.js +73 -47
- package/src/fx-var.js +7 -4
- package/src/getInScopeContext.js +23 -16
- package/src/modelitem.js +4 -4
- package/src/relevance.js +65 -0
- package/src/ui/abstract-control.js +55 -35
- package/src/ui/fx-alert.js +7 -1
- package/src/ui/fx-case.js +3 -1
- package/src/ui/fx-container.js +4 -2
- package/src/ui/fx-control.js +283 -33
- package/src/ui/fx-dialog.js +50 -45
- package/src/ui/fx-group.js +3 -1
- package/src/ui/fx-hint.js +4 -1
- package/src/ui/fx-inspector.js +117 -17
- package/src/ui/fx-items.js +7 -5
- package/src/ui/fx-output.js +14 -5
- package/src/ui/fx-repeat.js +13 -26
- package/src/ui/fx-repeatitem.js +10 -4
- package/src/ui/fx-switch.js +3 -1
- package/src/ui/fx-trigger.js +3 -1
- package/src/xpath-evaluation.js +114 -102
- package/src/xpath-util.js +1 -5
- package/dist/fore-all.js +0 -140
- package/dist/fore-debug.js +0 -140
- package/src/.DS_Store +0 -0
- package/src/actions/.DS_Store +0 -0
- package/src/ui/.DS_Store +0 -0
package/src/xpath-evaluation.js
CHANGED
|
@@ -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 === ''
|
|
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
|
-
|
|
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.
|
|
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') {
|