Fix local filetree navigation state and office proxy
This commit is contained in:
@@ -21,6 +21,9 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
|||||||
var fileTreeLazyChildrenCache = new Map();
|
var fileTreeLazyChildrenCache = new Map();
|
||||||
var fileTreeExpandedRelativePaths = new Set();
|
var fileTreeExpandedRelativePaths = new Set();
|
||||||
var fileTreeLazyCacheRootUri = '';
|
var fileTreeLazyCacheRootUri = '';
|
||||||
|
var fileTreeExpansionStorageRootUri = '';
|
||||||
|
var fileTreeExpansionRestoreTimer = 0;
|
||||||
|
var FILETREE_EXPANSION_STORAGE_KEY = 'mnote.localFileTree.expandedRelativePaths.v1';
|
||||||
|
|
||||||
function updateTitleEverywhere(documentId, title) {
|
function updateTitleEverywhere(documentId, title) {
|
||||||
if (!documentId) return;
|
if (!documentId) return;
|
||||||
@@ -616,19 +619,68 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
|||||||
fileTreeLazyCacheRootUri = rootUri;
|
fileTreeLazyCacheRootUri = rootUri;
|
||||||
fileTreeLazyChildrenCache.clear();
|
fileTreeLazyChildrenCache.clear();
|
||||||
fileTreeExpandedRelativePaths.clear();
|
fileTreeExpandedRelativePaths.clear();
|
||||||
|
loadStoredFileTreeExpansionState(rootUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
function storedFileTreeExpansionBuckets() {
|
||||||
|
try {
|
||||||
|
if (!window.sessionStorage) return {};
|
||||||
|
var parsed = JSON.parse(window.sessionStorage.getItem(FILETREE_EXPANSION_STORAGE_KEY) || '{}');
|
||||||
|
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
||||||
|
} catch (_) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadStoredFileTreeExpansionState(rootUri) {
|
||||||
|
var normalizedRootUri = String(rootUri || '').trim();
|
||||||
|
if (!normalizedRootUri || fileTreeExpansionStorageRootUri === normalizedRootUri) return;
|
||||||
|
fileTreeExpansionStorageRootUri = normalizedRootUri;
|
||||||
|
var buckets = storedFileTreeExpansionBuckets();
|
||||||
|
var paths = Array.isArray(buckets[normalizedRootUri]) ? buckets[normalizedRootUri] : [];
|
||||||
|
paths.forEach(function(path) {
|
||||||
|
var normalized = String(path || '').trim();
|
||||||
|
if (normalized) fileTreeExpandedRelativePaths.add(normalized);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistFileTreeExpansionState() {
|
||||||
|
var rootUri = String(currentRootUri() || fileTreeLazyCacheRootUri || '').trim();
|
||||||
|
if (!rootUri) return;
|
||||||
|
try {
|
||||||
|
if (!window.sessionStorage) return;
|
||||||
|
var buckets = storedFileTreeExpansionBuckets();
|
||||||
|
buckets[rootUri] = Array.from(fileTreeExpandedRelativePaths)
|
||||||
|
.map(function(path) { return String(path || '').trim(); })
|
||||||
|
.filter(Boolean)
|
||||||
|
.slice(0, 256);
|
||||||
|
window.sessionStorage.setItem(FILETREE_EXPANSION_STORAGE_KEY, JSON.stringify(buckets));
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleRestorePersistedFileTreeExpansionState() {
|
||||||
|
if (fileTreeExpansionRestoreTimer) window.clearTimeout(fileTreeExpansionRestoreTimer);
|
||||||
|
fileTreeExpansionRestoreTimer = window.setTimeout(function() {
|
||||||
|
fileTreeExpansionRestoreTimer = 0;
|
||||||
|
restorePersistedFileTreeExpansionState();
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function rememberFileTreeExpansionState() {
|
function rememberFileTreeExpansionState() {
|
||||||
|
var changed = false;
|
||||||
document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]').forEach(function(row) {
|
document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]').forEach(function(row) {
|
||||||
if (!(row instanceof HTMLElement)) return;
|
if (!(row instanceof HTMLElement)) return;
|
||||||
var relativePath = localFileTreeRelativePathFromRow(row);
|
var relativePath = localFileTreeRelativePathFromRow(row);
|
||||||
if (!relativePath) return;
|
if (!relativePath) return;
|
||||||
if (row.getAttribute('aria-expanded') === 'true') {
|
if (row.getAttribute('aria-expanded') === 'true') {
|
||||||
|
if (!fileTreeExpandedRelativePaths.has(relativePath)) changed = true;
|
||||||
fileTreeExpandedRelativePaths.add(relativePath);
|
fileTreeExpandedRelativePaths.add(relativePath);
|
||||||
} else {
|
} else {
|
||||||
|
if (fileTreeExpandedRelativePaths.has(relativePath)) changed = true;
|
||||||
fileTreeExpandedRelativePaths.delete(relativePath);
|
fileTreeExpandedRelativePaths.delete(relativePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (changed) persistFileTreeExpansionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFileProjection(projection) {
|
function renderFileProjection(projection) {
|
||||||
@@ -727,6 +779,8 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
|||||||
if (currentSourceKind() !== 'local_folder') return;
|
if (currentSourceKind() !== 'local_folder') return;
|
||||||
var rootUri = currentRootUri();
|
var rootUri = currentRootUri();
|
||||||
if (!rootUri) return;
|
if (!rootUri) return;
|
||||||
|
ensureFileTreeLazyCacheScope();
|
||||||
|
scheduleRestorePersistedFileTreeExpansionState();
|
||||||
var revision = '';
|
var revision = '';
|
||||||
var refreshTimer = 0;
|
var refreshTimer = 0;
|
||||||
var scheduleRefresh = function() {
|
var scheduleRefresh = function() {
|
||||||
@@ -824,6 +878,7 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
|||||||
if (!relativePath) return;
|
if (!relativePath) return;
|
||||||
if (expanded) fileTreeExpandedRelativePaths.add(relativePath);
|
if (expanded) fileTreeExpandedRelativePaths.add(relativePath);
|
||||||
else fileTreeExpandedRelativePaths.delete(relativePath);
|
else fileTreeExpandedRelativePaths.delete(relativePath);
|
||||||
|
persistFileTreeExpansionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCachedFileTreeChildren(row, button, relativePath) {
|
function renderCachedFileTreeChildren(row, button, relativePath) {
|
||||||
@@ -896,6 +951,29 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
|||||||
setTreeRowExpanded(row, button, !collapsed);
|
setTreeRowExpanded(row, button, !collapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function restorePersistedFileTreeExpansionState() {
|
||||||
|
if (currentSourceKind() !== 'local_folder') return false;
|
||||||
|
ensureFileTreeLazyCacheScope();
|
||||||
|
if (!fileTreeExpandedRelativePaths.size) return false;
|
||||||
|
var restored = false;
|
||||||
|
document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]').forEach(function(row) {
|
||||||
|
if (!(row instanceof HTMLElement)) return;
|
||||||
|
if (String(row.getAttribute('data-row-kind') || '').trim() !== 'folder') return;
|
||||||
|
var relativePath = localFileTreeRelativePathFromRow(row);
|
||||||
|
if (!relativePath || !fileTreeExpandedRelativePaths.has(relativePath)) return;
|
||||||
|
var button = row.querySelector('[data-rust-action="toggle"]');
|
||||||
|
if (row.getAttribute('data-filetree-children-loaded') === 'true') {
|
||||||
|
setTreeRowExpanded(row, button, true);
|
||||||
|
restored = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void loadFileTreeChildren(row, button);
|
||||||
|
restored = true;
|
||||||
|
});
|
||||||
|
if (restored) document.documentElement.setAttribute('data-mnote-filetree-expansion-restored', 'true');
|
||||||
|
return restored;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function installTreeLiveApplyEventListeners() {
|
function installTreeLiveApplyEventListeners() {
|
||||||
window.addEventListener('tree:title-updated', function(event) {
|
window.addEventListener('tree:title-updated', function(event) {
|
||||||
@@ -1021,6 +1099,7 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
|||||||
refreshLocalFolderSidebarSnapshot,
|
refreshLocalFolderSidebarSnapshot,
|
||||||
removeDocumentRowForMode,
|
removeDocumentRowForMode,
|
||||||
renderSidebarSnapshot,
|
renderSidebarSnapshot,
|
||||||
|
restorePersistedFileTreeExpansionState,
|
||||||
setTreeLiveApplyError,
|
setTreeLiveApplyError,
|
||||||
startLocalFolderSidebarWatch,
|
startLocalFolderSidebarWatch,
|
||||||
toggleChildren,
|
toggleChildren,
|
||||||
|
|||||||
@@ -474,7 +474,16 @@ pub async fn page(Query(query): Query<OnlyOfficePageQuery>) -> Result<Response,
|
|||||||
url.host = origin.host;
|
url.host = origin.host;
|
||||||
return url.toString();
|
return url.toString();
|
||||||
}}
|
}}
|
||||||
|
const isLocalFolderFileOpen = url.pathname === "/api/local-folder/files/open";
|
||||||
const isLocal = ["127.0.0.1", "localhost", "host.docker.internal"].includes(url.hostname);
|
const isLocal = ["127.0.0.1", "localhost", "host.docker.internal"].includes(url.hostname);
|
||||||
|
if (proxyOrigin && isLocalFolderFileOpen) {{
|
||||||
|
const origin = new URL(proxyOrigin);
|
||||||
|
url.protocol = origin.protocol;
|
||||||
|
url.host = origin.host;
|
||||||
|
const proxy = new URL("/api/onlyoffice/proxy", proxyOrigin);
|
||||||
|
proxy.searchParams.set("u", base64UrlEncodeUtf8(url.toString()));
|
||||||
|
return proxy.toString();
|
||||||
|
}}
|
||||||
if (proxyOrigin && (isLocal || url.searchParams.has("token"))) {{
|
if (proxyOrigin && (isLocal || url.searchParams.has("token"))) {{
|
||||||
const proxy = new URL("/api/onlyoffice/proxy", proxyOrigin);
|
const proxy = new URL("/api/onlyoffice/proxy", proxyOrigin);
|
||||||
proxy.searchParams.set("u", base64UrlEncodeUtf8(url.toString()));
|
proxy.searchParams.set("u", base64UrlEncodeUtf8(url.toString()));
|
||||||
@@ -1827,6 +1836,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert!(html.contains("documentUrlBase,"));
|
assert!(html.contains("documentUrlBase,"));
|
||||||
assert!(html.contains("resolvedFileUrl: fileState.resolvedFileUrl"));
|
assert!(html.contains("resolvedFileUrl: fileState.resolvedFileUrl"));
|
||||||
|
assert!(html.contains(
|
||||||
|
r#"const isLocalFolderFileOpen = url.pathname === "/api/local-folder/files/open";"#
|
||||||
|
));
|
||||||
|
assert!(html.contains("if (proxyOrigin && isLocalFolderFileOpen)"));
|
||||||
|
assert!(html.contains("if (proxyOrigin && (isLocal || url.searchParams.has(\"token\")))"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_state(legacy_next_base_url: Option<String>) -> AppState {
|
fn test_state(legacy_next_base_url: Option<String>) -> AppState {
|
||||||
|
|||||||
Reference in New Issue
Block a user