fix(virtual-scroll): avoid full reload on move-to-folder, scroll to top on filter/page reset

- MoveManager/SidebarManager: replace resetAndReload with in-place
  VirtualScroller update after move operations (remove non-visible,
  update visible items' file_path). Preserves scroll position and
  avoids empty grid.
- VirtualScroller: add removeMultipleItemsByFilePath for efficient
  batch removal with Array.isArray guard.
- baseModelApi: scroll to top on loadMoreWithVirtualScroll(true),
  covering filter/sort/search/folder/views changes.
- SidebarManager selectFolder: scroll now handled centrally.
This commit is contained in:
Will Miao
2026-06-19 09:18:49 +08:00
parent b24b1a7e57
commit 07f49559be
4 changed files with 232 additions and 29 deletions

View File

@@ -931,6 +931,38 @@ export class VirtualScroller {
return true;
}
/**
* Remove multiple items by their file paths.
* More efficient than calling removeItemByFilePath individually.
* @param {string[]} filePaths - Array of file paths to remove
* @returns {boolean} - True if any items were removed
*/
removeMultipleItemsByFilePath(filePaths) {
if (!Array.isArray(filePaths) || filePaths.length === 0 || this.disabled || this.items.length === 0) return false;
// Build a set for fast lookup
const pathsToRemove = new Set(filePaths);
const originalLength = this.items.length;
// Filter out removed items; keep those not in the set
this.items = this.items.filter(item => !pathsToRemove.has(item.file_path));
const removedCount = originalLength - this.items.length;
if (removedCount === 0) return false;
this.totalItems = Math.max(0, this.totalItems - removedCount);
// Update the spacer height
this.updateSpacerHeight();
// Re-render to fill gaps left by removed items
this.clearRenderedItems();
this.scheduleRender();
console.log(`Removed ${removedCount} items from virtual scroller data`);
return true;
}
// Add keyboard navigation methods
handlePageUpDown(direction) {
// Prevent duplicate animations by checking last trigger time