@jinntec/fore 2.4.2 → 2.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.
package/src/fx-fore.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  import getInScopeContext from './getInScopeContext.js';
12
12
  import { XPathUtil } from './xpath-util.js';
13
13
  import { FxRepeatAttributes } from './ui/fx-repeat-attributes.js';
14
+ import { ModelItem } from './modelitem.js';
14
15
 
15
16
  /**
16
17
  * Makes the dirty state of the form.
@@ -49,6 +50,13 @@ export class FxFore extends HTMLElement {
49
50
 
50
51
  static get properties() {
51
52
  return {
53
+ /**
54
+ * wether to create nodes that are missing in the loaded data and
55
+ * auto-create nodes when there's a binding found in the UI.
56
+ */
57
+ createNodes: {
58
+ type: Boolean,
59
+ },
52
60
  /**
53
61
  * ignore certain nodes for template expression search
54
62
  */
@@ -238,6 +246,9 @@ export class FxFore extends HTMLElement {
238
246
  : 'update';
239
247
  // this.mergePartial = this.hasAttribute('merge-partial')? true:false;
240
248
  this.mergePartial = false;
249
+ this.createNodes = this.hasAttribute('create-nodes') ? true : false;
250
+ this._localNamesWithChanges = new Set();
251
+ this.setAttribute('role', 'form'); // set aria role
241
252
  }
242
253
 
243
254
  connectedCallback() {
@@ -245,23 +256,23 @@ export class FxFore extends HTMLElement {
245
256
  console.time('init');
246
257
  this.strict = !!this.hasAttribute('strict');
247
258
  /*
248
- document.addEventListener('ready', (e) =>{
249
- if(e.target !== this){
250
- // e.preventDefault();
251
- console.log('>>> e', e);
252
- console.log('event this', this);
253
- // console.log('event eventPhase', e.eventPhase);
254
- // console.log('event cancelable', e.cancelable);
255
- console.log('event target', e.target);
256
- console.log('event composed', e.composedPath());
257
- console.log('<<< event stopping');
258
- e.stopPropagation();
259
- }else{
260
- console.log('event proceed', this);
261
- }
262
- // e.stopImmediatePropagation();
263
- },true);
264
- */
259
+ document.addEventListener('ready', (e) =>{
260
+ if(e.target !== this){
261
+ // e.preventDefault();
262
+ console.log('>>> e', e);
263
+ console.log('event this', this);
264
+ // console.log('event eventPhase', e.eventPhase);
265
+ // console.log('event cancelable', e.cancelable);
266
+ console.log('event target', e.target);
267
+ console.log('event composed', e.composedPath());
268
+ console.log('<<< event stopping');
269
+ e.stopPropagation();
270
+ }else{
271
+ console.log('event proceed', this);
272
+ }
273
+ // e.stopImmediatePropagation();
274
+ },true);
275
+ */
265
276
  this.ignoreExpressions = this.hasAttribute('ignore-expressions')
266
277
  ? this.getAttribute('ignore-expressions')
267
278
  : null;
@@ -359,6 +370,11 @@ export class FxFore extends HTMLElement {
359
370
  const devtools = document.createElement('fx-devtools');
360
371
  document.body.appendChild(devtools);
361
372
  }
373
+ if (urlParams.has('lens')) {
374
+ const lens = document.createElement('fx-lens');
375
+ document.body.appendChild(lens);
376
+ lens.setAttribute('open', 'open');
377
+ }
362
378
  }
363
379
 
364
380
  /**
@@ -374,6 +390,16 @@ export class FxFore extends HTMLElement {
374
390
  }
375
391
  }
376
392
 
393
+ /**
394
+ * Signal something happened with an element with the given local name. This will be used in the
395
+ * next (non-forceful) refresh to detect whether a component (usually a repeat) should update
396
+ *
397
+ * @param {string} localNameOfElement
398
+ */
399
+ signalChangeToElement(localNameOfElement) {
400
+ this._localNamesWithChanges.add(localNameOfElement);
401
+ }
402
+
377
403
  /**
378
404
  * Raise a flag that there might be new template expressions under some node. This happens with
379
405
  * repeats updating (new repeat items can have new template expressions) or switches changing their case (new case = new raw HTML)
@@ -450,12 +476,12 @@ export class FxFore extends HTMLElement {
450
476
  disconnectedCallback() {
451
477
  this.removeEventListener('dragstart', this.dragstart);
452
478
  /*
453
- this.removeEventListener('model-construct-done', this._handleModelConstructDone);
454
- this.removeEventListener('message', this._displayMessage);
455
- this.removeEventListener('error', this._displayError);
456
- this.storedTemplateExpressionByNode=null;
457
- this.shadowRoot = undefined;
458
- */
479
+ this.removeEventListener('model-construct-done', this._handleModelConstructDone);
480
+ this.removeEventListener('message', this._displayMessage);
481
+ this.removeEventListener('error', this._displayError);
482
+ this.storedTemplateExpressionByNode=null;
483
+ this.shadowRoot = undefined;
484
+ */
459
485
  }
460
486
 
461
487
  /**
@@ -488,106 +514,45 @@ export class FxFore extends HTMLElement {
488
514
  * @param {(boolean|{reason:'index-function'})} [force]fx-fore
489
515
  */
490
516
  async refresh(force) {
491
- /*
492
-
493
- if (!changedPaths) {
494
- changedPaths = this.toRefresh.map(item => item.path);
495
- } else {
496
- this.toRefresh.push(
497
- ...changedPaths
498
- .map(
499
- path =>
500
- this.getModel()
501
- .modelItems
502
- .find(item => item.path === path)
503
- )
504
- .filter(Boolean)
505
- );
506
-
507
- for(const changedPath of changedPaths) {
508
- for (const repeat of this.querySelectorAll('fx-repeat')) {
509
- if (repeat.closest('fx-fore') !== this) {
510
- continue;
511
- }
512
-
513
- if (repeat.touchedPaths && repeat.touchedPaths.has(changedPath)) {
514
- // Make a temporary model-item-like structure for this
515
- this.toRefresh.push({
516
- path: changedPath,
517
- boundControls: [repeat]
518
- });
519
-
520
- console.log('Found a repeat to update!!!', repeat)
521
- }
522
- }
523
- }
524
- }
525
- */
526
517
  if (this.isRefreshing) {
527
518
  return;
528
519
  }
520
+
521
+ if (force !== true && this._localNamesWithChanges.size > 0) {
522
+ force = {
523
+ ...(force || { reason: undefined }),
524
+ elementLocalnamesWithChanges: Array.from(this._localNamesWithChanges),
525
+ };
526
+ this._localNamesWithChanges.clear();
527
+ }
528
+
529
529
  this.isRefreshing = true;
530
- // console.log(`### <<<<< refresh() on '${this.id}' >>>>>`);
531
530
 
532
531
  // refresh () {
533
532
  // ### refresh Fore UI elements
534
533
  // if (!this.initialRun && this.toRefresh.length !== 0) {
534
+ // if (!this.initialRun && this.toRefresh.length !== 0) {
535
535
  if (!force && !this.initialRun && this.toRefresh.length !== 0) {
536
- // console.log('toRefresh', this.toRefresh);
537
- let needsRefresh = false;
538
-
539
- // ### after recalculation the changed modelItems are copied to 'toRefresh' array for processing
540
- this.toRefresh.forEach(modelItem => {
541
- // check if modelItem has boundControls - if so, call refresh() for each of them
542
- const controlsToRefresh = modelItem.boundControls;
543
- if (controlsToRefresh) {
544
- controlsToRefresh.forEach(ctrl => {
545
- ctrl.refresh(force);
546
- });
547
- }
548
-
549
- // ### check if other controls depend on current modelItem
550
- const { mainGraph } = this.getModel();
551
- if (mainGraph && mainGraph.hasNode(modelItem.path)) {
552
- const deps = this.getModel().mainGraph.dependentsOf(modelItem.path, false);
553
- // ### iterate dependant modelItems and refresh all their boundControls
554
- if (deps.length !== 0) {
555
- deps.forEach(dep => {
556
- // ### if changed modelItem has a 'facet' path we use the basePath that is the locationPath without facet name
557
- const basePath = XPathUtil.getBasePath(dep);
558
- const modelItemOfDep = this.getModel().modelItems.find(mip => mip.path === basePath);
559
- // ### refresh all boundControls
560
- modelItemOfDep.boundControls.forEach(control => {
561
- control.refresh(force);
562
- });
563
- });
564
- needsRefresh = true;
565
- }
566
- }
567
- });
568
- this.toRefresh = [];
569
- /*
570
- if (!needsRefresh) {
571
- console.log('no dependants to refresh');
572
- }
573
- */
536
+ this.refreshChanged(force);
574
537
  } else {
575
538
  // ### resetting visited state for controls to refresh
576
539
  /*
577
- const visited = this.parentNode.querySelectorAll('.visited');
578
- Array.from(visited).forEach(v =>{
579
- v.classList.remove('visited');
580
- });
581
- */
540
+ const visited = this.parentNode.querySelectorAll('.visited');
541
+ Array.from(visited).forEach(v =>{
542
+ v.classList.remove('visited');
543
+ });
544
+ */
582
545
 
583
546
  if (this.inited) {
547
+ console.log(`### <<<<< refresh() on '${this.id}' >>>>>`);
548
+
584
549
  Fore.refreshChildren(this, force);
585
550
  }
586
551
  // console.timeEnd('refreshChildren');
587
552
  }
588
553
 
589
554
  // ### refresh template expressions
590
- if (this.initialRun || this._scanForNewTemplateExpressionsNextRefresh) {
555
+ if (force || this.initialRun || this._scanForNewTemplateExpressionsNextRefresh) {
591
556
  this._updateTemplateExpressions();
592
557
  this._scanForNewTemplateExpressionsNextRefresh = false; // reset
593
558
  }
@@ -598,7 +563,11 @@ export class FxFore extends HTMLElement {
598
563
  // this.dispatchEvent(new CustomEvent('refresh-done'));
599
564
  // this.initialRun = false;
600
565
  this.style.visibility = 'visible';
601
- console.log(`### <<<<< refresh-done ${this.id} >>>>>`);
566
+ console.info(
567
+ `%crefresh-done on #${this.id}`,
568
+ 'background:darkorange; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
569
+ );
570
+
602
571
  Fore.dispatch(this, 'refresh-done', {});
603
572
 
604
573
  // this.isRefreshing = true;
@@ -606,29 +575,66 @@ export class FxFore extends HTMLElement {
606
575
 
607
576
  const subFores = Array.from(this.querySelectorAll('fx-fore'));
608
577
  /*
609
- calling the parent to refresh causes errors and inconsistent state. Also it is questionable
610
- if a child should actually interact with its parent in this way.
578
+ calling the parent to refresh causes errors and inconsistent state. Also it is questionable
579
+ if a child should actually interact with its parent in this way.
611
580
 
612
- This only affects the refreshing NOT the data mutation itself which is happening as expected.
581
+ This only affects the refreshing NOT the data mutation itself which is happening as expected.
613
582
 
614
- Current solution is that a child that wants the parent to refresh must do so by adding an additional
615
- event handler that dispatches an event upwards and having a handler in the parent to refresh itself.
583
+ Current solution is that a child that wants the parent to refresh must do so by adding an additional
584
+ event handler that dispatches an event upwards and having a handler in the parent to refresh itself.
616
585
 
617
- So refreshed propagate downwards but not upwards which is at least an option to consider.
586
+ So refreshed propagate downwards but not upwards which is at least an option to consider.
618
587
 
619
- if(this.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE){
620
- // await this.parentNode.closest('fx-fore')?.refresh(false);
621
- }
622
- */
588
+ if(this.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE){
589
+ // await this.parentNode.closest('fx-fore')?.refresh(false);
590
+ }
591
+ */
623
592
  for (const subFore of subFores) {
624
593
  // subFore.refresh(false, changedPaths);
625
594
  if (subFore.ready) {
626
- await subFore.refresh(force);
595
+ // Do an unconditional hard refresh: there might be changes that are relevant
596
+ await subFore.refresh(true);
627
597
  }
628
598
  }
629
599
  this.isRefreshing = false;
630
600
  }
631
601
 
602
+ refreshChanged(force) {
603
+ console.log('toRefresh', this.toRefresh);
604
+ let needsRefresh = false;
605
+
606
+ // ### after recalculation the changed modelItems are copied to 'toRefresh' array for processing
607
+ this.toRefresh.forEach(modelItem => {
608
+ // check if modelItem has boundControls - if so, call refresh() for each of them
609
+ const controlsToRefresh = modelItem.boundControls;
610
+ if (controlsToRefresh) {
611
+ controlsToRefresh.forEach(ctrl => {
612
+ ctrl.refresh(force);
613
+ });
614
+ }
615
+
616
+ // ### check if other controls depend on current modelItem
617
+ const { mainGraph } = this.getModel();
618
+ if (mainGraph && mainGraph.hasNode(modelItem.path)) {
619
+ const deps = this.getModel().mainGraph.dependentsOf(modelItem.path, false);
620
+ // ### iterate dependant modelItems and refresh all their boundControls
621
+ if (deps.length !== 0) {
622
+ deps.forEach(dep => {
623
+ // ### if changed modelItem has a 'facet' path we use the basePath that is the locationPath without facet name
624
+ const basePath = XPathUtil.getBasePath(dep);
625
+ const modelItemOfDep = this.getModel().modelItems.find(mip => mip.path === basePath);
626
+ // ### refresh all boundControls
627
+ modelItemOfDep.boundControls.forEach(control => {
628
+ control.refresh(force);
629
+ });
630
+ });
631
+ needsRefresh = true;
632
+ }
633
+ }
634
+ });
635
+ this.toRefresh = [];
636
+ }
637
+
632
638
  /**
633
639
  * entry point for processing of template expression enclosed in '{}' brackets.
634
640
  *
@@ -651,8 +657,8 @@ export class FxFore extends HTMLElement {
651
657
  // console.log('######### storedTemplateExpressions', this.storedTemplateExpressions.length);
652
658
 
653
659
  /*
654
- storing expressions and their nodes for re-evaluation
655
- */
660
+ storing expressions and their nodes for re-evaluation
661
+ */
656
662
  Array.from(tmplExpressions).forEach(node => {
657
663
  const ele = node.nodeType === Node.ATTRIBUTE_NODE ? node.ownerElement : node.parentNode;
658
664
  if (ele.closest('fx-fore') !== this) {
@@ -891,43 +897,43 @@ export class FxFore extends HTMLElement {
891
897
  }
892
898
 
893
899
  /*
894
- _createStep(){
900
+ _createStep(){
895
901
 
896
- }
897
- */
902
+ }
903
+ */
898
904
 
899
905
  /*
900
- _generateInstance(start, parent) {
901
- if (start.hasAttribute('ref')) {
902
- const ref = start.getAttribute('ref');
906
+ _generateInstance(start, parent) {
907
+ if (start.hasAttribute('ref')) {
908
+ const ref = start.getAttribute('ref');
903
909
 
904
- if(ref.includes('/')){
905
- console.log('complex path to create ', ref);
906
- const steps = ref.split('/');
907
- steps.forEach(step => {
908
- console.log('step ', step);
910
+ if(ref.includes('/')){
911
+ console.log('complex path to create ', ref);
912
+ const steps = ref.split('/');
913
+ steps.forEach(step => {
914
+ console.log('step ', step);
909
915
 
910
- });
911
- }
916
+ });
917
+ }
912
918
 
913
- // const generated = document.createElement(ref);
914
- const generated = parent.ownerDocument.createElement(ref);
915
- if (start.children.length === 0) {
916
- generated.textContent = start.textContent;
919
+ // const generated = document.createElement(ref);
920
+ const generated = parent.ownerDocument.createElement(ref);
921
+ if (start.children.length === 0) {
922
+ generated.textContent = start.textContent;
923
+ }
924
+ parent.appendChild(generated);
925
+ parent = generated;
917
926
  }
918
- parent.appendChild(generated);
919
- parent = generated;
920
- }
921
927
 
922
- if (start.hasChildNodes()) {
923
- const list = start.children;
924
- for (let i = 0; i < list.length; i += 1) {
925
- this._generateInstance(list[i], parent);
928
+ if (start.hasChildNodes()) {
929
+ const list = start.children;
930
+ for (let i = 0; i < list.length; i += 1) {
931
+ this._generateInstance(list[i], parent);
932
+ }
926
933
  }
934
+ return parent;
927
935
  }
928
- return parent;
929
- }
930
- */
936
+ */
931
937
 
932
938
  /**
933
939
  * Start the initialization of the UI by
@@ -941,22 +947,29 @@ export class FxFore extends HTMLElement {
941
947
  */
942
948
  async _initUI() {
943
949
  // console.log('### _initUI()');
944
- console.log(`### <<<<< _initUI '${this.id}' >>>>>`);
950
+ console.info(
951
+ `%cinitUI #${this.id}`,
952
+ 'background:lightblue; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
953
+ );
945
954
 
946
955
  if (!this.initialRun) return;
947
956
  this.classList.add('initialRun');
948
957
  await this._lazyCreateInstance();
949
958
 
950
959
  /*
951
- const options = {
952
- root: null,
953
- rootMargin: '0px',
954
- threshold: 0.3,
955
- };
956
- */
960
+ const options = {
961
+ root: null,
962
+ rootMargin: '0px',
963
+ threshold: 0.3,
964
+ };
965
+ */
957
966
 
958
967
  // First refresh should be forced
968
+ if (this.createNodes) {
969
+ this.initData();
970
+ }
959
971
  await this.refresh(true);
972
+
960
973
  // this.style.display='block'
961
974
  this.classList.add('fx-ready');
962
975
  document.body.classList.add('fx-ready');
@@ -964,7 +977,12 @@ export class FxFore extends HTMLElement {
964
977
  this.ready = true;
965
978
  this.initialRun = false;
966
979
  // console.log('### >>>>> dispatching ready >>>>>', this);
967
- console.log(`### <<<<< ${this.id} ready >>>>>`);
980
+ console.info(
981
+ `%c #${this.id} is ready`,
982
+ 'background:lightblue; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
983
+ );
984
+
985
+ // console.log(`### <<<<< ${this.id} ready >>>>>`);
968
986
 
969
987
  // console.log('### modelItems: ', this.getModel().modelItems);
970
988
  Fore.dispatch(this, 'ready', {});
@@ -982,6 +1000,144 @@ export class FxFore extends HTMLElement {
982
1000
  });
983
1001
  }
984
1002
 
1003
+ /**
1004
+ * @param {HTMLElement} root The root of the data initialization. fx-repeat overrides this when it makes new repeat items
1005
+ *
1006
+ */
1007
+ initData(root = this) {
1008
+ // const created = new Promise(resolve => {
1009
+ // console.log('INIT');
1010
+ // const boundControls = Array.from(root.querySelectorAll('[ref]:not(fx-model *),fx-repeatitem'));
1011
+
1012
+ const boundControls = Array.from(
1013
+ root.querySelectorAll(
1014
+ 'fx-control[ref],fx-upload[ref],fx-group[ref],fx-repeat[ref], fx-switch[ref]',
1015
+ ),
1016
+ );
1017
+ if (root.matches('fx-repeatitem')) {
1018
+ boundControls.unshift(root);
1019
+ }
1020
+ // console.log('_initD', boundControls);
1021
+ for (let i = 0; i < boundControls.length; i++) {
1022
+ const bound = boundControls[i];
1023
+
1024
+ /*
1025
+ ignore bound elements that are enclosed with a control like <select> or <fx-items> and repeated items
1026
+ */
1027
+ if (!bound.matches('fx-repeatitem') && !bound.parentNode.closest('fx-control')) {
1028
+ // Repeat items are dumb. They do not respond to evalInContext
1029
+ bound.evalInContext();
1030
+ }
1031
+ let ownerDoc;
1032
+ if (bound.nodeset !== null) {
1033
+ // console.log('Node exists', control.nodeset);
1034
+ continue;
1035
+ }
1036
+ // console.log('Node does not exists', control.ref);
1037
+
1038
+ // We need to create that node!
1039
+ const previousControl = boundControls[i - 1];
1040
+
1041
+ // Previous control can either be an ancestor of us, or a previous node, which can be a sibling, or a child of a sibling.
1042
+ // First: parent
1043
+ if (previousControl.contains(bound)) {
1044
+ // Parent is here.
1045
+ // console.log('insert into', control,previousControl);
1046
+ // console.log('insert into nodeset', control.nodeset);
1047
+ const parentNodeset = previousControl.nodeset;
1048
+ // console.log('parentNodeset', parentNodeset);
1049
+
1050
+ // const parentModelItemNode = parentModelItem.node;
1051
+ const ref = bound.ref;
1052
+ // const newElement = parentModelItemNode.ownerDocument.createElement(ref);
1053
+ if (parentNodeset.querySelector(`[ref="${ref}"]`)) {
1054
+ console.log(`Node with ref "${ref}" already exists.`);
1055
+ continue;
1056
+ }
1057
+
1058
+ const newElement = this._createNodes(ref, parentNodeset);
1059
+
1060
+ // Plonk it in at the start!
1061
+ parentNodeset.insertBefore(newElement, parentNodeset.firstChild);
1062
+ bound.evalInContext();
1063
+ // console.log('CREATED child', newElement);
1064
+ // console.log('new control evaluated to ', control.nodeset);
1065
+ // Done!
1066
+ continue;
1067
+ }
1068
+ // console.log('previousControl', previousControl);
1069
+ // console.log('control', control);
1070
+ // Is previousControl a sibling or a descendant of a logical sibling? Keep looking backwards until we share parents!
1071
+ const ourParent = XPathUtil.getParentBindingElement(bound);
1072
+ // console.log('ourParent', ourParent);
1073
+ let siblingControl = null;
1074
+ /*
1075
+ for (let j = i - 1; j >= 0; --j) {
1076
+ const potentialSibling = boundControls[j];
1077
+ if (XPathUtil.getParentBindingElement(potentialSibling) === ourParent) {
1078
+ siblingControl = potentialSibling;
1079
+ break; // Exit once the sibling is found
1080
+ }
1081
+ }
1082
+ */
1083
+ for (let j = i - 1; j > 0; --j) {
1084
+ const siblingOrDescendant = boundControls[j];
1085
+ if (XPathUtil.getParentBindingElement(siblingOrDescendant) === ourParent) {
1086
+ siblingControl = siblingOrDescendant;
1087
+ break;
1088
+ }
1089
+ }
1090
+ if (!siblingControl) {
1091
+ throw new Error('Unexpected! there must be a sibling right?');
1092
+ }
1093
+ // console.log('sibling', siblingControl);
1094
+ // todo: review: should this not just be inscopeContext?
1095
+ const parentNodeset = ourParent.nodeset;
1096
+ const ref = bound.ref;
1097
+ let referenceNodeset = siblingControl.nodeset;
1098
+ const newElement = this._createNodes(ref, parentNodeset);
1099
+
1100
+ // We know which node to insert this new element to, but it might be a descendant of a child of the actual parent. Walk up until we have a reference under our parent
1101
+ while (referenceNodeset?.parentNode && referenceNodeset?.parentNode !== parentNodeset) {
1102
+ referenceNodeset = referenceNodeset.parentNode;
1103
+ }
1104
+
1105
+ // Insert before the next sibling our our logical previous sibling
1106
+ parentNodeset.insertBefore(newElement, referenceNodeset.nextElementSibling);
1107
+ /*
1108
+ console.log('control inscope', control.getInScopeContext());
1109
+ console.log('control ref', control.ref);
1110
+ console.log('control new element parent', newElement.parentNode.nodeName);
1111
+ */
1112
+ bound.evalInContext();
1113
+ // console.log('new control evaluated to ', control.nodeset);
1114
+ // console.log('CREATED sibling', newElement);
1115
+ }
1116
+ // console.log('DATA', this.getModel().getDefaultContext());
1117
+ }
1118
+
1119
+ _createNodes(ref, referenceNode) {
1120
+ // console.log('creating', ref)
1121
+ // console.log('ownerDoc', referenceNode.ownerDocument);
1122
+ /*
1123
+ const existingNode = evaluateXPathToFirstNode(ref, referenceNode, this);
1124
+ if(existingNode){
1125
+ console.log(`Node already exists for ref: ${ref}`);
1126
+ return existingNode;
1127
+ }
1128
+ console.log(`creating new node for ref: ${ref}`);
1129
+ */
1130
+ let newElement;
1131
+ if (ref.includes('/')) {
1132
+ // multi-step ref expressions
1133
+ newElement = XPathUtil.createNodesFromXPath(ref, referenceNode.ownerDocument, this);
1134
+ // console.log('new subtree', newElement);
1135
+ return newElement;
1136
+ } else {
1137
+ return XPathUtil.createNodesFromXPath(ref, referenceNode.ownerDocument, this);
1138
+ }
1139
+ }
1140
+
985
1141
  _handleDragStart(event) {
986
1142
  const draggedItem = event.target.closest('[draggable="true"]');
987
1143
  this.originalDraggedItem = draggedItem;
@@ -1107,18 +1263,18 @@ export class FxFore extends HTMLElement {
1107
1263
  Array.from(repeats).forEach(item => {
1108
1264
  if (item.closest('fx-control')) return;
1109
1265
  /*
1110
- const parentRepeat = item.closest('fx-repeat');
1111
- if(parentRepeat){
1112
- this.dispatchEvent(
1113
- new CustomEvent('log', {
1114
- composed: false,
1115
- bubbles: true,
1116
- cancelable:true,
1117
- detail: { id:this.id, message: `nesting elements with data-ref attributes within fx-repeat is not supported by now`, level:'Error'},
1118
- }),
1119
- );
1120
- }
1121
- */
1266
+ const parentRepeat = item.closest('fx-repeat');
1267
+ if(parentRepeat){
1268
+ this.dispatchEvent(
1269
+ new CustomEvent('log', {
1270
+ composed: false,
1271
+ bubbles: true,
1272
+ cancelable:true,
1273
+ detail: { id:this.id, message: `nesting elements with data-ref attributes within fx-repeat is not supported by now`, level:'Error'},
1274
+ }),
1275
+ );
1276
+ }
1277
+ */
1122
1278
 
1123
1279
  const table = item.parentNode.closest('table');
1124
1280
  let host;
@@ -213,8 +213,9 @@ export class FxInstance extends HTMLElement {
213
213
  this.originalInstance = [...this.instanceData];
214
214
  }
215
215
  if (this.type === 'text') {
216
- this.instanceData = '';
217
- this.originalInstance = '';
216
+ this.instanceData = this.innerText;
217
+ this.originalInstance = this.innerText;
218
+ console.log('text data', this.instanceData);
218
219
  }
219
220
  }
220
221