diff --git a/packages/blocks/src/_common/adapters/html-adapter/delta-converter/html-inline.ts b/packages/blocks/src/_common/adapters/html-adapter/delta-converter/html-inline.ts index 2e3995ba5cd9..fd26d7a5be48 100644 --- a/packages/blocks/src/_common/adapters/html-adapter/delta-converter/html-inline.ts +++ b/packages/blocks/src/_common/adapters/html-adapter/delta-converter/html-inline.ts @@ -147,6 +147,41 @@ export const htmlLinkElementToDeltaMatcher: HtmlASTToDeltaMatcher = { if (typeof href !== 'string') { return []; } + const { configs } = context; + const baseUrl = configs.get('docLinkBaseUrl') ?? ''; + if (baseUrl && href.startsWith(baseUrl)) { + const path = href.substring(baseUrl.length); + // ^ - /{pageId}?mode={mode}&blockIds={blockIds}&elementIds={elementIds} + const match = path.match(/^\/([^?]+)(\?.*)?$/); + if (match) { + const pageId = match?.[1]; + const search = match?.[2]; + const searchParams = search ? new URLSearchParams(search) : undefined; + const mode = searchParams?.get('mode'); + const blockIds = searchParams?.get('blockIds')?.split(','); + const elementIds = searchParams?.get('elementIds')?.split(','); + + return [ + { + insert: ' ', + attributes: { + reference: { + type: 'LinkedPage', + pageId, + params: { + mode: + mode && ['edgeless', 'page'].includes(mode) + ? (mode as 'edgeless' | 'page') + : undefined, + blockIds, + elementIds, + }, + }, + }, + }, + ]; + } + } return ast.children.flatMap(child => context.toDelta(child, { trim: false }).map(delta => { if (href.startsWith('http')) { diff --git a/packages/blocks/src/_common/transformers/html.ts b/packages/blocks/src/_common/transformers/html.ts index 4ba3a3321a53..14b4ebbb098d 100644 --- a/packages/blocks/src/_common/transformers/html.ts +++ b/packages/blocks/src/_common/transformers/html.ts @@ -6,7 +6,9 @@ import { extMimeMap, Job } from '@blocksuite/store'; import { HtmlAdapter } from '../adapters/html-adapter/html.js'; import { defaultImageProxyMiddleware, + docLinkBaseURLMiddleware, fileNameMiddleware, + titleMiddleware, } from './middlewares.js'; import { createAssetsArchive, download, Unzip } from './utils.js'; @@ -28,7 +30,10 @@ type ImportHTMLZipOptions = { * @returns A Promise that resolves when the export is complete. */ async function exportDoc(doc: Doc) { - const job = new Job({ collection: doc.collection }); + const job = new Job({ + collection: doc.collection, + middlewares: [docLinkBaseURLMiddleware, titleMiddleware], + }); const snapshot = job.docToSnapshot(doc); const adapter = new HtmlAdapter(job); if (!snapshot) { @@ -73,7 +78,11 @@ async function importHTMLToDoc({ }: ImportHTMLToDocOptions) { const job = new Job({ collection, - middlewares: [defaultImageProxyMiddleware, fileNameMiddleware(fileName)], + middlewares: [ + defaultImageProxyMiddleware, + fileNameMiddleware(fileName), + docLinkBaseURLMiddleware, + ], }); const htmlAdapter = new HtmlAdapter(job); const page = await htmlAdapter.toDoc({ @@ -128,6 +137,7 @@ async function importHTMLZip({ collection, imported }: ImportHTMLZipOptions) { middlewares: [ defaultImageProxyMiddleware, fileNameMiddleware(fileNameWithoutExt), + docLinkBaseURLMiddleware, ], }); const assets = job.assets; diff --git a/packages/blocks/src/_common/transformers/markdown.ts b/packages/blocks/src/_common/transformers/markdown.ts index 8d1cd5a95466..3bfe35146e77 100644 --- a/packages/blocks/src/_common/transformers/markdown.ts +++ b/packages/blocks/src/_common/transformers/markdown.ts @@ -88,7 +88,7 @@ async function importMarkdownToBlock({ }: ImportMarkdownToBlockOptions) { const job = new Job({ collection: doc.collection, - middlewares: [defaultImageProxyMiddleware], + middlewares: [defaultImageProxyMiddleware, docLinkBaseURLMiddleware], }); const adapter = new MarkdownAdapter(job); const snapshot = await adapter.toSliceSnapshot({ @@ -124,7 +124,11 @@ async function importMarkdownToDoc({ }: ImportMarkdownToDocOptions) { const job = new Job({ collection, - middlewares: [defaultImageProxyMiddleware, fileNameMiddleware(fileName)], + middlewares: [ + defaultImageProxyMiddleware, + fileNameMiddleware(fileName), + docLinkBaseURLMiddleware, + ], }); const mdAdapter = new MarkdownAdapter(job); const page = await mdAdapter.toDoc({ @@ -181,6 +185,7 @@ async function importMarkdownZip({ middlewares: [ defaultImageProxyMiddleware, fileNameMiddleware(fileNameWithoutExt), + docLinkBaseURLMiddleware, ], }); const assets = job.assets; diff --git a/packages/blocks/src/_common/transformers/middlewares.ts b/packages/blocks/src/_common/transformers/middlewares.ts index 9a82ee58357a..369bdc3783d8 100644 --- a/packages/blocks/src/_common/transformers/middlewares.ts +++ b/packages/blocks/src/_common/transformers/middlewares.ts @@ -206,6 +206,15 @@ export const customImageProxyMiddleware = ( }; }; +const customDocLinkBaseUrlMiddleware = (baseUrl: string): JobMiddleware => { + return ({ adapterConfigs, collection }) => { + const docLinkBaseUrl = baseUrl + ? `${baseUrl}/workspace/${collection.id}` + : ''; + adapterConfigs.set('docLinkBaseUrl', docLinkBaseUrl); + }; +}; + export const titleMiddleware: JobMiddleware = ({ slots, collection, @@ -219,39 +228,25 @@ export const titleMiddleware: JobMiddleware = ({ }; export const docLinkBaseURLMiddlewareBuilder = (baseUrl: string) => { - let middleware: JobMiddleware = ({ slots, collection, adapterConfigs }) => { - slots.beforeExport.on(() => { - const docLinkBaseUrl = baseUrl - ? `${baseUrl}/workspace/${collection.id}` - : ''; - adapterConfigs.set('docLinkBaseUrl', docLinkBaseUrl); - }); - }; - + let middleware = customDocLinkBaseUrlMiddleware(baseUrl); return { get: () => middleware, - set: (customBaseUrl: string) => { - middleware = ({ slots, collection, adapterConfigs }) => { - slots.beforeExport.on(() => { - const docLinkBaseUrl = customBaseUrl - ? `${customBaseUrl}/workspace/${collection.id}` - : ''; - adapterConfigs.set('docLinkBaseUrl', docLinkBaseUrl); - }); - }; + set: (url: string) => { + middleware = customDocLinkBaseUrlMiddleware(url); }, }; }; -const defaultDocLinkBaseURLMiddlewareBuilder = - docLinkBaseURLMiddlewareBuilder(''); - -export const setDocLinkBaseURLMiddleware = - defaultDocLinkBaseURLMiddlewareBuilder.set; +const defaultDocLinkBaseURLMiddlewareBuilder = docLinkBaseURLMiddlewareBuilder( + typeof window !== 'undefined' ? window.location.origin : '.' +); export const docLinkBaseURLMiddleware = defaultDocLinkBaseURLMiddlewareBuilder.get(); +export const setDocLinkBaseURLMiddleware = + defaultDocLinkBaseURLMiddlewareBuilder.set; + const imageProxyMiddlewareBuilder = () => { let middleware = customImageProxyMiddleware(DEFAULT_IMAGE_PROXY_ENDPOINT); return {