refactor(files): konum senkronizasyonunu sağlamlaştır

URL tabanlı konum yönetimini tek bir fonksiyon altında toplayarak
tarayıcı navigasyonu ve history API olaylarının tutarlı şekilde işlenmesini
sağla. pushState ve replaceState metodlarını patch ederek özel locationchange
olayı oluşturur ve bileşen yok edildiğinde patch işlemini geri alır.
This commit is contained in:
2026-01-31 10:36:07 +03:00
parent 5e6da2b445
commit 569a7975de

View File

@@ -1,5 +1,5 @@
<script>
import { onMount, tick } from "svelte";
import { onDestroy, onMount, tick } from "svelte";
import MatchModal from "../components/MatchModal.svelte";
import { API, apiFetch, moveEntry, renameFolder, copyEntry } from "../utils/api.js";
import { cleanFileName, extractTitleAndYear } from "../utils/filename.js";
@@ -452,6 +452,7 @@
const VIEW_KEY = "filesViewMode";
let viewMode = "grid";
let initialPath = "";
let unpatchHistory = null;
if (typeof window !== "undefined") {
const storedView = window.localStorage.getItem(VIEW_KEY);
if (storedView === "grid" || storedView === "list") {
@@ -491,14 +492,16 @@
let clipboardItem = null;
let clipboardOperation = null; // 'cut' veya 'copy'
if (typeof window !== "undefined") {
const syncFromLocation = ({ replace = false } = {}) => {
if (typeof window === "undefined") return;
const params = new URLSearchParams(window.location.search);
const pathParam = params.get("path");
let nextPath = "";
if (pathParam) {
try {
initialPath = normalizePath(decodeURIComponent(pathParam));
nextPath = normalizePath(decodeURIComponent(pathParam));
} catch (err) {
initialPath = normalizePath(pathParam);
nextPath = normalizePath(pathParam);
}
}
const playParam = params.get("play");
@@ -509,16 +512,49 @@
pendingPlayTarget = playParam;
}
params.delete("play");
}
const search = params.toString();
const newUrl = `${window.location.pathname}${search ? `?${search}` : ""}${window.location.hash}`;
window.history.replaceState(
{ path: initialPath, originalPath: null },
{ path: nextPath, originalPath: null },
"",
newUrl,
);
}
currentPath = normalizePath(initialPath);
const state = window.history.state || {};
const nextOriginal =
typeof state.originalPath === "string"
? normalizePath(state.originalPath)
: resolveOriginalPathForDisplay(nextPath);
if (
normalizePath(currentPath) === nextPath &&
normalizePath(currentOriginalPath) === nextOriginal
) {
return;
}
const hadSearch = searchTerm.trim().length > 0;
const nextSearchTerm = hadSearch ? "" : searchTerm;
currentPath = nextPath;
currentOriginalPath = nextOriginal;
if (hadSearch) {
clearSearch("files");
}
selectedItems = new Set();
activeMenu = null;
if (isCreatingFolder) cancelCreateFolder();
updateVisibleState(files, nextPath);
renderedEntries = filterEntriesBySearch(visibleEntries, nextSearchTerm);
if (replace) {
updateUrlPath(nextPath, nextOriginal, { replace: true });
}
};
if (typeof window !== "undefined") {
syncFromLocation({ replace: true });
initialPath = currentPath;
}
// 🎬 Player kontrolleri
let videoEl;
let isPlaying = false;
@@ -1694,34 +1730,37 @@
}, 50);
}
});
const handlePopState = (event) => {
if (typeof window === "undefined") return;
const statePath =
event?.state && typeof event.state.path === "string"
? event.state.path
: null;
const stateOriginal =
event?.state && typeof event.state.originalPath === "string"
? event.state.originalPath
: null;
if (statePath !== null) {
currentPath = normalizePath(statePath);
} else {
const params = new URLSearchParams(window.location.search);
const paramPath = params.get("path");
currentPath = normalizePath(paramPath || "");
}
if (stateOriginal !== null) {
currentOriginalPath = normalizePath(stateOriginal);
} else {
currentOriginalPath = resolveOriginalPathForDisplay(
currentPath,
currentOriginalPath,
);
}
selectedItems = new Set();
activeMenu = null;
const handlePopState = () => {
syncFromLocation();
};
const handleLocationChange = () => {
syncFromLocation();
};
if (typeof window !== "undefined") {
const originalPushState = window.history.pushState;
const originalReplaceState = window.history.replaceState;
const triggerChange = () => {
window.dispatchEvent(new Event("locationchange"));
};
window.history.pushState = function (...args) {
originalPushState.apply(this, args);
triggerChange();
};
window.history.replaceState = function (...args) {
originalReplaceState.apply(this, args);
triggerChange();
};
window.addEventListener("locationchange", handleLocationChange);
window.addEventListener("popstate", handlePopState);
unpatchHistory = () => {
window.history.pushState = originalPushState;
window.history.replaceState = originalReplaceState;
window.removeEventListener("locationchange", handleLocationChange);
window.removeEventListener("popstate", handlePopState);
};
}
ws.onmessage = async (event) => {
try {
const msg = JSON.parse(event.data);
@@ -1949,6 +1988,7 @@
window.removeEventListener("click", handleClickOutside);
window.removeEventListener("popstate", handlePopState);
if (unpatchHistory) unpatchHistory();
// Resize observer'ı temizle
if (breadcrumbContainer) {