@jinntec/fore 2.0.0 → 2.1.1

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,268 +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
- // Tell the owner form we might have new template expressions here
283
- this.getOwnerForm().scanForNewTemplateExpressionsNextRefresh();
284
- }
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);
285
329
  }
286
330
 
287
- // ### update nodeset of repeatitems
288
- for (let position = 0; position < repeatItemCount; position += 1) {
289
- const item = repeatItems[position];
290
- 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
+ }
291
344
 
292
- if (item.nodeset !== this.nodeset[position]) {
293
- item.nodeset = this.nodeset[position];
294
- }
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
+ })();
295
362
  }
296
363
 
297
- // Fore.refreshChildren(clone,true);
298
- const fore = this.getOwnerForm();
299
- if (!fore.lazyRefresh || force) {
300
- 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);
301
383
  }
302
- // this.style.display = 'block';
303
- // this.style.display = this.display;
304
- this.setIndex(this.index);
305
- // console.timeEnd('repeat-refresh');
306
-
307
- // this.replaceWith(clone);
308
-
309
- // this.repeatCount = contextSize;
310
- // console.log('repeatCount', this.repeatCount);
311
- }
312
-
313
- // eslint-disable-next-line class-methods-use-this
314
- _fadeOut(el) {
315
- el.style.opacity = 1;
316
-
317
- (function fade() {
318
- // eslint-disable-next-line no-cond-assign
319
- if ((el.style.opacity -= 0.1) < 0) {
320
- el.style.display = 'none';
321
- } else {
322
- requestAnimationFrame(fade);
323
- }
324
- })();
325
- }
326
-
327
- // eslint-disable-next-line class-methods-use-this
328
- _fadeIn(el) {
329
- if (!el) return;
330
-
331
- el.style.opacity = 0;
332
- el.style.display = this.display;
333
-
334
- (function fade() {
335
- // setTimeout(() => {
336
- let val = parseFloat(el.style.opacity);
337
- // eslint-disable-next-line no-cond-assign
338
- if (!((val += 0.1) > 1)) {
339
- el.style.opacity = val;
340
- requestAnimationFrame(fade);
341
- }
342
- // }, 40);
343
- })();
344
- }
345
-
346
- _initTemplate() {
347
- // const shadowTemplate = this.shadowRoot.querySelector('template');
348
- // console.log('shadowtempl ', shadowTemplate);
349
-
350
- // const defaultSlot = this.shadowRoot.querySelector('slot');
351
- // todo: this is still weak - should handle that better maybe by an explicit slot?
352
- // this.template = this.firstElementChild;
353
- this.template = this.querySelector('template');
354
- // console.log('### init template for repeat ', this.id, this.template);
355
-
356
- if (this.template === null) {
357
- // console.error('### no template found for this repeat:', this.id);
358
- // todo: catch this on form element
359
- this.dispatchEvent(
360
- new CustomEvent('no-template-error', {
361
- composed: true,
362
- bubbles: true,
363
- detail: { message: `no template found for repeat:${this.id}` },
364
- }),
365
- );
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
+ });
366
400
  }
367
401
 
368
- this.shadowRoot.appendChild(this.template);
369
- }
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
+ }
370
414
 
371
- _initRepeatItems() {
372
- // const model = this.getModel();
373
- // this.textContent = '';
374
- this.nodeset.forEach((item, index) => {
375
- const repeatItem = document.createElement('fx-repeatitem');
376
- repeatItem.nodeset = this.nodeset[index];
377
- 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
+ }
378
421
 
379
- const clone = this._clone();
380
- repeatItem.appendChild(clone);
381
- this.appendChild(repeatItem);
422
+ _removeIndexMarker() {
423
+ Array.from(this.children).forEach(item => {
424
+ item.removeAttribute('repeat-index');
425
+ });
426
+ }
382
427
 
383
- if (repeatItem.index === 1) {
384
- this.applyIndex(repeatItem);
385
- }
386
- // console.log('*********repeat item created', repeatItem.nodeset)
387
- Fore.dispatch(this,'item-created',{nodeset:repeatItem.nodeset, pos:index+1});
388
- this._initVariables(repeatItem);
389
- });
390
- }
391
-
392
- _initVariables(newRepeatItem) {
393
- const inScopeVariables = new Map(this.inScopeVariables);
394
- newRepeatItem.setInScopeVariables(inScopeVariables);
395
- (function registerVariables(node) {
396
- for (const child of node.children) {
397
- if ('setInScopeVariables' in child) {
398
- child.setInScopeVariables(inScopeVariables);
399
- }
400
- registerVariables(child);
401
- }
402
- })(newRepeatItem);
403
- }
404
-
405
- _clone() {
406
- // const content = this.template.content.cloneNode(true);
407
- this.template = this.shadowRoot.querySelector('template');
408
- const content = this.template.content.cloneNode(true);
409
- return document.importNode(content, true);
410
- }
411
-
412
- _removeIndexMarker() {
413
- Array.from(this.children).forEach(item => {
414
- item.removeAttribute('repeat-index');
415
- });
416
- }
417
-
418
- setInScopeVariables(inScopeVariables) {
419
- // Repeats are interesting: the variables should be scoped per repeat item, they should not be
420
- // able to see the variables in adjacent repeat items!
421
- this.inScopeVariables = new Map(inScopeVariables);
422
- }
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
+ }
423
433
  }
424
434
 
425
435
  if (!customElements.get('fx-repeat')) {
426
- window.customElements.define('fx-repeat', FxRepeat);
436
+ window.customElements.define('fx-repeat', FxRepeat);
427
437
  }