Skip to content

Commit 0d6ab1e

Browse files
committed
fix: dispatch scroll event on view switch to fix empty file list
1 parent 366a9c7 commit 0d6ab1e

1 file changed

Lines changed: 63 additions & 0 deletions

File tree

src/nmcfiles.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,69 @@ if (document.readyState === 'loading') {
245245
setupPendingShare()
246246
}
247247

248+
/**
249+
* Fix for empty screen when switching between grid and list view.
250+
*
251+
* Root cause: the .files-list element is the actual scroll container. When the
252+
* view class changes (list to grid or vice versa), the virtual scroll does not
253+
* automatically recalculate visible rows for the new item sizes, leaving a blank
254+
* screen until the user scrolls. Dispatching a synthetic scroll event on the
255+
* .files-list element triggers the recalculation without changing scroll position.
256+
*/
257+
function setupGridViewScrollFix(): void {
258+
let filesListEl: Element | null = null
259+
let classObserver: MutationObserver | null = null
260+
261+
/**
262+
* Forces the virtual scroll to recalculate after a view switch.
263+
*
264+
* The actual scroll container is the .files-list element itself (scrollTop > 0
265+
* when scrolled, confirmed via DOM inspection). We dispatch a scroll event on it
266+
* so the virtual scroll recalculates visible rows at the current scroll position.
267+
* setTimeout ensures CSS has fully reflowed before the event fires.
268+
* @param scrollContainer The .files-list element to dispatch the scroll event on.
269+
*/
270+
function forceVirtualScrollUpdate(scrollContainer: Element): void {
271+
setTimeout(() => {
272+
scrollContainer.dispatchEvent(new Event('scroll', { bubbles: true }))
273+
}, 0)
274+
}
275+
276+
/**
277+
* Attaches a class mutation observer to the files list element.
278+
* @param el The files list element to observe.
279+
*/
280+
function attachClassObserver(el: Element): void {
281+
let prevIsGrid = el.classList.contains('files-list--grid')
282+
classObserver?.disconnect()
283+
classObserver = new MutationObserver(() => {
284+
const isGrid = el.classList.contains('files-list--grid')
285+
if (isGrid === prevIsGrid) return
286+
prevIsGrid = isGrid
287+
288+
// Wait one frame for Vue to finish applying the new layout
289+
requestAnimationFrame(() => forceVirtualScrollUpdate(el))
290+
})
291+
classObserver.observe(el, { attributes: true, attributeFilter: ['class'] })
292+
}
293+
294+
const domObserver = new MutationObserver(() => {
295+
const el = document.querySelector('.files-list')
296+
if (el && el !== filesListEl) {
297+
filesListEl = el
298+
attachClassObserver(el)
299+
}
300+
})
301+
302+
domObserver.observe(document.body, { childList: true, subtree: true })
303+
}
304+
305+
if (document.readyState === 'loading') {
306+
document.addEventListener('DOMContentLoaded', setupGridViewScrollFix)
307+
} else {
308+
setupGridViewScrollFix()
309+
}
310+
248311
window.addEventListener('DOMContentLoaded', function() {
249312
const breadcrumb = document.querySelector('.breadcrumb')
250313
const empty = document.querySelector('.files-list__empty')

0 commit comments

Comments
 (0)