Land password-vault dedicated workbench and mnote-vault-core/CLI, agent token read path design, vault transport split, and retire obsolete filetree smokes. Ignore local vault reimport scripts that trip secret scanners.
4150 lines
203 KiB
JavaScript
4150 lines
203 KiB
JavaScript
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, '"')
|
||
.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 (
|
||
'<section class="mnote-vault-workbench" data-testid="mnote-vault-workbench" data-workspace-id="' +
|
||
ws +
|
||
'" data-root-uri="' +
|
||
root +
|
||
'" data-status="active">' +
|
||
'<header class="mnote-vault-header">' +
|
||
'<div class="mnote-vault-header-main">' +
|
||
'<h1>密码箱</h1>' +
|
||
'<p class="mnote-vault-status" data-vault-status role="status" aria-live="polite"></p>' +
|
||
'</div>' +
|
||
'<div class="mnote-vault-header-actions">' +
|
||
'<button type="button" data-vault-create data-testid="vault-create">新建</button>' +
|
||
'<button type="button" data-vault-cipher-book data-testid="vault-cipher-book">密文簿</button>' +
|
||
'<label class="mnote-vault-insert-cipher" title="在当前焦点字段光标处插入 [Key]" hidden aria-hidden="true">' +
|
||
'<span class="mnote-vault-sr-only">插入密文</span>' +
|
||
'<select data-vault-insert-cipher data-testid="vault-insert-cipher" aria-label="插入密文">' +
|
||
'<option value="">插入密文…</option>' +
|
||
'</select></label>' +
|
||
'<input type="search" data-vault-search data-testid="vault-search" placeholder="搜索标题、用户名、标签、分组…" aria-label="搜索密码条目" />' +
|
||
'<div class="mnote-vault-tabs" role="tablist">' +
|
||
'<button type="button" role="tab" data-vault-tab="active" class="is-active" aria-selected="true">在用</button>' +
|
||
'<button type="button" role="tab" data-vault-tab="deleted" aria-selected="false">已删除</button>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'</header>' +
|
||
'<div class="mnote-vault-body">' +
|
||
'<aside class="mnote-vault-list" data-vault-list data-testid="vault-list" aria-label="密码条目列表"></aside>' +
|
||
'<main class="mnote-vault-detail" data-vault-detail data-testid="vault-detail" aria-label="条目详情"></main>' +
|
||
'</div>' +
|
||
'</section>'
|
||
);
|
||
}
|
||
|
||
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 = '<button type="button" class="mnote-tree-context-menu__item" role="menuitem" data-mnote-sidebar-shortcut-menu-action="open"><span class="material-symbols-outlined mnote-tree-context-menu__icon" data-icon="login" aria-hidden="true"></span><span class="mnote-tree-context-menu__label">在右侧边栏打开</span></button><div class="mnote-tree-context-menu__separator" role="separator"></div><button type="button" class="mnote-tree-context-menu__item" role="menuitem" data-mnote-sidebar-shortcut-menu-action="copy-link"><span class="material-symbols-outlined mnote-tree-context-menu__icon" data-icon="link" aria-hidden="true"></span><span class="mnote-tree-context-menu__label">复制访问链接</span></button><button type="button" class="mnote-tree-context-menu__item mnote-tree-context-menu__item--danger" role="menuitem" data-mnote-sidebar-shortcut-menu-action="remove"><span class="material-symbols-outlined mnote-tree-context-menu__icon" data-icon="star_off" aria-hidden="true"></span><span class="mnote-tree-context-menu__label">取消星标</span></button>';
|
||
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 = '<span class="wolai-row-caret" aria-hidden="true">›</span><span class="wolai-row-icon"><span class="material-symbols-outlined wolai-row-symbol" data-icon="' + (kind === 'folder' ? 'folder_open' : 'home') + '" aria-hidden="true"></span></span><span class="wolai-row-title">' + escapeHtml(title) + '</span><button type="button" class="wolai-row-more" data-mnote-shortcut-action="menu" aria-label="更多操作" title="更多操作"><span class="material-symbols-outlined" data-icon="more_horiz" aria-hidden="true"></span></button>';
|
||
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 =
|
||
'<div class="tree-row" role="treeitem" aria-level="' + (parentRow ? '2' : '1') + '" aria-expanded="false" data-rust-rendered-row="filetree" data-testid="filetree-asset-row" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-row-kind="asset" data-node-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-doc-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-object-identity="' + escapeHtml(objectIdentityAttr(objectIdentity)) + '" data-object-kind="' + escapeHtml(objectKind || 'attachment') + '" data-shell-mode="filetree" data-selected="false" data-active="false" draggable="true">' +
|
||
'<span class="tree-spacer" aria-hidden="true"></span><span class="tree-kind-badge" data-kind="' + escapeHtml(iconKind) + '" aria-hidden="true"></span>' +
|
||
'<button type="button" class="tree-link" data-rust-action="open" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '"><span class="tree-link-title">' + escapeHtml(title) + '</span></button>' +
|
||
'<div class="tree-actions"><button type="button" class="tree-action" data-testid="filetree-action-menu" data-rust-action="menu" data-row-id="' + escapeHtml('asset:' + assetId) + '" aria-label="更多操作">…</button></div></div>';
|
||
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 = '' +
|
||
'<div class="wolai-search-dialog">' +
|
||
'<div class="wolai-search-input-row">' +
|
||
'<span class="material-symbols-outlined wolai-search-input-icon" data-icon="search" aria-hidden="true"></span>' +
|
||
'<input data-testid="wolai-search-input" class="wolai-search-input" type="search" autocomplete="off" placeholder="在当前工作区中搜索" />' +
|
||
'<button type="button" class="wolai-search-close" data-testid="wolai-search-close" aria-label="关闭搜索">×</button>' +
|
||
'</div>' +
|
||
'<div class="wolai-search-options" data-testid="wolai-search-options" aria-label="搜索选项" hidden>' +
|
||
'<div class="wolai-search-options-left">' +
|
||
'<span class="wolai-search-switch-control"><span>仅匹配标题</span><button type="button" class="wolai-search-switch" data-search-switch="title" role="switch" aria-checked="false" aria-label="仅匹配标题"></button></span>' +
|
||
'<span class="wolai-search-switch-control"><span>精确匹配</span><button type="button" class="wolai-search-switch" data-search-switch="exact" role="switch" aria-checked="false" aria-label="精确匹配"></button></span>' +
|
||
'<span class="wolai-search-sort-control"><span>知识库模式</span><select class="wolai-search-sort-value" data-search-knowledge-mode aria-label="知识库检索模式"><option value="exact" selected>关键词</option><option value="mix">综合</option><option value="hybrid">图谱混合</option><option value="naive">向量</option><option value="local">实体</option><option value="global">关系</option></select></span>' +
|
||
'<span class="wolai-search-sort-control"><span>按编辑时间</span><button type="button" class="wolai-search-sort-value" data-search-sort="updated" aria-label="按编辑时间范围">所有</button></span>' +
|
||
'<span class="wolai-search-sort-control"><span>按创建时间</span><button type="button" class="wolai-search-sort-value" data-search-sort="created" aria-label="按创建时间范围">所有</button></span>' +
|
||
'</div>' +
|
||
'<div class="wolai-search-options-right">' +
|
||
'<span class="wolai-search-switch-control"><span>全盘知识库</span><button type="button" class="wolai-search-switch" data-search-switch="knowledge" role="switch" aria-checked="false" aria-label="全盘知识库检索"></button></span>' +
|
||
'<span class="wolai-search-switch-control"><span>页面内搜索</span><button type="button" class="wolai-search-switch" data-search-switch="page" role="switch" aria-checked="false" aria-label="页面内搜索"></button></span>' +
|
||
'<span class="wolai-search-switch-control"><span>折叠同来源</span><button type="button" class="wolai-search-switch is-on" data-search-switch="collapseSource" role="switch" aria-checked="true" aria-label="默认折叠相同来源结果"></button></span>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="wolai-search-result-meta" data-testid="wolai-search-result-meta"></div>' +
|
||
'<div class="wolai-search-results" data-testid="wolai-search-results" data-search-results-owner="rust-kernel"></div>' +
|
||
'</div>';
|
||
|
||
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)) +
|
||
'<mark>' + escapeHtml(text.slice(exactIndex, exactIndex + cleanQuery.length)) + '</mark>' +
|
||
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 += '<mark>' + escapeHtml(text.slice(range.start, range.end)) + '</mark>';
|
||
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(/<drawing\b[^>]*\/?>/gi, ' ');
|
||
text = text.replace(/<equation\b[^>]*>([\s\S]*?)<\/equation>/gi, '$1');
|
||
text = text.replace(/<drawing\b[^<>]*$/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 ? '' : '<span class="wolai-search-result-title">' + highlightSearchText(title, query, exact, highlightTerms) + '</span>';
|
||
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('<span class="wolai-search-result-type">' + escapeHtml(resourceType) + '</span>');
|
||
var metaHtml = metaParts.length ? '<span class="wolai-search-result-path"><span>' + metaParts.join('</span><span>') + '</span></span>' : '';
|
||
return '<button type="button" class="wolai-search-result-row" data-testid="wolai-search-result-row" data-search-result-owner="' + escapeHtml(item.provider || 'rust-kernel') + '" data-search-result-index="' + String(index) + '" data-document-id="' + escapeHtml(item.documentId || item.nodeId || item.id || '') + '" data-resource-type="' + escapeHtml(resourceType) + '"' + (locatorAttr ? ' data-evidence-locator="' + locatorAttr + '"' : '') + '>' +
|
||
'<span class="material-symbols-outlined wolai-search-result-icon" data-icon="article" aria-hidden="true"></span>' +
|
||
'<span class="wolai-search-result-main">' + titleHtml +
|
||
'<span class="wolai-search-result-snippet">' + (snippet ? highlightSearchText(snippet, query, exact, highlightTerms) : escapeHtml(path)) + '</span>' +
|
||
metaHtml + '</span>' +
|
||
'</button>';
|
||
}
|
||
|
||
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 '<section class="wolai-search-source-group" data-search-source-key="' + escapeHtml(group.key) + '">' +
|
||
'<button type="button" class="wolai-search-source-header" data-search-source-toggle="true" aria-expanded="' + (collapsed ? 'false' : 'true') + '">' +
|
||
'<span class="material-symbols-outlined wolai-search-result-icon" data-icon="article" aria-hidden="true"></span>' +
|
||
'<span class="wolai-search-source-main"><span class="wolai-search-result-title">' + escapeHtml(group.title) + '</span>' +
|
||
'<span class="wolai-search-result-path"><span class="wolai-search-result-type">' + escapeHtml(group.resourceType) + '</span><span>' + String(group.rows.length) + ' 处</span></span></span>' +
|
||
'<span class="wolai-search-source-chevron" aria-hidden="true">' + (collapsed ? '展开' : '收起') + '</span>' +
|
||
'</button>' +
|
||
'<div class="wolai-search-source-results" data-search-source-results="true"' + (collapsed ? ' hidden' : '') + '>' + children + '</div>' +
|
||
'</section>';
|
||
}).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 = '<span>最近浏览</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||
if (results) {
|
||
results.innerHTML = '<div class="wolai-search-recent" data-testid="wolai-search-recent">暂无最近浏览</div>';
|
||
}
|
||
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 = '<span>知识库检索</span><span>请输入至少 2 个字再搜索</span>';
|
||
results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">请输入至少 2 个字再搜索</div>';
|
||
window.__mnoteSearchResults = [];
|
||
saveSearchUiState(overlay);
|
||
searchUiState.hasRendered = true;
|
||
return;
|
||
}
|
||
var requestId = ++activeSearchRequestId;
|
||
var knowledgeRequestMode = knowledgeMode ? knowledgeSearchRequestMode(overlay) : '';
|
||
meta.innerHTML = '<span>搜索中…</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||
results.innerHTML = '<div class="wolai-search-empty" data-search-loading="true">搜索中…</div>';
|
||
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 = '<span>' + ownerLabel + ' · 共 ' + items.length + ' 条匹配结果</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||
if (!items.length) {
|
||
results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">没有搜索结果</div>';
|
||
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 = '<span>共 0 条匹配结果</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||
results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">没有搜索结果</div>';
|
||
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);
|
||
|
||
const sidebarPageAi = createSidebarPageAiRuntime({
|
||
buildLocalFileOpenUrl,
|
||
currentDocumentId,
|
||
currentPageAggregate,
|
||
currentPageOptions,
|
||
currentRootUri,
|
||
currentSourceKind,
|
||
escapeHtml,
|
||
cssEscape,
|
||
openLocalResourceInActiveTab,
|
||
pageUiState,
|
||
resolveWorkspaceId,
|
||
searchText,
|
||
});
|
||
const openPageAiDrawer = (...args) => sidebarPageAi.openPageAiDrawer(...args);
|
||
const closePageAiDrawer = (...args) => sidebarPageAi.closePageAiDrawer(...args);
|
||
const isPageAiDrawerOpen = (...args) => sidebarPageAi.isPageAiDrawerOpen(...args);
|
||
const ensurePageAiDrawer = (...args) => sidebarPageAi.ensurePageAiDrawer(...args);
|
||
const sendPageAiMessage = (...args) => sidebarPageAi.sendPageAiMessage(...args);
|
||
const pageAiOpenHermesSettings = (...args) => sidebarPageAi.pageAiOpenHermesSettings(...args);
|
||
const pageAiStopRun = (...args) => sidebarPageAi.pageAiStopRun(...args);
|
||
const pageAiLoadGatewayHealth = (...args) => sidebarPageAi.pageAiLoadGatewayHealth(...args);
|
||
const renderPageAiControls = (...args) => sidebarPageAi.renderPageAiControls(...args);
|
||
const renderPageAiConversation = (...args) => sidebarPageAi.renderPageAiConversation(...args);
|
||
const renderPageAiProviderButtons = (...args) => sidebarPageAi.renderPageAiProviderButtons(...args);
|
||
const renderPageAiSuggestions = (...args) => sidebarPageAi.renderPageAiSuggestions(...args);
|
||
const pageAiSaveProfileMemory = (...args) => sidebarPageAi.pageAiSaveProfileMemory(...args);
|
||
const pageAiToggleSkill = (...args) => sidebarPageAi.pageAiToggleSkill(...args);
|
||
const pageAiToggleTool = (...args) => sidebarPageAi.pageAiToggleTool(...args);
|
||
const pageAiResumeBackendSession = (...args) => sidebarPageAi.pageAiResumeBackendSession(...args);
|
||
const pageAiRenameBackendSession = (...args) => sidebarPageAi.pageAiRenameBackendSession(...args);
|
||
const pageAiDeleteBackendSession = (...args) => sidebarPageAi.pageAiDeleteBackendSession(...args);
|
||
const pageAiResolvePermission = (...args) => sidebarPageAi.pageAiResolvePermission(...args);
|
||
const pageAiOpenLocation = (...args) => sidebarPageAi.pageAiOpenLocation(...args);
|
||
const pageAiSetActiveSession = (...args) => sidebarPageAi.pageAiSetActiveSession(...args);
|
||
const pageAiStartNewSession = (...args) => sidebarPageAi.pageAiStartNewSession(...args);
|
||
const pageAiLoadSessions = (...args) => sidebarPageAi.pageAiLoadSessions(...args);
|
||
const pageAiLoadBackendSessions = (...args) => sidebarPageAi.pageAiLoadBackendSessions(...args);
|
||
const pageAiCancelQueuedRun = (...args) => sidebarPageAi.pageAiCancelQueuedRun(...args);
|
||
const pageAiSearchBackendSessions = (...args) => sidebarPageAi.pageAiSearchBackendSessions(...args);
|
||
const pageAiPersistSessions = (...args) => sidebarPageAi.pageAiPersistSessions(...args);
|
||
const pageAiLoadProfiles = (...args) => sidebarPageAi.pageAiLoadProfiles(...args);
|
||
const pageAiLoadProfileMemory = (...args) => sidebarPageAi.pageAiLoadProfileMemory(...args);
|
||
const pageAiLoadSkills = (...args) => sidebarPageAi.pageAiLoadSkills(...args);
|
||
const pageAiSwitchProfile = (...args) => sidebarPageAi.pageAiSwitchProfile(...args);
|
||
const pageAiSetSkillSource = (...args) => sidebarPageAi.pageAiSetSkillSource(...args);
|
||
const pageAiToggleSkillGroup = (...args) => sidebarPageAi.pageAiToggleSkillGroup(...args);
|
||
const pageAiSetReasonixMemoryEnabled = (...args) => sidebarPageAi.pageAiSetReasonixMemoryEnabled(...args);
|
||
const pageAiSetHideHermesBuiltinSkills = (...args) => sidebarPageAi.pageAiSetHideHermesBuiltinSkills(...args);
|
||
const pageAiSetContextScope = (...args) => sidebarPageAi.pageAiSetContextScope(...args);
|
||
const pageAiSetAgentId = (...args) => sidebarPageAi.pageAiSetAgentId(...args);
|
||
const pageAiToggleContextRef = (...args) => sidebarPageAi.pageAiToggleContextRef(...args);
|
||
const pageAiSetAgentPopoverOpen = (...args) => sidebarPageAi.pageAiSetAgentPopoverOpen(...args);
|
||
const pageAiSetTargetPopoverOpen = (...args) => sidebarPageAi.pageAiSetTargetPopoverOpen(...args);
|
||
const pageAiSelectTarget = (...args) => sidebarPageAi.pageAiSelectTarget(...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();
|
||
openPageAiDrawer();
|
||
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();
|
||
})();
|