// MNote 主壳文件树运行时外置模块。 // 当前先承接 SIDEBAR_TREE_JS 中低风险的行数据解析 helper; // inline script 保留 fallback,避免模块加载顺序影响首屏行为。 function fileTreeRowKind(row) { if (!(row instanceof HTMLElement)) return ''; return String(row.getAttribute('data-row-kind') || '').trim(); } function fileTreeRowDocumentId(row) { if (!(row instanceof HTMLElement)) return ''; return String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim(); } function fileTreeRowAssetId(row, deps) { if (!(row instanceof HTMLElement)) return ''; var assetId = String(row.getAttribute('data-asset-id') || '').trim(); if (assetId) return assetId; var currentSourceKind = deps && typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; }; if (currentSourceKind() === 'local_folder' && fileTreeRowKind(row) === 'asset') { return String(row.getAttribute('data-row-id') || '').trim(); } return ''; } function decodeLocalEncodedPath(value) { var path = String(value || '').trim().replace(/~2F/g, '/'); if (!path) return ''; try { return decodeURIComponent(path); } catch (_) { return path; } } function fileTreeRowLocalRelativePath(row, deps) { if (!(row instanceof HTMLElement)) return ''; var direct = String(row.getAttribute('data-local-relative-path') || '').trim(); if (direct) return direct; var localFilePathFromAssetId = deps && typeof deps.localFilePathFromAssetId === 'function' ? deps.localFilePathFromAssetId : function() { return ''; }; var assetPath = localFilePathFromAssetId(fileTreeRowAssetId(row, deps)); if (assetPath) return assetPath; var rowId = String(row.getAttribute('data-row-id') || '').trim(); var nodeId = String(row.getAttribute('data-node-id') || '').trim(); var documentId = fileTreeRowDocumentId(row); var kind = fileTreeRowKind(row); if (rowId.indexOf('local:asset:') === 0) return rowId.slice('local:asset:'.length); if (rowId.indexOf('local:markdown:') === 0) return rowId.slice('local:markdown:'.length); if (rowId.indexOf('local:folder:') === 0) return rowId.slice('local:folder:'.length); if (rowId.indexOf('local:node:') === 0) return rowId.slice('local:node:'.length); if (nodeId.indexOf('local:node:') === 0) return nodeId.slice('local:node:'.length); if ((kind === 'document' || kind === 'doc' || kind === 'markdown') && documentId.indexOf('local-md:') === 0) { return decodeLocalEncodedPath(documentId.slice('local-md:'.length)); } if ((kind === 'folder' || kind === 'directory' || kind === 'index') && documentId.indexOf('local-dir:') === 0) { return decodeLocalEncodedPath(documentId.slice('local-dir:'.length)); } return ''; } function fileTreeRowLocalUploadTargetRelativePath(row, deps) { if (!(row instanceof HTMLElement)) return ''; var kind = fileTreeRowKind(row); var relativePath = fileTreeRowLocalRelativePath(row, deps); if (!relativePath) return ''; if (kind === 'folder' || kind === 'directory') return relativePath; var lastSlash = relativePath.lastIndexOf('/'); return lastSlash >= 0 ? relativePath.slice(0, lastSlash) : ''; } function isFileTreeDownloadableAssetRow(row, deps) { if (!(row instanceof HTMLElement)) return false; var kind = fileTreeRowKind(row); if (kind === 'document' || kind === 'doc' || kind === 'index' || kind === 'markdown' || kind === 'folder' || kind === 'directory') return false; return Boolean(fileTreeRowAssetId(row, deps)); } function isFileTreeDownloadableRow(row, deps) { if (!(row instanceof HTMLElement)) return false; var currentSourceKind = deps && typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; }; if (currentSourceKind() !== 'local_folder') return isFileTreeDownloadableAssetRow(row, deps); return Boolean(fileTreeRowLocalRelativePath(row, deps) || isFileTreeDownloadableAssetRow(row, deps)); } function fileTreeAssetDownloadDetail(row, deps) { if (!isFileTreeDownloadableRow(row, deps)) return null; var rowTitle = deps && typeof deps.rowTitle === 'function' ? deps.rowTitle : function() { return ''; }; var resolveWorkspaceId = deps && typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; }; var title = rowTitle(row); var relativePath = fileTreeRowLocalRelativePath(row, deps); var assetId = fileTreeRowAssetId(row, deps) || (relativePath ? 'local-file:' + relativePath : ''); return { contextKind: 'filetree', documentId: fileTreeRowDocumentId(row), rowId: row.getAttribute('data-row-id') || '', rowKind: fileTreeRowKind(row), assetId: assetId, localRelativePath: relativePath, title: title, fileName: title, workspaceId: resolveWorkspaceId(row) }; } function fileTreeRowsByRowIds(rowIds, deps) { var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); }; return (rowIds || []).map(function(rowId) { return document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(rowId) + '"]'); }).filter(function(row) { return row instanceof HTMLElement; }); } function fileTreeChildCount(documentId, deps) { if (!documentId) return 0; var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); }; var row = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + documentId) + '"]'); var node = row ? row.closest('.tree-node') : null; var children = node ? node.querySelectorAll(':scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"][data-row-kind="document"], :scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"][data-row-kind="doc"]') : []; return children.length; } function defaultEscapeHtml(value) { return String(value == null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function defaultObjectIdentityAttr(identity) { try { return JSON.stringify(identity || {}); } catch (_) { return ''; } } function revealFileTreeRow(row) { if (!(row instanceof HTMLElement)) return; var node = row.closest('.tree-node'); while (node && node.parentElement) { if (node.parentElement.classList && node.parentElement.classList.contains('tree-children')) { node.parentElement.classList.remove('tree-children--collapsed'); var parentNode = node.parentElement.closest('.tree-node'); var parentRow = parentNode ? parentNode.querySelector(':scope > .tree-row') : null; if (parentRow instanceof HTMLElement) { parentRow.setAttribute('aria-expanded', 'true'); var toggle = parentRow.querySelector('[data-rust-action="toggle"]'); if (toggle) toggle.setAttribute('aria-expanded', 'true'); } } node = node.parentElement.closest('.tree-node'); } try { row.scrollIntoView({ block: 'nearest' }); } catch (_) {} } function revealFileTreeAssetRow(assetId, deps) { if (!assetId) return false; var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); }; var row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(assetId) + '"]'); if (!(row instanceof HTMLElement)) return false; revealFileTreeRow(row); return true; } function appendUploadedAssetRow(asset, documentId, deps) { deps = deps || {}; var cssEscape = typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); }; var escapeHtml = typeof deps.escapeHtml === 'function' ? deps.escapeHtml : defaultEscapeHtml; var objectIdentityAttr = typeof deps.objectIdentityAttr === 'function' ? deps.objectIdentityAttr : defaultObjectIdentityAttr; var uploadedAssetTitle = typeof deps.uploadedAssetTitle === 'function' ? deps.uploadedAssetTitle : function(nextAsset) { return String(nextAsset && (nextAsset.file_name || nextAsset.title || nextAsset.name) || '未命名附件').trim() || '未命名附件'; }; var uploadedAssetType = typeof deps.uploadedAssetType === 'function' ? deps.uploadedAssetType : function(nextAsset) { return String(nextAsset && (nextAsset.asset_type || nextAsset.assetType || nextAsset.mime_type || '') || '').trim(); }; var fileTreeIconKindForFileName = typeof deps.fileTreeIconKindForFileName === 'function' ? deps.fileTreeIconKindForFileName : function() { return ''; }; var currentDocumentId = typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; }; var currentSourceKind = typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; }; var assetId = String(asset && asset.id || '').trim(); if (!assetId) return false; if (revealFileTreeAssetRow(assetId, { cssEscape: cssEscape })) return true; var objectKind = String(asset && (asset.objectKind || asset.resourceKind || '') || '').trim(); if (!objectKind && (String(asset && (asset.asset_type || asset.assetType) || '').trim() === 'mindmap' || /\.mindmap\.json$/i.test(assetId))) { objectKind = 'mindmap'; } var targetDocumentId = String(documentId || asset.document_id || asset.documentId || currentDocumentId() || '').trim(); var parentRow = targetDocumentId ? document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + targetDocumentId) + '"]') : null; if (!parentRow && currentSourceKind() === 'local_folder' && objectKind === 'mindmap') return false; if (!parentRow) parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-kind="document"]'); var root = document.querySelector('#sidebar-file-tree-root .tree-root'); if (!root && !parentRow) return false; var parentLi = parentRow ? parentRow.closest('.tree-node') : null; var children = parentLi ? parentLi.querySelector(':scope > .tree-children') : null; if (parentLi && !children) { children = document.createElement('ul'); children.className = 'tree-children'; parentLi.appendChild(children); } if (children) { children.classList.remove('tree-children--collapsed'); if (parentRow) { parentRow.setAttribute('aria-expanded', 'true'); var toggle = parentRow.querySelector('[data-rust-action="toggle"]'); if (toggle) toggle.setAttribute('aria-expanded', 'true'); } } var container = children || root; var li = document.createElement('li'); li.className = 'tree-node'; var objectIdentity = { objectKind: objectKind || 'attachment', documentId: targetDocumentId || null, blockId: null, assetId: assetId }; li.setAttribute('data-node-id', 'asset:' + assetId); var title = uploadedAssetTitle(asset); var iconKind = fileTreeIconKindForFileName(title) || uploadedAssetType(asset) || 'file'; if (objectKind === 'mindmap') iconKind = 'mindmap'; li.innerHTML = '