import { ApproxStructure, Keys } from '@ephox/agar'; import { describe, it } from '@ephox/bedrock-client'; import { Fun } from '@ephox/katamari'; import { TinyAssertions, TinyContentActions, TinyHooks, TinySelections } from '@ephox/wrap-mcagar'; import { assert } from 'chai'; import Editor from 'tinymce/core/api/Editor'; import CaretPosition from 'tinymce/core/caret/CaretPosition'; import * as BoundaryLocation from 'tinymce/core/keyboard/BoundaryLocation'; import * as InlineUtils from 'tinymce/core/keyboard/InlineUtils'; describe('browser.tinymce.core.delete.InlineBoundaryDeleteTest', () => { const hook = TinyHooks.bddSetupLight({ base_url: '/project/tinymce/js/tinymce' }, [], true); const locationName = (location: BoundaryLocation.LocationAdt) => { return location.fold( Fun.constant('before'), Fun.constant('start'), Fun.constant('end'), Fun.constant('after') ); }; const readLocation = (editor: Editor) => { const isInlineTarget = Fun.curry(InlineUtils.isInlineTarget, editor); return BoundaryLocation .readLocation(isInlineTarget, editor.getBody(), CaretPosition.fromRangeStart(editor.selection.getRng())) .map(locationName) .getOr('none'); }; const testDeleteOrBackspaceKey = (key: number) => ( setupHtml: string, setupPath: number[], setupOffset: number, expectedHtml: string, expectedLocation: 'before' | 'start' | 'end' | 'after' | 'none', expectedPath: number[], expectedOffset: number, expectInputEvents: boolean = true ) => { const editor = hook.editor(); const inputEvents: string[] = []; const collect = (event: InputEvent) => { inputEvents.push(event.inputType); }; editor.on('input', collect); editor.setContent(setupHtml); TinySelections.setCursor(editor, setupPath, setupOffset); editor.nodeChanged(); TinyContentActions.keydown(editor, key); editor.off('input', collect); TinyAssertions.assertContent(editor, expectedHtml); assert.equal(readLocation(editor), expectedLocation, 'Should be expected location'); TinyAssertions.assertSelection(editor, expectedPath, expectedOffset, expectedPath, expectedOffset); if (expectInputEvents) { assert.deepEqual(inputEvents, [ key === Keys.backspace() ? 'deleteContentBackward' : 'deleteContentForward' ]); } normalizeBody(editor); }; const normalizeBody = (editor: Editor) => editor.getBody().normalize(); const paragraphWithText = (text: string) => ApproxStructure.build((s, str, _arr) => { return s.element('body', { children: [ s.element('p', { children: [ s.text(str.is(text)) ] }) ] }); }); const testBackspace = testDeleteOrBackspaceKey(Keys.backspace()); const testDelete = testDeleteOrBackspaceKey(Keys.delete()); it('Backspace key on text', () => { testBackspace('

abc

', [ 0, 2 ], 0, '

abc

', 'end', [ 0, 1, 0 ], 1); testBackspace('

abc

', [ 0, 1, 0 ], 0, '

abc

', 'before', [ 0, 0 ], 1); testBackspace('

abcd

', [ 0, 1, 0 ], 1, '

acd

', 'start', [ 0, 1, 0 ], 1); }); it('Backspace key on image', () => { testBackspace('

ac

', [ 0, 2 ], 0, '

ac

', 'end', [ 0, 1, 1 ], 0); testBackspace('

ac

', [ 0, 1 ], 0, '

ac

', 'before', [ 0, 0 ], 1); testBackspace('

acd

', [ 0, 1 ], 1, '

acd

', 'start', [ 0, 1, 0 ], 1); }); it('Delete key on text', () => { testDelete('

abc

', [ 0, 0 ], 1, '

abc

', 'start', [ 0, 1, 0 ], 1); testDelete('

abc

', [ 0, 1, 0 ], 1, '

abc

', 'after', [ 0, 2 ], 1); testDelete('

abcd

', [ 0, 1, 0 ], 1, '

abd

', 'end', [ 0, 1, 0 ], 1); }); it('Delete key on image', () => { testDelete('

ac

', [ 0, 0 ], 1, '

ac

', 'start', [ 0, 1, 0 ], 1); testDelete('

ac

', [ 0, 1 ], 1, '

ac

', 'after', [ 0, 2 ], 1); testDelete('

abd

', [ 0, 1, 0 ], 1, '

abd

', 'end', [ 0, 1, 0 ], 1); }); it('Backspace/delete last character', () => { const editor = hook.editor(); testDelete('

abc

', [ 0, 1, 0 ], 0, '

ac

', 'none', [ 0, 0 ], 1); testDelete('

b

', [ 0, 1, 0 ], 0, '

', 'none', [ 0 ], 1); testDelete('

abc

', [ 0, 1, 0 ], 0, '

ac

', 'none', [ 0, 0 ], 1); TinyAssertions.assertContentStructure(editor, paragraphWithText('ac')); testBackspace('

abc

', [ 0, 1, 0 ], 1, '

ac

', 'none', [ 0, 0 ], 1); TinyAssertions.assertContentStructure(editor, paragraphWithText('ac')); testDelete('

ac

', [ 0, 1 ], 0, '

ac

', 'none', [ 0, 0 ], 1); testBackspace('

ac

', [ 0, 1 ], 1, '

ac

', 'none', [ 0, 0 ], 1); }); it('Backspace/delete between blocks', () => { testBackspace('

a

b

', [ 1 ], 0, '

ab

', 'end', [ 0, 0, 0 ], 1); testDelete('

a

b

', [ 0 ], 1, '

ab

', 'end', [ 0, 0, 0 ], 1); }); it('Backspace key inline_boundaries: false', () => { const editor = hook.editor(); editor.options.set('inline_boundaries', false); testBackspace('

abc

', [ 0, 2 ], 0, '

abc

', 'after', [ 0, 2 ], 0, false); editor.options.unset('inline_boundaries'); }); });