fix: 修复本地文件夹垃圾箱恢复聚焦
This commit is contained in:
@@ -60,6 +60,7 @@ pub(crate) struct RootEntryQuery {
|
||||
workspace_id: Option<String>,
|
||||
source_kind: Option<String>,
|
||||
root_uri: Option<String>,
|
||||
restore_focus_row_id: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn gateway_health(State(state): State<AppState>) -> Response {
|
||||
@@ -298,8 +299,16 @@ pub async fn root_entry(
|
||||
);
|
||||
let sidebar_tree_html =
|
||||
render_local_sidebar_tree_html(root_uri, selected_active_page_id.as_deref())?;
|
||||
let file_tree_html =
|
||||
render_local_file_tree_html(root_uri, selected_active_page_id.as_deref())?;
|
||||
let restore_focus_row_id = query
|
||||
.restore_focus_row_id
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty());
|
||||
let file_tree_html = render_local_file_tree_html(
|
||||
root_uri,
|
||||
selected_active_page_id.as_deref(),
|
||||
restore_focus_row_id,
|
||||
)?;
|
||||
(
|
||||
workspace_id,
|
||||
workspace_projection,
|
||||
@@ -353,7 +362,7 @@ pub async fn root_entry(
|
||||
let sidebar_tree_html =
|
||||
render_local_sidebar_tree_html(&root_uri, selected_active_page_id.as_deref())?;
|
||||
let file_tree_html =
|
||||
render_local_file_tree_html(&root_uri, selected_active_page_id.as_deref())?;
|
||||
render_local_file_tree_html(&root_uri, selected_active_page_id.as_deref(), None)?;
|
||||
(
|
||||
workspace_id,
|
||||
workspace_projection,
|
||||
@@ -567,7 +576,7 @@ pub async fn trash_entry(
|
||||
let workspace_id =
|
||||
crate::routes::local_folder_source::local_workspace_id_from_root_uri(root_uri)?;
|
||||
let sidebar_tree_html = render_local_sidebar_tree_html(root_uri, None).unwrap_or_default();
|
||||
let file_tree_html = render_local_file_tree_html(root_uri, None).unwrap_or_default();
|
||||
let file_tree_html = render_local_file_tree_html(root_uri, None, None).unwrap_or_default();
|
||||
let workspace_projection = build_workspace_shell_projection(
|
||||
&json!({
|
||||
"active_workspace_id": workspace_id,
|
||||
@@ -944,8 +953,15 @@ fn render_local_trash_workbench_html(
|
||||
let original = escape_html(&entry.original_relative_path);
|
||||
let trash_path = escape_html(&entry.trash_relative_path);
|
||||
let kind = escape_html(&entry.resource_kind);
|
||||
let filetree_row_id = if entry.resource_kind == "markdown"
|
||||
|| entry.resource_kind == "markdown_bundle"
|
||||
{
|
||||
format!("doc:{}", entry.document_id)
|
||||
} else {
|
||||
format!("local:asset:{}", entry.original_relative_path)
|
||||
};
|
||||
let row = format!(
|
||||
r#"<article class="mnote-trash-row" data-trash-row="local" data-trash-entry-id="{entry_id}" data-resource-kind="{kind}">
|
||||
r#"<article class="mnote-trash-row" data-trash-row="local" data-trash-entry-id="{entry_id}" data-resource-kind="{kind}" data-filetree-row-id="{filetree_row_id}">
|
||||
<div class="mnote-trash-row-main">
|
||||
<span class="mnote-trash-kind">{kind}</span>
|
||||
<span class="mnote-trash-title">{original}</span>
|
||||
@@ -958,6 +974,7 @@ fn render_local_trash_workbench_html(
|
||||
</article>"#,
|
||||
entry_id = escape_html(entry_id),
|
||||
kind = kind,
|
||||
filetree_row_id = escape_html(&filetree_row_id),
|
||||
original = original,
|
||||
trash_path = trash_path,
|
||||
deleted_at = escape_html(&deleted_at),
|
||||
@@ -1062,6 +1079,16 @@ fn render_local_trash_workbench_html(
|
||||
workspaceId: workspaceId,
|
||||
documentId: entryId
|
||||
}}).then(function() {{
|
||||
if (action === 'local-restore') {{
|
||||
var row = button.closest('[data-trash-row="local"]');
|
||||
var filetreeRowId = row ? (row.getAttribute('data-filetree-row-id') || '') : '';
|
||||
if (filetreeRowId && window.localStorage) {{
|
||||
window.localStorage.setItem('mnote.pendingLocalFolderRestoreFiletreeRowId', filetreeRowId);
|
||||
}}
|
||||
if (filetreeRowId) {{
|
||||
window.name = 'mnote.pendingLocalFolderRestoreFiletreeRowId=' + encodeURIComponent(filetreeRowId);
|
||||
}}
|
||||
}}
|
||||
return refresh();
|
||||
}}).then(function() {{
|
||||
setStatus(action === 'local-restore' ? '已恢复项目' : '已彻底删除项目', false);
|
||||
@@ -2223,6 +2250,8 @@ mod tests {
|
||||
assert!(html.contains("Deleted"));
|
||||
assert!(html.contains(r#"data-trash-action="local-restore""#));
|
||||
assert!(html.contains(r#"data-trash-action="local-purge""#));
|
||||
assert!(html.contains(r#"data-filetree-row-id="doc:local-md:Deleted~2FDeleted.md""#));
|
||||
assert!(html.contains("mnote.pendingLocalFolderRestoreFiletreeRowId"));
|
||||
assert!(html.contains(r#"data-trash-action="local-empty-documents""#));
|
||||
assert!(html.contains(r#"data-trash-action="local-empty-resources" disabled"#));
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ pub async fn mindmap_object_shell(
|
||||
let sidebar_tree_html =
|
||||
render_local_sidebar_tree_html(root_uri, Some(&doc_id)).unwrap_or_default();
|
||||
let file_tree_html =
|
||||
render_local_file_tree_html(root_uri, Some(&doc_id)).unwrap_or_default();
|
||||
render_local_file_tree_html(root_uri, Some(&doc_id), None).unwrap_or_default();
|
||||
let workspace_projection = load_workspace_shell_projection(
|
||||
state.config(),
|
||||
&context,
|
||||
|
||||
@@ -125,7 +125,7 @@ pub async fn document_page_shell(
|
||||
let root_uri = query.root_uri.as_deref().unwrap_or_default();
|
||||
(
|
||||
render_local_sidebar_tree_html(root_uri, Some(&document_id)).unwrap_or_default(),
|
||||
render_local_file_tree_html(root_uri, Some(&document_id)).unwrap_or_default(),
|
||||
render_local_file_tree_html(root_uri, Some(&document_id), None).unwrap_or_default(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
@@ -4446,9 +4446,10 @@ pub(crate) fn render_local_sidebar_tree_html(
|
||||
pub(crate) fn render_local_file_tree_html(
|
||||
root_uri: &str,
|
||||
active_document_id: Option<&str>,
|
||||
active_row_id: Option<&str>,
|
||||
) -> Result<String, WebError> {
|
||||
let snapshot = load_local_folder_file_tree_snapshot(root_uri)?;
|
||||
let rows = collect_filetree_render_rows(&snapshot.projection, active_document_id, None);
|
||||
let rows = collect_filetree_render_rows(&snapshot.projection, active_document_id, active_row_id);
|
||||
Ok(render_initial_filetree_html(&FileTreeInitialRenderInput {
|
||||
rows,
|
||||
}))
|
||||
|
||||
@@ -127,6 +127,8 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
function currentFileTreeActiveRowId() {
|
||||
var explicitRowId = new URL(window.location.href).searchParams.get('restoreFocusRowId') || '';
|
||||
if (explicitRowId) return explicitRowId;
|
||||
var mindmapMatch = window.location.pathname.match(/^\/mindmap\/([^\/]+)\/([^\/]+)/);
|
||||
if (mindmapMatch) return 'asset:' + decodeURIComponent(mindmapMatch[2]);
|
||||
var documentId = currentDocumentId();
|
||||
@@ -1983,6 +1985,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
var renderedFile = filePayload ? renderFileProjection(filePayload.result || filePayload) : false;
|
||||
if (!renderedPage && !renderedFile) return false;
|
||||
syncSidebarFileTreeSelection();
|
||||
schedulePendingLocalFolderRestoreFocus();
|
||||
restoreSidebarTreeTab();
|
||||
document.documentElement.setAttribute('data-mnote-local-folder-watch-applied', 'projection');
|
||||
return true;
|
||||
@@ -4159,6 +4162,86 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
return true;
|
||||
}
|
||||
|
||||
function selectSidebarFileTreeRowById(rowId, options) {
|
||||
var id = String(rowId || '').trim();
|
||||
if (!id) return false;
|
||||
var row = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(id) + '"]');
|
||||
if (!(row instanceof HTMLElement)) return false;
|
||||
selectSidebarFileTreeRow(row, { ctrlKey: false, metaKey: false, shiftKey: false });
|
||||
document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-active="true"]').forEach(function(activeRow) {
|
||||
if (activeRow instanceof HTMLElement) activeRow.setAttribute('data-active', 'false');
|
||||
});
|
||||
row.setAttribute('data-active', 'true');
|
||||
if (options && options.scrollIntoView !== false) {
|
||||
try {
|
||||
row.scrollIntoView({ block: 'nearest' });
|
||||
} catch (_) {
|
||||
row.scrollIntoView();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function pendingLocalFolderRestoreRowId() {
|
||||
if (window.__mnotePendingLocalFolderRestoreFiletreeRowId) {
|
||||
return String(window.__mnotePendingLocalFolderRestoreFiletreeRowId || '').trim();
|
||||
}
|
||||
if (!window.localStorage) return '';
|
||||
var rowId = '';
|
||||
try {
|
||||
rowId = String(window.localStorage.getItem('mnote.pendingLocalFolderRestoreFiletreeRowId') || '').trim();
|
||||
} catch (_) {
|
||||
rowId = '';
|
||||
}
|
||||
if (!rowId && typeof window.name === 'string' && window.name.indexOf('mnote.pendingLocalFolderRestoreFiletreeRowId=') === 0) {
|
||||
rowId = decodeURIComponent(window.name.slice('mnote.pendingLocalFolderRestoreFiletreeRowId='.length));
|
||||
}
|
||||
if (rowId) window.__mnotePendingLocalFolderRestoreFiletreeRowId = rowId;
|
||||
return rowId;
|
||||
}
|
||||
|
||||
function clearPendingLocalFolderRestoreRowId() {
|
||||
window.__mnotePendingLocalFolderRestoreFiletreeRowId = '';
|
||||
try {
|
||||
window.localStorage.removeItem('mnote.pendingLocalFolderRestoreFiletreeRowId');
|
||||
} catch (_) {}
|
||||
if (typeof window.name === 'string' && window.name.indexOf('mnote.pendingLocalFolderRestoreFiletreeRowId=') === 0) {
|
||||
window.name = '';
|
||||
}
|
||||
}
|
||||
|
||||
function applyPendingLocalFolderRestoreFocusOnce() {
|
||||
var rowId = pendingLocalFolderRestoreRowId();
|
||||
if (!rowId) return false;
|
||||
document.documentElement.setAttribute('data-mnote-local-folder-restore-pending-row-id', rowId);
|
||||
if (!selectSidebarFileTreeRowById(rowId, { scrollIntoView: true })) {
|
||||
document.documentElement.setAttribute('data-mnote-local-folder-restore-focus-status', 'row-missing');
|
||||
return false;
|
||||
}
|
||||
document.documentElement.setAttribute('data-mnote-local-folder-restore-focused-row-id', rowId);
|
||||
document.documentElement.setAttribute('data-mnote-local-folder-restore-focus-status', 'focused');
|
||||
return true;
|
||||
}
|
||||
|
||||
function schedulePendingLocalFolderRestoreFocus() {
|
||||
if (!pendingLocalFolderRestoreRowId()) return false;
|
||||
if (window.__mnotePendingLocalFolderRestoreFocusTimer) return false;
|
||||
var attempts = 0;
|
||||
var focused = false;
|
||||
focused = applyPendingLocalFolderRestoreFocusOnce() || focused;
|
||||
window.__mnotePendingLocalFolderRestoreFocusTimer = window.setInterval(function() {
|
||||
attempts += 1;
|
||||
focused = applyPendingLocalFolderRestoreFocusOnce() || focused;
|
||||
if (attempts >= 20) {
|
||||
if (focused) clearPendingLocalFolderRestoreRowId();
|
||||
else document.documentElement.setAttribute('data-mnote-local-folder-restore-focus-status', 'timeout');
|
||||
window.clearInterval(window.__mnotePendingLocalFolderRestoreFocusTimer);
|
||||
window.__mnotePendingLocalFolderRestoreFocusTimer = 0;
|
||||
}
|
||||
}, 250);
|
||||
return focused;
|
||||
}
|
||||
|
||||
function selectedSidebarFileTreeRowIdsForDrag(row) {
|
||||
var rowId = row instanceof HTMLElement ? row.getAttribute('data-row-id') || '' : '';
|
||||
if (rowId && sidebarFileTreeSelection.selectedRowIds.has(rowId)) {
|
||||
@@ -9273,6 +9356,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
sidebarFileTreeSelection.focusedRowId = rowId;
|
||||
});
|
||||
syncSidebarFileTreeSelection();
|
||||
schedulePendingLocalFolderRestoreFocus();
|
||||
window.addEventListener('mnote:primary-document-activated', function(event) {
|
||||
var detail = event && event.detail ? event.detail : {};
|
||||
selectSidebarFileTreeDocument(detail.documentId, { scrollIntoView: false });
|
||||
@@ -9910,6 +9994,13 @@ mod tests {
|
||||
assert!(SIDEBAR_TREE_JS.contains("wolai:local-assets-changed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sidebar_tree_runtime_focuses_restored_local_folder_row() {
|
||||
assert!(SIDEBAR_TREE_JS.contains("applyPendingLocalFolderRestoreFocusOnce"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("mnote.pendingLocalFolderRestoreFiletreeRowId"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("data-mnote-local-folder-restore-focused-row-id"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sidebar_runtime_routes_local_mindmap_and_office_assets() {
|
||||
assert!(SIDEBAR_TREE_JS.contains("withLocalMindmapSourceParams"));
|
||||
|
||||
Reference in New Issue
Block a user