@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/dist/fore-dev.js +8 -8
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +7 -7
- package/dist/fore.js.map +1 -1
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/actions/abstract-action.js +42 -15
- package/src/fore.js +1 -0
- package/src/fx-fore.js +56 -0
- package/src/getInScopeContext.js +17 -1
- package/src/ui/fx-repeat-attributes.js +442 -0
- package/src/ui/fx-repeat.js +8 -0
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
|
@@ -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
|
|
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
|
-
|
|
41
|
-
type:
|
|
68
|
+
observer:{
|
|
69
|
+
type:Object,
|
|
42
70
|
},
|
|
43
71
|
/**
|
|
44
|
-
*
|
|
72
|
+
* can be either 'stop' or 'continue' (default)
|
|
45
73
|
*/
|
|
46
|
-
|
|
74
|
+
propagate:{
|
|
47
75
|
type: String,
|
|
48
76
|
},
|
|
49
77
|
/**
|
|
50
|
-
*
|
|
78
|
+
* id of target element to attach listener to
|
|
51
79
|
*/
|
|
52
|
-
|
|
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
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')) {
|
package/src/getInScopeContext.js
CHANGED
|
@@ -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
|
+
}
|