feat: select item on file list after navigating back (#5329)

This commit is contained in:
Ramires Viana
2025-07-27 08:03:00 -03:00
committed by GitHub
parent 25e47c3ce8
commit cbeec6d225
13 changed files with 143 additions and 79 deletions

View File

@@ -1,7 +1,7 @@
<template>
<div>
<header-bar
v-if="error || fileStore.req?.type === null"
v-if="error || fileStore.req?.type === undefined"
showMenu
showLogo
/>
@@ -9,7 +9,7 @@
<breadcrumbs base="/files" />
<errors v-if="error" :errorCode="error.status" />
<component v-else-if="currentView" :is="currentView"></component>
<div v-else-if="currentView !== null">
<div v-else>
<h2 class="message delayed">
<div class="spinner">
<div class="bounce1"></div>
@@ -102,15 +102,7 @@ onUnmounted(() => {
fetchDataController.abort();
});
watch(route, (to, from) => {
if (from.path.endsWith("/")) {
window.sessionStorage.setItem(
"listFrozen",
(!to.path.endsWith("/")).toString()
);
} else if (to.path.endsWith("/")) {
fileStore.updateRequest(null);
}
watch(route, () => {
fetchData();
});
watch(reload, (newValue) => {
@@ -122,6 +114,32 @@ watch(uploadError, (newValue) => {
// Define functions
const applyPreSelection = () => {
const preselect = fileStore.preselect;
fileStore.preselect = null;
if (!fileStore.req?.isDir || fileStore.oldReq === null) return;
let index = -1;
if (preselect) {
// Find item with the specified path
index = fileStore.req.items.findIndex((item) => item.path === preselect);
} else if (fileStore.oldReq.path.startsWith(fileStore.req.path)) {
// Get immediate child folder of the previous path
const name = fileStore.oldReq.path
.substring(fileStore.req.path.length)
.split("/")
.shift();
index = fileStore.req.items.findIndex(
(val) => val.path == fileStore.req!.path + name
);
}
if (index === -1) return;
fileStore.selected.push(index);
};
const fetchData = async () => {
// Reset view information.
fileStore.reload = false;
@@ -130,12 +148,7 @@ const fetchData = async () => {
layoutStore.closeHovers();
// Set loading to true and reset the error.
if (
window.sessionStorage.getItem("listFrozen") !== "true" &&
window.sessionStorage.getItem("modified") !== "true"
) {
layoutStore.loading = true;
}
layoutStore.loading = true;
error.value = null;
let url = route.path;
@@ -149,6 +162,9 @@ const fetchData = async () => {
fileStore.updateRequest(res);
document.title = `${res.name || t("sidebar.myFiles")} - ${t("files.files")} - ${name}`;
layoutStore.loading = false;
// Selects the post-reload target item or the previously visited child folder
applyPreSelection();
} catch (err) {
if (err instanceof StatusError && err.is_canceled) {
return;

View File

@@ -32,17 +32,25 @@
/>
</header-bar>
<Breadcrumbs base="/files" noLink />
<!-- preview container -->
<div
v-show="isPreview && isMarkdownFile"
id="preview-container"
class="md_preview"
v-html="previewContent"
></div>
<div class="loading delayed" v-if="layoutStore.loading">
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div>
<template v-else>
<Breadcrumbs base="/files" noLink />
<form v-show="!isPreview || !isMarkdownFile" id="editor"></form>
<div
v-show="isPreview && isMarkdownFile"
id="preview-container"
class="md_preview"
v-html="previewContent"
></div>
<form v-show="!isPreview || !isMarkdownFile" id="editor"></form>
</template>
</div>
</template>
@@ -146,12 +154,19 @@ onBeforeUnmount(() => {
});
onBeforeRouteUpdate((to, from, next) => {
if (!editor.value?.session.getUndoManager().isClean()) {
layoutStore.showHover("discardEditorChanges");
next(false);
} else {
if (editor.value?.session.getUndoManager().isClean()) {
next();
return;
}
layoutStore.showHover({
prompt: "discardEditorChanges",
confirm: (event: Event) => {
event.preventDefault();
next();
},
});
});
const keyEvent = (event: KeyboardEvent) => {
@@ -216,13 +231,6 @@ const decreaseFontSize = () => {
};
const close = () => {
if (!editor.value?.session.getUndoManager().isClean()) {
layoutStore.showHover("discardEditorChanges");
return;
}
fileStore.updateRequest(null);
const uri = url.removeLastDir(route.path) + "/";
router.push({ path: uri });
};

View File

@@ -303,6 +303,7 @@ import {
import { useRoute } from "vue-router";
import { useI18n } from "vue-i18n";
import { storeToRefs } from "pinia";
import { removePrefix } from "@/api/utils";
const showLimit = ref<number>(50);
const columnWidth = ref<number>(280);
@@ -420,25 +421,19 @@ const isMobile = computed(() => {
watch(req, () => {
// Reset the show value
if (
window.sessionStorage.getItem("listFrozen") !== "true" &&
window.sessionStorage.getItem("modified") !== "true"
) {
showLimit.value = 50;
showLimit.value = 50;
nextTick(() => {
// Ensures that the listing is displayed
// How much every listing item affects the window height
setItemWeight();
nextTick(() => {
// Ensures that the listing is displayed
// How much every listing item affects the window height
setItemWeight();
// Scroll to the item opened previously
if (!revealPreviousItem()) {
// Fill and fit the window with listing items
fillWindow(true);
});
}
if (req.value?.isDir) {
window.sessionStorage.setItem("listFrozen", "false");
window.sessionStorage.setItem("modified", "false");
}
}
});
});
onMounted(() => {
@@ -448,8 +443,11 @@ onMounted(() => {
// How much every listing item affects the window height
setItemWeight();
// Fill and fit the window with listing items
fillWindow(true);
// Scroll to the item opened previously
if (!revealPreviousItem()) {
// Fill and fit the window with listing items
fillWindow(true);
}
// Add the needed event listeners to the window and document.
window.addEventListener("keydown", keyEvent);
@@ -589,10 +587,13 @@ const paste = (event: Event) => {
return;
}
const preselect = removePrefix(route.path) + items[0].name;
let action = (overwrite: boolean, rename: boolean) => {
api
.copy(items, overwrite, rename)
.then(() => {
fileStore.preselect = preselect;
fileStore.reload = true;
})
.catch($showError);
@@ -604,6 +605,7 @@ const paste = (event: Event) => {
.move(items, overwrite, rename)
.then(() => {
clipboardStore.resetClipboard();
fileStore.preselect = preselect;
fileStore.reload = true;
})
.catch($showError);
@@ -731,6 +733,8 @@ const drop = async (event: DragEvent) => {
const conflict = upload.checkConflict(files, items);
const preselect = removePrefix(path) + (files[0].fullPath || files[0].name);
if (conflict) {
layoutStore.showHover({
prompt: "replace",
@@ -738,11 +742,13 @@ const drop = async (event: DragEvent) => {
event.preventDefault();
layoutStore.closeHovers();
upload.handleFiles(files, path, false);
fileStore.preselect = preselect;
},
confirm: (event: Event) => {
event.preventDefault();
layoutStore.closeHovers();
upload.handleFiles(files, path, true);
fileStore.preselect = preselect;
},
});
@@ -750,6 +756,7 @@ const drop = async (event: DragEvent) => {
}
upload.handleFiles(files, path);
fileStore.preselect = preselect;
};
const uploadInput = (event: Event) => {
@@ -953,4 +960,21 @@ const fillWindow = (fit = false) => {
// Set the number of displayed items
showLimit.value = showQuantity > totalItems ? totalItems : showQuantity;
};
const revealPreviousItem = () => {
if (!fileStore.req || !fileStore.oldReq) return;
const index = fileStore.selected[0];
if (index === undefined) return;
showLimit.value =
index + Math.ceil((window.innerHeight * 2) / itemWeight.value);
nextTick(() => {
const items = document.querySelectorAll("#listing .item");
items[index].scrollIntoView({ block: "center" });
});
return true;
};
</script>

View File

@@ -301,10 +301,8 @@ watch(route, () => {
// Specify hooks
onMounted(async () => {
window.addEventListener("keydown", key);
if (fileStore.oldReq) {
listing.value = fileStore.oldReq.items;
updatePreview();
}
listing.value = fileStore.oldReq?.items ?? null;
updatePreview();
});
onBeforeUnmount(() => window.removeEventListener("keydown", key));
@@ -317,11 +315,16 @@ const deleteFile = () => {
if (listing.value === null) {
return;
}
listing.value = listing.value.filter((item) => item.name !== name.value);
const index = listing.value.findIndex((item) => item.name == name.value);
listing.value.splice(index, 1);
if (hasNext.value) {
next();
} else if (!hasPrevious.value && !hasNext.value) {
const nearbyItem = listing.value[Math.max(0, index - 1)];
fileStore.preselect = nearbyItem?.path;
close();
} else {
prev();
@@ -427,8 +430,6 @@ const toggleNavigation = throttle(function () {
}, 500);
const close = () => {
fileStore.updateRequest(null);
const uri = url.removeLastDir(route.path) + "/";
router.push({ path: uri });
};