@jinntec/fore 1.2.0 → 1.4.0

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.
Files changed (51) hide show
  1. package/dist/fore-dev.js +8 -8
  2. package/dist/fore-dev.js.map +1 -1
  3. package/dist/fore.js +7 -7
  4. package/dist/fore.js.map +1 -1
  5. package/index.js +1 -0
  6. package/package.json +2 -2
  7. package/resources/fore.css +100 -72
  8. package/src/ForeElementMixin.js +4 -0
  9. package/src/actions/abstract-action.js +102 -18
  10. package/src/actions/fx-action.js +9 -10
  11. package/src/actions/fx-append.js +1 -1
  12. package/src/actions/fx-confirm.js +3 -3
  13. package/src/actions/fx-copy.js +68 -0
  14. package/src/actions/fx-delete.js +53 -62
  15. package/src/actions/fx-dispatch.js +1 -1
  16. package/src/actions/fx-hide.js +4 -2
  17. package/src/actions/fx-insert.js +1 -1
  18. package/src/actions/fx-message.js +26 -2
  19. package/src/actions/fx-refresh.js +2 -2
  20. package/src/actions/fx-reload.js +30 -0
  21. package/src/actions/fx-replace.js +1 -1
  22. package/src/actions/fx-return.js +1 -1
  23. package/src/actions/fx-send.js +13 -3
  24. package/src/actions/fx-setfocus.js +33 -6
  25. package/src/actions/fx-setvalue.js +5 -5
  26. package/src/actions/fx-show.js +2 -1
  27. package/src/actions/fx-toggle.js +6 -1
  28. package/src/actions/fx-update.js +1 -1
  29. package/src/events.js +24 -0
  30. package/src/fore.js +128 -17
  31. package/src/fx-bind.js +6 -1
  32. package/src/fx-fore.js +93 -41
  33. package/src/fx-instance.js +95 -70
  34. package/src/fx-model.js +430 -441
  35. package/src/fx-submission.js +423 -405
  36. package/src/getInScopeContext.js +88 -82
  37. package/src/modelitem.js +5 -3
  38. package/src/relevance.js +1 -1
  39. package/src/ui/abstract-control.js +108 -22
  40. package/src/ui/fx-alert.js +0 -1
  41. package/src/ui/fx-container.js +22 -26
  42. package/src/ui/fx-control.js +84 -34
  43. package/src/ui/fx-group.js +5 -0
  44. package/src/ui/fx-inspector.js +5 -0
  45. package/src/ui/fx-output.js +14 -14
  46. package/src/ui/fx-repeat.js +2 -2
  47. package/src/ui/fx-repeatitem.js +5 -3
  48. package/src/ui/fx-switch.js +20 -8
  49. package/src/ui/fx-trigger.js +26 -19
  50. package/src/xpath-evaluation.js +49 -26
  51. package/src/xpath-util.js +26 -28
package/src/fore.js CHANGED
@@ -9,8 +9,19 @@ export class Fore {
9
9
 
10
10
  static TYPE_DEFAULT = 'xs:string';
11
11
 
12
+ /**
13
+ * returns the next `fx-fore` element upwards in tree
14
+ *
15
+ * @param start
16
+ * @returns {*}
17
+ */
18
+ static getFore(start) {
19
+ return start.nodeType === Node.TEXT_NODE ? start.parentNode.closest('fx-fore'):start.closest('fx-fore');
20
+ }
21
+
12
22
  static get ACTION_ELEMENTS() {
13
23
  return [
24
+ 'FX-ACTION',
14
25
  'FX-DELETE',
15
26
  'FX-DISPATCH',
16
27
  'FX-HIDE',
@@ -21,6 +32,7 @@ export class Fore {
21
32
  'FX-RECALCULATE',
22
33
  'FX-REFRESH',
23
34
  'FX-RENEW',
35
+ 'FX-RELOAD',
24
36
  'FX-REPLACE',
25
37
  'FX-RESET',
26
38
  'FX-RETAIN',
@@ -64,16 +76,12 @@ export class Fore {
64
76
  return [
65
77
  'FX-ALERT',
66
78
  'FX-CONTROL',
67
- 'FX-BUTTON',
68
- 'FX-CONTROL',
69
79
  'FX-DIALOG',
70
80
  'FX-FILENAME',
71
81
  'FX-MEDIATYPE',
72
82
  'FX-GROUP',
73
83
  'FX-HINT',
74
- 'FX-INPUT',
75
84
  'FX-ITEMS',
76
- 'FX-LABEL',
77
85
  'FX-OUTPUT',
78
86
  'FX-RANGE',
79
87
  'FX-REPEAT',
@@ -89,6 +97,16 @@ export class Fore {
89
97
  ];
90
98
  }
91
99
 
100
+ static get MODEL_ELEMENTS(){
101
+ return [
102
+ 'FX-BIND',
103
+ 'FX-FUNCTION',
104
+ 'FX-MODEL',
105
+ 'FX-INSTANCE',
106
+ 'FX-SUBMISSION',
107
+ ];
108
+ }
109
+
92
110
  static isUiElement(elementName) {
93
111
  const found = Fore.UI_ELEMENTS.includes(elementName);
94
112
  if (found) {
@@ -133,7 +151,7 @@ export class Fore {
133
151
  if (Fore.isUiElement(element.nodeName) && typeof element.refresh === 'function') {
134
152
  // console.log('refreshing', element, element?.ref);
135
153
  // console.log('refreshing ',element);
136
- element.refresh();
154
+ element.refresh(force);
137
155
  } else if (element.nodeName.toUpperCase() !== 'FX-MODEL') {
138
156
  Fore.refreshChildren(element, force);
139
157
  }
@@ -145,6 +163,61 @@ export class Fore {
145
163
  return refreshed;
146
164
  }
147
165
 
166
+ static copyDom(inputElement){
167
+ console.time('convert');
168
+ const target = new DOMParser().parseFromString('<fx-fore></fx-fore>', 'text/html');
169
+ console.log('copyDom new doc',target);
170
+ console.log('copyDom new body',target.body);
171
+ console.log('copyDom new body',target.querySelector('fx-fore'));
172
+ const newFore = target.querySelector('fx-fore');
173
+ this.convertFromSimple(inputElement,newFore);
174
+ newFore.removeAttribute('convert');
175
+ console.log('converted', newFore);
176
+ return newFore;
177
+ console.timeEnd('convert');
178
+ }
179
+ static convertFromSimple(startElement,targetElement){
180
+ const children = startElement.childNodes;
181
+ if (children) {
182
+ Array.from(children).forEach(node => {
183
+ const lookFor = `FX-${node.nodeName.toUpperCase()}`;
184
+ if (Fore.MODEL_ELEMENTS.includes(lookFor)
185
+ || Fore.UI_ELEMENTS.includes(lookFor)
186
+ || Fore.ACTION_ELEMENTS.includes(lookFor)
187
+ ) {
188
+ const conv = targetElement.ownerDocument.createElement(lookFor);
189
+ console.log('conv', node, conv);
190
+ targetElement.appendChild(conv);
191
+ Fore.copyAttributes(node,conv);
192
+ Fore.convertFromSimple(node,conv);
193
+ } else{
194
+
195
+ if(node.nodeType === Node.TEXT_NODE){
196
+ const copied = targetElement.ownerDocument.createTextNode(node.textContent);
197
+ targetElement.appendChild(copied);
198
+ }
199
+
200
+ if(node.nodeType === Node.ELEMENT_NODE){
201
+ const copied = targetElement.ownerDocument.createElement(node.nodeName);
202
+ targetElement.appendChild(copied);
203
+ Fore.copyAttributes(node,targetElement);
204
+ Fore.convertFromSimple(node,copied);
205
+ }
206
+ }
207
+ });
208
+ }
209
+ }
210
+
211
+ static copyAttributes(source, target) {
212
+ return Array.from(source.attributes).forEach(attribute => {
213
+ target.setAttribute(
214
+ attribute.nodeName,
215
+ attribute.nodeValue,
216
+ );
217
+ });
218
+ }
219
+
220
+
148
221
  /**
149
222
  * Alternative to `closest` that respects subcontrol boundaries
150
223
  */
@@ -168,8 +241,8 @@ export class Fore {
168
241
  * @param instance an fx-instance element
169
242
  * @returns {string|null}
170
243
  */
171
- static getContentType(instance, method) {
172
- if (method === 'urlencoded-post') {
244
+ static getContentType(instance, contentType) {
245
+ if (contentType === 'application/x-www-form-urlencoded') {
173
246
  return 'application/x-www-form-urlencoded; charset=UTF-8';
174
247
  }
175
248
  if (instance.type === 'xml') {
@@ -222,14 +295,23 @@ export class Fore {
222
295
  return fadeOut();
223
296
  }
224
297
 
225
- static dispatch(target, eventName, detail) {
298
+ static async dispatch(target, eventName, detail) {
226
299
  const event = new CustomEvent(eventName, {
227
300
  composed: false,
228
301
  bubbles: true,
229
302
  detail,
230
303
  });
231
- console.log('dispatching', event);
232
- target.dispatchEvent(event);
304
+ event.listenerPromises = [];
305
+ // console.info('dispatching', event.type, target);
306
+ // console.log('!!! DISPATCH_START', eventName);
307
+
308
+ target.dispatchEvent(event);
309
+
310
+ // By now, all listeners for the event should have registered their completion promises to us.
311
+ if (event.listenerPromises.length) {
312
+ await Promise.all(event.listenerPromises);
313
+ }
314
+ // console.log('!!! DISPATCH_DONE', eventName);
233
315
  }
234
316
 
235
317
  static prettifyXml(source) {
@@ -346,13 +428,42 @@ export class Fore {
346
428
  }),
347
429
  );
348
430
  }
349
- hostElement.appendChild(theFore);
350
- theFore.classList.add('widget');
351
- // return theFore;
352
- // theFore.setAttribute('from-src', this.src);
353
- // this.replaceWith(theFore);
431
+ const imported = document.importNode(theFore,true);
432
+ console.log(`########## loaded fore as component ##### ${hostElement.url}`);
433
+ imported.addEventListener(
434
+ 'model-construct-done',
435
+ e => {
436
+ console.log('subcomponent ready', e.target);
437
+ const defaultInst = imported.querySelector('fx-instance');
438
+ // console.log('defaultInst', defaultInst);
439
+ if(hostElement.initialNode){
440
+ const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
441
+ // Note: Clone the input to prevent the inner fore from editing the outer node
442
+ doc.firstElementChild.appendChild(hostElement.initialNode.cloneNode(true));
443
+ // defaultinst.setInstanceData(this.initialNode);
444
+ defaultInst.setInstanceData(doc);
445
+ }
446
+ // console.log('new data', defaultInst.getInstanceData());
447
+ // theFore.getModel().modelConstruct();
448
+ imported.getModel().updateModel();
449
+ imported.refresh();
450
+ return 'done';
451
+
452
+ },
453
+ { once: true },
454
+ );
455
+
456
+ const dummy = hostElement.querySelector('input');
457
+ if (hostElement.hasAttribute('shadow')) {
458
+ dummy.parentNode.removeChild(dummy);
459
+ hostElement.shadowRoot.appendChild(imported);
460
+ } else {
461
+ console.log(this, 'replacing widget with',theFore);
462
+ dummy.replaceWith(imported);
463
+ // this.appendChild(imported);
464
+ }
354
465
  })
355
- .catch(error => {
466
+ /*.catch(error => {
356
467
  hostElement.dispatchEvent(
357
468
  new CustomEvent('error', {
358
469
  composed: false,
@@ -363,7 +474,7 @@ export class Fore {
363
474
  },
364
475
  }),
365
476
  );
366
- });
477
+ });*/
367
478
  }
368
479
 
369
480
  /**
package/src/fx-bind.js CHANGED
@@ -61,7 +61,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
61
61
  */
62
62
  init(model) {
63
63
  this.model = model;
64
- console.log('init binding ', this);
64
+ // console.log('init binding ', this);
65
65
  this.instanceId = this._getInstanceId();
66
66
  this.bindType = this.getModel().getInstance(this.instanceId).type;
67
67
  // console.log('binding type ', this.bindType);
@@ -320,6 +320,11 @@ export class FxBind extends foreElementMixin(HTMLElement) {
320
320
  this,
321
321
  );
322
322
 
323
+ const alert = this.getAlert();
324
+ if (alert) {
325
+ newItem.addAlert(alert);
326
+ }
327
+
323
328
  this.getModel().registerModelItem(newItem);
324
329
  }
325
330
 
package/src/fx-fore.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {Fore} from './fore.js';
2
2
  import './fx-instance.js';
3
- import './fx-model.js';
3
+ import {FxModel} from './fx-model.js';
4
4
  import '@jinntec/jinn-toast';
5
- import {evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
5
+ import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
6
6
  import getInScopeContext from './getInScopeContext.js';
7
7
  import {XPathUtil} from './xpath-util.js';
8
8
 
@@ -14,9 +14,9 @@ import {XPathUtil} from './xpath-util.js';
14
14
  * fx-fore is the outermost container for each form. A form can have exactly one model
15
15
  * with arbitrary number of instances.
16
16
  *
17
- * Main responsiblities are initialization and updating of model and instances, update of UI (refresh) and global messaging.
17
+ * Main responsibilities are initialization and updating of model and instances, update of UI (refresh) and global messaging.
18
18
  *
19
- * @event compute-exception - dispatched in case the dependency graph is cirular
19
+ * @event compute-exception - dispatched in case the dependency graph is circular
20
20
  * @event refresh-done - dispatched after a refresh() run
21
21
  * @event ready - dispatched after Fore has fully been initialized
22
22
  * @event error - dispatches error when template expression fails to evaluate
@@ -55,7 +55,7 @@ export class FxFore extends HTMLElement {
55
55
  constructor() {
56
56
  super();
57
57
  this.model = {};
58
- this.addEventListener('model-construct-done', this._handleModelConstructDone);
58
+ // this.addEventListener('model-construct-done', this._handleModelConstructDone);
59
59
  this.addEventListener('message', this._displayMessage);
60
60
  this.addEventListener('error', this._displayError);
61
61
  window.addEventListener('compute-exception', e => {
@@ -67,19 +67,11 @@ export class FxFore extends HTMLElement {
67
67
 
68
68
  const style = `
69
69
  :host {
70
- // display: none;
71
- height:auto;
72
- padding:var(--model-element-padding);
73
- font-family:Roboto, sans-serif;
74
- color:var(--paper-grey-900);
70
+ display: block;
75
71
  }
76
72
  :host ::slotted(fx-model){
77
73
  display:none;
78
74
  }
79
- // :host(.fx-ready){
80
- // animation: fadein .4s forwards;
81
- // display:block;
82
- // }
83
75
 
84
76
  #modalMessage .dialogActions{
85
77
  text-align:center;
@@ -143,14 +135,6 @@ export class FxFore extends HTMLElement {
143
135
  #messageContent{
144
136
  margin-top:40px;
145
137
  }
146
- @keyframes fadein {
147
- 0% {
148
- opacity:0;
149
- }
150
- 100% {
151
- opacity:1;
152
- }
153
- }
154
138
  `;
155
139
 
156
140
  const html = `
@@ -181,6 +165,8 @@ export class FxFore extends HTMLElement {
181
165
  }
182
166
 
183
167
  connectedCallback() {
168
+ this.style.visibility = 'hidden';
169
+ console.time('init');
184
170
  /*
185
171
  document.addEventListener('ready', (e) =>{
186
172
  if(e.target !== this){
@@ -217,7 +203,15 @@ export class FxFore extends HTMLElement {
217
203
  }
218
204
 
219
205
  const slot = this.shadowRoot.querySelector('slot');
220
- slot.addEventListener('slotchange', event => {
206
+ slot.addEventListener('slotchange', async event => {
207
+
208
+ // preliminary addition for auto-conversion of non-prefixed element into prefixed elements. See fore.js
209
+ if(this.hasAttribute('convert')){
210
+ this.replaceWith(Fore.copyDom(this));
211
+ // Fore.copyDom(this);
212
+ return;
213
+ }
214
+
221
215
  const children = event.target.assignedElements();
222
216
  let modelElement = children.find(
223
217
  modelElem => modelElem.nodeName.toUpperCase() === 'FX-MODEL',
@@ -228,18 +222,21 @@ export class FxFore extends HTMLElement {
228
222
  modelElement = generatedModel;
229
223
  }
230
224
  if (!modelElement.inited) {
231
- console.log(
232
- `########## FORE: kick off processing for ... ${window.location.href} ##########`,
225
+ console.info(
226
+ `%cFore is processing URL ${window.location.href}`,
227
+ "background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
233
228
  );
229
+
234
230
  if (this.src) {
235
231
  console.log('########## FORE: loaded from ... ', this.src, '##########');
236
232
  }
237
- modelElement.modelConstruct();
233
+ await modelElement.modelConstruct();
234
+ this._handleModelConstructDone();
238
235
  }
239
236
  this.model = modelElement;
240
237
  });
241
- this.addEventListener('path-mutated', e => {
242
- console.log('path-mutated event received', e.detail.path, e.detail.index);
238
+ this.addEventListener('path-mutated', () => {
239
+ // console.log('path-mutated event received', e.detail.path, e.detail.index);
243
240
  this.someInstanceDataStructureChanged = true;
244
241
  });
245
242
  }
@@ -287,7 +284,7 @@ export class FxFore extends HTMLElement {
287
284
 
288
285
  // console.log('thefore', theFore)
289
286
  if (!theFore) {
290
- Fore.dispatchEvent(this, 'error', {
287
+ Fore.dispatch(this, 'error', {
291
288
  detail: {
292
289
  message: `Fore element not found in '${this.src}'. Maybe wrapped within 'template' element?`,
293
290
  },
@@ -311,9 +308,13 @@ export class FxFore extends HTMLElement {
311
308
  */
312
309
  handleIntersect(entries, observer) {
313
310
  console.time('refreshLazy');
311
+
314
312
  entries.forEach(entry => {
315
313
  const {target} = entry;
316
314
 
315
+ const fore = Fore.getFore(target);
316
+ if(fore.initialRun) return;
317
+
317
318
  if (entry.isIntersecting) {
318
319
  console.log('in view', entry);
319
320
  // console.log('repeat in view entry', entry.target);
@@ -375,7 +376,8 @@ export class FxFore extends HTMLElement {
375
376
 
376
377
  async refresh(force) {
377
378
  // refresh () {
378
- console.group('### refresh');
379
+ console.info('%crefresh','font-style: italic; background: #8bc34a; color:white; padding:0.3rem 5rem 0.3rem 0.3rem; display:block; width:100%;');
380
+ console.group('refresh', force);
379
381
 
380
382
  console.time('refresh');
381
383
 
@@ -393,7 +395,7 @@ export class FxFore extends HTMLElement {
393
395
  const controlsToRefresh = modelItem.boundControls;
394
396
  if (controlsToRefresh) {
395
397
  controlsToRefresh.forEach(ctrl => {
396
- ctrl.refresh();
398
+ ctrl.refresh(force);
397
399
  });
398
400
  }
399
401
 
@@ -409,7 +411,7 @@ export class FxFore extends HTMLElement {
409
411
  const modelItemOfDep = this.getModel().modelItems.find(mip => mip.path === basePath);
410
412
  // ### refresh all boundControls
411
413
  modelItemOfDep.boundControls.forEach(control => {
412
- control.refresh();
414
+ control.refresh(force);
413
415
  });
414
416
  });
415
417
  needsRefresh = true;
@@ -418,7 +420,7 @@ export class FxFore extends HTMLElement {
418
420
  });
419
421
  this.toRefresh = [];
420
422
  if (!needsRefresh) {
421
- console.log('skipping refresh - no dependants');
423
+ console.log('no dependants to refresh');
422
424
  }
423
425
  } else {
424
426
  Fore.refreshChildren(this, true);
@@ -437,6 +439,8 @@ export class FxFore extends HTMLElement {
437
439
  console.groupEnd();
438
440
  // console.log('### <<<<< dispatching refresh-done - end of UI update cycle >>>>>');
439
441
  // this.dispatchEvent(new CustomEvent('refresh-done'));
442
+ // this.initialRun = false;
443
+ this.style.visibility='visible';
440
444
  Fore.dispatch(this, 'refresh-done', {});
441
445
  }
442
446
 
@@ -449,9 +453,8 @@ export class FxFore extends HTMLElement {
449
453
  * @private
450
454
  */
451
455
  _updateTemplateExpressions() {
452
- // Note the fact we're going over HTML here: therefore the `html` prefix.
453
456
  const search =
454
- "(descendant-or-self::*/(text(), @*))[not(ancestor-or-self::fx-model)][matches(.,'\\{.*\\}')]";
457
+ "(descendant-or-self::*!(text(), @*))[contains(., '{')][substring-after(., '{') => contains('}')][not(ancestor-or-self::fx-model)]";
455
458
 
456
459
  const tmplExpressions = evaluateXPathToNodes(search, this, this);
457
460
  // console.log('template expressions found ', tmplExpressions);
@@ -482,7 +485,18 @@ export class FxFore extends HTMLElement {
482
485
  }
483
486
 
484
487
  _processTemplateExpressions() {
485
- for (const node of this.storedTemplateExpressionByNode.keys()) {
488
+ for (const node of Array.from(this.storedTemplateExpressionByNode.keys())) {
489
+ if (node.nodeType === Node.ATTRIBUTE_NODE) {
490
+ // Attribute nodes are not contained by the document, but their owner elements are!
491
+ if (!node.ownerDocument.contains(node.ownerElement)) {
492
+ this.storedTemplateExpressionByNode.delete(node);
493
+ continue;
494
+ }
495
+ } else if (!node.ownerDocument.contains(node)) {
496
+ // For all other nodes, if the document does not contain them, they are dead
497
+ this.storedTemplateExpressionByNode.delete(node);
498
+ continue;
499
+ }
486
500
  this._processTemplateExpression({
487
501
  node,
488
502
  expr: this.storedTemplateExpressionByNode.get(node),
@@ -497,7 +511,7 @@ export class FxFore extends HTMLElement {
497
511
  const {expr} = exprObj;
498
512
  const {node} = exprObj;
499
513
  // console.log('expr ', expr);
500
- this.evaluateTemplateExpression(expr, node, this);
514
+ this.evaluateTemplateExpression(expr, node);
501
515
  }
502
516
 
503
517
  /**
@@ -552,11 +566,43 @@ export class FxFore extends HTMLElement {
552
566
 
553
567
  /**
554
568
  * called when `model-construct-done` event is received to
555
- * start initing of the UI.
569
+ * start initing the UI.
556
570
  *
557
571
  * @private
558
572
  */
559
573
  _handleModelConstructDone() {
574
+ /*
575
+ listening on beforeunload after model is constructed - this is to be able to evaluate a condition on the data
576
+ that specifies whether or not to show confirmation.
577
+ */
578
+ if(this.hasAttribute('show-confirmation')){
579
+ const condition = this.getAttribute('show-confirmation');
580
+ if(condition
581
+ && condition !== 'show-confirmation'
582
+ && condition !== 'true'
583
+ && condition !== ''){
584
+ window.addEventListener('beforeunload', event => {
585
+ const mustDisplay = evaluateXPathToBoolean(condition, this.getModel().getDefaultContext(), this)
586
+ if(mustDisplay){
587
+ console.log('have to display confirmation')
588
+ return event.returnValue = 'are you sure';
589
+ }
590
+ event.preventDefault();
591
+ console.log('do not display confirmation')
592
+ })
593
+ }else{
594
+ window.addEventListener('beforeunload', event => {
595
+ // if(AbstractAction.dataChanged){
596
+ if(FxModel.dataChanged){
597
+ console.log('have to display confirmation')
598
+ return event.returnValue = 'are you sure';
599
+ }
600
+ event.preventDefault();
601
+ console.log('do not display confirmation')
602
+ })
603
+ }
604
+ }
605
+
560
606
  this._initUI();
561
607
  }
562
608
 
@@ -700,7 +746,8 @@ export class FxFore extends HTMLElement {
700
746
  };
701
747
  */
702
748
 
703
- await this.refresh();
749
+ // First refresh should be forced
750
+ await this.refresh(true);
704
751
  // this.style.display='block'
705
752
  this.classList.add('fx-ready');
706
753
  document.body.classList.add('fx-ready');
@@ -708,9 +755,14 @@ export class FxFore extends HTMLElement {
708
755
  this.ready = true;
709
756
  this.initialRun = false;
710
757
  // console.log('### >>>>> dispatching ready >>>>>', this);
711
- console.log('### modelItems: ', this.getModel().modelItems);
712
- console.log('### <<<<< FORE: form fully initialized...', this);
758
+ // console.log('### modelItems: ', this.getModel().modelItems);
713
759
  Fore.dispatch(this, 'ready', {});
760
+ console.info(
761
+ `%cPage Initialization done`,
762
+ "background:#64b5f6; color:white; padding:1rem; display:block; white-space: nowrap; border-radius:0.3rem;width:100%;",
763
+ );
764
+ console.timeEnd('init');
765
+ console.log('dataChanged', FxModel.dataChanged);
714
766
  }
715
767
 
716
768
  registerLazyElement(element) {