@jinntec/fore 1.9.0 → 1.10.1
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 +6 -41
- package/src/DependencyNotifyingDomFacade.js +2 -2
- package/src/actions/abstract-action.js +43 -41
- package/src/actions/fx-call.js +9 -0
- package/src/actions/fx-delete.js +1 -1
- package/src/actions/fx-insert.js +15 -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 +7 -2
- package/src/fore.js +241 -1
- package/src/fx-bind.js +12 -6
- package/src/fx-fore.js +99 -36
- package/src/fx-model.js +22 -7
- package/src/fx-submission.js +13 -14
- package/src/tools/adi.js +16 -7
- package/src/tools/fx-action-log.js +1 -1
- package/src/ui/abstract-control.js +26 -46
- package/src/ui/fx-control.js +13 -13
- package/src/ui/fx-dialog.js +2 -0
- package/src/ui/fx-group.js +4 -1
- package/src/ui/fx-repeat-attributes.js +4 -1
- package/src/ui/fx-repeat.js +21 -1
- package/src/ui/fx-repeatitem.js +5 -9
- package/src/ui/fx-trigger.js +6 -14
- package/src/xpath-evaluation.js +324 -73
- package/src/xpath-util.js +137 -132
package/package.json
CHANGED
package/resources/fore.css
CHANGED
|
@@ -28,7 +28,7 @@ html {
|
|
|
28
28
|
nonrelevant must always be hidden
|
|
29
29
|
*/
|
|
30
30
|
[nonrelevant] {
|
|
31
|
-
display: none
|
|
31
|
+
display: none;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
[relevant] {
|
|
@@ -41,46 +41,6 @@ fx-control[required]:after {
|
|
|
41
41
|
color: red;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
[slot=messages] {
|
|
45
|
-
margin: 0 auto;
|
|
46
|
-
width: 100%;
|
|
47
|
-
padding: 2rem 0 1rem;
|
|
48
|
-
background: white;
|
|
49
|
-
border-radius: 0.5rem;
|
|
50
|
-
position: relative;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
[slot=messages]::before {
|
|
54
|
-
content: attr(data-level);
|
|
55
|
-
padding: 0.5rem;
|
|
56
|
-
background: darkred;
|
|
57
|
-
color: white;
|
|
58
|
-
display: block;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
[slot=messages] div {
|
|
62
|
-
color: black;
|
|
63
|
-
padding: 0.25rem;
|
|
64
|
-
border: thin solid #efefef;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
[slot=messages] div::before {
|
|
68
|
-
width: 6rem;
|
|
69
|
-
display: inline-block;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
[slot=messages] div:nth-child(1)::before {
|
|
73
|
-
content: 'Id:';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
[slot=messages] div:nth-child(2)::before {
|
|
77
|
-
content: 'Path:';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
[slot=messages] div:nth-child(3)::before {
|
|
81
|
-
content: 'Message:';
|
|
82
|
-
}
|
|
83
|
-
|
|
84
44
|
.fore-error {
|
|
85
45
|
height: 2rem;
|
|
86
46
|
background: darkred;
|
|
@@ -101,6 +61,10 @@ fx-alert {
|
|
|
101
61
|
display: none;
|
|
102
62
|
}
|
|
103
63
|
|
|
64
|
+
[valid] fx-alert{
|
|
65
|
+
display: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
104
68
|
.visited[invalid] fx-alert {
|
|
105
69
|
display: block;
|
|
106
70
|
}
|
|
@@ -116,6 +80,7 @@ fx-output[readonly] img {
|
|
|
116
80
|
|
|
117
81
|
.error {
|
|
118
82
|
background: var(--paper-red-500);
|
|
83
|
+
display: flex;
|
|
119
84
|
}
|
|
120
85
|
|
|
121
86
|
fx-control, fx-trigger, .fx-checkbox {
|
|
@@ -114,7 +114,7 @@ export class DependencyNotifyingDomFacade {
|
|
|
114
114
|
// eslint-disable-next-line class-methods-use-this
|
|
115
115
|
getNextSibling(node, bucket) {
|
|
116
116
|
for (let sibling = node.nextSibling; sibling; sibling = sibling.nextSibling) {
|
|
117
|
-
if (!getBucketsForNode(sibling).includes(bucket)) {
|
|
117
|
+
if (bucket && !getBucketsForNode(sibling).includes(bucket)) {
|
|
118
118
|
// eslint-disable-next-line no-continue
|
|
119
119
|
continue;
|
|
120
120
|
}
|
|
@@ -149,7 +149,7 @@ export class DependencyNotifyingDomFacade {
|
|
|
149
149
|
previousSibling;
|
|
150
150
|
previousSibling = previousSibling.previousSibling
|
|
151
151
|
) {
|
|
152
|
-
if (!getBucketsForNode(previousSibling).includes(bucket)) {
|
|
152
|
+
if (bucket && !getBucketsForNode(previousSibling).includes(bucket)) {
|
|
153
153
|
// eslint-disable-next-line no-continue
|
|
154
154
|
continue;
|
|
155
155
|
}
|
|
@@ -156,20 +156,22 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
message: `
|
|
159
|
+
async performSafe() {
|
|
160
|
+
try {
|
|
161
|
+
await this.perform();
|
|
162
|
+
// Return true to indicate success
|
|
163
|
+
return true;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
await Fore.dispatch(this, 'error', {
|
|
166
|
+
origin: this,
|
|
167
|
+
message: `Action execution failed`,
|
|
168
|
+
expr:XPathUtil.getDocPath(this),
|
|
169
|
+
level:'Error'
|
|
168
170
|
});
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
// Return false to indicate failure. Any loops must be canceled
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
173
175
|
|
|
174
176
|
/**
|
|
175
177
|
* executes the action.
|
|
@@ -183,7 +185,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
183
185
|
* @param e
|
|
184
186
|
*/
|
|
185
187
|
async execute(e) {
|
|
186
|
-
|
|
188
|
+
console.log(this);
|
|
187
189
|
// console.log('execute', this.event);
|
|
188
190
|
|
|
189
191
|
|
|
@@ -208,7 +210,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
208
210
|
e.preventDefault();
|
|
209
211
|
}
|
|
210
212
|
|
|
211
|
-
|
|
213
|
+
let resolveThisEvent = () => {};
|
|
212
214
|
if (e && e.listenerPromises) {
|
|
213
215
|
e.listenerPromises.push(
|
|
214
216
|
new Promise(resolve => {
|
|
@@ -222,13 +224,13 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
222
224
|
// console.log('executing e phase', e.eventPhase);
|
|
223
225
|
if (FxFore.outermostHandler === null) {
|
|
224
226
|
// console.time('outermostHandler');
|
|
225
|
-
/*
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
*/
|
|
227
|
+
/*
|
|
228
|
+
console.info(
|
|
229
|
+
`%coutermost Action `,
|
|
230
|
+
'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
|
|
231
|
+
this,
|
|
232
|
+
);
|
|
233
|
+
*/
|
|
232
234
|
// console.log('starting outermost handler',this);
|
|
233
235
|
FxFore.outermostHandler = this;
|
|
234
236
|
this.dispatchEvent(new CustomEvent('outermost-action-start', {
|
|
@@ -238,15 +240,15 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
238
240
|
}));
|
|
239
241
|
}
|
|
240
242
|
|
|
241
|
-
/*
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
*/
|
|
243
|
+
/*
|
|
244
|
+
if (FxFore.outermostHandler !== this) {
|
|
245
|
+
console.info(
|
|
246
|
+
`%cAction `,
|
|
247
|
+
'background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
|
|
248
|
+
this,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
*/
|
|
250
252
|
// console.log('>>> outermostHandler', FxFore.outermostHandler);
|
|
251
253
|
|
|
252
254
|
if (e) {
|
|
@@ -289,8 +291,8 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
289
291
|
|
|
290
292
|
// Perform the action once. But quit if it errored
|
|
291
293
|
if (!this.performSafe()) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
294
296
|
|
|
295
297
|
// Go for one more iteration
|
|
296
298
|
if (this.delay) {
|
|
@@ -330,14 +332,14 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
330
332
|
this.actionPerformed();
|
|
331
333
|
if (FxFore.outermostHandler === this) {
|
|
332
334
|
FxFore.outermostHandler = null;
|
|
333
|
-
/*
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
*/
|
|
335
|
+
/*
|
|
336
|
+
console.info(
|
|
337
|
+
`%coutermost Action done`,
|
|
338
|
+
'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
|
|
339
|
+
this,
|
|
340
|
+
);
|
|
341
|
+
console.timeEnd('outermostHandler');
|
|
342
|
+
*/
|
|
341
343
|
this.dispatchEvent(new CustomEvent('outermost-action-end', {
|
|
342
344
|
composed: true,
|
|
343
345
|
bubbles: true,
|
package/src/actions/fx-call.js
CHANGED
|
@@ -3,6 +3,7 @@ import {AbstractAction} from './abstract-action.js';
|
|
|
3
3
|
import {evaluateXPath, evaluateXPathToString} from "../xpath-evaluation.js";
|
|
4
4
|
import {Fore} from "../fore";
|
|
5
5
|
import getInScopeContext from "../getInScopeContext";
|
|
6
|
+
import {XPathUtil} from "../xpath-util.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* `fx-call`
|
|
@@ -60,7 +61,15 @@ export default class FxCall extends AbstractAction {
|
|
|
60
61
|
const action = document.querySelector(`#${this.action}`);
|
|
61
62
|
if(action){
|
|
62
63
|
await action.perform();
|
|
64
|
+
}else{
|
|
65
|
+
Fore.dispatch(this, 'error', {
|
|
66
|
+
origin: this,
|
|
67
|
+
message: `Action '${this.action}' not found`,
|
|
68
|
+
expr:XPathUtil.getDocPath(this),
|
|
69
|
+
level:'Error'
|
|
70
|
+
});
|
|
63
71
|
}
|
|
72
|
+
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
_callFunction(){
|
package/src/actions/fx-delete.js
CHANGED
|
@@ -35,7 +35,7 @@ class FxDelete extends AbstractAction {
|
|
|
35
35
|
|
|
36
36
|
// console.log('delete nodeset ', this.nodeset);
|
|
37
37
|
|
|
38
|
-
const instanceId = XPathUtil.resolveInstance(this);
|
|
38
|
+
const instanceId = XPathUtil.resolveInstance(this, this.ref);
|
|
39
39
|
const instance = this.getModel().getInstance(instanceId);
|
|
40
40
|
|
|
41
41
|
// const path = instance && this.nodeset.length !== 0 ? evaluateXPathToString('path()', this.nodeset[0], instance) : '';
|
package/src/actions/fx-insert.js
CHANGED
|
@@ -221,14 +221,22 @@ export class FxInsert extends AbstractAction {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
+
// instance('default')/items/item[index()]
|
|
224
225
|
|
|
225
226
|
// console.log('insert context item ', insertLocationNode);
|
|
226
227
|
// console.log('parent ', insertLocationNode.parentNode);
|
|
227
228
|
// console.log('instance ', this.getModel().getDefaultContext());
|
|
228
229
|
// Fore.dispatch()
|
|
229
230
|
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
// const instanceId = XPathUtil.resolveInstance(this, this.getAttribute('context'));
|
|
232
|
+
const instanceId = XPathUtil.resolveInstance(this, this.ref);
|
|
233
|
+
const inst = this.getModel().getInstance(instanceId);
|
|
234
|
+
// console.log('<<<<<<< resolved instance', inst);
|
|
235
|
+
// Note: the parent to insert under is always the parent of the inserted node. The 'context' is not always the parent if the sequence is empty, or the position is different
|
|
236
|
+
// const xpath = XPathUtil.getPath(originSequenceClone.parentNode, instanceId);
|
|
237
|
+
const xpath = XPathUtil.getPath(insertLocationNode.parentNode, instanceId);
|
|
238
|
+
|
|
239
|
+
|
|
232
240
|
|
|
233
241
|
const path = Fore.getDomNodeIndexString(originSequenceClone);
|
|
234
242
|
this.dispatchEvent(
|
|
@@ -259,7 +267,9 @@ export class FxInsert extends AbstractAction {
|
|
|
259
267
|
}),
|
|
260
268
|
);
|
|
261
269
|
|
|
262
|
-
|
|
270
|
+
this.needsUpdate = true;
|
|
271
|
+
console.log('Changed!', xpath)
|
|
272
|
+
return [xpath];
|
|
263
273
|
}
|
|
264
274
|
|
|
265
275
|
// eslint-disable-next-line class-methods-use-this
|
|
@@ -273,7 +283,8 @@ export class FxInsert extends AbstractAction {
|
|
|
273
283
|
return null;
|
|
274
284
|
}
|
|
275
285
|
|
|
276
|
-
actionPerformed() {
|
|
286
|
+
actionPerformed(changedPaths) {
|
|
287
|
+
// ### make sure the necessary modelItems will get created
|
|
277
288
|
this.getModel().rebuild();
|
|
278
289
|
super.actionPerformed();
|
|
279
290
|
}
|
package/src/actions/fx-load.js
CHANGED
|
@@ -113,11 +113,14 @@ class FxLoad extends AbstractAction {
|
|
|
113
113
|
// for authoring errors we log errors directly to DOM
|
|
114
114
|
|
|
115
115
|
this.dispatchEvent(
|
|
116
|
-
new CustomEvent('
|
|
116
|
+
new CustomEvent('error', {
|
|
117
117
|
composed: false,
|
|
118
118
|
bubbles: true,
|
|
119
119
|
cancelable:true,
|
|
120
|
-
detail: {
|
|
120
|
+
detail: {
|
|
121
|
+
origin:this,
|
|
122
|
+
message: `neither template element nor Url was specified.`,
|
|
123
|
+
level:'Error'},
|
|
121
124
|
}),
|
|
122
125
|
);
|
|
123
126
|
return;
|
package/src/actions/fx-reload.js
CHANGED
package/src/actions/fx-send.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../fx-model.js';
|
|
2
2
|
import '../fx-submission.js';
|
|
3
3
|
import { AbstractAction } from './abstract-action.js';
|
|
4
|
+
import {XPathUtil} from "../xpath-util.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* `fx-send` - finds and activates a `fx-submission` element.
|
|
@@ -45,16 +46,20 @@ class FxSend extends AbstractAction {
|
|
|
45
46
|
new CustomEvent('error', {
|
|
46
47
|
composed: true,
|
|
47
48
|
bubbles: true,
|
|
48
|
-
detail: { message: `fx-submission element with id: '${this.submission}' not found` },
|
|
49
|
+
detail: { message: `fx-submission element with id: '${this.submission}' not found - ${XPathUtil.getDocPath(this)}` },
|
|
49
50
|
}),
|
|
50
51
|
);
|
|
51
52
|
*/
|
|
52
53
|
this.dispatchEvent(
|
|
53
|
-
new CustomEvent('
|
|
54
|
+
new CustomEvent('error', {
|
|
54
55
|
composed: false,
|
|
55
56
|
bubbles: true,
|
|
56
57
|
cancelable:true,
|
|
57
|
-
detail: { id:this.id,
|
|
58
|
+
detail: { id:this.id,
|
|
59
|
+
origin: this,
|
|
60
|
+
message: `<fx-submission id="${this.submission}"> not found`,
|
|
61
|
+
expr:XPathUtil.getDocPath(this),
|
|
62
|
+
level:'Error'},
|
|
58
63
|
}),
|
|
59
64
|
);
|
|
60
65
|
return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {AbstractAction} from "./abstract-action.js";
|
|
2
|
+
import {Fore} from "../fore";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* `fx-setfocus`
|
|
@@ -32,7 +33,11 @@ export class FxSetfocus extends AbstractAction {
|
|
|
32
33
|
let targetElement = document.querySelector(selector);
|
|
33
34
|
|
|
34
35
|
if(!targetElement) {
|
|
35
|
-
|
|
36
|
+
Fore.dispatch(this, 'error', {
|
|
37
|
+
origin: this,
|
|
38
|
+
message: `Instance '${this.control}' not found`,
|
|
39
|
+
level:'Error'
|
|
40
|
+
});
|
|
36
41
|
return;
|
|
37
42
|
}
|
|
38
43
|
|
|
@@ -41,7 +46,7 @@ export class FxSetfocus extends AbstractAction {
|
|
|
41
46
|
if(parentIItem){
|
|
42
47
|
targetElement = parentIItem.querySelector(selector);
|
|
43
48
|
this._focus(targetElement);
|
|
44
|
-
return;
|
|
49
|
+
// return;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
// ### the target element is hosted within a repeat
|
package/src/fore.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import getInScopeContext from "./getInScopeContext.js";
|
|
2
|
-
import {evaluateXPathToString} from "./xpath-evaluation.js";
|
|
2
|
+
import {evaluateXPath, evaluateXPathToFirstNode, evaluateXPathToString, evaluateXPathToNodes} from "./xpath-evaluation.js";
|
|
3
3
|
import { XPathUtil } from "./xpath-util.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -18,6 +18,243 @@ export class Fore {
|
|
|
18
18
|
|
|
19
19
|
static TYPE_DEFAULT = 'xs:string';
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* recursively walks along a template instance that contains all nodes relevant for editing and
|
|
23
|
+
* applying all nodes being present in partial instance onto it.
|
|
24
|
+
*
|
|
25
|
+
* @param start
|
|
26
|
+
* @param partial
|
|
27
|
+
* @returns {*}
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
static combine(start, partial, foreElement,expr){
|
|
31
|
+
if(!start) return;
|
|
32
|
+
|
|
33
|
+
const appended = false;
|
|
34
|
+
// ### get the path of the current element
|
|
35
|
+
let path = evaluateXPath('path()',start,foreElement)[0];
|
|
36
|
+
if(expr){
|
|
37
|
+
path = expr;
|
|
38
|
+
}
|
|
39
|
+
// const attrMap = new Map();
|
|
40
|
+
console.log('########process path', XPathUtil.shortenPath(path));
|
|
41
|
+
const predicates = Fore.buildPredicates(start);
|
|
42
|
+
// console.log('########process search', path);
|
|
43
|
+
// ### search the path in the partial instance
|
|
44
|
+
const toMerge = evaluateXPathToFirstNode( path,partial,foreElement);
|
|
45
|
+
if(expr){
|
|
46
|
+
console.log('skipped one - new toMerge', toMerge);
|
|
47
|
+
}
|
|
48
|
+
// console.log('tomerge node', toMerge);
|
|
49
|
+
// if(toMerge.length === 1){}
|
|
50
|
+
if(toMerge){
|
|
51
|
+
// console.log('merging nodes', toMerge);
|
|
52
|
+
const mergeAttrs = Fore.buildPredicates(toMerge);
|
|
53
|
+
if(predicates === mergeAttrs) {
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
// console.log('####### attr maps', attrMap, toMergeAttrMap);
|
|
57
|
+
// console.log('########process merge attrs', mergeAttrs);
|
|
58
|
+
if(start.getAttribute('type') !== toMerge.getAttribute('type') ){
|
|
59
|
+
console.log('###### element type attr not matching', start, toMerge);
|
|
60
|
+
const nextSibling = start.nextElementSibling;
|
|
61
|
+
if(nextSibling && nextSibling.nodeName === start.nodeName){
|
|
62
|
+
console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
|
|
63
|
+
console.log('start', start, XPathUtil.shortenPath(path));
|
|
64
|
+
Fore.combine(start,partial,foreElement,path);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ### iterate the attributes of the template node
|
|
69
|
+
// if(attrMap === toMergeAttrMap){
|
|
70
|
+
// if(start.attributes){
|
|
71
|
+
Array.from(start.attributes).forEach(attr => {
|
|
72
|
+
// ### if the template attribute has a matching attribute in partial...
|
|
73
|
+
if (toMerge.hasAttribute(attr.nodeName)) {
|
|
74
|
+
if (attr.nodeName !== 'xmlns') {
|
|
75
|
+
// console.log('overwrite attr', attr);
|
|
76
|
+
const toMergeAttr = toMerge.getAttribute(attr.nodeName);
|
|
77
|
+
// if (attr.nodeValue !== toMergeAttr.nodeValue) {
|
|
78
|
+
// ### apply the attribute value from partial to template
|
|
79
|
+
if(toMergeAttr){
|
|
80
|
+
start.setAttribute(attr.nodeName, toMergeAttr)
|
|
81
|
+
}
|
|
82
|
+
// }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
// }
|
|
87
|
+
}else{
|
|
88
|
+
console.log('###### element in template but not in partial',start);
|
|
89
|
+
const nextSibling = start.nextElementSibling;
|
|
90
|
+
if(nextSibling && nextSibling.nodeName === start.nodeName){
|
|
91
|
+
Fore.combine(nextSibling,partial,foreElement,path);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// ### if we don't have children we still might have text
|
|
95
|
+
if(toMerge.children.length === 0){
|
|
96
|
+
const toMergeText = toMerge.textContent;
|
|
97
|
+
if(toMergeText){
|
|
98
|
+
start.textContent = toMergeText;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ### if the template node does not have children but the partial has then copy them over
|
|
103
|
+
if(start.children.length === 0 && toMerge.children.length !== 0){
|
|
104
|
+
const mergeChildren = Array.from(toMerge.children);
|
|
105
|
+
mergeChildren.forEach(child => {
|
|
106
|
+
start.append(child);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ### recurse
|
|
112
|
+
if(start.children){
|
|
113
|
+
Array.from(start.children).forEach(element => {
|
|
114
|
+
/*
|
|
115
|
+
console.log('stepping into element', element);
|
|
116
|
+
if(element.getAttribute('type') !== toMerge.getAttribute('type')){
|
|
117
|
+
// console.log('###### element in template but not in partial');
|
|
118
|
+
// const nextSibling = start.nextElementSibling;
|
|
119
|
+
const nextSibling = element.nextElementSibling;
|
|
120
|
+
if(nextSibling && nextSibling.nodeName === toMerge.nodeName){
|
|
121
|
+
console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
|
|
122
|
+
Fore.combine(nextSibling,partial,foreElement,path);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
*/
|
|
126
|
+
return Fore.combine(element, partial,foreElement,null);
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return start;
|
|
132
|
+
}
|
|
133
|
+
/*
|
|
134
|
+
static combine(start, partial, foreElement,expr){
|
|
135
|
+
if(!start) return;
|
|
136
|
+
// ### get the path of the current element
|
|
137
|
+
let path = evaluateXPath('path()',start,foreElement)[0];
|
|
138
|
+
if(expr){
|
|
139
|
+
path = expr;
|
|
140
|
+
}
|
|
141
|
+
// const attrMap = new Map();
|
|
142
|
+
console.log('########process path', XPathUtil.shortenPath(path));
|
|
143
|
+
const predicates = Fore.buildPredicates(start);
|
|
144
|
+
/!*
|
|
145
|
+
if(predicates){
|
|
146
|
+
path = path.substring(1, path.lastIndexOf('['));
|
|
147
|
+
}
|
|
148
|
+
path += Fore.buildPredicates(start);
|
|
149
|
+
*!/
|
|
150
|
+
// console.log('########process search', path);
|
|
151
|
+
// ### search the path in the partial instance
|
|
152
|
+
const toMerge = evaluateXPathToFirstNode( path,partial,foreElement);
|
|
153
|
+
|
|
154
|
+
// console.log('tomerge node', toMerge);
|
|
155
|
+
// if(toMerge.length === 1){}
|
|
156
|
+
if(toMerge){
|
|
157
|
+
// console.log('merging nodes', toMerge);
|
|
158
|
+
const mergeAttrs = Fore.buildPredicates(toMerge);
|
|
159
|
+
if(predicates === mergeAttrs) {
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
// console.log('####### attr maps', attrMap, toMergeAttrMap);
|
|
163
|
+
// console.log('########process merge attrs', mergeAttrs);
|
|
164
|
+
/!*
|
|
165
|
+
if(toMerge.getAttribute('type') !== start.getAttribute('type')){
|
|
166
|
+
// console.log('###### element in template but not in partial');
|
|
167
|
+
// const nextSibling = start.nextElementSibling;
|
|
168
|
+
const nextSibling = start.nextElementSibling;
|
|
169
|
+
if(nextSibling && nextSibling.nodeName === start.nodeName){
|
|
170
|
+
console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
|
|
171
|
+
Fore.combine(nextSibling,partial,foreElement,path);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
*!/
|
|
175
|
+
|
|
176
|
+
// ### iterate the attributes of the template node
|
|
177
|
+
// if(attrMap === toMergeAttrMap){
|
|
178
|
+
// if(start.attributes){
|
|
179
|
+
Array.from(start.attributes).forEach(attr => {
|
|
180
|
+
// ### if the template attribute has a matching attribute in partial...
|
|
181
|
+
if (toMerge.hasAttribute(attr.nodeName)) {
|
|
182
|
+
if (attr.nodeName !== 'xmlns') {
|
|
183
|
+
// console.log('overwrite attr', attr);
|
|
184
|
+
const toMergeAttr = toMerge.getAttribute(attr.nodeName);
|
|
185
|
+
// if (attr.nodeValue !== toMergeAttr.nodeValue) {
|
|
186
|
+
// ### apply the attribute value from partial to template
|
|
187
|
+
if(toMergeAttr){
|
|
188
|
+
start.setAttribute(attr.nodeName, toMergeAttr)
|
|
189
|
+
}
|
|
190
|
+
// }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
// }
|
|
195
|
+
}else{
|
|
196
|
+
console.log('###### element in template but not in partial',start);
|
|
197
|
+
const nextSibling = start.nextElementSibling;
|
|
198
|
+
if(nextSibling && nextSibling.nodeName === start.nodeName){
|
|
199
|
+
Fore.combine(nextSibling,partial,foreElement,path);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// ### if we don't have children we still might have text
|
|
203
|
+
if(toMerge.children.length === 0){
|
|
204
|
+
const toMergeText = toMerge.textContent;
|
|
205
|
+
if(toMergeText){
|
|
206
|
+
start.textContent = toMergeText;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ### if the template node does not have children but the partial has then copy them over
|
|
211
|
+
if(start.children.length === 0 && toMerge.children.length !== 0){
|
|
212
|
+
const mergeChildren = Array.from(toMerge.children);
|
|
213
|
+
mergeChildren.forEach(child => {
|
|
214
|
+
start.append(child);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ### recurse
|
|
220
|
+
if(start.children){
|
|
221
|
+
Array.from(start.children).forEach(element => {
|
|
222
|
+
/!*
|
|
223
|
+
console.log('stepping into element', element);
|
|
224
|
+
if(element.getAttribute('type') !== toMerge.getAttribute('type')){
|
|
225
|
+
// console.log('###### element in template but not in partial');
|
|
226
|
+
// const nextSibling = start.nextElementSibling;
|
|
227
|
+
const nextSibling = element.nextElementSibling;
|
|
228
|
+
if(nextSibling && nextSibling.nodeName === toMerge.nodeName){
|
|
229
|
+
console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
|
|
230
|
+
Fore.combine(nextSibling,partial,foreElement,path);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
*!/
|
|
234
|
+
return Fore.combine(element, partial,foreElement);
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
return start;
|
|
240
|
+
}
|
|
241
|
+
*/
|
|
242
|
+
|
|
243
|
+
static buildPredicates(node){
|
|
244
|
+
let attrPredicate='';
|
|
245
|
+
Array.from(node.attributes).forEach(attr =>{
|
|
246
|
+
// attrMap.set(attr.nodeName,attr.nodeValue);
|
|
247
|
+
// if(attr.nodeName !== 'xmlns'){
|
|
248
|
+
// if(attr.nodeValue !== ''){
|
|
249
|
+
// attrPredicate += `[@${attr.nodeName}='${attr.nodeValue}']`;
|
|
250
|
+
// }else{
|
|
251
|
+
attrPredicate += `[@${attr.nodeName}]`;
|
|
252
|
+
// }
|
|
253
|
+
// }
|
|
254
|
+
});
|
|
255
|
+
return attrPredicate
|
|
256
|
+
}
|
|
257
|
+
|
|
21
258
|
|
|
22
259
|
/**
|
|
23
260
|
* returns true if target element is the widget itself or some element within the widget.
|
|
@@ -449,6 +686,9 @@ export class Fore {
|
|
|
449
686
|
}
|
|
450
687
|
}
|
|
451
688
|
|
|
689
|
+
static stringifiedComponent(element){
|
|
690
|
+
return `<${element.localName} ${Array.from(element.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(' ')}>…</${element.localName}>`;
|
|
691
|
+
}
|
|
452
692
|
static async loadForeFromUrl(hostElement, url) {
|
|
453
693
|
// console.log('########## loading Fore from ', this.src, '##########');
|
|
454
694
|
await fetch(url, {
|