@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinntec/fore",
3
- "version": "1.9.0",
3
+ "version": "1.10.1",
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;
@@ -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
- async performSafe() {
160
- try {
161
- await this.perform();
162
- // Return true to indicate success
163
- return true;
164
- } catch (error) {
165
- const stringifiedComponent = `<${this.localName} ${Array.from(this.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(' ')}>…</${this.localName}>`;
166
- await Fore.dispatch(this, 'error', {
167
- 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'
168
170
  });
169
- // Return false to indicate failure. Any loops must be canceled
170
- return false;
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
- // console.log('execute', this, e);
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
- let resolveThisEvent = () => {};
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
- console.info(
227
- `%coutermost Action `,
228
- 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
229
- this,
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
- if (FxFore.outermostHandler !== this) {
243
- console.info(
244
- `%cAction `,
245
- 'background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
246
- this,
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
- return;
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
- console.info(
335
- `%coutermost Action done`,
336
- 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
337
- this,
338
- );
339
- console.timeEnd('outermostHandler');
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,
@@ -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) : '';
@@ -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
- const inst = this.getModel().getInstance(XPathUtil.resolveInstance(this));
231
- // console.log('<<<<<<< resolved instance', inst);
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
- this.needsUpdate = true;
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
  }
@@ -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
 
@@ -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, {