@jinntec/fore 1.10.0 → 1.10.2
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 -2
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +2 -2
- package/dist/fore.js.map +1 -1
- package/package.json +1 -1
- package/resources/fore.css +2 -41
- package/src/actions/abstract-action.js +51 -62
- package/src/actions/fx-call.js +9 -0
- package/src/actions/fx-delete.js +1 -1
- package/src/actions/fx-insert.js +8 -4
- package/src/actions/fx-load.js +5 -2
- package/src/actions/fx-reload.js +1 -1
- package/src/actions/fx-send.js +8 -3
- package/src/actions/fx-setfocus.js +6 -1
- package/src/actions/fx-toggle.js +1 -0
- package/src/fore.js +3 -222
- package/src/fx-bind.js +1 -1
- package/src/fx-fore.js +96 -89
- package/src/fx-model.js +31 -7
- package/src/fx-submission.js +5 -0
- package/src/tools/fx-action-log.js +1 -1
- package/src/ui/abstract-control.js +18 -39
- package/src/ui/fx-control.js +12 -12
- package/src/ui/fx-repeat-attributes.js +2 -2
- package/src/ui/fx-repeat.js +12 -1
- package/src/ui/fx-repeatitem.js +2 -8
- package/src/ui/fx-switch.js +63 -40
- package/src/ui/fx-trigger.js +3 -13
- package/src/xpath-evaluation.js +215 -83
- package/src/xpath-util.js +138 -130
package/src/xpath-util.js
CHANGED
|
@@ -2,151 +2,159 @@ import * as fx from 'fontoxpath';
|
|
|
2
2
|
|
|
3
3
|
export class XPathUtil {
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
}
|
|
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;
|
|
50
22
|
}
|
|
51
|
-
return start;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* returns next bound element upwards in tree
|
|
56
|
-
* @param start where to start the search
|
|
57
|
-
* @returns {*|null}
|
|
58
|
-
*/
|
|
59
|
-
static getParentBindingElement(start) {
|
|
60
|
-
/* if (start.parentNode.host) {
|
|
61
|
-
const { host } = start.parentNode;
|
|
62
|
-
if (host.hasAttribute('ref')) {
|
|
63
|
-
return host;
|
|
64
|
-
}
|
|
65
|
-
} else */
|
|
66
|
-
if (start.parentNode &&
|
|
67
|
-
(start.parentNode.nodeType !== Node.DOCUMENT_NODE || start.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) ) {
|
|
68
|
-
/*
|
|
69
|
-
if (start.parentNode.hasAttribute('ref')) {
|
|
70
|
-
return start.parentNode;
|
|
71
|
-
}
|
|
72
|
-
return XPathUtil.getParentBindingElement(start.parentNode);
|
|
73
|
-
*/
|
|
74
23
|
|
|
75
|
-
|
|
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;
|
|
76
52
|
}
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
53
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
54
|
+
/**
|
|
55
|
+
* returns next bound element upwards in tree
|
|
56
|
+
* @param start where to start the search
|
|
57
|
+
* @returns {*|null}
|
|
58
|
+
*/
|
|
59
|
+
static getParentBindingElement(start) {
|
|
60
|
+
/* if (start.parentNode.host) {
|
|
61
|
+
const { host } = start.parentNode;
|
|
62
|
+
if (host.hasAttribute('ref')) {
|
|
63
|
+
return host;
|
|
64
|
+
}
|
|
65
|
+
} else */
|
|
66
|
+
if (start.parentNode &&
|
|
67
|
+
(start.parentNode.nodeType !== Node.DOCUMENT_NODE || start.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE)) {
|
|
68
|
+
/*
|
|
69
|
+
if (start.parentNode.hasAttribute('ref')) {
|
|
70
|
+
return start.parentNode;
|
|
71
|
+
}
|
|
72
|
+
return XPathUtil.getParentBindingElement(start.parentNode);
|
|
73
|
+
*/
|
|
90
74
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
75
|
+
return start.parentNode.closest('[ref]');
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
94
79
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
static getInstanceId(ref) {
|
|
105
|
-
if (!ref) {
|
|
106
|
-
return 'default';
|
|
80
|
+
/**
|
|
81
|
+
* Checks whether the specified path expression is an absolute path.
|
|
82
|
+
*
|
|
83
|
+
* @param path the path expression.
|
|
84
|
+
* @return <code>true</code> if specified path expression is an absolute
|
|
85
|
+
* path, otherwise <code>false</code>.
|
|
86
|
+
*/
|
|
87
|
+
static isAbsolutePath(path) {
|
|
88
|
+
return path != null && (path.startsWith('/') || path.startsWith('instance('));
|
|
107
89
|
}
|
|
108
|
-
|
|
109
|
-
|
|
90
|
+
|
|
91
|
+
static isSelfReference(ref) {
|
|
92
|
+
return ref === '.' || ref === './text()' || ref === 'text()' || ref === '' || ref === null;
|
|
110
93
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* returns the instance id from a complete XPath using `instance()` function.
|
|
97
|
+
*
|
|
98
|
+
* Will return 'default' in case no ref is given at all or the `instance()` function is called without arg.
|
|
99
|
+
*
|
|
100
|
+
* Otherwise instance id is extracted from function and returned. If all fails null is returned.
|
|
101
|
+
* @param ref
|
|
102
|
+
* @returns {string}
|
|
103
|
+
*/
|
|
104
|
+
static getInstanceId(ref) {
|
|
105
|
+
if (!ref) {
|
|
106
|
+
return 'default';
|
|
107
|
+
}
|
|
108
|
+
if (ref.startsWith('instance()')) {
|
|
109
|
+
return 'default';
|
|
110
|
+
}
|
|
111
|
+
if (ref.startsWith('instance(')) {
|
|
112
|
+
const result = ref.substring(ref.indexOf('(') + 1);
|
|
113
|
+
return result.substring(1, result.indexOf(')') - 1);
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
114
116
|
}
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
static resolveInstance(boundElement, path) {
|
|
119
|
+
let instanceId = XPathUtil.getInstanceId(path);
|
|
120
|
+
if (!instanceId) {
|
|
121
|
+
instanceId = XPathUtil.getInstanceId(boundElement.getAttribute('ref'));
|
|
122
|
+
}
|
|
123
|
+
if (instanceId !== null) {
|
|
124
|
+
return instanceId;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const parentBinding = XPathUtil.getParentBindingElement(boundElement);
|
|
128
|
+
if (parentBinding) {
|
|
129
|
+
return this.resolveInstance(parentBinding, path);
|
|
130
|
+
}
|
|
131
|
+
return 'default';
|
|
125
132
|
}
|
|
126
133
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
static getDocPath(node) {
|
|
135
|
+
const path = fx.evaluateXPathToString('path()', node);
|
|
136
|
+
// Path is like `$default/x[1]/y[1]`
|
|
137
|
+
const shortened = XPathUtil.shortenPath(path);
|
|
138
|
+
return shortened.startsWith('/') ? `${shortened}` : `/${shortened}`;
|
|
130
139
|
}
|
|
131
|
-
return 'default';
|
|
132
|
-
}
|
|
133
140
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
static getPath(node, instanceId) {
|
|
142
|
+
const path = fx.evaluateXPathToString('path()', node);
|
|
143
|
+
// Path is like `$default/x[1]/y[1]`
|
|
144
|
+
const shortened = XPathUtil.shortenPath(path);
|
|
145
|
+
return shortened.startsWith('/') ? `$${instanceId}${shortened}` : `$${instanceId}/${shortened}`;
|
|
146
|
+
}
|
|
139
147
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
148
|
+
static shortenPath(path) {
|
|
149
|
+
const tmp = path.replaceAll(/(Q{(.*?)\})/g, '');
|
|
150
|
+
// cut off leading slash
|
|
151
|
+
const tmp1 = tmp.substring(1, tmp.length);
|
|
152
|
+
// ### cut-off root node ref
|
|
153
|
+
return tmp1.substring(tmp1.indexOf('/'), tmp.length);
|
|
154
|
+
}
|
|
147
155
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
static getBasePath(dep) {
|
|
157
|
+
const split = dep.split(':');
|
|
158
|
+
return split[0];
|
|
159
|
+
}
|
|
152
160
|
}
|