@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.
Files changed (53) hide show
  1. package/dist/fore-dev.js +4470 -2643
  2. package/dist/fore.js +4415 -2620
  3. package/index.js +2 -0
  4. package/package.json +10 -4
  5. package/resources/fore.css +2 -6
  6. package/src/DependencyNotifyingDomFacade.js +27 -21
  7. package/src/ForeElementMixin.js +282 -277
  8. package/src/actions/abstract-action.js +7 -12
  9. package/src/actions/fx-append.js +23 -2
  10. package/src/actions/fx-call.js +2 -2
  11. package/src/actions/fx-delete.js +54 -29
  12. package/src/actions/fx-insert.js +23 -15
  13. package/src/actions/fx-refresh.js +15 -5
  14. package/src/actions/fx-replace.js +18 -3
  15. package/src/actions/fx-reset.js +6 -0
  16. package/src/actions/fx-send.js +10 -7
  17. package/src/actions/fx-setattribute.js +12 -0
  18. package/src/actions/fx-setfocus.js +11 -8
  19. package/src/actions/fx-setvalue.js +93 -93
  20. package/src/actions/fx-toggle.js +1 -1
  21. package/src/extract-predicate-deps.js +57 -0
  22. package/src/extractPredicateDependencies.js +36 -0
  23. package/src/fore.js +41 -16
  24. package/src/fx-bind.js +128 -23
  25. package/src/fx-connection.js +24 -7
  26. package/src/fx-fore.js +506 -259
  27. package/src/fx-instance.js +9 -11
  28. package/src/fx-model.js +154 -65
  29. package/src/fx-submission.js +19 -30
  30. package/src/fx-var.js +5 -0
  31. package/src/getInScopeContext.js +7 -8
  32. package/src/modelitem.js +247 -112
  33. package/src/tools/fx-action-log.js +21 -19
  34. package/src/tools/fx-log-settings.js +4 -2
  35. package/src/ui/TemplateExpression.js +12 -0
  36. package/src/ui/UIElement.js +125 -10
  37. package/src/ui/abstract-control.js +5 -0
  38. package/src/ui/fx-case.js +15 -3
  39. package/src/ui/fx-container.js +5 -0
  40. package/src/ui/fx-control-menu.js +23 -14
  41. package/src/ui/fx-control.js +55 -15
  42. package/src/ui/fx-items.js +10 -4
  43. package/src/ui/fx-repeat-attributes.js +111 -35
  44. package/src/ui/fx-repeat.js +332 -85
  45. package/src/ui/fx-repeat.updated.js +821 -0
  46. package/src/ui/fx-repeatitem.js +23 -20
  47. package/src/ui/fx-switch.js +5 -3
  48. package/src/ui/fx-upload.js +36 -40
  49. package/src/ui/repeat-base.js +532 -0
  50. package/src/withDraggability.js +8 -4
  51. package/src/xpath-evaluation.js +26 -8
  52. package/src/xpath-path.js +79 -0
  53. package/src/xpath-util.js +357 -289
@@ -2,8 +2,9 @@ import { Fore } from '../fore.js';
2
2
  import { evaluateXPath } from '../xpath-evaluation.js';
3
3
  import getInScopeContext from '../getInScopeContext.js';
4
4
  import { XPathUtil } from '../xpath-util.js';
5
- import ForeElementMixin from '../ForeElementMixin.js';
6
5
  import { withDraggability } from '../withDraggability.js';
6
+ import { getPath } from '../xpath-path.js';
7
+ import { RepeatBase } from './repeat-base.js';
7
8
 
8
9
  /**
9
10
  * `fx-repeat`
@@ -20,7 +21,7 @@ import { withDraggability } from '../withDraggability.js';
20
21
  *
21
22
  * todo: it should be seriously be considered to extend FxContainer instead but needs refactoring first.
22
23
  */
23
- export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false) {
24
+ export class FxRepeatAttributes extends withDraggability(RepeatBase, false) {
24
25
  static get properties() {
25
26
  return {
26
27
  ...super.properties,
@@ -62,8 +63,23 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
62
63
  this.index = 1;
63
64
  this.repeatSize = 0;
64
65
  this.attachShadow({ mode: 'open', delegatesFocus: true });
66
+ /**
67
+ * @type {Map<Element, Node>} A lookup from a repeat item to the node it has associated
68
+ */
69
+ this._contextItemByRepeatItem = new Map();
65
70
  }
66
71
 
72
+ /**
73
+ * Get the context node for the given repeat item
74
+ *
75
+ * @param {Element} repeatItem
76
+ * @returns {Node} The node (if any) that is the active item for this repeat item
77
+ */
78
+ getContextForRepeatItem(repeatItem) {
79
+ return this._contextItemByRepeatItem.get(repeatItem);
80
+ }
81
+
82
+ /*
67
83
  get repeatSize() {
68
84
  return this.querySelectorAll(':scope > .fx-repeatitem').length;
69
85
  }
@@ -71,22 +87,66 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
71
87
  set repeatSize(size) {
72
88
  super.repeatSize = size;
73
89
  }
90
+ */
91
+
92
+ async init() {
93
+ // ### there must be a single 'template' child
94
+
95
+ const inited = new Promise(resolve => {
96
+ // console.log('##### repeat-attributes init ', this.id);
97
+ // if(!this.inited) this.init();
98
+ // does not use this.evalInContext as it is expecting a nodeset instead of single node
99
+ this._evalNodeset();
100
+ // console.log('##### ',this.id, this.nodeset);
101
+
102
+ this._initTemplate();
103
+ // this._initRepeatItems();
104
+
105
+ this.setAttribute('index', this.index);
106
+ this.inited = true;
107
+ resolve('done');
108
+ });
109
+
110
+ return inited;
111
+ }
112
+
113
+ _deleteHandler(deleted) {
114
+ super._deleteHandler(deleted);
115
+ const refd = this.querySelector('[data-ref]');
116
+ const rItems = refd ? refd.querySelectorAll(':scope > .fx-repeatitem') : [];
117
+
118
+ for (let i = 0; i < Math.min(this.nodeset.length, rItems.length); ++i) {
119
+ this._contextItemByRepeatItem.set(rItems[i], this.nodeset[i]);
120
+ }
121
+ }
74
122
 
75
123
  setIndex(index) {
76
- // console.log('new repeat index ', index);
77
- this.index = index;
78
124
  const refd = this.querySelector('[data-ref]');
79
- const rItems = refd.querySelectorAll(':scope > *');
80
- this.applyIndex(rItems[this.index - 1]);
125
+ const rItems = refd ? refd.querySelectorAll(':scope > .fx-repeatitem') : [];
126
+ const size = rItems.length;
127
+
128
+ const clamped = size === 0 ? 0 : Math.max(1, Math.min(index, size));
129
+ this.index = clamped;
130
+
131
+ if (size > 0) {
132
+ this.applyIndex(rItems[this.index - 1]);
133
+ } else {
134
+ this._removeIndexMarker(); // nothing selected
135
+ }
136
+
137
+ this.setAttribute('index', String(this.index));
81
138
  }
82
139
 
140
+ /*
83
141
  applyIndex(repeatItem) {
84
142
  this._removeIndexMarker();
85
143
  if (repeatItem) {
86
144
  repeatItem.setAttribute('repeat-index', '');
87
145
  }
88
146
  }
147
+ */
89
148
 
149
+ /*
90
150
  get index() {
91
151
  return parseInt(this.getAttribute('index'), 10);
92
152
  }
@@ -94,6 +154,7 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
94
154
  set index(idx) {
95
155
  this.setAttribute('index', idx);
96
156
  }
157
+ */
97
158
 
98
159
  _getRepeatedItems() {
99
160
  const refd = this.querySelector('[data-ref]');
@@ -101,6 +162,7 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
101
162
  }
102
163
 
103
164
  async connectedCallback() {
165
+ super.connectedCallback();
104
166
  // console.log('connectedCallback',this);
105
167
  // this.display = window.getComputedStyle(this, null).getPropertyValue("display");
106
168
  this.ref = this.getAttribute('ref');
@@ -111,7 +173,8 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
111
173
  const { item } = e.detail;
112
174
  const repeatedItems = this._getRepeatedItems();
113
175
  const idx = Array.from(repeatedItems).indexOf(item);
114
- this.applyIndex(repeatedItems[idx]);
176
+ this.setIndex(idx + 1);
177
+ // this.applyIndex(repeatedItems[idx]);
115
178
  this.index = idx + 1;
116
179
  });
117
180
  // todo: review - this is just used by append action - event consolidation ?
@@ -120,15 +183,7 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
120
183
  if (!e.target === this) return;
121
184
  const { index } = e.detail;
122
185
  this.index = Number(index);
123
- this.applyIndex(this.children[index - 1]);
124
- });
125
- /*
126
- document.addEventListener('insert', e => {
127
- const nodes = e.detail.insertedNodes;
128
- this.index = e.detail.position;
129
- console.log('insert catched', nodes, this.index);
130
186
  });
131
- */
132
187
 
133
188
  // if (this.getOwnerForm().lazyRefresh) {
134
189
  this.mutationObserver = new MutationObserver(mutations => {
@@ -136,7 +191,7 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
136
191
  const added = mutations[0].addedNodes[0];
137
192
  if (added) {
138
193
  const instance = XPathUtil.resolveInstance(this, this.ref);
139
- const path = XPathUtil.getPath(added, instance);
194
+ const path = getPath(added, instance);
140
195
  // this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
141
196
  // this.index = index;
142
197
  // const prev = mutations[0].previousSibling.previousElementSibling;
@@ -196,6 +251,10 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
196
251
  return inited;
197
252
  }
198
253
 
254
+ getRepeatItems() {
255
+ return Array.from(this.querySelectorAll(':scope [data-ref] > .fx-repeatitem'));
256
+ }
257
+
199
258
  _getRef() {
200
259
  return this.getAttribute('ref');
201
260
  }
@@ -248,6 +307,7 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
248
307
  // remove repeatitem
249
308
  const itemToRemove = repeatItems[position - 1];
250
309
  itemToRemove.parentNode.removeChild(itemToRemove);
310
+ this._contextItemByRepeatItem.delete(itemToRemove);
251
311
  this.getOwnerForm().unRegisterLazyElement(itemToRemove);
252
312
  // this._fadeOut(itemToRemove);
253
313
  // Fore.fadeOutElement(itemToRemove)
@@ -259,29 +319,15 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
259
319
  for (let position = repeatItemCount + 1; position <= contextSize; position += 1) {
260
320
  // add new repeatitem
261
321
 
262
- const clonedTemplate = this._clone();
322
+ const clonedTemplate = this._createNewRepeatItem(position, this.nodeset[position - 1]);
263
323
  if (!clonedTemplate) return;
264
324
 
265
- // ### cloned templates are always appended to the binding element - the one having the data-ref
266
- const bindingElement = this.querySelector('[data-ref]');
267
- bindingElement.appendChild(clonedTemplate);
268
- clonedTemplate.classList.add('fx-repeatitem');
269
- clonedTemplate.setAttribute('index', position);
270
-
271
- clonedTemplate.addEventListener('click', this._dispatchIndexChange);
272
- // this.addEventListener('focusin', this._handleFocus);
273
- clonedTemplate.addEventListener('focusin', this._dispatchIndexChange);
274
-
275
- // this._initVariables(clonedTemplate);
276
-
277
- // newItem.nodeset = this.nodeset[position - 1];
278
- // newItem.index = position;
279
325
  this.getOwnerForm().someInstanceDataStructureChanged = true;
280
326
  }
281
327
  }
282
328
 
283
329
  // ### update nodeset of repeatitems
284
- repeatItems = this.querySelectorAll(':scope > .fx-repeatitem');
330
+ repeatItems = this.querySelectorAll('.fx-repeatitem');
285
331
  repeatItemCount = repeatItems.length;
286
332
 
287
333
  for (let position = 0; position < repeatItemCount; position += 1) {
@@ -291,6 +337,8 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
291
337
  if (item.nodeset !== this.nodeset[position]) {
292
338
  item.nodeset = this.nodeset[position];
293
339
  }
340
+
341
+ this._contextItemByRepeatItem.set(item, this.nodeset[position]);
294
342
  }
295
343
 
296
344
  // Fore.refreshChildren(clone,true);
@@ -385,10 +433,38 @@ export class FxRepeatAttributes extends withDraggability(ForeElementMixin, false
385
433
  })(newRepeatItem);
386
434
  }
387
435
 
388
- _clone() {
436
+ /**
437
+ * @override
438
+ *
439
+ * @param {number} insertionIndex - the one-based index of where to insert the new node
440
+ * @param {Node} node - The node related to this new repeat item
441
+ *
442
+ * @returns {HTMLElement}
443
+ */
444
+ _createNewRepeatItem(insertionIndex, node) {
389
445
  this.template = this.shadowRoot.querySelector('template');
390
- if (!this.template) return;
391
- return this.template.content.firstElementChild.cloneNode(true);
446
+ if (!this.template) return null;
447
+ const newNode = /** @type {HTMLElement} */ (
448
+ this.template.content.firstElementChild.cloneNode(true)
449
+ );
450
+
451
+ // ### cloned templates are always appended to the binding element - the one having the data-ref
452
+ const bindingElement = this.querySelector('[data-ref]');
453
+
454
+ const repeatItems = bindingElement.querySelectorAll('.fx-repeatitem');
455
+
456
+ const beforeNode = repeatItems[insertionIndex - 1] ?? null; // Null appends by default
457
+ bindingElement.insertBefore(newNode, beforeNode);
458
+ newNode.classList.add('fx-repeatitem');
459
+ // newNode.setAttribute('index', `${insertionIndex}`);
460
+
461
+ newNode.addEventListener('click', this._dispatchIndexChange);
462
+ // this.addEventListener('focusin', this._handleFocus);
463
+ newNode.addEventListener('focusin', this._dispatchIndexChange);
464
+
465
+ this._contextItemByRepeatItem.set(newNode, node);
466
+
467
+ return newNode;
392
468
  }
393
469
 
394
470
  _removeIndexMarker() {