From f05574f579393f81848ba8c621700ae3371b4e8d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 12 Jul 2021 13:57:37 +0530 Subject: [PATCH] Fix updates Signed-off-by: RMidhunSuresh --- src/platform/web/ui/general/LazyListView.js | 65 ++++++++++++++++----- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/src/platform/web/ui/general/LazyListView.js b/src/platform/web/ui/general/LazyListView.js index 53c7b12f..6ad0f057 100644 --- a/src/platform/web/ui/general/LazyListView.js +++ b/src/platform/web/ui/general/LazyListView.js @@ -42,6 +42,10 @@ class ItemRange { totalSize() { return this.topCount + this.renderCount + this.bottomCount; } + + normalize(idx) { + return idx - this.topCount; + } } export class LazyListView extends ListView { @@ -64,7 +68,7 @@ export class LazyListView extends ListView { return new ItemRange(topCount, renderCount, bottomCount); } - _renderMoreIfNeeded() { + _renderIfNeeded() { const range = this._getVisibleRange(); const intersectRange = range.expand(this._overflowMargin); const renderRange = range.expand(this._overflowItems); @@ -83,6 +87,7 @@ export class LazyListView extends ListView { } _renderItems(items) { + this._childInstances = []; const fragment = document.createDocumentFragment(); for (const item of items) { const view = this._childCreator(item.value); @@ -114,8 +119,8 @@ export class LazyListView extends ListView { But in most of these scroll events, we return early. Do we need to do more (like event throttling)? */ - this._parent.addEventListener("scroll", () => this._renderMoreIfNeeded()); - this._renderMoreIfNeeded(); + this._parent.addEventListener("scroll", () => this._renderIfNeeded()); + this._renderIfNeeded(); return this._parent; } @@ -123,49 +128,81 @@ export class LazyListView extends ListView { if (!this._list) { return; } this._subscription = this._list.subscribe(this); this._childInstances = []; + // todo: this breaks update in parent } - // onAdd, onRemove, ... should be called only if the element is already rendered + + // If size of the list changes, re-render onAdd() { - this._renderMoreIfNeeded(); + this._renderIfNeeded(); } onRemove() { - this._renderMoreIfNeeded(); + this._renderIfNeeded(); } onUpdate(idx, value, params) { - console.log("onUpdate"); if (this._renderRange.containsIndex(idx)) { - super.onUpdate(idx, value, params); + const normalizedIdx = this._renderRange.normalize(idx); + super.onUpdate(normalizedIdx, value, params); } } recreateItem(idx, value) { - console.log("recreateItem"); if (this._renderRange.containsIndex(idx)) { super.recreateItem(idx, value) } } + _renderAdditionalElement(fromIdx, toIdx) { + const {topCount, renderCount} = this._renderRange; + const childFromIndex = index => this._childCreator(this._list.get(index)); + if (toIdx < fromIdx) { + // Element is moved up the list, so render element from top boundary + const index = topCount; + const child = childFromIndex(index); + // Modify childInstances here + this._root.insertBefore(mountView(child, this._mountArgs), this._root.firstChild); + } + else { + // Element is moved down the list, so render element from bottom boundary + const index = topCount + renderCount - 1; + const child = childFromIndex(index); + this._root.appendChild(mountView(child, this._mountArgs)); + } + } + + _removeAdditionalElement(fromIdx, toIdx) { + if (toIdx < fromIdx) { + // Element comes from the bottom, so remove element at bottom + this._root.lastChild.remove(); + } + else { + this._root.firstChild.remove(); + } + } + onMove(fromIdx, toIdx, value) { - console.log("onMove"); const fromInRange = this._renderRange.containsIndex(fromIdx); const toInRange = this._renderRange.containsIndex(toIdx); + const normalizedFromIdx = this._renderRange.normalize(fromIdx); + const normalizedToIdx = this._renderRange.normalize(toIdx); if (fromInRange && toInRange) { - super.onMove(fromIdx, toIdx, value); + super.onMove(normalizedFromIdx, normalizedToIdx, value); } else if (fromInRange && !toInRange) { this.onBeforeListChanged(); - const [child] = this._childInstances.splice(fromIdx, 1); + const [child] = this._childInstances.splice(normalizedFromIdx, 1); child.root().remove(); + this._renderAdditionalElement(fromIdx, toIdx); this.onListChanged(); } else if (!fromInRange && toInRange) { this.onBeforeListChanged(); const child = this._childCreator(value); - this._childInstances.splice(toIdx, 0, child); - insertAt(this._root, toIdx, mountView(child, this._mountArgs)); + this._childInstances.splice(normalizedToIdx, 0, child); + this._removeAdditionalElement(fromIdx, toIdx); + insertAt(this._root, normalizedToIdx, mountView(child, this._mountArgs)); this.onListChanged(); } }