@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinntec/fore",
3
- "version": "1.10.0",
3
+ "version": "1.10.2",
4
4
  "description": "Fore - declarative user interfaces in plain HTML",
5
5
  "module": "./index.js",
6
6
  "publishConfig": {
@@ -28,7 +28,7 @@ html {
28
28
  nonrelevant must always be hidden
29
29
  */
30
30
  [nonrelevant] {
31
- display: none !important;
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;
@@ -120,6 +80,7 @@ fx-output[readonly] img {
120
80
 
121
81
  .error {
122
82
  background: var(--paper-red-500);
83
+ display: flex;
123
84
  }
124
85
 
125
86
  fx-control, fx-trigger, .fx-checkbox {
@@ -101,8 +101,6 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
101
101
  super();
102
102
  this.detail = {};
103
103
  this.needsUpdate = false;
104
-
105
- this.changedPathsQueue = [];
106
104
  }
107
105
 
108
106
  connectedCallback() {
@@ -158,20 +156,22 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
158
156
  }
159
157
  }
160
158
 
161
- async performSafe() {
162
- try {
163
- const changedPaths = await this.perform();
164
- // Return truthy to indicate success
165
- return changedPaths;
166
- } catch (error) {
167
- const stringifiedComponent = `<${this.localName} ${Array.from(this.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(' ')}>…</${this.localName}>`;
168
- await Fore.dispatch(this, 'error', {
169
- message: `The action could not be performed. ${error} The error came from ${stringifiedComponent}`,
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'
170
170
  });
171
- // Return false to indicate failure. Any loops must be canceled
172
- return false;
173
- }
174
- }
171
+ // Return false to indicate failure. Any loops must be canceled
172
+ return false;
173
+ }
174
+ }
175
175
 
176
176
  /**
177
177
  * executes the action.
@@ -185,7 +185,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
185
185
  * @param e
186
186
  */
187
187
  async execute(e) {
188
- // console.log('execute', this, e);
188
+ console.log(this);
189
189
  // console.log('execute', this.event);
190
190
 
191
191
 
@@ -210,7 +210,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
210
210
  e.preventDefault();
211
211
  }
212
212
 
213
- let resolveThisEvent = () => {};
213
+ let resolveThisEvent = () => {};
214
214
  if (e && e.listenerPromises) {
215
215
  e.listenerPromises.push(
216
216
  new Promise(resolve => {
@@ -224,13 +224,13 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
224
224
  // console.log('executing e phase', e.eventPhase);
225
225
  if (FxFore.outermostHandler === null) {
226
226
  // console.time('outermostHandler');
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
- */
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
+ */
234
234
  // console.log('starting outermost handler',this);
235
235
  FxFore.outermostHandler = this;
236
236
  this.dispatchEvent(new CustomEvent('outermost-action-start', {
@@ -240,15 +240,15 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
240
240
  }));
241
241
  }
242
242
 
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
- */
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
+ */
252
252
  // console.log('>>> outermostHandler', FxFore.outermostHandler);
253
253
 
254
254
  if (e) {
@@ -290,10 +290,9 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
290
290
  }
291
291
 
292
292
  // Perform the action once. But quit if it errored
293
- const result = this.performSafe();
294
- if (!result) {
295
- return;
296
- }
293
+ if (!this.performSafe()) {
294
+ return;
295
+ }
297
296
 
298
297
  // Go for one more iteration
299
298
  if (this.delay) {
@@ -308,8 +307,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
308
307
 
309
308
  // After loop is done call actionPerformed to update the model and UI
310
309
  await loop();
311
- // TODO: pass the result(s)
312
- this._finalizePerform(resolveThisEvent, []);
310
+ this._finalizePerform(resolveThisEvent);
313
311
 
314
312
  return;
315
313
  }
@@ -325,28 +323,23 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
325
323
  }
326
324
  }
327
325
 
328
- const result = await this.performSafe();
329
- if (!result) {
330
- this._finalizePerform(resolveThisEvent, []);
331
- return;
332
- }
333
- this._finalizePerform(resolveThisEvent, result);
334
-
326
+ await this.performSafe();
327
+ this._finalizePerform(resolveThisEvent);
335
328
  }
336
329
 
337
- _finalizePerform(resolveThisEvent, changedPaths) {
330
+ _finalizePerform(resolveThisEvent) {
338
331
  this.currentEvent = null;
339
- this.actionPerformed(changedPaths);
332
+ this.actionPerformed();
340
333
  if (FxFore.outermostHandler === this) {
341
334
  FxFore.outermostHandler = null;
342
- /*
343
- console.info(
344
- `%coutermost Action done`,
345
- 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
346
- this,
347
- );
348
- console.timeEnd('outermostHandler');
349
- */
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
+ */
350
343
  this.dispatchEvent(new CustomEvent('outermost-action-end', {
351
344
  composed: true,
352
345
  bubbles: true,
@@ -372,7 +365,6 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
372
365
  this.evalInContext();
373
366
  }
374
367
 
375
- /*
376
368
  this.dispatchEvent(
377
369
  new CustomEvent('execute-action', {
378
370
  composed: true,
@@ -381,14 +373,13 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
381
373
  detail: {action: this, event: this.event},
382
374
  }),
383
375
  );
384
- */
385
376
 
386
377
  }
387
378
 
388
379
  /**
389
380
  * calls the update cycle if action signalled that update is needed.
390
381
  */
391
- actionPerformed(changedPaths = []) {
382
+ actionPerformed() {
392
383
  const model = this.getModel();
393
384
  if (!model) {
394
385
  return;
@@ -413,15 +404,13 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
413
404
  // console.log('running update cycle for outermostHandler', this);
414
405
  model.recalculate();
415
406
  model.revalidate();
416
- model.parentNode.refresh(false, [...this.changedPathsQueue, ...changedPaths]);
417
- this.changedPathsQueue = [];
407
+ model.parentNode.refresh(true);
418
408
  this.dispatchActionPerformed();
419
409
  } else if (this.needsUpdate) {
420
410
  // console.log('Update delayed!');
421
411
  // We need an update, but the outermost action handler is not done yet. Make this clear!
422
412
  // console.log('running actionperformed on', this, ' to be updated by ', FxFore.outermostHandler);
423
413
  FxFore.outermostHandler.needsUpdate = true;
424
- FxFore.outermostHandler.changedPathsQueue.push(...changedPaths);
425
414
  }
426
415
 
427
416
  // console.log('running actionperformed on', this, ' outermostHandler', FxFore.outermostHandler);
@@ -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(){
@@ -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) : '';
@@ -228,11 +228,14 @@ export class FxInsert extends AbstractAction {
228
228
  // console.log('instance ', this.getModel().getDefaultContext());
229
229
  // Fore.dispatch()
230
230
 
231
- const instanceId = XPathUtil.resolveInstance(this, this.getAttribute('context'));
231
+ // const instanceId = XPathUtil.resolveInstance(this, this.getAttribute('context'));
232
+ const instanceId = XPathUtil.resolveInstance(this, this.ref);
232
233
  const inst = this.getModel().getInstance(instanceId);
233
234
  // console.log('<<<<<<< resolved instance', inst);
234
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
235
- const xpath = XPathUtil.getPath(originSequenceClone.parentNode, instanceId);
236
+ // const xpath = XPathUtil.getPath(originSequenceClone.parentNode, instanceId);
237
+ const xpath = XPathUtil.getPath(insertLocationNode.parentNode, instanceId);
238
+
236
239
 
237
240
 
238
241
  const path = Fore.getDomNodeIndexString(originSequenceClone);
@@ -281,8 +284,9 @@ export class FxInsert extends AbstractAction {
281
284
  }
282
285
 
283
286
  actionPerformed(changedPaths) {
284
- // this.getModel().rebuild();
285
- super.actionPerformed(changedPaths);
287
+ // ### make sure the necessary modelItems will get created
288
+ this.getModel().rebuild();
289
+ super.actionPerformed();
286
290
  }
287
291
 
288
292
  /**
@@ -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('log', {
116
+ new CustomEvent('error', {
117
117
  composed: false,
118
118
  bubbles: true,
119
119
  cancelable:true,
120
- detail: { id:this.id, message: `neiter template element nor Url was specified.`, level:'Error'},
120
+ detail: {
121
+ origin:this,
122
+ message: `neither template element nor Url was specified.`,
123
+ level:'Error'},
121
124
  }),
122
125
  );
123
126
  return;
@@ -1,5 +1,5 @@
1
- import { Fore } from '../fore.js';
2
1
  import { AbstractAction } from './abstract-action.js';
2
+ import {Fore} from "../fore.js";
3
3
 
4
4
  /**
5
5
  * `fx-reload`
@@ -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('log', {
54
+ new CustomEvent('error', {
54
55
  composed: false,
55
56
  bubbles: true,
56
57
  cancelable:true,
57
- detail: { id:this.id, message: `fx-submission element with id: '${this.submission}' not found`, level:'Error'},
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
- console.warn('targetElement of setfocus action does not exist (yet)', selector);
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
 
@@ -23,6 +23,7 @@ class FxToggle extends AbstractAction {
23
23
  super.perform();
24
24
  if (this.case) {
25
25
  const ownerForm = this.getOwnerForm();
26
+ // todo: id resolution!!!
26
27
  const caseElement = ownerForm.querySelector(`#${this.case}`);
27
28
  if(!caseElement){
28
29
  Fore.dispatch(this, 'error', { message: `fx-case id not found: ${this.case}` });
package/src/fore.js CHANGED
@@ -18,228 +18,6 @@ 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
21
  static buildPredicates(node){
244
22
  let attrPredicate='';
245
23
  Array.from(node.attributes).forEach(attr =>{
@@ -686,6 +464,9 @@ export class Fore {
686
464
  }
687
465
  }
688
466
 
467
+ static stringifiedComponent(element){
468
+ return `<${element.localName} ${Array.from(element.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(' ')}>…</${element.localName}>`;
469
+ }
689
470
  static async loadForeFromUrl(hostElement, url) {
690
471
  // console.log('########## loading Fore from ', this.src, '##########');
691
472
  await fetch(url, {