@jinntec/fore 1.4.0 → 1.6.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 (71) hide show
  1. package/dist/fore-dev.js +2 -36
  2. package/dist/fore-dev.js.map +1 -1
  3. package/dist/fore.js +2 -30
  4. package/dist/fore.js.map +1 -1
  5. package/index.js +13 -0
  6. package/package.json +9 -5
  7. package/resources/fore.css +178 -92
  8. package/src/DependencyNotifyingDomFacade.js +1 -2
  9. package/src/ForeElementMixin.js +31 -5
  10. package/src/actions/abstract-action.js +379 -270
  11. package/src/actions/fx-action.js +0 -1
  12. package/src/actions/fx-append.js +1 -2
  13. package/src/actions/fx-confirm.js +12 -0
  14. package/src/actions/fx-copy.js +0 -1
  15. package/src/actions/fx-delete.js +31 -9
  16. package/src/actions/fx-dispatch.js +19 -5
  17. package/src/actions/fx-hide.js +19 -0
  18. package/src/actions/fx-insert.js +72 -8
  19. package/src/actions/fx-load.js +253 -0
  20. package/src/actions/fx-message.js +22 -7
  21. package/src/actions/fx-refresh.js +11 -1
  22. package/src/actions/fx-reload.js +12 -2
  23. package/src/actions/fx-replace.js +5 -4
  24. package/src/actions/fx-reset.js +48 -0
  25. package/src/actions/fx-return.js +0 -1
  26. package/src/actions/fx-send.js +40 -2
  27. package/src/actions/fx-setfocus.js +25 -7
  28. package/src/actions/fx-setvalue.js +32 -4
  29. package/src/actions/fx-show.js +14 -2
  30. package/src/actions/fx-toggle.js +0 -1
  31. package/src/actions/fx-update.js +9 -0
  32. package/src/events.js +0 -1
  33. package/src/fore.js +119 -63
  34. package/src/functions/common-function.js +28 -0
  35. package/src/fx-bind.js +7 -7
  36. package/src/fx-fore.js +207 -54
  37. package/src/fx-instance.js +55 -17
  38. package/src/fx-model.js +31 -33
  39. package/src/fx-submission.js +50 -47
  40. package/src/getInScopeContext.js +22 -8
  41. package/src/lab/fore-component.js +90 -0
  42. package/src/lab/instance-inspector.js +56 -0
  43. package/src/lab/template.html +16 -0
  44. package/src/relevance.js +27 -1
  45. package/src/tools/adi.js +1056 -0
  46. package/src/tools/fx-action-log.js +662 -0
  47. package/src/tools/fx-devtools.js +444 -0
  48. package/src/tools/fx-dom-inspector.js +609 -0
  49. package/src/tools/fx-json-instance.js +435 -0
  50. package/src/tools/fx-log-item.js +133 -0
  51. package/src/tools/fx-log-settings.js +474 -0
  52. package/src/tools/fx-minimap.js +194 -0
  53. package/src/tools/helpers.js +132 -0
  54. package/src/ui/abstract-control.js +41 -3
  55. package/src/ui/fx-action-log.js +358 -0
  56. package/src/ui/fx-alert.js +0 -1
  57. package/src/ui/fx-container.js +14 -3
  58. package/src/ui/fx-control.js +553 -474
  59. package/src/ui/fx-dialog.js +2 -0
  60. package/src/ui/fx-dom-inspector.js +1255 -0
  61. package/src/ui/fx-group.js +3 -4
  62. package/src/ui/fx-hint.js +2 -4
  63. package/src/ui/fx-inspector.js +5 -6
  64. package/src/ui/fx-items.js +55 -14
  65. package/src/ui/fx-output.js +36 -17
  66. package/src/ui/fx-repeat-attributes.js +409 -0
  67. package/src/ui/fx-repeat.js +12 -6
  68. package/src/ui/fx-switch.js +14 -3
  69. package/src/ui/fx-trigger.js +13 -1
  70. package/src/xpath-evaluation.js +109 -26
  71. package/src/xpath-util.js +55 -1
package/src/fx-fore.js CHANGED
@@ -2,9 +2,10 @@ import {Fore} from './fore.js';
2
2
  import './fx-instance.js';
3
3
  import {FxModel} from './fx-model.js';
4
4
  import '@jinntec/jinn-toast';
5
- import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
5
+ import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToFirstNode, evaluateXPathToString} from './xpath-evaluation.js';
6
6
  import getInScopeContext from './getInScopeContext.js';
7
7
  import {XPathUtil} from './xpath-util.js';
8
+ import {FxRepeatAttributes} from './ui/fx-repeat-attributes.js';
8
9
 
9
10
  /**
10
11
  * Main class for Fore.Outermost container element for each Fore application.
@@ -24,6 +25,8 @@ import {XPathUtil} from './xpath-util.js';
24
25
  * @ts-check
25
26
  */
26
27
  export class FxFore extends HTMLElement {
28
+ static outermostHandler = null;
29
+
27
30
  static get properties() {
28
31
  return {
29
32
  /**
@@ -41,6 +44,12 @@ export class FxFore extends HTMLElement {
41
44
  ready: {
42
45
  type: Boolean,
43
46
  },
47
+ /**
48
+ *
49
+ */
50
+ validateOn: {
51
+ type: String
52
+ }
44
53
  };
45
54
  }
46
55
 
@@ -55,9 +64,13 @@ export class FxFore extends HTMLElement {
55
64
  constructor() {
56
65
  super();
57
66
  this.model = {};
67
+ this.inited=false;
58
68
  // this.addEventListener('model-construct-done', this._handleModelConstructDone);
69
+ // todo: refactoring - these should rather go into connectedcallback
59
70
  this.addEventListener('message', this._displayMessage);
60
71
  this.addEventListener('error', this._displayError);
72
+ this.addEventListener('warn', this._displayWarning);
73
+ this.addEventListener('log', this._logError);
61
74
  window.addEventListener('compute-exception', e => {
62
75
  console.error('circular dependency: ', e);
63
76
  });
@@ -65,6 +78,10 @@ export class FxFore extends HTMLElement {
65
78
  this.ready = false;
66
79
  this.storedTemplateExpressionByNode = new Map();
67
80
 
81
+ // Stores the outer most action handler. If an action handler is already running, all
82
+ // updates are included in that one
83
+ this.outermostHandler = null;
84
+
68
85
  const style = `
69
86
  :host {
70
87
  display: block;
@@ -135,13 +152,20 @@ export class FxFore extends HTMLElement {
135
152
  #messageContent{
136
153
  margin-top:40px;
137
154
  }
155
+ .warning{
156
+ background:orange;
157
+ }
138
158
  `;
139
159
 
140
160
  const html = `
161
+ <noscript>This page uses Web Components and needs JavaScript to be enabled..</noscript>
162
+
141
163
  <jinn-toast id="message" gravity="bottom" position="left"></jinn-toast>
142
164
  <jinn-toast id="sticky" gravity="bottom" position="left" duration="-1" close="true" data-class="sticky-message"></jinn-toast>
143
- <jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="left" gravity="bottom"></jinn-toast>
144
- <slot></slot>
165
+ <jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="left" gravity="bottom" escape-markup="false"></jinn-toast>
166
+ <jinn-toast id="warn" text="warning" duration="-1" data-class="warning" close="true" position="right" gravity="bottom"></jinn-toast>
167
+ <slot id="default"></slot>
168
+ <slot name="messages"></slot>
145
169
  <div id="modalMessage" class="overlay">
146
170
  <div class="popup">
147
171
  <h2></h2>
@@ -149,6 +173,7 @@ export class FxFore extends HTMLElement {
149
173
  <div id="messageContent"></div>
150
174
  </div>
151
175
  </div>
176
+ <slot name="event"></slot>
152
177
  `;
153
178
 
154
179
  this.attachShadow({mode: 'open'});
@@ -162,6 +187,8 @@ export class FxFore extends HTMLElement {
162
187
  this.toRefresh = [];
163
188
  this.initialRun = true;
164
189
  this.someInstanceDataStructureChanged = false;
190
+ this.repeatsFromAttributesCreated = false;
191
+ this.validateOn = this.hasAttribute('validate-on') ? this.getAttribute('validate-on'):'update';
165
192
  }
166
193
 
167
194
  connectedCallback() {
@@ -202,10 +229,12 @@ export class FxFore extends HTMLElement {
202
229
  return;
203
230
  }
204
231
 
205
- const slot = this.shadowRoot.querySelector('slot');
206
- slot.addEventListener('slotchange', async event => {
232
+ this._injectDevtools();
207
233
 
234
+ const slot = this.shadowRoot.querySelector('slot#default');
235
+ slot.addEventListener('slotchange', async event => {
208
236
  // preliminary addition for auto-conversion of non-prefixed element into prefixed elements. See fore.js
237
+ if(this.inited) return;
209
238
  if(this.hasAttribute('convert')){
210
239
  this.replaceWith(Fore.copyDom(this));
211
240
  // Fore.copyDom(this);
@@ -220,6 +249,9 @@ export class FxFore extends HTMLElement {
220
249
  const generatedModel = document.createElement('fx-model');
221
250
  this.appendChild(generatedModel);
222
251
  modelElement = generatedModel;
252
+ // We are going to get a new slotchange event immediately, because we changed a slot.
253
+ // so cancel this one.
254
+ return;
223
255
  }
224
256
  if (!modelElement.inited) {
225
257
  console.info(
@@ -227,20 +259,33 @@ export class FxFore extends HTMLElement {
227
259
  "background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
228
260
  );
229
261
 
230
- if (this.src) {
231
- console.log('########## FORE: loaded from ... ', this.src, '##########');
232
- }
233
262
  await modelElement.modelConstruct();
234
263
  this._handleModelConstructDone();
235
264
  }
236
265
  this.model = modelElement;
266
+
267
+ this._createRepeatsFromAttributes();
268
+ this.inited = true;
269
+
237
270
  });
238
271
  this.addEventListener('path-mutated', () => {
239
- // console.log('path-mutated event received', e.detail.path, e.detail.index);
240
272
  this.someInstanceDataStructureChanged = true;
241
273
  });
242
274
  }
243
275
 
276
+ _injectDevtools(){
277
+ if (this.ownerDocument.querySelector('fx-devtools')) {
278
+ // There's already a devtools, so we can ignore this one.
279
+ // One devtools can focus multiple fore elements
280
+ return;
281
+ }
282
+ const search = window.location.search;
283
+ const urlParams = new URLSearchParams(search);
284
+ if(urlParams.has('inspect')){
285
+ const devtools = document.createElement('fx-devtools');
286
+ document.body.appendChild(devtools);
287
+ }
288
+ }
244
289
  addToRefresh(modelItem) {
245
290
  const found = this.toRefresh.find(mi => mi.path === modelItem.path);
246
291
  if (!found) {
@@ -255,7 +300,7 @@ export class FxFore extends HTMLElement {
255
300
  * @private
256
301
  */
257
302
  _loadFromSrc() {
258
- console.log('########## loading Fore from ', this.src, '##########');
303
+ // console.log('########## loading Fore from ', this.src, '##########');
259
304
  fetch(this.src, {
260
305
  method: 'GET',
261
306
  mode: 'cors',
@@ -291,6 +336,12 @@ export class FxFore extends HTMLElement {
291
336
  });
292
337
  }
293
338
  theFore.setAttribute('from-src', this.src);
339
+ const thisAttrs = this.attributes;
340
+ Array.from(thisAttrs).forEach(attr =>{
341
+ if(attr.name !== 'src'){
342
+ theFore.setAttribute(attr.name,attr.value);
343
+ }
344
+ });
294
345
  this.replaceWith(theFore);
295
346
  })
296
347
  .catch(() => {
@@ -307,7 +358,7 @@ export class FxFore extends HTMLElement {
307
358
  * @param observer
308
359
  */
309
360
  handleIntersect(entries, observer) {
310
- console.time('refreshLazy');
361
+ // console.time('refreshLazy');
311
362
 
312
363
  entries.forEach(entry => {
313
364
  const {target} = entry;
@@ -316,7 +367,7 @@ export class FxFore extends HTMLElement {
316
367
  if(fore.initialRun) return;
317
368
 
318
369
  if (entry.isIntersecting) {
319
- console.log('in view', entry);
370
+ // console.log('in view', entry);
320
371
  // console.log('repeat in view entry', entry.target);
321
372
  // const target = entry.target;
322
373
  // if(target.hasAttribute('refresh-on-view')){
@@ -325,17 +376,17 @@ export class FxFore extends HTMLElement {
325
376
 
326
377
  // todo: too restrictive here? what if target is a usual html element? shouldn't it refresh downwards?
327
378
  if (typeof target.refresh === 'function') {
328
- console.log('refreshing target', target);
379
+ // console.log('refreshing target', target);
329
380
  target.refresh(target, true);
330
381
  } else {
331
- console.log('refreshing children', target);
382
+ // console.log('refreshing children', target);
332
383
  Fore.refreshChildren(target, true);
333
384
  }
334
385
  }
335
386
  });
336
387
  entries[0].target.getOwnerForm().dispatchEvent(new CustomEvent('refresh-done'));
337
388
 
338
- console.timeEnd('refreshLazy');
389
+ // console.timeEnd('refreshLazy');
339
390
  }
340
391
 
341
392
  evaluateToNodes(xpath, context) {
@@ -361,8 +412,8 @@ export class FxFore extends HTMLElement {
361
412
  *
362
413
  */
363
414
  async forceRefresh() {
364
- console.time('refresh');
365
- console.group('### forced refresh', this);
415
+ // console.time('refresh');
416
+ // console.group('### forced refresh', this);
366
417
 
367
418
  Fore.refreshChildren(this, true);
368
419
  this._updateTemplateExpressions();
@@ -370,23 +421,16 @@ export class FxFore extends HTMLElement {
370
421
  this._processTemplateExpressions();
371
422
  Fore.dispatch(this, 'refresh-done', {});
372
423
 
373
- console.groupEnd();
374
- console.timeEnd('refresh');
424
+ // console.groupEnd();
425
+ // console.timeEnd('refresh');
375
426
  }
376
427
 
377
428
  async refresh(force) {
378
429
  // 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);
381
-
382
- console.time('refresh');
383
-
384
430
  // ### refresh Fore UI elements
385
- // console.time('refreshChildren');
386
- console.log('toRefresh', this.toRefresh);
387
-
388
431
  // if (!this.initialRun && this.toRefresh.length !== 0) {
389
432
  if (!force && !this.initialRun && this.toRefresh.length !== 0) {
433
+ // console.log('toRefresh', this.toRefresh);
390
434
  let needsRefresh = false;
391
435
 
392
436
  // ### after recalculation the changed modelItems are copied to 'toRefresh' array for processing
@@ -419,10 +463,20 @@ export class FxFore extends HTMLElement {
419
463
  }
420
464
  });
421
465
  this.toRefresh = [];
466
+ /*
422
467
  if (!needsRefresh) {
423
468
  console.log('no dependants to refresh');
424
469
  }
470
+ */
425
471
  } else {
472
+ // ### resetting visited state for controls to refresh
473
+ /*
474
+ const visited = this.parentNode.querySelectorAll('.visited');
475
+ Array.from(visited).forEach(v =>{
476
+ v.classList.remove('visited');
477
+ });
478
+ */
479
+
426
480
  Fore.refreshChildren(this, true);
427
481
  // console.timeEnd('refreshChildren');
428
482
  }
@@ -434,9 +488,6 @@ export class FxFore extends HTMLElement {
434
488
  }
435
489
  this._processTemplateExpressions();
436
490
 
437
- console.timeEnd('refresh');
438
-
439
- console.groupEnd();
440
491
  // console.log('### <<<<< dispatching refresh-done - end of UI update cycle >>>>>');
441
492
  // this.dispatchEvent(new CustomEvent('refresh-done'));
442
493
  // this.initialRun = false;
@@ -488,12 +539,12 @@ export class FxFore extends HTMLElement {
488
539
  for (const node of Array.from(this.storedTemplateExpressionByNode.keys())) {
489
540
  if (node.nodeType === Node.ATTRIBUTE_NODE) {
490
541
  // Attribute nodes are not contained by the document, but their owner elements are!
491
- if (!node.ownerDocument.contains(node.ownerElement)) {
542
+ if (!XPathUtil.contains(this, node.ownerElement)) {
492
543
  this.storedTemplateExpressionByNode.delete(node);
493
544
  continue;
494
545
  }
495
- } else if (!node.ownerDocument.contains(node)) {
496
- // For all other nodes, if the document does not contain them, they are dead
546
+ } else if (!XPathUtil.contains(this, node)) {
547
+ // For all other nodes, if this `fore` element does not contain them, they are dead
497
548
  this.storedTemplateExpressionByNode.delete(node);
498
549
  continue;
499
550
  }
@@ -515,10 +566,9 @@ export class FxFore extends HTMLElement {
515
566
  }
516
567
 
517
568
  /**
518
- * evaluate a template expression (some expression in {} brackets) on a node (either text- or attribute node.
519
- * @param input The string to parse for expressions
569
+ * evaluate a template expression on a node either text- or attribute node.
570
+ * @param expr The string to parse for expressions
520
571
  * @param node the node which will get updated with evaluation result
521
- * @param form the form element
522
572
  */
523
573
  evaluateTemplateExpression(expr, node) {
524
574
  const replaced = expr.replace(/{[^}]*}/g, match => {
@@ -536,11 +586,15 @@ export class FxFore extends HTMLElement {
536
586
  // Templates are special: they use the namespace configuration from the place where they are
537
587
  // being defined
538
588
  const instanceId = XPathUtil.getInstanceId(naked);
539
- const inst = this.getModel().getInstance(instanceId);
540
- try {
589
+
590
+ // If there is an instance referred
591
+ const inst = instanceId ? this.getModel().getInstance(instanceId) : this.getModel().getDefaultInstance();
592
+
593
+ try {
541
594
  return evaluateXPathToString(naked, inscope, node, null, inst);
542
595
  } catch (error) {
543
- console.log('ignoring unparseable expr');
596
+ console.warn('ignoring unparseable expr', error);
597
+
544
598
  return match;
545
599
  }
546
600
  });
@@ -584,21 +638,17 @@ export class FxFore extends HTMLElement {
584
638
  window.addEventListener('beforeunload', event => {
585
639
  const mustDisplay = evaluateXPathToBoolean(condition, this.getModel().getDefaultContext(), this)
586
640
  if(mustDisplay){
587
- console.log('have to display confirmation')
588
641
  return event.returnValue = 'are you sure';
589
642
  }
590
643
  event.preventDefault();
591
- console.log('do not display confirmation')
592
644
  })
593
645
  }else{
594
646
  window.addEventListener('beforeunload', event => {
595
647
  // if(AbstractAction.dataChanged){
596
648
  if(FxModel.dataChanged){
597
- console.log('have to display confirmation')
598
649
  return event.returnValue = 'are you sure';
599
650
  }
600
651
  event.preventDefault();
601
- console.log('do not display confirmation')
602
652
  })
603
653
  }
604
654
  }
@@ -616,7 +666,7 @@ export class FxFore extends HTMLElement {
616
666
  async _lazyCreateInstance() {
617
667
  const model = this.querySelector('fx-model');
618
668
  if (model.instances.length === 0) {
619
- console.log('### lazy creation of instance');
669
+ // console.log('### lazy creation of instance');
620
670
  const generatedInstance = document.createElement('fx-instance');
621
671
  model.appendChild(generatedInstance);
622
672
 
@@ -625,7 +675,7 @@ export class FxFore extends HTMLElement {
625
675
  this._generateInstance(this, generated.firstElementChild);
626
676
  generatedInstance.instanceData = generated;
627
677
  model.instances.push(generatedInstance);
628
- console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
678
+ // console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
629
679
  }
630
680
  }
631
681
 
@@ -638,11 +688,9 @@ export class FxFore extends HTMLElement {
638
688
  const ref = start.getAttribute('ref');
639
689
 
640
690
  if (ref.includes('/')) {
641
- console.log('complex path to create ', ref);
691
+ // console.log('complex path to create ', ref);
642
692
  const steps = ref.split('/');
643
693
  steps.forEach(step => {
644
- console.log('step ', step);
645
-
646
694
  // const generated = document.createElement(ref);
647
695
  parent = this._generateNode(parent, step, start);
648
696
  });
@@ -722,8 +770,9 @@ export class FxFore extends HTMLElement {
722
770
  * @private
723
771
  */
724
772
  async _initUI() {
725
- console.log('### _initUI()');
773
+ // console.log('### _initUI()');
726
774
  if (!this.initialRun) return;
775
+ this.classList.add('initialRun');
727
776
  await this._lazyCreateInstance();
728
777
 
729
778
  // console.log('registering variables!');
@@ -757,12 +806,8 @@ export class FxFore extends HTMLElement {
757
806
  // console.log('### >>>>> dispatching ready >>>>>', this);
758
807
  // console.log('### modelItems: ', this.getModel().modelItems);
759
808
  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
- );
809
+ // console.log('dataChanged', FxModel.dataChanged);
764
810
  console.timeEnd('init');
765
- console.log('dataChanged', FxModel.dataChanged);
766
811
  }
767
812
 
768
813
  registerLazyElement(element) {
@@ -802,6 +847,50 @@ export class FxFore extends HTMLElement {
802
847
  toast.showToast(msg);
803
848
  }
804
849
 
850
+ _displayWarning(e){
851
+ const msg = e.detail.message;
852
+ // this._showMessage('modal', msg);
853
+ const path = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
854
+ const toast = this.shadowRoot.querySelector('#warn');
855
+ toast.showToast(`WARN: ${path}:${msg}`);
856
+ }
857
+
858
+ _logError(e) {
859
+ e.stopPropagation();
860
+ e.preventDefault();
861
+
862
+ const div = document.createElement('div');
863
+ div.setAttribute('slot','messages');
864
+ div.setAttribute('data-level',e.detail.level);
865
+
866
+ const id = document.createElement('div');
867
+ id.textContent = `"${e.detail.id}"`;
868
+ div.appendChild(id);
869
+
870
+ const path = document.createElement('div');
871
+ const pathExpr = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
872
+ // console.log('pathExpr',pathExpr)
873
+ path.textContent = pathExpr;
874
+ div.appendChild(path);
875
+
876
+ const message = document.createElement('div');
877
+ message.textContent = e.detail.message;
878
+ div.appendChild(message);
879
+
880
+ /*
881
+ const path = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
882
+ div.innerText = `${path} :: ${e.detail.message}`;
883
+ */
884
+ this.appendChild(div);
885
+ div.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
886
+
887
+
888
+ const errorElement = evaluateXPathToFirstNode(`/${pathExpr}`,document,null);
889
+ errorElement.classList.add('fore-error');
890
+
891
+
892
+ }
893
+
805
894
  _showMessage(level, msg) {
806
895
  if (level === 'modal') {
807
896
  // this.$.messageContent.innerText = msg;
@@ -818,6 +907,70 @@ export class FxFore extends HTMLElement {
818
907
  toast.showToast(msg);
819
908
  }
820
909
  }
910
+
911
+ /**
912
+ * wraps the element having a 'data-ref' attribute with an fx-repeat-attributes element.
913
+ * @private
914
+ */
915
+ _createRepeatsFromAttributes() {
916
+ if(this.repeatsFromAttributesCreated) return;
917
+ const repeats = this.querySelectorAll('[data-ref]');
918
+ if(repeats){
919
+ Array.from(repeats).forEach(item =>{
920
+ if(item.closest('fx-control')) return;
921
+ /*
922
+ const parentRepeat = item.closest('fx-repeat');
923
+ if(parentRepeat){
924
+ this.dispatchEvent(
925
+ new CustomEvent('log', {
926
+ composed: false,
927
+ bubbles: true,
928
+ cancelable:true,
929
+ detail: { id:this.id, message: `nesting elements with data-ref attributes within fx-repeat is not supported by now`, level:'Error'},
930
+ }),
931
+ );
932
+ }
933
+ */
934
+
935
+ const table = item.parentNode.closest('table');
936
+ let host;
937
+ if(table){
938
+ host = table.cloneNode(true);
939
+ }else{
940
+ host = item.cloneNode(true);
941
+ }
942
+ // ### clone original item to move it into fx-repeat-attributes
943
+ // const host = item.cloneNode(true);
944
+
945
+ // ### create wrapper element
946
+ const repeatFromAttr = new FxRepeatAttributes();
947
+ // const repeatFromAttr = document.createElement('fx-repeat-attributes');
948
+
949
+ // ### copy the value of 'data-ref' to 'ref' on fx-repeat-attributes
950
+ repeatFromAttr.setAttribute('ref',item.getAttribute('data-ref'));
951
+ // item.removeAttribute('data-ref');
952
+
953
+ // ### append the cloned original element to fx-repeat-attributes
954
+ repeatFromAttr.appendChild(host);
955
+
956
+ // ### insert fx-repeat-attributes element before element with the 'data-ref'
957
+ // repeats[0].parentNode.insertBefore(repeatFromAttr,repeats[0]);
958
+
959
+ if(table){
960
+ table.parentNode.insertBefore(repeatFromAttr,table);
961
+ table.parentNode.removeChild(table);
962
+ }else{
963
+ item.parentNode.insertBefore(repeatFromAttr,item);
964
+ item.parentNode.removeChild(item);
965
+ }
966
+
967
+ // ### remove original item from DOM
968
+ item.setAttribute('insertPoint','');
969
+
970
+ });
971
+ }
972
+ this.repeatsFromAttributesCreated = true;
973
+ }
821
974
  }
822
975
 
823
976
  if (!customElements.get('fx-fore')) {