@jinntec/fore 2.5.0 → 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.
@@ -122,6 +122,7 @@ export class AbstractAction extends ForeElementMixin {
122
122
  disconnectedCallback() {}
123
123
 
124
124
  connectedCallback() {
125
+ super.connectedCallback();
125
126
  this.setAttribute('inert', 'true');
126
127
  this.style.display = 'none';
127
128
  this.propagate = this.hasAttribute('propagate') ? this.getAttribute('propagate') : 'continue';
@@ -176,6 +177,7 @@ export class AbstractAction extends ForeElementMixin {
176
177
  }
177
178
  } else {
178
179
  this.targetElement = this.parentNode;
180
+ if(!this.targetElement || this.targetElement.nodeType !== Node.ELEMENT_NODE) return;
179
181
  this.targetElement.addEventListener(this.event, e => this.execute(e), {
180
182
  capture: this.phase === 'capture',
181
183
  });
@@ -212,30 +214,28 @@ export class AbstractAction extends ForeElementMixin {
212
214
  * @param e
213
215
  */
214
216
  async execute(e) {
215
- if(!this.getModel().modelConstructed) return;
217
+ if (!this.getModel().modelConstructed) return;
216
218
  // console.log(this, this.event);
217
- if(this.event){
218
- if(this.event === 'submit-done'){
219
+ if (this.event) {
220
+ if (this.event === 'submit-done') {
219
221
  console.info(
220
- `%csubmit-done ${this.event} #${this?.parentNode?.id}`,
221
- 'background:lime; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
222
+ `%csubmit-done ${this.event} #${this?.parentNode?.id}`,
223
+ 'background:lime; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
222
224
  );
223
- }else{
225
+ } else {
224
226
  console.info(
225
- `%cexecuting ${this.constructor.name} ${this.event}`,
226
- 'background:lime; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
227
+ `%cexecuting ${this.constructor.name} ${this.event}`,
228
+ 'background:lime; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
227
229
  );
228
230
  }
229
-
230
- }else{
231
+ } else {
231
232
  console.info(
232
- `%cexecuting ${this.constructor.name}`,
233
- 'background:limegreen; color:black; margin-left:1rem; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
234
- this
233
+ `%cexecuting ${this.constructor.name}`,
234
+ 'background:limegreen; color:black; margin-left:1rem; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
235
+ this,
235
236
  );
236
237
  }
237
238
 
238
-
239
239
  if (e && e.target.nodeType !== Node.DOCUMENT_NODE && e.target !== window) {
240
240
  /*
241
241
  ### ignore event if there's a parent fore and the current element is NOT part of it. This avoids
@@ -260,7 +260,7 @@ export class AbstractAction extends ForeElementMixin {
260
260
  let resolveThisEvent = () => {};
261
261
  if (e && e.listenerPromises) {
262
262
  e.listenerPromises.push(
263
- new Promise((resolve) => {
263
+ new Promise(resolve => {
264
264
  resolveThisEvent = resolve;
265
265
  }),
266
266
  );
@@ -269,9 +269,9 @@ export class AbstractAction extends ForeElementMixin {
269
269
  // Outermost handling
270
270
  if (FxFore.outermostHandler === null) {
271
271
  console.log(
272
- `%coutermost Action on ${this.getOwnerForm().id}`,
273
- 'background:darkblue; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
274
- this,
272
+ `%coutermost Action on ${this.getOwnerForm().id}`,
273
+ 'background:darkblue; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
274
+ this,
275
275
  );
276
276
 
277
277
  FxFore.outermostHandler = this;
@@ -406,9 +406,9 @@ export class AbstractAction extends ForeElementMixin {
406
406
  this.actionPerformed();
407
407
  if (FxFore.outermostHandler === this) {
408
408
  console.log(
409
- `%cfinalizing outermost Action on ${this.getOwnerForm().id}`,
410
- 'background:darkblue; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
411
- this,
409
+ `%cfinalizing outermost Action on ${this.getOwnerForm().id}`,
410
+ 'background:darkblue; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
411
+ this,
412
412
  );
413
413
 
414
414
  FxFore.outermostHandler = null;
@@ -467,8 +467,8 @@ export class AbstractAction extends ForeElementMixin {
467
467
  return;
468
468
  }
469
469
  if (
470
- FxFore.outermostHandler
471
- && !XPathUtil.contains(FxFore.outermostHandler.ownerDocument, FxFore.outermostHandler)
470
+ FxFore.outermostHandler &&
471
+ !XPathUtil.contains(FxFore.outermostHandler.ownerDocument, FxFore.outermostHandler)
472
472
  ) {
473
473
  // The old outermostHandler fell out of the document. An error has happened.
474
474
  // Just remove the old one and act like we are starting anew.
@@ -480,7 +480,7 @@ export class AbstractAction extends ForeElementMixin {
480
480
  // console.log('running update cycle for outermostHandler', this);
481
481
  model.recalculate();
482
482
  model.revalidate();
483
- model.parentNode.refresh(true);
483
+ this.getOwnerForm().refresh(true);
484
484
  this.dispatchActionPerformed();
485
485
  } else if (this.needsUpdate) {
486
486
  // console.log('Update delayed!');
@@ -109,6 +109,8 @@ class FxAppend extends AbstractAction {
109
109
  const data = this._generateInstance(templ.content, rootNode);
110
110
  // console.log('_dataFromTemplate DATA', data);
111
111
  inscope.appendChild(data);
112
+ parentForm.signalChangeToElement(inscope.localName);
113
+ parentForm.signalChangeToElement(data.localName);
112
114
  // console.log('appended new item ', data);
113
115
  // return data;
114
116
  }
@@ -52,19 +52,31 @@ class FxDelete extends AbstractAction {
52
52
  }),
53
53
  );
54
54
 
55
+ const fore = this.getOwnerForm();
56
+
55
57
  let parent;
56
58
  if (Array.isArray(nodesToDelete)) {
57
59
  if (nodesToDelete.length === 0) return;
58
60
  parent = nodesToDelete[0].parentNode;
61
+ fore.signalChangeToElement(parent.localName);
59
62
  nodesToDelete.forEach(item => {
60
63
  this._deleteNode(parent, item);
64
+ fore.signalChangeToElement(item.localName);
61
65
  });
62
66
  } else {
63
67
  parent = nodesToDelete.parentNode;
68
+ fore.signalChangeToElement(parent.localName);
69
+
64
70
  this._deleteNode(parent, nodesToDelete);
71
+ fore.signalChangeToElement(nodesToDelete.localName);
65
72
  }
66
- const foreId = this.getOwnerForm().id;
67
- await Fore.dispatch(instance, 'deleted', { ref: path, deletedNodes: nodesToDelete , instanceId:instanceId, foreId:foreId});
73
+
74
+ await Fore.dispatch(instance, 'deleted', {
75
+ ref: path,
76
+ deletedNodes: nodesToDelete,
77
+ instanceId,
78
+ foreId: fore.id,
79
+ });
68
80
  this.needsUpdate = true;
69
81
  }
70
82
 
@@ -38,7 +38,7 @@ export class FxHide extends AbstractAction {
38
38
  );
39
39
 
40
40
  const dialog = resolveId(this.dialog, this);
41
- dialog.hide();
41
+ dialog.close();
42
42
  Fore.dispatch(dialog, 'dialog-hidden', {});
43
43
  }
44
44
  }
@@ -60,30 +60,6 @@ export class FxInsert extends AbstractAction {
60
60
  this.keepValues = !!this.hasAttribute('keep-values');
61
61
  }
62
62
 
63
- _getOriginSequence(inscope, targetSequence) {
64
- let originSequence;
65
- if (this.origin) {
66
- // ### if there's an origin attribute use it
67
- let originTarget;
68
- try {
69
- originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
70
- if (Array.isArray(originTarget) && originTarget.length === 0) {
71
- console.warn('invalid origin for this insert action - ignoring...', this);
72
- originSequence = null;
73
- }
74
- originSequence = originTarget;
75
- } catch (error) {
76
- console.warn('invalid origin for this insert action - ignoring...', this);
77
- }
78
- } else if (targetSequence) {
79
- // ### use last item of targetSequence
80
- originSequence = targetSequence;
81
- if (originSequence && !this.keepValues) {
82
- this._clear(originSequence);
83
- }
84
- }
85
- return originSequence;
86
- }
87
63
 
88
64
  _cloneOriginSequence(inscope, targetSequence) {
89
65
  let originSequenceClone;
@@ -96,13 +72,25 @@ export class FxInsert extends AbstractAction {
96
72
  */
97
73
  // this.setInScopeVariables(this.detail);
98
74
 
99
- // originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
100
- originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
101
- if (Array.isArray(originTarget) && originTarget.length === 0) {
102
- console.warn('invalid origin for this insert action - ignoring...', this);
103
- originSequenceClone = null;
75
+ /*
76
+ if in 'create-nodes' mode and origin targets a repeat, the repeat
77
+ we use the already during initData() created nodeset as a template for insertion
78
+ */
79
+ if(this.origin.startsWith('#') && this.getOwnerForm().createNodes){
80
+ const repeat = this.getOwnerForm().querySelector(this.origin);
81
+ originSequenceClone = repeat.createdNodeset.cloneNode(true);
82
+ if(!originSequenceClone){
83
+ console.error(`createdNodeset for repeat ${this.origin} does not exist`);
84
+ }
85
+ }else{
86
+ // originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
87
+ originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
88
+ if (Array.isArray(originTarget) && originTarget.length === 0) {
89
+ console.warn('invalid origin for this insert action - ignoring...', this);
90
+ originSequenceClone = null;
91
+ }
92
+ originSequenceClone = originTarget.cloneNode(true);
104
93
  }
105
- originSequenceClone = originTarget.cloneNode(true);
106
94
  } catch (error) {
107
95
  console.warn('invalid origin for this insert action - ignoring...', this);
108
96
  }
@@ -136,13 +124,11 @@ export class FxInsert extends AbstractAction {
136
124
  let targetSequence = [];
137
125
  const inscopeContext = getInScopeContext(this);
138
126
 
127
+ const fore = this.getOwnerForm();
128
+
139
129
  // ### 'context' attribute takes precedence over 'ref'
140
130
  if (this.hasAttribute('context')) {
141
- [context] = evaluateXPathToNodes(
142
- this.getAttribute('context'),
143
- inscopeContext,
144
- this.getOwnerForm(),
145
- );
131
+ [context] = evaluateXPathToNodes(this.getAttribute('context'), inscopeContext, fore);
146
132
  inscope = inscopeContext;
147
133
  }
148
134
 
@@ -154,6 +140,8 @@ export class FxInsert extends AbstractAction {
154
140
  targetSequence = evaluateXPathToNodes(this.ref, inscope, this);
155
141
  }
156
142
  }
143
+ // const originSequenceClone = this._cloneOriginSequence(inscope, targetSequence);
144
+
157
145
  const originSequenceClone = this._cloneOriginSequence(inscope, targetSequence);
158
146
  if (!originSequenceClone) return; // if no origin back out without effect
159
147
 
@@ -165,12 +153,24 @@ export class FxInsert extends AbstractAction {
165
153
  if (context) {
166
154
  insertLocationNode = context;
167
155
  context.appendChild(originSequenceClone);
156
+ fore.signalChangeToElement(insertLocationNode.localName);
157
+ fore.signalChangeToElement(originSequenceClone.localName);
168
158
  index = 1;
169
159
  } else {
170
- // No context. We can insert into the `inscope`.
171
- insertLocationNode = inscope;
172
- inscope.appendChild(originSequenceClone);
173
- index = 1;
160
+
161
+ // No context but creating nodes from UI
162
+ if(!inscope && this.getOwnerForm().createNodes){
163
+ const repeat = this.getOwnerForm().querySelector(this.origin);
164
+ inscope = getInScopeContext(repeat, repeat.ref);
165
+ insertLocationNode = inscope;
166
+ inscope.appendChild(originSequenceClone);
167
+ index = inscope.length - 1;
168
+ }else{
169
+ insertLocationNode = inscope;
170
+ inscope.appendChild(originSequenceClone);
171
+ index = 1;
172
+ }
173
+
174
174
  }
175
175
  } else {
176
176
  /* ### insert at position given by 'at' or use the last item in the targetSequence ### */
@@ -205,6 +205,8 @@ export class FxInsert extends AbstractAction {
205
205
  if (this.position && this.position === 'before') {
206
206
  // this.at -= 1;
207
207
  insertLocationNode.parentNode.insertBefore(originSequenceClone, insertLocationNode);
208
+ fore.signalChangeToElement(insertLocationNode.parentNode);
209
+ fore.signalChangeToElement(originSequenceClone.localName);
208
210
  }
209
211
 
210
212
  if (this.position && this.position === 'after') {
@@ -217,8 +219,12 @@ export class FxInsert extends AbstractAction {
217
219
  } else if (this.hasAttribute('context')) {
218
220
  index = 1;
219
221
  insertLocationNode.prepend(originSequenceClone);
222
+ fore.signalChangeToElement(insertLocationNode);
223
+ fore.signalChangeToElement(originSequenceClone.localName);
220
224
  } else {
221
225
  insertLocationNode.insertAdjacentElement('afterend', originSequenceClone);
226
+ fore.signalChangeToElement(insertLocationNode);
227
+ fore.signalChangeToElement(originSequenceClone.localName);
222
228
  }
223
229
  }
224
230
  }
@@ -251,8 +257,8 @@ export class FxInsert extends AbstractAction {
251
257
  'inserted-nodes': originSequenceClone,
252
258
  'insert-location-node': insertLocationNode,
253
259
  position: this.position,
254
- instanceId:instanceId,
255
- foreId:this.getOwnerForm().id
260
+ instanceId,
261
+ foreId: fore.id,
256
262
  });
257
263
 
258
264
  // todo: this actually should dispatch to respective instance
@@ -27,12 +27,13 @@ class FxLoad extends AbstractAction {
27
27
  super();
28
28
  this.attachShadow({ mode: 'open' });
29
29
  this.url = '';
30
+ this.replace=false;
30
31
  }
31
32
 
32
33
  connectedCallback() {
33
34
  super.connectedCallback();
34
35
  this.attachTo = this.hasAttribute('attach-to') ? this.getAttribute('attach-to') : '_self';
35
-
36
+ this.replace = this.hasAttribute('replace') ? true : false;
36
37
  // Add a 'doneEvent' to block the action chain untill the event fired on the element we're
37
38
  // loading something into.
38
39
  this.awaitEvent = this.hasAttribute('await') ? this.getAttribute('await') : '';
@@ -88,7 +89,11 @@ class FxLoad extends AbstractAction {
88
89
  resolved.removeEventListener(this.awaitEvent, eventListener);
89
90
  };
90
91
 
91
- resolved.appendChild(content);
92
+ if(this.replace){
93
+ this.parentNode.replaceChild(content,resolved);
94
+ }else{
95
+ resolved.appendChild(content);
96
+ }
92
97
  resolved.addEventListener(this.awaitEvent, eventListener);
93
98
 
94
99
  await waitForEvent;
@@ -3,6 +3,7 @@ import '../fx-model.js';
3
3
  import { AbstractAction } from './abstract-action.js';
4
4
  import { evaluateXPath } from '../xpath-evaluation.js';
5
5
  import { Fore } from '../fore.js';
6
+ import getInScopeContext from '../getInScopeContext.js';
6
7
 
7
8
  /**
8
9
  * `fx-setvalue`
@@ -10,106 +11,123 @@ import { Fore } from '../fore.js';
10
11
  * @customElement
11
12
  */
12
13
  export default class FxSetvalue extends AbstractAction {
13
- static get properties() {
14
- return {
15
- ...super.properties,
16
- ref: {
17
- type: String,
18
- },
19
- valueAttr: {
20
- type: String,
21
- },
22
- };
23
- }
24
-
25
- constructor() {
26
- super();
27
- this.ref = '';
28
- this.valueAttr = '';
29
- }
30
-
31
- connectedCallback() {
32
- if (super.connectedCallback) {
33
- super.connectedCallback();
14
+ static get properties() {
15
+ return {
16
+ ...super.properties,
17
+ ref: {
18
+ type: String,
19
+ },
20
+ valueAttr: {
21
+ type: String,
22
+ },
23
+ };
34
24
  }
35
25
 
36
- if (this.hasAttribute('ref')) {
37
- this.ref = this.getAttribute('ref');
38
- } else {
39
- throw new Error('fx-setvalue must specify a "ref" attribute');
26
+ constructor() {
27
+ super();
28
+ this.ref = '';
29
+ this.valueAttr = '';
40
30
  }
41
- this.valueAttr = this.getAttribute('value');
42
- }
43
31
 
44
- async perform() {
45
- super.perform();
46
- let { value } = this;
47
- if (this.valueAttr !== null) {
48
- [value] = evaluateXPath(this.valueAttr, this.nodeset, this, this.detail);
49
- } else if (this.textContent !== '') {
50
- value = this.textContent;
51
- } else {
52
- value = '';
32
+ connectedCallback() {
33
+ if (super.connectedCallback) {
34
+ super.connectedCallback();
35
+ }
36
+
37
+ if (this.hasAttribute('ref')) {
38
+ this.ref = this.getAttribute('ref');
39
+ } else {
40
+ throw new Error('fx-setvalue must specify a "ref" attribute');
41
+ }
42
+ this.valueAttr = this.getAttribute('value');
53
43
  }
54
- if (value?.nodeType && value.nodeType === Node.ATTRIBUTE_NODE) {
55
- value = value.nodeValue;
44
+
45
+ async perform() {
46
+ super.perform();
47
+ let { value } = this;
48
+ if (this.valueAttr !== null) {
49
+ const inscopeContext = getInScopeContext(this, this.valueAttr);
50
+ /*
51
+ todo: review @martin - shouldn't we always return a string value?
52
+ this comes down to the question if setvalue should only allow setting of strings
53
+ which i tend to agree. Can't remember a case where i wanted to set an attribute
54
+ or element (for json wouldn't make much sense either) - for cases like that
55
+ fx-replace would be more appropriate.
56
+
57
+ This is of practical relevance cause currently forces to append 'text()' to value expressions
58
+ or getting unexpected results.
59
+ */
60
+
61
+ [value] = evaluateXPath(
62
+ this.valueAttr,
63
+ inscopeContext,
64
+ this,
65
+ this.detail,
66
+ );
67
+ } else if (this.textContent !== '') {
68
+ value = this.textContent;
69
+ } else {
70
+ value = '';
71
+ }
72
+ if (value?.nodeType && value.nodeType === Node.ATTRIBUTE_NODE) {
73
+ value = value.nodeValue;
74
+ }
75
+ const mi = this.getModelItem();
76
+ this.setValue(mi, value);
77
+ // todo: check this again - logically needsUpate should be set but makes tests fail
78
+ // this.needsUpdate = true;
56
79
  }
57
- const mi = this.getModelItem();
58
- this.setValue(mi, value);
59
- // todo: check this again - logically needsUpate should be set but makes tests fail
60
- // this.needsUpdate = true;
61
- }
62
80
 
63
- /**
64
- * need to overwrite default dispatchExecute to do it ourselves. This is necessary for tracking control value changes
65
- * which call setvalue directly without perform().
66
- */
67
- dispatchExecute() {}
81
+ /**
82
+ * need to overwrite default dispatchExecute to do it ourselves. This is necessary for tracking control value changes
83
+ * which call setvalue directly without perform().
84
+ */
85
+ dispatchExecute() {}
68
86
 
69
- setValue(modelItem, newVal) {
70
- const item = modelItem;
71
- if (!item) return;
87
+ setValue(modelItem, newVal) {
88
+ const item = modelItem;
89
+ if (!item) return;
72
90
 
73
- if (item.value !== newVal) {
74
- // const path = XPathUtil.getPath(modelItem.node);
75
- const path = Fore.getDomNodeIndexString(modelItem.node);
91
+ if (item.value !== newVal) {
92
+ // const path = XPathUtil.getPath(modelItem.node);
93
+ const path = Fore.getDomNodeIndexString(modelItem.node);
76
94
 
77
- const ev = this.event;
78
- const targetElem = this;
79
- this.dispatchEvent(
80
- new CustomEvent('execute-action', {
81
- composed: true,
82
- bubbles: true,
83
- cancelable: true,
84
- detail: {
85
- action: targetElem,
86
- event: ev,
87
- value: newVal,
88
- path,
89
- },
90
- }),
91
- );
95
+ const ev = this.event;
96
+ const targetElem = this;
97
+ this.dispatchEvent(
98
+ new CustomEvent('execute-action', {
99
+ composed: true,
100
+ bubbles: true,
101
+ cancelable: true,
102
+ detail: {
103
+ action: targetElem,
104
+ event: ev,
105
+ value: newVal,
106
+ path,
107
+ },
108
+ }),
109
+ );
92
110
 
93
- if (newVal?.nodeType) {
94
- if (newVal.nodeType === Node.ELEMENT_NODE) {
95
- item.value = newVal;
96
- }
97
- if (newVal.nodeType === Node.ATTRIBUTE_NODE) {
98
- item.value = newVal.getValue();
99
- }
100
- if(newVal.nodeType === Node.TEXT_NODE){
101
- item.value = newVal.textContent;
111
+ if (newVal?.nodeType) {
112
+ if (newVal.nodeType === Node.ELEMENT_NODE) {
113
+ item.value = newVal;
114
+ }
115
+ if (newVal.nodeType === Node.ATTRIBUTE_NODE) {
116
+ item.value = newVal.getValue();
117
+ }
118
+ if (newVal.nodeType === Node.TEXT_NODE) {
119
+ item.value = newVal.textContent;
120
+ }
121
+ } else {
122
+ item.value = newVal;
123
+ item.node.textContent = newVal;
124
+ }
125
+ this.getModel().changed.push(modelItem);
126
+ this.needsUpdate = true;
102
127
  }
103
- } else {
104
- item.value = newVal;
105
- item.node.textContent = newVal;
106
- }
107
- this.getModel().changed.push(modelItem);
108
- this.needsUpdate = true;
109
128
  }
110
- }
111
129
  }
112
130
 
113
131
  if (!customElements.get('fx-setvalue')) {
114
- window.customElements.define('fx-setvalue', FxSetvalue);
132
+ window.customElements.define('fx-setvalue', FxSetvalue);
115
133
  }
@@ -4,7 +4,9 @@ import { resolveId } from '../xpath-evaluation.js';
4
4
 
5
5
  /**
6
6
  * `fx-show`
7
- * Displays a simple confirmation before actually executing the nested actions.
7
+ * to show a `<dialog>` with given id.
8
+ *
9
+ *
8
10
  *
9
11
  * @customElement
10
12
  * @event fx-show dispatched when dialog is shown
@@ -34,7 +36,7 @@ export class FxShow extends FxAction {
34
36
  if (!targetDlg) {
35
37
  console.error('target dialog with given id does not exist', this.dialog);
36
38
  }
37
- targetDlg.open();
39
+ targetDlg.showModal();
38
40
  Fore.dispatch(targetDlg, 'dialog-shown', {});
39
41
  }
40
42
  }
package/src/fore.js CHANGED
@@ -275,7 +275,7 @@ export class Fore {
275
275
  * recursively refreshes all UI Elements.
276
276
  *
277
277
  * @param {HTMLElement} startElement
278
- * @param {(boolean|{reason:'index-function'})} force Whether to do a forced refresh. Forced
278
+ * @param {(boolean|{reason:'index-function', elementLocalnamesWithChanges: string[]})} force Whether to do a forced refresh. Forced
279
279
  * refreshes are very bad for performance, try to limit them. If the forced refresh is because index functions may change, it is better to pass the reason
280
280
  * @returns {Promise<void>}
281
281
  */
@@ -300,30 +300,47 @@ export class Fore {
300
300
  const { children } = startElement;
301
301
  if (children) {
302
302
  for (const element of Array.from(children)) {
303
- if (element.nodeName.toUpperCase() === 'FX-FORE') {
304
- break;
303
+ if (element.nodeName.toUpperCase() === 'FX-FORE') {
304
+ break;
305
+ }
306
+ if (Fore.isUiElement(element.nodeName) && typeof element.refresh === 'function') {
307
+ /**
308
+ * @type {import('./ForeElementMixin.js').default}
309
+ */
310
+ const bound = element;
311
+ if (!force) {
312
+ continue;
313
+ }
314
+ if (force === true) {
315
+ // Unconditional force refresh
316
+ bound.refresh(force);
317
+ continue;
318
+ }
319
+ if (typeof force !== 'object') {
320
+ continue;
321
+ }
322
+ if (
323
+ force.reason === 'index-function' &&
324
+ bound.dependencies.isInvalidatedByIndexFunction()
325
+ ) {
326
+ bound.refresh(force);
327
+ continue;
305
328
  }
306
- if (Fore.isUiElement(element.nodeName) && typeof element.refresh === 'function') {
307
- /**
308
- * @type {import('./ForeElementMixin.js').default}
309
- */
310
- if (
311
- force &&
312
- typeof force === 'object' &&
313
- force.reason === 'index-function' &&
314
- element._dependencies.isInvalidatedByIndexFunction()
315
- ) {
316
- element.refresh(force);
317
- continue;
318
- } else if (force === true) {
319
- element.refresh(force);
320
- }
321
- // console.log('refreshing', element, element?.ref);
322
- // console.log('refreshing ',element);
323
- } else if (!(element.inert === true) ) {
324
- // testing for inert catches model and action elements and should just leave updateable html elements
325
- Fore.refreshChildren(element, force);
329
+
330
+ if (
331
+ bound.dependencies.isInvalidatedByChildlistChanges(force.elementLocalnamesWithChanges)
332
+ ) {
333
+ bound.refresh(force);
334
+ continue;
326
335
  }
336
+
337
+ // console.log('refreshing', element, element?.ref);
338
+ // console.log('refreshing ',element);
339
+ }
340
+ if (!(element.inert === true)) {
341
+ // testing for inert catches model and action elements and should just leave updateable html elements
342
+ Fore.refreshChildren(element, force);
343
+ }
327
344
  }
328
345
  }
329
346
  resolve('done');