import { Assertions } from '@ephox/agar'; import { describe, it } from '@ephox/bedrock-client'; import { Fun, Optional } from '@ephox/katamari'; import { Hierarchy, Remove, SimRange, SimSelection, SugarElement, Traverse, WindowSelection } from '@ephox/sugar'; import { assert } from 'chai'; import * as SelectionBookmark from 'tinymce/core/selection/SelectionBookmark'; import * as ViewBlock from '../../module/test/ViewBlock'; describe('browser.tinymce.core.selection.SelectionBookmarkTest', () => { const viewBlock = ViewBlock.bddSetup(); const setHtml = viewBlock.update; const setSelection = (startPath: number[], soffset: number, finishPath: number[], foffset: number) => { const sc = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), startPath).getOrDie('invalid startPath'); const fc = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), finishPath).getOrDie('invalid finishPath'); const win = Traverse.defaultView(sc); WindowSelection.setExact(win.dom, sc, soffset, fc, foffset); }; const getBookmark = (rootPath: number[]) => { const root = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), rootPath).getOrDie(); return SelectionBookmark.getBookmark(root); }; const validateBookmark = (bookmark: Optional, rootPath: number[]) => { const root = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), rootPath).getOrDie(); return bookmark.bind((b) => SelectionBookmark.validate(root, b)); }; const assertNone = (x: Optional) => { assert.isTrue(x.isNone(), 'should be none'); }; const assertSome = (x: Optional) => { assert.isTrue(x.isSome(), 'should be some'); }; const assertSelection = (startPath: number[], startOffset: number, finishPath: number[], finishOffset: number) => { const sc = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), startPath).getOrDie(); const fc = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), finishPath).getOrDie(); const win = Traverse.defaultView(SugarElement.fromDom(viewBlock.get())); const sel = WindowSelection.getExact(win.dom).getOrDie('no selection'); Assertions.assertDomEq('sc', sc, sel.start); assert.equal(sel.soffset, startOffset, 'soffset'); Assertions.assertDomEq('fc', fc, sel.finish); assert.equal(sel.foffset, finishOffset, 'foffset'); }; const manipulateBookmarkOffsets = (bookmark: Optional, startPad: number, finishPad: number) => { return bookmark.map((bm) => { return SimSelection.range(bm.start, bm.soffset + startPad, bm.finish, bm.foffset + finishPad); }); }; const deleteElement = (path: number[]) => { Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), path).each(Remove.remove); }; const assertBookmark = (bookmark: Optional, startPath: number[], startOffset: number, finishPath: number[], finishOffset: number) => { const sc = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), startPath).getOrDie(); const fc = Hierarchy.follow(SugarElement.fromDom(viewBlock.get()), finishPath).getOrDie(); const bookmarkRng = bookmark.getOrDie('no bookmark!'); Assertions.assertDomEq('sc', sc, bookmarkRng.start); assert.equal(bookmarkRng.soffset, startOffset, 'soffset'); Assertions.assertDomEq('fc', fc, bookmarkRng.finish); assert.equal(bookmarkRng.foffset, finishOffset, 'foffset'); }; const setSelectionFromBookmark = (bookmark: Optional) => { bookmark.each((b) => { const root = SugarElement.fromDom(viewBlock.get()); const win = Traverse.defaultView(root); SelectionBookmark.validate(root, b) .each((rng) => { WindowSelection.setExact(win.dom, rng.start, rng.soffset, rng.finish, rng.foffset); }); }); }; it('attached element returns some', () => { setHtml('hello'); setSelection([ 0 ], 0, [ 0 ], 1); const bookmark = getBookmark([]); assertSome(bookmark); setSelectionFromBookmark(bookmark); assertSelection([ 0 ], 0, [ 0 ], 1); }); it('foffset too big', () => { setHtml('hello'); setSelection([ 0 ], 0, [ 0 ], 3); const bookmark = getBookmark([]); const newBookmark = manipulateBookmarkOffsets(bookmark, 0, 10); setSelectionFromBookmark(newBookmark); assertSelection([ 0 ], 0, [ 0 ], 5); }); it('soffset too small', () => { setHtml('hello'); setSelection([ 0 ], 0, [ 0 ], 3); const bookmark = getBookmark([]); const newBookmark = manipulateBookmarkOffsets(bookmark, -2, 5); setSelectionFromBookmark(newBookmark); assertSelection([ 0 ], 0, [ 0 ], 5); }); it('both offsets too small', () => { setHtml('hello'); setSelection([ 0 ], 0, [ 0 ], 3); const bookmark = getBookmark([]); const newBookmark = manipulateBookmarkOffsets(bookmark, -2, -5); setSelectionFromBookmark(newBookmark); assertSelection([ 0 ], 0, [ 0 ], 0); }); it('both offsets too big', () => { setHtml('hello'); setSelection([ 0 ], 0, [ 0 ], 3); const bookmark = getBookmark([]); const newBookmark = manipulateBookmarkOffsets(bookmark, 6, 6); setSelectionFromBookmark(newBookmark); assertSelection([ 0 ], 5, [ 0 ], 5); }); it('two p tags offsets too big', () => { setHtml('

abc

123

'); setSelection([ 0, 0 ], 0, [ 1, 0 ], 1); const bookmark = getBookmark([]); assertSome(bookmark); const newBookmark = manipulateBookmarkOffsets(bookmark, 4, 4); setSelectionFromBookmark(newBookmark); assertSelection([ 0, 0 ], 3, [ 1, 0 ], 3); }); it('two p tags, delete one and should be none', () => { setHtml('

abc

123

'); setSelection([ 0, 0 ], 0, [ 1, 0 ], 1); const bookmark = getBookmark([]); assertSome(bookmark); deleteElement([ 0 ]); const validBookmark = validateBookmark(bookmark, []); assertNone(validBookmark); }); it('three p tags, delete middle and should be none', () => { setHtml('

abc

xyz

123

'); setSelection([ 0, 0 ], 0, [ 2, 0 ], 1); const bookmark = getBookmark([]); assertSome(bookmark); deleteElement([ 1 ]); const validBookmark = validateBookmark(bookmark, []); setSelectionFromBookmark(validBookmark); assertSelection([ 0, 0 ], 0, [ 1, 0 ], 1); }); it('backwards selection should set a non-backwards bookmark, one p tag', () => { setHtml('

hello

'); setSelection([ 0, 0 ], 5, [ 0, 0 ], 0); const bookmark = getBookmark([]); assertSome(bookmark); const validBookmark = validateBookmark(bookmark, []); assertBookmark(validBookmark, [ 0, 0 ], 0, [ 0, 0 ], 5); }); it('backwards selection should set a non-backwards bookmark, two p tags', () => { setHtml('

hello

world

'); setSelection([ 1, 0 ], 3, [ 0, 0 ], 2); const bookmark = getBookmark([]); assertSome(bookmark); const validBookmark = validateBookmark(bookmark, []); assertBookmark(validBookmark, [ 0, 0 ], 2, [ 1, 0 ], 3); }); it('readRange with with win without getSelection should return Optional.none', () => { const mockWin = { getSelection: Fun.constant(null) } as Window; const rngOpt = SelectionBookmark.readRange(mockWin); assertNone(rngOpt); }); });