import { createSidebarWorkspaceRuntime } from './sidebar-workspace-runtime.js'; import { createSidebarPageTreeRuntime } from './sidebar-page-tree-runtime.js'; import { createSidebarTreeLiveApplyRuntime } from './sidebar-tree-live-apply-runtime.js'; import { createSidebarFileTreeOpenRuntime } from './sidebar-filetree-open-runtime.js'; import { createSidebarAttachmentOpenRuntime } from './sidebar-attachment-open-runtime.js'; import { createSidebarFileTreeCommandRuntime } from './sidebar-filetree-command-runtime.js'; import { createSidebarFileTreeUploadRuntime } from './sidebar-filetree-upload-runtime.js'; import { createSidebarPageAiRuntime } from './sidebar-page-ai-runtime.js'; import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtime.js'; (function(){ if (window.__mnoteSidebarTreeRuntimeStarted) return; window.__mnoteSidebarTreeRuntimeStarted = true; var FILETREE_DRAG_MIME = 'application/x-mnote-filetree-row-ids'; var MNOTE_SIDEBAR_TREE_MODE_KEY = 'mnote.sidebar.tree.mode'; var MNOTE_RECENT_LOCAL_ROOTS_KEY_PREFIX = 'mnote.localFolder.recentRoots:'; var MNOTE_LAST_CLOUD_WORKSPACE_KEY = 'mnote.workspace.lastCloudWorkspaceId'; var MNOTE_GLOBAL_SHOW_HEADING_NUMBERS_KEY = 'mnote.global.showHeadingNumbers'; var mnoteNavigationInFlight = ''; var draggingFileTreeRowIds = []; var activeFileTreeDropRow = null; var sidebarFileTreeClipboard = null; var sidebarFileTreeSelection = { selectedRowIds: new Set(), anchorRowId: null, focusedRowId: null }; var activeTreeContextMenu = null; var pageUiState = { pageOptions: null, pageWidthPreferences: null, historySnapshots: [], pageSettingsOpen: false, localIndexSummary: { scopeKey: '', loading: false, error: '', backlinks: null, tags: null } }; function closestAction(target, selector) { var node = target && target.nodeType === Node.TEXT_NODE ? target.parentElement : target; return node && typeof node.closest === 'function' ? node.closest(selector) : null; } function sidebarShellRuntimeFunction(name) { var runtime = window.__mnoteSidebarShellRuntime; return runtime && typeof runtime[name] === 'function' ? runtime[name] : null; } function toggleWorkspaceSidebar(trigger) { var runtimeFn = sidebarShellRuntimeFunction('toggleWorkspaceSidebar'); if (runtimeFn) return runtimeFn(trigger); } function installWorkspaceSidebarResizer() { var runtimeFn = sidebarShellRuntimeFunction('installWorkspaceSidebarResizer'); if (runtimeFn) return runtimeFn(); } function escapeHtml(value) { return String(value == null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function cssEscape(value) { if (window.CSS && typeof window.CSS.escape === 'function') return window.CSS.escape(value); return String(value).replace(/["\\]/g, '\\$&'); } function parseJsonScript(id) { var node = document.getElementById(id); if (!node) return null; try { return JSON.parse(node.textContent || 'null'); } catch (_) { return null; } } function currentDocumentId() { var match = window.location.pathname.match(/^\/documents\/([^\/]+)/); if (!match) match = window.location.pathname.match(/^\/mindmap\/([^\/]+)\/([^\/]+)/); if (match) return decodeURIComponent(match[1]); var params = new URLSearchParams(window.location.search); var fromQuery = (params.get('documentId') || params.get('pageId') || '').trim(); if (fromQuery) return fromQuery; var activePane = document.querySelector('.document-pane[data-pane-role="primary"][data-pane-document-id], .document-pane[data-pane-visible="true"][data-pane-document-id]'); if (activePane instanceof HTMLElement) { var paneDocumentId = (activePane.getAttribute('data-pane-document-id') || '').trim(); if (paneDocumentId) return paneDocumentId; } var shell = document.querySelector('.document-shell[data-document-id]'); if (shell instanceof HTMLElement) return (shell.getAttribute('data-document-id') || '').trim(); return ''; } function localFolderSelfChangeSuppressions() { window.__mnoteLocalFolderSelfChangeSuppressions = window.__mnoteLocalFolderSelfChangeSuppressions || new Map(); return window.__mnoteLocalFolderSelfChangeSuppressions; } function persistLocalFolderSelfChangeSuppression(documentId, expiresAt) { var doc = String(documentId || '').trim(); if (!doc) return; localFolderSelfChangeSuppressions().set(doc, expiresAt); try { var key = 'mnote.localFolder.selfChangeSuppressions.v1'; var existing = JSON.parse(window.sessionStorage.getItem(key) || '{}'); existing[doc] = expiresAt; window.sessionStorage.setItem(key, JSON.stringify(existing)); } catch (_) {} } var EDITOR_UPLOAD_ROOT_SELECTOR = '[data-editor-host-kind="leptos_tiptap_island"], [data-editor-host-kind="leptos_tiptap_resource"]'; function editorUploadRootFromElement(target) { if (!(target instanceof Element)) return null; var root = target.closest(EDITOR_UPLOAD_ROOT_SELECTOR); return root instanceof HTMLElement ? root : null; } function rememberEditorUploadRootFromTarget(target) { var root = editorUploadRootFromElement(target); if (root instanceof HTMLElement) { window.__mnoteLastEditorUploadRoot = root; return root; } return null; } document.addEventListener('pointerdown', function(event) { rememberEditorUploadRootFromTarget(event.target); }, true); document.addEventListener('focusin', function(event) { rememberEditorUploadRootFromTarget(event.target); }, true); 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(); return documentId ? 'doc:' + documentId : ''; } function currentPageAggregate() { return parseJsonScript('__MNOTE_PAGE_AGGREGATE__') || {}; } const sidebarWorkspace = createSidebarWorkspaceRuntime({ cssEscape, currentDocumentId, escapeHtml, parseJsonScript, setCommandPending: (...args) => setCommandPending(...args), sidebarShellRuntimeFunction, }); const normalizeSidebarTreeMode = (...args) => sidebarWorkspace.normalizeSidebarTreeMode(...args); const readStoredSidebarTreeMode = (...args) => sidebarWorkspace.readStoredSidebarTreeMode(...args); const persistSidebarTreeMode = (...args) => sidebarWorkspace.persistSidebarTreeMode(...args); const activeSidebarTreeMode = (...args) => sidebarWorkspace.activeSidebarTreeMode(...args); const resolveWorkspaceId = (...args) => sidebarWorkspace.resolveWorkspaceId(...args); const currentWorkspaceId = (...args) => sidebarWorkspace.currentWorkspaceId(...args); const currentSourceKind = (...args) => sidebarWorkspace.currentSourceKind(...args); const currentRootUri = (...args) => sidebarWorkspace.currentRootUri(...args); const copyWorkspaceSourceParams = (...args) => sidebarWorkspace.copyWorkspaceSourceParams(...args); const currentWorkspaceSourcePayload = (...args) => sidebarWorkspace.currentWorkspaceSourcePayload(...args); const openTrashModal = (...args) => sidebarWorkspace.openTrashModal(...args); const closeTrashModal = (...args) => sidebarWorkspace.closeTrashModal(...args); const closeLocalFolderDialog = (...args) => sidebarWorkspace.closeLocalFolderDialog(...args); const requestOpenLocalFolder = (...args) => sidebarWorkspace.requestOpenLocalFolder(...args); const createDefaultLocalWorkspace = (...args) => sidebarWorkspace.createDefaultLocalWorkspace(...args); const closeWorkspaceSourceMenu = (...args) => sidebarWorkspace.closeWorkspaceSourceMenu(...args); const openWorkspaceSourceMenu = (...args) => sidebarWorkspace.openWorkspaceSourceMenu(...args); const closeAccountMenu = (...args) => sidebarWorkspace.closeAccountMenu(...args); const openAccountMenu = (...args) => sidebarWorkspace.openAccountMenu(...args); sidebarWorkspace.autoOpenRecentLocalRootOnHome(); const sidebarPageSettings = createSidebarPageSettingsRuntime({ currentDocumentId, currentPageAggregate, currentRootUri, currentSourceKind, currentWorkspaceSourcePayload, escapeHtml, globalShowHeadingNumbersKey: MNOTE_GLOBAL_SHOW_HEADING_NUMBERS_KEY, pageUiState, resolveWorkspaceId, searchText, }); const applyPageOptionsToShell = (...args) => sidebarPageSettings.applyPageOptionsToShell(...args); const closePageHistoryDrawer = (...args) => sidebarPageSettings.closePageHistoryDrawer(...args); const closeAllSettingsPopovers = (...args) => sidebarPageSettings.closeAllSettingsPopovers(...args); const closePageSettingsPopover = (...args) => sidebarPageSettings.closePageSettingsPopover(...args); const closePageShareDialog = (...args) => sidebarPageSettings.closePageShareDialog(...args); const currentPageOptions = (...args) => sidebarPageSettings.currentPageOptions(...args); const ensureHistorySnapshotsSeeded = (...args) => sidebarPageSettings.ensureHistorySnapshotsSeeded(...args); const isAnySettingsOpen = (...args) => sidebarPageSettings.isAnySettingsOpen(...args); const isPageSettingsOpen = (...args) => sidebarPageSettings.isPageSettingsOpen(...args); const openPageHistoryDrawer = (...args) => sidebarPageSettings.openPageHistoryDrawer(...args); const openPageIndexSettingsPopover = (...args) => sidebarPageSettings.openPageIndexSettingsPopover(...args); const openKnowledgeRagSettingsPopover = (...args) => sidebarPageSettings.openKnowledgeRagSettingsPopover(...args); const openKnowledgeRagSourceReference = (...args) => sidebarPageSettings.openKnowledgeRagSourceReference(...args); const openPageShareDialog = (...args) => sidebarPageSettings.openPageShareDialog(...args); const pageOptionIsSupported = (...args) => sidebarPageSettings.pageOptionIsSupported(...args); const addLocalIndexRange = (...args) => sidebarPageSettings.addLocalIndexRange(...args); const addKnowledgeRagSourceInput = (...args) => sidebarPageSettings.addKnowledgeRagSourceInput(...args); const deleteKnowledgeRagSource = (...args) => sidebarPageSettings.deleteKnowledgeRagSource(...args); const ingestKnowledgeRagSources = (...args) => sidebarPageSettings.ingestKnowledgeRagSources(...args); const ingestSingleKnowledgeRagSource = (...args) => sidebarPageSettings.ingestSingleKnowledgeRagSource(...args); const loadKnowledgeRagStatus = (...args) => sidebarPageSettings.loadKnowledgeRagStatus(...args); const openKnowledgeRagDashboard = (...args) => sidebarPageSettings.openKnowledgeRagDashboard(...args); const createKnowledgeRagKnowledgeBase = (...args) => sidebarPageSettings.createKnowledgeRagKnowledgeBase(...args); const deleteKnowledgeRagKnowledgeBase = (...args) => sidebarPageSettings.deleteKnowledgeRagKnowledgeBase(...args); const toggleKnowledgeRagCreateCard = (...args) => sidebarPageSettings.toggleKnowledgeRagCreateCard(...args); const setActiveKnowledgeRagDetailTab = (...args) => sidebarPageSettings.setActiveKnowledgeRagDetailTab(...args); const performKnowledgeRagSearch = (...args) => sidebarPageSettings.performKnowledgeRagSearch(...args); const saveKnowledgeRagSearchParams = (...args) => sidebarPageSettings.saveKnowledgeRagSearchParams(...args); const loadKnowledgeRagSearchParamsToForm = (...args) => sidebarPageSettings.loadKnowledgeRagSearchParamsToForm(...args); const syncKnowledgeRagThresholdDisplay = (...args) => sidebarPageSettings.syncKnowledgeRagThresholdDisplay(...args); const refreshDashboardPanel = (...args) => sidebarPageSettings.refreshDashboardPanel(...args); const pruneKnowledgeRagRegistry = (...args) => sidebarPageSettings.pruneKnowledgeRagRegistry(...args); const setKnowledgeRagSelectedProviderKnowledgeBaseId = (...args) => sidebarPageSettings.setKnowledgeRagSelectedProviderKnowledgeBaseId(...args); const setKnowledgeRagSourceFilter = (...args) => sidebarPageSettings.setKnowledgeRagSourceFilter(...args); const useKnowledgeRagFileTreeSelection = (...args) => sidebarPageSettings.useKnowledgeRagFileTreeSelection(...args); const persistLocalIndexSettings = (...args) => sidebarPageSettings.persistLocalIndexSettings(...args); const persistPageOptionsPatch = (...args) => sidebarPageSettings.persistPageOptionsPatch(...args); const persistPageWidthPreference = (...args) => sidebarPageSettings.persistPageWidthPreference(...args); const refreshLocalIndex = (...args) => sidebarPageSettings.refreshLocalIndex(...args); const removeKnowledgeRagSourceInput = (...args) => sidebarPageSettings.removeKnowledgeRagSourceInput(...args); const removeLocalIndexRange = (...args) => sidebarPageSettings.removeLocalIndexRange(...args); const recordPageHistorySnapshot = (...args) => sidebarPageSettings.recordPageHistorySnapshot(...args); const renderPageSettingsPopover = (...args) => sidebarPageSettings.renderPageSettingsPopover(...args); const setActiveExtensionsSubtab = (...args) => sidebarPageSettings.setActiveExtensionsSubtab(...args); const setActivePageSettingsTab = (...args) => sidebarPageSettings.setActivePageSettingsTab(...args); const togglePageSettingsPopover = (...args) => sidebarPageSettings.togglePageSettingsPopover(...args); const updatePageSettingsTriggerState = (...args) => sidebarPageSettings.updatePageSettingsTriggerState(...args); const writeGlobalShowHeadingNumbers = (...args) => sidebarPageSettings.writeGlobalShowHeadingNumbers(...args); const loadPageWidthPreferences = (...args) => sidebarPageSettings.loadPageWidthPreferences(...args); function setCommandPending(trigger, pending) { if (!(trigger instanceof HTMLElement)) return; trigger.setAttribute('data-pending', pending ? 'true' : 'false'); if ('disabled' in trigger) { if (pending) trigger.setAttribute('disabled', 'disabled'); else trigger.removeAttribute('disabled'); } } async function dispatchTreeCommand(trigger, body) { setCommandPending(trigger, true); var commandBody = Object.assign({}, currentWorkspaceSourcePayload(), body || {}); try { var response = await fetch('/api/tree/commands', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(commandBody) }); var payload = await response.json().catch(function(){ return null; }); if (!response.ok || !payload || !payload.result) { 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); if (trigger instanceof HTMLElement) { trigger.setAttribute('data-error', error instanceof Error ? error.message : String(error)); } throw error; } } var sidebarPageTree = null; const navigateToDocument = (...args) => sidebarPageTree.navigateToDocument(...args); const createPage = (...args) => sidebarPageTree.createPage(...args); const startPageDrag = (...args) => sidebarPageTree.startPageDrag(...args); const readPageDragNodeId = (...args) => sidebarPageTree.readPageDragNodeId(...args); const clearPageDropFeedback = (...args) => sidebarPageTree.clearPageDropFeedback(...args); const setActivePageDropRow = (...args) => sidebarPageTree.setActivePageDropRow(...args); const clearPageDragState = (...args) => sidebarPageTree.clearPageDragState(...args); const canDropPage = (...args) => sidebarPageTree.canDropPage(...args); const pageDropPosition = (...args) => sidebarPageTree.pageDropPosition(...args); const resolvePageMoveTarget = (...args) => sidebarPageTree.resolvePageMoveTarget(...args); async function createFileTreeFolder(trigger, parentId) { if (currentSourceKind() !== 'local_folder') return false; var workspaceId = resolveWorkspaceId(trigger || document.body); var effectiveParentId = String(parentId || '').trim(); var result = await dispatchTreeCommand(trigger || document.body, { action: 'create_folder', workspaceId: workspaceId, parentId: effectiveParentId || null, title: '新建文件夹' }); document.documentElement.setAttribute('data-mnote-filetree-folder-created', 'true'); document.documentElement.setAttribute('data-mnote-filetree-folder-created-id', commandDocumentId(result, result.id || '')); void refreshLocalFolderSidebarSnapshot(); return true; } function applySidebarTreeTab(mode, shell) { var runtimeFn = sidebarShellRuntimeFunction('applySidebarTreeTab'); if (runtimeFn) return runtimeFn(mode, shell); } function switchSidebarTreeTab(trigger) { var runtimeFn = sidebarShellRuntimeFunction('switchSidebarTreeTab'); if (runtimeFn) return runtimeFn(trigger); } function restoreSidebarTreeTab() { var runtimeFn = sidebarShellRuntimeFunction('restoreSidebarTreeTab'); if (runtimeFn) return runtimeFn(); } const sidebarTreeLiveApply = createSidebarTreeLiveApplyRuntime({ activeSidebarTreeMode, cssEscape, currentDocumentId: (...args) => currentDocumentId(...args), currentFileTreeActiveRowId: (...args) => currentFileTreeActiveRowId(...args), currentRootUri, currentSourceKind, currentWorkspaceId, escapeHtml, fileTreeRuntimeFunction: (...args) => fileTreeRuntimeFunction(...args), localFilePathFromAssetId: (...args) => localFilePathFromAssetId(...args), navigateToDocument, refreshEditorLocalAttachmentExistence: (...args) => refreshEditorLocalAttachmentExistence(...args), restoreSidebarTreeTab, rowTitle: (...args) => rowTitle(...args), schedulePendingLocalFolderRestoreFocus: (...args) => schedulePendingLocalFolderRestoreFocus(...args), shortMindmapFileName: (...args) => shortMindmapFileName(...args), syncSidebarFileTreeSelection: (...args) => syncSidebarFileTreeSelection(...args), }); const updateTitleEverywhere = (...args) => sidebarTreeLiveApply.updateTitleEverywhere(...args); const commandDocumentId = (...args) => sidebarTreeLiveApply.commandDocumentId(...args); sidebarPageTree = createSidebarPageTreeRuntime({ activeSidebarTreeMode, commandDocumentId, copyWorkspaceSourceParams, cssEscape, currentDocumentId, currentRootUri, currentSourceKind, dispatchTreeCommand, normalizeSidebarTreeMode, persistLocalFolderSelfChangeSuppression, persistSidebarTreeMode, refreshLocalFolderSidebarSnapshot: (...args) => refreshLocalFolderSidebarSnapshot(...args), refreshLocalFolderAfterCommand: (...args) => refreshLocalFolderAfterCommand(...args), resolveWorkspaceId, rowCenter: (...args) => rowCenter(...args), selectSidebarFileTreeDocument: (...args) => selectSidebarFileTreeDocument(...args), toggleChildren: (...args) => toggleChildren(...args), dispatchSidebarEvent: (...args) => dispatchSidebarEvent(...args), openPageTreeContextMenu: (...args) => openPageTreeContextMenu(...args), updateTitleEverywhere: (...args) => updateTitleEverywhere(...args), }); const selectSidebarPageTreeDocument = (...args) => sidebarPageTree.selectSidebarPageTreeDocument(...args); const fileTreePageTitle = (...args) => sidebarTreeLiveApply.fileTreePageTitle(...args); const isFileTreePageRow = (...args) => sidebarTreeLiveApply.isFileTreePageRow(...args); const normalizeFileTreePageRenameTitle = (...args) => sidebarTreeLiveApply.normalizeFileTreePageRenameTitle(...args); const validateFileTreeRename = (...args) => sidebarTreeLiveApply.validateFileTreeRename(...args); const removeDocumentRowForMode = (...args) => sidebarTreeLiveApply.removeDocumentRowForMode(...args); const applyCreatedDocumentLocally = (...args) => sidebarTreeLiveApply.applyCreatedDocumentLocally(...args); const localCommandNeedsProjectionRefresh = (...args) => sidebarTreeLiveApply.localCommandNeedsProjectionRefresh(...args); const refreshLocalFolderAfterCommand = (...args) => sidebarTreeLiveApply.refreshLocalFolderAfterCommand(...args); const applyMoveDocumentDelta = (...args) => sidebarTreeLiveApply.applyMoveDocumentDelta(...args); const applyRemoveDocumentDelta = (...args) => sidebarTreeLiveApply.applyRemoveDocumentDelta(...args); const setTreeLiveApplyError = (...args) => sidebarTreeLiveApply.setTreeLiveApplyError(...args); const objectIdentityAttr = (...args) => sidebarTreeLiveApply.objectIdentityAttr(...args); const renderPageProjection = (...args) => sidebarTreeLiveApply.renderPageProjection(...args); const renderSidebarSnapshot = (...args) => sidebarTreeLiveApply.renderSidebarSnapshot(...args); const refreshLocalFolderSidebarSnapshot = (...args) => sidebarTreeLiveApply.refreshLocalFolderSidebarSnapshot(...args); const startLocalFolderSidebarWatch = (...args) => sidebarTreeLiveApply.startLocalFolderSidebarWatch(...args); const deltaNeedsProjectionRefresh = (...args) => sidebarTreeLiveApply.deltaNeedsProjectionRefresh(...args); const toggleChildren = (...args) => sidebarTreeLiveApply.toggleChildren(...args); const revealFileTreeResource = (...args) => sidebarTreeLiveApply.revealFileTreeResource(...args); function dispatchSidebarEvent(name, detail) { document.documentElement.setAttribute('data-mnote-last-tree-action', name); window.dispatchEvent(new CustomEvent(name, { detail: detail })); } function sidebarShortcutWorkspaceId() { return currentWorkspaceId() || (document.getElementById('sidebar-file-tree-root') && document.getElementById('sidebar-file-tree-root').getAttribute('data-workspace-id') || '') || (document.getElementById('sidebar-tree-root') && document.getElementById('sidebar-tree-root').getAttribute('data-workspace-id') || ''); } function sidebarShortcutSourceKind() { return currentSourceKind() || 'workspace'; } function currentFileTreeScope() { var params = new URLSearchParams(window.location.search); var fromUrl = String(params.get('fileTreeScope') || '').trim(); if (fromUrl) return fromUrl; var root = document.getElementById('sidebar-file-tree-root'); return root instanceof HTMLElement ? String(root.getAttribute('data-mnote-filetree-scope') || '').trim() : ''; } function recordNavigationRecent(payload) { var body = Object.assign({ sourceKind: currentSourceKind() || 'local_folder', rootUri: currentRootUri() || '', }, payload || {}); if (!body.kind || !body.rootUri || !body.title) return Promise.resolve(false); return fetch('/api/navigation/recent', { method: 'POST', credentials: 'include', headers: { accept: 'application/json', 'content-type': 'application/json' }, body: JSON.stringify(body) }).then(function(response) { return response.ok; }).catch(function(error) { console.warn('[mnote navigation] record recent failed', error); return false; }); } function openNavigationPageForFolder(rootUri, relativePath, workspaceId, title, options) { rootUri = String(rootUri || '').trim(); relativePath = String(relativePath || '').trim().replace(/^\/+|\/+$/g, ''); workspaceId = String(workspaceId || '').trim(); title = String(title || relativePath || '本地文件夹').trim(); if (!rootUri) return false; void recordNavigationRecent({ kind: 'folder', sourceKind: 'local_folder', rootUri: rootUri, relativePath: relativePath, title: title, workspaceId: workspaceId }); var targetUrl = new URL('/', window.location.origin); if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId); targetUrl.searchParams.set('sourceKind', 'local_folder'); targetUrl.searchParams.set('rootUri', rootUri); targetUrl.searchParams.set('treeView', 'filetree'); if (relativePath) targetUrl.searchParams.set('fileTreeScope', relativePath); var url = targetUrl.pathname + targetUrl.search; if (options && options.newTab) { window.open(url, '_blank', 'noopener'); } else { window.location.assign(url); } return true; } /** * Soft-open password vault: swap main content only, keep sidebar PageTree/FileTree DOM. * Full /vault navigation re-SSRs the tree and drops expand state — avoid that on left-rail click. */ function ensureVaultWorkbenchRuntimeLoaded() { if (window.mnote && window.mnote.vaultWorkbench && typeof window.mnote.vaultWorkbench.boot === 'function') { return Promise.resolve(window.mnote.vaultWorkbench); } return new Promise(function (resolve, reject) { var existing = document.querySelector('script[data-mnote-vault-runtime="1"]'); if (existing) { var onLoad = function () { existing.removeEventListener('load', onLoad); existing.removeEventListener('error', onError); if (window.mnote && window.mnote.vaultWorkbench) resolve(window.mnote.vaultWorkbench); else reject(new Error('vault_workbench_runtime_missing')); }; var onError = function () { existing.removeEventListener('load', onLoad); existing.removeEventListener('error', onError); reject(new Error('vault_workbench_runtime_load_failed')); }; existing.addEventListener('load', onLoad); existing.addEventListener('error', onError); return; } var script = document.createElement('script'); script.src = '/api/mnote-browser-runtime/vault-workbench-runtime.js'; script.defer = true; script.setAttribute('data-mnote-vault-runtime', '1'); script.onload = function () { if (window.mnote && window.mnote.vaultWorkbench) resolve(window.mnote.vaultWorkbench); else reject(new Error('vault_workbench_runtime_missing')); }; script.onerror = function () { reject(new Error('vault_workbench_runtime_load_failed')); }; document.head.appendChild(script); }); } function buildVaultWorkbenchShellHtml(workspaceId, rootUri) { var ws = escapeHtml(String(workspaceId || '').trim()); var root = escapeHtml(String(rootUri || '').trim()); return ( '
' + '
' + '
' + '

密码箱

' + '

' + '
' + '
' + '' + '' + '' + '' + '
' + '' + '' + '
' + '
' + '
' + '
' + '' + '
' + '
' + '
' ); } function markVaultNavActive() { document.querySelectorAll('.mnote-sidebar-nav a.active, .wolai-quick-actions a.active').forEach(function (link) { link.classList.remove('active'); }); document .querySelectorAll('a[data-mnote-nav="vault"], a[data-testid="mnote-nav-vault"]') .forEach(function (link) { link.classList.add('active'); }); } async function openVaultWorkbenchSoft(targetUrl, options) { var url = targetUrl instanceof URL ? targetUrl : new URL(String(targetUrl || '/vault'), window.location.origin); if (url.pathname !== '/vault') { window.location.assign(url.pathname + url.search + url.hash); return false; } copyWorkspaceSourceParams(url); if (!url.searchParams.get('sourceKind') && (url.searchParams.get('rootUri') || currentRootUri())) { url.searchParams.set('sourceKind', 'local_folder'); } if (!url.searchParams.get('rootUri')) { var bodyRoot = currentRootUri(); if (bodyRoot) url.searchParams.set('rootUri', bodyRoot); } var rootUri = (url.searchParams.get('rootUri') || currentRootUri() || '').trim(); var workspaceId = ( currentWorkspaceId() || resolveWorkspaceId(document.body) || (document.getElementById('sidebar-tree-root') && document.getElementById('sidebar-tree-root').getAttribute('data-workspace-id')) || '' ).trim(); var content = document.querySelector('article.mnote-content'); if (!(content instanceof HTMLElement)) { window.location.assign(url.pathname + url.search + url.hash); return false; } var nextHref = url.pathname + url.search + url.hash; if (mnoteNavigationInFlight === 'vault:' + nextHref) return true; mnoteNavigationInFlight = 'vault:' + nextHref; try { // Preserve #sidebar-tree-root / #sidebar-file-tree-root; only replace main pane. content.innerHTML = buildVaultWorkbenchShellHtml(workspaceId, rootUri); if (document.body instanceof HTMLElement) { document.body.setAttribute('data-mnote-page', 'vault'); if (rootUri) document.body.setAttribute('data-mnote-root-uri', rootUri); document.body.setAttribute('data-mnote-source-kind', 'local_folder'); } document.title = '密码箱'; markVaultNavActive(); if (!(options && options.replaceUrl === false)) { window.history.pushState({ mnoteSoftNav: 'vault' }, '', nextHref); } var vaultApi = await ensureVaultWorkbenchRuntimeLoaded(); if (vaultApi && typeof vaultApi.boot === 'function') vaultApi.boot(); return true; } catch (error) { console.warn('[mnote vault] soft open failed, falling back to full navigation', error); window.location.assign(nextHref); return false; } finally { if (mnoteNavigationInFlight === 'vault:' + nextHref) mnoteNavigationInFlight = ''; } } window.__mnoteOpenVaultWorkbench = openVaultWorkbenchSoft; function openCurrentNavigationPage(trigger) { if (currentSourceKind() === 'local_folder') { var rootUri = currentRootUri(); var scope = currentFileTreeScope(); var workspaceId = currentWorkspaceId() || sidebarShortcutWorkspaceId() || resolveWorkspaceId(trigger || document.body); var title = scope ? scope.split('/').filter(Boolean).pop() : '本地文件夹'; return openNavigationPageForFolder(rootUri, scope, workspaceId, title || scope || '本地文件夹'); } var targetUrl = new URL('/', window.location.origin); var workspaceId = currentWorkspaceId() || resolveWorkspaceId(trigger || document.body); if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId); window.location.assign(targetUrl.pathname + targetUrl.search); return true; } function knowledgeHostUrl(options) { options = options || {}; var knowledgeUrl = new URL('/knowledge', window.location.origin); var workspaceId = String(options.workspaceId || currentWorkspaceId() || resolveWorkspaceId(document.body) || '').trim(); var sourceKind = String(options.sourceKind || currentSourceKind() || '').trim(); var rootUri = String(options.rootUri || currentRootUri() || '').trim(); var treeView = String(options.treeView || activeSidebarTreeMode() || '').trim(); var fileTreeScope = String(options.fileTreeScope || currentFileTreeScope() || '').trim(); if (workspaceId) knowledgeUrl.searchParams.set('workspaceId', workspaceId); if (sourceKind) knowledgeUrl.searchParams.set('sourceKind', sourceKind); if (rootUri) knowledgeUrl.searchParams.set('rootUri', rootUri); if (treeView) knowledgeUrl.searchParams.set('treeView', treeView); if (fileTreeScope) knowledgeUrl.searchParams.set('fileTreeScope', fileTreeScope); return knowledgeUrl.pathname + knowledgeUrl.search; } function currentTopbarTitle() { var title = document.querySelector('[data-page-title-current="true"]'); return title && title.textContent ? title.textContent.trim() : '无标题'; } function fileTreeRowTitleForShortcut(row, fallback) { var title = row && row.querySelector ? row.querySelector(':scope > .tree-link > .tree-link-title') : null; return title && title.textContent ? title.textContent.trim() : (fallback || '文件夹'); } function isRetiredOcrSidecarMarkdownPath(relativePath) { var normalized = String(relativePath || '').trim().replace(/\\/g, '/').replace(/^\/+/, ''); return /(^|\/)[^/]+\.ocr\/[^/]+\.ocr\.md$/i.test(normalized); } function sidebarShortcutRows() { return Array.from(document.querySelectorAll('.wolai-starred-section [data-mnote-shortcut-kind]')); } function shortcutMatches(row, kind, targetId, relativePath, documentId) { if (!(row instanceof HTMLElement)) return false; if ((row.getAttribute('data-mnote-shortcut-kind') || '') !== kind) return false; if (documentId && (row.getAttribute('data-mnote-shortcut-document-id') || row.getAttribute('data-document-id') || '') === documentId) return true; if (relativePath && (row.getAttribute('data-mnote-shortcut-relative-path') || '') === relativePath) return true; return Boolean(targetId && (row.getAttribute('data-mnote-shortcut-target-id') || row.getAttribute('data-node-id') || '') === targetId); } async function listSidebarShortcuts(workspaceId) { var url = new URL('/api/sidebar/shortcuts', window.location.origin); url.searchParams.set('workspaceId', workspaceId); var response = await fetch(url.toString(), { method: 'GET', credentials: 'include', headers: { accept: 'application/json' }, cache: 'no-store' }); var payload = await response.json().catch(function() { return null; }); if (!response.ok) throw new Error(payload && (payload.error || payload.message) || 'sidebar_shortcuts_list_failed_' + response.status); return payload && Array.isArray(payload.shortcuts) ? payload.shortcuts : []; } function shortcutRecordMatches(shortcut, kind, targetId, relativePath, documentId) { if (!shortcut || shortcut.kind !== kind) return false; var shortcutMetadata = shortcut && shortcut.metadata && typeof shortcut.metadata === 'object' ? shortcut.metadata : {}; var shortcutRootUri = String(shortcut.rootUri || shortcut.root_uri || shortcutMetadata.rootUri || shortcutMetadata.root_uri || '').trim(); var currentShortcutRootUri = currentRootUri(); if (shortcutRootUri && currentShortcutRootUri && shortcutRootUri !== currentShortcutRootUri) return false; if (documentId && String(shortcut.documentId || shortcut.document_id || '') === documentId) return true; if (relativePath && String(shortcut.relativePath || shortcut.relative_path || '') === relativePath) return true; return Boolean(targetId && String(shortcut.targetId || shortcut.target_id || '') === targetId); } async function findSidebarShortcut(payload) { var workspaceId = payload.workspaceId || sidebarShortcutWorkspaceId(); if (!workspaceId) return null; var shortcuts = await listSidebarShortcuts(workspaceId); return shortcuts.find(function(shortcut) { return shortcutRecordMatches(shortcut, payload.kind, payload.targetId, payload.relativePath, payload.documentId); }) || null; } async function upsertSidebarShortcut(payload) { var response = await fetch('/api/sidebar/shortcuts', { method: 'POST', credentials: 'include', headers: { accept: 'application/json', 'content-type': 'application/json' }, body: JSON.stringify(payload) }); var result = await response.json().catch(function() { return null; }); if (!response.ok) throw new Error(result && (result.error || result.message) || 'sidebar_shortcut_upsert_failed_' + response.status); return result && result.shortcut ? result.shortcut : null; } async function deleteSidebarShortcut(shortcutId) { if (!shortcutId) return false; var response = await fetch('/api/sidebar/shortcuts/' + encodeURIComponent(shortcutId), { method: 'DELETE', credentials: 'include', headers: { accept: 'application/json' } }); var result = await response.json().catch(function() { return null; }); if (!response.ok) throw new Error(result && (result.error || result.message) || 'sidebar_shortcut_delete_failed_' + response.status); return true; } function closeSidebarShortcutMenu() { var existing = document.querySelector('[data-testid="mnote-sidebar-shortcut-menu"]'); if (existing && existing.parentElement) existing.parentElement.removeChild(existing); document.querySelectorAll('[data-mnote-shortcut-action="menu"][aria-expanded="true"]').forEach(function(button) { button.setAttribute('aria-expanded', 'false'); }); } async function removeSidebarShortcutByRow(row) { if (!(row instanceof HTMLElement)) return false; var shortcutId = String(row.getAttribute('data-mnote-shortcut-id') || '').trim(); if (!shortcutId) return false; row.setAttribute('data-mnote-shortcut-pending', 'true'); try { await deleteSidebarShortcut(shortcutId); row.remove(); closeSidebarShortcutMenu(); document.documentElement.setAttribute('data-mnote-sidebar-shortcut-last-action', 'remove'); return true; } finally { if (row.isConnected) row.removeAttribute('data-mnote-shortcut-pending'); } } function openSidebarShortcutMenu(row, trigger) { if (!(row instanceof HTMLElement)) return; closeSidebarShortcutMenu(); if (trigger instanceof HTMLElement) trigger.setAttribute('aria-expanded', 'true'); var rect = trigger && trigger.getBoundingClientRect ? trigger.getBoundingClientRect() : row.getBoundingClientRect(); var menu = document.createElement('div'); menu.className = 'mnote-tree-context-menu'; menu.setAttribute('role', 'menu'); menu.setAttribute('data-testid', 'mnote-sidebar-shortcut-menu'); menu.innerHTML = ''; menu.__mnoteShortcutRow = row; document.body.appendChild(menu); var width = menu.offsetWidth || 220; var left = Math.min(Math.max(8, rect.right - width), Math.max(8, window.innerWidth - width - 8)); var top = Math.min(Math.max(8, rect.bottom + 4), Math.max(8, window.innerHeight - (menu.offsetHeight || 120) - 8)); menu.style.left = left + 'px'; menu.style.top = top + 'px'; } function removeSidebarShortcutRow(shortcut) { sidebarShortcutRows().forEach(function(row) { if (shortcutMatches( row, shortcut.kind, String(shortcut.targetId || shortcut.target_id || ''), String(shortcut.relativePath || shortcut.relative_path || ''), String(shortcut.documentId || shortcut.document_id || '') )) { row.remove(); } }); } function renderSidebarShortcutRow(shortcut) { if (!shortcut) return; var section = document.querySelector('.wolai-starred-section'); if (!(section instanceof HTMLElement)) return; removeSidebarShortcutRow(shortcut); var kind = String(shortcut.kind || '').trim(); var shortcutId = String(shortcut.id || shortcut.targetId || shortcut.target_id || '').trim(); var targetId = String(shortcut.targetId || shortcut.target_id || '').trim(); var relativePath = String(shortcut.relativePath || shortcut.relative_path || '').trim(); var documentId = String(shortcut.documentId || shortcut.document_id || '').trim(); var sourceKind = String(shortcut.sourceKind || shortcut.source_kind || '').trim(); var metadata = shortcut.metadata && typeof shortcut.metadata === 'object' ? shortcut.metadata : {}; var rootUri = String(shortcut.rootUri || shortcut.root_uri || metadata.rootUri || metadata.root_uri || '').trim(); var workspaceId = String(shortcut.workspaceId || shortcut.workspace_id || sidebarShortcutWorkspaceId() || '').trim(); var title = String(shortcut.title || (kind === 'folder' ? '文件夹' : '无标题')).trim(); var href = ''; if (documentId) { var targetUrl = new URL('/documents/' + encodeURIComponent(documentId), window.location.origin); if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId); if (sourceKind) targetUrl.searchParams.set('sourceKind', sourceKind); if (rootUri) targetUrl.searchParams.set('rootUri', rootUri); href = targetUrl.pathname + targetUrl.search; } var row = document.createElement(href ? 'a' : 'div'); row.className = 'wolai-page-row'; if (href) row.setAttribute('href', href); else { row.setAttribute('role', 'button'); row.setAttribute('tabindex', '0'); } row.setAttribute('data-testid', 'wolai-sidebar-row'); row.setAttribute('data-node-id', shortcutId || targetId); row.setAttribute('data-document-id', documentId || shortcutId || targetId); if (shortcutId) row.setAttribute('data-mnote-shortcut-id', shortcutId); if (workspaceId) row.setAttribute('data-workspace-id', workspaceId); row.setAttribute('data-mnote-shortcut-kind', kind); if (sourceKind) row.setAttribute('data-mnote-shortcut-source-kind', sourceKind); row.setAttribute('data-mnote-shortcut-target-id', targetId); if (relativePath) row.setAttribute('data-mnote-shortcut-relative-path', relativePath); if (rootUri) row.setAttribute('data-mnote-shortcut-root-uri', rootUri); if (documentId) row.setAttribute('data-mnote-shortcut-document-id', documentId); row.setAttribute('data-depth', '0'); row.setAttribute('data-active', String(documentId && documentId === currentDocumentId())); row.innerHTML = '' + escapeHtml(title) + ''; section.appendChild(row); } async function toggleSidebarShortcut(payload) { var workspaceId = payload.workspaceId || sidebarShortcutWorkspaceId(); if (!workspaceId) return false; var normalized = Object.assign({}, payload, { workspaceId: workspaceId }); var existing = await findSidebarShortcut(normalized); if (existing && existing.id) { await deleteSidebarShortcut(existing.id); removeSidebarShortcutRow(existing); document.documentElement.setAttribute('data-mnote-sidebar-shortcut-last-action', 'remove'); return true; } var shortcut = await upsertSidebarShortcut(normalized); renderSidebarShortcutRow(shortcut); document.documentElement.setAttribute('data-mnote-sidebar-shortcut-last-action', 'upsert'); return true; } function currentPageShortcutPayload() { var documentId = currentDocumentId(); var workspaceId = sidebarShortcutWorkspaceId(); if (!documentId || !workspaceId) return null; return { workspaceId: workspaceId, kind: 'page', sourceKind: sidebarShortcutSourceKind(), targetId: documentId, documentId: documentId, title: currentTopbarTitle(), icon: 'star', rootUri: currentRootUri(), metadataJson: JSON.stringify({ rootUri: currentRootUri() }) }; } function folderShortcutPayload(detail, trigger) { detail = detail || {}; var row = trigger && trigger.closest ? trigger.closest('.tree-row[data-shell-mode="filetree"]') : trigger; var rowKind = String(detail.rowKind || (row && row.getAttribute('data-row-kind')) || '').trim(); if (rowKind !== 'folder' && rowKind !== 'directory') return null; var relativePath = String(detail.localRelativePath || (row && row.getAttribute('data-local-relative-path')) || '').trim(); if (!relativePath) return null; var workspaceId = String(detail.workspaceId || sidebarShortcutWorkspaceId() || '').trim(); if (!workspaceId) return null; var rowId = String(detail.rowId || (row && row.getAttribute('data-row-id')) || '').trim(); return { workspaceId: workspaceId, kind: 'folder', sourceKind: 'local_folder', targetId: rowId || ('folder:' + relativePath), relativePath: relativePath, title: detail.title || fileTreeRowTitleForShortcut(row, relativePath), icon: 'folder_open', rootUri: currentRootUri(), metadataJson: JSON.stringify({ rootUri: currentRootUri() }) }; } async function toggleCurrentPageSidebarShortcut(trigger) { var payload = currentPageShortcutPayload(); if (!payload) return; if (trigger instanceof HTMLElement) trigger.setAttribute('data-mnote-shortcut-pending', 'true'); try { await toggleSidebarShortcut(payload); } finally { if (trigger instanceof HTMLElement) trigger.removeAttribute('data-mnote-shortcut-pending'); } } async function toggleFolderSidebarShortcut(detail, trigger) { var payload = folderShortcutPayload(detail, trigger); if (!payload) return false; await toggleSidebarShortcut(payload); return true; } function ensureStarredFolderFileTreeHost(workspaceId) { var root = document.getElementById('sidebar-file-tree-root'); if (root instanceof HTMLElement) return root; var panel = document.getElementById('wolai-sidebar-file-tree-panel'); if (!(panel instanceof HTMLElement)) return null; var section = document.createElement('div'); section.className = 'sidebar-tree-section sidebar-file-tree-section'; root = document.createElement('div'); root.id = 'sidebar-file-tree-root'; root.className = 'sidebar-tree'; root.setAttribute('data-tree-shell-mode', 'filetree'); if (workspaceId) root.setAttribute('data-workspace-id', workspaceId); section.appendChild(root); panel.appendChild(section); return root; } function ensureStarredFolderPageTreeHost(workspaceId) { var root = document.getElementById('sidebar-tree-root'); if (root instanceof HTMLElement) return root; var panel = document.getElementById('wolai-sidebar-page-tree-panel') || document.querySelector('[data-mnote-sidebar-tree-panel="page"]'); if (!(panel instanceof HTMLElement)) return null; var section = document.createElement('div'); section.className = 'sidebar-tree-section'; root = document.createElement('div'); root.id = 'sidebar-tree-root'; root.className = 'sidebar-tree'; root.setAttribute('data-tree-shell-mode', 'page'); if (workspaceId) root.setAttribute('data-workspace-id', workspaceId); section.appendChild(root); panel.appendChild(section); return root; } function persistStarredFolderScope(workspaceId, rootUri, relativePath) { var targetUrl = new URL(window.location.href); if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId); targetUrl.searchParams.set('sourceKind', 'local_folder'); targetUrl.searchParams.set('rootUri', rootUri); targetUrl.searchParams.set('treeView', 'filetree'); targetUrl.searchParams.set('fileTreeScope', relativePath); window.history.replaceState(window.history.state, '', targetUrl.pathname + targetUrl.search + targetUrl.hash); if (document.body instanceof HTMLElement) { document.body.setAttribute('data-mnote-source-kind', 'local_folder'); document.body.setAttribute('data-mnote-root-uri', rootUri); } } function readShortcutRootUri(row) { if (!(row instanceof HTMLElement)) return ''; return String(row.getAttribute('data-mnote-shortcut-root-uri') || '').trim(); } async function openStarredFolderShortcut(row) { if (!(row instanceof HTMLElement)) return false; var relativePath = String(row.getAttribute('data-mnote-shortcut-relative-path') || '').trim(); var workspaceId = String(row.getAttribute('data-workspace-id') || '').trim() || sidebarShortcutWorkspaceId(); var rootUri = readShortcutRootUri(row); if (!relativePath || !rootUri || !workspaceId) { document.documentElement.setAttribute('data-mnote-sidebar-shortcut-open-error', !rootUri ? 'missing_root_uri' : 'missing_target'); return false; } document.documentElement.removeAttribute('data-mnote-sidebar-shortcut-open-error'); var tab = document.querySelector('[data-mnote-sidebar-tree-tab="filetree"]'); if (tab instanceof HTMLElement) switchSidebarTreeTab(tab); var root = ensureStarredFolderFileTreeHost(workspaceId); var pageRoot = ensureStarredFolderPageTreeHost(workspaceId); if (root instanceof HTMLElement) { root.setAttribute('data-workspace-id', workspaceId); root.setAttribute('data-mnote-filetree-scope', relativePath); root.setAttribute('data-mnote-filetree-scope-title', row.textContent ? row.textContent.trim() : relativePath); } if (pageRoot instanceof HTMLElement) { pageRoot.setAttribute('data-workspace-id', workspaceId); pageRoot.setAttribute('data-mnote-page-tree-scope', relativePath); } persistStarredFolderScope(workspaceId, rootUri, relativePath); void recordNavigationRecent({ kind: 'folder', sourceKind: 'local_folder', rootUri: rootUri, relativePath: relativePath, title: row.textContent ? row.textContent.trim() : relativePath, workspaceId: workspaceId }); document.documentElement.setAttribute('data-mnote-filetree-scope', relativePath); var sidebarUrl = new URL('/api/tree/projections/sidebar', window.location.origin); sidebarUrl.searchParams.set('workspaceId', workspaceId); sidebarUrl.searchParams.set('sourceKind', 'local_folder'); sidebarUrl.searchParams.set('rootUri', rootUri); sidebarUrl.searchParams.set('parentRelativePath', relativePath); var url = new URL('/api/tree/projections/file', window.location.origin); url.searchParams.set('workspaceId', workspaceId); url.searchParams.set('sourceKind', 'local_folder'); url.searchParams.set('rootUri', rootUri); url.searchParams.set('parentRelativePath', relativePath); var sidebarRequest = fetch(sidebarUrl.toString(), { method: 'GET', credentials: 'include', headers: { accept: 'application/json' }, cache: 'no-store' }); var fileRequest = fetch(url.toString(), { method: 'GET', credentials: 'include', headers: { accept: 'application/json' }, cache: 'no-store' }); var response = await fileRequest; var payload = await response.json().catch(function() { return null; }); if (!response.ok) throw new Error(payload && (payload.error || payload.message) || 'scoped_filetree_failed_' + response.status); var fileProjection = payload && (payload.result || payload); var renderedFile = renderSidebarSnapshot({ dataset: { kernel_file_tree_projection: fileProjection } }); root = document.getElementById('sidebar-file-tree-root'); if (root instanceof HTMLElement) { root.setAttribute('data-workspace-id', workspaceId); root.setAttribute('data-mnote-filetree-scope', relativePath); root.setAttribute('data-mnote-filetree-scope-title', row.textContent ? row.textContent.trim() : relativePath); } var sidebarResponse = await sidebarRequest; var sidebarPayload = await sidebarResponse.json().catch(function() { return null; }); if (!sidebarResponse.ok) throw new Error(sidebarPayload && (sidebarPayload.error || sidebarPayload.message) || 'local_page_tree_failed_' + sidebarResponse.status); var sidebarProjection = sidebarPayload && (sidebarPayload.result || sidebarPayload) || {}; var renderedPage = sidebarProjection ? await renderPageProjection(sidebarProjection) : false; root = document.getElementById('sidebar-file-tree-root'); if (root instanceof HTMLElement) { root.setAttribute('data-workspace-id', workspaceId); root.setAttribute('data-mnote-filetree-scope', relativePath); root.setAttribute('data-mnote-filetree-scope-title', row.textContent ? row.textContent.trim() : relativePath); } return renderedFile || renderedPage; } const sidebarFileTreeOpen = createSidebarFileTreeOpenRuntime({ copyWorkspaceSourceParams, currentDocumentId, currentRootUri, currentSourceKind, fileTreeIconKindForFileName: (...args) => fileTreeIconKindForFileName(...args), getNavigationInFlight: () => mnoteNavigationInFlight, isCodeAttachmentFileName: (...args) => isCodeAttachmentFileName(...args), isNonOfficeAttachmentName: (...args) => isNonOfficeAttachmentName(...args), isPdfAttachmentFileName: (...args) => isPdfAttachmentFileName(...args), openCodeEditorAttachment: (...args) => openCodeEditorAttachment(...args), resolveWorkspaceId, setNavigationInFlight: (value) => { mnoteNavigationInFlight = String(value || ''); }, shouldOpenLocalResourceInNewWindow: (...args) => shouldOpenLocalResourceInNewWindow(...args), uploadedFileSize: (...args) => uploadedFileSize(...args), }); const inferOnlyOfficeFileType = (...args) => sidebarFileTreeOpen.inferOnlyOfficeFileType(...args); const buildOnlyOfficeOpenUrl = (...args) => sidebarFileTreeOpen.buildOnlyOfficeOpenUrl(...args); const buildOnlyOfficeOpenPath = (...args) => sidebarFileTreeOpen.buildOnlyOfficeOpenPath(...args); const buildOfficePreviewOpenUrl = (...args) => sidebarFileTreeOpen.buildOfficePreviewOpenUrl(...args); const buildPdfPreviewOpenUrl = (...args) => sidebarFileTreeOpen.buildPdfPreviewOpenUrl(...args); const buildLocalOnlyOfficeOpenUrl = (...args) => sidebarFileTreeOpen.buildLocalOnlyOfficeOpenUrl(...args); const openLocalOfficeFileInActiveTab = (...args) => sidebarFileTreeOpen.openLocalOfficeFileInActiveTab(...args); const buildMindmapOpenPath = (...args) => sidebarFileTreeOpen.buildMindmapOpenPath(...args); const navigateToMindmapObject = (...args) => sidebarFileTreeOpen.navigateToMindmapObject(...args); const isMindmapAssetDetail = (...args) => sidebarFileTreeOpen.isMindmapAssetDetail(...args); const localFilePathFromAssetId = (...args) => sidebarFileTreeOpen.localFilePathFromAssetId(...args); const buildLocalFileOpenUrl = (...args) => sidebarFileTreeOpen.buildLocalFileOpenUrl(...args); const openLocalResourceInActiveTab = (...args) => sidebarFileTreeOpen.openLocalResourceInActiveTab(...args); const readFileTreeObjectIdentity = (...args) => sidebarFileTreeOpen.readFileTreeObjectIdentity(...args); const fetchCurrentOnlyOfficeUserId = (...args) => sidebarFileTreeOpen.fetchCurrentOnlyOfficeUserId(...args); const openConvexAssetFromFileTree = (...args) => sidebarFileTreeOpen.openConvexAssetFromFileTree(...args); var sidebarFileTreeUpload = null; const fileTreeRowsForUploadPreflight = (...args) => sidebarFileTreeUpload.fileTreeRowsForUploadPreflight(...args); const fileTreeRowCapabilities = (...args) => sidebarFileTreeUpload.fileTreeRowCapabilities(...args); const fileTreeRowIsReadonly = (...args) => sidebarFileTreeUpload.fileTreeRowIsReadonly(...args); const blockReadonlyFileTreeAction = (...args) => sidebarFileTreeUpload.blockReadonlyFileTreeAction(...args); const fileTreeDocumentParentsForPreflight = (...args) => sidebarFileTreeUpload.fileTreeDocumentParentsForPreflight(...args); const fileTreeTargetChildrenForPreflight = (...args) => sidebarFileTreeUpload.fileTreeTargetChildrenForPreflight(...args); const fileTreeDropPreflightRows = (...args) => sidebarFileTreeUpload.fileTreeDropPreflightRows(...args); const ensureFileTreeWritableTarget = (...args) => sidebarFileTreeUpload.ensureFileTreeWritableTarget(...args); const fileTreeDocumentWorkspacesForUploadPreflight = (...args) => sidebarFileTreeUpload.fileTreeDocumentWorkspacesForUploadPreflight(...args); const preflightFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.preflightFileTreeUploadTarget(...args); const fallbackFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.fallbackFileTreeUploadTarget(...args); const resolveFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.resolveFileTreeUploadTarget(...args); function localUploadRuntimeFunction(name) { var runtime = window.__mnoteLocalUploadRuntime; var fn = runtime && runtime[name]; return typeof fn === 'function' ? fn : null; } function fileTreeRuntimeFunction(name) { var runtime = window.__mnoteFileTreeRuntime; var fn = runtime && runtime[name]; return typeof fn === 'function' ? fn : null; } function fileTreeRuntimeDeps() { return { currentSourceKind: currentSourceKind, currentRootUri: currentRootUri, currentDocumentId: currentDocumentId, localFilePathFromAssetId: localFilePathFromAssetId, rowTitle: rowTitle, resolveWorkspaceId: resolveWorkspaceId, cssEscape: cssEscape, escapeHtml: escapeHtml, objectIdentityAttr: objectIdentityAttr, uploadedAssetTitle: uploadedAssetTitle, uploadedAssetType: uploadedAssetType, fileTreeIconKindForFileName: fileTreeIconKindForFileName }; } function fileTreeSelectionRuntimeFunction(name) { var runtime = window.__mnoteFileTreeSelectionRuntime; var fn = runtime && runtime[name]; return typeof fn === 'function' ? fn : null; } function fileTreeSelectionRuntimeDeps() { return { cssEscape: cssEscape }; } function uploadedAssetTitle(asset) { var runtimeFn = localUploadRuntimeFunction('uploadedAssetTitle'); if (runtimeFn) return runtimeFn(asset); return String(asset && (asset.file_name || asset.title || asset.name) || '未命名附件').trim() || '未命名附件'; } function uploadedAssetUrl(asset) { var runtimeFn = localUploadRuntimeFunction('uploadedAssetUrl'); if (runtimeFn) return runtimeFn(asset); return String(asset && (asset.sourcePath || asset.file_url || asset.signedUrl || asset.signed_url || asset.thumbnail_url) || '').trim(); } function uploadedAssetMarkdownHref(asset) { var runtimeFn = localUploadRuntimeFunction('uploadedAssetMarkdownHref'); if (runtimeFn) return runtimeFn(asset); var href = String(asset && (asset.markdownHref || asset.markdown_href) || '').trim(); if (href) { var normalizedHref = href.replace(/\\/g, '/'); if (normalizedHref.indexOf('../') === 0 || normalizedHref.indexOf('/../') >= 0) return ''; return href; } var relativePath = String(asset && (asset.markdownRelativePath || asset.markdown_relative_path) || '').trim().replace(/\\/g, '/'); if (!relativePath) return ''; if (relativePath.indexOf('../') === 0 || relativePath.indexOf('/../') >= 0) return ''; if (relativePath.indexOf('./') === 0) return relativePath; return './' + relativePath; } function localAssetOpenUrl(asset, download) { var runtimeFn = localUploadRuntimeFunction('localAssetOpenUrl'); if (runtimeFn) return runtimeFn(asset, download, { rootUri: currentRootUri() }); if (!isLocalUploadedAsset(asset)) return ''; var rootUri = String(asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri(); var rootRelativePath = String(asset && (asset.rootRelativePath || asset.root_relative_path) || '').trim(); if (!rootUri || !rootRelativePath) return ''; var url = new URL('/api/local-folder/files/open', window.location.origin); url.searchParams.set('rootUri', rootUri); url.searchParams.set('path', rootRelativePath); if (download) url.searchParams.set('download', 'true'); return url.toString(); } function uploadedAssetType(asset) { var runtimeFn = localUploadRuntimeFunction('uploadedAssetType'); if (runtimeFn) return runtimeFn(asset); return String(asset && (asset.asset_type || asset.assetType || asset.mime_type || '') || '').trim(); } function fileTreeIconKindForFileName(fileName) { var runtimeFn = localUploadRuntimeFunction('fileTreeIconKindForFileName'); if (runtimeFn) return runtimeFn(fileName); var name = String(fileName || '').trim().toLowerCase(); var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : ''; if (['doc', 'docx', 'odt', 'rtf', 'ppt', 'pptx', 'odp', 'xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'office'; if (ext === 'md' || ext === 'markdown') return 'markdown'; if (ext === 'pdf') return 'pdf'; if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp'].indexOf(ext) >= 0) return 'image'; if (['html', 'htm', 'css', 'scss', 'less', 'js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'vue', 'svelte', 'astro'].indexOf(ext) >= 0) return 'web'; if (['json', 'jsonc', 'json5', 'toml', 'yaml', 'yml', 'ini', 'env', 'xml', 'lock', 'hcl', 'tf', 'tfvars', 'nix', 'properties', 'conf', 'cfg', 'config', 'service', 'desktop', 'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'prettierrc', 'eslintrc'].indexOf(ext) >= 0 || ['.dockerignore', '.editorconfig', '.env', '.eslintrc', '.gitattributes', '.gitignore', '.npmrc', '.prettierrc', 'dockerfile', 'containerfile', 'makefile', 'cmakelists.txt', 'gemfile', 'rakefile', 'procfile'].indexOf(name) >= 0) return 'config'; if (['rs', 'py', 'go', 'java', 'c', 'cpp', 'h', 'hpp', 'cs', 'php', 'rb', 'sh', 'bash', 'zsh', 'sql', 'lua', 'dart', 'kt', 'kts', 'swift', 'scala', 'gradle', 'groovy', 'clj', 'ex', 'exs', 'erl', 'hrl', 'fs', 'fsx', 'r', 'jl', 'm', 'mm', 'pl', 'pm', 'ps1', 'bat', 'cmd', 'psm1', 'psd1', 'proto', 'graphql', 'gql', 'prisma', 'cmake', 'bazel', 'bzl'].indexOf(ext) >= 0) return 'code'; return ''; } function shouldOpenLocalResourceInNewWindow(fileName) { return false; } function isLocalUploadedAsset(asset) { var runtimeFn = localUploadRuntimeFunction('isLocalUploadedAsset'); if (runtimeFn) return runtimeFn(asset); var id = String(asset && asset.id || '').trim(); return String(asset && asset.sourceKind || '').trim() === 'local_folder' || id.indexOf('local:asset:') === 0; } function uploadedAssetExtension(asset) { var runtimeFn = localUploadRuntimeFunction('uploadedAssetExtension'); if (runtimeFn) return runtimeFn(asset); var match = uploadedAssetTitle(asset).toLowerCase().match(/\.([a-z0-9]+)$/); return match ? match[1] : ''; } function isNonOfficeAttachmentName(name, ext) { var runtimeFn = localUploadRuntimeFunction('isNonOfficeAttachmentName'); if (runtimeFn) return runtimeFn(name, ext); var codeFileNames = [ '.dockerignore', '.editorconfig', '.env', '.eslintrc', '.gitattributes', '.gitignore', '.npmrc', '.prettierrc', 'dockerfile', 'makefile', 'cmakelists.txt', 'gemfile', 'rakefile', 'procfile' ]; return [ 'pdf', 'toml', 'json', 'yaml', 'yml', 'md', 'markdown', 'txt', 'ini', 'env', 'xml', 'html', 'htm', 'css', 'scss', 'less', 'js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'py', 'rs', 'go', 'java', 'c', 'cpp', 'h', 'hpp', 'cs', 'php', 'rb', 'sh', 'bash', 'zsh', 'sql', 'lock', 'log', 'vue', 'svelte', 'astro', 'jsonc', 'json5', 'mts', 'cts', 'lua', 'dart', 'kt', 'kts', 'swift', 'scala', 'gradle', 'groovy', 'clj', 'ex', 'exs', 'erl', 'hrl', 'fs', 'fsx', 'r', 'jl', 'm', 'mm', 'pl', 'pm', 'ps1', 'bat', 'cmd', 'psm1', 'psd1', 'dockerfile', 'containerfile', 'proto', 'graphql', 'gql', 'prisma', 'tf', 'tfvars', 'hcl', 'nix', 'cmake', 'bazel', 'bzl', 'properties', 'conf', 'cfg', 'config', 'service', 'desktop', 'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'prettierrc', 'eslintrc' ].indexOf(ext) >= 0 || codeFileNames.indexOf(name) >= 0; } function attachmentExtensionFromFileName(fileName) { var runtimeFn = localUploadRuntimeFunction('attachmentExtensionFromFileName'); if (runtimeFn) return runtimeFn(fileName); var name = String(fileName || '').trim().toLowerCase(); return name.indexOf('.') >= 0 ? name.split('.').pop() : ''; } function isPdfAttachmentFileName(fileName) { var runtimeFn = localUploadRuntimeFunction('isPdfAttachmentFileName'); if (runtimeFn) return runtimeFn(fileName); return attachmentExtensionFromFileName(fileName) === 'pdf'; } function isCodeAttachmentFileName(fileName) { var runtimeFn = localUploadRuntimeFunction('isCodeAttachmentFileName'); if (runtimeFn) return runtimeFn(fileName); var name = String(fileName || '').trim().toLowerCase(); var ext = attachmentExtensionFromFileName(name); return ext !== 'pdf' && isNonOfficeAttachmentName(name, ext); } function inferCodeAttachmentLanguage(fileName) { var runtimeFn = localUploadRuntimeFunction('inferCodeAttachmentLanguage'); if (runtimeFn) return runtimeFn(fileName); var name = String(fileName || '').trim().toLowerCase(); var ext = attachmentExtensionFromFileName(name); var byName = { 'dockerfile': 'dockerfile', 'makefile': 'makefile', 'cmakelists.txt': 'cmake', '.gitignore': 'gitignore', '.gitattributes': 'gitattributes', '.editorconfig': 'ini', '.env': 'dotenv' }; if (byName[name]) return byName[name]; var byExt = { bash: 'bash', bat: 'batch', c: 'c', cjs: 'javascript', cmd: 'batch', conf: 'text', cpp: 'cpp', cs: 'csharp', css: 'css', cts: 'typescript', dart: 'dart', dockerfile: 'dockerfile', env: 'dotenv', go: 'go', gql: 'graphql', gradle: 'groovy', graphql: 'graphql', h: 'c', hcl: 'hcl', hpp: 'cpp', htm: 'html', html: 'html', ini: 'ini', java: 'java', js: 'javascript', json: 'json', json5: 'json', jsonc: 'jsonc', jsx: 'javascript', kt: 'kotlin', kts: 'kotlin', less: 'less', log: 'text', lua: 'lua', m: 'objective-c', markdown: 'markdown', md: 'markdown', mjs: 'javascript', mts: 'typescript', nix: 'nix', php: 'php', pl: 'perl', pm: 'perl', prisma: 'prisma', proto: 'protobuf', ps1: 'powershell', py: 'python', r: 'r', rb: 'ruby', rs: 'rust', scss: 'scss', sh: 'bash', sql: 'sql', svelte: 'svelte', swift: 'swift', tf: 'terraform', tfvars: 'terraform', toml: 'toml', ts: 'typescript', tsx: 'typescript', txt: 'text', vue: 'vue', xml: 'xml', yaml: 'yaml', yml: 'yaml', zsh: 'bash' }; return byExt[ext] || 'text'; } function attachmentClassForFileName(fileName) { var runtimeFn = localUploadRuntimeFunction('attachmentClassForFileName'); if (runtimeFn) return runtimeFn(fileName); var name = String(fileName || '').trim().toLowerCase(); var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : ''; if (['doc', 'docx', 'odt', 'rtf'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-word'; if (['ppt', 'pptx', 'odp'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-ppt'; if (['xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-sheet'; if (ext === 'pdf') return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-pdf'; if (isNonOfficeAttachmentName(name, ext)) { return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-code'; } return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-file'; } function uploadedAttachmentClass(asset) { var runtimeFn = localUploadRuntimeFunction('uploadedAttachmentClass'); if (runtimeFn) return runtimeFn(asset); return attachmentClassForFileName(uploadedAssetTitle(asset)); } function buildOnlyOfficeAssetOpenUrl(asset, userId) { var title = uploadedAssetTitle(asset); var fileType = inferOnlyOfficeFileType(title, asset && asset.mime_type); if (!fileType) return ''; var assetId = String(asset && asset.id || '').trim(); if (isLocalUploadedAsset(asset)) { var localUrl = localAssetOpenUrl(asset, false); if (!localUrl) return ''; return buildOnlyOfficeOpenUrl({ fileUrl: localUrl, fileName: title, fileType: fileType, assetId: assetId, documentId: String(asset && (asset.document_id || asset.documentId) || currentDocumentId() || '').trim(), userId: userId || '', mode: 'view' }); } return buildOnlyOfficeOpenUrl({ fileUrl: assetId ? '' : uploadedAssetUrl(asset), fileName: title, fileType: fileType, assetId: assetId, documentId: String(asset && (asset.document_id || asset.documentId) || currentDocumentId() || '').trim(), userId: userId || '', mode: 'view' }); } function uploadedFileSize(asset) { var runtimeFn = localUploadRuntimeFunction('uploadedFileSize'); if (runtimeFn) return runtimeFn(asset); var size = Number(asset && (asset.file_size || asset.fileSize) || 0); if (!Number.isFinite(size) || size <= 0) return ''; if (size >= 1024 * 1024) return (size / 1024 / 1024).toFixed(size >= 10 * 1024 * 1024 ? 1 : 2) + ' MB'; if (size >= 1024) return (size / 1024).toFixed(size >= 100 * 1024 ? 0 : 2) + ' KB'; return String(Math.round(size)) + ' B'; } var attachmentMetaCache = Object.create(null); var attachmentMetaPending = Object.create(null); var legacyOfficeAttachmentIndex = null; var legacyOfficeAttachmentIndexPending = null; function parseCurrentWorkspaceId() { return (new URLSearchParams(window.location.search).get('workspaceId') || '').trim(); } async function fetchLegacyOfficeAttachmentIndex() { if (legacyOfficeAttachmentIndex) return legacyOfficeAttachmentIndex; if (legacyOfficeAttachmentIndexPending) return legacyOfficeAttachmentIndexPending; var documentId = currentDocumentId(); var workspaceId = parseCurrentWorkspaceId(); if (!documentId || !workspaceId) { legacyOfficeAttachmentIndex = Object.create(null); return legacyOfficeAttachmentIndex; } var projectionUrl = new URL('/api/tree/projections/file', window.location.origin); projectionUrl.searchParams.set('documentId', documentId); projectionUrl.searchParams.set('workspaceId', workspaceId); var sourcePayload = currentWorkspaceSourcePayload(); if (sourcePayload.sourceKind) projectionUrl.searchParams.set('sourceKind', sourcePayload.sourceKind); if (sourcePayload.rootUri) projectionUrl.searchParams.set('rootUri', sourcePayload.rootUri); legacyOfficeAttachmentIndexPending = fetch(projectionUrl.toString(), { method: 'GET', credentials: 'include', cache: 'no-store' }).then(function(response) { return response.json().catch(function() { return null; }).then(function(payload) { var items = payload && payload.ok && payload.result && Array.isArray(payload.result.items) ? payload.result.items : []; var index = Object.create(null); items.forEach(function(item) { if (!item || item.rowKind !== 'asset') return; var title = String(item.title || '').trim(); if (!title || index[title]) return; var fileType = inferOnlyOfficeFileType(title, ''); if (!fileType) return; var rowId = String(item.rowId || '').trim(); var assetId = String(item.assetId || '').trim(); if (!assetId && rowId.indexOf('asset:') === 0) assetId = rowId.slice('asset:'.length); if (!assetId) return; index[title] = { assetId: assetId, fileName: title, fileType: fileType, documentId: documentId }; }); legacyOfficeAttachmentIndex = index; return index; }); }).catch(function() { var empty = Object.create(null); legacyOfficeAttachmentIndex = empty; return empty; }).finally(function() { legacyOfficeAttachmentIndexPending = null; }); return legacyOfficeAttachmentIndexPending; } async function healLegacyOfficeAttachmentParagraphs() { var editor = document.querySelector('.editor-surface .ProseMirror'); if (!(editor instanceof HTMLElement)) return; var paragraphs = Array.from(editor.querySelectorAll('p')); var candidates = paragraphs.filter(function(paragraph) { if (!(paragraph instanceof HTMLParagraphElement)) return; if (paragraph.querySelector('a, img, video, audio, table, iframe, canvas')) return; if (paragraph.childNodes.length !== 1 || paragraph.firstChild?.nodeType !== Node.TEXT_NODE) return; var fileName = String(paragraph.textContent || '').trim(); if (!fileName) return; return Boolean(inferOnlyOfficeFileType(fileName, '')); }); if (!candidates.length) return; var index = await fetchLegacyOfficeAttachmentIndex(); candidates.forEach(function(paragraph) { var fileName = String(paragraph.textContent || '').trim(); var detail = index[fileName]; if (!detail) return; var link = document.createElement('a'); link.textContent = fileName; link.setAttribute('href', buildOnlyOfficeOpenPath({ fileUrl: '', fileName: detail.fileName, fileType: detail.fileType, assetId: detail.assetId, documentId: detail.documentId || currentDocumentId() || '', userId: '', mode: 'view' })); link.setAttribute('data-asset-id', detail.assetId); attachmentClassForFileName(fileName).split(/\s+/).forEach(function(name) { if (name) link.classList.add(name); }); paragraph.replaceChildren(link); enhanceEditorAttachmentLink(link); }); } function applyEditorAttachmentMeta(link, meta) { if (!(link instanceof HTMLAnchorElement) || !meta) return; if (meta.assetId) link.setAttribute('data-asset-id', meta.assetId); if (meta.fileSize) link.setAttribute('data-file-size', meta.fileSize); } async function hydrateEditorAttachmentMeta(link) { if (!(link instanceof HTMLAnchorElement)) return; var detail = detailFromEditorAttachmentLink(link); var assetId = String(detail && detail.assetId || '').trim(); if (!assetId) return; var localFilePath = localFilePathFromAssetId(assetId); if (localFilePath) { var localMeta = { assetId: assetId, fileSize: String(detail && detail.fileSize || '').trim() }; attachmentMetaCache[assetId] = localMeta; applyEditorAttachmentMeta(link, localMeta); return; } if (attachmentMetaCache[assetId]) { applyEditorAttachmentMeta(link, attachmentMetaCache[assetId]); return; } if (attachmentMetaPending[assetId]) { try { await attachmentMetaPending[assetId]; } catch (_) {} applyEditorAttachmentMeta(link, attachmentMetaCache[assetId]); return; } document.documentElement.setAttribute('data-mnote-media-sign-retired', 'true'); attachmentMetaPending[assetId] = Promise.resolve(null).finally(function() { delete attachmentMetaPending[assetId]; }); try { var meta = await attachmentMetaPending[assetId]; applyEditorAttachmentMeta(link, meta); } catch (_) {} } function revealFileTreeRow(row) { var runtimeFn = fileTreeRuntimeFunction('revealFileTreeRow'); if (runtimeFn) return runtimeFn(row, fileTreeRuntimeDeps()); 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) { var runtimeFn = fileTreeRuntimeFunction('revealFileTreeAssetRow'); if (runtimeFn) return runtimeFn(assetId, fileTreeRuntimeDeps()); if (!assetId) return false; 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) { var runtimeFn = fileTreeRuntimeFunction('appendUploadedAssetRow'); if (runtimeFn) return runtimeFn(asset, documentId, fileTreeRuntimeDeps()); var assetId = String(asset && asset.id || '').trim(); if (!assetId) return false; if (revealFileTreeAssetRow(assetId)) 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 = ''; container.appendChild(li); revealFileTreeRow(li.querySelector('.tree-row')); document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId); return true; } function removeFileTreeAssetRow(assetId) { var normalized = String(assetId || '').trim(); if (!normalized) return false; var row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(normalized) + '"]'); var node = row ? row.closest('.tree-node') : null; if (!node || !node.parentElement) return false; node.parentElement.removeChild(node); return true; } function applyAssetsChangedToFileTree(detail) { detail = detail || {}; var docId = String(detail.docId || detail.documentId || currentDocumentId() || '').trim(); var changed = false; var explicitAsset = detail.asset && typeof detail.asset === 'object' ? detail.asset : null; if (explicitAsset) { appendUploadedAssetRow(explicitAsset, docId); changed = true; } var mindmapAssetIds = Array.isArray(detail.mindmapAssetIds) ? detail.mindmapAssetIds : []; if (detail.mindmapDeleted === true) { mindmapAssetIds.forEach(function(assetId) { if (removeFileTreeAssetRow(assetId)) changed = true; }); } if (changed) { document.documentElement.setAttribute('data-mnote-assets-local-applied', 'true'); } } function mindmapAssetFromTarget(documentId, mindmapId, writeResult) { var docId = String(documentId || currentDocumentId() || '').trim(); var assetId = String(mindmapId || '').trim(); if (!docId || !assetId) return null; var result = writeResult && typeof writeResult === 'object' ? writeResult : {}; var resultAssetId = String(result.assetId || result.id || '').trim(); var relativePath = String(result.relativePath || result.rootRelativePath || '').trim(); var fileName = String(result.fileName || '').trim() || shortMindmapFileName(assetId); return { id: resultAssetId || (relativePath ? 'local-file:' + relativePath : assetId), document_id: docId, asset_type: 'mindmap', file_name: fileName, file_url: relativePath || ('/documents/' + encodeURIComponent(docId) + '/' + encodeURIComponent(fileName)), sourcePath: relativePath, rootRelativePath: relativePath, sourceKind: currentSourceKind(), rootUri: currentRootUri(), objectKind: 'mindmap' }; } function shortMindmapFileName(mindmapId) { var runtimeFn = fileTreeRuntimeFunction('shortMindmapFileName'); if (runtimeFn) return runtimeFn(mindmapId); var raw = String(mindmapId || '').trim(); var pathName = raw.indexOf('/') >= 0 ? raw.split('/').pop() : raw; if (/\.json$/i.test(pathName)) return pathName; var digits = raw.match(/(\d{4,})$/); var suffix = digits ? digits[1].slice(-6) : ''; return suffix ? '思维导图' + suffix + '.json' : '思维导图.json'; } function parseMindmapApiTarget(input) { var runtimeFn = fileTreeRuntimeFunction('parseMindmapApiTarget'); if (runtimeFn) return runtimeFn(input); try { var rawUrl = typeof input === 'string' ? input : input && typeof input.url === 'string' ? input.url : ''; if (!rawUrl) return null; var url = new URL(rawUrl, window.location.origin); var match = /^\/api\/mindmap\/([^/]+)\/([^/]+)$/.exec(url.pathname); if (!match) return null; return { documentId: decodeURIComponent(match[1]), mindmapId: decodeURIComponent(match[2]) }; } catch (_) { return null; } } function withLocalMindmapSourceParams(input) { var target = parseMindmapApiTarget(input); if (!target || currentSourceKind() !== 'local_folder') return input; var rootUri = currentRootUri(); if (!rootUri) return input; var rawUrl = typeof input === 'string' ? input : input && typeof input.url === 'string' ? input.url : ''; if (!rawUrl) return input; var url = new URL(rawUrl, window.location.origin); url.searchParams.set('sourceKind', 'local_folder'); url.searchParams.set('rootUri', rootUri); if (typeof input === 'string') return url.pathname + url.search; if (typeof Request !== 'undefined' && input instanceof Request) { return new Request(url.toString(), input); } return url.toString(); } function requestMethod(input, init) { var runtimeFn = fileTreeRuntimeFunction('requestMethod'); if (runtimeFn) return runtimeFn(input, init); return String( init && init.method ? init.method : input && typeof input.method === 'string' ? input.method : 'GET' ).toUpperCase(); } function requestBodyHasMindmapCreateOnly(init) { var runtimeFn = fileTreeRuntimeFunction('requestBodyHasMindmapCreateOnly'); if (runtimeFn) return runtimeFn(init); var body = init && typeof init.body === 'string' ? init.body : ''; if (!body) return false; try { var payload = JSON.parse(body); return payload && payload.createOnly === true; } catch (_) { return false; } } function applyMindmapApiMutationToFileTree(target, payload) { if (!target || !target.documentId || !target.mindmapId) return; var asset = mindmapAssetFromTarget(target.documentId, target.mindmapId, payload && payload.writeResult); if (!asset) return; var appended = appendUploadedAssetRow(asset, target.documentId); if (!appended && currentSourceKind() === 'local_folder') void refreshLocalFolderSidebarSnapshot(); document.documentElement.setAttribute('data-mnote-assets-local-applied', 'true'); document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', asset.id || target.mindmapId); } function installMindmapAssetFetchObserver() { if (window.__mnoteMindmapAssetFetchObserverInstalled === true) return; if (typeof window.fetch !== 'function') return; window.__mnoteMindmapAssetFetchObserverInstalled = true; var originalFetch = window.fetch.bind(window); window.fetch = function(input, init) { var nextInput = withLocalMindmapSourceParams(input); var target = parseMindmapApiTarget(nextInput); var method = requestMethod(input, init); var createOnly = requestBodyHasMindmapCreateOnly(init || {}); return originalFetch(nextInput, init).then(function(response) { if (target && method === 'POST' && response && response.ok) { var cloned = response.clone(); void cloned.json().then(function(payload) { if (createOnly || target.documentId === currentDocumentId()) { applyMindmapApiMutationToFileTree(target, payload); } }).catch(function() { if (createOnly || target.documentId === currentDocumentId()) { applyMindmapApiMutationToFileTree(target, null); } }); } return response; }); }; } async function archiveLocalFileTreeAsset(row, assetId) { if (!assetId) return false; await dispatchTreeCommand(row || document.body, { action: 'archive', workspaceId: resolveWorkspaceId(row || document.body), documentId: assetId }); removeFileTreeAssetRow(assetId); return true; } async function deleteSingleFileTreeAsset(detail, trigger) { var assetId = String(detail && detail.assetId || '').trim(); if (!assetId) return false; var row = trigger && trigger.closest ? trigger.closest('.tree-row[data-shell-mode="filetree"]') : null; if (!row) row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(assetId) + '"]'); if (currentSourceKind() === 'local_folder') { return archiveLocalFileTreeAsset(row, assetId); } var documentId = String(detail && detail.documentId || '').trim(); var kind = classifySidebarFileTreeAsset(row); if (kind === 'mindmap') { var response = await fetch('/api/mindmap/' + encodeURIComponent(documentId) + '/' + encodeURIComponent(assetId), { method: 'DELETE' }); if (!response.ok) throw new Error('mindmap_delete_failed_' + response.status); removeFileTreeAssetRow(assetId); return true; } if (kind === 'table') { var tableResponse = await fetch('/api/tables/' + encodeURIComponent(assetId), { method: 'DELETE' }); if (!tableResponse.ok) throw new Error('table_delete_failed_' + tableResponse.status); removeFileTreeAssetRow(assetId); return true; } await postSidebarFileTreeJson('/api/media/batch', { action: 'delete', assetIds: [assetId] }); removeFileTreeAssetRow(assetId); return true; } function resolveEditorUploadContext(detail) { var runtimeFn = localUploadRuntimeFunction('resolveEditorUploadContext'); if (runtimeFn) { return runtimeFn(detail || {}, { rootSelector: EDITOR_UPLOAD_ROOT_SELECTOR, editorUploadRootFromElement: editorUploadRootFromElement, currentDocumentId: currentDocumentId, resolveWorkspaceId: resolveWorkspaceId }); } var root = null; var selector = detail && detail.editorRootSelector ? String(detail.editorRootSelector) : ''; if (selector) { try { var selected = document.querySelector(selector); if (selected instanceof HTMLElement) root = selected; } catch (_) {} } if (!root && window.__mnoteIntendedSlashRoot instanceof HTMLElement && window.__mnoteIntendedSlashRoot.isConnected) { root = window.__mnoteIntendedSlashRoot; } if (!root && window.__mnoteLastEditorUploadRoot instanceof HTMLElement && window.__mnoteLastEditorUploadRoot.isConnected) { root = window.__mnoteLastEditorUploadRoot; } if (!root && document.activeElement instanceof Element) { root = editorUploadRootFromElement(document.activeElement); } if (!root) { var focused = document.querySelector(EDITOR_UPLOAD_ROOT_SELECTOR + ' .ProseMirror:focus-within'); root = editorUploadRootFromElement(focused); } if (!root) { root = document.querySelector('[data-editor-host-kind="leptos_tiptap_island"][data-pane-role="primary"]'); } var pane = root instanceof Element ? root.closest('.document-pane[data-pane-role]') : null; var shell = root instanceof Element ? root.closest('.document-shell[data-document-id]') : null; return { root: root instanceof HTMLElement ? root : null, documentId: String( detail && detail.documentId || (root instanceof HTMLElement && root.getAttribute('data-document-id')) || (pane instanceof HTMLElement && pane.getAttribute('data-pane-document-id')) || (shell instanceof HTMLElement && shell.getAttribute('data-document-id')) || currentDocumentId() || '' ).trim(), workspaceId: String( detail && detail.workspaceId || (root instanceof HTMLElement && root.getAttribute('data-workspace-id')) || (pane instanceof HTMLElement && pane.getAttribute('data-pane-workspace-id')) || (shell instanceof HTMLElement && shell.getAttribute('data-workspace-id')) || resolveWorkspaceId(document.body) || '' ).trim() }; } function editorRootFromUploadOptions(options) { var runtimeFn = localUploadRuntimeFunction('editorRootFromUploadOptions'); if (runtimeFn) { return runtimeFn(options || {}, { rootSelector: EDITOR_UPLOAD_ROOT_SELECTOR, editorUploadRootFromElement: editorUploadRootFromElement }); } if (options && options.editorRoot instanceof HTMLElement) return options.editorRoot; if (window.__mnoteIntendedSlashRoot instanceof HTMLElement && window.__mnoteIntendedSlashRoot.isConnected) { return window.__mnoteIntendedSlashRoot; } if (window.__mnoteLastEditorUploadRoot instanceof HTMLElement && window.__mnoteLastEditorUploadRoot.isConnected) { return window.__mnoteLastEditorUploadRoot; } var focused = document.querySelector(EDITOR_UPLOAD_ROOT_SELECTOR + ' .ProseMirror:focus-within'); return editorUploadRootFromElement(focused); } async function fetchWithTimeout(input, init, timeoutMs, label) { var runtimeFn = localUploadRuntimeFunction('fetchWithTimeout'); if (runtimeFn) { return await runtimeFn(input, init || {}, timeoutMs, label); } var controller = typeof AbortController === 'function' ? new AbortController() : null; var timer = 0; var timeout = Math.max(1000, Number(timeoutMs) || 15000); try { if (controller) { timer = window.setTimeout(function() { controller.abort(); }, timeout); } var nextInit = Object.assign({}, init || {}); if (controller) nextInit.signal = controller.signal; return await fetch(input, nextInit); } catch (error) { if (error && error.name === 'AbortError') { throw new Error((label || '请求') + '超时'); } throw error; } finally { if (timer) window.clearTimeout(timer); } } function uploadTimeoutMsForFile(file, requestedMs) { var runtimeFn = localUploadRuntimeFunction('uploadTimeoutMsForFile'); if (runtimeFn) return runtimeFn(file, requestedMs); var requested = Number(requestedMs) || 0; var size = Number(file && file.size || 0); if (!Number.isFinite(size) || size <= 0) return Math.max(requested, 15000); var sizeBased = 15000 + Math.ceil(size / (1024 * 1024)) * 12000; return Math.min(10 * 60 * 1000, Math.max(requested, 60000, sizeBased)); } async function insertUploadedAssetIntoEditor(asset, targetRoot) { var runtimeFn = localUploadRuntimeFunction('insertUploadedAssetIntoEditor'); if (runtimeFn) { return await runtimeFn(asset, targetRoot, { uploadedAssetTitle: uploadedAssetTitle, localAssetOpenUrl: localAssetOpenUrl, uploadedAssetUrl: uploadedAssetUrl, uploadedAssetType: uploadedAssetType, isLocalUploadedAsset: isLocalUploadedAsset, buildOnlyOfficeAssetOpenUrl: buildOnlyOfficeAssetOpenUrl, fetchCurrentOnlyOfficeUserId: fetchCurrentOnlyOfficeUserId, buildOnlyOfficeOpenPath: buildOnlyOfficeOpenPath, inferOnlyOfficeFileType: inferOnlyOfficeFileType, currentDocumentId: currentDocumentId, currentRootUri: currentRootUri, uploadedAttachmentClass: uploadedAttachmentClass, uploadedFileSize: uploadedFileSize, cssEscape: cssEscape, enhanceEditorAttachmentLinks: enhanceEditorAttachmentLinks }); } var editorRoot = targetRoot instanceof HTMLElement ? targetRoot.querySelector('.editor-surface .ProseMirror') : document.querySelector('.editor-surface .ProseMirror'); if (targetRoot instanceof HTMLElement) window.__mnoteLastEditorUploadRoot = targetRoot; var editor = editorRoot && editorRoot.editor; if (!editor || !editor.chain) { document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'false'); document.documentElement.setAttribute('data-mnote-last-upload-insert-error', 'editor_unavailable'); return false; } var title = uploadedAssetTitle(asset); var markdownHref = uploadedAssetMarkdownHref(asset); var localOpenUrl = localAssetOpenUrl(asset, false); var fallbackUrl = uploadedAssetUrl(asset); var imageUrl = localOpenUrl || fallbackUrl || markdownHref; var url = markdownHref || localOpenUrl || fallbackUrl; var type = uploadedAssetType(asset); var assetId = String(asset && asset.id || '').trim(); var sizeLabel = uploadedFileSize(asset); try { if (type === 'image' && imageUrl) { return editor.chain().focus().setImage({ src: imageUrl, alt: title, title: title }).run() === true; } var href = markdownHref || url; if (href) { var inserted = editor.chain().focus().insertContent([ { type: 'paragraph', content: [{ type: 'text', text: title, marks: [{ type: 'link', attrs: { href: href, target: '_blank', rel: 'noopener noreferrer nofollow', class: uploadedAttachmentClass(asset) } }] }] }, { type: 'paragraph' } ]).focus('end').run() === true; if (inserted) { document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'true'); document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId || ''); document.documentElement.removeAttribute('data-mnote-last-upload-insert-error'); } else { document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'false'); document.documentElement.setAttribute('data-mnote-last-upload-insert-error', 'insert_content_failed'); } window.setTimeout(function annotateUploadedLink(attempt) { if (targetRoot instanceof HTMLElement) window.__mnoteLastEditorUploadRoot = targetRoot; enhanceEditorAttachmentLinks(); var selector = assetId ? '.editor-surface .ProseMirror a[href*="' + cssEscape(assetId) + '"]' : '.editor-surface .ProseMirror a'; var link = targetRoot instanceof HTMLElement ? targetRoot.querySelector(selector) : document.querySelector(selector); if (!(link instanceof HTMLElement) && assetId) { var scope = targetRoot instanceof HTMLElement ? targetRoot : document; link = Array.from(scope.querySelectorAll('.editor-surface .ProseMirror a')).find(function(candidate) { var href = String(candidate.getAttribute('href') || ''); try { href = decodeURIComponent(href); } catch (_) {} return href.indexOf(assetId) >= 0; }) || null; } if (link instanceof HTMLElement) { if (assetId) link.setAttribute('data-asset-id', assetId); if (sizeLabel) link.setAttribute('data-file-size', sizeLabel); } else if (Number(attempt) < 20) { window.setTimeout(function() { annotateUploadedLink(Number(attempt) + 1); }, 50); } }, 0, 0); return inserted; } } catch (error) { console.warn('[mnote upload] insert uploaded asset failed', error); } return false; } async function uploadFileToMediaAsset(file, plan, options) { var runtimeFn = localUploadRuntimeFunction('uploadFileToMediaAsset'); if (runtimeFn) { return await runtimeFn(file, plan, options || {}, { currentSourceKind: currentSourceKind, currentRootUri: currentRootUri, currentDocumentId: currentDocumentId, editorRootFromUploadOptions: editorRootFromUploadOptions, appendUploadedAssetRow: appendUploadedAssetRow, refreshLocalFolderSidebarSnapshot: refreshLocalFolderSidebarSnapshot, dispatchEvent: function(event) { return window.dispatchEvent(event); }, CustomEvent: CustomEvent, buildOnlyOfficeAssetOpenUrl: buildOnlyOfficeAssetOpenUrl, fetchCurrentOnlyOfficeUserId: fetchCurrentOnlyOfficeUserId, buildOnlyOfficeOpenPath: buildOnlyOfficeOpenPath, inferOnlyOfficeFileType: inferOnlyOfficeFileType, enhanceEditorAttachmentLinks: enhanceEditorAttachmentLinks, cssEscape: cssEscape }); } if (currentSourceKind() === 'local_folder') { var rootUri = currentRootUri(); var documentId = String(plan && plan.targetDocumentId || currentDocumentId() || '').trim(); var hasFolderTarget = plan && Object.prototype.hasOwnProperty.call(plan, 'targetRelativePath'); var uploadIntent = String(plan && plan.uploadIntent || (hasFolderTarget ? 'filetree.folder.drop' : 'editor.markdown.attach')).trim(); if (!rootUri || !uploadIntent) { throw new Error('本地 Markdown 上传缺少 rootUri 或 documentId'); } var localUploadRuntime = localUploadRuntimeFunction('uploadLocalFolderAsset'); var localPayload = null; if (localUploadRuntime) { var localResult = await localUploadRuntime(file, plan, { rootUri: rootUri, documentId: documentId, timeoutMs: uploadTimeoutMsForFile(file, 15000) }); localPayload = localResult && localResult.asset ? { asset: localResult.asset } : null; } else { var localForm = new FormData(); localForm.append('file', file); localForm.append('rootUri', rootUri); localForm.append('uploadIntent', uploadIntent); if (documentId) localForm.append('documentId', documentId); if (hasFolderTarget) localForm.append('targetRelativePath', String(plan.targetRelativePath || '')); localForm.append('kind', file && String(file.type || '').indexOf('image/') === 0 ? 'image' : 'attachment'); var localResponse = await fetchWithTimeout('/api/local-folder/assets/upload', { method: 'POST', credentials: 'include', body: localForm }, uploadTimeoutMsForFile(file, 15000), '本地上传'); localPayload = await localResponse.json().catch(function() { return null; }); if (!localResponse.ok || !localPayload || !localPayload.asset) { throw new Error(localPayload && localPayload.error ? localPayload.error : '上传失败'); } } if (options && options.insertIntoEditor) { await insertUploadedAssetIntoEditor(localPayload.asset, editorRootFromUploadOptions(options)); } if (!(options && options.insertIntoEditor)) void refreshLocalFolderSidebarSnapshot(); window.dispatchEvent(new CustomEvent('wolai:local-assets-changed', { detail: { docId: documentId, asset: localPayload.asset, assetIds: [localPayload.asset.id] } })); return localPayload.asset; } var mediaUploadRuntime = localUploadRuntimeFunction('uploadMediaAsset'); var payload = null; if (mediaUploadRuntime) { var mediaResult = await mediaUploadRuntime(file, plan, { timeoutMs: 15000 }); payload = mediaResult && mediaResult.asset ? { asset: mediaResult.asset } : null; if (!payload || !payload.asset) { throw new Error('上传失败'); } } else { document.documentElement.setAttribute('data-mnote-media-upload-retired', 'true'); throw new Error('旧 Convex Files 上传链已退役;local-first 附件请使用本地文件夹上传目标。'); } appendUploadedAssetRow(payload.asset, plan.targetDocumentId); if (options && options.insertIntoEditor) { await insertUploadedAssetIntoEditor(payload.asset, editorRootFromUploadOptions(options)); } window.dispatchEvent(new CustomEvent('wolai:assets-changed', { detail: { docId: plan.targetDocumentId, asset: payload.asset, assetIds: [payload.asset.id] } })); return payload.asset; } window.addEventListener('wolai:assets-changed', function(event) { applyAssetsChangedToFileTree(event.detail || {}); }); window.addEventListener('wolai:local-assets-changed', function(event) { applyAssetsChangedToFileTree(event.detail || {}); }); window.addEventListener('mnote:knowledge-rag-source-updated', function() { if (currentSourceKind() === 'local_folder') void refreshLocalFolderSidebarSnapshot(); }); installMindmapAssetFetchObserver(); async function uploadFilesWithResolvedTarget(files, detail, options) { var runtimeFn = localUploadRuntimeFunction('uploadFilesWithResolvedTarget'); if (runtimeFn) { return await runtimeFn(files, detail || {}, options || {}, { resolveFileTreeUploadTarget: resolveFileTreeUploadTarget, uploadFileToMediaAsset: uploadFileToMediaAsset, alert: function(message) { window.alert(message); } }); } var list = Array.from(files || []).filter(Boolean); if (!list.length) return []; var plan = await resolveFileTreeUploadTarget(detail || {}); var uploaded = []; var errors = []; for (var i = 0; i < list.length; i += 1) { try { uploaded.push(await uploadFileToMediaAsset(list[i], plan, options || {})); } catch (error) { errors.push(list[i].name + ': ' + (error && error.message ? error.message : '上传失败')); } } if (errors.length) { window.alert('部分文件上传失败:\n' + errors.slice(0, 6).join('\n') + (errors.length > 6 ? '\n...' : '')); } return uploaded; } function openEditorUploadFilePicker(detail) { var runtimeFn = localUploadRuntimeFunction('openEditorUploadFilePicker'); if (runtimeFn) { return runtimeFn(detail || {}, { rootSelector: EDITOR_UPLOAD_ROOT_SELECTOR, editorUploadRootFromElement: editorUploadRootFromElement, currentDocumentId: currentDocumentId, resolveWorkspaceId: resolveWorkspaceId, uploadFilesWithResolvedTarget: uploadFilesWithResolvedTarget }); } var uploadContext = resolveEditorUploadContext(detail || {}); var input = document.createElement('input'); input.type = 'file'; input.multiple = detail && detail.multiple !== false; if (detail && detail.accept) input.accept = String(detail.accept); input.style.position = 'fixed'; input.style.left = '-9999px'; input.style.top = '-9999px'; document.body.appendChild(input); input.addEventListener('change', function() { var files = Array.from(input.files || []); input.remove(); void uploadFilesWithResolvedTarget(files, { workspaceId: uploadContext.workspaceId || resolveWorkspaceId(document.body), documentId: uploadContext.documentId || currentDocumentId(), targetRowId: null, uploadIntent: 'editor.markdown.attach' }, { insertIntoEditor: detail && detail.insertIntoEditor !== false, editorRoot: uploadContext.root }); }, { once: true }); input.click(); } window.addEventListener('mnote:editor-upload-request', function(event) { openEditorUploadFilePicker(event.detail || {}); }); window.addEventListener('tree.filetree.external-drop', function(event) { var detail = event.detail || {}; void uploadFilesWithResolvedTarget(detail.files || [], detail, { insertIntoEditor: String(detail.documentId || '') === currentDocumentId() }); }); document.addEventListener('dragover', function(event) { var editorTarget = closestAction(event.target, '[data-testid="mnote-leptos-tiptap-editor-stage"], .editor-surface .ProseMirror'); var hasFiles = event.dataTransfer && Array.prototype.indexOf.call(event.dataTransfer.types || [], 'Files') >= 0; if (!editorTarget || !hasFiles) return; event.preventDefault(); event.stopPropagation(); if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy'; }, true); document.addEventListener('drop', function(event) { var editorTarget = closestAction(event.target, '[data-testid="mnote-leptos-tiptap-editor-stage"], .editor-surface .ProseMirror'); var files = event.dataTransfer ? Array.from(event.dataTransfer.files || []) : []; if (!editorTarget || !files.length) return; event.preventDefault(); event.stopPropagation(); void uploadFilesWithResolvedTarget(files, { workspaceId: resolveWorkspaceId(document.body), documentId: currentDocumentId(), targetRowId: null, uploadIntent: 'editor.markdown.attach' }, { insertIntoEditor: true, editorRoot: editorUploadRootFromElement(editorTarget) }); }, true); const sidebarFileTreeCommandState = { get activeTreeContextMenu() { return activeTreeContextMenu; }, set activeTreeContextMenu(value) { activeTreeContextMenu = value; }, get sidebarFileTreeClipboard() { return sidebarFileTreeClipboard; }, set sidebarFileTreeClipboard(value) { sidebarFileTreeClipboard = value; }, }; const sidebarFileTreeCommand = createSidebarFileTreeCommandRuntime({ applyRemoveDocumentDelta, createFileTreeFolder, createPage, cssEscape, currentDocumentId, currentRootUri, currentSourceKind, deleteSingleFileTreeAsset, dispatchSidebarEvent, dispatchTreeCommand, ensureFileTreeWritableTarget, fileTreeRuntimeDeps, fileTreeRuntimeFunction, fileTreeSelectionRuntimeDeps, fileTreeSelectionRuntimeFunction, isFileTreePageRow, localFilePathFromAssetId, normalizeFileTreePageRenameTitle, openConvexAssetFromFileTree, openEditorAttachmentDetail: (...args) => openEditorAttachmentDetail(...args), openEditorAttachmentDownload: (...args) => openEditorAttachmentDownload(...args), openEditorAttachmentEditTab: (...args) => openEditorAttachmentEditTab(...args), openEditorAttachmentNewWindow: (...args) => openEditorAttachmentNewWindow(...args), openLocalResourceInActiveTab: (...args) => openLocalResourceInActiveTab(...args), knowledgeHostUrl, refreshLocalFolderSidebarSnapshot, removeFileTreeAssetRow, revealFileTreeResource, resolveWorkspaceId, runtimeState: sidebarFileTreeCommandState, selectedSidebarFileTreeSelection: sidebarFileTreeSelection, updateTitleEverywhere, validateFileTreeRename, }); const rowTitle = (...args) => sidebarFileTreeCommand.rowTitle(...args); const rowCenter = (...args) => sidebarFileTreeCommand.rowCenter(...args); const renameFileTreeAsset = (...args) => sidebarFileTreeCommand.renameFileTreeAsset(...args); const beginFileTreeInlineRename = (...args) => sidebarFileTreeCommand.beginFileTreeInlineRename(...args); const closeTreeContextMenu = (...args) => sidebarFileTreeCommand.closeTreeContextMenu(...args); const copyTreeContextValue = (...args) => sidebarFileTreeCommand.copyTreeContextValue(...args); const triggerBrowserDownload = (...args) => sidebarFileTreeCommand.triggerBrowserDownload(...args); const recordFileTreeAction = (...args) => sidebarFileTreeCommand.recordFileTreeAction(...args); const recordFileTreeActionStatus = (...args) => sidebarFileTreeCommand.recordFileTreeActionStatus(...args); const documentHref = (...args) => sidebarFileTreeCommand.documentHref(...args); const convertToPreviousSiblingChild = (...args) => sidebarFileTreeCommand.convertToPreviousSiblingChild(...args); const fileTreeCopyPath = (...args) => sidebarFileTreeCommand.fileTreeCopyPath(...args); const fileTreeMenuTargetParentId = (...args) => sidebarFileTreeCommand.fileTreeMenuTargetParentId(...args); const withOfficeEditModeGuard = (...args) => sidebarFileTreeCommand.withOfficeEditModeGuard(...args); const handleTreeContextMenuAction = (...args) => sidebarFileTreeCommand.handleTreeContextMenuAction(...args); const appendTreeContextMenuButton = (...args) => sidebarFileTreeCommand.appendTreeContextMenuButton(...args); const buildSidebarFileTreeContext = (...args) => sidebarFileTreeCommand.buildSidebarFileTreeContext(...args); const evaluateSidebarFileTreeWhen = (...args) => sidebarFileTreeCommand.evaluateSidebarFileTreeWhen(...args); const openTreeContextMenu = (...args) => sidebarFileTreeCommand.openTreeContextMenu(...args); const openPageTreeContextMenu = (...args) => sidebarFileTreeCommand.openPageTreeContextMenu(...args); const openFileTreeContextMenu = (...args) => sidebarFileTreeCommand.openFileTreeContextMenu(...args); const visibleFileTreeRows = (...args) => sidebarFileTreeCommand.visibleFileTreeRows(...args); const syncSidebarFileTreeSelection = (...args) => sidebarFileTreeCommand.syncSidebarFileTreeSelection(...args); const selectSidebarFileTreeRow = (...args) => sidebarFileTreeCommand.selectSidebarFileTreeRow(...args); const selectSidebarFileTreeDocument = (...args) => sidebarFileTreeCommand.selectSidebarFileTreeDocument(...args); const selectSidebarFileTreeRowById = (...args) => sidebarFileTreeCommand.selectSidebarFileTreeRowById(...args); const pendingLocalFolderRestoreRowId = (...args) => sidebarFileTreeCommand.pendingLocalFolderRestoreRowId(...args); const clearPendingLocalFolderRestoreRowId = (...args) => sidebarFileTreeCommand.clearPendingLocalFolderRestoreRowId(...args); const applyPendingLocalFolderRestoreFocusOnce = (...args) => sidebarFileTreeCommand.applyPendingLocalFolderRestoreFocusOnce(...args); const schedulePendingLocalFolderRestoreFocus = (...args) => sidebarFileTreeCommand.schedulePendingLocalFolderRestoreFocus(...args); const selectedSidebarFileTreeRowIdsForDrag = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeRowIdsForDrag(...args); const selectedSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeRows(...args); const fileTreeRowDocumentId = (...args) => sidebarFileTreeCommand.fileTreeRowDocumentId(...args); const fileTreeRowAssetId = (...args) => sidebarFileTreeCommand.fileTreeRowAssetId(...args); const decodeLocalEncodedPath = (...args) => sidebarFileTreeCommand.decodeLocalEncodedPath(...args); const fileTreeRowLocalRelativePath = (...args) => sidebarFileTreeCommand.fileTreeRowLocalRelativePath(...args); const fileTreeRowLocalUploadTargetRelativePath = (...args) => sidebarFileTreeCommand.fileTreeRowLocalUploadTargetRelativePath(...args); const readWorkspacePathFromRow = (...args) => sidebarFileTreeCommand.readWorkspacePathFromRow(...args); const fileTreeRowKind = (...args) => sidebarFileTreeCommand.fileTreeRowKind(...args); const isFileTreeDownloadableAssetRow = (...args) => sidebarFileTreeCommand.isFileTreeDownloadableAssetRow(...args); const isFileTreeDownloadableRow = (...args) => sidebarFileTreeCommand.isFileTreeDownloadableRow(...args); const fileTreeAssetDownloadDetail = (...args) => sidebarFileTreeCommand.fileTreeAssetDownloadDetail(...args); const selectedSidebarFileTreeRowsForDownload = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeRowsForDownload(...args); const selectedSidebarFileTreeAssetRowsForDownload = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeAssetRowsForDownload(...args); const downloadSelectedFileTreeAssetRows = (...args) => sidebarFileTreeCommand.downloadSelectedFileTreeAssetRows(...args); const hasSelectedDocumentAncestor = (...args) => sidebarFileTreeCommand.hasSelectedDocumentAncestor(...args); const classifySidebarFileTreeAsset = (...args) => sidebarFileTreeCommand.classifySidebarFileTreeAsset(...args); const buildSidebarFileTreeDeletePlan = (...args) => sidebarFileTreeCommand.buildSidebarFileTreeDeletePlan(...args); const sidebarFileTreeDeleteConfirmText = (...args) => sidebarFileTreeCommand.sidebarFileTreeDeleteConfirmText(...args); const postSidebarFileTreeJson = (...args) => sidebarFileTreeCommand.postSidebarFileTreeJson(...args); const fileTreeRowsByRowIds = (...args) => sidebarFileTreeCommand.fileTreeRowsByRowIds(...args); const fileTreeChildCount = (...args) => sidebarFileTreeCommand.fileTreeChildCount(...args); const moveSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.moveSidebarFileTreeRows(...args); const pasteSidebarFileTreeClipboard = (...args) => sidebarFileTreeCommand.pasteSidebarFileTreeClipboard(...args); const deleteSelectedSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.deleteSelectedSidebarFileTreeRows(...args); sidebarFileTreeUpload = createSidebarFileTreeUploadRuntime({ cssEscape, currentDocumentId, fileTreeRuntimeDeps, fileTreeRuntimeFunction, recordFileTreeAction, recordFileTreeActionStatus, resolveWorkspaceId, rowTitle, selectedSidebarFileTreeSelection: sidebarFileTreeSelection, }); function ensureSearchModal() { var existing = document.querySelector('[data-testid="wolai-search-modal"]'); if (existing instanceof HTMLElement) return existing; var overlay = document.createElement('div'); overlay.className = 'wolai-search-overlay'; overlay.setAttribute('data-testid', 'wolai-search-modal'); overlay.setAttribute('role', 'dialog'); overlay.setAttribute('aria-modal', 'true'); overlay.hidden = true; overlay.innerHTML = '' + '
' + '
' + '' + '' + '' + '
' + '' + '
' + '
' + '
'; document.body.appendChild(overlay); var input = overlay.querySelector('[data-testid="wolai-search-input"]'); var closeButton = overlay.querySelector('[data-testid="wolai-search-close"]'); applySearchSwitchState(overlay, { knowledge: false, collapseSource: readSearchCollapseSourcesDefault() }); var initialKnowledgeModeSelect = overlay.querySelector('[data-search-knowledge-mode]'); if (initialKnowledgeModeSelect && 'value' in initialKnowledgeModeSelect) initialKnowledgeModeSelect.value = 'exact'; if (input) input.addEventListener('input', function() { searchUiState.hasRendered = false; scheduleSearchResultsRender(); }); overlay.querySelectorAll('[data-search-switch]').forEach(function(button) { button.addEventListener('click', function() { var switchName = searchText(button.getAttribute('data-search-switch')); var isOn = button.getAttribute('aria-checked') !== 'true'; button.setAttribute('aria-checked', isOn ? 'true' : 'false'); button.classList.toggle('is-on', isOn); if (switchName === 'collapseSource') { writeSearchCollapseSourcesDefault(isOn); searchUiState.sourceCollapsed = {}; } searchUiState.hasRendered = false; scheduleSearchResultsRender(); }); }); var knowledgeModeSelect = overlay.querySelector('[data-search-knowledge-mode]'); if (knowledgeModeSelect) { knowledgeModeSelect.addEventListener('change', function() { searchUiState.hasRendered = false; scheduleSearchResultsRender(); }); } if (closeButton) closeButton.addEventListener('click', closeSearchModal); overlay.addEventListener('click', function(event) { if (event.target === overlay) closeSearchModal(); }); return overlay; } var activeSearchRequestId = 0; var searchRenderTimer = 0; var SEARCH_COLLAPSE_SOURCES_KEY = 'mnote.search.collapseSourcesDefault.v1'; var searchUiState = { query: '', switches: {}, metaHtml: '', resultsHtml: '', items: [], knowledgeMode: 'exact', sourceCollapsed: {}, scrollTop: 0, signature: '', hasRendered: false }; function searchText(value) { return String(value == null ? '' : value).replace(/\s+/g, ' ').trim(); } function searchNonWhitespaceCharCount(value) { return String(value == null ? '' : value).replace(/\s+/g, '').length; } function currentWorkspaceName() { var name = document.querySelector('.sidebar-workspace-name'); return searchText(name && name.textContent) || '当前工作区'; } function currentDocumentId() { var shell = document.querySelector('.document-shell[data-document-id]'); var bodyId = document.body && document.body.getAttribute('data-document-id'); return searchText(shell && shell.getAttribute('data-document-id')) || searchText(bodyId); } function localResourceDocumentIdFromPath(path) { var normalized = searchText(path).replace(/\\/g, '/'); return normalized ? 'local-resource:' + normalized.replace(/\//g, '~2F') : ''; } function currentSearchDocumentId() { var activePanel = document.querySelector('[data-mnote-resource-tab-panel][data-pane-role="primary"]:not([hidden])'); if (activePanel instanceof HTMLElement) { var resourceKind = searchText(activePanel.getAttribute('data-resource-kind')).toLowerCase(); var resourcePath = searchText(activePanel.getAttribute('data-resource-path')); if (resourceKind && resourceKind !== 'markdown' && resourcePath) return localResourceDocumentIdFromPath(resourcePath); try { var locator = JSON.parse(activePanel.getAttribute('data-mnote-evidence-locator') || 'null'); var locatorDoc = searchText(locator && (locator.ownerDocumentId || locator.owner_document_id)); if (locatorDoc) return locatorDoc; } catch (_) {} } return currentDocumentId(); } function searchSwitchValue(overlay, name) { var button = overlay.querySelector('[data-search-switch="' + name + '"]'); return button instanceof HTMLElement && button.getAttribute('aria-checked') === 'true'; } function searchKnowledgeModeValue(overlay) { var select = overlay.querySelector('[data-search-knowledge-mode]'); var value = select && 'value' in select ? searchText(select.value).toLowerCase() : ''; if (['mix', 'hybrid', 'naive', 'local', 'global', 'exact'].indexOf(value) >= 0) return value; return 'mix'; } function knowledgeSearchRequestMode(overlay) { if (searchSwitchValue(overlay, 'exact')) return 'exact'; return searchKnowledgeModeValue(overlay); } function knowledgeSearchModeLabel(mode) { if (mode === 'exact') return '关键词'; if (mode === 'naive') return '向量'; if (mode === 'local') return '实体'; if (mode === 'global') return '关系'; if (mode === 'hybrid') return '图谱混合'; return '综合'; } function readSearchCollapseSourcesDefault() { try { var stored = window.localStorage && window.localStorage.getItem(SEARCH_COLLAPSE_SOURCES_KEY); if (stored === '0') return false; if (stored === '1') return true; } catch (_) {} return true; } function writeSearchCollapseSourcesDefault(value) { try { if (window.localStorage) window.localStorage.setItem(SEARCH_COLLAPSE_SOURCES_KEY, value ? '1' : '0'); } catch (_) {} } function collectSearchSwitchState(overlay) { var state = {}; if (!(overlay instanceof HTMLElement)) return state; overlay.querySelectorAll('[data-search-switch]').forEach(function(button) { if (!(button instanceof HTMLElement)) return; var name = searchText(button.getAttribute('data-search-switch')); if (!name) return; state[name] = button.getAttribute('aria-checked') === 'true'; }); return state; } function applySearchSwitchState(overlay, switches) { if (!(overlay instanceof HTMLElement) || !switches || typeof switches !== 'object') return; overlay.querySelectorAll('[data-search-switch]').forEach(function(button) { if (!(button instanceof HTMLElement)) return; var name = searchText(button.getAttribute('data-search-switch')); if (!name || !Object.prototype.hasOwnProperty.call(switches, name)) return; var isOn = Boolean(switches[name]); button.setAttribute('aria-checked', isOn ? 'true' : 'false'); button.classList.toggle('is-on', isOn); }); } function searchRequestSignature(overlay, query) { var switches = collectSearchSwitchState(overlay); return JSON.stringify({ query: searchText(query), knowledge: Boolean(switches.knowledge), page: Boolean(switches.page), title: Boolean(switches.title), exact: Boolean(switches.exact), collapseSource: Boolean(switches.collapseSource), knowledgeMode: searchKnowledgeModeValue(overlay), workspaceId: resolveWorkspaceId(document.body) || '', rootUri: currentRootUri() || '' }); } function saveSearchUiState(overlay) { if (!(overlay instanceof HTMLElement)) return; var input = overlay.querySelector('[data-testid="wolai-search-input"]'); var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]'); var results = overlay.querySelector('[data-testid="wolai-search-results"]'); var query = input && 'value' in input ? searchText(input.value) : searchUiState.query; searchUiState.query = query; searchUiState.switches = collectSearchSwitchState(overlay); searchUiState.knowledgeMode = searchKnowledgeModeValue(overlay); searchUiState.metaHtml = meta ? meta.innerHTML : searchUiState.metaHtml; searchUiState.resultsHtml = results ? results.innerHTML : searchUiState.resultsHtml; searchUiState.items = Array.isArray(window.__mnoteSearchResults) ? window.__mnoteSearchResults.slice() : searchUiState.items; searchUiState.scrollTop = results instanceof HTMLElement ? results.scrollTop : searchUiState.scrollTop; searchUiState.signature = query ? searchRequestSignature(overlay, query) : ''; } function restoreSearchUiState(overlay) { if (!(overlay instanceof HTMLElement) || !searchUiState.hasRendered) return false; var input = overlay.querySelector('[data-testid="wolai-search-input"]'); var options = overlay.querySelector('[data-testid="wolai-search-options"]'); var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]'); var results = overlay.querySelector('[data-testid="wolai-search-results"]'); if (input && 'value' in input) input.value = searchUiState.query || ''; applySearchSwitchState(overlay, searchUiState.switches); var knowledgeModeSelect = overlay.querySelector('[data-search-knowledge-mode]'); if (knowledgeModeSelect && 'value' in knowledgeModeSelect) knowledgeModeSelect.value = searchUiState.knowledgeMode || 'exact'; if (options instanceof HTMLElement) options.hidden = !searchText(searchUiState.query); if (meta && searchUiState.metaHtml) meta.innerHTML = searchUiState.metaHtml; if (results && searchUiState.resultsHtml) { results.innerHTML = searchUiState.resultsHtml; results.scrollTop = Number(searchUiState.scrollTop || 0); } window.__mnoteSearchResults = Array.isArray(searchUiState.items) ? searchUiState.items.slice() : []; return true; } function searchHighlightTerms(item, query) { var info = item && item.matchInfo || item && item.evidence && item.evidence.matchInfo || null; var terms = info && Array.isArray(info.matchedTerms) ? info.matchedTerms : []; terms = terms.map(searchText).filter(Boolean); if (!terms.length) { terms = searchText(query).split(/[\s,;:,;:。、()[\]{}]+/).map(searchText).filter(Boolean); } terms.sort(function(left, right) { return right.length - left.length; }); return terms.filter(function(term, index) { return terms.indexOf(term) === index; }); } function highlightSearchText(value, query, exact, terms) { var text = searchText(value); var cleanQuery = searchText(query); if (!text || !cleanQuery) return escapeHtml(text); var lower = text.toLowerCase(); var lowerQuery = cleanQuery.toLowerCase(); var exactIndex = lower.indexOf(lowerQuery); if (exact || exactIndex >= 0) { if (exactIndex < 0) return escapeHtml(text); return escapeHtml(text.slice(0, exactIndex)) + '' + escapeHtml(text.slice(exactIndex, exactIndex + cleanQuery.length)) + '' + escapeHtml(text.slice(exactIndex + cleanQuery.length)); } terms = Array.isArray(terms) ? terms.map(searchText).filter(Boolean) : []; if (!terms.length) return escapeHtml(text); var ranges = []; terms.forEach(function(term) { var lowerTerm = term.toLowerCase(); var start = lower.indexOf(lowerTerm); while (start >= 0) { var end = start + lowerTerm.length; var overlaps = ranges.some(function(range) { return start < range.end && end > range.start; }); if (!overlaps) ranges.push({ start: start, end: end }); start = lower.indexOf(lowerTerm, end); } }); if (!ranges.length) return escapeHtml(text); ranges.sort(function(left, right) { return left.start - right.start; }); var html = ''; var cursor = 0; ranges.forEach(function(range) { if (range.start > cursor) html += escapeHtml(text.slice(cursor, range.start)); html += '' + escapeHtml(text.slice(range.start, range.end)) + ''; cursor = range.end; }); if (cursor < text.length) html += escapeHtml(text.slice(cursor)); return html; } function cleanSearchDisplayText(value) { var text = String(value == null ? '' : value); text = text.replace(/]*\/?>/gi, ' '); text = text.replace(/]*>([\s\S]*?)<\/equation>/gi, '$1'); text = text.replace(/]*$/gi, ' '); text = text.replace(/<\/?equat[^<>]*$/gi, ' '); text = text.replace(/<\/?e(?:q(?:uation)?)?[^<>]*$/gi, ' '); text = text.replace(/<[^>]+>/g, ' '); text = text .replace(/\b(?:equation|latex|drawing)\b(?:\s+[a-z_-]+=(?:"[^"]*"|'[^']*'|[^\s<>]+))*/gi, ' ') .replace(/\\left|\\right|\\mathrm|\\text|\\operatorname/g, '') .replace(/\\gt/g, '>') .replace(/\\lt/g, '<') .replace(/\\sim/g, '∼') .replace(/\\[a-zA-Z]+/g, ' ') .replace(/\{([^{}]*)\}/g, '$1') .replace(/\{([^{}]*)\}/g, '$1') .replace(/[_^]/g, '') .replace(/[<>]\/?(?:equation|eq)\b[^<>]*>?/gi, ' ') .replace(/<\/?e(?:q(?:uation)?)?[^<>\s]*>?/gi, ' ') .replace(/\s+(?:equation|latex|drawing)\s+/gi, ' '); return searchText(text); } function searchResultEvidenceLocator(item) { if (item && item.locator && typeof item.locator === 'object') return item.locator; if (item && item.evidence && item.evidence.source && typeof item.evidence.source === 'object') return item.evidence.source; if (item && item.source && item.source.locator && typeof item.source.locator === 'object') return item.source.locator; if (item && Array.isArray(item.evidence) && item.evidence[0] && item.evidence[0].source && typeof item.evidence[0].source === 'object') return item.evidence[0].source; return null; } function searchResultSourceKey(item) { var locator = searchResultEvidenceLocator(item); var locatorPath = locator ? searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path) : ''; return locatorPath || searchText(item && (item.path || item.documentId || item.nodeId || item.id)) || 'unknown-source'; } function searchResultSourceTitle(item) { var key = searchResultSourceKey(item); var locator = searchResultEvidenceLocator(item); var path = locator ? searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path) : ''; var sourcePath = path || searchText(item && item.path) || key; var title = searchText(item && (item.title || item.name || item.documentTitle)); return title || sourcePath.split('/').filter(Boolean).pop() || sourcePath || '未知来源'; } function renderSearchResultButton(item, index, query, exact, grouped) { var title = searchText(item.title || item.name || item.documentTitle || '无标题'); var snippet = searchText(item.displayQuote || item.snippet || item.evidence && item.evidence.displayQuote || item.evidence && item.evidence.quote || (Array.isArray(item.evidence) && item.evidence[0] && (item.evidence[0].displayQuote || item.evidence[0].quote || item.evidence[0].snippet)) || ''); if (!item.displayQuote) snippet = cleanSearchDisplayText(snippet); var path = searchText(item.path || item.parentTitle || item.workspaceName || currentWorkspaceName()); var resourceType = searchText(item.resourceType || item.resourceKind || 'page'); var locator = searchResultEvidenceLocator(item); var locatorAttr = locator ? escapeHtml(JSON.stringify(locator)) : ''; var highlightTerms = searchHighlightTerms(item, query); var titleHtml = grouped && snippet ? '' : '' + highlightSearchText(title, query, exact, highlightTerms) + ''; var page = locator && locator.page != null && locator.page !== '' ? String(locator.page) : ''; var metaParts = grouped ? [] : [escapeHtml(path)]; if (page) metaParts.push('第 ' + escapeHtml(page) + ' 页'); if (!grouped) metaParts.push('' + escapeHtml(resourceType) + ''); var metaHtml = metaParts.length ? '' + metaParts.join('') + '' : ''; return ''; } function renderSearchResultsHtml(items, overlay, query) { var exact = searchSwitchValue(overlay, 'exact'); if (!searchSwitchValue(overlay, 'collapseSource')) { return items.map(function(item, index) { return renderSearchResultButton(item, index, query, exact, false); }).join(''); } var groups = []; var groupByKey = {}; items.forEach(function(item, index) { var key = searchResultSourceKey(item); var group = groupByKey[key]; if (!group) { group = { key: key, title: searchResultSourceTitle(item), path: searchText(item.path || key), resourceType: searchText(item.resourceType || item.resourceKind || 'page'), rows: [] }; groupByKey[key] = group; groups.push(group); } group.rows.push({ item: item, index: index }); }); return groups.map(function(group) { var collapsed = Object.prototype.hasOwnProperty.call(searchUiState.sourceCollapsed, group.key) ? searchUiState.sourceCollapsed[group.key] : true; var children = group.rows.map(function(row) { return renderSearchResultButton(row.item, row.index, query, exact, true); }).join(''); return '
' + '' + '
' + children + '
' + '
'; }).join(''); } function evidenceLocatorResourceKind(locator, fallback) { return searchText(locator && (locator.resourceKind || locator.resource_kind) || fallback || '').toLowerCase(); } function evidenceLocatorBbox(locator) { var bbox = locator && locator.bbox; if (Array.isArray(bbox)) return bbox.slice(0, 4).join(','); if (bbox && typeof bbox === 'object') return [bbox.x0, bbox.y0, bbox.x1, bbox.y1].join(','); return ''; } function evidenceLocatorOpenUrl(locator) { var action = locator && locator.openAction && typeof locator.openAction === 'object' ? locator.openAction : null; return searchText(action && action.url); } function evidenceLocatorLineRange(locator) { return locator && (locator.lineRange || locator.line_range) || null; } function evidenceLocatorCharRange(locator) { return locator && (locator.charRange || locator.char_range) || null; } function evidenceLocatorBlockId(locator) { return searchText(locator && (locator.blockId || locator.block_id)); } function resourceHrefForEvidenceLocator(resourceKind, resourcePath, fileName, ownerDocumentId, locator) { var localFileUrl = buildLocalFileOpenUrl(resourcePath, false); if (!localFileUrl) return ''; if (resourceKind === 'pdf') return buildPdfPreviewOpenUrl(localFileUrl, fileName); if (resourceKind === 'office') { var fileType = inferOnlyOfficeFileType(fileName, '') || (fileName.indexOf('.') >= 0 ? fileName.split('.').pop() : 'docx'); return buildOfficePreviewOpenUrl({ fileUrl: localFileUrl, fileName: fileName, fileType: fileType, assetId: 'local-file:' + resourcePath, documentId: ownerDocumentId || currentDocumentId() || '', workspaceId: resolveWorkspaceId(document.body) || '', sourceKind: currentSourceKind() || 'local_folder', rootUri: searchText(locator && (locator.rootUri || locator.root_uri) || currentRootUri()) }); } return localFileUrl; } async function openEvidenceSearchResult(item, event) { var locator = searchResultEvidenceLocator(item); if (!locator) { var citationUrl = searchText(item && (item.citationUrl || item.publicPath)); if (citationUrl) { closeSearchModal(); window.location.assign(citationUrl); return; } var fallbackId = searchText(item && (item.documentId || item.nodeId || item.id)); if (fallbackId) window.location.assign('/documents/' + encodeURIComponent(fallbackId)); return; } var resourcePath = searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path); var ownerDocumentId = searchText(locator.ownerDocumentId || locator.owner_document_id || item.documentId || ''); var resourceKind = evidenceLocatorResourceKind(locator, item && item.resourceType); var overlay = document.querySelector('[data-testid="wolai-search-modal"]'); var searchInput = overlay instanceof HTMLElement ? overlay.querySelector('[data-testid="wolai-search-input"]') : null; var searchQueryText = searchText(item && (item.searchQuery || item.query) || locator && locator.openAction && locator.openAction.params && locator.openAction.params.searchQuery) || searchText(searchInput && 'value' in searchInput ? searchInput.value : '') || searchText(searchUiState.query); var locatorEvidenceText = searchText(item && item.locatorEvidenceText || locator.evidenceText || locator.query || locator.openAction && locator.openAction.params && (locator.openAction.params.evidenceText || locator.openAction.params.query) || ''); var locatorParams = locator && locator.openAction && locator.openAction.params && typeof locator.openAction.params === 'object' ? locator.openAction.params : {}; var openTarget = event && event.altKey ? 'side' : 'active-tab'; if (resourcePath && resourceKind) { var fileName = resourcePath.split('/').filter(Boolean).pop() || resourcePath; var normalizedKind = resourceKind === 'raw_file' || resourceKind === 'resource' ? fileTreeIconKindForFileName(fileName) || 'file' : resourceKind; var hostDocumentId = currentDocumentId() || ownerDocumentId || ''; var href = resourceHrefForEvidenceLocator(normalizedKind, resourcePath, fileName, hostDocumentId, locator); var openedInResourceTab = await openLocalResourceInActiveTab({ path: resourcePath, title: fileName, kind: normalizedKind, href: href, officeUrl: normalizedKind === 'office' ? href : '', assetId: 'local-file:' + resourcePath, documentId: hostDocumentId, ownerDocumentId: ownerDocumentId || hostDocumentId, workspaceId: resolveWorkspaceId(document.body) || '', sourceKind: currentSourceKind() || 'local_folder', rootUri: searchText(locator.rootUri || locator.root_uri || currentRootUri()), paneRole: openTarget === 'side' ? 'secondary' : 'primary', evidenceLocator: locator, page: locator.page, bbox: locator.bbox, sourceMapPath: searchText(locator.sourceMapPath || locator.source_map_path), blockId: evidenceLocatorBlockId(locator), paragraphOrdinal: searchText(locator.paragraphOrdinal || locatorParams.paragraphOrdinal), paraIdStart: searchText(locator.paraIdStart || locatorParams.paraIdStart), paraIdEnd: searchText(locator.paraIdEnd || locatorParams.paraIdEnd), textFingerprint: searchText(locator.textFingerprint || locatorParams.textFingerprint), evidenceText: locatorEvidenceText, query: searchQueryText, searchQuery: searchQueryText, lineRange: evidenceLocatorLineRange(locator), charRange: evidenceLocatorCharRange(locator) }); if (!openedInResourceTab) console.warn('mnote evidence 搜索结果无法在当前页面资源标签打开', locator); closeSearchModal(); return; } var url = evidenceLocatorOpenUrl(locator) || ('/documents/' + encodeURIComponent(ownerDocumentId || currentDocumentId() || '')); try { var target = new URL(url, window.location.origin); var blockId = searchText(locator.blockId || locator.block_id); var sourceMapPath = searchText(locator.sourceMapPath || locator.source_map_path); if (blockId) target.searchParams.set('blockId', blockId); if (locator.page) target.searchParams.set('page', String(locator.page)); var bbox = evidenceLocatorBbox(locator); if (bbox) target.searchParams.set('bbox', bbox); if (sourceMapPath) target.searchParams.set('sourceMapPath', sourceMapPath); if (locatorParams.paragraphOrdinal != null) target.searchParams.set('paragraphOrdinal', searchText(locatorParams.paragraphOrdinal)); if (locatorParams.paraIdStart) target.searchParams.set('paraIdStart', searchText(locatorParams.paraIdStart)); if (locatorParams.paraIdEnd) target.searchParams.set('paraIdEnd', searchText(locatorParams.paraIdEnd)); if (locatorParams.textFingerprint) target.searchParams.set('textFingerprint', searchText(locatorParams.textFingerprint)); window.location.assign(target.pathname + target.search + target.hash); } catch (_) { window.location.assign(url); } } function renderSearchRecentState(overlay) { var options = overlay.querySelector('[data-testid="wolai-search-options"]'); var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]'); var results = overlay.querySelector('[data-testid="wolai-search-results"]'); if (options instanceof HTMLElement) options.hidden = true; if (meta) meta.innerHTML = '最近浏览Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开'; if (results) { results.innerHTML = '
暂无最近浏览
'; } saveSearchUiState(overlay); searchUiState.hasRendered = true; } function scheduleSearchResultsRender() { window.clearTimeout(searchRenderTimer); searchRenderTimer = window.setTimeout(function() { void renderSearchResults(); }, 120); } async function renderSearchResults() { var overlay = document.querySelector('[data-testid="wolai-search-modal"]'); if (!(overlay instanceof HTMLElement)) return; var input = overlay.querySelector('[data-testid="wolai-search-input"]'); var options = overlay.querySelector('[data-testid="wolai-search-options"]'); var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]'); var results = overlay.querySelector('[data-testid="wolai-search-results"]'); if (!input || !meta || !results) return; var query = searchText(input.value); if (!query) { activeSearchRequestId += 1; renderSearchRecentState(overlay); return; } if (options instanceof HTMLElement) options.hidden = false; var knowledgeMode = searchSwitchValue(overlay, 'knowledge'); if (knowledgeMode && searchNonWhitespaceCharCount(query) < 2) { activeSearchRequestId += 1; meta.innerHTML = '知识库检索请输入至少 2 个字再搜索'; results.innerHTML = '
请输入至少 2 个字再搜索
'; window.__mnoteSearchResults = []; saveSearchUiState(overlay); searchUiState.hasRendered = true; return; } var requestId = ++activeSearchRequestId; var knowledgeRequestMode = knowledgeMode ? knowledgeSearchRequestMode(overlay) : ''; meta.innerHTML = '搜索中…Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开'; results.innerHTML = '
搜索中…
'; try { var response = await fetch(knowledgeMode ? '/api/knowledge-rag/search' : '/api/search/documents', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(knowledgeMode ? { workspaceId: resolveWorkspaceId(document.body), rootUri: currentRootUri() || null, query: query, mode: knowledgeRequestMode, topK: 12, chunkTopK: 24, includeChunkContent: true } : { workspaceId: resolveWorkspaceId(document.body), sourceKind: currentSourceKind() || null, rootUri: currentRootUri() || null, documentId: searchSwitchValue(overlay, 'page') ? (currentSearchDocumentId() || null) : (currentDocumentId() || null), query: query, limit: 30, filters: { titleOnly: searchSwitchValue(overlay, 'title'), exact: searchSwitchValue(overlay, 'exact'), includeOcr: false, onlyCurrentPage: searchSwitchValue(overlay, 'page'), timeRange: 'any', timeField: 'updated' } }) }); var payload = await response.json(); if (requestId !== activeSearchRequestId) return; var items = Array.isArray(payload.results) ? payload.results : []; var ownerLabel = knowledgeMode ? ('知识库检索 · ' + knowledgeSearchModeLabel(payload.retrievalMode || knowledgeRequestMode)) : '工作区搜索'; meta.innerHTML = '' + ownerLabel + ' · 共 ' + items.length + ' 条匹配结果Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开'; if (!items.length) { results.innerHTML = '
没有搜索结果
'; window.__mnoteSearchResults = []; saveSearchUiState(overlay); searchUiState.hasRendered = true; return; } window.__mnoteSearchResults = items; results.innerHTML = renderSearchResultsHtml(items, overlay, query); saveSearchUiState(overlay); searchUiState.hasRendered = true; } catch (error) { if (requestId !== activeSearchRequestId) return; meta.innerHTML = '共 0 条匹配结果Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开'; results.innerHTML = '
没有搜索结果
'; window.__mnoteSearchResults = []; saveSearchUiState(overlay); searchUiState.hasRendered = true; } } function isSearchModalOpen() { var overlay = document.querySelector('[data-testid="wolai-search-modal"]'); return overlay instanceof HTMLElement && !overlay.hidden; } function openSearchModal() { var overlay = ensureSearchModal(); overlay.hidden = false; document.documentElement.setAttribute('data-mnote-search-modal-open', 'true'); var restored = restoreSearchUiState(overlay); var input = overlay.querySelector('[data-testid="wolai-search-input"]'); if (input) input.setAttribute('placeholder', '在 ' + currentWorkspaceName() + ' 中搜索'); var query = input && 'value' in input ? searchText(input.value) : ''; var signature = query ? searchRequestSignature(overlay, query) : ''; if (!restored || signature !== searchUiState.signature) void renderSearchResults(); if (input) { setTimeout(function() { input.focus(); input.select(); }, 0); } } function closeSearchModal() { var overlay = document.querySelector('[data-testid="wolai-search-modal"]'); if (overlay instanceof HTMLElement) { saveSearchUiState(overlay); overlay.hidden = true; } document.documentElement.removeAttribute('data-mnote-search-modal-open'); } function toggleSearchModal() { if (isSearchModalOpen()) closeSearchModal(); else openSearchModal(); } function isSearchShortcutEvent(event) { return Boolean(event && (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey && event.key && event.key.toLowerCase() === 'p'); } document.addEventListener('keydown', function(event) { if (!isSearchShortcutEvent(event)) return; event.preventDefault(); event.stopPropagation(); openSearchModal(); }, true); // Page AI 产品入口仅 Pi Lab;facade 只桥接 open / trigger / no-op delegates。 const sidebarPageAi = createSidebarPageAiRuntime({ pageUiState }); const openPageAiDrawer = (...args) => sidebarPageAi.openPageAiDrawer(...args); const updatePageAiTriggerState = (...args) => sidebarPageAi.updatePageAiTriggerState(...args); const sidebarAttachmentOpen = createSidebarAttachmentOpenRuntime({ attachmentClassForFileName: (...args) => attachmentClassForFileName(...args), buildLocalFileOpenUrl, buildLocalOnlyOfficeOpenUrl, buildOnlyOfficeOpenPath, buildOnlyOfficeOpenUrl, buildPdfPreviewOpenUrl, closestAction, currentDocumentId, currentRootUri, currentWorkspaceSourcePayload, fileTreeIconKindForFileName, healLegacyOfficeAttachmentParagraphs, hydrateEditorAttachmentMeta, inferCodeAttachmentLanguage: (...args) => inferCodeAttachmentLanguage(...args), inferOnlyOfficeFileType, isCodeAttachmentFileName: (...args) => isCodeAttachmentFileName(...args), isPdfAttachmentFileName: (...args) => isPdfAttachmentFileName(...args), localFilePathFromAssetId, openLocalOfficeFileInActiveTab, openLocalResourceInActiveTab, openTreeContextMenu: (...args) => openTreeContextMenu(...args), resolveWorkspaceId, triggerBrowserDownload: (...args) => triggerBrowserDownload(...args), uploadedFileSize, }); const refreshEditorLocalAttachmentExistence = (...args) => sidebarAttachmentOpen.refreshEditorLocalAttachmentExistence(...args); const detailFromEditorAttachmentLink = (...args) => sidebarAttachmentOpen.detailFromEditorAttachmentLink(...args); const enhanceEditorAttachmentLink = (...args) => sidebarAttachmentOpen.enhanceEditorAttachmentLink(...args); const enhanceEditorAttachmentLinks = (...args) => sidebarAttachmentOpen.enhanceEditorAttachmentLinks(...args); const openEditorAttachmentDetail = (...args) => sidebarAttachmentOpen.openEditorAttachmentDetail(...args); const openEditorAttachmentNewWindow = (...args) => sidebarAttachmentOpen.openEditorAttachmentNewWindow(...args); const openEditorAttachmentEditTab = (...args) => sidebarAttachmentOpen.openEditorAttachmentEditTab(...args); const openCodeEditorAttachment = (...args) => sidebarAttachmentOpen.openCodeEditorAttachment(...args); const openEditorAttachmentDownload = (...args) => sidebarAttachmentOpen.openEditorAttachmentDownload(...args); document.addEventListener('click', function(e) { if (activeTreeContextMenu && activeTreeContextMenu.contains(e.target)) return; if (activeTreeContextMenu) closeTreeContextMenu(); var sidebarToggle = closestAction(e.target, '[data-mnote-action="toggle-sidebar"]'); if (sidebarToggle) { e.preventDefault(); toggleWorkspaceSidebar(sidebarToggle); return; } var attachmentAction = closestAction(e.target, '[data-attachment-action]'); if (attachmentAction) { e.preventDefault(); e.stopPropagation(); var link = activeEditorAttachmentLink; if (!(link instanceof HTMLAnchorElement)) return; var attachmentDetail = detailFromEditorAttachmentLink(link); var attachmentActionName = attachmentAction.getAttribute('data-attachment-action') || ''; if (attachmentActionName === 'download') { openEditorAttachmentDownload(attachmentDetail); return; } if (attachmentActionName === 'menu') { openEditorAttachmentMenu(link, attachmentAction); return; } return; } var editorAttachmentLink = closestAction(e.target, '.editor-surface .ProseMirror a.mnote-uploaded-attachment-row'); if (editorAttachmentLink instanceof HTMLAnchorElement) { e.preventDefault(); openEditorAttachmentLink(editorAttachmentLink); return; } var historyClose = closestAction(e.target, '[data-page-history-action="close"]'); if (historyClose) { e.preventDefault(); closePageHistoryDrawer(); return; } var shareClose = closestAction(e.target, '[data-page-share-action="close"]'); if (shareClose) { e.preventDefault(); closePageShareDialog(); return; } var shareCopy = closestAction(e.target, '[data-page-share-action="copy-link"]'); if (shareCopy) { e.preventDefault(); void copyTreeContextValue(window.location.href, 'page-share-link'); return; } var pageHistoryTrigger = closestAction(e.target, '[data-mnote-action="open-page-history"]'); if (pageHistoryTrigger) { e.preventDefault(); openPageHistoryDrawer(); return; } var pageSettingsTrigger = closestAction(e.target, '[data-mnote-action="open-page-settings"]'); if (pageSettingsTrigger) { e.preventDefault(); togglePageSettingsPopover(); return; } var indexSettingsTrigger = closestAction(e.target, '[data-mnote-action="open-index-settings"]'); if (indexSettingsTrigger) { e.preventDefault(); openKnowledgeRagSettingsPopover(); return; } var knowledgeHostTrigger = closestAction(e.target, '[data-mnote-action="open-knowledge-host"]'); if (knowledgeHostTrigger) { var hostUrl = knowledgeHostUrl(); if (knowledgeHostTrigger instanceof HTMLAnchorElement) knowledgeHostTrigger.setAttribute('href', hostUrl); if (knowledgeHostTrigger instanceof HTMLAnchorElement && (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1)) return; e.preventDefault(); window.location.href = hostUrl; return; } var knowledgeRagSettingsTrigger = closestAction(e.target, '[data-mnote-action="open-knowledge-rag-settings"]'); if (knowledgeRagSettingsTrigger) { e.preventDefault(); window.location.href = knowledgeHostUrl(); return; } var knowledgeRagDebugTrigger = closestAction(e.target, '[data-mnote-action="open-knowledge-rag-debug-settings"]'); if (knowledgeRagDebugTrigger) { e.preventDefault(); openKnowledgeRagSettingsPopover(); return; } var settingsClose = closestAction(e.target, '[data-settings-action="close"]'); if (settingsClose) { e.preventDefault(); closeAllSettingsPopovers(); return; } var pageSettingsPanel = closestAction(e.target, '.wolai-page-settings-panel'); if (isAnySettingsOpen() && !pageSettingsPanel) { closeAllSettingsPopovers(); } var pageSettingsTab = closestAction(e.target, '[data-page-settings-tab]'); if (pageSettingsTab) { e.preventDefault(); setActivePageSettingsTab(pageSettingsTab.getAttribute('data-page-settings-tab') || 'page'); return; } var extensionsSubtab = closestAction(e.target, '[data-extensions-subtab]'); if (extensionsSubtab) { e.preventDefault(); setActiveExtensionsSubtab(extensionsSubtab.getAttribute('data-extensions-subtab') || 'knowledge'); return; } var localIndexAction = closestAction(e.target, '[data-local-index-action]'); if (localIndexAction) { e.preventDefault(); var localIndexActionName = localIndexAction.getAttribute('data-local-index-action') || ''; if (localIndexActionName === 'save') { void persistLocalIndexSettings(); return; } if (localIndexActionName === 'refresh') { void refreshLocalIndex(); return; } if (localIndexActionName === 'add-path') { addLocalIndexRange(); return; } if (localIndexActionName === 'remove-path') { removeLocalIndexRange(localIndexAction.getAttribute('data-local-index-path-index') || '0'); return; } } var knowledgeRagAction = closestAction(e.target, '[data-knowledge-rag-action]'); if (knowledgeRagAction) { e.preventDefault(); var knowledgeRagActionName = knowledgeRagAction.getAttribute('data-knowledge-rag-action') || ''; if (knowledgeRagActionName === 'manage') { void openKnowledgeRagSettingsPopover(); return; } if (knowledgeRagActionName === 'refresh-status') { void refreshKnowledgeExtensionsPanel(); return; } if (knowledgeRagActionName === 'refresh') { void loadKnowledgeRagStatus(true); return; } if (knowledgeRagActionName === 'create-kb') { void createKnowledgeRagKnowledgeBase(); return; } if (knowledgeRagActionName === 'delete-kb') { void deleteKnowledgeRagKnowledgeBase(); return; } if (knowledgeRagActionName === 'toggle-create-kb') { toggleKnowledgeRagCreateCard(); return; } if (knowledgeRagActionName === 'focus-create-kb') { toggleKnowledgeRagCreateCard(); var createKbInput = document.querySelector('[data-knowledge-rag-create-kb-name]'); if (createKbInput instanceof HTMLInputElement) createKbInput.focus(); return; } if (knowledgeRagActionName === 'select-kb') { setKnowledgeRagSelectedProviderKnowledgeBaseId(knowledgeRagAction.getAttribute('data-knowledge-rag-kb-id') || ''); return; } if (knowledgeRagActionName === 'add-source') { addKnowledgeRagSourceInput(); return; } if (knowledgeRagActionName === 'remove-source') { removeKnowledgeRagSourceInput(knowledgeRagAction); return; } if (knowledgeRagActionName === 'use-filetree-selection') { useKnowledgeRagFileTreeSelection(); return; } if (knowledgeRagActionName === 'ingest') { void ingestKnowledgeRagSources(); return; } if (knowledgeRagActionName === 'ingest-active') { window.dispatchEvent(new CustomEvent('mnote:knowledge-rag-settings-action', { detail: { action: 'run-active' } })); return; } if (knowledgeRagActionName === 'reindex-source') { void ingestSingleKnowledgeRagSource(knowledgeRagAction.getAttribute('data-knowledge-rag-source-path') || ''); return; } if (knowledgeRagActionName === 'delete-source') { void deleteKnowledgeRagSource(knowledgeRagAction.getAttribute('data-knowledge-rag-source-path') || ''); return; } if (knowledgeRagActionName === 'open-source-reference') { openKnowledgeRagSourceReference(knowledgeRagAction.getAttribute('data-knowledge-rag-source-path') || ''); return; } if (knowledgeRagActionName === 'prune') { void pruneKnowledgeRagRegistry(); return; } if (knowledgeRagActionName === 'filter-sources') { setKnowledgeRagSourceFilter(knowledgeRagAction.getAttribute('data-knowledge-rag-filter') || 'attention'); return; } if (knowledgeRagActionName === 'open-dashboard') { openKnowledgeRagDashboard(); return; } } var kbRagDetailTab = closestAction(e.target, '[data-kb-rag-tab]'); if (kbRagDetailTab) { e.preventDefault(); var tabName = kbRagDetailTab.getAttribute('data-kb-rag-tab') || 'sources'; setActiveKnowledgeRagDetailTab(tabName); if (tabName === 'params') loadKnowledgeRagSearchParamsToForm(); return; } var kbRagAction = closestAction(e.target, '[data-kb-rag-action]'); if (kbRagAction) { e.preventDefault(); var kbRagActionName = kbRagAction.getAttribute('data-kb-rag-action') || ''; if (kbRagActionName === 'search') { void performKnowledgeRagSearch(); return; } if (kbRagActionName === 'save-params') { saveKnowledgeRagSearchParams(); return; } } var kbRagSearchInput = closestAction(e.target, '[data-kb-rag-search-input]'); if (kbRagSearchInput && e.key === 'Enter') { e.preventDefault(); void performKnowledgeRagSearch(); return; } var kbRagThresholdRange = closestAction(e.target, '[data-kb-rag-param="similarity_threshold"]'); if (kbRagThresholdRange && e.type === 'input') { syncKnowledgeRagThresholdDisplay(); return; } var dashboardAction = closestAction(e.target, '[data-dashboard-action="refresh"]'); if (dashboardAction) { e.preventDefault(); refreshDashboardPanel(); return; } var pageSettingsAction = closestAction(e.target, '[data-page-settings-action]'); if (pageSettingsAction) { e.preventDefault(); var actionName = pageSettingsAction.getAttribute('data-page-settings-action') || ''; if (actionName === 'history') { openPageHistoryDrawer(); return; } if (actionName === 'share') { openPageShareDialog(); return; } return; } var pageAiTrigger = closestAction(e.target, '[data-mnote-action="open-page-ai"]'); if (pageAiTrigger) { e.preventDefault(); // 产品面唯一 Page AI:Pi Lab(不再打开 Hermes/OpenCode legacy drawer) if (window.createSidebarPageAiPiLabRuntime) { window.createSidebarPageAiPiLabRuntime({}); } window.postMessage({ source: 'mnote-sidebar', type: 'mnote:pi-lab-show' }, window.location.origin); return; } var pageAiPiLabTrigger = closestAction(e.target, '[data-mnote-action="open-page-ai-pi-lab"]'); if (pageAiPiLabTrigger) { e.preventDefault(); if (window.createSidebarPageAiPiLabRuntime) { window.createSidebarPageAiPiLabRuntime({}); } window.postMessage({ source: 'mnote-sidebar', type: 'mnote:pi-lab-show' }, window.location.origin); return; } var navigationPageTrigger = closestAction(e.target, '[data-mnote-action="open-navigation-page"]'); if (navigationPageTrigger) { e.preventDefault(); openCurrentNavigationPage(navigationPageTrigger); return; } var searchTrigger = closestAction(e.target, '[data-mnote-action="open-search-modal"]'); if (searchTrigger) { e.preventDefault(); toggleSearchModal(); return; } var searchDialog = closestAction(e.target, '.wolai-search-dialog'); if (isSearchModalOpen() && !searchDialog) { closeSearchModal(); return; } var searchSourceToggle = closestAction(e.target, '[data-search-source-toggle]'); if (searchSourceToggle) { e.preventDefault(); var sourceGroup = searchSourceToggle.closest('.wolai-search-source-group'); var sourceResults = sourceGroup && sourceGroup.querySelector('[data-search-source-results="true"]'); var sourceKey = sourceGroup ? searchText(sourceGroup.getAttribute('data-search-source-key')) : ''; var nextCollapsed = !(sourceResults instanceof HTMLElement && sourceResults.hidden); if (sourceResults instanceof HTMLElement) sourceResults.hidden = nextCollapsed; searchSourceToggle.setAttribute('aria-expanded', nextCollapsed ? 'false' : 'true'); var chevron = searchSourceToggle.querySelector('.wolai-search-source-chevron'); if (chevron) chevron.textContent = nextCollapsed ? '展开' : '收起'; if (sourceKey) searchUiState.sourceCollapsed[sourceKey] = nextCollapsed; var overlay = document.querySelector('[data-testid="wolai-search-modal"]'); if (overlay instanceof HTMLElement) saveSearchUiState(overlay); return; } var searchResultRow = closestAction(e.target, '[data-testid="wolai-search-result-row"]'); if (searchResultRow) { e.preventDefault(); var index = Number(searchResultRow.getAttribute('data-search-result-index') || -1); var item = Array.isArray(window.__mnoteSearchResults) && index >= 0 ? window.__mnoteSearchResults[index] : null; if (!item) { var locatorPayload = searchResultRow.getAttribute('data-evidence-locator') || ''; try { var locator = locatorPayload ? JSON.parse(locatorPayload) : null; item = locator ? { evidence: { source: locator }, documentId: searchResultRow.getAttribute('data-document-id') || '' } : null; } catch (_) { item = null; } } void openEvidenceSearchResult(item || { documentId: searchResultRow.getAttribute('data-document-id') || '' }, e) .catch(function(error) { console.warn('mnote evidence 搜索结果打开失败', error); }); return; } var sourceMenuTrigger = closestAction(e.target, '[data-mnote-action="open-workspace-source-menu"]'); if (sourceMenuTrigger) { e.preventDefault(); var existingSourceMenu = document.querySelector('[data-testid="mnote-workspace-source-menu"]'); if (existingSourceMenu) closeWorkspaceSourceMenu(); else openWorkspaceSourceMenu(sourceMenuTrigger); return; } var sourceMenu = closestAction(e.target, '[data-testid="mnote-workspace-source-menu"]'); if (!sourceMenu) closeWorkspaceSourceMenu(); var accountMenuTrigger = closestAction(e.target, '[data-mnote-action="open-account-menu"]'); if (accountMenuTrigger) { e.preventDefault(); var existingAccountMenu = document.querySelector('[data-testid="mnote-account-menu"]'); if (existingAccountMenu) closeAccountMenu(); else openAccountMenu(accountMenuTrigger); return; } var accountMenu = closestAction(e.target, '[data-testid="mnote-account-menu"]'); if (!accountMenu) closeAccountMenu(); var trashTrigger = closestAction(e.target, '[data-mnote-action="open-trash-modal"]'); if (trashTrigger) { e.preventDefault(); openTrashModal(trashTrigger); return; } var trashClose = closestAction(e.target, '[data-mnote-trash-modal-close]'); if (trashClose) { e.preventDefault(); closeTrashModal(); return; } var tabTrigger = closestAction(e.target, '[data-mnote-sidebar-tree-tab]'); if (tabTrigger) { e.preventDefault(); switchSidebarTreeTab(tabTrigger); return; } var pageShortcutTrigger = closestAction(e.target, '[data-mnote-action="toggle-sidebar-shortcut"]'); if (pageShortcutTrigger) { e.preventDefault(); void toggleCurrentPageSidebarShortcut(pageShortcutTrigger); return; } var shortcutMenu = closestAction(e.target, '[data-testid="mnote-sidebar-shortcut-menu"]'); var shortcutMenuAction = closestAction(e.target, '[data-mnote-sidebar-shortcut-menu-action]'); if (shortcutMenuAction) { e.preventDefault(); var action = String(shortcutMenuAction.getAttribute('data-mnote-sidebar-shortcut-menu-action') || '').trim(); var shortcutRowFromMenu = shortcutMenu && shortcutMenu.__mnoteShortcutRow instanceof HTMLElement ? shortcutMenu.__mnoteShortcutRow : null; if (action === 'remove') { void removeSidebarShortcutByRow(shortcutRowFromMenu); return; } if (action === 'open') { closeSidebarShortcutMenu(); if (shortcutRowFromMenu && shortcutRowFromMenu.getAttribute('data-mnote-shortcut-kind') === 'folder') { void openStarredFolderShortcut(shortcutRowFromMenu); } else if (shortcutRowFromMenu && shortcutRowFromMenu.getAttribute('href')) { window.location.assign(shortcutRowFromMenu.getAttribute('href')); } return; } if (action === 'copy-link') { var href = shortcutRowFromMenu && shortcutRowFromMenu.getAttribute('href') || window.location.href; if (navigator.clipboard && href) void navigator.clipboard.writeText(new URL(href, window.location.origin).toString()); closeSidebarShortcutMenu(); return; } } if (!shortcutMenu) closeSidebarShortcutMenu(); var shortcutMenuTrigger = closestAction(e.target, '.wolai-starred-section [data-mnote-shortcut-action="menu"]'); if (shortcutMenuTrigger) { e.preventDefault(); var shortcutRow = shortcutMenuTrigger.closest('[data-mnote-shortcut-id]'); openSidebarShortcutMenu(shortcutRow, shortcutMenuTrigger); return; } var folderShortcutRow = closestAction(e.target, '.wolai-starred-section [data-mnote-shortcut-kind="folder"]'); if (folderShortcutRow) { e.preventDefault(); void openStarredFolderShortcut(folderShortcutRow); return; } var vaultNavLink = closestAction( e.target, 'a[data-mnote-nav="vault"], a[data-testid="mnote-nav-vault"], a[href="/vault"], a[href^="/vault?"]' ); if (vaultNavLink instanceof HTMLAnchorElement) { // Modifier / middle-click: keep native full navigation (new tab etc.). if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) { try { var enrichUrl = new URL(vaultNavLink.getAttribute('href') || '/vault', window.location.origin); if (enrichUrl.pathname === '/vault') { copyWorkspaceSourceParams(enrichUrl); vaultNavLink.setAttribute('href', enrichUrl.pathname + enrichUrl.search + enrichUrl.hash); } } catch (_) {} } else { try { var vaultUrl = new URL(vaultNavLink.getAttribute('href') || '/vault', window.location.origin); if (vaultUrl.pathname === '/vault') { e.preventDefault(); copyWorkspaceSourceParams(vaultUrl); vaultNavLink.setAttribute('href', vaultUrl.pathname + vaultUrl.search + vaultUrl.hash); void openVaultWorkbenchSoft(vaultUrl); return; } } catch (_) {} } } var localFolderTrigger = closestAction(e.target, '[data-mnote-action="open-local-folder"]'); if (localFolderTrigger) { e.preventDefault(); requestOpenLocalFolder(); return; } var createLocalWorkspaceTrigger = closestAction(e.target, '[data-mnote-action="create-local-workspace"]'); if (createLocalWorkspaceTrigger) { e.preventDefault(); void createDefaultLocalWorkspace(createLocalWorkspaceTrigger); return; } var createTrigger = closestAction(e.target, '[data-mnote-action="create-page"]'); if (createTrigger) { e.preventDefault(); void createPage(createTrigger, null); return; } var createFolderTrigger = closestAction(e.target, '[data-mnote-action="create-folder"]'); if (createFolderTrigger) { e.preventDefault(); if (currentSourceKind() !== 'local_folder') return; var scope = currentFileTreeScope(); var parentId = scope ? 'local:folder:' + scope : null; void createFileTreeFolder(createFolderTrigger, parentId); return; } var fileTree = document.getElementById('sidebar-file-tree-root'); if (fileTree && fileTree.contains(e.target)) { var fileBtn = closestAction(e.target, '[data-rust-action]'); var fileRow = closestAction(e.target, '.tree-row[data-shell-mode="filetree"]'); if (!fileRow) return; var fileAction = fileBtn ? fileBtn.getAttribute('data-rust-action') : 'open'; var rowId = fileRow.getAttribute('data-row-id') || ''; var rowKind = fileRow.getAttribute('data-row-kind') || ''; var documentId = fileRow.getAttribute('data-document-id') || fileRow.getAttribute('data-doc-id') || ''; var ownerDocumentId = fileRow.getAttribute('data-owner-document-id') || documentId; var assetId = fileRow.getAttribute('data-asset-id') || ''; var assetType = ''; var kindBadge = fileRow.querySelector('.tree-kind-badge'); if (kindBadge instanceof HTMLElement) { assetType = kindBadge.getAttribute('data-kind') || ''; } if (fileAction === 'toggle') { e.preventDefault(); toggleChildren(fileRow, fileBtn); return; } if (fileAction === 'create') { e.preventDefault(); void createPage(fileBtn || fileRow, documentId || fileRow.getAttribute('data-node-id')); return; } if (fileAction === 'menu') { e.preventDefault(); if (rowId && !sidebarFileTreeSelection.selectedRowIds.has(rowId)) { selectSidebarFileTreeRow(fileRow, { ctrlKey: false, metaKey: false, shiftKey: false }); } var point = rowCenter(fileBtn || fileRow); dispatchSidebarEvent('tree.filetree.context-menu', { rowId: rowId, rowKind: rowKind, documentId: documentId || null, assetId: assetId || null }); openFileTreeContextMenu(fileRow, point.x, point.y, fileBtn || fileRow); return; } if (fileAction === 'open' && rowKind === 'folder') { e.preventDefault(); selectSidebarFileTreeRow(fileRow, { ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey }); toggleChildren(fileRow, fileRow.querySelector('[data-rust-action="toggle"]')); return; } e.preventDefault(); selectSidebarFileTreeRow(fileRow, { ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey }); var objectIdentity = readFileTreeObjectIdentity(fileRow); var workspacePath = readWorkspacePathFromRow(fileRow); var localRelativePath = fileTreeRowLocalRelativePath(fileRow) || String(workspacePath && (workspacePath.relativePath || workspacePath.localRelativePath) || '').trim(); dispatchSidebarEvent('tree.filetree.open', { rowId: rowId, rowKind: rowKind, documentId: ownerDocumentId || null, assetId: assetId || null, assetType: assetType || null, objectIdentity: objectIdentity, workspacePath: workspacePath, workspaceId: resolveWorkspaceId(fileRow) }); if (e.shiftKey || e.ctrlKey || e.metaKey) { return; } if ((rowKind === 'document' || rowKind === 'index' || rowKind === 'markdown') && isRetiredOcrSidecarMarkdownPath(localRelativePath)) { document.documentElement.setAttribute('data-mnote-retired-ocr-sidecar-filetree-open', 'resource-tab'); var retiredOcrSidecarResourceInput = { path: localRelativePath, title: fileTreeRowTitleForShortcut(fileRow, localRelativePath), kind: 'markdown', objectIdentity: 'retired-ocr-sidecar:' + localRelativePath, assetId: 'retired-ocr-sidecar:' + localRelativePath, documentId: documentId || ownerDocumentId || null, workspaceId: resolveWorkspaceId(fileRow), sourceKind: 'local_folder', rootUri: currentRootUri(), resourceKind: 'markdown', workspacePath: workspacePath, paneRole: 'primary' }; if (typeof window.__mnoteDocumentPaneRuntime?.openResourceInActiveTab === 'function') { void window.__mnoteDocumentPaneRuntime.openResourceInActiveTab(retiredOcrSidecarResourceInput); } else { void openLocalResourceInActiveTab(retiredOcrSidecarResourceInput); } return; } if ((rowKind === 'document' || rowKind === 'index' || rowKind === 'markdown') && documentId) { void recordNavigationRecent({ kind: 'page', sourceKind: currentSourceKind() || 'local_folder', rootUri: currentRootUri(), relativePath: String(fileRow.getAttribute('data-local-relative-path') || '').trim(), documentId: documentId, title: fileTreeRowTitleForShortcut(fileRow, documentId), workspaceId: resolveWorkspaceId(fileRow) }); navigateToDocument(documentId, resolveWorkspaceId(fileRow), { treeView: 'filetree', fileTreeScope: currentFileTreeScope() }); } else if (assetId) { dispatchSidebarEvent('tree.asset.open', { rowId: rowId, rowKind: rowKind, documentId: ownerDocumentId || null, assetId: assetId, assetType: assetType || null, objectIdentity: objectIdentity, workspacePath: workspacePath, workspaceId: resolveWorkspaceId(fileRow), openTarget: e.shiftKey || e.ctrlKey || e.metaKey ? 'new-window' : 'active-tab' }); } return; } if (sidebarPageTree.handlePageTreeClick(e, { closestAction: closestAction })) return; }); window.addEventListener('tree.sidebarShortcut.toggleFolder', function(event) { var detail = event.detail || {}; var row = detail.rowId ? document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(detail.rowId) + '"]') : null; void toggleFolderSidebarShortcut(detail, row); }); window.addEventListener('tree.filetree.internal-drop', function(event) { var detail = event.detail || {}; var rowIds = Array.isArray(detail.rowIds) ? detail.rowIds : []; if (!rowIds.length) return; var targetRow = detail.targetRowId ? document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(detail.targetRowId) + '"]') : null; var dropPosition = detail.dropPosition || 'inside'; recordFileTreeAction('internal-drop', { rowId: detail.targetRowId || '', sourceRowIds: rowIds, copy: Boolean(detail.copy), dropPosition: dropPosition }); void moveSidebarFileTreeRows(rowIds, targetRow, { copy: Boolean(detail.copy), dropPosition: dropPosition, }); }); document.addEventListener('contextmenu', function(event) { var editorAttachmentLink = closestAction(event.target, '.editor-surface .ProseMirror a.mnote-uploaded-attachment-row'); if (editorAttachmentLink instanceof HTMLAnchorElement) { event.preventDefault(); event.stopPropagation(); enhanceEditorAttachmentLink(editorAttachmentLink); openEditorAttachmentMenu(editorAttachmentLink, editorAttachmentLink, { x: event.clientX, y: event.clientY }); return; } var fileRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"]'); if (fileRow) { event.preventDefault(); var contextRowId = fileRow.getAttribute('data-row-id') || ''; if (contextRowId && !sidebarFileTreeSelection.selectedRowIds.has(contextRowId)) { selectSidebarFileTreeRow(fileRow, { ctrlKey: false, metaKey: false, shiftKey: false }); } openFileTreeContextMenu(fileRow, event.clientX, event.clientY, fileRow); return; } if (sidebarPageTree.handlePageTreeContextMenu(event, { closestAction: closestAction })) return; }); document.addEventListener('keydown', function(event) { var keyTarget = event.target; var fileTreeRootForKey = document.getElementById('sidebar-file-tree-root'); var fileTreeRowForKey = closestAction(keyTarget, '.tree-row[data-shell-mode="filetree"]'); if (!fileTreeRowForKey && fileTreeRootForKey && fileTreeRootForKey.contains(document.activeElement)) { fileTreeRowForKey = closestAction(document.activeElement, '.tree-row[data-shell-mode="filetree"]'); } if (fileTreeRowForKey) { var _kbRT_ = window.__mnoteFileTreeKeyboardRuntime; if (_kbRT_ && typeof _kbRT_.handleFileTreeKeyDown === 'function') { var handled = _kbRT_.handleFileTreeKeyDown(event, { closestAction: closestAction, beginFileTreeInlineRename: beginFileTreeInlineRename, selectedSidebarFileTreeRows: selectedSidebarFileTreeRows, buildSidebarFileTreeContext: buildSidebarFileTreeContext, evaluateSidebarFileTreeWhen: evaluateSidebarFileTreeWhen, deleteSelectedSidebarFileTreeRows: deleteSelectedSidebarFileTreeRows, pasteSidebarFileTreeClipboard: pasteSidebarFileTreeClipboard, onClipboardChange: function(nextClipboard) { sidebarFileTreeClipboard = nextClipboard; }, }); if (handled) return; } else { // inline fallback if (event.key === 'F2') { event.preventDefault(); var renameCtx = buildSidebarFileTreeContext('filetree', { targetRow: fileTreeRowForKey }); if (!evaluateSidebarFileTreeWhen(renameCtx, '!workspace.readonly && !editor.dirty')) { return; } beginFileTreeInlineRename(fileTreeRowForKey); return; } if ((event.ctrlKey || event.metaKey) && !event.altKey && event.key) { var shortcutKey = event.key.toLowerCase(); if (shortcutKey === 'c' || shortcutKey === 'x') { var selectedRows = selectedSidebarFileTreeRows(); var selectedRowIds = selectedRows.map(function(row) { return row.getAttribute('data-row-id') || ''; }).filter(Boolean); if (selectedRowIds.length > 0) { event.preventDefault(); sidebarFileTreeClipboard = { action: shortcutKey === 'x' ? 'cut' : 'copy', rowIds: selectedRowIds }; document.documentElement.setAttribute('data-mnote-filetree-clipboard-action', sidebarFileTreeClipboard.action); } return; } if (shortcutKey === 'v') { event.preventDefault(); var pasteCtx = buildSidebarFileTreeContext('filetree', { targetRow: fileTreeRowForKey }); if (!evaluateSidebarFileTreeWhen(pasteCtx, '!workspace.readonly')) { return; } void pasteSidebarFileTreeClipboard(fileTreeRowForKey); return; } } if (event.key === 'Delete' || event.key === 'Backspace') { event.preventDefault(); var delCtx = buildSidebarFileTreeContext('filetree', { targetRow: fileTreeRowForKey }); if (!evaluateSidebarFileTreeWhen(delCtx, '!workspace.readonly && !editor.dirty')) { return; } void deleteSelectedSidebarFileTreeRows(fileTreeRowForKey); return; } } } if (event.key === 'Escape' && isAnySettingsOpen()) { event.preventDefault(); closeAllSettingsPopovers(); return; } if (isSearchShortcutEvent(event)) { event.preventDefault(); openSearchModal(); return; } if (event.key === 'Escape') { closeTrashModal(); closeSearchModal(); closeTreeContextMenu(); } }); document.addEventListener('change', function(event) { var globalCheckbox = closestAction(event.target, '[data-global-option-checkbox="showHeadingNumbers"]'); if (globalCheckbox instanceof HTMLInputElement) { writeGlobalShowHeadingNumbers(globalCheckbox.checked); applyPageOptionsToShell(); renderPageSettingsPopover(); return; } var checkbox = closestAction(event.target, '[data-page-option-checkbox]'); if (checkbox instanceof HTMLInputElement) { var key = checkbox.getAttribute('data-page-option-checkbox') || ''; if (!pageOptionIsSupported(key)) return; var patch = {}; patch[key] = checkbox.checked; void persistPageOptionsPatch(patch); return; } var select = closestAction(event.target, '[data-page-option-select]'); if (select instanceof HTMLSelectElement) { var selectKey = select.getAttribute('data-page-option-select') || ''; var next = {}; if (selectKey === 'layoutDensity') next.layoutDensity = select.value; if (selectKey === 'pageFont') next.pageFont = select.value; if (Object.keys(next).length) { void persistPageOptionsPatch(next); } return; } var pageWidthSelect = closestAction(event.target, '[data-page-width-select]'); if (pageWidthSelect instanceof HTMLSelectElement) { var pageWidthType = pageWidthSelect.getAttribute('data-page-width-select') || ''; void persistPageWidthPreference(pageWidthType, pageWidthSelect.value); return; } var knowledgeRagKbSelect = closestAction(event.target, '[data-knowledge-rag-kb-select]'); if (knowledgeRagKbSelect instanceof HTMLSelectElement) { setKnowledgeRagSelectedProviderKnowledgeBaseId(knowledgeRagKbSelect.value); } }); sidebarPageAi.installPageAiDelegates(); function initializePageUiSurfaces() { pageUiState.pageOptions = null; pageUiState.pageWidthPreferences = null; applyPageOptionsToShell(); void loadPageWidthPreferences(); updatePageSettingsTriggerState(); updatePageAiTriggerState(); ensureHistorySnapshotsSeeded(); installWorkspaceSidebarResizer(); } window.__mnoteRecordPageHistorySnapshot = recordPageHistorySnapshot; window.__mnoteApplyPageOptionsToShell = applyPageOptionsToShell; function scheduleInitializePageUiSurfaces() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { setTimeout(initializePageUiSurfaces, 0); }, { once: true }); return; } setTimeout(initializePageUiSurfaces, 0); } scheduleInitializePageUiSurfaces(); function mnoteDevHotReloadEnabled() { try { return new URL(import.meta.url).searchParams.has('devHot'); } catch (_) { return false; } } function installMnoteDevHotReload() { var bootId = ''; var failedOnce = false; var timer = 0; function tick() { fetch('/api/dev/hot-reload', { cache: 'no-store', headers: { accept: 'application/json' } }) .then(function(response) { return response.ok ? response.json() : null; }) .then(function(payload) { if (!payload || payload.enabled !== true || !payload.bootId) { if (!bootId && timer) window.clearInterval(timer); return; } document.documentElement.setAttribute('data-mnote-dev-hot-reload', 'enabled'); if (!bootId) { bootId = String(payload.bootId); return; } if (failedOnce || String(payload.bootId) !== bootId) { window.location.assign(window.location.href); } }) .catch(function() { if (bootId) failedOnce = true; }); } tick(); timer = window.setInterval(tick, 1000); } if (mnoteDevHotReloadEnabled()) { installMnoteDevHotReload(); } document.addEventListener('dragstart', function(event) { var pageRow = closestAction(event.target, '.tree-row[data-shell-mode="page"][draggable="true"]'); if (pageRow) { startPageDrag(pageRow, event); return; } var fileRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"][draggable="true"]'); if (fileRow) { var _dndRT_ = window.__mnoteFileTreeDndRuntime; if (_dndRT_ && typeof _dndRT_.startFileTreeDrag === 'function') { var dragInfo = _dndRT_.startFileTreeDrag(fileRow, { selectedSidebarFileTreeRowIdsForDrag: selectedSidebarFileTreeRowIdsForDrag, }); draggingFileTreeRowIds = _dndRT_.draggingFileTreeRowIds; if (event.dataTransfer && dragInfo) { event.dataTransfer.effectAllowed = dragInfo.effectAllowed || 'copyMove'; event.dataTransfer.setData(_dndRT_.FILETREE_DRAG_MIME, dragInfo.payload); event.dataTransfer.setData('application/x-mnote-file-tree', dragInfo.payload); event.dataTransfer.setData('text/plain', dragInfo.payload); } } else { // inline fallback draggingFileTreeRowIds = selectedSidebarFileTreeRowIdsForDrag(fileRow); if (event.dataTransfer) { var payload = JSON.stringify({ type: 'mnote-file-tree-dnd', version: 1, rowIds: draggingFileTreeRowIds }); event.dataTransfer.effectAllowed = 'copyMove'; event.dataTransfer.setData(FILETREE_DRAG_MIME, payload); event.dataTransfer.setData('application/x-mnote-file-tree', payload); event.dataTransfer.setData('text/plain', payload); } } } }); document.addEventListener('dragover', function(event) { var pageRow = closestAction(event.target, '.tree-row[data-shell-mode="page"]'); var sourceNodeId = readPageDragNodeId(event); if (pageRow && canDropPage(sourceNodeId, pageRow)) { event.preventDefault(); var pagePosition = pageDropPosition(event, pageRow); setActivePageDropRow(pageRow, pagePosition); if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'; return; } var _dndRT_ = window.__mnoteFileTreeDndRuntime; if (_dndRT_ && typeof _dndRT_.handleFileTreeDragOver === 'function') { if (_dndRT_.handleFileTreeDragOver(event, { closestAction: closestAction })) { return; } } else { // inline fallback var fileTree = document.getElementById('sidebar-file-tree-root'); if (fileTree && fileTree.contains(event.target)) { var hasFiles = event.dataTransfer && Array.prototype.indexOf.call(event.dataTransfer.types || [], 'Files') >= 0; var hasInternal = event.dataTransfer && Array.prototype.indexOf.call(event.dataTransfer.types || [], FILETREE_DRAG_MIME) >= 0; if (!hasFiles && !hasInternal && draggingFileTreeRowIds.length === 0) return; event.preventDefault(); if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'false'); activeFileTreeDropRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"]') || fileTree; if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'true'); var copyModifier = event.altKey || event.ctrlKey || event.metaKey; if (event.dataTransfer) event.dataTransfer.dropEffect = hasFiles || copyModifier ? 'copy' : 'move'; } } }); document.addEventListener('drop', function(event) { var pageRow = closestAction(event.target, '.tree-row[data-shell-mode="page"]'); var sourceNodeId = readPageDragNodeId(event); if (pageRow && canDropPage(sourceNodeId, pageRow)) { event.preventDefault(); var position = pageDropPosition(event, pageRow); var target = resolvePageMoveTarget(pageRow, position); clearPageDragState(); void dispatchTreeCommand(pageRow, { action: 'move', workspaceId: resolveWorkspaceId(pageRow), documentId: sourceNodeId, parentId: target.parentId, sortOrder: target.sortOrder }); return; } var _dndRT_ = window.__mnoteFileTreeDndRuntime; if (_dndRT_ && typeof _dndRT_.handleFileTreeDrop === 'function') { _dndRT_.handleFileTreeDrop(event, { closestAction: closestAction, resolveWorkspaceId: resolveWorkspaceId, fileTreeRowLocalUploadTargetRelativePath: fileTreeRowLocalUploadTargetRelativePath, ensureFileTreeWritableTarget: ensureFileTreeWritableTarget, dispatchSidebarEvent: dispatchSidebarEvent, }); } else { // inline fallback var fileTree = document.getElementById('sidebar-file-tree-root'); if (fileTree && fileTree.contains(event.target)) { var targetRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"]'); var files = event.dataTransfer ? Array.from(event.dataTransfer.files || []) : []; var raw = event.dataTransfer ? event.dataTransfer.getData(FILETREE_DRAG_MIME) || event.dataTransfer.getData('application/x-mnote-file-tree') || '' : ''; var rowIds = draggingFileTreeRowIds.slice(); if (raw) { try { var parsed = JSON.parse(raw); if (Array.isArray(parsed.rowIds)) rowIds = parsed.rowIds; } catch (_) {} } if (!files.length && !rowIds.length) return; event.preventDefault(); var detail = { workspaceId: resolveWorkspaceId(targetRow || fileTree), targetRowId: targetRow ? targetRow.getAttribute('data-row-id') : null, targetRowKind: targetRow ? targetRow.getAttribute('data-row-kind') : 'root', documentId: targetRow ? targetRow.getAttribute('data-document-id') || targetRow.getAttribute('data-doc-id') : null, assetId: targetRow ? targetRow.getAttribute('data-asset-id') : null, targetRelativePath: targetRow ? fileTreeRowLocalUploadTargetRelativePath(targetRow) : '', uploadIntent: 'filetree.folder.drop' }; if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'false'); activeFileTreeDropRow = null; if (files.length) { dispatchSidebarEvent('tree.filetree.external-drop', Object.assign({}, detail, { files: files })); } else { void Promise.resolve(ensureFileTreeWritableTarget('drop', targetRow, rowIds, event.altKey === true || event.ctrlKey === true || event.metaKey === true)).then(function(writable) { if (!writable) return; dispatchSidebarEvent('tree.filetree.internal-drop', Object.assign({}, detail, { rowIds: rowIds, copy: event.altKey === true || event.ctrlKey === true || event.metaKey === true })); }); } draggingFileTreeRowIds = []; } } }); document.addEventListener('dragend', function() { clearPageDragState(); var _dndRT_ = window.__mnoteFileTreeDndRuntime; if (_dndRT_ && typeof _dndRT_.resetFileTreeDragState === 'function') { _dndRT_.resetFileTreeDragState(); } else { draggingFileTreeRowIds = []; clearPageDropFeedback(); if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'false'); activeFileTreeDropRow = null; } }); sidebarTreeLiveApply.installTreeLiveApplyEventListeners(); var tree = document.getElementById('sidebar-tree-root'); var activeId = currentDocumentId(); if (tree && activeId) { var activeRow = tree.querySelector('.tree-row[data-node-id="' + cssEscape(activeId) + '"]'); if (activeRow instanceof HTMLElement) activeRow.setAttribute('data-active', 'true'); } var initiallySelectedFileRows = document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-selected="true"]'); initiallySelectedFileRows.forEach(function(row) { if (!(row instanceof HTMLElement)) return; var rowId = row.getAttribute('data-row-id') || ''; if (!rowId) return; sidebarFileTreeSelection.selectedRowIds.add(rowId); if (!sidebarFileTreeSelection.anchorRowId) sidebarFileTreeSelection.anchorRowId = rowId; sidebarFileTreeSelection.focusedRowId = rowId; }); syncSidebarFileTreeSelection(); // Shell-first home: FileTree may be a pending placeholder; hydrate after first paint. if (typeof sidebarTreeLiveApply.hydratePendingFileTreeShell === 'function') { var schedulePendingHydrate = typeof queueMicrotask === 'function' ? queueMicrotask : function(fn) { setTimeout(fn, 0); }; schedulePendingHydrate(function() { void sidebarTreeLiveApply.hydratePendingFileTreeShell('boot'); }); } schedulePendingLocalFolderRestoreFocus(); var recentPageOptionsApply = { documentId: '', at: 0 }; function applyPrimaryPageOptionsOnce(documentId) { var normalizedDocumentId = searchText(documentId || currentDocumentId() || ''); pageUiState.pageOptions = null; applyPageOptionsToShell(); if (isPageSettingsOpen()) renderPageSettingsPopover(); recentPageOptionsApply = { documentId: normalizedDocumentId, at: Date.now() }; } function hasRecentPageOptionsApply(documentId) { var normalizedDocumentId = searchText(documentId || currentDocumentId() || ''); return normalizedDocumentId && recentPageOptionsApply.documentId === normalizedDocumentId && Date.now() - recentPageOptionsApply.at < 1000; } window.addEventListener('mnote:primary-document-activated', function(event) { var detail = event && event.detail ? event.detail : {}; if (!hasRecentPageOptionsApply(detail.documentId)) { applyPrimaryPageOptionsOnce(detail.documentId); } if (detail.pageBlockNavigation === true) { detail.sidebarSelectionHandled = false; return; } if (activeSidebarTreeMode() === 'filetree') { detail.sidebarSelectionHandled = selectSidebarFileTreeDocument(detail.documentId, { rootUri: detail.rootUri || currentRootUri(), scrollIntoView: false }); } else { detail.sidebarSelectionHandled = selectSidebarPageTreeDocument(detail.documentId, { scrollIntoView: false }); } }); window.addEventListener('mnote:page-aggregate-synced', function(event) { var detail = event && event.detail ? event.detail : {}; if (detail.scriptId && detail.scriptId !== '__MNOTE_PAGE_AGGREGATE__') return; var documentId = searchText(detail.documentId || ''); if (documentId && currentDocumentId() && documentId !== currentDocumentId()) return; applyPrimaryPageOptionsOnce(documentId); }); restoreSidebarTreeTab(); if (window.location.pathname === '/debug/knowledge-rag' || window.location.pathname === '/knowledge') { window.setTimeout(function() { openKnowledgeRagSettingsPopover(); }, 0); } startLocalFolderSidebarWatch(); })();