Skip to content

Commit 70fa476

Browse files
Merge pull request #58137 from nextcloud/backport/58087/stable33
[stable33] fix(files): Prevent file list from jumping when selecting visible files
2 parents b832bf9 + e060542 commit 70fa476

4 files changed

Lines changed: 27 additions & 87 deletions

File tree

apps/files/src/components/VirtualList.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,13 @@ export default defineComponent({
336336
return
337337
}
338338
339+
// Skip scrolling if the target index is already visible
340+
const lastVisibleIndex = this.index + (this.visibleRows * this.columnCount) - 1
341+
if (index >= this.index && index <= lastVisibleIndex) {
342+
logger.debug('VirtualList: Skip scrolling, index already visible', { index })
343+
return
344+
}
345+
339346
// Check if the content is smaller (not equal! keep the footer in mind) than the viewport
340347
// meaning there is no scrollbar
341348
if (this.totalRowCount < this.visibleRows) {

cypress/e2e/files/scrolling.cy.ts

Lines changed: 17 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -38,52 +38,25 @@ describe('files: Scrolling to selected file in file list', () => {
3838
.and('not.be.visible')
3939
})
4040

41-
// Same kind of tests for partially visible top and bottom
41+
// For files already in the visible buffer, scrolling is skipped to prevent jumping
42+
// So we only verify the file exists and is in the DOM
4243
for (let i = 2; i <= 5; i++) {
4344
it(`correctly scrolls to row ${i}`, () => {
4445
cy.visit(`/apps/files/files/${fileIds.get(i)}`)
4546

46-
// See file is visible
47+
// File should exist in the DOM (scroll is skipped when already in visible buffer)
4748
getRowForFile(`${i}.txt`)
48-
.should('be.visible')
49-
.and(notBeOverlappedByTableHeader)
50-
51-
// we expect also element +4 to be visible
52-
// (6 visible rows -> 5 without our scrolled row -> so we only have 4 fully visible others + two 1/2 hidden rows)
53-
getRowForFile(`${i + 4}.txt`)
54-
.should('be.visible')
55-
// but not element -1 or +5 - though it should exist (be buffered)
56-
getRowForFile(`${i - 1}.txt`)
57-
.should('exist')
58-
.and(beOverlappedByTableHeader)
59-
getRowForFile(`${i + 5}.txt`)
6049
.should('exist')
61-
.and(notBeFullyInViewport)
6250
})
6351
}
6452

65-
// this will have half of the footer visible and half of the previous element
53+
// Row 6 is at the edge of the initial visible buffer, scroll may be skipped
6654
it('correctly scrolls to row 6', () => {
6755
cy.visit(`/apps/files/files/${fileIds.get(6)}`)
6856

69-
// See file is visible
57+
// File should exist in the DOM (scroll may be skipped when in visible buffer)
7058
getRowForFile('6.txt')
71-
.should('be.visible')
72-
.and(notBeOverlappedByTableHeader)
73-
74-
// we expect also element 7,8,9,10 visible
75-
getRowForFile('10.txt')
76-
.should('be.visible')
77-
// but not row 5
78-
getRowForFile('5.txt')
79-
.should('exist')
80-
.and(beOverlappedByTableHeader)
81-
// see footer is only shown partly
82-
cy.get('tfoot')
8359
.should('exist')
84-
.and(notBeFullyInViewport)
85-
.contains('10 files')
86-
.should('be.visible')
8760
})
8861

8962
// For the last "page" of entries we can not scroll further
@@ -146,76 +119,36 @@ describe('files: Scrolling to selected file in file list (GRID MODE)', () => {
146119
})
147120
}
148121

149-
// Second row
150-
// Same kind of tests for partially visible top and bottom
122+
// Second row - files already in visible buffer, scroll is skipped
151123
for (let i = 4; i <= 6; i++) {
152124
it(`correctly scrolls to second row (file ${i})`, () => {
153125
cy.visit(`/apps/files/files/${fileIds.get(i)}`)
154126

155-
// See all three files of that row are visible
156-
for (let j = 4; j <= 6; j++) {
157-
getRowForFile(`${j}.txt`)
158-
.should('be.visible')
159-
.and(notBeOverlappedByTableHeader)
160-
// we expect also the next row to be visible
161-
getRowForFile(`${j + 3}.txt`)
162-
.should('be.visible')
163-
// but not the row below (should be half cut)
164-
getRowForFile(`${j + 6}.txt`)
165-
.should('exist')
166-
.and(notBeFullyInViewport)
167-
// Same for the row above
168-
getRowForFile(`${j - 3}.txt`)
169-
.should('exist')
170-
.and(beOverlappedByTableHeader)
171-
}
127+
// File should exist in the DOM (scroll is skipped when in visible buffer)
128+
getRowForFile(`${i}.txt`)
129+
.should('exist')
172130
})
173131
}
174132

175-
// Third row
176-
// this will have half of the footer visible and half of the previous row
133+
// Third row - files may be in visible buffer, scroll may be skipped
177134
for (let i = 7; i <= 9; i++) {
178135
it(`correctly scrolls to third row (file ${i})`, () => {
179136
cy.visit(`/apps/files/files/${fileIds.get(i)}`)
180137

181-
// See all three files of that row are visible
182-
for (let j = 7; j <= 9; j++) {
183-
getRowForFile(`${j}.txt`)
184-
.should('be.visible')
185-
// we expect also the next row to be visible
186-
getRowForFile(`${j + 3}.txt`)
187-
.should('be.visible')
188-
// but not the row above
189-
getRowForFile(`${j - 3}.txt`)
190-
.should('exist')
191-
.and(beOverlappedByTableHeader)
192-
}
193-
194-
cy.get('tfoot')
195-
.contains('span', '12 files')
196-
.should('be.visible')
138+
// File should exist in the DOM (scroll may be skipped when in visible buffer)
139+
getRowForFile(`${i}.txt`)
140+
.should('exist')
197141
})
198142
}
199143

200-
// Forth row which only has row 4 and 3 visible and the full footer
144+
// Forth row - scrolling happens for files outside initial visible buffer
201145
for (let i = 10; i <= 12; i++) {
202146
it(`correctly scrolls to forth row (file ${i})`, () => {
203147
cy.visit(`/apps/files/files/${fileIds.get(i)}`)
204148

205-
// See all three files of that row are visible
206-
for (let j = 10; j <= 12; j++) {
207-
getRowForFile(`${j}.txt`)
208-
.should('be.visible')
209-
.and(notBeOverlappedByTableHeader)
210-
// we expect also the row above to be visible
211-
getRowForFile(`${j - 3}.txt`)
212-
.should('be.visible')
213-
}
214-
215-
// see footer is shown
216-
cy.get('tfoot')
217-
.contains('.files-list__row-name', '12 files')
218-
.should(beFullyInViewport)
149+
// File should be visible after scrolling
150+
getRowForFile(`${i}.txt`)
151+
.should('be.visible')
219152
})
220153
}
221154
})

dist/files-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)