@jinntec/fore 1.4.0 → 1.5.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/index.js CHANGED
@@ -15,6 +15,7 @@ import './src/ui/fx-group.js';
15
15
  import './src/ui/fx-hint.js';
16
16
  import './src/ui/fx-output.js';
17
17
  import './src/ui/fx-repeat.js';
18
+ import './src/ui/fx-repeat-attributes.js';
18
19
  import './src/ui/fx-switch.js';
19
20
  import './src/ui/fx-trigger.js';
20
21
  import './src/ui/fx-case.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinntec/fore",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Fore - declarative user interfaces in plain HTML",
5
5
  "module": "./index.js",
6
6
  "publishConfig": {
@@ -22,12 +22,39 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
22
22
  static get properties() {
23
23
  return {
24
24
  ...super.properties,
25
+ /**
26
+ * can be either 'cancel' or 'perform' (default)
27
+ */
28
+ defaultAction:{
29
+ type: String
30
+ },
31
+ /**
32
+ * delay before executing action in milliseconds
33
+ */
34
+ delay: {
35
+ type: Number,
36
+ },
25
37
  /**
26
38
  * detail - event detail object
27
39
  */
28
40
  detail: {
29
41
  type: Object,
30
42
  },
43
+ /**
44
+ * event to listen for
45
+ */
46
+ event: {
47
+ type: Object,
48
+ },
49
+ handler:{
50
+ type:Object,
51
+ },
52
+ /**
53
+ * boolean XPath expression. If true the action will be executed.
54
+ */
55
+ ifExpr: {
56
+ type: String,
57
+ },
31
58
  /**
32
59
  * wether nor not an action needs to run the update cycle
33
60
  */
@@ -35,21 +62,22 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
35
62
  type: Boolean,
36
63
  },
37
64
  /**
38
- * event to listen for
65
+ * The observer if given is the element on which an event is triggered. It must be an ancestor of the target
66
+ * element of an event.
39
67
  */
40
- event: {
41
- type: Object,
68
+ observer:{
69
+ type:Object,
42
70
  },
43
71
  /**
44
- * id of target element to attach listener to
72
+ * can be either 'stop' or 'continue' (default)
45
73
  */
46
- target: {
74
+ propagate:{
47
75
  type: String,
48
76
  },
49
77
  /**
50
- * boolean XPath expression. If true the action will be executed.
78
+ * id of target element to attach listener to
51
79
  */
52
- ifExpr: {
80
+ target: {
53
81
  type: String,
54
82
  },
55
83
  /**
@@ -59,12 +87,6 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
59
87
  whileExpr: {
60
88
  type: String,
61
89
  },
62
- /**
63
- * delay before executing action in milliseconds
64
- */
65
- delay: {
66
- type: Number,
67
- },
68
90
  };
69
91
  }
70
92
 
@@ -76,6 +98,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
76
98
 
77
99
  connectedCallback() {
78
100
  this.style.display = 'none';
101
+ this.propagate = this.hasAttribute('propagate')? this.getAttribute('propagate'):'continue';
79
102
  this.repeatContext = undefined;
80
103
 
81
104
  if (this.hasAttribute('event')) {
@@ -117,6 +140,11 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
117
140
  * @param e
118
141
  */
119
142
  async execute(e) {
143
+ if(this.propagate === 'stop'){
144
+ console.log('event propagation stopped', e)
145
+ e.stopPropagation();
146
+ }
147
+
120
148
  let resolveThisEvent = () => {};
121
149
  if (e && e.listenerPromises) {
122
150
  e.listenerPromises.push(
@@ -219,8 +247,8 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
219
247
 
220
248
  // After loop is done call actionPerformed to update the model and UI
221
249
  await loop();
222
-
223
250
  this._finalizePerform(resolveThisEvent);
251
+
224
252
  return;
225
253
  }
226
254
 
@@ -237,7 +265,6 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
237
265
 
238
266
  await this.perform();
239
267
  this._finalizePerform(resolveThisEvent);
240
-
241
268
  }
242
269
 
243
270
  _finalizePerform(resolveThisEvent) {
package/src/fore.js CHANGED
@@ -86,6 +86,7 @@ export class Fore {
86
86
  'FX-RANGE',
87
87
  'FX-REPEAT',
88
88
  'FX-REPEATITEM',
89
+ 'FX-REPEAT-ATTRIBUTES',
89
90
  'FX-SWITCH',
90
91
  'FX-SECRET',
91
92
  'FX-SELECT',
package/src/fx-fore.js CHANGED
@@ -5,6 +5,8 @@ import '@jinntec/jinn-toast';
5
5
  import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
6
6
  import getInScopeContext from './getInScopeContext.js';
7
7
  import {XPathUtil} from './xpath-util.js';
8
+ // import {FxRepeat} from "./ui/fx-repeat";
9
+ import {FxRepeatAttributes} from './ui/fx-repeat-attributes.js';
8
10
 
9
11
  /**
10
12
  * Main class for Fore.Outermost container element for each Fore application.
@@ -162,6 +164,7 @@ export class FxFore extends HTMLElement {
162
164
  this.toRefresh = [];
163
165
  this.initialRun = true;
164
166
  this.someInstanceDataStructureChanged = false;
167
+ this.repeatsFromAttributesCreated = false;
165
168
  }
166
169
 
167
170
  connectedCallback() {
@@ -234,6 +237,9 @@ export class FxFore extends HTMLElement {
234
237
  this._handleModelConstructDone();
235
238
  }
236
239
  this.model = modelElement;
240
+
241
+ this._createRepeatsFromAttributes();
242
+
237
243
  });
238
244
  this.addEventListener('path-mutated', () => {
239
245
  // console.log('path-mutated event received', e.detail.path, e.detail.index);
@@ -818,6 +824,56 @@ export class FxFore extends HTMLElement {
818
824
  toast.showToast(msg);
819
825
  }
820
826
  }
827
+
828
+ /**
829
+ * wraps the element having a 'data-ref' attribute with an fx-repeat-attributes element.
830
+ * @private
831
+ */
832
+ _createRepeatsFromAttributes() {
833
+ if(this.repeatsFromAttributesCreated) return;
834
+ const repeats = this.querySelectorAll('[data-ref]');
835
+ if(repeats){
836
+ Array.from(repeats).forEach(item =>{
837
+
838
+ const table = item.parentNode.closest('table');
839
+ let host;
840
+ if(table){
841
+ host = table.cloneNode(true);
842
+ }else{
843
+ host = item.cloneNode(true);
844
+ }
845
+ // ### clone original item to move it into fx-repeat-attributes
846
+ // const host = item.cloneNode(true);
847
+
848
+ // ### create wrapper element
849
+ const repeatFromAttr = new FxRepeatAttributes();
850
+ // const repeatFromAttr = document.createElement('fx-repeat-attributes');
851
+
852
+ // ### copy the value of 'data-ref' to 'ref' on fx-repeat-attributes
853
+ repeatFromAttr.setAttribute('ref',item.getAttribute('data-ref'));
854
+ // item.removeAttribute('data-ref');
855
+
856
+ // ### append the cloned original element to fx-repeat-attributes
857
+ repeatFromAttr.appendChild(host);
858
+
859
+ // ### insert fx-repeat-attributes element before element with the 'data-ref'
860
+ // repeats[0].parentNode.insertBefore(repeatFromAttr,repeats[0]);
861
+
862
+ if(table){
863
+ table.parentNode.insertBefore(repeatFromAttr,table);
864
+ table.parentNode.removeChild(table);
865
+ }else{
866
+ item.parentNode.insertBefore(repeatFromAttr,item);
867
+ item.parentNode.removeChild(item);
868
+ }
869
+
870
+ // ### remove original item from DOM
871
+ item.setAttribute('insertPoint','');
872
+
873
+ });
874
+ }
875
+ this.repeatsFromAttributesCreated = true;
876
+ }
821
877
  }
822
878
 
823
879
  if (!customElements.get('fx-fore')) {
@@ -1,4 +1,4 @@
1
- import {evaluateXPathToFirstNode} from './xpath-evaluation.js';
1
+ import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
2
2
  import {Fore} from './fore.js';
3
3
 
4
4
  import {XPathUtil} from './xpath-util.js';
@@ -79,6 +79,22 @@ export default function getInScopeContext(node, ref) {
79
79
  return repeatItem.nodeset;
80
80
  }
81
81
 
82
+ // ### check for repeatitems created by fx-repeat-attributes - this could possibly be unified with standard repeats
83
+ // const repeatItemFromAttrs = Fore.getClosest('.fx-repeatitem', parentElement);
84
+ // const repeatItemFromAttrs = Fore.getClosest('.fx-repeatitem', parentElement);
85
+ const repeatItemFromAttrs = parentElement.closest('.fx-repeatitem');
86
+
87
+ if (repeatItemFromAttrs) {
88
+ // ### determine correct inscopecontext by determining the index of the repeatitem in its parent list and
89
+ // ### using that as an index on the repeat nodeset
90
+ const parent = repeatItemFromAttrs.parentNode;
91
+ const index = Array.from(parent.children).indexOf(repeatItemFromAttrs);
92
+
93
+ // ### fetching nodeset from fx-repeat-attributes element
94
+ const repeatFromAttributes = Fore.getClosest('fx-repeat-attributes', parentElement);
95
+ return repeatFromAttributes.nodeset[index];
96
+ }
97
+
82
98
  if (parentElement.hasAttribute('context')) {
83
99
  const initialContext = _getInitialContext(parentElement.parentNode, ref);
84
100
  const contextAttr = parentElement.getAttribute('context');
@@ -0,0 +1,442 @@
1
+ import { Fore } from '../fore.js';
2
+ import { evaluateXPath } from '../xpath-evaluation.js';
3
+ import getInScopeContext from '../getInScopeContext.js';
4
+ import { XPathUtil } from '../xpath-util.js';
5
+ import {foreElementMixin} from "../ForeElementMixin.js";
6
+
7
+ /**
8
+ * `fx-repeat`
9
+ *
10
+ * Repeats its template for each node in its' bound nodeset.
11
+ *
12
+ * Template is a standard HTML `<template>` element. Once instanciated the template
13
+ * is moved to the shadowDOM of the repeat for safe re-use.
14
+ *
15
+ *
16
+ *
17
+ * @customElement
18
+ * @demo demo/todo.html
19
+ *
20
+ * todo: it should be seriously be considered to extend FxContainer instead but needs refactoring first.
21
+ */
22
+ export class FxRepeatAttributes extends foreElementMixin(HTMLElement) {
23
+ static get properties() {
24
+ return {
25
+ ...super.properties,
26
+ index: {
27
+ type: Number,
28
+ },
29
+ template: {
30
+ type: Object,
31
+ },
32
+ focusOnCreate: {
33
+ type: String,
34
+ },
35
+ initDone: {
36
+ type: Boolean,
37
+ },
38
+ repeatIndex: {
39
+ type: Number,
40
+ },
41
+ repeatSize:{
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.host= {};
60
+ this.index = 1;
61
+ this.repeatSize = 0;
62
+ this.attachShadow({ mode: 'open', delegatesFocus: true });
63
+ }
64
+
65
+ get repeatSize() {
66
+ return this.querySelectorAll(':scope > .fx-repeatitem').length;
67
+ }
68
+
69
+ set repeatSize(size) {
70
+ super.repeatSize = size;
71
+ }
72
+
73
+
74
+ setIndex(index) {
75
+ // console.log('new repeat index ', index);
76
+ this.index = index;
77
+ const refd = this.querySelector('[data-ref]');
78
+ const rItems = refd.querySelectorAll(':scope > *');
79
+ this.applyIndex(rItems[this.index - 1]);
80
+ }
81
+
82
+ applyIndex(repeatItem) {
83
+ this._removeIndexMarker();
84
+ if (repeatItem) {
85
+ repeatItem.setAttribute('repeat-index', '');
86
+ }
87
+ }
88
+
89
+ get index() {
90
+ return this.getAttribute('index');
91
+ }
92
+
93
+ set index(idx) {
94
+ this.setAttribute('index', idx);
95
+ }
96
+
97
+ _getRepeatedItems(){
98
+ const refd = this.querySelector('[data-ref]');
99
+ return refd.children;
100
+ }
101
+ async connectedCallback() {
102
+ console.log('connectedCallback',this);
103
+ // this.display = window.getComputedStyle(this, null).getPropertyValue("display");
104
+ this.ref = this.getAttribute('ref');
105
+ // this.ref = this._getRef();
106
+ // console.log('### fx-repeat connected ', this.id);
107
+ this.addEventListener('item-changed', e => {
108
+ console.log('handle index event ', e);
109
+ const { item } = e.detail;
110
+ const repeatedItems = this._getRepeatedItems();
111
+ const idx = Array.from(repeatedItems).indexOf(item);
112
+ this.applyIndex(repeatedItems[idx]);
113
+ this.index = idx + 1;
114
+ });
115
+ // todo: review - this is just used by append action - event consolidation ?
116
+ document.addEventListener('index-changed', e => {
117
+ e.stopPropagation();
118
+ if (!e.target === this) return;
119
+ console.log('handle index event ', e);
120
+ // const { item } = e.detail;
121
+ // const idx = Array.from(this.children).indexOf(item);
122
+ const { index } = e.detail;
123
+ this.index = Number(index);
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 path = XPathUtil.getPath(added);
142
+ console.log('path mutated', path);
143
+ // this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
144
+ // this.index = index;
145
+ // const prev = mutations[0].previousSibling.previousElementSibling;
146
+ // const index = prev.index();
147
+ // this.applyIndex(this.index -1);
148
+
149
+ Fore.dispatch(this, 'path-mutated', { path, index: this.index });
150
+ }
151
+ }
152
+ });
153
+ // }
154
+ this.getOwnerForm().registerLazyElement(this);
155
+
156
+ const style = `
157
+ :host{
158
+ }
159
+ .fade-out-bottom {
160
+ -webkit-animation: fade-out-bottom 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
161
+ animation: fade-out-bottom 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
162
+ }
163
+ .fade-out-bottom {
164
+ -webkit-animation: fade-out-bottom 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
165
+ animation: fade-out-bottom 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
166
+ }
167
+ `;
168
+ const html = `
169
+ <slot></slot>
170
+ `;
171
+ this.shadowRoot.innerHTML = `
172
+ <style>
173
+ ${style}
174
+ </style>
175
+ ${html}
176
+ `;
177
+
178
+ // this.init();
179
+ }
180
+
181
+ async init() {
182
+ // ### there must be a single 'template' child
183
+
184
+ const inited = new Promise(resolve => {
185
+ console.log('##### repeat-attributes init ', this.id);
186
+ // if(!this.inited) this.init();
187
+ // does not use this.evalInContext as it is expecting a nodeset instead of single node
188
+ this._evalNodeset();
189
+ // console.log('##### ',this.id, this.nodeset);
190
+
191
+ this._initTemplate();
192
+ // this._initRepeatItems();
193
+
194
+ this.setAttribute('index', this.index);
195
+ this.inited = true;
196
+ resolve('done');
197
+ });
198
+
199
+ return inited;
200
+ }
201
+
202
+ _getRef(){
203
+ return this.getAttribute('ref');
204
+ }
205
+
206
+ /**
207
+ * repeat has no own modelItems
208
+ * @private
209
+ */
210
+ _evalNodeset() {
211
+ // const inscope = this.getInScopeContext();
212
+ const inscope = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
213
+ // console.log('##### inscope ', inscope);
214
+ // console.log('##### ref ', this.ref);
215
+ // now we got a nodeset and attach MutationObserver to it
216
+
217
+ if (this.mutationObserver && inscope.nodeName) {
218
+ this.mutationObserver.observe(inscope, {
219
+ childList: true,
220
+ subtree: true,
221
+ });
222
+ }
223
+
224
+ const rawNodeset = evaluateXPath(this.ref, inscope, this);
225
+ if (rawNodeset.length === 1 && Array.isArray(rawNodeset[0])) {
226
+ // This XPath likely returned an XPath array. Just collapse to that array
227
+ this.nodeset = rawNodeset[0];
228
+ return;
229
+ }
230
+ this.nodeset = rawNodeset;
231
+ }
232
+
233
+ async refresh(force) {
234
+ // console.group('fx-repeat.refresh on', this.id);
235
+
236
+ if (!this.inited) this.init();
237
+ console.time('repeat-refresh', this);
238
+ this._evalNodeset();
239
+ // console.log('repeat refresh nodeset ', this.nodeset);
240
+
241
+ let repeatItems = this.querySelectorAll('.fx-repeatitem');
242
+ let repeatItemCount = repeatItems.length;
243
+
244
+ let nodeCount = 1;
245
+ if (Array.isArray(this.nodeset)) {
246
+ nodeCount = this.nodeset.length;
247
+ }
248
+
249
+ // const contextSize = this.nodeset.length;
250
+ const contextSize = nodeCount;
251
+ // todo: review - cant the context really never be smaller than the repeat count?
252
+ // todo: this code can be deprecated probably but check first
253
+ if (contextSize < repeatItemCount) {
254
+ for (let position = repeatItemCount; position > contextSize; position -= 1) {
255
+ // remove repeatitem
256
+ const itemToRemove = repeatItems[position - 1];
257
+ itemToRemove.parentNode.removeChild(itemToRemove);
258
+ this.getOwnerForm().unRegisterLazyElement(itemToRemove);
259
+ // this._fadeOut(itemToRemove);
260
+ // Fore.fadeOutElement(itemToRemove)
261
+ this.getOwnerForm().someInstanceDataStructureChanged = true;
262
+
263
+ }
264
+ }
265
+
266
+ if (contextSize > repeatItemCount) {
267
+ for (let position = repeatItemCount + 1; position <= contextSize; position += 1) {
268
+ // add new repeatitem
269
+
270
+ const clonedTemplate = this._clone();
271
+
272
+ // ### cloned templates are always appended to the binding element - the one having the data-ref
273
+ const bindingElement = this.querySelector('[data-ref]');
274
+ bindingElement.appendChild(clonedTemplate);
275
+ clonedTemplate.classList.add('fx-repeatitem');
276
+ clonedTemplate.setAttribute('index',position);
277
+
278
+ clonedTemplate.addEventListener('click', this._dispatchIndexChange);
279
+ // this.addEventListener('focusin', this._handleFocus);
280
+ clonedTemplate.addEventListener('focusin', this._dispatchIndexChange);
281
+
282
+
283
+ // this._initVariables(clonedTemplate);
284
+
285
+ // newItem.nodeset = this.nodeset[position - 1];
286
+ // newItem.index = position;
287
+ this.getOwnerForm().someInstanceDataStructureChanged = true;
288
+ }
289
+ }
290
+
291
+ // ### update nodeset of repeatitems
292
+ repeatItems = this.querySelectorAll(':scope > .fx-repeatitem');
293
+ repeatItemCount = repeatItems.length;
294
+
295
+ for (let position = 0; position < repeatItemCount; position += 1) {
296
+ const item = repeatItems[position];
297
+ this.getOwnerForm().registerLazyElement(item);
298
+
299
+ if (item.nodeset !== this.nodeset[position]) {
300
+ item.nodeset = this.nodeset[position];
301
+ }
302
+ }
303
+
304
+ // Fore.refreshChildren(clone,true);
305
+ const fore = this.getOwnerForm();
306
+ if (!fore.lazyRefresh || force) {
307
+ Fore.refreshChildren(this, force);
308
+ }
309
+ // this.style.display = 'block';
310
+ // this.style.display = this.display;
311
+ this.setIndex(this.index);
312
+ console.timeEnd('repeat-refresh');
313
+
314
+ console.groupEnd();
315
+ }
316
+
317
+ _dispatchIndexChange() {
318
+ // console.log('_dispatchIndexChange on index ', this.index);
319
+ this.dispatchEvent(
320
+ new CustomEvent('item-changed', { composed: false, bubbles: true, detail: { item: this , index:this.index } }),
321
+ );
322
+ }
323
+
324
+ // eslint-disable-next-line class-methods-use-this
325
+ _fadeOut(el) {
326
+ el.style.opacity = 1;
327
+
328
+ (function fade() {
329
+ // eslint-disable-next-line no-cond-assign
330
+ if ((el.style.opacity -= 0.1) < 0) {
331
+ el.style.display = 'none';
332
+ } else {
333
+ requestAnimationFrame(fade);
334
+ }
335
+ })();
336
+ }
337
+
338
+ // eslint-disable-next-line class-methods-use-this
339
+ _fadeIn(el) {
340
+ if (!el) return;
341
+
342
+ el.style.opacity = 0;
343
+ el.style.display = this.display;
344
+
345
+ (function fade() {
346
+ // setTimeout(() => {
347
+ let val = parseFloat(el.style.opacity);
348
+ // eslint-disable-next-line no-cond-assign
349
+ if (!((val += 0.1) > 1)) {
350
+ el.style.opacity = val;
351
+ requestAnimationFrame(fade);
352
+ }
353
+ // }, 40);
354
+ })();
355
+ }
356
+
357
+ async _initTemplate() {
358
+ // const shadowTemplate = this.shadowRoot.querySelector('template');
359
+ // console.log('shadowtempl ', shadowTemplate);
360
+
361
+ // const defaultSlot = this.shadowRoot.querySelector('slot');
362
+ // todo: this is still weak - should handle that better maybe by an explicit slot?
363
+ // this.template = this.firstElementChild;
364
+ this.template = this.querySelector('template');
365
+ console.log('### init template for repeat ', this.id, this.template);
366
+
367
+ if (this.template === null) {
368
+ // console.error('### no template found for this repeat:', this.id);
369
+ // todo: catch this on form element
370
+ this.dispatchEvent(
371
+ new CustomEvent('no-template-error', {
372
+ composed: true,
373
+ bubbles: true,
374
+ detail: { message: `no template found for repeat:${this.id}` },
375
+ }),
376
+ );
377
+ }
378
+
379
+ this.shadowRoot.appendChild(this.template);
380
+ }
381
+
382
+ /*
383
+ _initRepeatItems() {
384
+ console.log('_initRepeatItems', this.nodeset);
385
+ // const model = this.getModel();
386
+ // this.textContent = '';
387
+ Array.from(this.nodeset).forEach((item, index) => {
388
+
389
+ const clone = this._clone();
390
+ this.appendChild(clone);
391
+ /!*
392
+ this.appendChild(repeatItem);
393
+
394
+ if (item.index === 1) {
395
+ this.applyIndex(item);
396
+ }
397
+
398
+ this._initVariables(item);
399
+ *!/
400
+ });
401
+ }
402
+ */
403
+
404
+ _initVariables(newRepeatItem) {
405
+ const inScopeVariables = new Map(this.inScopeVariables);
406
+ newRepeatItem.setInScopeVariables(inScopeVariables);
407
+ (function registerVariables(node) {
408
+ for (const child of node.children) {
409
+ if ('setInScopeVariables' in child) {
410
+ child.setInScopeVariables(inScopeVariables);
411
+ }
412
+ registerVariables(child);
413
+ }
414
+ })(newRepeatItem);
415
+ }
416
+
417
+ _clone() {
418
+ // const content = this.template.content.cloneNode(true);
419
+ this.template = this.shadowRoot.querySelector('template');
420
+ // this.template = this.querySelector('template');
421
+ // const content = this.template.content.cloneNode(true);
422
+ // return document.importNode(content, true);
423
+ return this.template.content.firstElementChild.cloneNode(true);
424
+ }
425
+
426
+ _removeIndexMarker() {
427
+ const refd = this.querySelector('[data-ref]');
428
+ Array.from(refd.children).forEach(item => {
429
+ item.removeAttribute('repeat-index');
430
+ });
431
+ }
432
+
433
+ setInScopeVariables(inScopeVariables) {
434
+ // Repeats are interesting: the variables should be scoped per repeat item, they should not be
435
+ // able to see the variables in adjacent repeat items!
436
+ this.inScopeVariables = new Map(inScopeVariables);
437
+ }
438
+ }
439
+
440
+ if (!customElements.get('fx-repeat-attributes')) {
441
+ window.customElements.define('fx-repeat-attributes', FxRepeatAttributes);
442
+ }