@jinntec/fore 2.6.0 → 2.7.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/dist/fore-dev.js +4470 -2643
- package/dist/fore.js +4415 -2620
- package/index.js +2 -0
- package/package.json +10 -4
- package/resources/fore.css +2 -6
- package/src/DependencyNotifyingDomFacade.js +27 -21
- package/src/ForeElementMixin.js +282 -277
- package/src/actions/abstract-action.js +7 -12
- package/src/actions/fx-append.js +23 -2
- package/src/actions/fx-call.js +2 -2
- package/src/actions/fx-delete.js +54 -29
- package/src/actions/fx-insert.js +23 -15
- package/src/actions/fx-refresh.js +15 -5
- package/src/actions/fx-replace.js +18 -3
- package/src/actions/fx-reset.js +6 -0
- package/src/actions/fx-send.js +10 -7
- package/src/actions/fx-setattribute.js +12 -0
- package/src/actions/fx-setfocus.js +11 -8
- package/src/actions/fx-setvalue.js +93 -93
- package/src/actions/fx-toggle.js +1 -1
- package/src/extract-predicate-deps.js +57 -0
- package/src/extractPredicateDependencies.js +36 -0
- package/src/fore.js +41 -16
- package/src/fx-bind.js +128 -23
- package/src/fx-connection.js +24 -7
- package/src/fx-fore.js +506 -259
- package/src/fx-instance.js +9 -11
- package/src/fx-model.js +154 -65
- package/src/fx-submission.js +19 -30
- package/src/fx-var.js +5 -0
- package/src/getInScopeContext.js +7 -8
- package/src/modelitem.js +247 -112
- package/src/tools/fx-action-log.js +21 -19
- package/src/tools/fx-log-settings.js +4 -2
- package/src/ui/TemplateExpression.js +12 -0
- package/src/ui/UIElement.js +125 -10
- package/src/ui/abstract-control.js +5 -0
- package/src/ui/fx-case.js +15 -3
- package/src/ui/fx-container.js +5 -0
- package/src/ui/fx-control-menu.js +23 -14
- package/src/ui/fx-control.js +55 -15
- package/src/ui/fx-items.js +10 -4
- package/src/ui/fx-repeat-attributes.js +111 -35
- package/src/ui/fx-repeat.js +332 -85
- package/src/ui/fx-repeat.updated.js +821 -0
- package/src/ui/fx-repeatitem.js +23 -20
- package/src/ui/fx-switch.js +5 -3
- package/src/ui/fx-upload.js +36 -40
- package/src/ui/repeat-base.js +532 -0
- package/src/withDraggability.js +8 -4
- package/src/xpath-evaluation.js +26 -8
- package/src/xpath-path.js +79 -0
- package/src/xpath-util.js +357 -289
package/src/ui/fx-repeat.js
CHANGED
|
@@ -7,6 +7,9 @@ import getInScopeContext from '../getInScopeContext.js';
|
|
|
7
7
|
import { XPathUtil } from '../xpath-util.js';
|
|
8
8
|
import { withDraggability } from '../withDraggability.js';
|
|
9
9
|
import { UIElement } from './UIElement.js';
|
|
10
|
+
import { getPath } from '../xpath-path.js';
|
|
11
|
+
import { FxModel } from '../fx-model.js';
|
|
12
|
+
import { FxBind } from '../fx-bind.js';
|
|
10
13
|
|
|
11
14
|
// import {DependencyNotifyingDomFacade} from '../DependencyNotifyingDomFacade';
|
|
12
15
|
|
|
@@ -65,46 +68,13 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
65
68
|
this.index = 1;
|
|
66
69
|
this.repeatSize = 0;
|
|
67
70
|
this.attachShadow({ mode: 'open', delegatesFocus: true });
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
get repeatSize() {
|
|
71
|
-
return this.querySelectorAll(':scope > fx-repeatitem').length;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
set repeatSize(size) {
|
|
75
|
-
this.size = size;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
setIndex(index) {
|
|
79
|
-
// console.log('new repeat index ', index);
|
|
80
|
-
this.index = index;
|
|
81
|
-
const rItems = this.querySelectorAll(':scope > fx-repeatitem');
|
|
82
|
-
this.applyIndex(rItems[this.index - 1]);
|
|
83
|
-
|
|
84
|
-
this.getOwnerForm().refresh({ reason: 'index-function', elementLocalnamesWithChanges: [] });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
applyIndex(repeatItem) {
|
|
88
|
-
this._removeIndexMarker();
|
|
89
|
-
if (repeatItem) {
|
|
90
|
-
repeatItem.setAttribute('repeat-index', '');
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
get index() {
|
|
95
|
-
return parseInt(this.getAttribute('index'), 10);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
set index(idx) {
|
|
99
|
-
this.setAttribute('index', idx);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
_getRef() {
|
|
103
|
-
return this.getAttribute('ref');
|
|
71
|
+
this.opNum = 0; // global number of operations
|
|
104
72
|
}
|
|
105
73
|
|
|
106
74
|
connectedCallback() {
|
|
107
75
|
super.connectedCallback();
|
|
76
|
+
this.template = this.querySelector('template');
|
|
77
|
+
|
|
108
78
|
// console.log('connectedCallback',this);
|
|
109
79
|
// this.display = window.getComputedStyle(this, null).getPropertyValue("display");
|
|
110
80
|
this.ref = this.getAttribute('ref');
|
|
@@ -113,49 +83,134 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
113
83
|
// console.log('### fx-repeat connected ', this.id);
|
|
114
84
|
this.addEventListener('item-changed', e => {
|
|
115
85
|
const { item } = e.detail;
|
|
116
|
-
|
|
117
|
-
// Warning: index is one-based
|
|
118
|
-
this.setIndex(idx + 1);
|
|
86
|
+
this.setIndex(item.index);
|
|
119
87
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
this.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
88
|
+
|
|
89
|
+
// Listen for insertion events
|
|
90
|
+
this.handleInsertHandler = event => {
|
|
91
|
+
const { detail } = event;
|
|
92
|
+
const myForeId = this.getOwnerForm().id;
|
|
93
|
+
if (myForeId !== detail.foreId) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// todo: early out if this.ref does not match the ref of the inserted node. Avoid re-evaluating the nodeset
|
|
97
|
+
// if (this.ref !== detail.ref) return;
|
|
98
|
+
|
|
99
|
+
console.log('insert catched', detail);
|
|
100
|
+
|
|
101
|
+
// Step 1: Refresh/re-evaluate the nodeset
|
|
102
|
+
const oldNodesetLength = this.nodeset.length;
|
|
103
|
+
this._evalNodeset();
|
|
104
|
+
const newNodesetLength = this.nodeset.length;
|
|
105
|
+
if (oldNodesetLength === newNodesetLength) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @type {number}
|
|
111
|
+
*/
|
|
112
|
+
// const insertionIndex = detail.index;
|
|
113
|
+
/**
|
|
114
|
+
* The newly inserted node. TODO: handle multiple?
|
|
115
|
+
* @type {Node}
|
|
116
|
+
*/
|
|
117
|
+
const insertedNode = detail.insertedNodes;
|
|
118
|
+
const insertionIndex = this.nodeset.indexOf(insertedNode) + 1;
|
|
119
|
+
// Step 2: Get current repeat items and create a new item
|
|
120
|
+
/**
|
|
121
|
+
* @type {import('./fx-repeatitem.js').FxRepeatitem[]}
|
|
122
|
+
*/
|
|
123
|
+
const repeatItems = Array.from(
|
|
124
|
+
this.querySelectorAll(
|
|
125
|
+
':scope > fx-repeat-item, :scope > fx-repeatitem, :scope > .repeat-item',
|
|
126
|
+
),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// todo: search fx-bind elements with same nodeset as this repeat - if present update modelItem instead of creating one
|
|
130
|
+
const newRepeatItem = this._createNewRepeatItem();
|
|
131
|
+
|
|
132
|
+
// Step 3: Insert the new repeatItem at the correct position
|
|
133
|
+
const beforeNode = repeatItems[insertionIndex - 1] ?? null; // Null appends by default
|
|
134
|
+
this.insertBefore(newRepeatItem, beforeNode);
|
|
135
|
+
newRepeatItem.index = insertionIndex;
|
|
136
|
+
this._initVariables(newRepeatItem);
|
|
137
|
+
|
|
138
|
+
// Step 4: Assign the inserted nodeset to the new `repeatItem`
|
|
139
|
+
newRepeatItem.nodeset = detail.insertedNodes;
|
|
140
|
+
|
|
141
|
+
// Update all the indices following here
|
|
142
|
+
for (let i = insertionIndex - 1; i < repeatItems.length; ++i) {
|
|
143
|
+
const sibling = repeatItems[i];
|
|
144
|
+
// TODO: handle the next ones
|
|
145
|
+
sibling.index += 1;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.setIndex(insertionIndex); // sets attribute + applies repeat-index + refresh
|
|
149
|
+
|
|
150
|
+
// Generate the parent `modelItem` for the new repeat item
|
|
151
|
+
this.opNum++;
|
|
152
|
+
const parentModelItem = FxBind.createModelItem(
|
|
153
|
+
this.ref,
|
|
154
|
+
detail.insertedNodes,
|
|
155
|
+
newRepeatItem,
|
|
156
|
+
this.opNum,
|
|
157
|
+
);
|
|
158
|
+
newRepeatItem.modelItem = parentModelItem;
|
|
159
|
+
|
|
160
|
+
this.getModel().registerModelItem(parentModelItem);
|
|
161
|
+
|
|
162
|
+
// Step 5: Create modelItems recursively for child elements
|
|
163
|
+
this._createModelItemsRecursively(newRepeatItem, parentModelItem);
|
|
164
|
+
// Step 6: Notify and refresh the UI
|
|
165
|
+
this.getOwnerForm().scanForNewTemplateExpressionsNextRefresh();
|
|
166
|
+
this.getOwnerForm().addToBatchedNotifications(newRepeatItem);
|
|
167
|
+
};
|
|
168
|
+
this.handleDeleteHandler = event => {
|
|
169
|
+
console.log('delete catched', event);
|
|
170
|
+
const { detail } = event;
|
|
171
|
+
if (!detail || !detail.deletedNodes) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Remove corresponding repeat items for deleted nodes
|
|
176
|
+
detail.deletedNodes.forEach(node => {
|
|
177
|
+
this.handleDelete(node);
|
|
178
|
+
// this.removeRepeatItemForNode(node);
|
|
179
|
+
});
|
|
180
|
+
this.getOwnerForm().addToBatchedNotifications(this);
|
|
181
|
+
};
|
|
182
|
+
// inside connectedCallback()
|
|
183
|
+
document.addEventListener('insert', this.handleInsertHandler, true);
|
|
184
|
+
document.addEventListener('deleted', this.handleDeleteHandler, true);
|
|
137
185
|
|
|
138
186
|
// if (this.getOwnerForm().lazyRefresh) {
|
|
187
|
+
/**
|
|
188
|
+
* @type {MutationRecord[]}
|
|
189
|
+
*/
|
|
190
|
+
let bufferedMutationRecords = [];
|
|
191
|
+
let debouncedOnMutations = null;
|
|
139
192
|
this.mutationObserver = new MutationObserver(mutations => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
193
|
+
bufferedMutationRecords.push(...mutations);
|
|
194
|
+
if (!debouncedOnMutations) {
|
|
195
|
+
debouncedOnMutations = new Promise(() => {
|
|
196
|
+
debouncedOnMutations = null;
|
|
197
|
+
const records = bufferedMutationRecords;
|
|
198
|
+
bufferedMutationRecords = [];
|
|
199
|
+
const shouldRefresh = false;
|
|
200
|
+
for (const mutation of records) {
|
|
201
|
+
if (mutation.type === 'childList') {
|
|
202
|
+
const added = mutation.addedNodes[0];
|
|
203
|
+
if (added) {
|
|
204
|
+
const instance = XPathUtil.resolveInstance(this, this.ref);
|
|
205
|
+
const path = getPath(added, instance);
|
|
206
|
+
Fore.dispatch(this, 'path-mutated', { path, index: this.index });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
156
211
|
}
|
|
157
212
|
});
|
|
158
|
-
|
|
213
|
+
|
|
159
214
|
this.getOwnerForm().registerLazyElement(this);
|
|
160
215
|
|
|
161
216
|
const style = `
|
|
@@ -185,6 +240,180 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
185
240
|
// this.init();
|
|
186
241
|
}
|
|
187
242
|
|
|
243
|
+
disconnectedCallback() {
|
|
244
|
+
document.removeEventListener('deleted', this.handleDeleteHandler, true);
|
|
245
|
+
document.removeEventListener('insert', this.handleInsertHandler, true);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
get repeatSize() {
|
|
249
|
+
return this.querySelectorAll(':scope > fx-repeatitem').length;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
set repeatSize(size) {
|
|
253
|
+
this.size = size;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
setIndex(index) {
|
|
257
|
+
// console.log('new repeat index ', index);
|
|
258
|
+
this.index = index;
|
|
259
|
+
const rItems = this.querySelectorAll(':scope > fx-repeatitem');
|
|
260
|
+
this.applyIndex(rItems[this.index - 1]);
|
|
261
|
+
|
|
262
|
+
// trying to do without
|
|
263
|
+
// this.getOwnerForm().refresh({ reason: 'index-function', elementLocalnamesWithChanges: [] });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
applyIndex(repeatItem) {
|
|
267
|
+
this._removeIndexMarker();
|
|
268
|
+
if (repeatItem) {
|
|
269
|
+
repeatItem.setAttribute('repeat-index', '');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
get index() {
|
|
274
|
+
return parseInt(this.getAttribute('index'), 10);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
set index(idx) {
|
|
278
|
+
this.setAttribute('index', idx);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
_getRef() {
|
|
282
|
+
return this.getAttribute('ref');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
_createModelItemsRecursively(parentNode, parentModelItem) {
|
|
286
|
+
const parentWithDewey = parentModelItem?.path || null; // e.g. $default/AllowanceCharge[2]_1
|
|
287
|
+
const parentBase = parentWithDewey ? parentWithDewey.replace(/_\d+$/, '') : null; // e.g. $default/AllowanceCharge[2]
|
|
288
|
+
|
|
289
|
+
// Robust Dewey rewrite that tolerates $inst vs instance('inst') forms
|
|
290
|
+
const __applyDeweyRewrite = mi => {
|
|
291
|
+
if (!mi || typeof mi.path !== 'string' || !parentModelItem?.path) return;
|
|
292
|
+
|
|
293
|
+
const pWith = parentModelItem.path; // e.g. $default/AllowanceCharge[2]_1 or instance('default')/AllowanceCharge[2]_1
|
|
294
|
+
const opMatch = pWith.match(/_(\d+)$/);
|
|
295
|
+
if (!opMatch) return;
|
|
296
|
+
const op = opMatch[1];
|
|
297
|
+
|
|
298
|
+
// Normalize to $name/ and strip _n on parent; normalize child for prefix test only
|
|
299
|
+
const toDollar = s => s.replace(/^instance\('([^']+)'\)\//, (_m, g1) => `$${g1}/`);
|
|
300
|
+
const parentBaseNorm = toDollar(pWith).replace(/_\d+$/, ''); // $default/AllowanceCharge[2]
|
|
301
|
+
const childNorm = toDollar(mi.path);
|
|
302
|
+
|
|
303
|
+
if (!childNorm.startsWith(parentBaseNorm)) return; // unrelated subtree
|
|
304
|
+
|
|
305
|
+
// Preserve original style of child's instance prefix
|
|
306
|
+
const childUsesInstanceFn = /^instance\('/.test(mi.path);
|
|
307
|
+
const parentBaseInChildStyle = childUsesInstanceFn
|
|
308
|
+
? parentBaseNorm.replace(/^\$([A-Za-z0-9_-]+)\//, `instance('$1')/`)
|
|
309
|
+
: parentBaseNorm;
|
|
310
|
+
|
|
311
|
+
// If already suffixed for this parent, nothing to do
|
|
312
|
+
if (mi.path.startsWith(`${parentBaseInChildStyle}_`)) return;
|
|
313
|
+
|
|
314
|
+
// Inject _op immediately after the parent base segment
|
|
315
|
+
mi.path = `${parentBaseInChildStyle}_${op}${mi.path.slice(parentBaseInChildStyle.length)}`;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
Array.from(parentNode.children).forEach(child => {
|
|
319
|
+
const nextParentMI = parentModelItem;
|
|
320
|
+
|
|
321
|
+
// Skip native/embedded widgets that may carry a 'ref' but are UI only
|
|
322
|
+
const isWidgetEl =
|
|
323
|
+
child &&
|
|
324
|
+
((child.classList && child.classList.contains('widget')) ||
|
|
325
|
+
(typeof Fore !== 'undefined' && Fore.isWidget && Fore.isWidget(child)) ||
|
|
326
|
+
(child.tagName &&
|
|
327
|
+
['INPUT', 'SELECT', 'TEXTAREA', 'OPTION', 'DATALIST'].includes(child.tagName)));
|
|
328
|
+
|
|
329
|
+
if (!isWidgetEl && child.hasAttribute('ref')) {
|
|
330
|
+
const ref = child.getAttribute('ref').trim();
|
|
331
|
+
if (ref && ref !== '.') {
|
|
332
|
+
// Evaluate the FULL ref once — this yields the terminal (last) node(s)
|
|
333
|
+
let node = evaluateXPath(ref, parentModelItem.node, this);
|
|
334
|
+
if (Array.isArray(node)) node = node[0];
|
|
335
|
+
|
|
336
|
+
if (node) {
|
|
337
|
+
let modelItem = this.getModel().getModelItem(node);
|
|
338
|
+
if (!modelItem) {
|
|
339
|
+
// Create a ModelItem only for the final node; children never get their own opNum
|
|
340
|
+
modelItem = FxBind.createModelItem(ref, node, child, null);
|
|
341
|
+
modelItem.parentModelItem = parentModelItem;
|
|
342
|
+
this.getModel().registerModelItem(modelItem);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Always apply Dewey rewrite (handles both $inst and instance('inst') forms)
|
|
346
|
+
__applyDeweyRewrite(modelItem);
|
|
347
|
+
|
|
348
|
+
child.nodeset = node;
|
|
349
|
+
if (child.attachObserver) child.attachObserver();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Recurse into non-widget subtrees
|
|
355
|
+
if (!isWidgetEl) this._createModelItemsRecursively(child, nextParentMI);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Removes the repeat item corresponding to a deleted node.
|
|
361
|
+
* Cleans up its observers and notifies the parent form.
|
|
362
|
+
* @param {Node} node - The deleted node
|
|
363
|
+
*/
|
|
364
|
+
removeRepeatItemForNode(node) {
|
|
365
|
+
const index = this.nodeset.indexOf(node);
|
|
366
|
+
if (index === -1) return;
|
|
367
|
+
|
|
368
|
+
const repeatItem = this.querySelector(`fx-repeatitem:nth-of-type(${index + 1})`);
|
|
369
|
+
if (repeatItem) {
|
|
370
|
+
this.removeChild(repeatItem);
|
|
371
|
+
this.getOwnerForm().addToBatchedNotifications(this);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Remove the node from the nodeset
|
|
375
|
+
this.nodeset.splice(index, 1);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
handleDelete(deleted) {
|
|
379
|
+
console.log('handleDelete', deleted);
|
|
380
|
+
// grab the current repeat items (tweak selector if yours differs)
|
|
381
|
+
/**
|
|
382
|
+
* @type {import('./fx-repeatitem.js').FxRepeatitem[]}
|
|
383
|
+
*/
|
|
384
|
+
const items = Array.from(
|
|
385
|
+
this.querySelectorAll(
|
|
386
|
+
':scope > fx-repeat-item, :scope > fx-repeatitem, :scope > .repeat-item',
|
|
387
|
+
),
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
this._evalNodeset();
|
|
391
|
+
|
|
392
|
+
const indexToRemove = items.findIndex(item => item.nodeset === deleted);
|
|
393
|
+
if (indexToRemove === -1) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const itemToRemove = items[indexToRemove];
|
|
397
|
+
itemToRemove.remove();
|
|
398
|
+
|
|
399
|
+
// If the list is now empty, clear selection (0). Adjust if you prefer 1-based only.
|
|
400
|
+
const newLength = this.querySelectorAll(
|
|
401
|
+
':scope > fx-repeat-item, :scope > fx-repeatitem, :scope > .repeat-item',
|
|
402
|
+
).length;
|
|
403
|
+
|
|
404
|
+
let nextIndex = indexToRemove + 1; // 1-based index at the deleted slot
|
|
405
|
+
if (newLength === 0) {
|
|
406
|
+
nextIndex = 0; // nothing left; clear selection
|
|
407
|
+
} else if (nextIndex > newLength) {
|
|
408
|
+
nextIndex = newLength; // deleted the last one; move to new last
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
this.setIndex(nextIndex);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* @returns {import('./fx-repeatitem.js').FxRepeatitem}
|
|
416
|
+
*/
|
|
188
417
|
_createNewRepeatItem() {
|
|
189
418
|
const newItem = document.createElement('fx-repeatitem');
|
|
190
419
|
|
|
@@ -223,7 +452,7 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
223
452
|
// console.log('##### inscope ', inscope);
|
|
224
453
|
// console.log('##### ref ', this.ref);
|
|
225
454
|
// now we got a nodeset and attach MutationObserver to it
|
|
226
|
-
|
|
455
|
+
if (!inscope) return;
|
|
227
456
|
if (this.mutationObserver && inscope.nodeName) {
|
|
228
457
|
this.mutationObserver.observe(inscope, {
|
|
229
458
|
childList: true,
|
|
@@ -251,19 +480,12 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
251
480
|
}
|
|
252
481
|
|
|
253
482
|
async refresh(force) {
|
|
254
|
-
|
|
483
|
+
console.log('🔄 fx-repeat.refresh on', this.id);
|
|
255
484
|
|
|
256
485
|
if (!this.inited) this.init();
|
|
257
486
|
// console.time('repeat-refresh', this);
|
|
258
487
|
this._evalNodeset();
|
|
259
488
|
|
|
260
|
-
// ### register ourselves as boundControl
|
|
261
|
-
/*
|
|
262
|
-
const modelItem = this.getModelItem();
|
|
263
|
-
if (!modelItem.boundControls.includes(this)) {
|
|
264
|
-
modelItem.boundControls.push(this);
|
|
265
|
-
}
|
|
266
|
-
*/
|
|
267
489
|
// console.log('repeat refresh nodeset ', this.nodeset);
|
|
268
490
|
// console.log('repeatCount', this.repeatCount);
|
|
269
491
|
|
|
@@ -297,6 +519,7 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
297
519
|
const newItem = this._createNewRepeatItem();
|
|
298
520
|
|
|
299
521
|
this.appendChild(newItem);
|
|
522
|
+
|
|
300
523
|
this._initVariables(newItem);
|
|
301
524
|
|
|
302
525
|
newItem.nodeset = this.nodeset[position - 1];
|
|
@@ -308,6 +531,8 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
308
531
|
|
|
309
532
|
// Tell the owner form we might have new template expressions here
|
|
310
533
|
this.getOwnerForm().scanForNewTemplateExpressionsNextRefresh();
|
|
534
|
+
|
|
535
|
+
newItem.refresh(true);
|
|
311
536
|
}
|
|
312
537
|
}
|
|
313
538
|
|
|
@@ -318,11 +543,15 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
318
543
|
|
|
319
544
|
if (item.nodeset !== this.nodeset[position]) {
|
|
320
545
|
item.nodeset = this.nodeset[position];
|
|
546
|
+
if (this.getOwnerForm().createNodes) {
|
|
547
|
+
this.getOwnerForm().initData(item);
|
|
548
|
+
}
|
|
321
549
|
}
|
|
322
550
|
}
|
|
323
551
|
|
|
324
|
-
// Fore.refreshChildren(clone,true);
|
|
552
|
+
// Fore.refreshChildren(clone, true);
|
|
325
553
|
const fore = this.getOwnerForm();
|
|
554
|
+
// if (!fore.lazyRefresh || force) {
|
|
326
555
|
if (!fore.lazyRefresh || force) {
|
|
327
556
|
// Turn the possibly conditional force refresh into a forced one: we changed our children
|
|
328
557
|
Fore.refreshChildren(this, force);
|
|
@@ -372,7 +601,6 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
372
601
|
}
|
|
373
602
|
|
|
374
603
|
_initTemplate() {
|
|
375
|
-
this.template = this.querySelector('template');
|
|
376
604
|
// console.log('### init template for repeat ', this.id, this.template);
|
|
377
605
|
// todo: this.dropTarget not needed?
|
|
378
606
|
this.dropTarget = this.template.getAttribute('drop-target');
|
|
@@ -415,11 +643,12 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
415
643
|
if (repeatItem.index === 1) {
|
|
416
644
|
this.applyIndex(repeatItem);
|
|
417
645
|
}
|
|
418
|
-
// console.log('*********repeat item created', repeatItem.nodeset)
|
|
646
|
+
// console.log('*********repeat item created', repeatItem.nodeset);
|
|
419
647
|
Fore.dispatch(this, 'item-created', { nodeset: repeatItem.nodeset, pos: index + 1 });
|
|
420
648
|
this._initVariables(repeatItem);
|
|
421
649
|
});
|
|
422
650
|
}
|
|
651
|
+
|
|
423
652
|
clearTextValues(node) {
|
|
424
653
|
if (!node) return;
|
|
425
654
|
|
|
@@ -454,12 +683,30 @@ export class FxRepeat extends withDraggability(UIElement, false) {
|
|
|
454
683
|
})(newRepeatItem);
|
|
455
684
|
}
|
|
456
685
|
|
|
686
|
+
/*
|
|
457
687
|
_clone() {
|
|
458
688
|
// const content = this.template.content.cloneNode(true);
|
|
459
689
|
this.template = this.shadowRoot.querySelector('template');
|
|
460
690
|
const content = this.template.content.cloneNode(true);
|
|
461
691
|
return document.importNode(content, true);
|
|
462
692
|
}
|
|
693
|
+
*/
|
|
694
|
+
|
|
695
|
+
_clone() {
|
|
696
|
+
// Prefer the cached template set in _initTemplate; fall back to either DOM.
|
|
697
|
+
const tpl =
|
|
698
|
+
this.template ||
|
|
699
|
+
(this.shadowRoot && this.shadowRoot.querySelector('template')) ||
|
|
700
|
+
this.querySelector('template');
|
|
701
|
+
|
|
702
|
+
if (!tpl) {
|
|
703
|
+
console.error(`[fx-repeat] ${this.id || ''}: no <template> found when cloning`);
|
|
704
|
+
return document.createDocumentFragment();
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const content = tpl.content.cloneNode(true);
|
|
708
|
+
return document.importNode(content, true);
|
|
709
|
+
}
|
|
463
710
|
|
|
464
711
|
_removeIndexMarker() {
|
|
465
712
|
Array.from(this.children).forEach(item => {
|