@plcmp/pl-virtual-scroll 0.1.13 → 1.0.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/package.json +2 -2
- package/pl-virtual-scroll.js +203 -115
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plcmp/pl-virtual-scroll",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Component for lazy list render.",
|
|
5
5
|
"main": "pl-virtual-scroll.js",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
}
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"polylib": "^1.1.
|
|
26
|
+
"polylib": "^1.1.12",
|
|
27
27
|
"@plcmp/utils": "^0.1.0"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/pl-virtual-scroll.js
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
|
-
import { html, PlElement, TemplateInstance } from
|
|
2
|
-
import { PlaceHolder } from
|
|
3
|
-
import {ContextMixin} from
|
|
4
|
-
import {normalizePath} from
|
|
1
|
+
import { html, PlElement, TemplateInstance } from 'polylib';
|
|
2
|
+
import { PlaceHolder } from '@plcmp/utils';
|
|
3
|
+
import { ContextMixin } from 'polylib/engine/v1/ctx.js';
|
|
4
|
+
import { normalizePath } from 'polylib/common.js';
|
|
5
5
|
|
|
6
6
|
/** @typedef VirtualScrollItem
|
|
7
|
-
* @property {
|
|
8
|
-
* @property {TemplateInstance} ti
|
|
9
|
-
* @property {
|
|
10
|
-
* @property {
|
|
7
|
+
* @property { RepeatItem } ctx
|
|
8
|
+
* @property { TemplateInstance } ti
|
|
9
|
+
* @property { number | null } index
|
|
10
|
+
* @property { number } h - height of rendered item
|
|
11
|
+
* @property { number } offset
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
class PlVirtualScroll extends PlElement {
|
|
14
|
-
/** @type VirtualScrollItem[]*/
|
|
15
|
+
/** @type VirtualScrollItem[] */
|
|
15
16
|
phyPool = [];
|
|
17
|
+
/** @type {number | undefined} */
|
|
18
|
+
elementHeight;
|
|
19
|
+
|
|
16
20
|
constructor() {
|
|
17
21
|
super({ lightDom: true });
|
|
18
22
|
}
|
|
23
|
+
|
|
19
24
|
static properties = {
|
|
20
25
|
as: { value: 'item' },
|
|
21
26
|
items: { type: Array, observer: '_dataChanged' },
|
|
22
|
-
renderedStart: { type: Number, value: 0 },
|
|
23
|
-
renderedCount: { type: Number, value: 0 },
|
|
24
27
|
phyItems: { type: Array, value: () => [] },
|
|
25
28
|
canvas: { type: Object },
|
|
26
|
-
|
|
29
|
+
variableRowHeight: { type: Boolean, value: false },
|
|
30
|
+
rowHeight: { type: Number }
|
|
31
|
+
};
|
|
32
|
+
|
|
27
33
|
static template = html`
|
|
28
34
|
<style>
|
|
29
35
|
pl-virtual-scroll {
|
|
@@ -50,37 +56,32 @@ class PlVirtualScroll extends PlElement {
|
|
|
50
56
|
</style>
|
|
51
57
|
<div id="vsCanvas"></div>
|
|
52
58
|
`;
|
|
59
|
+
|
|
53
60
|
static repTpl = html`<template d:repeat="{{phyItems}}" d:as="[[as]]"><div class="vs-item">[[sTpl]]</div></template>`;
|
|
61
|
+
|
|
54
62
|
connectedCallback() {
|
|
55
63
|
super.connectedCallback();
|
|
56
64
|
|
|
57
65
|
this.canvas = this.canvas ?? this.$.vsCanvas;
|
|
58
|
-
this.canvas.parentNode.addEventListener('scroll', e => this.onScroll(e)
|
|
59
|
-
let tplEl = [...this.childNodes].find(
|
|
66
|
+
this.canvas.parentNode.addEventListener('scroll', e => this.onScroll(e));
|
|
67
|
+
let tplEl = [...this.childNodes].find(n => n.nodeType === document.COMMENT_NODE && n.textContent.startsWith('tpl:'));
|
|
60
68
|
this.sTpl = tplEl?._tpl;
|
|
61
69
|
this._hctx = tplEl?._hctx;
|
|
62
|
-
|
|
63
|
-
/* let ti = new TemplateInstance(PlVirtualScroll.repTpl);
|
|
64
|
-
ti.attach(canvas, this, this);
|
|
65
|
-
*/
|
|
66
|
-
/* render items if them already assigned */
|
|
67
|
-
/*if (Array.isArray(this.items) && this.items.length > 0) {
|
|
68
|
-
this.render();
|
|
69
|
-
}*/
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
_dataChanged(data, old, /** DataMutation */ mutation) {
|
|
72
73
|
// set microtask, element may be not inserted in dom tree yet,
|
|
73
74
|
// but we need to know viewport height to render
|
|
74
75
|
let [, index, ...rest] = normalizePath(mutation.path);
|
|
75
76
|
switch (mutation.action) {
|
|
76
77
|
case 'upd':
|
|
77
|
-
if(mutation.path
|
|
78
|
-
this.phyPool.forEach(i => {
|
|
78
|
+
if (mutation.path === 'items' && Array.isArray(mutation.value) && Array.isArray(mutation.oldValue)) {
|
|
79
|
+
this.phyPool.forEach((i) => {
|
|
79
80
|
if (i.index !== null && i.index < this.items.length) {
|
|
80
81
|
if (this.items[i.index] instanceof PlaceHolder) this.items.load?.(this.items[i.index]);
|
|
81
82
|
|
|
82
83
|
i.ctx.replace(this.items[i.index]);
|
|
83
|
-
i.ctx.applyEffects();
|
|
84
|
+
i.ctx.applyEffects(undefined);
|
|
84
85
|
i.ctx._ti.applyBinds();
|
|
85
86
|
} else if (i.index >= this.items.length) {
|
|
86
87
|
i.index = null;
|
|
@@ -93,119 +94,187 @@ class PlVirtualScroll extends PlElement {
|
|
|
93
94
|
if (el && rest.length > 0) {
|
|
94
95
|
let path = [this.as, ...rest].join('.');
|
|
95
96
|
el.ctx.applyEffects({ ...mutation, path });
|
|
96
|
-
if (this.items[el.index] instanceof PlaceHolder) this.items.load?.(this.items[el.index])
|
|
97
|
+
if (this.items[el.index] instanceof PlaceHolder) this.items.load?.(this.items[el.index]);
|
|
97
98
|
}
|
|
98
99
|
} else {
|
|
99
100
|
setTimeout(() => this.render(), 0);
|
|
100
101
|
}
|
|
101
102
|
break;
|
|
102
|
-
case 'splice':
|
|
103
|
+
case 'splice': {
|
|
103
104
|
let { index: spliceIndex } = mutation;
|
|
104
|
-
// if mutation is not root try to apply effects to
|
|
105
|
-
if(rest.length > 0) {
|
|
105
|
+
// if mutation is not root try to apply effects to children (need when pushing to array inside array)
|
|
106
|
+
if (rest.length > 0) {
|
|
106
107
|
let path = [this.as, ...rest].join('.');
|
|
107
108
|
this.phyPool[index].ctx.applyEffects({ ...mutation, path });
|
|
108
109
|
} else {
|
|
109
|
-
this.phyPool.forEach(i => {
|
|
110
|
+
this.phyPool.forEach((i) => {
|
|
110
111
|
if (i.index !== null && i.index >= spliceIndex && i.index < this.items.length) {
|
|
111
112
|
if (this.items[i.index] instanceof PlaceHolder) this.items.load?.(this.items[i.index]);
|
|
112
|
-
|
|
113
|
+
|
|
113
114
|
i.ctx.replace(this.items[i.index]);
|
|
114
|
-
i.ctx.applyEffects();
|
|
115
|
+
i.ctx.applyEffects(undefined);
|
|
115
116
|
i.ctx._ti.applyBinds();
|
|
116
117
|
} else if (i.index >= this.items.length) {
|
|
117
118
|
i.index = null;
|
|
119
|
+
i.offset = -10000;
|
|
120
|
+
fixOffset(i);
|
|
118
121
|
}
|
|
119
122
|
});
|
|
120
123
|
}
|
|
121
124
|
|
|
122
|
-
//TODO: add more Heuristic to scroll list if visible elements that not changed? like insert rows before
|
|
125
|
+
// TODO: add more Heuristic to scroll list if visible elements that not changed? like insert rows before
|
|
123
126
|
// visible area
|
|
124
127
|
|
|
125
|
-
//refresh all PHY if they can be affected
|
|
126
|
-
|
|
128
|
+
// refresh all PHY if they can be affected
|
|
127
129
|
setTimeout(() => this.render(), 0);
|
|
128
130
|
|
|
129
131
|
break;
|
|
132
|
+
}
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
/*let first = Math.floor(offset / this.elementHeight);
|
|
148
|
-
let last = Math.ceil((offset+height) / this.elementHeight);*/
|
|
149
|
-
// Reset scroll position if update data smaller than current visible index
|
|
150
|
-
if (!scroll && this.items.length < (offset + height * 1.5) / this.elementHeight) {
|
|
151
|
-
canvas.parentNode.scrollTop = 0;
|
|
136
|
+
render() {
|
|
137
|
+
const canvas = this.canvas;
|
|
138
|
+
let visibleStart = canvas.parentNode.scrollTop,
|
|
139
|
+
height = canvas.parentNode.offsetHeight,
|
|
140
|
+
visibleEnd = visibleStart + height,
|
|
141
|
+
// render cant complete on too small window, set minimal shadow window
|
|
142
|
+
shadowSize = Math.max(height / 2, 500),
|
|
143
|
+
shadowStart = visibleStart - shadowSize,
|
|
144
|
+
shadowEnd = visibleEnd + shadowSize;
|
|
145
|
+
|
|
146
|
+
// cancel render on invisible canvas or empty data
|
|
147
|
+
if (height === 0 || !this.items || this.items.length === 0) {
|
|
148
|
+
canvas.style.setProperty('height', 0);
|
|
149
|
+
return;
|
|
152
150
|
}
|
|
153
|
-
let shadowEnd = Math.min(this.items.length, Math.ceil((offset + height * 1.5) / this.elementHeight));
|
|
154
|
-
let shadowBegin = Math.max(0, Math.floor(Math.min((offset - height / 2) / this.elementHeight, shadowEnd - height * 2 / this.elementHeight)));
|
|
155
|
-
|
|
156
|
-
let used = [], unused = [];
|
|
157
|
-
this.phyPool.forEach(x => {
|
|
158
|
-
if (x.index !== null && shadowBegin <= x.index && x.index <= shadowEnd && x.index < this.items.length) {
|
|
159
|
-
used.push(x);
|
|
160
|
-
} else {
|
|
161
|
-
unused.push(x);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
151
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
let lastUsedIndex = prev.index;
|
|
170
|
-
for (let i = lastUsedIndex + 1; i <= Math.min(shadowEnd, this.items.length - 1); i++) {
|
|
171
|
-
prev = this.renderItem(i, unused.pop(), prev);
|
|
152
|
+
let used = this.phyPool
|
|
153
|
+
.filter((i) => {
|
|
154
|
+
if (i.offset + i.h < shadowStart || i.offset > shadowEnd) {
|
|
155
|
+
i.index = null;
|
|
172
156
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
157
|
+
return i.index !== null;
|
|
158
|
+
})
|
|
159
|
+
.sort((a, b) => a.index - b.index);
|
|
160
|
+
|
|
161
|
+
// check items height and offset
|
|
162
|
+
if (this.variableRowHeight) {
|
|
163
|
+
let firstVisible = used.findIndex(i => i.offset >= visibleStart && i.offset < visibleEnd);
|
|
164
|
+
if (firstVisible >= 0) {
|
|
165
|
+
// fix forward
|
|
166
|
+
for (let i = firstVisible + 1; i < used.length && used[i].offset < shadowEnd; i++) {
|
|
167
|
+
const newHeight = calcNodesRect(used[i - 1].ctx._ti._nodes).height;
|
|
168
|
+
if (used[i - 1].h !== newHeight) used[i - 1].h = newHeight;
|
|
169
|
+
if (used[i - 1].offset + newHeight !== used[i].offset) {
|
|
170
|
+
used[i].offset = used[i - 1].offset + newHeight;
|
|
171
|
+
fixOffset(used[i]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// fix last height
|
|
175
|
+
const last = used[used.length - 1];
|
|
176
|
+
last.h = calcNodesRect(last.ctx._ti._nodes).height;
|
|
177
|
+
// fix backward
|
|
178
|
+
for (let i = firstVisible - 1; i >= 0 && used[i].offset > shadowStart; i--) {
|
|
179
|
+
const newHeight = calcNodesRect(used[i].ctx._ti._nodes).height;
|
|
180
|
+
if (used[i].h !== newHeight) used[i].h = newHeight;
|
|
181
|
+
if (used[i].offset + newHeight !== used[i + 1].offset) {
|
|
182
|
+
used[i].offset = used[i + 1].offset - newHeight;
|
|
183
|
+
fixOffset(used[i]);
|
|
184
|
+
}
|
|
179
185
|
}
|
|
186
|
+
used = used
|
|
187
|
+
.filter((i) => {
|
|
188
|
+
if (i.offset + i.h < shadowStart || i.offset > shadowEnd) {
|
|
189
|
+
i.index = null;
|
|
190
|
+
}
|
|
191
|
+
return i.index !== null;
|
|
192
|
+
})
|
|
193
|
+
.sort((a, b) => a.index - b.index);
|
|
180
194
|
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
195
|
+
}
|
|
196
|
+
// filter
|
|
197
|
+
|
|
198
|
+
let unused = this.phyPool.filter(i => i.index === null);
|
|
199
|
+
|
|
200
|
+
let firstShadow = used.find(i => i.offset + i.h > shadowStart && i.offset < shadowEnd);
|
|
201
|
+
let lastShadow = used.findLast(i => i.offset < shadowEnd && i.offset + i.h > shadowStart);
|
|
202
|
+
|
|
203
|
+
if (!firstShadow && !lastShadow) {
|
|
204
|
+
// jump to nowhere,
|
|
205
|
+
if (this.canvas.parentNode.scrollTop === 0)
|
|
206
|
+
firstShadow = lastShadow = this.renderItem(0, unused.pop());
|
|
207
|
+
else {
|
|
208
|
+
const heightForStart
|
|
209
|
+
= this.phyPool.length > 0
|
|
210
|
+
? this.phyPool.reduce((a, i) => a + i.h, 0) / this.phyPool.length
|
|
211
|
+
: 32; // TODO: replace w/o constant
|
|
212
|
+
const predictedStart = Math.min(Math.ceil(this.canvas.parentNode.scrollTop / heightForStart), this.items.length - 1);
|
|
213
|
+
firstShadow = lastShadow = this.renderItem(predictedStart, unused.pop(), this.canvas.parentNode.scrollTop);
|
|
185
214
|
}
|
|
186
215
|
}
|
|
187
216
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
217
|
+
// render forward
|
|
218
|
+
while (
|
|
219
|
+
lastShadow.offset + lastShadow.h < shadowEnd // последний нарисованный не дотягивает до конца окна рисования
|
|
220
|
+
&& lastShadow.index < this.items.length - 1 // при этом данные еще не кончились
|
|
221
|
+
) {
|
|
222
|
+
lastShadow = this.renderItem(lastShadow ? lastShadow.index + 1 : 0, unused.pop(), lastShadow);
|
|
223
|
+
used.push(lastShadow);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// render backward
|
|
227
|
+
while (
|
|
228
|
+
firstShadow.offset > shadowStart // последний нарисованный не дотягивает до конца окна рисования
|
|
229
|
+
&& firstShadow.index > 0 // при этом данные еще не кончились
|
|
230
|
+
) {
|
|
231
|
+
firstShadow = this.renderItem(firstShadow.index - 1, unused.pop(), firstShadow, true);
|
|
232
|
+
used.unshift(firstShadow);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// move unused to invisible place
|
|
236
|
+
unused.forEach((i) => {
|
|
237
|
+
i.offset = -10000;
|
|
238
|
+
fixOffset(i);
|
|
191
239
|
});
|
|
192
240
|
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
|
|
241
|
+
// calc offset and canvas size
|
|
242
|
+
// TODO: reduce scroll jump
|
|
243
|
+
const avgHeight = used.reduce((a, i) => a + i.h, 0) / used.length;
|
|
244
|
+
|
|
245
|
+
if (lastShadow && !isNaN(avgHeight) && isFinite(avgHeight)) {
|
|
246
|
+
const
|
|
247
|
+
lastRenderedPixel = lastShadow.offset + lastShadow.h,
|
|
248
|
+
restRows = this.items.length - lastShadow.index - 1,
|
|
249
|
+
currentHeight = canvas.offsetHeight,
|
|
250
|
+
predictedHeight = lastRenderedPixel + restRows * avgHeight;
|
|
251
|
+
|
|
252
|
+
if (Math.abs(predictedHeight - currentHeight) > restRows / 10 * avgHeight) {
|
|
253
|
+
canvas.style.setProperty('height', predictedHeight + 'px');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
196
256
|
|
|
257
|
+
if (firstShadow && !isNaN(avgHeight) && isFinite(avgHeight)) {
|
|
258
|
+
const
|
|
259
|
+
firstRenderedPixel = firstShadow.offset,
|
|
260
|
+
restRows = firstShadow.index,
|
|
261
|
+
predictedOffset = firstRenderedPixel - restRows * avgHeight;
|
|
197
262
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
263
|
+
if (Math.abs(predictedOffset) > restRows / 10 * avgHeight) {
|
|
264
|
+
used.forEach((i) => {
|
|
265
|
+
i.offset -= predictedOffset;
|
|
266
|
+
fixOffset(i);
|
|
267
|
+
});
|
|
268
|
+
this.canvas.parentNode.scrollTop -= predictedOffset;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
202
271
|
}
|
|
203
272
|
|
|
204
273
|
/**
|
|
205
274
|
*
|
|
206
275
|
* @param index
|
|
207
276
|
* @param {VirtualScrollItem} p_item
|
|
208
|
-
* @param prev
|
|
277
|
+
* @param [prev]
|
|
209
278
|
* @param [backward]
|
|
210
279
|
* @return {VirtualScrollItem}
|
|
211
280
|
*/
|
|
@@ -216,52 +285,59 @@ class PlVirtualScroll extends PlElement {
|
|
|
216
285
|
if (p_item) p_item.index = null;
|
|
217
286
|
return p_item;
|
|
218
287
|
}
|
|
219
|
-
if (this.items[index] instanceof PlaceHolder) this.items.load?.(this.items[index])
|
|
288
|
+
if (this.items[index] instanceof PlaceHolder) this.items.load?.(this.items[index]);
|
|
220
289
|
let target = p_item ?? this.createNewItem(this.items[index]);
|
|
221
290
|
|
|
222
291
|
target.index = index;
|
|
223
292
|
if (p_item) {
|
|
224
|
-
p_item.ctx.replace(this.items[index])
|
|
293
|
+
p_item.ctx.replace(this.items[index]);
|
|
225
294
|
p_item.ctx._ti.applyBinds();
|
|
226
|
-
p_item.ctx.applyEffects();
|
|
295
|
+
p_item.ctx.applyEffects(undefined);
|
|
296
|
+
if (!this.variableRowHeight) p_item.h = calcNodesRect(p_item.ctx._ti._nodes).height;
|
|
227
297
|
} else {
|
|
228
298
|
this.phyPool.push(target);
|
|
229
299
|
}
|
|
300
|
+
prev ??= 0;
|
|
230
301
|
target.offset = typeof (prev) == 'number' ? prev : (backward ? prev.offset - target.h : prev.offset + prev.h);
|
|
231
|
-
target.ctx._ti._nodes.forEach(n => {
|
|
302
|
+
target.ctx._ti._nodes.forEach((n) => {
|
|
232
303
|
if (n.style) {
|
|
233
304
|
n.style.transform = `translateY(${target.offset}px)`;
|
|
234
305
|
n.style.position = 'absolute';
|
|
235
|
-
n.setAttribute('virtualOffser', target.offset);
|
|
236
306
|
}
|
|
237
307
|
});
|
|
238
308
|
return target;
|
|
239
309
|
}
|
|
310
|
+
|
|
240
311
|
createNewItem(v) {
|
|
241
312
|
if (!this.sTpl) return;
|
|
242
313
|
let inst = new TemplateInstance(this.sTpl);
|
|
243
314
|
|
|
244
|
-
let ctx = new RepeatItem(v, this.as, (ctx, m) => this.onItemChanged(ctx, m)
|
|
245
|
-
ctx._ti = inst
|
|
246
|
-
inst.attach(this.canvas, undefined, [ctx, ...this._hctx
|
|
247
|
-
let h = this.elementHeight
|
|
315
|
+
let ctx = new RepeatItem(v, this.as, (ctx, m) => this.onItemChanged(ctx, m));
|
|
316
|
+
ctx._ti = inst;
|
|
317
|
+
inst.attach(this.canvas, undefined, [ctx, ...this._hctx]);
|
|
318
|
+
let h = !this.variableRowHeight && this.elementHeight ? this.elementHeight : calcNodesRect(inst._nodes).height;
|
|
319
|
+
|
|
320
|
+
if (!this.variableRowHeight && !this.elementHeight) {
|
|
321
|
+
this.elementHeight = h;
|
|
322
|
+
}
|
|
248
323
|
|
|
249
324
|
return { ctx, h };
|
|
250
325
|
}
|
|
326
|
+
|
|
251
327
|
onScroll() {
|
|
252
328
|
this.render(true);
|
|
253
329
|
}
|
|
330
|
+
|
|
254
331
|
onItemChanged(ctx, m) {
|
|
255
332
|
// skip replace data call
|
|
256
333
|
if (!m) return;
|
|
257
|
-
let ind = this.items.findIndex(
|
|
334
|
+
let ind = this.items.findIndex(i => i === ctx[this.as]);
|
|
258
335
|
if (ind < 0) console.warn('repeat item not found');
|
|
259
336
|
if (m.path === this.as) {
|
|
260
337
|
this.set(['items', ind], m.value, m.wmh);
|
|
261
338
|
} else {
|
|
262
|
-
this.forwardNotify(m,this.as, 'items.'+ind);
|
|
339
|
+
this.forwardNotify(m, this.as, 'items.' + ind);
|
|
263
340
|
}
|
|
264
|
-
|
|
265
341
|
}
|
|
266
342
|
}
|
|
267
343
|
|
|
@@ -270,31 +346,43 @@ class RepeatItem extends ContextMixin(EventTarget) {
|
|
|
270
346
|
super();
|
|
271
347
|
this.as = as;
|
|
272
348
|
this[as] = item;
|
|
273
|
-
this.addEffect(as, m => cb(this, m))
|
|
349
|
+
this.addEffect(as, m => cb(this, m));
|
|
274
350
|
}
|
|
351
|
+
|
|
275
352
|
get model() {
|
|
276
353
|
return this[this.as];
|
|
277
354
|
}
|
|
355
|
+
|
|
278
356
|
replace(v) {
|
|
279
357
|
this[this.as] = v;
|
|
280
358
|
this.wmh = {};
|
|
281
359
|
}
|
|
282
360
|
}
|
|
283
361
|
|
|
362
|
+
function fixOffset(item) {
|
|
363
|
+
item.ctx._ti._nodes.forEach((n) => {
|
|
364
|
+
if (n.style) {
|
|
365
|
+
n.style.transform = `translateY(${item.offset}px)`;
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
284
370
|
function calcNodesRect(nodes) {
|
|
285
371
|
nodes = nodes.filter(n => n.getBoundingClientRect);
|
|
286
372
|
let rect = nodes[0].getBoundingClientRect();
|
|
287
373
|
let { top, bottom, left, right } = rect;
|
|
288
|
-
({ top, bottom, left, right } = nodes.map(n => n.getBoundingClientRect())
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
374
|
+
({ top, bottom, left, right } = nodes.map(n => n.getBoundingClientRect())
|
|
375
|
+
.filter(i => i)
|
|
376
|
+
.reduce((a, c) => (
|
|
377
|
+
{
|
|
378
|
+
top: Math.min(a.top, c.top),
|
|
379
|
+
bottom: Math.max(a.bottom, c.bottom),
|
|
380
|
+
left: Math.min(a.left, c.left),
|
|
381
|
+
right: Math.max(a.right, c.right)
|
|
382
|
+
})
|
|
295
383
|
, { top, bottom, left, right }));
|
|
296
384
|
let { x, y, height, width } = { x: left, y: top, width: right - left, height: bottom - top };
|
|
297
385
|
return { x, y, height, width };
|
|
298
386
|
}
|
|
299
387
|
|
|
300
|
-
customElements.define('pl-virtual-scroll', PlVirtualScroll);
|
|
388
|
+
customElements.define('pl-virtual-scroll', PlVirtualScroll);
|