@jinntec/fore 1.10.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.10.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;
@@ -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
 
package/src/fore.js CHANGED
@@ -686,6 +686,9 @@ export class Fore {
686
686
  }
687
687
  }
688
688
 
689
+ static stringifiedComponent(element){
690
+ return `<${element.localName} ${Array.from(element.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(' ')}>…</${element.localName}>`;
691
+ }
689
692
  static async loadForeFromUrl(hostElement, url) {
690
693
  // console.log('########## loading Fore from ', this.src, '##########');
691
694
  await fetch(url, {
package/src/fx-bind.js CHANGED
@@ -80,7 +80,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
80
80
  _buildBindGraph() {
81
81
  if (this.bindType === 'xml') {
82
82
  this.nodeset.forEach(node => {
83
- const instance = XPathUtil.resolveInstance(this);
83
+ const instance = XPathUtil.resolveInstance(this,this.ref);
84
84
 
85
85
  const path = XPathUtil.getPath(node, instance);
86
86
  this.model.mainGraph.addNode(path, node);
package/src/fx-fore.js CHANGED
@@ -85,9 +85,10 @@ export class FxFore extends HTMLElement {
85
85
  // this.addEventListener('model-construct-done', this._handleModelConstructDone);
86
86
  // todo: refactoring - these should rather go into connectedcallback
87
87
  this.addEventListener('message', this._displayMessage);
88
- this.addEventListener('error', this._displayError);
88
+ // this.addEventListener('error', this._displayError);
89
+ this.addEventListener('error', this._logError);
89
90
  this.addEventListener('warn', this._displayWarning);
90
- this.addEventListener('log', this._logError);
91
+ // this.addEventListener('log', this._logError);
91
92
  window.addEventListener('compute-exception', e => {
92
93
  console.error('circular dependency: ', e);
93
94
  });
@@ -176,7 +177,7 @@ export class FxFore extends HTMLElement {
176
177
 
177
178
  const html = `
178
179
  <noscript>This page uses Web Components and needs JavaScript to be enabled..</noscript>
179
-
180
+ <!-- <slot name="errors"></slot> -->
180
181
  <jinn-toast id="message" gravity="bottom" position="left"></jinn-toast>
181
182
  <jinn-toast id="sticky" gravity="bottom" position="left" duration="-1" close="true" data-class="sticky-message"></jinn-toast>
182
183
  <jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="right" gravity="top" escape-markup="false"></jinn-toast>
@@ -324,9 +325,9 @@ export class FxFore extends HTMLElement {
324
325
  * Will extract the `fx-fore` element from that target file and use and replace current `fx-fore` element with the loaded one.
325
326
  * @private
326
327
  */
327
- _loadFromSrc() {
328
+ async _loadFromSrc() {
328
329
  // console.log('########## loading Fore from ', this.src, '##########');
329
- fetch(this.src, {
330
+ await fetch(this.src, {
330
331
  method: 'GET',
331
332
  mode: 'cors',
332
333
  credentials: 'include',
@@ -450,42 +451,50 @@ export class FxFore extends HTMLElement {
450
451
  // console.timeEnd('refresh');
451
452
  }
452
453
 
453
- async refresh(force, changedPaths) {
454
- if (!changedPaths) {
455
- changedPaths = this.toRefresh.map(item => item.path);
456
- } else {
457
- this.toRefresh.push(
458
- ...changedPaths
459
- .map(
460
- path =>
461
- this.getModel()
462
- .modelItems
463
- .find(item => item.path === path)
464
- )
465
- .filter(Boolean)
466
- );
467
-
468
- for(const changedPath of changedPaths) {
469
- for (const repeat of this.querySelectorAll('fx-repeat')) {
470
- if (repeat.closest('fx-fore') !== this) {
471
- continue;
472
- }
473
-
474
- if (repeat.touchedPaths.has(changedPath)) {
475
- // Make a temporary model-item-like structure for this
476
- this.toRefresh.push({
477
- path: changedPath,
478
- boundControls: [repeat]
479
- });
480
-
481
- console.log('Found a repeat to update!!!', repeat)
482
- }
483
- }
484
- }
454
+ // async refresh(force, changedPaths) {
455
+ async refresh(force) {
456
+
457
+ /*
458
+
459
+ if (!changedPaths) {
460
+ changedPaths = this.toRefresh.map(item => item.path);
461
+ } else {
462
+ this.toRefresh.push(
463
+ ...changedPaths
464
+ .map(
465
+ path =>
466
+ this.getModel()
467
+ .modelItems
468
+ .find(item => item.path === path)
469
+ )
470
+ .filter(Boolean)
471
+ );
472
+
473
+ for(const changedPath of changedPaths) {
474
+ for (const repeat of this.querySelectorAll('fx-repeat')) {
475
+ if (repeat.closest('fx-fore') !== this) {
476
+ continue;
477
+ }
478
+
479
+ if (repeat.touchedPaths && repeat.touchedPaths.has(changedPath)) {
480
+ // Make a temporary model-item-like structure for this
481
+ this.toRefresh.push({
482
+ path: changedPath,
483
+ boundControls: [repeat]
484
+ });
485
+
486
+ console.log('Found a repeat to update!!!', repeat)
487
+ }
488
+ }
489
+ }
485
490
  }
491
+ */
486
492
  if (this.isRefreshing) {
487
493
  return;
488
494
  }
495
+ this.isRefreshing = true;
496
+ console.log('### <<<<< refresh() >>>>>');
497
+
489
498
  // refresh () {
490
499
  // ### refresh Fore UI elements
491
500
  // if (!this.initialRun && this.toRefresh.length !== 0) {
@@ -556,10 +565,12 @@ export class FxFore extends HTMLElement {
556
565
  this.style.visibility='visible';
557
566
  Fore.dispatch(this, 'refresh-done', {});
558
567
 
559
- this.isRefreshing = true;
560
- this.parentNode.closest('fx-fore')?.refresh(false, changedPaths);
568
+ // this.isRefreshing = true;
569
+ // this.parentNode.closest('fx-fore')?.refresh(false, changedPaths);
570
+ this.parentNode.closest('fx-fore')?.refresh(false);
561
571
  for (const subFore of this.querySelectorAll('fx-fore')) {
562
- subFore.refresh(false, changedPaths);
572
+ // subFore.refresh(false, changedPaths);
573
+ subFore.refresh(false);
563
574
  }
564
575
  this.isRefreshing = false;
565
576
  }
@@ -649,6 +660,13 @@ export class FxFore extends HTMLElement {
649
660
  * @param node the node which will get updated with evaluation result
650
661
  */
651
662
  evaluateTemplateExpression(expr, node) {
663
+
664
+ // ### do not evaluate template expressions with nonrelevant sections
665
+ if(node.nodeType === Node.ATTRIBUTE_NODE && node.ownerElement.closest('[nonrelevant]')) return;
666
+ if(node.nodeType === Node.TEXT_NODE && node.parentNode.closest('[nonrelevant]')) return;
667
+ if(node.nodeType === Node.ELEMENT_NODE && node.closest('[nonrelevant]')) return;
668
+
669
+ // if(node.closest('[nonrelevant]')) return;
652
670
  const replaced = expr.replace(/{[^}]*}/g, match => {
653
671
  if (match === '{}') return match;
654
672
  const naked = match.substring(1, match.length - 1);
@@ -869,6 +887,8 @@ export class FxFore extends HTMLElement {
869
887
  */
870
888
  async _initUI() {
871
889
  // console.log('### _initUI()');
890
+ console.log('### <<<<< _initUI >>>>>');
891
+
872
892
  if (!this.initialRun) return;
873
893
  this.classList.add('initialRun');
874
894
  await this._lazyCreateInstance();
@@ -902,6 +922,8 @@ export class FxFore extends HTMLElement {
902
922
  this.ready = true;
903
923
  this.initialRun = false;
904
924
  // console.log('### >>>>> dispatching ready >>>>>', this);
925
+ console.log(`### <<<<< ${this.id} ready >>>>>`);
926
+
905
927
  // console.log('### modelItems: ', this.getModel().modelItems);
906
928
  Fore.dispatch(this, 'ready', {});
907
929
  // console.log('dataChanged', FxModel.dataChanged);
@@ -953,39 +975,23 @@ export class FxFore extends HTMLElement {
953
975
  toast.showToast(`WARN: ${path}:${msg}`);
954
976
  }
955
977
 
978
+
956
979
  _logError(e) {
957
980
  e.stopPropagation();
958
981
  e.preventDefault();
959
982
 
960
- const div = document.createElement('div');
961
- div.setAttribute('slot','messages');
962
- div.setAttribute('data-level',e.detail.level);
963
-
964
- const id = document.createElement('div');
965
- id.textContent = `"${e.detail.id}"`;
966
- div.appendChild(id);
967
-
968
- const path = document.createElement('div');
969
- const pathExpr = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
970
- // console.log('pathExpr',pathExpr)
971
- path.textContent = pathExpr;
972
- div.appendChild(path);
973
-
974
- const message = document.createElement('div');
975
- message.textContent = e.detail.message;
976
- div.appendChild(message);
977
-
978
- /*
979
- const path = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
980
- div.innerText = `${path} :: ${e.detail.message}`;
981
- */
982
- this.appendChild(div);
983
- div.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
984
-
985
-
986
- const errorElement = evaluateXPathToFirstNode(`/${pathExpr}`,document,null);
987
- errorElement.classList.add('fore-error');
983
+ console.error('ERROR',e.detail.message);
984
+ console.error(e.detail.origin);
985
+ if(e.detail.expr){
986
+ console.error('Failing expression',e.detail.expr);
987
+ }
988
+ console.error('---');
989
+ this._displayError(e);
990
+ }
988
991
 
992
+ _copyToClipboard(target){
993
+ console.log('copyToClipboard' , target.value)
994
+ navigator.clipboard.writeText(target.value);
989
995
 
990
996
  }
991
997