export const createSidebarFileTreeOpenRuntime = (dependencies = {}) => { const { copyWorkspaceSourceParams, currentDocumentId, currentRootUri, currentSourceKind, fileTreeIconKindForFileName, getNavigationInFlight, isCodeAttachmentFileName, isNonOfficeAttachmentName, isPdfAttachmentFileName, openCodeEditorAttachment, resolveWorkspaceId, setNavigationInFlight, shouldOpenLocalResourceInNewWindow, uploadedFileSize, } = dependencies; const currentSourceKindFn = typeof currentSourceKind === 'function' ? currentSourceKind : function() { return ''; }; function inferOnlyOfficeFileType(fileName, mimeType) { var name = String(fileName || '').trim().toLowerCase(); var mt = String(mimeType || '').trim().toLowerCase(); var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : ''; if (['doc', 'docx', 'odt', 'rtf'].indexOf(ext) >= 0) return ext; if (['ppt', 'pptx', 'odp'].indexOf(ext) >= 0) return ext; if (['xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return ext; if (isNonOfficeAttachmentName(name, ext)) return ''; if (mt.indexOf('wordprocessingml') >= 0) return 'docx'; if (mt.indexOf('presentationml') >= 0) return 'pptx'; if (mt.indexOf('spreadsheetml') >= 0) return 'xlsx'; return ''; } function buildOnlyOfficeOpenUrl(input) { if (shouldUseOfficePreview(input.fileType, input.mode)) { return buildOfficePreviewOpenUrl(input); } var target = new URL('/onlyoffice', window.location.origin); var fileUrl = String(input.fileUrl || '').trim(); if (fileUrl) { try { fileUrl = new URL(fileUrl, window.location.origin).toString(); } catch (_error) {} } target.searchParams.set('fileUrl', fileUrl); target.searchParams.set('fileName', input.fileName || '未命名资源'); target.searchParams.set('fileType', input.fileType || 'docx'); if (input.assetId) target.searchParams.set('assetId', input.assetId); if (input.documentId) target.searchParams.set('documentId', input.documentId); if (input.userId) target.searchParams.set('userId', input.userId); target.searchParams.set('mode', input.mode || 'view'); return target.toString(); } function shouldUseOfficePreview(fileType, mode) { var normalizedMode = String(mode || 'view').trim().toLowerCase(); if (normalizedMode === 'edit') return false; var ext = String(fileType || '').trim().toLowerCase(); return ['docx', 'xlsx', 'xls', 'csv', 'pptx'].indexOf(ext) >= 0; } function buildOfficePreviewOpenUrl(input) { var _rto_ = window.__mnoteResourceOpenRuntime; if (_rto_ && typeof _rto_.buildOfficePreviewOpenUrl === 'function') { return _rto_.buildOfficePreviewOpenUrl(input); } var target = new URL('/office-preview', window.location.origin); var workspacePath = input && input.workspacePath && typeof input.workspacePath === 'object' ? input.workspacePath : {}; var fileUrl = String(input.fileUrl || '').trim(); if (fileUrl) { try { fileUrl = new URL(fileUrl, window.location.origin).toString(); } catch (_error) {} } target.searchParams.set('fileUrl', fileUrl); target.searchParams.set('fileName', input.fileName || '未命名资源'); target.searchParams.set('fileType', input.fileType || 'docx'); if (input.assetId) target.searchParams.set('assetId', input.assetId); if (input.documentId) target.searchParams.set('documentId', input.documentId); if (input.userId) target.searchParams.set('userId', input.userId); var workspaceId = String(input.workspaceId || workspacePath.workspaceId || '').trim(); var sourceKind = String(input.sourceKind || workspacePath.sourceKind || currentSourceKindFn() || '').trim(); var rootUri = String(input.rootUri || workspacePath.rootUri || currentRootUri() || '').trim(); if (workspaceId) target.searchParams.set('workspaceId', workspaceId); if (sourceKind) target.searchParams.set('sourceKind', sourceKind); if (rootUri) target.searchParams.set('rootUri', rootUri); return target.toString(); } function buildOnlyOfficeOpenPath(input) { var _rto_ = window.__mnoteResourceOpenRuntime; if (_rto_ && typeof _rto_.buildOnlyOfficeOpenPath === 'function') { return _rto_.buildOnlyOfficeOpenPath(input); } if (shouldUseOfficePreview(input.fileType, input.mode)) { return buildOfficePreviewOpenUrl(input); } var params = new URLSearchParams(); params.set('fileUrl', input.fileUrl || ''); params.set('fileName', input.fileName || '未命名资源'); params.set('fileType', input.fileType || 'docx'); if (input.assetId) params.set('assetId', input.assetId); if (input.documentId) params.set('documentId', input.documentId); if (input.userId) params.set('userId', input.userId); params.set('mode', input.mode || 'view'); if (input.documentId && input.assetId) { return '/office/' + encodeURIComponent(input.documentId) + '/' + encodeURIComponent(input.assetId) + '?' + params.toString(); } return '/onlyoffice?' + params.toString(); } function buildLocalOnlyOfficeOpenUrl(relativePath, fileName, documentId, assetId, mode) { var fileType = inferOnlyOfficeFileType(fileName || relativePath || '', ''); if (!fileType) return ''; var fileUrl = buildLocalFileOpenUrl(relativePath, false); if (!fileUrl) return ''; return buildOnlyOfficeOpenUrl({ fileUrl: fileUrl, fileName: fileName || relativePath || '未命名资源', fileType: fileType, assetId: assetId || ('local-file:' + relativePath), documentId: documentId || currentDocumentId() || '', userId: '', mode: mode || 'view', workspaceId: resolveWorkspaceId(document.body) || '', sourceKind: currentSourceKindFn() || 'local_folder', rootUri: currentRootUri() || '' }); } async function openLocalOfficeFileInActiveTab(detail, mode) { var localFilePath = localFilePathFromAssetId(detail.assetId); var workspacePath = workspacePathFromDetail(detail); if (!localFilePath && workspacePath) localFilePath = String(workspacePath.relativePath || workspacePath.localRelativePath || '').trim(); if (!localFilePath) return false; var localFileName = localFilePath.split('/').pop() || localFilePath; var localOfficeUrl = buildLocalOnlyOfficeOpenUrl(localFilePath, localFileName, String(detail.documentId || currentDocumentId() || '').trim(), detail.assetId, mode || 'view'); if (!localOfficeUrl) return false; var opened = await openLocalResourceInActiveTab({ path: localFilePath, title: detail.fileName || localFileName, kind: 'office', assetId: detail.assetId, documentId: detail.documentId || currentDocumentId() || '', workspaceId: detail.workspaceId || resolveWorkspaceId(document.body) || '', href: buildLocalFileOpenUrl(localFilePath, false), officeUrl: localOfficeUrl, workspacePath: workspacePath, paneRole: detail.paneRole || 'primary' }); if (!opened) window.open(localOfficeUrl, '_blank', 'noopener,noreferrer'); return true; } function buildMindmapOpenPath(documentId, assetId) { var doc = String(documentId || '').trim(); var map = String(assetId || '').trim(); if (!doc || !map) return ''; var targetUrl = new URL('/mindmap/' + encodeURIComponent(doc) + '/' + encodeURIComponent(map), window.location.origin); copyWorkspaceSourceParams(targetUrl); return targetUrl.pathname + targetUrl.search; } function navigateToMindmapObject(documentId, assetId, workspaceId) { var mindmapPath = buildMindmapOpenPath(documentId, assetId); if (!mindmapPath) return false; var targetUrl = new URL(mindmapPath, window.location.origin); var url = targetUrl.pathname + targetUrl.search; if (getNavigationInFlight() === url) return true; if (typeof window.__mnoteDocumentPaneRuntime?.openPrimaryMindmap === 'function') { setNavigationInFlight(url); document.documentElement.setAttribute('data-mnote-navigation-pending', 'true'); document.documentElement.setAttribute('data-mnote-navigation-target', assetId); window.__mnoteDocumentPaneRuntime.openPrimaryMindmap({ documentId: documentId, mindmapId: assetId, workspaceId: workspaceId || '', url: targetUrl }).then(function(){ if (getNavigationInFlight() === url) setNavigationInFlight(''); document.documentElement.removeAttribute('data-mnote-navigation-pending'); }).catch(function(error){ console.warn('mnote mindmap pane 内导航失败,将回退整页导航', error); if (window.__mnoteTreeLiveEventSource && typeof window.__mnoteTreeLiveEventSource.close === 'function') { window.__mnoteTreeLiveEventSource.close(); } window.location.assign(url); }); return true; } setNavigationInFlight(url); document.documentElement.setAttribute('data-mnote-navigation-pending', 'true'); document.documentElement.setAttribute('data-mnote-navigation-target', assetId); if (window.__mnoteTreeLiveEventSource && typeof window.__mnoteTreeLiveEventSource.close === 'function') { window.__mnoteTreeLiveEventSource.close(); } window.location.assign(url); return true; } function isMindmapAssetDetail(detail) { var assetId = String(detail && detail.assetId || '').trim(); var assetType = String(detail && detail.assetType || '').trim(); if (assetType === 'mindmap') return true; var fileName = assetId.indexOf('/') >= 0 ? assetId.split('/').pop() : assetId; return assetId.indexOf('mindmap_') === 0 || assetId.indexOf('mindmap-') === 0 || /\.mindmap\.json$/i.test(fileName) || (/^思维导图/i.test(fileName) && /\.json$/i.test(fileName)); } function sanitizeWorkspaceRelativePath(rel) { var value = String(rel || '').trim().replace(/\\/g, '/'); try { value = decodeURIComponent(value); } catch (_) { // keep raw } value = value.replace(/\\/g, '/').replace(/^\/+/, ''); if (!value || value.indexOf('\0') >= 0) return ''; var parts = []; value.split('/').forEach(function (seg) { if (!seg || seg === '.') return; if (seg === '..') { if (parts.length) parts.pop(); return; } parts.push(seg); }); return parts.join('/'); } function localFilePathFromAssetId(assetId) { var _rto_ = window.__mnoteResourceOpenRuntime; if (_rto_ && typeof _rto_.localFilePathFromAssetId === 'function') { return sanitizeWorkspaceRelativePath(_rto_.localFilePathFromAssetId(assetId)); } var value = String(assetId || '').trim(); var raw = value.indexOf('local-file:') === 0 ? value.slice('local-file:'.length) : value.indexOf('local:asset:') === 0 ? value.slice('local:asset:'.length) : ''; return sanitizeWorkspaceRelativePath(raw); } function workspacePathFromDetail(detail) { var workspacePath = detail && detail.workspacePath && typeof detail.workspacePath === 'object' ? detail.workspacePath : null; return workspacePath && workspacePath.schema === 'mnote.workspace_path.v1' ? workspacePath : null; } function workspacePathObjectIdentity(workspacePath) { var objectIdentity = workspacePath && workspacePath.objectIdentity && typeof workspacePath.objectIdentity === 'object' ? workspacePath.objectIdentity : null; return objectIdentity || {}; } function resourceObjectIdentityFromWorkspacePath(input) { input = input || {}; var workspacePath = input.workspacePath && typeof input.workspacePath === 'object' ? input.workspacePath : null; var structuredIdentity = workspacePathObjectIdentity(workspacePath); var objectKind = String(input.objectKind || workspacePath && (workspacePath.objectKind || workspacePath.resourceKind) || structuredIdentity.objectKind || '').trim(); var documentId = String(input.documentId || workspacePath && workspacePath.documentId || structuredIdentity.documentId || currentDocumentId() || '').trim(); var assetId = String(input.assetId || workspacePath && workspacePath.assetId || structuredIdentity.assetId || '').trim(); var relativePath = String(input.path || workspacePath && (workspacePath.relativePath || workspacePath.localRelativePath) || '').trim(); var rootUri = String(input.rootUri || workspacePath && workspacePath.rootUri || currentRootUri() || '').trim(); var fallback = String(input.fallback || '').trim(); if (relativePath && rootUri) return 'resource:file:' + rootUri + ':' + relativePath; if (objectKind === 'mindmap' && assetId) return 'resource:mindmap:' + documentId + ':' + assetId; if ((objectKind === 'only_office' || objectKind === 'office') && assetId) return 'resource:onlyoffice:' + documentId + ':' + assetId; if (objectKind === 'pdf' && assetId) return 'resource:pdf:' + documentId + ':' + assetId; if (assetId && documentId) return 'resource:' + (objectKind || 'attachment') + ':' + documentId + ':' + assetId; return fallback || assetId || ''; } function buildLocalFileOpenUrl(relativePath, download) { var safePath = sanitizeWorkspaceRelativePath(relativePath); var _rto_ = window.__mnoteResourceOpenRuntime; if (_rto_ && typeof _rto_.buildLocalFileOpenUrl === 'function') { return safePath ? _rto_.buildLocalFileOpenUrl(safePath, download) : ''; } var rootUri = currentRootUri(); if (!rootUri || !safePath) return ''; var url = new URL('/api/local-folder/files/open', window.location.origin); url.searchParams.set('rootUri', rootUri); url.searchParams.set('path', safePath); if (download) url.searchParams.set('download', 'true'); return url.toString(); } function buildPdfPreviewOpenUrl(fileUrl, fileName) { var _rto_ = window.__mnoteResourceOpenRuntime; if (_rto_ && typeof _rto_.buildPdfPreviewOpenUrl === 'function') { return _rto_.buildPdfPreviewOpenUrl(fileUrl, fileName); } var rawUrl = String(fileUrl || '').trim(); if (!rawUrl) return ''; var url = new URL('/pdf-preview', window.location.origin); url.searchParams.set('fileUrl', rawUrl); if (fileName) url.searchParams.set('fileName', fileName); return url.toString(); } async function openLocalResourceInActiveTab(input) { if (typeof window.__mnoteDocumentPaneRuntime?.openResourceInActiveTab !== 'function') return false; var relativePath = String(input && input.path || '').trim(); var rootUri = String(input && input.rootUri || currentRootUri() || '').trim(); if (!relativePath || !rootUri) return false; var title = String(input && input.title || '').trim() || relativePath.split('/').pop() || relativePath; var kind = String(input && input.kind || fileTreeIconKindForFileName(title) || '').trim(); var documentId = String(input && input.documentId || currentDocumentId() || '').trim(); var assetId = String(input && input.assetId || '').trim() || 'local-file:' + relativePath; var officeUrl = String(input && input.officeUrl || '').trim(); if (!officeUrl && kind === 'office') { officeUrl = buildLocalOnlyOfficeOpenUrl(relativePath, title, documentId, assetId, 'view'); } var workspacePath = input && input.workspacePath && typeof input.workspacePath === 'object' ? input.workspacePath : null; var objectIdentity = resourceObjectIdentityFromWorkspacePath({ workspacePath: workspacePath, objectKind: kind, documentId: documentId, assetId: assetId, path: relativePath, rootUri: rootUri }); return await window.__mnoteDocumentPaneRuntime.openResourceInActiveTab({ objectIdentity: objectIdentity, assetId: assetId, title: title, fileName: title, kind: kind, rootUri: rootUri, path: relativePath, href: String(input && input.href || buildLocalFileOpenUrl(relativePath, false) || '').trim(), officeUrl: officeUrl, documentId: documentId, workspaceId: String(input && input.workspaceId || resolveWorkspaceId(document.body) || '').trim(), workspacePath: workspacePath, paneRole: String(input && input.paneRole || 'primary').trim() || 'primary', evidenceLocator: input && input.evidenceLocator && typeof input.evidenceLocator === 'object' ? input.evidenceLocator : null, page: input && input.page, bbox: input && input.bbox, sourceMapPath: String(input && input.sourceMapPath || '').trim(), blockId: String(input && input.blockId || '').trim(), evidenceText: String(input && input.evidenceText || '').trim(), query: String(input && input.query || '').trim(), searchQuery: String(input && input.searchQuery || '').trim(), paragraphOrdinal: String(input && input.paragraphOrdinal || '').trim(), paraIdStart: String(input && input.paraIdStart || '').trim(), paraIdEnd: String(input && input.paraIdEnd || '').trim(), textFingerprint: String(input && input.textFingerprint || '').trim(), lineRange: input && input.lineRange, charRange: input && input.charRange }); } function readFileTreeObjectIdentity(row) { if (!row) return null; var raw = row.getAttribute('data-object-identity') || ''; if (!raw) return null; try { var parsed = JSON.parse(raw); return parsed && typeof parsed === 'object' ? parsed : null; } catch (_error) { return null; } } async function fetchCurrentOnlyOfficeUserId() { try { var response = await fetch('/api/auth/whoami', { method: 'GET', credentials: 'include', cache: 'no-store' }); var payload = await response.json().catch(function() { return null; }); return String(payload && payload.userId || '').trim(); } catch (_error) { return ''; } } async function openConvexAssetFromFileTree(detail) { var assetId = String(detail && detail.assetId || '').trim(); if (!assetId) return; var openTarget = String(detail && detail.openTarget || '').trim().toLowerCase(); var forceNewWindow = openTarget === 'new-window'; var forceEditMode = openTarget === 'edit-mode'; if (openTarget === 'side') { if (typeof window.__mnoteDocumentPaneRuntime?.openResourceAsSideTarget === 'function') { var sideWorkspacePath = workspacePathFromDetail(detail); var sideLocalFilePath = localFilePathFromAssetId(assetId); if (!sideLocalFilePath && sideWorkspacePath) sideLocalFilePath = String(sideWorkspacePath.relativePath || sideWorkspacePath.localRelativePath || '').trim(); var sideRootUri = String(detail.rootUri || currentRootUri() || '').trim(); var sideFileName = String(detail.title || detail.fileName || (sideLocalFilePath ? sideLocalFilePath.split('/').pop() : '') || assetId || '').trim(); var sideKind = String(detail.iconKind || detail.assetType || fileTreeIconKindForFileName(sideFileName) || 'file').trim(); var sideHref = sideLocalFilePath ? buildLocalFileOpenUrl(sideLocalFilePath, false) : ''; var sideOfficeUrl = sideLocalFilePath ? buildLocalOnlyOfficeOpenUrl(sideLocalFilePath, sideFileName, String(detail.documentId || currentDocumentId() || '').trim(), assetId, 'view') : ''; if (sideOfficeUrl) sideKind = 'office'; if (!sideOfficeUrl && isPdfAttachmentFileName(sideFileName)) sideHref = buildPdfPreviewOpenUrl(sideHref, sideFileName); void window.__mnoteDocumentPaneRuntime.openResourceAsSideTarget({ objectIdentity: resourceObjectIdentityFromWorkspacePath({ workspacePath: sideWorkspacePath, objectKind: sideKind, documentId: detail.documentId, assetId: assetId, path: sideLocalFilePath, rootUri: sideRootUri, fallback: String(detail.objectIdentity || detail.assetId || '') }), assetId: assetId, title: sideFileName, fileName: sideFileName, kind: sideKind, path: sideLocalFilePath, rootUri: sideRootUri, href: sideHref, officeUrl: sideOfficeUrl, documentId: String(detail.documentId || currentDocumentId() || ''), workspaceId: String(detail.workspaceId || resolveWorkspaceId(document.body) || ''), workspacePath: sideWorkspacePath }); } return; } var detailWorkspacePath = workspacePathFromDetail(detail); var localFilePath = localFilePathFromAssetId(assetId); if (!localFilePath && detailWorkspacePath) localFilePath = String(detailWorkspacePath.relativePath || detailWorkspacePath.localRelativePath || '').trim(); if (localFilePath) { var localFileName = localFilePath.split('/').pop() || localFilePath; if (isMindmapAssetDetail(detail) || String(detail && detail.assetType || '').trim() === 'mindmap') { if (typeof window.__mnoteDocumentPaneRuntime?.openResourceInActiveTab === 'function') { document.documentElement.setAttribute('data-mnote-last-mindmap-asset-open-mode', 'mindmap-resource-tab'); document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', assetId); void window.__mnoteDocumentPaneRuntime.openResourceInActiveTab({ objectIdentity: resourceObjectIdentityFromWorkspacePath({ workspacePath: detailWorkspacePath, objectKind: 'mindmap', documentId: detail && detail.documentId, assetId: assetId, path: localFilePath }), assetId: assetId, mindmapId: assetId, title: String(detail && detail.title || localFileName || '思维导图').trim(), fileName: localFileName, kind: 'mindmap', documentId: String(detail && detail.documentId || currentDocumentId() || '').trim(), workspaceId: String(detail.workspaceId || '').trim(), workspacePath: detailWorkspacePath }); return; } document.documentElement.setAttribute('data-mnote-last-mindmap-asset-open-mode', 'local-mindmap-object-shell'); document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', assetId); navigateToMindmapObject(String(detail && detail.documentId || currentDocumentId() || '').trim(), assetId, String(detail.workspaceId || '').trim()); return; } var requestedOfficeMode = forceEditMode ? 'edit' : 'view'; var localOfficeUrl = buildLocalOnlyOfficeOpenUrl(localFilePath, localFileName, String(detail && detail.documentId || currentDocumentId() || '').trim(), assetId, requestedOfficeMode); if (localOfficeUrl) { if (!forceNewWindow && await openLocalResourceInActiveTab({ path: localFilePath, title: localFileName, kind: 'office', assetId: assetId, documentId: String(detail && detail.documentId || currentDocumentId() || '').trim(), workspaceId: String(detail.workspaceId || '').trim(), officeUrl: localOfficeUrl, workspacePath: detailWorkspacePath })) return; window.open(localOfficeUrl, '_blank', 'noopener,noreferrer'); return; } var localFileUrl = buildLocalFileOpenUrl(localFilePath, false); if (localFileUrl) { var localOpenUrl = isPdfAttachmentFileName(localFileName) ? buildPdfPreviewOpenUrl(localFileUrl, localFileName) : localFileUrl; var shouldOpenInNewWindow = forceNewWindow || shouldOpenLocalResourceInNewWindow(localFileName); if (!shouldOpenInNewWindow && await openLocalResourceInActiveTab({ path: localFilePath, title: localFileName, kind: fileTreeIconKindForFileName(localFileName), assetId: assetId, documentId: String(detail && detail.documentId || currentDocumentId() || '').trim(), workspaceId: String(detail.workspaceId || '').trim(), href: localOpenUrl, workspacePath: detailWorkspacePath })) return; window.open(localOpenUrl, '_blank', 'noopener,noreferrer'); } return; } var documentId = String(detail && detail.documentId || '').trim(); if (isMindmapAssetDetail(detail) && documentId) { if (typeof window.__mnoteDocumentPaneRuntime?.openResourceInActiveTab === 'async function') { document.documentElement.setAttribute('data-mnote-last-mindmap-asset-open-mode', 'mindmap-resource-tab'); document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', assetId); void window.__mnoteDocumentPaneRuntime.openResourceInActiveTab({ objectIdentity: resourceObjectIdentityFromWorkspacePath({ workspacePath: detailWorkspacePath, objectKind: 'mindmap', documentId: documentId, assetId: assetId }), assetId: assetId, mindmapId: assetId, title: String(detail.title || '思维导图').trim(), fileName: String(detail.title || '思维导图').trim(), kind: 'mindmap', documentId: documentId, workspaceId: String(detail.workspaceId || '').trim(), workspacePath: detailWorkspacePath }); return; } document.documentElement.setAttribute('data-mnote-last-mindmap-asset-open-mode', 'mindmap-object-shell'); document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', assetId); navigateToMindmapObject(documentId, assetId, String(detail.workspaceId || '').trim()); return; } document.documentElement.setAttribute('data-mnote-media-sign-retired', 'true'); await window.mnote.alert('旧 Convex Files 附件签名链已退役;local-first 附件请通过本地文件夹资源打开。'); } window.addEventListener('tree.asset.open', function(event) { void openConvexAssetFromFileTree(event.detail || {}); }); return { buildLocalFileOpenUrl, buildLocalOnlyOfficeOpenUrl, buildMindmapOpenPath, buildOfficePreviewOpenUrl, buildOnlyOfficeOpenPath, buildOnlyOfficeOpenUrl, buildPdfPreviewOpenUrl, fetchCurrentOnlyOfficeUserId, inferOnlyOfficeFileType, isMindmapAssetDetail, localFilePathFromAssetId, navigateToMindmapObject, openConvexAssetFromFileTree, openLocalOfficeFileInActiveTab, openLocalResourceInActiveTab, readFileTreeObjectIdentity, resourceObjectIdentityFromWorkspacePath, workspacePathFromDetail, }; };