diff --git a/blocksuite/affine/shared/src/adapters/middlewares/copy.ts b/blocksuite/affine/shared/src/adapters/middlewares/copy.ts index 9d217bab3c..95b7c1ab3e 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/copy.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/copy.ts @@ -37,7 +37,7 @@ const handlePoint = ( }; const sliceText = (slots: TransformerSlots, std: EditorHost['std']) => { - slots.afterExport.subscribe(payload => { + const afterExportSubscription = slots.afterExport.subscribe(payload => { if (payload.type === 'block') { const snapshot = payload.snapshot; @@ -53,10 +53,14 @@ const sliceText = (slots: TransformerSlots, std: EditorHost['std']) => { } } }); + + return () => { + afterExportSubscription.unsubscribe(); + }; }; export const copyMiddleware = (std: BlockStdScope): TransformerMiddleware => { return ({ slots }) => { - sliceText(slots, std); + return sliceText(slots, std); }; }; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/file-name.ts b/blocksuite/affine/shared/src/adapters/middlewares/file-name.ts index cb6e71abf4..5ac700fa05 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/file-name.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/file-name.ts @@ -3,7 +3,7 @@ import type { TransformerMiddleware } from '@blocksuite/store'; export const fileNameMiddleware = (fileName?: string): TransformerMiddleware => ({ slots }) => { - slots.beforeImport.subscribe(payload => { + const beforeImportSubscription = slots.beforeImport.subscribe(payload => { if (payload.type !== 'page') { return; } @@ -20,4 +20,8 @@ export const fileNameMiddleware = ], }; }); + + return () => { + beforeImportSubscription.unsubscribe(); + }; }; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/paste.ts b/blocksuite/affine/shared/src/adapters/middlewares/paste.ts index 6c1617672e..852aa49859 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/paste.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/paste.ts @@ -528,7 +528,7 @@ export const pasteMiddleware = ( ): TransformerMiddleware => { return ({ slots }) => { let tr: PasteTr | undefined; - slots.beforeImport.subscribe(payload => { + const beforeImportSubscription = slots.beforeImport.subscribe(payload => { if (payload.type === 'slice') { const { snapshot } = payload; flatNote(snapshot); @@ -543,13 +543,18 @@ export const pasteMiddleware = ( } } }); - slots.afterImport.subscribe(payload => { + const afterImportSubscription = slots.afterImport.subscribe(payload => { if (tr && payload.type === 'slice') { tr.pasted(); tr.focusPasted(); tr.convertToLinkedDoc(); } }); + + return () => { + beforeImportSubscription.unsubscribe(); + afterImportSubscription.unsubscribe(); + }; }; }; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts b/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts index a2c734dfb2..f16f05fac2 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts @@ -32,7 +32,7 @@ export const replaceIdMiddleware = map(({ model }) => model) ); - afterImportBlock$ + const afterImportBlockSubscription = afterImportBlock$ .pipe(filter(model => matchModels(model, [DatabaseBlockModel]))) .subscribe(model => { Object.keys(model.props.cells).forEach(cellId => { @@ -44,7 +44,7 @@ export const replaceIdMiddleware = }); // replace LinkedPage pageId with new id in paragraph blocks - afterImportBlock$ + const replaceLinkedPageIdSubscription = afterImportBlock$ .pipe( filter(model => matchModels(model, [ParagraphBlockModel, ListBlockModel]) @@ -84,7 +84,7 @@ export const replaceIdMiddleware = } }); - afterImportBlock$ + const replaceSurfaceRefIdSubscription = afterImportBlock$ .pipe(filter(model => matchModels(model, [SurfaceRefBlockModel]))) .subscribe(model => { const original = model.props.reference; @@ -105,7 +105,7 @@ export const replaceIdMiddleware = }); // TODO(@fundon): process linked block/element - afterImportBlock$ + const replaceLinkedDocIdSubscription = afterImportBlock$ .pipe( filter(model => matchModels(model, [EmbedLinkedDocModel, EmbedSyncedDocModel]) @@ -128,7 +128,7 @@ export const replaceIdMiddleware = // Before Import - slots.beforeImport + const beforeImportPageSubscription = slots.beforeImport .pipe(filter(payload => payload.type === 'page')) .subscribe(payload => { if (idMap.has(payload.snapshot.meta.id)) { @@ -140,7 +140,7 @@ export const replaceIdMiddleware = payload.snapshot.meta.id = newId; }); - slots.beforeImport + const beforeImportBlockSubscription = slots.beforeImport .pipe( filter( (payload): payload is BeforeImportBlockPayload => @@ -244,4 +244,13 @@ export const replaceIdMiddleware = }); } }); + + return () => { + afterImportBlockSubscription.unsubscribe(); + replaceLinkedPageIdSubscription.unsubscribe(); + replaceSurfaceRefIdSubscription.unsubscribe(); + replaceLinkedDocIdSubscription.unsubscribe(); + beforeImportPageSubscription.unsubscribe(); + beforeImportBlockSubscription.unsubscribe(); + }; }; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/surface-ref-to-embed.ts b/blocksuite/affine/shared/src/adapters/middlewares/surface-ref-to-embed.ts index 2ccff6426b..fd943662fb 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/surface-ref-to-embed.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/surface-ref-to-embed.ts @@ -5,33 +5,42 @@ export const surfaceRefToEmbed = (std: BlockStdScope): TransformerMiddleware => ({ slots }) => { let pageId: string | null = null; - slots.beforeImport.subscribe(payload => { - if (payload.type === 'slice') { - pageId = payload.snapshot.pageId; + const beforeImportSliceSubscription = slots.beforeImport.subscribe( + payload => { + if (payload.type === 'slice') { + pageId = payload.snapshot.pageId; + } } - }); - slots.beforeImport.subscribe(payload => { - // only handle surface-ref block snapshot - if ( - payload.type !== 'block' || - payload.snapshot.flavour !== 'affine:surface-ref' - ) - return; + ); + const beforeImportBlockSubscription = slots.beforeImport.subscribe( + payload => { + // only handle surface-ref block snapshot + if ( + payload.type !== 'block' || + payload.snapshot.flavour !== 'affine:surface-ref' + ) + return; - // turn into embed-linked-doc if the current doc is different from the pageId of the surface-ref block - const isNotSameDoc = pageId !== std.store.doc.id; - if (pageId && isNotSameDoc) { - // The blockId of the original surface-ref block - const blockId = payload.snapshot.id; - payload.snapshot.id = std.workspace.idGenerator(); - payload.snapshot.flavour = 'affine:embed-linked-doc'; - payload.snapshot.props = { - pageId, - params: { - mode: 'page', - blockIds: [blockId], - }, - }; + // turn into embed-linked-doc if the current doc is different from the pageId of the surface-ref block + const isNotSameDoc = pageId !== std.store.doc.id; + if (pageId && isNotSameDoc) { + // The blockId of the original surface-ref block + const blockId = payload.snapshot.id; + payload.snapshot.id = std.workspace.idGenerator(); + payload.snapshot.flavour = 'affine:embed-linked-doc'; + payload.snapshot.props = { + pageId, + params: { + mode: 'page', + blockIds: [blockId], + }, + }; + } } - }); + ); + + return () => { + beforeImportSliceSubscription.unsubscribe(); + beforeImportBlockSubscription.unsubscribe(); + }; }; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/title.ts b/blocksuite/affine/shared/src/adapters/middlewares/title.ts index 83cdfbe046..4d0a421f9a 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/title.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/title.ts @@ -3,9 +3,13 @@ import type { DocMeta, TransformerMiddleware } from '@blocksuite/store'; export const titleMiddleware = (metas: DocMeta[]): TransformerMiddleware => ({ slots, adapterConfigs }) => { - slots.beforeExport.subscribe(() => { + const beforeExportSubscription = slots.beforeExport.subscribe(() => { for (const meta of metas) { adapterConfigs.set('title:' + meta.id, meta.title); } }); + + return () => { + beforeExportSubscription.unsubscribe(); + }; }; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/upload.ts b/blocksuite/affine/shared/src/adapters/middlewares/upload.ts index 231aa80cb6..bf398a4f3b 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/upload.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/upload.ts @@ -79,7 +79,7 @@ export const uploadMiddleware = ( } } - blockView$ + const blockViewSubscription = blockView$ .pipe( map(payload => { if (assetsManager.uploadingAssetsMap.size === 0) return null; @@ -110,5 +110,9 @@ export const uploadMiddleware = ( ) ) .subscribe(); + + return () => { + blockViewSubscription.unsubscribe(); + }; }; }; diff --git a/blocksuite/affine/widgets/drag-handle/src/middleware/blocks-filter.ts b/blocksuite/affine/widgets/drag-handle/src/middleware/blocks-filter.ts index a5526df49a..949fd26acd 100644 --- a/blocksuite/affine/widgets/drag-handle/src/middleware/blocks-filter.ts +++ b/blocksuite/affine/widgets/drag-handle/src/middleware/blocks-filter.ts @@ -40,7 +40,7 @@ export const gfxBlocksFilter = ( } return ({ slots, transformerConfigs }) => { - slots.beforeExport.subscribe(payload => { + const beforeExportSubscription = slots.beforeExport.subscribe(payload => { if (payload.type !== 'block') { return; } @@ -54,7 +54,7 @@ export const gfxBlocksFilter = ( } }); - slots.afterExport.subscribe(payload => { + const afterExportSubscription = slots.afterExport.subscribe(payload => { if (payload.type !== 'block') { return; } @@ -110,5 +110,10 @@ export const gfxBlocksFilter = ( }); } }); + + return () => { + beforeExportSubscription.unsubscribe(); + afterExportSubscription.unsubscribe(); + }; }; }; diff --git a/blocksuite/affine/widgets/drag-handle/src/middleware/new-id-cross-doc.ts b/blocksuite/affine/widgets/drag-handle/src/middleware/new-id-cross-doc.ts index 0bebf4b0d0..07d30e39eb 100644 --- a/blocksuite/affine/widgets/drag-handle/src/middleware/new-id-cross-doc.ts +++ b/blocksuite/affine/widgets/drag-handle/src/middleware/new-id-cross-doc.ts @@ -9,36 +9,45 @@ export const newIdCrossDoc = let samePage = false; const oldToNewIdMap = new Map(); - slots.beforeImport.subscribe(payload => { - if (payload.type === 'slice') { - samePage = payload.snapshot.pageId === std.store.id; + const beforeImportSliceSubscription = slots.beforeImport.subscribe( + payload => { + if (payload.type === 'slice') { + samePage = payload.snapshot.pageId === std.store.id; + } + if (payload.type === 'block' && !samePage) { + const newId = std.workspace.idGenerator(); + + oldToNewIdMap.set(payload.snapshot.id, newId); + payload.snapshot.id = newId; + } } - if (payload.type === 'block' && !samePage) { - const newId = std.workspace.idGenerator(); + ); - oldToNewIdMap.set(payload.snapshot.id, newId); - payload.snapshot.id = newId; + const afterImportBlockSubscription = slots.afterImport.subscribe( + payload => { + if ( + !samePage && + payload.type === 'block' && + matchModels(payload.model, [DatabaseBlockModel]) + ) { + const originalCells = payload.model.props.cells; + const newCells = { + ...originalCells, + }; + + Object.keys(originalCells).forEach(cellId => { + if (oldToNewIdMap.has(cellId)) { + newCells[oldToNewIdMap.get(cellId)!] = originalCells[cellId]; + } + }); + + payload.model.props.cells$.value = newCells; + } } - }); + ); - slots.afterImport.subscribe(payload => { - if ( - !samePage && - payload.type === 'block' && - matchModels(payload.model, [DatabaseBlockModel]) - ) { - const originalCells = payload.model.props.cells; - const newCells = { - ...originalCells, - }; - - Object.keys(originalCells).forEach(cellId => { - if (oldToNewIdMap.has(cellId)) { - newCells[oldToNewIdMap.get(cellId)!] = originalCells[cellId]; - } - }); - - payload.model.props.cells$.value = newCells; - } - }); + return () => { + beforeImportSliceSubscription.unsubscribe(); + afterImportBlockSubscription.unsubscribe(); + }; }; diff --git a/blocksuite/affine/widgets/drag-handle/src/middleware/reorder-list.ts b/blocksuite/affine/widgets/drag-handle/src/middleware/reorder-list.ts index 7a8406bea3..476d97fe22 100644 --- a/blocksuite/affine/widgets/drag-handle/src/middleware/reorder-list.ts +++ b/blocksuite/affine/widgets/drag-handle/src/middleware/reorder-list.ts @@ -7,19 +7,25 @@ import type { TransformerMiddleware } from '@blocksuite/store'; export const reorderList = (std: BlockStdScope): TransformerMiddleware => ({ slots }) => { - slots.afterImport.subscribe(payload => { - if (payload.type === 'block') { - const model = payload.model; - if ( - matchModels(model, [ListBlockModel]) && - model.props.type === 'numbered' - ) { - const next = std.store.getNext(model); - correctNumberedListsOrderToPrev(std.store, model); - if (next) { - correctNumberedListsOrderToPrev(std.store, next); + const afterImportBlockSubscription = slots.afterImport.subscribe( + payload => { + if (payload.type === 'block') { + const model = payload.model; + if ( + matchModels(model, [ListBlockModel]) && + model.props.type === 'numbered' + ) { + const next = std.store.getNext(model); + correctNumberedListsOrderToPrev(std.store, model); + if (next) { + correctNumberedListsOrderToPrev(std.store, next); + } } } } - }); + ); + + return () => { + afterImportBlockSubscription.unsubscribe(); + }; }; diff --git a/blocksuite/framework/store/src/transformer/middleware.ts b/blocksuite/framework/store/src/transformer/middleware.ts index 5fbf6006c9..855ffd9891 100644 --- a/blocksuite/framework/store/src/transformer/middleware.ts +++ b/blocksuite/framework/store/src/transformer/middleware.ts @@ -113,6 +113,8 @@ type TransformerMiddlewareOptions = { transformerConfigs: Map; }; +type TransformerMiddlewareCleanup = () => void; + export type TransformerMiddleware = ( options: TransformerMiddlewareOptions -) => void; +) => void | TransformerMiddlewareCleanup; diff --git a/blocksuite/framework/store/src/transformer/transformer.ts b/blocksuite/framework/store/src/transformer/transformer.ts index 939f2bc7fb..54cefa6e2b 100644 --- a/blocksuite/framework/store/src/transformer/transformer.ts +++ b/blocksuite/framework/store/src/transformer/transformer.ts @@ -1,3 +1,4 @@ +import { DisposableGroup } from '@blocksuite/global/disposable'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { nextTick } from '@blocksuite/global/utils'; import { Subject } from 'rxjs'; @@ -67,6 +68,8 @@ export class Transformer { private readonly _docCRUD: DocCRUD; + private readonly _disposables: DisposableGroup = new DisposableGroup(); + private readonly _slots: TransformerSlots = { beforeImport: new Subject(), afterImport: new Subject(), @@ -366,13 +369,16 @@ export class Transformer { this._docCRUD = docCRUD; middlewares.forEach(middleware => { - middleware({ + const cleanup = middleware({ slots: this._slots, docCRUD: this._docCRUD, assetsManager: this._assetsManager, adapterConfigs: this._adapterConfigs, transformerConfigs: this._transformerConfigs, }); + if (cleanup) { + this._disposables.add(cleanup); + } }); } @@ -646,4 +652,9 @@ export class Transformer { reset() { this._assetsManager.cleanup(); } + + [Symbol.dispose]() { + this._disposables.dispose(); + this._assetsManager.cleanup(); + } }