feat: consolidate local-first mnote web runtime

This commit is contained in:
lix-2026
2026-05-28 22:01:44 +08:00
parent 7354807ee9
commit 39b9a0183a
154 changed files with 13591 additions and 12728 deletions
@@ -29,6 +29,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
var activeTreeContextMenu = null;
var pageUiState = {
pageOptions: null,
pageWidthPreferences: null,
historySnapshots: [],
pageSettingsOpen: false,
pageAiOpen: false,
@@ -244,12 +245,14 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
const openPageShareDialog = (...args) => sidebarPageSettings.openPageShareDialog(...args);
const pageOptionIsSupported = (...args) => sidebarPageSettings.pageOptionIsSupported(...args);
const persistPageOptionsPatch = (...args) => sidebarPageSettings.persistPageOptionsPatch(...args);
const persistPageWidthPreference = (...args) => sidebarPageSettings.persistPageWidthPreference(...args);
const recordPageHistorySnapshot = (...args) => sidebarPageSettings.recordPageHistorySnapshot(...args);
const renderPageSettingsPopover = (...args) => sidebarPageSettings.renderPageSettingsPopover(...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;
@@ -413,6 +416,57 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
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;
}
function currentTopbarTitle() {
var title = document.querySelector('[data-page-title-current="true"]');
return title && title.textContent ? title.textContent.trim() : '无标题';
@@ -749,6 +803,14 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
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);
@@ -805,10 +867,12 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
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 || ''); },
@@ -818,6 +882,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
const inferOnlyOfficeFileType = (...args) => sidebarFileTreeOpen.inferOnlyOfficeFileType(...args);
const buildOnlyOfficeOpenUrl = (...args) => sidebarFileTreeOpen.buildOnlyOfficeOpenUrl(...args);
const buildOnlyOfficeOpenPath = (...args) => sidebarFileTreeOpen.buildOnlyOfficeOpenPath(...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);
@@ -925,6 +990,9 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
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 '';
}
@@ -1720,7 +1788,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'false');
document.documentElement.setAttribute('data-mnote-last-upload-insert-error', 'insert_content_failed');
}
window.setTimeout(function() {
window.setTimeout(function annotateUploadedLink(attempt) {
if (targetRoot instanceof HTMLElement) window.__mnoteLastEditorUploadRoot = targetRoot;
enhanceEditorAttachmentLinks();
var selector = assetId
@@ -1729,12 +1797,22 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
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) {
link.setAttribute('data-mnote-attachment-link', 'true');
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, 0);
return inserted;
}
} catch (error) {
@@ -1801,7 +1879,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
if (options && options.insertIntoEditor) {
await insertUploadedAssetIntoEditor(localPayload.asset, editorRootFromUploadOptions(options));
}
void refreshLocalFolderSidebarSnapshot();
if (!(options && options.insertIntoEditor)) void refreshLocalFolderSidebarSnapshot();
window.dispatchEvent(new CustomEvent('wolai:local-assets-changed', {
detail: { docId: documentId, asset: localPayload.asset, assetIds: [localPayload.asset.id] }
}));
@@ -1844,6 +1922,9 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
window.addEventListener('wolai:assets-changed', function(event) {
applyAssetsChangedToFileTree(event.detail || {});
});
window.addEventListener('wolai:local-assets-changed', function(event) {
applyAssetsChangedToFileTree(event.detail || {});
});
installMindmapAssetFetchObserver();
async function uploadFilesWithResolvedTarget(files, detail, options) {
@@ -2022,6 +2103,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
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);
@@ -2300,6 +2382,8 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
const pageAiLoadSkills = (...args) => sidebarPageAi.pageAiLoadSkills(...args);
const pageAiSwitchProfile = (...args) => sidebarPageAi.pageAiSwitchProfile(...args);
const pageAiSetContextScope = (...args) => sidebarPageAi.pageAiSetContextScope(...args);
const pageAiSetAgentId = (...args) => sidebarPageAi.pageAiSetAgentId(...args);
const pageAiToggleContextRef = (...args) => sidebarPageAi.pageAiToggleContextRef(...args);
const updatePageAiTriggerState = (...args) => sidebarPageAi.updatePageAiTriggerState(...args);
const sidebarAttachmentOpen = createSidebarAttachmentOpenRuntime({
@@ -2308,12 +2392,14 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
buildLocalOnlyOfficeOpenUrl,
buildOnlyOfficeOpenPath,
buildOnlyOfficeOpenUrl,
buildPdfPreviewOpenUrl,
closestAction,
currentDocumentId,
currentRootUri,
currentWorkspaceSourcePayload,
fileTreeIconKindForFileName,
healLegacyOfficeAttachmentParagraphs,
hydrateEditorAttachmentMeta,
inferCodeAttachmentLanguage: (...args) => inferCodeAttachmentLanguage(...args),
inferOnlyOfficeFileType,
isCodeAttachmentFileName: (...args) => isCodeAttachmentFileName(...args),
@@ -2366,7 +2452,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
return;
}
var editorAttachmentLink = closestAction(e.target, '.editor-surface .ProseMirror a[data-mnote-attachment-link="true"], .editor-surface .ProseMirror a.mnote-uploaded-attachment-row, .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]');
var editorAttachmentLink = closestAction(e.target, '.editor-surface .ProseMirror a[data-mnote-attachment-link="true"], .editor-surface .ProseMirror a.mnote-uploaded-attachment-row, .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"], .editor-surface .ProseMirror a[href*="/office-preview"]');
if (editorAttachmentLink instanceof HTMLAnchorElement) {
e.preventDefault();
openEditorAttachmentLink(editorAttachmentLink);
@@ -2503,6 +2589,20 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
return;
}
var pageAiAgent = closestAction(e.target, '[data-page-ai-agent-id]');
if (pageAiAgent) {
e.preventDefault();
pageAiSetAgentId(pageAiAgent.getAttribute('data-page-ai-agent-id') || 'reasonix');
return;
}
var pageAiContextRef = closestAction(e.target, '[data-page-ai-context-ref]');
if (pageAiContextRef) {
e.preventDefault();
pageAiToggleContextRef(pageAiContextRef.getAttribute('data-page-ai-context-ref') || '');
return;
}
var pageAiMemorySave = closestAction(e.target, '[data-page-ai-memory-save]');
if (pageAiMemorySave) {
e.preventDefault();
@@ -2820,14 +2920,24 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
e.preventDefault();
selectSidebarFileTreeRow(fileRow, { ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey });
var objectIdentity = readFileTreeObjectIdentity(fileRow);
dispatchSidebarEvent('tree.filetree.open', { rowId: rowId, rowKind: rowKind, documentId: ownerDocumentId || null, assetId: assetId || null, assetType: assetType || null, objectIdentity: objectIdentity, workspaceId: resolveWorkspaceId(fileRow) });
var workspacePath = readWorkspacePathFromRow(fileRow);
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') && 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, workspaceId: resolveWorkspaceId(fileRow), openTarget: e.shiftKey || e.ctrlKey || e.metaKey ? 'new-window' : 'active-tab' });
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;
}
@@ -2859,7 +2969,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
});
document.addEventListener('contextmenu', function(event) {
var editorAttachmentLink = closestAction(event.target, '.editor-surface .ProseMirror a[data-mnote-attachment-link="true"], .editor-surface .ProseMirror a.mnote-uploaded-attachment-row, .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]');
var editorAttachmentLink = closestAction(event.target, '.editor-surface .ProseMirror a[data-mnote-attachment-link="true"], .editor-surface .ProseMirror a.mnote-uploaded-attachment-row, .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"], .editor-surface .ProseMirror a[href*="/office-preview"]');
if (editorAttachmentLink instanceof HTMLAnchorElement) {
event.preventDefault();
event.stopPropagation();
@@ -2904,6 +3014,10 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
// 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;
}
@@ -2921,14 +3035,18 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
}
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');
if (!evaluateSidebarFileTreeWhen(delCtx, '!workspace.readonly')) {
var delCtx = buildSidebarFileTreeContext('filetree', { targetRow: fileTreeRowForKey });
if (!evaluateSidebarFileTreeWhen(delCtx, '!workspace.readonly && !editor.dirty')) {
return;
}
void deleteSelectedSidebarFileTreeRows(fileTreeRowForKey);
@@ -3044,12 +3162,20 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
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);
}
});
function initializePageUiSurfaces() {
pageUiState.pageOptions = null;
pageUiState.pageWidthPreferences = null;
applyPageOptionsToShell();
void loadPageWidthPreferences();
updatePageSettingsTriggerState();
updatePageAiTriggerState();
ensureHistorySnapshotsSeeded();