export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => { const { activeSidebarTreeMode, cssEscape, currentDocumentId, currentFileTreeActiveRowId, currentRootUri, currentSourceKind, currentWorkspaceId, escapeHtml, fileTreeRuntimeFunction, localFilePathFromAssetId, navigateToDocument, refreshEditorLocalAttachmentExistence, restoreSidebarTreeTab, rowTitle, schedulePendingLocalFolderRestoreFocus, shortMindmapFileName, syncSidebarFileTreeSelection, } = dependencies; function updateTitleEverywhere(documentId, title) { if (!documentId) return; var escaped = cssEscape(documentId); var escapedDocRowId = cssEscape('doc:' + documentId); var isCurrentDocument = currentDocumentId() === documentId; var pageSelectors = [ '.tree-row[data-shell-mode="page"][data-node-id="' + escaped + '"] > .tree-link > .tree-link-title', '.wolai-page-row[data-node-id="' + escaped + '"] > .wolai-row-title', 'a[href="/documents/' + escaped + '"] > .wolai-row-title', 'a[href^="/documents/' + escaped + '?"] > .wolai-row-title' ]; pageSelectors.forEach(function(selector) { document.querySelectorAll(selector).forEach(function(node) { if (node instanceof HTMLElement) node.textContent = title; }); }); document.querySelectorAll('.tree-row[data-shell-mode="filetree"][data-row-id="' + escapedDocRowId + '"] > .tree-link > .tree-link-title').forEach(function(node) { if (node instanceof HTMLElement) node.textContent = fileTreePageTitle(title); }); document.querySelectorAll('[data-page-title-input="true"][data-document-id="' + escaped + '"]').forEach(function(node) { if (!(node instanceof HTMLTextAreaElement)) return; node.value = title; node.setAttribute('data-title-last-saved', title); node.setAttribute('data-title-save-status', 'saved'); node.style.height = 'auto'; node.style.height = Math.max(48, node.scrollHeight) + 'px'; }); document.querySelectorAll('[data-document-pane="true"][data-pane-document-id="' + escaped + '"] [data-page-title-current="true"]').forEach(function(node) { if (node instanceof HTMLElement) node.textContent = title; }); if (isCurrentDocument) { document.title = title; var topbarCurrent = document.querySelector('.wolai-breadcrumb-current [data-page-title-current]'); if (topbarCurrent instanceof HTMLElement) topbarCurrent.textContent = title; } } function fileTreePageTitle(title) { var normalized = String(title || '无标题').trim() || '无标题'; return normalized.endsWith('.md') ? normalized : normalized + '.md'; } function isFileTreePageRow(row) { if (!(row instanceof HTMLElement)) return false; if (row.getAttribute('data-asset-id')) return false; var rowKind = row.getAttribute('data-row-kind') || ''; return rowKind === 'document' || rowKind === 'doc' || rowKind === 'index' || rowKind === 'markdown'; } function normalizeFileTreePageRenameTitle(value) { var normalized = String(value || '').trim(); if (/\.md$/i.test(normalized)) normalized = normalized.slice(0, -3).trim(); return normalized; } function validateFileTreeRename(row, draft) { var raw = String(draft || '').trim(); if (!raw) return '名称不能为空'; if (/[\\/:*?"<>|]/.test(raw)) return '文件名不能包含 / \\ : * ? " < > |'; if (!isFileTreePageRow(row)) return ''; var pageTitle = normalizeFileTreePageRenameTitle(raw); if (!pageTitle) return '名称不能为空'; var expectedFileName = fileTreePageTitle(pageTitle).toLocaleLowerCase(); var rowId = row.getAttribute('data-row-id') || ''; var parentId = row.getAttribute('data-parent-id') || ''; var siblings = Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-kind="document"], #sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-kind="doc"], #sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-kind="markdown"]')); var duplicate = siblings.some(function(sibling) { if (!(sibling instanceof HTMLElement)) return false; if ((sibling.getAttribute('data-row-id') || '') === rowId) return false; if ((sibling.getAttribute('data-parent-id') || '') !== parentId) return false; return fileTreePageTitle(normalizeFileTreePageRenameTitle(rowTitle(sibling))).toLocaleLowerCase() === expectedFileName; }); return duplicate ? '同级已存在同名页面' : ''; } function documentIdFromDelta(data) { return String(data && (data.documentId || data.id || (data.document && data.document.id) || (data.node && data.node.id) || (data.args && data.args.documentId)) || '').trim(); } function parentIdFromDelta(data) { if (!data || typeof data !== 'object') return null; if (Object.prototype.hasOwnProperty.call(data, 'parentId')) return data.parentId ? String(data.parentId).trim() : null; if (Object.prototype.hasOwnProperty.call(data, 'parent_id')) return data.parent_id ? String(data.parent_id).trim() : null; if (data.args && Object.prototype.hasOwnProperty.call(data.args, 'parentId')) return data.args.parentId ? String(data.args.parentId).trim() : null; return null; } function treeRootForMode(mode) { var id = mode === 'filetree' ? 'sidebar-file-tree-root' : 'sidebar-tree-root'; return document.querySelector('#' + id + ' .tree-root'); } function rowSelectorForDocument(mode, documentId) { var escaped = cssEscape(documentId); if (mode === 'filetree') { return '.tree-row[data-shell-mode="filetree"][data-doc-id="' + escaped + '"], .tree-row[data-shell-mode="filetree"][data-document-id="' + escaped + '"]'; } return '.tree-row[data-shell-mode="page"][data-node-id="' + escaped + '"]'; } function ensureTreeChildren(parentRow) { var parentNode = parentRow ? parentRow.closest('.tree-node') : null; if (!parentNode) return null; var children = parentNode.querySelector(':scope > .tree-children'); if (!children) { children = document.createElement('ul'); children.className = 'tree-children'; parentNode.appendChild(children); } children.classList.remove('tree-children--collapsed'); parentRow.setAttribute('aria-expanded', 'true'); var toggle = parentRow.querySelector('[data-rust-action="toggle"]'); if (toggle) toggle.setAttribute('aria-expanded', 'true'); return children; } function removeDocumentRowForMode(mode, documentId) { var row = document.querySelector(rowSelectorForDocument(mode, documentId)); var node = row ? row.closest('.tree-node') : null; if (!node || !node.parentElement) return false; node.parentElement.removeChild(node); return true; } function commandDocumentId(result, fallback) { var value = result && ( (result.execution && (result.execution.documentId || result.execution.id || result.execution.nodeId)) || 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.execution && result.execution.title) || 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 depth = localFileInsertDepth(parentId); var grouped = new Map(); grouped.set(parentNodeId, [{ id: docNodeId, nodeId: docNodeId, rowId: docNodeId, rowKind: 'document', title: fileTreePageTitle(title), documentId: documentId, parentNodeId: parentNodeId, depth: depth, 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 localCommandNeedsProjectionRefresh(action, result) { if (currentSourceKind() !== 'local_folder') return false; if (action === 'create' || action === 'rename' || action === 'move' || action === 'delete' || action === 'archive' || action === 'trash' || action === 'purge') { return true; } if (result && (result.previousDocumentId || result.previousRelativePath || result.relativePath || result.trashPath)) { return true; } return false; } function sortOrderFromDelta(data) { var raw = data && (data.sortOrder ?? data.sort_order); var value = Number(raw); return Number.isFinite(value) && value >= 0 ? Math.floor(value) : null; } function insertTreeNodeAtSortOrder(targetContainer, node, sortOrder) { if (!targetContainer || !node) return false; if (sortOrder === null || sortOrder === undefined) { targetContainer.appendChild(node); return true; } var siblings = Array.from(targetContainer.querySelectorAll(':scope > .tree-node')).filter(function(candidate) { return candidate !== node; }); var targetIndex = Math.max(0, Math.min(Number(sortOrder), siblings.length)); var referenceNode = siblings[targetIndex] || null; if (referenceNode) targetContainer.insertBefore(node, referenceNode); else targetContainer.appendChild(node); return true; } function moveDocumentRowForMode(mode, documentId, parentId, sortOrder) { var row = document.querySelector(rowSelectorForDocument(mode, documentId)); var node = row ? row.closest('.tree-node') : null; var root = treeRootForMode(mode); if (!row || !node || !root) return false; var targetContainer = root; if (parentId) { var parentRow = document.querySelector(rowSelectorForDocument(mode, parentId)); targetContainer = ensureTreeChildren(parentRow); if (!targetContainer) return false; row.setAttribute('data-parent-id', parentId); } else { row.removeAttribute('data-parent-id'); } return insertTreeNodeAtSortOrder(targetContainer, node, sortOrder); } function applyMoveDocumentDelta(data) { var documentId = documentIdFromDelta(data); if (!documentId) return false; var parentId = parentIdFromDelta(data); var sortOrder = sortOrderFromDelta(data); var movedPage = moveDocumentRowForMode('page', documentId, parentId, sortOrder); var movedFile = moveDocumentRowForMode('filetree', documentId, parentId, sortOrder); return movedPage || movedFile; } function applyRemoveDocumentDelta(data) { var documentId = documentIdFromDelta(data); if (!documentId) return false; var removedPage = removeDocumentRowForMode('page', documentId); var removedFile = removeDocumentRowForMode('filetree', documentId); return removedPage || removedFile; } function readProjection(value) { var runtimeFn = fileTreeRuntimeFunction('readProjection'); if (runtimeFn) return runtimeFn(value); if (!value || typeof value !== 'object') return null; if (value.result && typeof value.result === 'object') return value.result; if (value.snapshot && value.snapshot.tree) return value.snapshot.tree; if (value.data && value.data.tree) return value.data.tree; if (value.tree && typeof value.tree === 'object') return value.tree; return value; } function readSidebarDataset(value) { var runtimeFn = fileTreeRuntimeFunction('readSidebarDataset'); if (runtimeFn) return runtimeFn(value); if (!value || typeof value !== 'object') return null; if (value.snapshot && value.snapshot.dataset && typeof value.snapshot.dataset === 'object') return value.snapshot.dataset; if (value.data && value.data.dataset && typeof value.data.dataset === 'object') return value.data.dataset; if (value.dataset && typeof value.dataset === 'object') return value.dataset; if (value.sidebar && typeof value.sidebar === 'object') return value.sidebar; return null; } function readDatasetProjection(value, snakeCaseKey, camelCaseKey) { var runtimeFn = fileTreeRuntimeFunction('readDatasetProjection'); if (runtimeFn) return runtimeFn(value, snakeCaseKey, camelCaseKey); var dataset = readSidebarDataset(value); if (!dataset || typeof dataset !== 'object') return null; if (dataset[snakeCaseKey] && typeof dataset[snakeCaseKey] === 'object') return dataset[snakeCaseKey]; if (dataset[camelCaseKey] && typeof dataset[camelCaseKey] === 'object') return dataset[camelCaseKey]; return null; } function setTreeLiveApplyError(reason) { document.documentElement.setAttribute('data-mnote-tree-live-apply-error', String(reason || 'tree_live_apply_failed')); } function projectionItems(projection) { var runtimeFn = fileTreeRuntimeFunction('projectionItems'); if (runtimeFn) return runtimeFn(projection); var resolved = readProjection(projection); return resolved && Array.isArray(resolved.items) ? resolved.items : []; } function hasProjectionItems(projection) { var runtimeFn = fileTreeRuntimeFunction('hasProjectionItems'); if (runtimeFn) return runtimeFn(projection); var resolved = readProjection(projection); return Boolean(resolved && Array.isArray(resolved.items)); } function nodeIdOf(item) { var runtimeFn = fileTreeRuntimeFunction('nodeIdOf'); if (runtimeFn) return runtimeFn(item); return String(item && (item.nodeId || item.id || item.documentId) || '').trim(); } function rowIdOf(item) { var runtimeFn = fileTreeRuntimeFunction('rowIdOf'); if (runtimeFn) return runtimeFn(item); return String(item && (item.rowId || item.nodeId || item.id) || '').trim(); } function parentIdOf(item) { var runtimeFn = fileTreeRuntimeFunction('parentIdOf'); if (runtimeFn) return runtimeFn(item); return String(item && (item.parentNodeId || item.parentId || '') || '').trim(); } function titleOf(item) { var runtimeFn = fileTreeRuntimeFunction('titleOf'); if (runtimeFn) return runtimeFn(item); return String(item && item.title || '无标题').trim() || '无标题'; } function fileWorkspaceRelativePath(item) { var runtimeFn = fileTreeRuntimeFunction('fileWorkspaceRelativePath'); if (runtimeFn) return runtimeFn(item); var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {}; var workspacePath = meta.workspacePath && typeof meta.workspacePath === 'object' ? meta.workspacePath : {}; var fromWorkspacePath = String(workspacePath.relativePath || '').trim(); if (fromWorkspacePath) return fromWorkspacePath; var extra = meta.extra && typeof meta.extra === 'object' ? meta.extra : {}; var source = extra.source && typeof extra.source === 'object' ? extra.source : {}; var fromSource = String(source.relativePath || '').trim(); if (fromSource) return fromSource; return String(item && (item.relativePath || item.rootRelativePath) || '').trim(); } function groupRowsByParent(rows) { var runtimeFn = fileTreeRuntimeFunction('groupRowsByParent'); if (runtimeFn) return runtimeFn(rows); var ids = new Set(rows.map(nodeIdOf).filter(Boolean)); var grouped = new Map(); rows.forEach(function(item) { var parentId = parentIdOf(item); if (!ids.has(parentId)) parentId = ''; if (!grouped.has(parentId)) grouped.set(parentId, []); grouped.get(parentId).push(item); }); return grouped; } function pageTreeChevronSvg() { return ''; } function renderPageRows(parentId, grouped, activeId, inheritedDepth) { var computedDepth = Number(inheritedDepth || 0); return (grouped.get(parentId) || []).map(function(item) { var nodeId = nodeIdOf(item); var title = titleOf(item); var depth = computedDepth; var parent = parentIdOf(item); var children = grouped.get(nodeId) || []; var expandable = Boolean(item.expandable || item.childCount > 0 || children.length); var expanded = expandable && item.expandedByDefault !== false; var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {}; var openable = Boolean(meta.documentId || item.documentId || !String(nodeId).startsWith('local-dir:')); var toggle = expandable ? '' : ''; var childHtml = expandable ? '
' : ''; var currentAttr = nodeId === activeId ? ' aria-current="page" aria-selected="true"' : ' aria-selected="false"'; return '