From d8bcc3e79bfbe06bc0f6f3c9c29c307d79617d30 Mon Sep 17 00:00:00 2001 From: Pascal Wengerter Date: Fri, 2 Jun 2023 00:00:49 +0200 Subject: [PATCH] Feature/7600 - scroll to newly created folder --- .../enhancement-scroll-to-created-folder | 6 +++++ .../components/FilesList/KeyboardActions.vue | 6 ++--- .../files/useFileActionsCreateNewFolder.ts | 6 ++++- .../src/composables/scrollTo/useScrollTo.ts | 24 ++++--------------- .../composables/scrollTo/useScrollTo.spec.ts | 21 ++-------------- 5 files changed, 21 insertions(+), 42 deletions(-) create mode 100644 changelog/unreleased/enhancement-scroll-to-created-folder diff --git a/changelog/unreleased/enhancement-scroll-to-created-folder b/changelog/unreleased/enhancement-scroll-to-created-folder new file mode 100644 index 00000000000..70a95699eb0 --- /dev/null +++ b/changelog/unreleased/enhancement-scroll-to-created-folder @@ -0,0 +1,6 @@ +Enhancement: Scroll to newly created folder + +After creating a new folder that gets sorted into the currently displayed resources but outside of the current viewport, we now scroll to the new folder. + +https://github.com/owncloud/web/issues/7600 +https://github.com/owncloud/web/pulls/8145 diff --git a/packages/web-app-files/src/components/FilesList/KeyboardActions.vue b/packages/web-app-files/src/components/FilesList/KeyboardActions.vue index c6f686c6440..8a9b6c235a2 100644 --- a/packages/web-app-files/src/components/FilesList/KeyboardActions.vue +++ b/packages/web-app-files/src/components/FilesList/KeyboardActions.vue @@ -121,7 +121,7 @@ export default defineComponent({ resetSelectionCursor() store.dispatch('Files/resetFileSelection') store.commit('Files/ADD_FILE_SELECTION', { id: nextId }) - scrollToResource({ id: nextId } as any) + scrollToResource(nextId) } const handleCtrlClickAction = (resource) => { store.dispatch('Files/toggleFileSelection', { id: resource.id }) @@ -148,7 +148,7 @@ export default defineComponent({ // select store.commit('Files/ADD_FILE_SELECTION', { id: nextResourceId }) } - scrollToResource({ id: nextResourceId } as any) + scrollToResource(nextResourceId) selectionCursor.value = unref(selectionCursor) - 1 } const handleShiftDownAction = () => { @@ -164,7 +164,7 @@ export default defineComponent({ // select store.commit('Files/ADD_FILE_SELECTION', { id: nextResourceId }) } - scrollToResource({ id: nextResourceId } as any) + scrollToResource(nextResourceId) selectionCursor.value = unref(selectionCursor) + 1 } const handleShiftClickAction = ({ resource, skipTargetSelection }) => { diff --git a/packages/web-app-files/src/composables/actions/files/useFileActionsCreateNewFolder.ts b/packages/web-app-files/src/composables/actions/files/useFileActionsCreateNewFolder.ts index 40d826ec289..2e5cde7bf68 100644 --- a/packages/web-app-files/src/composables/actions/files/useFileActionsCreateNewFolder.ts +++ b/packages/web-app-files/src/composables/actions/files/useFileActionsCreateNewFolder.ts @@ -9,6 +9,7 @@ import { join } from 'path' import { WebDAV } from 'web-client/src/webdav' import { isLocationSpacesActive } from 'web-app-files/src/router' import { getIndicators } from 'web-app-files/src/helpers/statusIndicators' +import { useScrollTo } from '../../scrollTo/useScrollTo' export const useFileActionsCreateNewFolder = ({ store, @@ -17,6 +18,7 @@ export const useFileActionsCreateNewFolder = ({ store = store || useStore() const router = useRouter() const { $gettext } = useGettext() + const { scrollToResource } = useScrollTo() const clientService = useClientService() const currentFolder = computed((): Resource => store.getters['Files/currentFolder']) @@ -66,12 +68,14 @@ export const useFileActionsCreateNewFolder = ({ resource.indicators = getIndicators({ resource, ancestorMetaData: unref(ancestorMetaData) }) } - store.commit('Files/UPSERT_RESOURCE', resource) + await store.commit('Files/UPSERT_RESOURCE', resource) store.dispatch('hideModal') store.dispatch('showMessage', { title: $gettext('"%{folderName}" was created successfully', { folderName }) }) + + scrollToResource(resource.id) } catch (error) { console.error(error) store.dispatch('showMessage', { diff --git a/packages/web-app-files/src/composables/scrollTo/useScrollTo.ts b/packages/web-app-files/src/composables/scrollTo/useScrollTo.ts index ad87357bf1c..0d7a94b8adc 100644 --- a/packages/web-app-files/src/composables/scrollTo/useScrollTo.ts +++ b/packages/web-app-files/src/composables/scrollTo/useScrollTo.ts @@ -6,7 +6,7 @@ import { useRouteQuery } from 'web-pkg/src/composables' import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar' export interface ScrollToResult { - scrollToResource(resource: Resource): void + scrollToResource(resourceId: Resource['id']): void scrollToResourceFromRoute(resources: Resource[]): void } @@ -21,30 +21,16 @@ export const useScrollTo = (): ScrollToResult => { return queryItemAsString(unref(detailsQuery)) }) - const scrollToResource = (resource) => { + const scrollToResource = (resourceId: Resource['id']) => { const resourceElement = document.querySelectorAll( - `[data-item-id='${resource.id}']` + `[data-item-id='${resourceId}']` )[0] as HTMLElement if (!resourceElement) { return } - // bottom reached - if (resourceElement.getBoundingClientRect().bottom > window.innerHeight) { - resourceElement.scrollIntoView(false) - return - } - - const topbarElement = document.getElementsByClassName('files-topbar')[0] as HTMLElement - // topbar height + th height + height of one row = offset needed when scrolling top - const topOffset = topbarElement.offsetHeight + resourceElement.offsetHeight * 2 - - // top reached - if (resourceElement.getBoundingClientRect().top < topOffset) { - const fileListWrapperElement = document.getElementsByClassName('files-view-wrapper')[0] - fileListWrapperElement.scrollBy(0, -resourceElement.offsetHeight) - } + resourceElement.scrollIntoView({ behavior: 'smooth', block: 'center' }) } const scrollToResourceFromRoute = (resources: Resource[]) => { @@ -55,7 +41,7 @@ export const useScrollTo = (): ScrollToResult => { const resource = unref(resources).find((r) => r.id === unref(scrollTo)) if (resource) { store.commit('Files/SET_FILE_SELECTION', [resource]) - scrollToResource(resource) + scrollToResource(resource.id) if (unref(details)) { eventBus.publish(SideBarEventTopics.openWithPanel, unref(details)) diff --git a/packages/web-app-files/tests/unit/composables/scrollTo/useScrollTo.spec.ts b/packages/web-app-files/tests/unit/composables/scrollTo/useScrollTo.spec.ts index b38d523d3e5..6504fc8b82b 100644 --- a/packages/web-app-files/tests/unit/composables/scrollTo/useScrollTo.spec.ts +++ b/packages/web-app-files/tests/unit/composables/scrollTo/useScrollTo.spec.ts @@ -25,7 +25,7 @@ describe('useScrollTo', () => { getComposableWrapper( () => { const { scrollToResource } = useScrollTo() - scrollToResource(mockDeep()) + scrollToResource('mockResourceId') expect(htmlPageObject.scrollIntoView).not.toHaveBeenCalled() }, { mocks: defaultComponentMocks(), store: defaultStoreMockOptions } @@ -39,29 +39,12 @@ describe('useScrollTo', () => { getComposableWrapper( () => { const { scrollToResource } = useScrollTo() - scrollToResource(mockDeep()) + scrollToResource('mockResourceId') expect(htmlPageObject.scrollIntoView).toHaveBeenCalled() }, { mocks: defaultComponentMocks(), store: defaultStoreMockOptions } ) }) - it('calls "scrollBy" when the page top is reached', () => { - const htmlPageObject = getHTMLPageObject() - jest.spyOn(document, 'querySelectorAll').mockImplementation(() => [htmlPageObject] as any) - jest - .spyOn(document, 'getElementsByClassName') - .mockImplementation(() => [htmlPageObject] as any) - window.innerHeight = 500 - - getComposableWrapper( - () => { - const { scrollToResource } = useScrollTo() - scrollToResource(mockDeep()) - expect(htmlPageObject.scrollBy).toHaveBeenCalled() - }, - { mocks: defaultComponentMocks(), store: defaultStoreMockOptions } - ) - }) }) describe('method "scrollToResourceFromRoute"', () => { const resourceId = 'someFileId'