Skip to content

Commit

Permalink
Catch error and continue when dispose editor (#2129)
Browse files Browse the repository at this point in the history
* Cache error and continue when dispose editor

* Improve
  • Loading branch information
JiuqingSong authored Oct 6, 2023
1 parent 9b6b52b commit 565ac17
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 2 deletions.
10 changes: 9 additions & 1 deletion packages/roosterjs-editor-core/lib/editor/EditorBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,16 @@ export class EditorBase<TEditorCore extends EditorCore, TEditorOptions extends E
*/
public dispose(): void {
const core = this.getCore();

for (let i = core.plugins.length - 1; i >= 0; i--) {
core.plugins[i].dispose();
const plugin = core.plugins[i];

try {
plugin.dispose();
} catch (e) {
// Cache the error and pass it out, then keep going since dispose should always succeed
core.disposeErrorHandler?.(plugin, e as Error);
}
}

core.darkColorHandler.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const createEditorCore: CoreCreator<EditorCore, EditorOptions> = (content
getVisibleViewport,
imageSelectionBorderColor: options.imageSelectionBorderColor,
darkColorHandler: new DarkColorHandlerImpl(contentDiv, pluginState.lifecycle.getDarkColor),
disposeErrorHandler: options.disposeErrorHandler,
};

return core;
Expand Down
40 changes: 39 additions & 1 deletion packages/roosterjs-editor-core/test/editor/EditorTest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as getSelectionRange from '../../lib/coreApi/getSelectionRange';
import * as TestHelper from '../TestHelper';
import { ContentPosition, IEditor } from 'roosterjs-editor-types';
import Editor from '../../lib/editor/Editor';
import { ContentPosition, EditorPlugin, IEditor } from 'roosterjs-editor-types';

let editor: IEditor;
let testID = 'EditorTest';
Expand Down Expand Up @@ -509,3 +510,40 @@ describe('Editor getCustomData()', () => {
expect(objCount).toBe(0);
});
});

describe('Dispose with exception', () => {
it('handle exception when dispose', () => {
const errorMsg = 'Test error';
const disposeSpy1 = jasmine.createSpy('dispose1');
const disposeSpy2 = jasmine.createSpy('dispose2').and.throwError(errorMsg);
const disposeSpy3 = jasmine.createSpy('dispose3');
const handlerSpy = jasmine.createSpy('disposeErrorhandler');

const plugin1 = ({
initialize: () => {},
dispose: disposeSpy1,
} as any) as EditorPlugin;
const plugin2 = ({
initialize: () => {},
dispose: disposeSpy2,
} as any) as EditorPlugin;
const plugin3 = ({
initialize: () => {},
dispose: disposeSpy3,
} as any) as EditorPlugin;

const div = document.createElement('div');
const editor = new Editor(div, {
plugins: [plugin1, plugin2, plugin3],
disposeErrorHandler: handlerSpy,
});

editor.dispose();

expect(disposeSpy1).toHaveBeenCalledTimes(1);
expect(disposeSpy2).toHaveBeenCalledTimes(1);
expect(disposeSpy3).toHaveBeenCalledTimes(1);
expect(handlerSpy).toHaveBeenCalledTimes(1);
expect(handlerSpy).toHaveBeenCalledWith(plugin2, new Error(errorMsg));
});
});
7 changes: 7 additions & 0 deletions packages/roosterjs-editor-types/lib/interface/EditorCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ export default interface EditorCore extends PluginState {
* If keep it null, editor will still use original dataset-based dark mode solution.
*/
darkColorHandler: DarkColorHandler;

/**
* A callback to be invoked when any exception is thrown during disposing editor
* @param plugin The plugin that causes exception
* @param error The error object we got
*/
disposeErrorHandler?: (plugin: EditorPlugin, error: Error) => void;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,11 @@ export default interface EditorOptions {
* Color of the border of a selectedImage. Default color: '#DB626C'
*/
imageSelectionBorderColor?: string;

/**
* A callback to be invoked when any exception is thrown during disposing editor
* @param plugin The plugin that causes exception
* @param error The error object we got
*/
disposeErrorHandler?: (plugin: EditorPlugin, error: Error) => void;
}

0 comments on commit 565ac17

Please sign in to comment.