feat: restore Wolai workspace navigation and assets
This commit is contained in:
@@ -470,18 +470,33 @@ import {
|
||||
const topbarCurrent = document.querySelector('.wolai-breadcrumb-current [data-page-title-current]');
|
||||
if (topbarCurrent instanceof HTMLElement) topbarCurrent.textContent = title;
|
||||
window.dispatchEvent(new CustomEvent('mnote:primary-document-activated', {
|
||||
detail: { documentId, workspaceId, title }
|
||||
detail: {
|
||||
documentId,
|
||||
workspaceId,
|
||||
title,
|
||||
sourceKind: bootstrap.sourceKind || '',
|
||||
rootUri: bootstrap.rootUri || '',
|
||||
pageBlockNavigation: runtimeDescriptor.pageBlockNavigation === true,
|
||||
}
|
||||
}));
|
||||
document.documentElement.removeAttribute('data-mnote-side-target-unsupported');
|
||||
document.documentElement.removeAttribute('data-mnote-side-target-asset-id');
|
||||
document.querySelectorAll('.tree-row[data-active="true"], .tree-row[data-selected="true"]').forEach((row) => {
|
||||
const activeTreeTab = document.querySelector('[data-mnote-sidebar-tree-tab][aria-selected="true"]');
|
||||
const activeTreeMode = activeTreeTab instanceof HTMLElement
|
||||
&& activeTreeTab.getAttribute('data-mnote-sidebar-tree-tab') === 'filetree'
|
||||
? 'filetree'
|
||||
: 'page';
|
||||
const activeTreeRows = activeTreeMode === 'filetree'
|
||||
? '#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]'
|
||||
: '#sidebar-tree-root .tree-row[data-shell-mode="page"]';
|
||||
document.querySelectorAll(`${activeTreeRows}[data-active="true"], ${activeTreeRows}[data-selected="true"]`).forEach((row) => {
|
||||
if (row instanceof HTMLElement) {
|
||||
row.setAttribute('data-active', 'false');
|
||||
row.setAttribute('data-selected', 'false');
|
||||
}
|
||||
});
|
||||
const escapedId = window.CSS && typeof window.CSS.escape === 'function' ? window.CSS.escape(documentId) : String(documentId).replace(/["\\]/g, '\\$&');
|
||||
document.querySelectorAll(`.tree-row[data-node-id="${escapedId}"], .tree-row[data-document-id="${escapedId}"], .tree-row[data-doc-id="${escapedId}"]`).forEach((row) => {
|
||||
document.querySelectorAll(`${activeTreeRows}[data-node-id="${escapedId}"], ${activeTreeRows}[data-document-id="${escapedId}"], ${activeTreeRows}[data-doc-id="${escapedId}"]`).forEach((row) => {
|
||||
if (!(row instanceof HTMLElement)) return;
|
||||
if (row.getAttribute('data-shell-mode') === 'filetree') {
|
||||
row.setAttribute('data-selected', String(row.getAttribute('data-row-id') === `doc:${documentId}`));
|
||||
@@ -610,7 +625,7 @@ import {
|
||||
}
|
||||
const bootstrap = buildBootstrapFromAggregate(aggregate, descriptor, paneRole);
|
||||
syncPageAggregateScript({ pageAggregateScriptId: bootstrap.pageAggregateScriptId }, aggregate);
|
||||
const runtimeDescriptor = { paneRole, root, observability, aggregate, bootstrap };
|
||||
const runtimeDescriptor = { paneRole, root, observability, aggregate, bootstrap, pageBlockNavigation: descriptor.pageBlockNavigation === true };
|
||||
updatePaneChrome(runtimeDescriptor);
|
||||
if (paneRole === 'secondary' && workspace instanceof HTMLElement) {
|
||||
workspace.setAttribute('data-has-secondary-pane', 'true');
|
||||
@@ -677,6 +692,70 @@ import {
|
||||
pushUrlState(url);
|
||||
};
|
||||
|
||||
const openPrimaryDocumentFromPageBlockHref = (href) => {
|
||||
const raw = typeof href === 'string' ? href.trim() : '';
|
||||
if (!raw) return false;
|
||||
let target = null;
|
||||
try {
|
||||
target = new URL(raw, window.location.href);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
if (target.origin !== window.location.origin || !target.pathname.startsWith('/documents/')) return false;
|
||||
const encodedId = target.pathname.slice('/documents/'.length).split('/')[0] || '';
|
||||
const documentId = decodeURIComponent(encodedId).trim();
|
||||
if (!documentId || typeof window.__mnoteDocumentPaneRuntime?.openPrimaryDocument !== 'function') return false;
|
||||
const current = currentUrl();
|
||||
const workspaceId = target.searchParams.get('workspaceId') || current.searchParams.get('workspaceId') || '';
|
||||
const sourceKind = target.searchParams.get('sourceKind') || current.searchParams.get('sourceKind') || '';
|
||||
const rootUri = target.searchParams.get('rootUri') || current.searchParams.get('rootUri') || '';
|
||||
void window.__mnoteDocumentPaneRuntime.openPrimaryDocument({
|
||||
documentId,
|
||||
workspaceId,
|
||||
sourceKind,
|
||||
rootUri,
|
||||
url: target,
|
||||
pageBlockNavigation: true,
|
||||
}).catch((error) => {
|
||||
console.warn('mnote page block pane navigation failed, fallback to full navigation', error);
|
||||
window.location.assign(target.pathname + target.search + target.hash);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
const installPageBlockOpenCapture = () => {
|
||||
if (window.__mnotePageBlockOpenCaptureInstalled === true) return;
|
||||
window.__mnotePageBlockOpenCaptureInstalled = true;
|
||||
document.addEventListener('mousedown', (event) => {
|
||||
if (event.button !== 0) return;
|
||||
const target = event.target;
|
||||
const anchor = target instanceof Element ? target.closest('a.mnote-page-block-link') : null;
|
||||
if (!(anchor instanceof HTMLAnchorElement)) return;
|
||||
const href = anchor.getAttribute('href') || '';
|
||||
if (!href) return;
|
||||
// Tiptap's Link extension handles mouse down before the click bubble. Keep
|
||||
// the target aside so that it cannot trigger a native document navigation.
|
||||
anchor.setAttribute('data-mnote-page-block-href', href);
|
||||
anchor.removeAttribute('href');
|
||||
}, true);
|
||||
document.addEventListener('click', (event) => {
|
||||
const target = event.target;
|
||||
const anchor = target instanceof Element ? target.closest('a.mnote-page-block-link') : null;
|
||||
if (!(anchor instanceof HTMLAnchorElement)) return;
|
||||
const href = anchor.getAttribute('data-mnote-page-block-href') || anchor.getAttribute('href') || '';
|
||||
if (!href) return;
|
||||
anchor.removeAttribute('data-mnote-page-block-href');
|
||||
anchor.removeAttribute('href');
|
||||
if (!openPrimaryDocumentFromPageBlockHref(href)) {
|
||||
anchor.setAttribute('href', href);
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
|
||||
}, true);
|
||||
};
|
||||
|
||||
const setSecondaryEditorHostVisible = (visible) => {
|
||||
const host = document.querySelector('[data-testid="mnote-secondary-editor-tab-host"]');
|
||||
if (host instanceof HTMLElement) host.hidden = !visible;
|
||||
@@ -973,10 +1052,11 @@ import {
|
||||
};
|
||||
|
||||
window.__mnoteDocumentPaneRuntime = {
|
||||
openPrimaryDocument: async ({ documentId, workspaceId, sourceKind, rootUri, url } = {}) => {
|
||||
openPrimaryDocument: async ({ documentId, workspaceId, sourceKind, rootUri, url, pageBlockNavigation } = {}) => {
|
||||
const id = typeof documentId === 'string' ? documentId.trim() : '';
|
||||
if (!id) return false;
|
||||
const descriptor = descriptorFromCurrentUrl('primary', id, { workspaceId, sourceKind, rootUri });
|
||||
descriptor.pageBlockNavigation = pageBlockNavigation === true;
|
||||
await replacePaneDocument('primary', descriptor);
|
||||
activateMainEditorTab('', 'primary');
|
||||
updatePrimaryUrl(descriptor, url instanceof URL ? url : null);
|
||||
@@ -1037,6 +1117,7 @@ import {
|
||||
return 1;
|
||||
},
|
||||
};
|
||||
installPageBlockOpenCapture();
|
||||
|
||||
bindMainEditorPageTab('primary');
|
||||
bindMainEditorPageTab('secondary');
|
||||
|
||||
Reference in New Issue
Block a user