@jinntec/fore 1.10.3 → 2.1.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.
@@ -1,11 +1,14 @@
1
1
  import './fx-repeatitem.js';
2
2
 
3
- import { Fore } from '../fore.js';
4
- import { foreElementMixin } from '../ForeElementMixin.js';
5
- import { evaluateXPath } from '../xpath-evaluation.js';
3
+ import {Fore} from '../fore.js';
4
+ import {foreElementMixin} from '../ForeElementMixin.js';
5
+ import {evaluateXPath} from '../xpath-evaluation.js';
6
6
  import getInScopeContext from '../getInScopeContext.js';
7
- import { XPathUtil } from '../xpath-util.js';
8
- import {DependencyNotifyingDomFacade} from '../DependencyNotifyingDomFacade';
7
+ import {XPathUtil} from '../xpath-util.js';
8
+ import {FxFore} from '../fx-fore.js';
9
+ import {withDraggability} from '../withDraggability.js';
10
+
11
+ // import {DependencyNotifyingDomFacade} from '../DependencyNotifyingDomFacade';
9
12
 
10
13
  /**
11
14
  * `fx-repeat`
@@ -22,133 +25,136 @@ import {DependencyNotifyingDomFacade} from '../DependencyNotifyingDomFacade';
22
25
  *
23
26
  * todo: it should be seriously be considered to extend FxContainer instead but needs refactoring first.
24
27
  */
25
- export class FxRepeat extends foreElementMixin(HTMLElement) {
26
- static get properties() {
27
- return {
28
- ...super.properties,
29
- index: {
30
- type: Number,
31
- },
32
- template: {
33
- type: Object,
34
- },
35
- focusOnCreate: {
36
- type: String,
37
- },
38
- initDone: {
39
- type: Boolean,
40
- },
41
- repeatIndex: {
42
- type: Number,
43
- },
44
- nodeset: {
45
- type: Array,
46
- },
47
- };
48
- }
49
-
50
- constructor() {
51
- super();
52
- this.ref = '';
53
- this.dataTemplate = [];
54
- this.focusOnCreate = '';
55
- this.initDone = false;
56
- this.repeatIndex = 1;
57
- this.nodeset = [];
58
- this.inited = false;
59
- this.index = 1;
60
- this.repeatSize = 0;
61
- this.attachShadow({ mode: 'open', delegatesFocus: true });
62
- }
63
-
64
- get repeatSize() {
65
- return this.querySelectorAll(':scope > fx-repeatitem').length;
66
- }
67
-
68
- set repeatSize(size) {
69
- this.size = size;
70
- }
71
-
72
- setIndex(index) {
73
- // console.log('new repeat index ', index);
74
- this.index = index;
75
- const rItems = this.querySelectorAll(':scope > fx-repeatitem');
76
- this.applyIndex(rItems[this.index - 1]);
77
- }
78
-
79
- applyIndex(repeatItem) {
80
- this._removeIndexMarker();
81
- if (repeatItem) {
82
- repeatItem.setAttribute('repeat-index', '');
28
+ export class FxRepeat extends withDraggability(foreElementMixin(HTMLElement), false) {
29
+ static get properties() {
30
+ return {
31
+ ...super.properties,
32
+ index: {
33
+ type: Number,
34
+ },
35
+ template: {
36
+ type: Object,
37
+ },
38
+ focusOnCreate: {
39
+ type: String,
40
+ },
41
+ initDone: {
42
+ type: Boolean,
43
+ },
44
+ repeatIndex: {
45
+ type: Number,
46
+ },
47
+ nodeset: {
48
+ type: Array,
49
+ },
50
+ };
51
+ }
52
+
53
+ constructor() {
54
+ super();
55
+ this.ref = '';
56
+ this.dataTemplate = [];
57
+ this.isDraggable=null;
58
+ this.dropTarget=null;
59
+ this.focusOnCreate = '';
60
+ this.initDone = false;
61
+ this.repeatIndex = 1;
62
+ this.nodeset = [];
63
+ this.inited = false;
64
+ this.index = 1;
65
+ this.repeatSize = 0;
66
+ this.attachShadow({mode: 'open', delegatesFocus: true});
67
+ }
68
+
69
+ get repeatSize() {
70
+ return this.querySelectorAll(':scope > fx-repeatitem').length;
71
+ }
72
+
73
+ set repeatSize(size) {
74
+ this.size = size;
83
75
  }
84
- }
85
-
86
- get index() {
87
- return this.getAttribute('index');
88
- }
89
-
90
- set index(idx) {
91
- this.setAttribute('index', idx);
92
- }
93
-
94
- _getRef(){
95
- return this.getAttribute('ref');
96
- }
97
-
98
- connectedCallback() {
99
- // console.log('connectedCallback',this);
100
- // this.display = window.getComputedStyle(this, null).getPropertyValue("display");
101
- this.ref = this.getAttribute('ref');
102
- // this.ref = this._getRef();
103
- // console.log('### fx-repeat connected ', this.id);
104
- this.addEventListener('item-changed', e => {
105
- const { item } = e.detail;
106
- const idx = Array.from(this.children).indexOf(item);
107
- this.applyIndex(this.children[idx]);
108
- this.index = idx + 1;
109
- });
110
- // todo: review - this is just used by append action - event consolidation ?
111
- document.addEventListener('index-changed', e => {
112
- e.stopPropagation();
113
- if (!e.target === this) return;
114
- // const { item } = e.detail;
115
- // const idx = Array.from(this.children).indexOf(item);
116
- const { index } = e.detail;
117
- this.index = Number(index);
118
- this.applyIndex(this.children[index - 1]);
119
- });
120
- /*
121
- document.addEventListener('insert', e => {
122
- const nodes = e.detail.insertedNodes;
123
- this.index = e.detail.position;
124
- console.log('insert catched', nodes, this.index);
125
- });
126
- */
127
-
128
- // if (this.getOwnerForm().lazyRefresh) {
129
- this.mutationObserver = new MutationObserver(mutations => {
130
- // console.log('mutations', mutations);
131
-
132
- if (mutations[0].type === 'childList') {
133
- const added = mutations[0].addedNodes[0];
134
- if (added) {
135
- const instance = XPathUtil.resolveInstance(this, this.ref);
136
- const path = XPathUtil.getPath(added, instance);
137
- // console.log('path mutated', path);
138
- // this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
139
- // this.index = index;
140
- // const prev = mutations[0].previousSibling.previousElementSibling;
141
- // const index = prev.index();
142
- // this.applyIndex(this.index -1);
143
-
144
- Fore.dispatch(this, 'path-mutated', { path, index: this.index });
76
+
77
+ setIndex(index) {
78
+ // console.log('new repeat index ', index);
79
+ this.index = index;
80
+ const rItems = this.querySelectorAll(':scope > fx-repeatitem');
81
+ this.applyIndex(rItems[this.index - 1]);
82
+ }
83
+
84
+ applyIndex(repeatItem) {
85
+ this._removeIndexMarker();
86
+ if (repeatItem) {
87
+ repeatItem.setAttribute('repeat-index', '');
145
88
  }
146
- }
147
- });
148
- // }
149
- this.getOwnerForm().registerLazyElement(this);
89
+ }
90
+
91
+ get index() {
92
+ return parseInt(this.getAttribute('index'), 10);
93
+ }
94
+
95
+ set index(idx) {
96
+ this.setAttribute('index', idx);
97
+ }
150
98
 
151
- const style = `
99
+ _getRef() {
100
+ return this.getAttribute('ref');
101
+ }
102
+
103
+ connectedCallback() {
104
+ super.connectedCallback();
105
+ // console.log('connectedCallback',this);
106
+ // this.display = window.getComputedStyle(this, null).getPropertyValue("display");
107
+ this.ref = this.getAttribute('ref');
108
+ // this.ref = this._getRef();
109
+ // console.log('### fx-repeat connected ', this.id);
110
+ this.addEventListener('item-changed', e => {
111
+ const {item} = e.detail;
112
+ const idx = Array.from(this.children).indexOf(item);
113
+ this.applyIndex(this.children[idx]);
114
+ this.index = idx + 1;
115
+ });
116
+ // todo: review - this is just used by append action - event consolidation ?
117
+ document.addEventListener('index-changed', e => {
118
+ e.stopPropagation();
119
+ if (!e.target === this) return;
120
+ // const { item } = e.detail;
121
+ // const idx = Array.from(this.children).indexOf(item);
122
+ const {index} = e.detail;
123
+ this.index = parseInt(index, 10);
124
+ this.applyIndex(this.children[index - 1]);
125
+ });
126
+ /*
127
+ document.addEventListener('insert', e => {
128
+ const nodes = e.detail.insertedNodes;
129
+ this.index = e.detail.position;
130
+ console.log('insert catched', nodes, this.index);
131
+ });
132
+ */
133
+
134
+ // if (this.getOwnerForm().lazyRefresh) {
135
+ this.mutationObserver = new MutationObserver(mutations => {
136
+ // console.log('mutations', mutations);
137
+
138
+ if (mutations[0].type === 'childList') {
139
+ const added = mutations[0].addedNodes[0];
140
+ if (added) {
141
+ const instance = XPathUtil.resolveInstance(this, this.ref);
142
+ const path = XPathUtil.getPath(added, instance);
143
+ // console.log('path mutated', path);
144
+ // this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
145
+ // this.index = index;
146
+ // const prev = mutations[0].previousSibling.previousElementSibling;
147
+ // const index = prev.index();
148
+ // this.applyIndex(this.index -1);
149
+
150
+ Fore.dispatch(this, 'path-mutated', {path, index: this.index});
151
+ }
152
+ }
153
+ });
154
+ // }
155
+ this.getOwnerForm().registerLazyElement(this);
156
+
157
+ const style = `
152
158
  :host{
153
159
  }
154
160
  .fade-out-bottom {
@@ -160,267 +166,272 @@ export class FxRepeat extends foreElementMixin(HTMLElement) {
160
166
  animation: fade-out-bottom 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
161
167
  }
162
168
  `;
163
- const html = `
169
+ const html = `
164
170
  <slot name="header"></slot>
165
171
  <slot></slot>
166
172
  `;
167
- this.shadowRoot.innerHTML = `
173
+ this.shadowRoot.innerHTML = `
168
174
  <style>
169
175
  ${style}
170
176
  </style>
171
177
  ${html}
172
178
  `;
173
179
 
174
- // this.init();
175
- }
176
-
177
- init() {
178
- // ### there must be a single 'template' child
179
- // console.log('##### repeat init ', this.id);
180
- // if(!this.inited) this.init();
181
- // does not use this.evalInContext as it is expecting a nodeset instead of single node
182
- this._evalNodeset();
183
- // console.log('##### ',this.id, this.nodeset);
184
-
185
- this._initTemplate();
186
- this._initRepeatItems();
187
-
188
- this.setAttribute('index', this.index);
189
- this.inited = true;
190
- }
191
-
192
- /**
193
- * repeat has no own modelItems
194
- * @private
195
- */
196
- _evalNodeset() {
197
- // const inscope = this.getInScopeContext();
198
- const inscope = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
199
- // console.log('##### inscope ', inscope);
200
- // console.log('##### ref ', this.ref);
201
- // now we got a nodeset and attach MutationObserver to it
202
-
203
- if (this.mutationObserver && inscope.nodeName) {
204
- this.mutationObserver.observe(inscope, {
205
- childList: true,
206
- subtree: true,
207
- });
208
- }
180
+ // this.init();
209
181
 
210
- /*
211
- this.touchedPaths = new Set();
212
- const instance = XPathUtil.resolveInstance(this, this.ref);
213
- const depTrackDomfacade = new DependencyNotifyingDomFacade((node) => {
214
- this.touchedPaths.add(XPathUtil.getPath(node, instance));
215
- });
216
- const rawNodeset = evaluateXPath(this.ref, inscope, this, {}, {}, depTrackDomfacade );
217
- */
218
- const rawNodeset = evaluateXPath(this.ref, inscope, this);
219
-
220
- // console.log('Touched!', this.ref, [...this.touchedPaths].join(', '));
221
- if (rawNodeset.length === 1 && Array.isArray(rawNodeset[0])) {
222
- // This XPath likely returned an XPath array. Just collapse to that array
223
- this.nodeset = rawNodeset[0];
224
- return;
225
182
  }
226
- this.nodeset = rawNodeset;
227
- }
228
183
 
229
- async refresh(force) {
230
- // console.group('fx-repeat.refresh on', this.id);
184
+ _createNewRepeatItem() {
185
+ const newItem = document.createElement('fx-repeatitem');
231
186
 
232
- if (!this.inited) this.init();
233
- // console.time('repeat-refresh', this);
234
- this._evalNodeset();
187
+ if (this.isDraggable) {
188
+ newItem.setAttribute('draggable', 'true');
189
+ newItem.setAttribute('tabindex', 0);
190
+ }
191
+ const clone = this._clone();
192
+ newItem.appendChild(clone);
235
193
 
236
- // ### register ourselves as boundControl
237
- /*
238
- const modelItem = this.getModelItem();
239
- if (!modelItem.boundControls.includes(this)) {
240
- modelItem.boundControls.push(this);
241
- }
242
- */
243
- // console.log('repeat refresh nodeset ', this.nodeset);
244
- // console.log('repeatCount', this.repeatCount);
194
+ return newItem;
195
+ }
245
196
 
246
- const repeatItems = this.querySelectorAll(':scope > fx-repeatitem');
247
- const repeatItemCount = repeatItems.length;
197
+ init() {
198
+ // ### there must be a single 'template' child
199
+ console.log('##### repeat init ', this.id);
200
+ // if(!this.inited) this.init();
201
+ // does not use this.evalInContext as it is expecting a nodeset instead of single node
202
+ this._evalNodeset();
203
+ // console.log('##### ',this.id, this.nodeset);
248
204
 
249
- let nodeCount = 1;
250
- if (Array.isArray(this.nodeset)) {
251
- nodeCount = this.nodeset.length;
205
+ this._initTemplate();
206
+ this._initRepeatItems();
207
+
208
+ this.setAttribute('index', this.index);
209
+ this.inited = true;
252
210
  }
253
211
 
254
- // const contextSize = this.nodeset.length;
255
- const contextSize = nodeCount;
256
- // todo: review - cant the context really never be smaller than the repeat count?
257
- // todo: this code can be deprecated probably but check first
258
- if (contextSize < repeatItemCount) {
259
- for (let position = repeatItemCount; position > contextSize; position -= 1) {
260
- // remove repeatitem
261
- const itemToRemove = repeatItems[position - 1];
262
- itemToRemove.parentNode.removeChild(itemToRemove);
263
- this.getOwnerForm().unRegisterLazyElement(itemToRemove);
264
- // this._fadeOut(itemToRemove);
265
- // Fore.fadeOutElement(itemToRemove)
266
- }
212
+ /**
213
+ * repeat has no own modelItems
214
+ * @private
215
+ */
216
+ _evalNodeset() {
217
+ // const inscope = this.getInScopeContext();
218
+ const inscope = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
219
+ // console.log('##### inscope ', inscope);
220
+ // console.log('##### ref ', this.ref);
221
+ // now we got a nodeset and attach MutationObserver to it
222
+
223
+ if (this.mutationObserver && inscope.nodeName) {
224
+ this.mutationObserver.observe(inscope, {
225
+ childList: true,
226
+ subtree: true,
227
+ });
228
+ }
229
+
230
+ /*
231
+ this.touchedPaths = new Set();
232
+ const instance = XPathUtil.resolveInstance(this, this.ref);
233
+ const depTrackDomfacade = new DependencyNotifyingDomFacade((node) => {
234
+ this.touchedPaths.add(XPathUtil.getPath(node, instance));
235
+ });
236
+ const rawNodeset = evaluateXPath(this.ref, inscope, this, {}, {}, depTrackDomfacade );
237
+ */
238
+ const rawNodeset = evaluateXPath(this.ref, inscope, this);
239
+
240
+ // console.log('Touched!', this.ref, [...this.touchedPaths].join(', '));
241
+ if (rawNodeset.length === 1 && Array.isArray(rawNodeset[0])) {
242
+ // This XPath likely returned an XPath array. Just collapse to that array
243
+ this.nodeset = rawNodeset[0];
244
+ return;
245
+ }
246
+ this.nodeset = rawNodeset;
267
247
  }
268
248
 
269
- if (contextSize > repeatItemCount) {
270
- for (let position = repeatItemCount + 1; position <= contextSize; position += 1) {
271
- // add new repeatitem
249
+ async refresh(force) {
250
+ // console.group('fx-repeat.refresh on', this.id);
251
+
252
+ if (!this.inited) this.init();
253
+ // console.time('repeat-refresh', this);
254
+ this._evalNodeset();
255
+
256
+ // ### register ourselves as boundControl
257
+ /*
258
+ const modelItem = this.getModelItem();
259
+ if (!modelItem.boundControls.includes(this)) {
260
+ modelItem.boundControls.push(this);
261
+ }
262
+ */
263
+ // console.log('repeat refresh nodeset ', this.nodeset);
264
+ // console.log('repeatCount', this.repeatCount);
265
+
266
+ const repeatItems = this.querySelectorAll(':scope > fx-repeatitem');
267
+ const repeatItemCount = repeatItems.length;
268
+
269
+ let nodeCount = 1;
270
+ if (Array.isArray(this.nodeset)) {
271
+ nodeCount = this.nodeset.length;
272
+ }
273
+
274
+ // const contextSize = this.nodeset.length;
275
+ const contextSize = nodeCount;
276
+ // todo: review - cant the context really never be smaller than the repeat count?
277
+ // todo: this code can be deprecated probably but check first
278
+ if (contextSize < repeatItemCount) {
279
+ for (let position = repeatItemCount; position > contextSize; position -= 1) {
280
+ // remove repeatitem
281
+ const itemToRemove = repeatItems[position - 1];
282
+ itemToRemove.parentNode.removeChild(itemToRemove);
283
+ this.getOwnerForm().unRegisterLazyElement(itemToRemove);
284
+ // this._fadeOut(itemToRemove);
285
+ // Fore.fadeOutElement(itemToRemove)
286
+ }
287
+ }
288
+
289
+ if (contextSize > repeatItemCount) {
290
+ for (let position = repeatItemCount + 1; position <= contextSize; position += 1) {
291
+ // add new repeatitem
272
292
 
273
- const newItem = document.createElement('fx-repeatitem');
274
- const clonedTemplate = this._clone();
275
- newItem.appendChild(clonedTemplate);
276
- this.appendChild(newItem);
293
+ const newItem = this._createNewRepeatItem();
277
294
 
278
- this._initVariables(newItem);
295
+ this.appendChild(newItem);
296
+ this._initVariables(newItem);
279
297
 
280
- newItem.nodeset = this.nodeset[position - 1];
281
- newItem.index = position;
282
- this.getOwnerForm().someInstanceDataStructureChanged = true;
283
- }
298
+ newItem.nodeset = this.nodeset[position - 1];
299
+ newItem.index = position;
300
+ // Tell the owner form we might have new template expressions here
301
+ this.getOwnerForm().scanForNewTemplateExpressionsNextRefresh();
302
+ }
303
+ }
304
+
305
+ // ### update nodeset of repeatitems
306
+ for (let position = 0; position < repeatItemCount; position += 1) {
307
+ const item = repeatItems[position];
308
+ this.getOwnerForm().registerLazyElement(item);
309
+
310
+ if (item.nodeset !== this.nodeset[position]) {
311
+ item.nodeset = this.nodeset[position];
312
+ }
313
+ }
314
+
315
+ // Fore.refreshChildren(clone,true);
316
+ const fore = this.getOwnerForm();
317
+ if (!fore.lazyRefresh || force) {
318
+ Fore.refreshChildren(this, force);
319
+ }
320
+ // this.style.display = 'block';
321
+ // this.style.display = this.display;
322
+ this.setIndex(this.index);
323
+ // console.timeEnd('repeat-refresh');
324
+
325
+ // this.replaceWith(clone);
326
+
327
+ // this.repeatCount = contextSize;
328
+ // console.log('repeatCount', this.repeatCount);
284
329
  }
285
330
 
286
- // ### update nodeset of repeatitems
287
- for (let position = 0; position < repeatItemCount; position += 1) {
288
- const item = repeatItems[position];
289
- this.getOwnerForm().registerLazyElement(item);
331
+ // eslint-disable-next-line class-methods-use-this
332
+ _fadeOut(el) {
333
+ el.style.opacity = 1;
334
+
335
+ (function fade() {
336
+ // eslint-disable-next-line no-cond-assign
337
+ if ((el.style.opacity -= 0.1) < 0) {
338
+ el.style.display = 'none';
339
+ } else {
340
+ requestAnimationFrame(fade);
341
+ }
342
+ })();
343
+ }
290
344
 
291
- if (item.nodeset !== this.nodeset[position]) {
292
- item.nodeset = this.nodeset[position];
293
- }
345
+ // eslint-disable-next-line class-methods-use-this
346
+ _fadeIn(el) {
347
+ if (!el) return;
348
+
349
+ el.style.opacity = 0;
350
+ el.style.display = this.display;
351
+
352
+ (function fade() {
353
+ // setTimeout(() => {
354
+ let val = parseFloat(el.style.opacity);
355
+ // eslint-disable-next-line no-cond-assign
356
+ if (!((val += 0.1) > 1)) {
357
+ el.style.opacity = val;
358
+ requestAnimationFrame(fade);
359
+ }
360
+ // }, 40);
361
+ })();
294
362
  }
295
363
 
296
- // Fore.refreshChildren(clone,true);
297
- const fore = this.getOwnerForm();
298
- if (!fore.lazyRefresh || force) {
299
- Fore.refreshChildren(this, force);
364
+ _initTemplate() {
365
+ this.template = this.querySelector('template');
366
+ // console.log('### init template for repeat ', this.id, this.template);
367
+ // todo: this.dropTarget not needed?
368
+ this.dropTarget = this.template.getAttribute('drop-target');
369
+ this.isDraggable = this.template.hasAttribute('draggable') ? this.template.getAttribute('draggable') : null;
370
+
371
+ if (this.template === null) {
372
+ // todo: catch this on form element
373
+ this.dispatchEvent(
374
+ new CustomEvent('no-template-error', {
375
+ composed: true,
376
+ bubbles: true,
377
+ detail: {message: `no template found for repeat:${this.id}`},
378
+ }),
379
+ );
380
+ }
381
+
382
+ this.shadowRoot.appendChild(this.template);
300
383
  }
301
- // this.style.display = 'block';
302
- // this.style.display = this.display;
303
- this.setIndex(this.index);
304
- // console.timeEnd('repeat-refresh');
305
-
306
- // this.replaceWith(clone);
307
-
308
- // this.repeatCount = contextSize;
309
- // console.log('repeatCount', this.repeatCount);
310
- }
311
-
312
- // eslint-disable-next-line class-methods-use-this
313
- _fadeOut(el) {
314
- el.style.opacity = 1;
315
-
316
- (function fade() {
317
- // eslint-disable-next-line no-cond-assign
318
- if ((el.style.opacity -= 0.1) < 0) {
319
- el.style.display = 'none';
320
- } else {
321
- requestAnimationFrame(fade);
322
- }
323
- })();
324
- }
325
-
326
- // eslint-disable-next-line class-methods-use-this
327
- _fadeIn(el) {
328
- if (!el) return;
329
-
330
- el.style.opacity = 0;
331
- el.style.display = this.display;
332
-
333
- (function fade() {
334
- // setTimeout(() => {
335
- let val = parseFloat(el.style.opacity);
336
- // eslint-disable-next-line no-cond-assign
337
- if (!((val += 0.1) > 1)) {
338
- el.style.opacity = val;
339
- requestAnimationFrame(fade);
340
- }
341
- // }, 40);
342
- })();
343
- }
344
-
345
- _initTemplate() {
346
- // const shadowTemplate = this.shadowRoot.querySelector('template');
347
- // console.log('shadowtempl ', shadowTemplate);
348
-
349
- // const defaultSlot = this.shadowRoot.querySelector('slot');
350
- // todo: this is still weak - should handle that better maybe by an explicit slot?
351
- // this.template = this.firstElementChild;
352
- this.template = this.querySelector('template');
353
- // console.log('### init template for repeat ', this.id, this.template);
354
-
355
- if (this.template === null) {
356
- // console.error('### no template found for this repeat:', this.id);
357
- // todo: catch this on form element
358
- this.dispatchEvent(
359
- new CustomEvent('no-template-error', {
360
- composed: true,
361
- bubbles: true,
362
- detail: { message: `no template found for repeat:${this.id}` },
363
- }),
364
- );
384
+
385
+ _initRepeatItems() {
386
+ this.nodeset.forEach((item, index) => {
387
+ const repeatItem = this._createNewRepeatItem();
388
+ repeatItem.nodeset = this.nodeset[index];
389
+ repeatItem.index = index + 1; // 1-based index
390
+
391
+ this.appendChild(repeatItem);
392
+
393
+ if (repeatItem.index === 1) {
394
+ this.applyIndex(repeatItem);
395
+ }
396
+ // console.log('*********repeat item created', repeatItem.nodeset)
397
+ Fore.dispatch(this, 'item-created', {nodeset: repeatItem.nodeset, pos: index + 1});
398
+ this._initVariables(repeatItem);
399
+ });
365
400
  }
366
401
 
367
- this.shadowRoot.appendChild(this.template);
368
- }
402
+ _initVariables(newRepeatItem) {
403
+ const inScopeVariables = new Map(this.inScopeVariables);
404
+ newRepeatItem.setInScopeVariables(inScopeVariables);
405
+ (function registerVariables(node) {
406
+ for (const child of node.children) {
407
+ if ('setInScopeVariables' in child) {
408
+ child.setInScopeVariables(inScopeVariables);
409
+ }
410
+ registerVariables(child);
411
+ }
412
+ })(newRepeatItem);
413
+ }
369
414
 
370
- _initRepeatItems() {
371
- // const model = this.getModel();
372
- // this.textContent = '';
373
- this.nodeset.forEach((item, index) => {
374
- const repeatItem = document.createElement('fx-repeatitem');
375
- repeatItem.nodeset = this.nodeset[index];
376
- repeatItem.index = index + 1; // 1-based index
415
+ _clone() {
416
+ // const content = this.template.content.cloneNode(true);
417
+ this.template = this.shadowRoot.querySelector('template');
418
+ const content = this.template.content.cloneNode(true);
419
+ return document.importNode(content, true);
420
+ }
377
421
 
378
- const clone = this._clone();
379
- repeatItem.appendChild(clone);
380
- this.appendChild(repeatItem);
422
+ _removeIndexMarker() {
423
+ Array.from(this.children).forEach(item => {
424
+ item.removeAttribute('repeat-index');
425
+ });
426
+ }
381
427
 
382
- if (repeatItem.index === 1) {
383
- this.applyIndex(repeatItem);
384
- }
385
- // console.log('*********repeat item created', repeatItem.nodeset)
386
- Fore.dispatch(this,'item-created',{nodeset:repeatItem.nodeset, pos:index+1});
387
- this._initVariables(repeatItem);
388
- });
389
- }
390
-
391
- _initVariables(newRepeatItem) {
392
- const inScopeVariables = new Map(this.inScopeVariables);
393
- newRepeatItem.setInScopeVariables(inScopeVariables);
394
- (function registerVariables(node) {
395
- for (const child of node.children) {
396
- if ('setInScopeVariables' in child) {
397
- child.setInScopeVariables(inScopeVariables);
398
- }
399
- registerVariables(child);
400
- }
401
- })(newRepeatItem);
402
- }
403
-
404
- _clone() {
405
- // const content = this.template.content.cloneNode(true);
406
- this.template = this.shadowRoot.querySelector('template');
407
- const content = this.template.content.cloneNode(true);
408
- return document.importNode(content, true);
409
- }
410
-
411
- _removeIndexMarker() {
412
- Array.from(this.children).forEach(item => {
413
- item.removeAttribute('repeat-index');
414
- });
415
- }
416
-
417
- setInScopeVariables(inScopeVariables) {
418
- // Repeats are interesting: the variables should be scoped per repeat item, they should not be
419
- // able to see the variables in adjacent repeat items!
420
- this.inScopeVariables = new Map(inScopeVariables);
421
- }
428
+ setInScopeVariables(inScopeVariables) {
429
+ // Repeats are interesting: the variables should be scoped per repeat item, they should not be
430
+ // able to see the variables in adjacent repeat items!
431
+ this.inScopeVariables = new Map(inScopeVariables);
432
+ }
422
433
  }
423
434
 
424
435
  if (!customElements.get('fx-repeat')) {
425
- window.customElements.define('fx-repeat', FxRepeat);
436
+ window.customElements.define('fx-repeat', FxRepeat);
426
437
  }