import { oneLineTrim } from 'common-tags'; import { DOMParser } from 'prosemirror-model'; import { chainCommands, deleteSelection, joinBackward, selectNodeBackward, } from 'prosemirror-commands'; import WysiwygEditor from '@/wysiwyg/wwEditor'; import EventEmitter from '@/event/eventEmitter'; import { WwToDOMAdaptor } from '@/wysiwyg/adaptor/wwToDOMAdaptor'; import CellSelection from '@/wysiwyg/plugins/selection/cellSelection'; import { cls } from '@/utils/dom'; const CELL_SELECTION_CLS = cls('cell-selected'); const CODE_BLOCK_CLS = cls('ww-code-block'); describe('keymap', () => { let wwe: WysiwygEditor, em: EventEmitter; let html; function setContent(content: string) { const wrapper = document.createElement('div'); wrapper.innerHTML = content; const nodes = DOMParser.fromSchema(wwe.schema).parse(wrapper); wwe.setModel(nodes); } function forceKeymapFn(type: string, methodName: string, args: any[] = []) { const { specs, view } = wwe; // @ts-ignore const [keymapFn] = specs.specs.filter((spec) => spec.name === type); // @ts-ignore keymapFn[methodName](...args)(view.state, view.dispatch); } function selectCells(from: number, to: number) { const { state, dispatch } = wwe.view; const { doc, tr } = state; const startCellPos = doc.resolve(from); const endCellPos = doc.resolve(to); const selection = new CellSelection(startCellPos, endCellPos); dispatch!(tr.setSelection(selection)); } beforeEach(() => { const toDOMAdaptor = new WwToDOMAdaptor({}, {}); em = new EventEmitter(); wwe = new WysiwygEditor(em, { toDOMAdaptor }); }); afterEach(() => { wwe.destroy(); }); describe('table', () => { beforeEach(() => { html = oneLineTrim`

foo

bar

baz

qux

`; setContent(html); }); describe('moveToCell keymap with right (tab key)', () => { it('should move to start of right cell', () => { wwe.setSelection(7, 7); // in 'foo' cell forceKeymapFn('table', 'moveToCell', ['right']); expect(wwe.getSelection()).toEqual([12, 12]); }); it('should move to first cell of next line', () => { wwe.setSelection(13, 13); // in 'bar' cell forceKeymapFn('table', 'moveToCell', ['right']); expect(wwe.getSelection()).toEqual([23, 23]); }); }); describe('moveToCell keymap with left (shift + tab key)', () => { it('should move to end of left cell', () => { wwe.setSelection(13, 13); // in 'bar' cell forceKeymapFn('table', 'moveToCell', ['left']); expect(wwe.getSelection()).toEqual([8, 8]); }); it('should move to last cell of previous line', () => { wwe.setSelection(24, 24); // in 'baz' cell forceKeymapFn('table', 'moveToCell', ['left']); expect(wwe.getSelection()).toEqual([15, 15]); }); }); describe('moveInCell keymap with up', () => { it('should move to end of up cell', () => { wwe.setSelection(26, 26); // in 'baz' cell forceKeymapFn('table', 'moveInCell', ['up']); expect(wwe.getSelection()).toEqual([8, 8]); }); it('should add paragraph when there is no content before table and cursor is in first row', () => { wwe.setSelection(13, 13); // in 'bar' cell forceKeymapFn('table', 'moveInCell', ['up']); const expected = oneLineTrim`


foo

bar

baz

qux

`; expect(wwe.getHTML()).toBe(expected); }); it('should move to before table content when cursor is in first row', () => { html = oneLineTrim`

before

foo

bar

baz

qux

`; setContent(html); wwe.setSelection(15, 15); // in 'foo' cell forceKeymapFn('table', 'moveInCell', ['up']); expect(wwe.getSelection()).toEqual([7, 7]); // 'before' paragraph }); }); describe('moveInCell keymap with down', () => { it('should move to start of down cell', () => { wwe.setSelection(7, 7); // in 'foo' cell forceKeymapFn('table', 'moveInCell', ['down']); expect(wwe.getSelection()).toEqual([23, 23]); }); it('should add paragraph when there is no content after table and cursor is in last row', () => { wwe.setSelection(26, 26); // in 'baz' cell forceKeymapFn('table', 'moveInCell', ['down']); const expected = oneLineTrim`

foo

bar

baz

qux


`; expect(wwe.getHTML()).toBe(expected); }); it('should move to after table content when cursor is in last row', () => { html = oneLineTrim`

foo

bar

baz

qux

after

`; setContent(html); wwe.setSelection(32, 32); // in 'qux' cell forceKeymapFn('table', 'moveInCell', ['down']); expect(wwe.getSelection()).toEqual([39, 39]); // 'after' paragraph }); }); describe('moveInCell keymap with left and right', () => { let expected: string; beforeEach(() => { expected = oneLineTrim`

foo

bar

baz

qux

`; }); it('should select table when cursor is in start of first cell', () => { wwe.setSelection(5, 5); // in 'foo' cell forceKeymapFn('table', 'moveInCell', ['left']); expect(wwe.getHTML()).toBe(expected); }); it('should select table when cursor is in end of last cell', () => { wwe.setSelection(33, 33); // in 'qux' cell forceKeymapFn('table', 'moveInCell', ['right']); expect(wwe.getHTML()).toBe(expected); }); }); it('deleteCells keymap should delete cells in selection', () => { selectCells(3, 28); forceKeymapFn('table', 'deleteCells'); const expected = oneLineTrim`





`; expect(wwe.getHTML()).toBe(expected); }); describe('exitTable keymap', () => { it('should exit the table node and add paragraph', () => { wwe.setSelection(5, 5); // in 'foo' cell forceKeymapFn('table', 'exitTable'); const expected = oneLineTrim`

foo

bar

baz

qux


`; expect(wwe.getHTML()).toBe(expected); expect(wwe.getSelection()).toEqual([39, 39]); // in added paragraph }); }); }); describe('table with list and multiple lines', () => { beforeEach(() => { html = oneLineTrim`

foo

bar

  • baz

  • qux

  • quux

    • quuz

corge

`; setContent(html); }); describe('moveInCell keymap with up', () => { it('should move from first paragraph to end list item of up cell', () => { wwe.setSelection(65, 65); // in 'corge' cell forceKeymapFn('table', 'moveInCell', ['up']); expect(wwe.getSelection()).toEqual([55, 55]); // in 'quux' }); it('should move from first list item to end list item of up cell', () => { wwe.setSelection(44, 44); // in 'quux' cell forceKeymapFn('table', 'moveInCell', ['up']); expect(wwe.getSelection()).toEqual([33, 33]); // in 'qux' }); }); describe('moveInCell keymap with down', () => { it('should move from last paragraph to start list item of down cell', () => { wwe.setSelection(10, 10); // in 'bar' forceKeymapFn('table', 'moveInCell', ['down']); expect(wwe.getSelection()).toEqual([23, 23]); // in 'baz' }); it('should move from last list item to start list item of down cell', () => { wwe.setSelection(30, 30); // in 'qux' forceKeymapFn('table', 'moveInCell', ['down']); expect(wwe.getSelection()).toEqual([43, 43]); // in 'quux' }); }); }); describe('code block', () => { beforeEach(() => { html = oneLineTrim`
            foo\nbar\nbaz
          
`; setContent(html); }); describe('moveCursor keymap with up', () => { it('should add paragraph when there is no content before code block and cursor is in first line', () => { wwe.setSelection(4, 4); // in 'foo' text forceKeymapFn('codeBlock', 'moveCursor', ['up']); const expected = oneLineTrim`


              foo\nbar\nbaz
            
`; expect(wwe.getHTML()).toBe(expected); }); }); describe('moveCursor keymap with down', () => { it('should add paragraph when there is no content after code block and cursor is in last line', () => { wwe.setSelection(10, 10); // in 'baz' text forceKeymapFn('codeBlock', 'moveCursor', ['down']); const expected = oneLineTrim`
              foo\nbar\nbaz
            


`; expect(wwe.getHTML()).toBe(expected); }); }); }); describe('list item', () => { function forceBackspaceKeymap() { const { view } = wwe; const { state, dispatch } = view; chainCommands(deleteSelection, joinBackward, selectNodeBackward)(state, dispatch, view); } it('should remove list item and lift up to previous list item by backspace keymap ', () => { html = oneLineTrim` `; setContent(html); wwe.setSelection(9, 10); // in second list item forceBackspaceKeymap(); forceKeymapFn('listItem', 'liftToPrevListItem'); const expected = oneLineTrim` `; expect(wwe.getHTML()).toBe(expected); }); it('should remove list item and lift up to parent list item by backspace keymap ', () => { html = oneLineTrim` `; setContent(html); wwe.setSelection(19, 20); // in nested last child list item forceBackspaceKeymap(); forceKeymapFn('listItem', 'liftToPrevListItem'); const expected = oneLineTrim` `; expect(wwe.getHTML()).toBe(expected); }); }); });