import { ApproxStructure, Keys } from '@ephox/agar'; import { context, describe, it } from '@ephox/bedrock-client'; import { Arr } from '@ephox/katamari'; import { TinyAssertions, TinyContentActions, TinyHooks, TinySelections } from '@ephox/wrap-mcagar'; import Editor from 'tinymce/core/api/Editor'; const applyForDeleteAndBackspace = (fn: (pair: { label: string; key: () => number }) => void) => Arr.each([ { label: 'Delete', key: Keys.delete }, { label: 'Backspace', key: Keys.backspace } ], fn); describe('browser.tinymce.core.delete.CefDeleteTest', () => { const hook = TinyHooks.bddSetupLight({ base_url: '/project/tinymce/js/tinymce' }, [], true); const fakeBackspaceKeyOnRange = (editor: Editor) => { editor.getDoc().execCommand('Delete'); TinyContentActions.keyup(editor, Keys.backspace()); }; it('Should padd empty ce=true inside ce=false when everything is deleted', () => { const editor = hook.editor(); editor.setContent('
a

a

b
'); TinySelections.setSelection(editor, [ 1, 1, 0 ], 0, [ 1, 1, 0 ], 1); fakeBackspaceKeyOnRange(editor); TinyAssertions.assertContentStructure(editor, ApproxStructure.build((s, str, _arr) => { return s.element('body', { children: [ s.element('div', { children: [ s.text(str.is('a')), s.element('p', { children: [ s.element('br', { attrs: { 'data-mce-bogus': str.is('1') } }) ] }), s.text(str.is('b')) ] }) ] }); }) ); }); it('Should not padd an non empty ce=true inside ce=false', () => { const editor = hook.editor(); editor.setContent('
a

ab

b
'); TinySelections.setSelection(editor, [ 1, 1, 0 ], 0, [ 1, 1, 0 ], 1); fakeBackspaceKeyOnRange(editor); TinyAssertions.assertContentStructure(editor, ApproxStructure.build((s, str, _arr) => { return s.element('body', { children: [ s.element('div', { children: [ s.text(str.is('a')), s.element('p', { children: [ s.text(str.is('b')) ] }), s.text(str.is('b')) ] }) ] }); }) ); }); it('Should padd editor with paragraph and br if the editor is empty after delete of a cef element', () => { const editor = hook.editor(); editor.setContent('
a
'); TinySelections.setSelection(editor, [], 1, [], 2); TinyContentActions.keystroke(editor, Keys.backspace()); TinyAssertions.assertSelection(editor, [ 0 ], 0, [ 0 ], 0); TinyAssertions.assertContentStructure(editor, ApproxStructure.build((s, str, _arr) => { return s.element('body', { children: [ s.element('p', { children: [ s.element('br', { attrs: { 'data-mce-bogus': str.is('1') } }) ] }) ] }); }) ); }); it('Should padd editor with empty paragraph if we delete last element', () => { const editor = hook.editor(); editor.setContent('
a
'); TinySelections.setSelection(editor, [], 2, [], 2); TinyContentActions.keystroke(editor, Keys.backspace()); TinyAssertions.assertSelection(editor, [ 0 ], 0, [ 0 ], 0); TinyAssertions.assertContentStructure(editor, ApproxStructure.build((s, str, _arr) => { return s.element('body', { children: [ s.element('p', { children: [ s.element('br', { attrs: { 'data-mce-bogus': str.is('1') } }) ] }) ] }); }) ); }); it('Should remove fake caret if we delete block cef', () => { const editor = hook.editor(); editor.setContent('
a

b

'); TinySelections.setSelection(editor, [], 2, [], 2); TinyContentActions.keystroke(editor, Keys.backspace()); TinyAssertions.assertSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 0); TinyAssertions.assertContentStructure(editor, ApproxStructure.build((s, str, _arr) => { return s.element('body', { children: [ s.element('p', { children: [ s.text(str.is('b')) ] }) ] }); }) ); }); context('cef block is at the start/end of the content and covered with the selection', () => { applyForDeleteAndBackspace(({ label, key }) => { it(`TINY-8729: should delete selected content when cef block is at the start and ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

CEF

abc

'); // actual content:

CEF

abc

TinySelections.setSelection(editor, [ 0 ], 0, [ 2, 0 ], 2); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertCursor(editor, [ 0, 0 ], 0); TinyAssertions.assertContent(editor, '

c

'); }); it(`TINY-8729: should delete selected content when cef block is at the end and ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

abc

CEF

'); TinySelections.setSelection(editor, [ 0, 0 ], 1, [], 2); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertCursor(editor, [ 0, 0 ], 1); TinyAssertions.assertContent(editor, '

a

'); }); it(`TINY-8729: should delete selected content when cef block is at the start and at the end after ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

CEF

abc

CEF

'); // actual content:

CEF

abc

CEF

TinySelections.setSelection(editor, [ 0 ], 0, [], 4); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertContent(editor, ''); }); }); }); context('inline cef is at the start/end of the content and covered with the selection', () => { applyForDeleteAndBackspace(({ label, key }) => { it(`TINY-8729: should delete selected content when inline cef is at the start and ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

CEFabc

'); // actual content:

CEFabc

TinySelections.setSelection(editor, [ 0 ], 0, [ 0, 2 ], 2); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertCursor(editor, [ 0 ], 0); TinyAssertions.assertContent(editor, '

c

'); }); it(`TINY-8729: should delete selected content when inline cef is at the end and ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

abcCEF

'); // actual content:

CEFabc

TinySelections.setSelection(editor, [ 0, 0 ], 1, [ 0 ], 2); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertCursor(editor, [ 0 ], 1); TinyAssertions.assertContent(editor, '

a

'); }); it(`TINY-8729: should delete selected content when inline cef is at the start and at the end after ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

CEFabcCEF

'); // actual content:

CEFabcCEF

TinySelections.setSelection(editor, [ 0 ], 0, [ 0 ], 4); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertCursor(editor, [ 0 ], 0); TinyAssertions.assertContent(editor, ''); }); }); }); context('Cleaning up after rng.deleteContents call', () => { applyForDeleteAndBackspace(({ label, key }) => { it(`TINY-8729: should clean up empty nodes and padd empty block with bogus br when ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

Welcome

CEF

'); TinySelections.setSelection(editor, [ 0, 0, 0 ], 0, [ ], 2); TinyContentActions.keystroke(editor, key()); // it should remove empty

nodes TinyAssertions.assertRawContent(editor, '


'); TinyAssertions.assertCursor(editor, [ 0 ], 0); }); it(`TINY-8729: should delete selected content and padd empty list item with bogus br when ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent(''); // actual content: TinySelections.setSelection(editor, [ 0, 0, 0 ], 0, [ 0, 0 ], 2); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertRawContent(editor, ''); TinyAssertions.assertCursor(editor, [ 0, 0 ], 0); }); it(`TINY-8877: should delete when all content is selected and add back the forced root block when ${label} is pressed`, () => { const editor = hook.editor(); editor.setContent('

CEF

Second line

CEF

'); editor.execCommand('SelectAll'); TinyContentActions.keystroke(editor, key()); TinyAssertions.assertRawContent(editor, '


'); TinyAssertions.assertCursor(editor, [ 0 ], 0); }); }); }); });