fix(mnote-web): 主文档壳本地应用树命令
This commit is contained in:
@@ -856,6 +856,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
throw new Error((payload && payload.message) || 'tree_command_failed_' + response.status);
|
||||
}
|
||||
window.dispatchEvent(new CustomEvent('tree:local-command', { detail: { body: commandBody, result: payload.result } }));
|
||||
setCommandPending(trigger, false);
|
||||
return payload.result;
|
||||
} catch (error) {
|
||||
setCommandPending(trigger, false);
|
||||
@@ -1033,6 +1034,152 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
return true;
|
||||
}
|
||||
|
||||
function commandDocumentId(result, fallback) {
|
||||
var value = result && (
|
||||
result.documentId ||
|
||||
result.id ||
|
||||
result.nodeId ||
|
||||
(result.document && (result.document.id || result.document.documentId)) ||
|
||||
(result.node && (result.node.id || result.node.documentId)) ||
|
||||
(result.payload && result.payload.documentId)
|
||||
);
|
||||
return String(value || fallback || '').trim();
|
||||
}
|
||||
|
||||
function commandDocumentTitle(result, fallback) {
|
||||
var value = result && (
|
||||
result.title ||
|
||||
(result.document && result.document.title) ||
|
||||
(result.node && result.node.title) ||
|
||||
(result.payload && result.payload.title)
|
||||
);
|
||||
return String(value || fallback || '新页面').trim() || '新页面';
|
||||
}
|
||||
|
||||
function normalizeDocumentRowId(value) {
|
||||
return String(value || '').trim().replace(/^doc:/, '').replace(/^index:/, '');
|
||||
}
|
||||
|
||||
function appendRenderedTreeNode(container, html) {
|
||||
if (!container || !html) return false;
|
||||
var empty = container.querySelector(':scope > .tree-empty');
|
||||
if (empty && empty.parentElement) empty.parentElement.removeChild(empty);
|
||||
var template = document.createElement('template');
|
||||
template.innerHTML = html;
|
||||
var node = template.content.firstElementChild;
|
||||
if (!node) return false;
|
||||
container.appendChild(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
function localPageInsertDepth(parentId) {
|
||||
if (!parentId) return 0;
|
||||
var parentRow = document.querySelector(rowSelectorForDocument('page', parentId));
|
||||
var depth = parentRow ? Number(parentRow.getAttribute('data-depth') || 0) : 0;
|
||||
return Number.isFinite(depth) ? depth + 1 : 1;
|
||||
}
|
||||
|
||||
function upsertPageDocumentRow(documentId, parentId, title) {
|
||||
if (!documentId) return false;
|
||||
var existing = document.querySelector(rowSelectorForDocument('page', documentId));
|
||||
if (existing instanceof HTMLElement) {
|
||||
updateTitleEverywhere(documentId, title);
|
||||
moveDocumentRowForMode('page', documentId, parentId || null);
|
||||
return true;
|
||||
}
|
||||
var root = treeRootForMode('page');
|
||||
if (!root) return false;
|
||||
var targetContainer = root;
|
||||
if (parentId) {
|
||||
var parentRow = document.querySelector(rowSelectorForDocument('page', parentId));
|
||||
targetContainer = ensureTreeChildren(parentRow);
|
||||
if (!targetContainer) targetContainer = root;
|
||||
}
|
||||
var grouped = new Map();
|
||||
grouped.set(parentId || '', [{
|
||||
id: documentId,
|
||||
nodeId: documentId,
|
||||
documentId: documentId,
|
||||
parentNodeId: parentId || '',
|
||||
rowKind: 'document',
|
||||
title: title,
|
||||
expandable: false,
|
||||
childCount: 0
|
||||
}]);
|
||||
return appendRenderedTreeNode(targetContainer, renderPageRows(parentId || '', grouped, currentDocumentId(), localPageInsertDepth(parentId)));
|
||||
}
|
||||
|
||||
function fileTreeParentContainer(parentId) {
|
||||
var root = treeRootForMode('filetree');
|
||||
if (!root) return null;
|
||||
if (!parentId) return root;
|
||||
var parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + parentId) + '"]');
|
||||
var children = ensureTreeChildren(parentRow);
|
||||
return children || root;
|
||||
}
|
||||
|
||||
function localFileInsertDepth(parentId) {
|
||||
if (!parentId) return 0;
|
||||
var parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + parentId) + '"]');
|
||||
var level = parentRow ? Number(parentRow.getAttribute('aria-level') || 1) : 1;
|
||||
return Number.isFinite(level) ? level : 1;
|
||||
}
|
||||
|
||||
function upsertFileDocumentRows(documentId, parentId, title) {
|
||||
if (!documentId) return false;
|
||||
var existing = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + documentId) + '"]');
|
||||
if (existing instanceof HTMLElement) {
|
||||
updateTitleEverywhere(documentId, title);
|
||||
moveDocumentRowForMode('filetree', documentId, parentId || null);
|
||||
return true;
|
||||
}
|
||||
var targetContainer = fileTreeParentContainer(parentId);
|
||||
if (!targetContainer) return false;
|
||||
var parentNodeId = parentId ? 'doc:' + parentId : '';
|
||||
var docNodeId = 'doc:' + documentId;
|
||||
var indexNodeId = 'index:' + documentId;
|
||||
var depth = localFileInsertDepth(parentId);
|
||||
var grouped = new Map();
|
||||
grouped.set(parentNodeId, [{
|
||||
id: docNodeId,
|
||||
nodeId: docNodeId,
|
||||
rowId: docNodeId,
|
||||
rowKind: 'document',
|
||||
title: title,
|
||||
documentId: documentId,
|
||||
parentNodeId: parentNodeId,
|
||||
depth: depth,
|
||||
expandable: true,
|
||||
childCount: 1
|
||||
}]);
|
||||
grouped.set(docNodeId, [{
|
||||
id: indexNodeId,
|
||||
nodeId: indexNodeId,
|
||||
rowId: indexNodeId,
|
||||
rowKind: 'index',
|
||||
title: 'index.md',
|
||||
documentId: documentId,
|
||||
parentNodeId: docNodeId,
|
||||
depth: depth + 1,
|
||||
expandable: false,
|
||||
childCount: 0
|
||||
}]);
|
||||
return appendRenderedTreeNode(targetContainer, renderFileRows(parentNodeId, grouped, currentDocumentId()));
|
||||
}
|
||||
|
||||
function applyCreatedDocumentLocally(result, parentId, fallbackTitle) {
|
||||
var documentId = commandDocumentId(result, null);
|
||||
if (!documentId) return false;
|
||||
var normalizedParentId = normalizeDocumentRowId(parentId);
|
||||
var title = commandDocumentTitle(result, fallbackTitle);
|
||||
var pageChanged = upsertPageDocumentRow(documentId, normalizedParentId, title);
|
||||
var fileChanged = upsertFileDocumentRows(documentId, normalizedParentId, title);
|
||||
if (pageChanged || fileChanged) {
|
||||
document.documentElement.setAttribute('data-mnote-tree-local-command-applied', 'create');
|
||||
}
|
||||
return pageChanged || fileChanged;
|
||||
}
|
||||
|
||||
function moveDocumentRowForMode(mode, documentId, parentId) {
|
||||
var row = document.querySelector(rowSelectorForDocument(mode, documentId));
|
||||
var node = row ? row.closest('.tree-node') : null;
|
||||
@@ -4109,6 +4256,21 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
document.documentElement.setAttribute('data-mnote-title-local-applied', 'true');
|
||||
});
|
||||
|
||||
window.addEventListener('tree:local-command', function(event) {
|
||||
var detail = event.detail || {};
|
||||
var body = detail.body || {};
|
||||
var action = String(body.action || '').trim();
|
||||
if (action === 'create') {
|
||||
applyCreatedDocumentLocally(detail.result || {}, body.parentId || null, body.title || '新页面');
|
||||
return;
|
||||
}
|
||||
if ((action === 'purge' || action === 'delete' || action === 'archive') && body.documentId) {
|
||||
if (applyRemoveDocumentDelta({ documentId: body.documentId })) {
|
||||
document.documentElement.setAttribute('data-mnote-tree-local-command-applied', 'remove');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('tree:snapshot', function(event) {
|
||||
var payload = event.detail && event.detail.payload ? event.detail.payload : event.detail;
|
||||
if (renderSidebarSnapshot(payload)) {
|
||||
@@ -4448,6 +4610,10 @@ mod tests {
|
||||
assert!(SIDEBAR_TREE_JS.contains("data-global-option-checkbox=\"showHeadingNumbers\""));
|
||||
assert!(SIDEBAR_TREE_JS.contains("restoreSidebarTreeTab"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("treeView"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("tree:local-command"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("applyCreatedDocumentLocally"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("data-mnote-tree-local-command-applied', 'create"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("data-mnote-tree-local-command-applied', 'remove"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("application/x-mnote-page-tree-node"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("dragstart"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("drop"));
|
||||
|
||||
Reference in New Issue
Block a user