@jinntec/fore 1.4.0 → 1.6.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/dist/fore-dev.js +2 -36
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +2 -30
- package/dist/fore.js.map +1 -1
- package/index.js +13 -0
- package/package.json +9 -5
- package/resources/fore.css +178 -92
- package/src/DependencyNotifyingDomFacade.js +1 -2
- package/src/ForeElementMixin.js +31 -5
- package/src/actions/abstract-action.js +379 -270
- package/src/actions/fx-action.js +0 -1
- package/src/actions/fx-append.js +1 -2
- package/src/actions/fx-confirm.js +12 -0
- package/src/actions/fx-copy.js +0 -1
- package/src/actions/fx-delete.js +31 -9
- package/src/actions/fx-dispatch.js +19 -5
- package/src/actions/fx-hide.js +19 -0
- package/src/actions/fx-insert.js +72 -8
- package/src/actions/fx-load.js +253 -0
- package/src/actions/fx-message.js +22 -7
- package/src/actions/fx-refresh.js +11 -1
- package/src/actions/fx-reload.js +12 -2
- package/src/actions/fx-replace.js +5 -4
- package/src/actions/fx-reset.js +48 -0
- package/src/actions/fx-return.js +0 -1
- package/src/actions/fx-send.js +40 -2
- package/src/actions/fx-setfocus.js +25 -7
- package/src/actions/fx-setvalue.js +32 -4
- package/src/actions/fx-show.js +14 -2
- package/src/actions/fx-toggle.js +0 -1
- package/src/actions/fx-update.js +9 -0
- package/src/events.js +0 -1
- package/src/fore.js +119 -63
- package/src/functions/common-function.js +28 -0
- package/src/fx-bind.js +7 -7
- package/src/fx-fore.js +207 -54
- package/src/fx-instance.js +55 -17
- package/src/fx-model.js +31 -33
- package/src/fx-submission.js +50 -47
- package/src/getInScopeContext.js +22 -8
- package/src/lab/fore-component.js +90 -0
- package/src/lab/instance-inspector.js +56 -0
- package/src/lab/template.html +16 -0
- package/src/relevance.js +27 -1
- package/src/tools/adi.js +1056 -0
- package/src/tools/fx-action-log.js +662 -0
- package/src/tools/fx-devtools.js +444 -0
- package/src/tools/fx-dom-inspector.js +609 -0
- package/src/tools/fx-json-instance.js +435 -0
- package/src/tools/fx-log-item.js +133 -0
- package/src/tools/fx-log-settings.js +474 -0
- package/src/tools/fx-minimap.js +194 -0
- package/src/tools/helpers.js +132 -0
- package/src/ui/abstract-control.js +41 -3
- package/src/ui/fx-action-log.js +358 -0
- package/src/ui/fx-alert.js +0 -1
- package/src/ui/fx-container.js +14 -3
- package/src/ui/fx-control.js +553 -474
- package/src/ui/fx-dialog.js +2 -0
- package/src/ui/fx-dom-inspector.js +1255 -0
- package/src/ui/fx-group.js +3 -4
- package/src/ui/fx-hint.js +2 -4
- package/src/ui/fx-inspector.js +5 -6
- package/src/ui/fx-items.js +55 -14
- package/src/ui/fx-output.js +36 -17
- package/src/ui/fx-repeat-attributes.js +409 -0
- package/src/ui/fx-repeat.js +12 -6
- package/src/ui/fx-switch.js +14 -3
- package/src/ui/fx-trigger.js +13 -1
- package/src/xpath-evaluation.js +109 -26
- package/src/xpath-util.js +55 -1
package/src/xpath-evaluation.js
CHANGED
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
registerCustomXPathFunction,
|
|
11
11
|
registerXQueryModule,
|
|
12
12
|
} from 'fontoxpath';
|
|
13
|
-
import {Fore} from './fore.js';
|
|
14
13
|
|
|
15
14
|
import {XPathUtil} from './xpath-util.js';
|
|
15
|
+
import {prettifyXml} from './functions/common-function.js';
|
|
16
16
|
|
|
17
17
|
const XFORMS_NAMESPACE_URI = 'http://www.w3.org/2002/xforms';
|
|
18
18
|
|
|
@@ -42,12 +42,15 @@ const xhtmlNamespaceResolver = prefix => {
|
|
|
42
42
|
}
|
|
43
43
|
return undefined;
|
|
44
44
|
};
|
|
45
|
+
export function isInShadow(node) {
|
|
46
|
+
return node.getRootNode() instanceof ShadowRoot;
|
|
47
|
+
}
|
|
45
48
|
|
|
46
49
|
/**
|
|
47
50
|
* Resolve an id in scope. Behaves like the algorithm defined on https://www.w3.org/community/xformsusers/wiki/XForms_2.0#idref-resolve
|
|
48
51
|
*/
|
|
49
52
|
export function resolveId(id, sourceObject, nodeName = null) {
|
|
50
|
-
|
|
53
|
+
const query = 'outermost(ancestor-or-self::fx-fore[1]/(descendant::fx-fore|descendant::*[@id = $id]))[not(self::fx-fore)]';
|
|
51
54
|
/*
|
|
52
55
|
if (nodeName === 'fx-instance') {
|
|
53
56
|
// Instance elements can only be in the `model` element
|
|
@@ -60,6 +63,25 @@ export function resolveId(id, sourceObject, nodeName = null) {
|
|
|
60
63
|
return document.getElementById(id);
|
|
61
64
|
}
|
|
62
65
|
*/
|
|
66
|
+
if (sourceObject.nodeType === Node.TEXT_NODE) {
|
|
67
|
+
sourceObject = sourceObject.parentNode;
|
|
68
|
+
}
|
|
69
|
+
if (sourceObject.nodeType === Node.ATTRIBUTE_NODE) {
|
|
70
|
+
sourceObject = sourceObject.ownerElement;
|
|
71
|
+
}
|
|
72
|
+
if(sourceObject.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE){
|
|
73
|
+
sourceObject = sourceObject.parentNode.host;
|
|
74
|
+
}
|
|
75
|
+
const ownerForm = sourceObject.localName === 'fx-fore' ? sourceObject : sourceObject.closest('fx-fore');
|
|
76
|
+
const elementsWithId = ownerForm.querySelectorAll(`[id='${id}']`);
|
|
77
|
+
if (elementsWithId.length === 1) {
|
|
78
|
+
// A single one is found. Assume no ID reuse.
|
|
79
|
+
const targetObject = elementsWithId[0];
|
|
80
|
+
if (nodeName && targetObject.localName !== nodeName) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return targetObject;
|
|
84
|
+
}
|
|
63
85
|
|
|
64
86
|
const allMatchingTargetObjects = fxEvaluateXPathToNodes(query,
|
|
65
87
|
sourceObject,
|
|
@@ -116,7 +138,7 @@ export function resolveId(id, sourceObject, nodeName = null) {
|
|
|
116
138
|
{namespaceResolver: xhtmlNamespaceResolver},
|
|
117
139
|
)) {
|
|
118
140
|
const foundTargetObjects = allMatchingTargetObjects.filter(to =>
|
|
119
|
-
|
|
141
|
+
XPathUtil.contains(ancestorRepeatItem, to),
|
|
120
142
|
);
|
|
121
143
|
switch (foundTargetObjects.length) {
|
|
122
144
|
case 0:
|
|
@@ -159,11 +181,16 @@ export function resolveId(id, sourceObject, nodeName = null) {
|
|
|
159
181
|
// Make namespace resolving use the `instance` element that is related to here
|
|
160
182
|
const xmlDocument = new DOMParser().parseFromString('<xml />', 'text/xml');
|
|
161
183
|
|
|
184
|
+
const instanceReferencesByQuery = new Map();
|
|
185
|
+
|
|
162
186
|
function findInstanceReferences(xpathQuery) {
|
|
163
187
|
if (!xpathQuery.includes('instance')) {
|
|
164
188
|
// No call to the instance function anyway: short-circuit and prevent AST processing
|
|
165
189
|
return [];
|
|
166
190
|
}
|
|
191
|
+
if (instanceReferencesByQuery.has(xpathQuery)) {
|
|
192
|
+
return instanceReferencesByQuery.get(xpathQuery);
|
|
193
|
+
}
|
|
167
194
|
const xpathAST = parseScript(xpathQuery, {}, xmlDocument);
|
|
168
195
|
const instanceReferences = fxEvaluateXPathToStrings(
|
|
169
196
|
`descendant::xqx:functionCallExpr
|
|
@@ -180,6 +207,8 @@ function findInstanceReferences(xpathQuery) {
|
|
|
180
207
|
},
|
|
181
208
|
);
|
|
182
209
|
|
|
210
|
+
instanceReferencesByQuery.set(xpathQuery, instanceReferences);
|
|
211
|
+
|
|
183
212
|
return instanceReferences;
|
|
184
213
|
}
|
|
185
214
|
|
|
@@ -307,6 +336,7 @@ function functionNameResolver({prefix, localName}, _arity) {
|
|
|
307
336
|
case 'current':
|
|
308
337
|
case 'depends':
|
|
309
338
|
case 'event':
|
|
339
|
+
case 'fore-attr':
|
|
310
340
|
case 'index':
|
|
311
341
|
case 'instance':
|
|
312
342
|
case 'log':
|
|
@@ -350,10 +380,20 @@ function getVariablesInScope(formElement) {
|
|
|
350
380
|
const variables = {};
|
|
351
381
|
if (closestActualFormElement.inScopeVariables) {
|
|
352
382
|
for (const key of closestActualFormElement.inScopeVariables.keys()) {
|
|
353
|
-
const
|
|
354
|
-
if(
|
|
355
|
-
|
|
356
|
-
|
|
383
|
+
const varElementOrValue = closestActualFormElement.inScopeVariables.get(key);
|
|
384
|
+
if (!varElementOrValue) {
|
|
385
|
+
continue;
|
|
386
|
+
|
|
387
|
+
}
|
|
388
|
+
if (varElementOrValue.nodeType) {
|
|
389
|
+
// We are a var element, set the value to the value computed there
|
|
390
|
+
variables[key] = varElementOrValue.value;
|
|
391
|
+
// variables[key] = varElementOrValue.inScopeVariables.get(key);
|
|
392
|
+
} else {
|
|
393
|
+
// We are a direct value. This is used to leak in event variables
|
|
394
|
+
variables[key] = varElementOrValue;
|
|
395
|
+
}
|
|
396
|
+
|
|
357
397
|
}
|
|
358
398
|
}
|
|
359
399
|
return variables;
|
|
@@ -584,6 +624,12 @@ const currentFunction = (dynamicContext, string) => {
|
|
|
584
624
|
return null;
|
|
585
625
|
};
|
|
586
626
|
|
|
627
|
+
const elementFunction = (dynamicContext, string) => {
|
|
628
|
+
const caller = dynamicContext.currentContext.formElement;
|
|
629
|
+
const newElement = document.createElement(string);
|
|
630
|
+
return newElement;
|
|
631
|
+
};
|
|
632
|
+
|
|
587
633
|
/**
|
|
588
634
|
* @param id as string
|
|
589
635
|
* @return instance data for given id serialized to string.
|
|
@@ -613,6 +659,13 @@ registerCustomXPathFunction(
|
|
|
613
659
|
currentFunction,
|
|
614
660
|
);
|
|
615
661
|
|
|
662
|
+
registerCustomXPathFunction(
|
|
663
|
+
{namespaceURI: XFORMS_NAMESPACE_URI, localName: 'element'},
|
|
664
|
+
['xs:string'],
|
|
665
|
+
'item()?',
|
|
666
|
+
elementFunction,
|
|
667
|
+
);
|
|
668
|
+
|
|
616
669
|
/**
|
|
617
670
|
* @param id as string
|
|
618
671
|
* @return instance data for given id serialized to string.
|
|
@@ -630,12 +683,30 @@ registerCustomXPathFunction(
|
|
|
630
683
|
// return JSON.stringify(instance.getDefaultContext());
|
|
631
684
|
} else {
|
|
632
685
|
const def = new XMLSerializer().serializeToString(instance.getDefaultContext());
|
|
633
|
-
return
|
|
686
|
+
return prettifyXml(def);
|
|
634
687
|
}
|
|
635
688
|
}
|
|
636
689
|
return null;
|
|
637
690
|
},
|
|
638
691
|
);
|
|
692
|
+
registerCustomXPathFunction(
|
|
693
|
+
{namespaceURI: XFORMS_NAMESPACE_URI, localName: 'fore-attr'},
|
|
694
|
+
['xs:string?'],
|
|
695
|
+
'xs:string?',
|
|
696
|
+
(dynamicContext, string) => {
|
|
697
|
+
const {formElement} = dynamicContext.currentContext;
|
|
698
|
+
|
|
699
|
+
let parent = formElement;
|
|
700
|
+
if(formElement.nodeType === Node.TEXT_NODE){
|
|
701
|
+
parent = formElement.parentNode;
|
|
702
|
+
}
|
|
703
|
+
const foreElement = parent.closest('fx-fore');
|
|
704
|
+
if(foreElement.hasAttribute(string)){
|
|
705
|
+
return foreElement.getAttribute(string);
|
|
706
|
+
}
|
|
707
|
+
return null;
|
|
708
|
+
},
|
|
709
|
+
);
|
|
639
710
|
|
|
640
711
|
registerCustomXPathFunction(
|
|
641
712
|
{namespaceURI: XFORMS_NAMESPACE_URI, localName: 'parse'},
|
|
@@ -827,29 +898,41 @@ registerCustomXPathFunction(
|
|
|
827
898
|
['xs:string?'],
|
|
828
899
|
'item()?',
|
|
829
900
|
(dynamicContext, arg) => {
|
|
830
|
-
if (!arg) return
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
901
|
+
if (!arg) return null;
|
|
902
|
+
|
|
903
|
+
for (let ancestor = dynamicContext.currentContext.formElement;
|
|
904
|
+
ancestor;
|
|
905
|
+
ancestor = ancestor.parentNode) {
|
|
906
|
+
if (!ancestor.currentEvent) {
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// We have a current event. read the property either from detail, or from the event
|
|
911
|
+
// itself.
|
|
912
|
+
// Check detail for custom events! This is how that is passed along
|
|
913
|
+
if (ancestor.currentEvent.detail && typeof ancestor.currentEvent.detail === 'object' && arg in ancestor.currentEvent.detail) {
|
|
914
|
+
return ancestor.currentEvent.detail[arg];
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// arg might be `code`, so currentEvent.code should work
|
|
918
|
+
if(arg.includes('.')){
|
|
919
|
+
return _propertyLookup(ancestor.currentEvent, arg);
|
|
839
920
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
if (dynamicContext.currentContext.formElement.inScopeVariables) {
|
|
843
|
-
console.log('event()', dynamicContext.currentContext.formElement.inScopeVariables);
|
|
844
|
-
console.log('event()', dynamicContext.currentContext.formElement.inScopeVariables.get(arg));
|
|
845
|
-
// dynamicContext.currentContext.variables = dynamicContext.currentContext.formElement.inScopeVariables;
|
|
846
|
-
return dynamicContext.currentContext.formElement.inScopeVariables.get(arg);
|
|
847
|
-
}
|
|
921
|
+
return ancestor.currentEvent[arg] || null;
|
|
848
922
|
|
|
849
|
-
|
|
923
|
+
}
|
|
924
|
+
return null;
|
|
850
925
|
},
|
|
851
926
|
);
|
|
852
927
|
|
|
928
|
+
function _propertyLookup(obj,path){
|
|
929
|
+
const parts = path.split(".");
|
|
930
|
+
if (parts.length==1){
|
|
931
|
+
return obj[parts[0]];
|
|
932
|
+
}
|
|
933
|
+
return _propertyLookup(obj[parts[0]], parts.slice(1).join("."));
|
|
934
|
+
}
|
|
935
|
+
|
|
853
936
|
// Implement the XForms standard functions here.
|
|
854
937
|
registerXQueryModule(`
|
|
855
938
|
module namespace xf="${XFORMS_NAMESPACE_URI}";
|
package/src/xpath-util.js
CHANGED
|
@@ -2,6 +2,55 @@ import * as fx from 'fontoxpath';
|
|
|
2
2
|
|
|
3
3
|
export class XPathUtil {
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Alternative to `contains` that respects shadowroots
|
|
7
|
+
*/
|
|
8
|
+
static contains(ancestor, descendant) {
|
|
9
|
+
while (descendant) {
|
|
10
|
+
if (descendant === ancestor) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (descendant.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
15
|
+
// We are passing a shadow root boundary
|
|
16
|
+
descendant = descendant.host;
|
|
17
|
+
} else {
|
|
18
|
+
descendant = descendant.parentNode;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Alternative to `closest` that respects subcontrol boundaries
|
|
26
|
+
*/
|
|
27
|
+
static getClosest(querySelector, start) {
|
|
28
|
+
while (start && !start.matches || !start.matches(querySelector)) {
|
|
29
|
+
if (start.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
30
|
+
// We are passing a shadow root boundary
|
|
31
|
+
start = start.host;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (start.nodeType === Node.ATTRIBUTE_NODE) {
|
|
35
|
+
// We are passing an attribute
|
|
36
|
+
start = start.ownerElement;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (start.nodeType === Node.TEXT_NODE) {
|
|
40
|
+
start = start.parentNode;
|
|
41
|
+
}
|
|
42
|
+
if (start.matches('fx-fore')) {
|
|
43
|
+
// Subform reached. Bail out
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
start = start.parentNode;
|
|
47
|
+
if (!start) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return start;
|
|
52
|
+
}
|
|
53
|
+
|
|
5
54
|
/**
|
|
6
55
|
* returns next bound element upwards in tree
|
|
7
56
|
* @param start where to start the search
|
|
@@ -14,11 +63,16 @@ export class XPathUtil {
|
|
|
14
63
|
return host;
|
|
15
64
|
}
|
|
16
65
|
} else */
|
|
17
|
-
if (start.parentNode &&
|
|
66
|
+
if (start.parentNode &&
|
|
67
|
+
(start.parentNode.nodeType !== Node.DOCUMENT_NODE || start.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) ) {
|
|
68
|
+
/*
|
|
18
69
|
if (start.parentNode.hasAttribute('ref')) {
|
|
19
70
|
return start.parentNode;
|
|
20
71
|
}
|
|
21
72
|
return XPathUtil.getParentBindingElement(start.parentNode);
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
return start.parentNode.closest('[ref]');
|
|
22
76
|
}
|
|
23
77
|
return null;
|
|
24
78
|
}
|