diff --git a/demo/scripts/controls/sidePane/editorOptions/ContentEditFeatures.tsx b/demo/scripts/controls/sidePane/editorOptions/ContentEditFeatures.tsx index 5b5fd35382f..a0df6e3b246 100644 --- a/demo/scripts/controls/sidePane/editorOptions/ContentEditFeatures.tsx +++ b/demo/scripts/controls/sidePane/editorOptions/ContentEditFeatures.tsx @@ -48,6 +48,7 @@ const EditFeatureDescriptionMap: Record> = { [ExperimentalFeatures.DefaultFormatInSpan]: 'When apply default format when initialize or user type, apply the format on a SPAN element.', [ExperimentalFeatures.VariableBasedDarkColor]: 'Use variable-based color for dark mode', + [ExperimentalFeatures.DeleteTableWithBackspace]: + 'Delete a table selected with the table selector pressing Backspace key', }; export default class ExperimentalFeaturesPane extends React.Component< diff --git a/packages/roosterjs-editor-plugins/lib/plugins/ContentEdit/features/tableFeatures.ts b/packages/roosterjs-editor-plugins/lib/plugins/ContentEdit/features/tableFeatures.ts index cfb8c553901..68bfd2dad1e 100644 --- a/packages/roosterjs-editor-plugins/lib/plugins/ContentEdit/features/tableFeatures.ts +++ b/packages/roosterjs-editor-plugins/lib/plugins/ContentEdit/features/tableFeatures.ts @@ -12,6 +12,7 @@ import { SelectionRangeTypes, TableSelectionRange, Indentation, + ExperimentalFeatures, } from 'roosterjs-editor-types'; import { Browser, @@ -151,6 +152,23 @@ const UpDownInTable: BuildInEditFeature = { defaultDisabled: !Browser.isChrome && !Browser.isSafari, }; +/** + * Requires @see ExperimentalFeatures.DeleteTableWithBackspace + * Delete a table selected with the table selector pressing Backspace key + */ +const DeleteTableWithBackspace: BuildInEditFeature = { + keys: [Keys.BACKSPACE], + shouldHandleEvent: (event: PluginKeyboardEvent, editor: IEditor) => + editor.isFeatureEnabled(ExperimentalFeatures.DeleteTableWithBackspace) && + cacheIsWholeTableSelected(event, editor), + handleEvent: (event, editor) => { + const td = cacheGetTableCell(event, editor); + const vtable = new VTable(td); + vtable.edit(TableOperation.DeleteTable); + vtable.writeBack(); + }, +}; + function cacheGetTableCell(event: PluginEvent, editor: IEditor): HTMLTableCellElement { return cacheGetEventData(event, 'TABLE_CELL_FOR_TABLE_FEATURES', () => { let pos = editor.getFocusedPosition(); @@ -189,4 +207,5 @@ export const TableFeatures: Record< tabInTable: TabInTable, upDownInTable: UpDownInTable, indentTableOnTab: IndentTableOnTab, + deleteTableWithBackspace: DeleteTableWithBackspace, }; diff --git a/packages/roosterjs-editor-plugins/test/ContentEdit/features/tableFeaturesTest.ts b/packages/roosterjs-editor-plugins/test/ContentEdit/features/tableFeaturesTest.ts index b3e73c65e88..e4a17460641 100644 --- a/packages/roosterjs-editor-plugins/test/ContentEdit/features/tableFeaturesTest.ts +++ b/packages/roosterjs-editor-plugins/test/ContentEdit/features/tableFeaturesTest.ts @@ -155,6 +155,7 @@ describe('TableFeature', () => { expect(!!shouldHandleEvent).toBeFalsy(); }); }); + describe('HandleEvent', () => { let setIndentationFn: jasmine.Spy; @@ -338,4 +339,48 @@ describe('TableFeature', () => { }); }); }); + + describe('deleteTable | ', () => { + const feature = TableFeatures.deleteTableWithBackspace; + + describe('ShouldHandle', () => { + it('Should not handle, is not in a table', () => { + editor.setContent(``); + editor.focus(); + editor.select(document.getElementById('TEST_ELEMENT_ID')!, 0); + const shouldHandleEvent = feature.shouldHandleEvent(keyboardEvent, editor, false); + expect(!!shouldHandleEvent).toBeFalsy(); + }); + it('Should handle, table is fully selected', () => { + editor.select(table!, { + firstCell: { x: 0, y: 0 }, + lastCell: { y: 1, x: 1 }, + }); + spyOn(editor, 'isFeatureEnabled').and.returnValue(true); + const shouldHandleEvent = feature.shouldHandleEvent(keyboardEvent, editor, false); + expect(!!shouldHandleEvent).toBeTruthy(); + }); + it('Should not handle, table is not fully selected', () => { + editor.select(table!, { + firstCell: { x: 0, y: 0 }, + lastCell: { y: 0, x: 1 }, + }); + const shouldHandleEvent = feature.shouldHandleEvent(keyboardEvent, editor, false); + expect(!!shouldHandleEvent).toBeFalsy(); + }); + }); + + describe('HandleEvent', () => { + it('Should delete table', () => { + editor.select(table!, { + firstCell: { x: 0, y: 0 }, + lastCell: { y: 1, x: 1 }, + }); + + feature.handleEvent(keyboardEvent, editor); + const deletedTable = document.getElementById('TEST_ELEMENT_ID'); + expect(deletedTable).toBe(null); + }); + }); + }); }); diff --git a/packages/roosterjs-editor-types/lib/enum/ExperimentalFeatures.ts b/packages/roosterjs-editor-types/lib/enum/ExperimentalFeatures.ts index 944dbe2dd81..5113374e215 100644 --- a/packages/roosterjs-editor-types/lib/enum/ExperimentalFeatures.ts +++ b/packages/roosterjs-editor-types/lib/enum/ExperimentalFeatures.ts @@ -133,4 +133,9 @@ export const enum ExperimentalFeatures { * if you need them work for dark mode */ VariableBasedDarkColor = 'VariableBasedDarkColor', + + /** + * Delete table with Backspace key with the whole was selected with table selector + */ + DeleteTableWithBackspace = 'DeleteTableWithBackspace', } diff --git a/packages/roosterjs-editor-types/lib/interface/ContentEditFeatureSettings.ts b/packages/roosterjs-editor-types/lib/interface/ContentEditFeatureSettings.ts index 4aa43f01db5..9f11df6273e 100644 --- a/packages/roosterjs-editor-types/lib/interface/ContentEditFeatureSettings.ts +++ b/packages/roosterjs-editor-types/lib/interface/ContentEditFeatureSettings.ts @@ -222,6 +222,12 @@ export interface TableFeatureSettings { * IndentTableOnTab edit feature, provides the ability to indent the table if it is all cells are selected. */ indentTableOnTab: boolean; + + /** + * Requires @see ExperimentalFeatures.DeleteTableWithBackspace + * Delete a table selected with the table selector pressing Backspace key + */ + deleteTableWithBackspace: boolean; } /**