import { Assertions, Logger, Pipeline, NamedChain, Chain, RawAssertions } from '@ephox/agar'; import { Editor, ApiChains } from '@ephox/mcagar'; import Theme from 'tinymce/themes/modern/Theme'; import { UnitTest } from '@ephox/bedrock'; import GetBookmark from 'tinymce/core/bookmark/GetBookmark'; import { Hierarchy, Element, Remove, Html, SelectorFilter, Replication } from '@ephox/sugar'; import { Result, Arr } from '@ephox/katamari'; import { isRangeBookmark, isPathBookmark, isIdBookmark, isIndexBookmark, isStringPathBookmark } from 'tinymce/core/bookmark/BookmarkTypes'; import ResolveBookmark from 'tinymce/core/bookmark/ResolveBookmark'; UnitTest.asynctest('browser.tinymce.core.bookmark.BookmarksTest', (success, failure) => { Theme(); const cGetBookmark = (type: number, normalized: boolean) => { return NamedChain.direct('editor', Chain.mapper((editor) => GetBookmark.getBookmark(editor.selection, type, normalized)), 'bookmark'); }; const cGetFilledPersistentBookmark = (type: number, normalized: boolean) => { return NamedChain.direct('editor', Chain.mapper((editor) => GetBookmark.getPersistentBookmark(editor.selection, true)), 'bookmark'); }; const assertRawRange = function (element, rng, startPath, startOffset, endPath, endOffset) { const startContainer = Hierarchy.follow(element, startPath).getOrDie(); const endContainer = Hierarchy.follow(element, endPath).getOrDie(); Assertions.assertDomEq('Should be expected start container', startContainer, Element.fromDom(rng.startContainer)); Assertions.assertEq('Should be expected start offset', startOffset, rng.startOffset); Assertions.assertDomEq('Should be expected end container', endContainer, Element.fromDom(rng.endContainer)); Assertions.assertEq('Should be expected end offset', endOffset, rng.endOffset); }; const cBundleOp = (f) => { return NamedChain.bundle((input) => { f(input); return Result.value(input); }); }; const cCreateNamedEditor = NamedChain.write('editor', Editor.cFromSettings({ skin_url: '/project/js/tinymce/skins/lightgray' })); const cSetupEditor = (content, startPath, startOffset, endPath, endOffset) => { return NamedChain.read('editor', Chain.fromChains([ ApiChains.cSetContent(content), ApiChains.cSetSelection(startPath, startOffset, endPath, endOffset) ])); }; const cRemoveEditor = NamedChain.read('editor', Editor.cRemove); const cSetCursor = (path, offset) => NamedChain.read('editor', ApiChains.cSetCursor(path, offset)); const cResolveBookmark = cBundleOp((input) => { const rng = ResolveBookmark.resolve(input.editor.selection, input.bookmark).getOrDie('Should be resolved'); input.editor.selection.setRng(rng); }); const cAssertSelection = (spath, soffset, fpath, foffset) => NamedChain.read('editor', ApiChains.cAssertSelection(spath, soffset, fpath, foffset)); const sBookmarkTest = (namedChains) => { return Chain.asStep({}, [ NamedChain.asChain(Arr.flatten([ [ cCreateNamedEditor ], namedChains, [ cRemoveEditor ] ]) )]); }; const cAssertRangeBookmark = (spath, soffset, fpath, foffset) => cBundleOp((input) => { RawAssertions.assertEq('Should be a range bookmark', true, isRangeBookmark(input.bookmark)); assertRawRange(Element.fromDom(input.editor.getBody()), input.bookmark.rng, spath, soffset, fpath, foffset); }); const cAssertPathBookmark = (expectedStart, expectedEnd) => cBundleOp((input) => { RawAssertions.assertEq('Should be a path bookmark', true, isPathBookmark(input.bookmark)); RawAssertions.assertEq('Should be expected start path', expectedStart, input.bookmark.start); RawAssertions.assertEq('Should be expected end path', expectedEnd, input.bookmark.end); }); const cAssertIndexBookmark = (expectedName, expectedIndex) => cBundleOp((input) => { RawAssertions.assertEq('Should be an index bookmark', true, isIndexBookmark(input.bookmark)); RawAssertions.assertEq('Should be expected name', expectedName, input.bookmark.name); RawAssertions.assertEq('Should be expected index', expectedIndex, input.bookmark.index); }); const cAssertStringPathBookmark = (expectedStart, expectedEnd) => cBundleOp((input) => { RawAssertions.assertEq('Should be a string bookmark', true, isStringPathBookmark(input.bookmark)); RawAssertions.assertEq('Should be expected start', expectedStart, input.bookmark.start); RawAssertions.assertEq('Should be expected end', expectedEnd, input.bookmark.end); }); const cAssertIdBookmark = cBundleOp((input) => { RawAssertions.assertEq('Should be an id bookmark', true, isIdBookmark(input.bookmark)); }); const cAssertApproxRawContent = (expectedHtml) => NamedChain.read('editor', Chain.op((editor) => { const elm = Replication.deep(Element.fromDom(editor.getBody())); Arr.each(SelectorFilter.descendants(elm, '*[data-mce-bogus="all"]'), Remove.remove); const actualHtml = Html.get(elm); Assertions.assertHtmlStructure('Should expected structure', `
${expectedHtml}`, `${actualHtml}`); })); Pipeline.async({}, [ Logger.t('Range bookmark', sBookmarkTest([ cSetupEditor('a
', [0, 0], 0, [0, 0], 1), cGetBookmark(1, false), cAssertRangeBookmark([0, 0], 0, [0, 0], 1), cSetCursor([0, 0], 0), cResolveBookmark, cAssertSelection([0, 0], 0, [0, 0], 1) ])), Logger.t('Get path bookmark', sBookmarkTest([ cSetupEditor('a
', [0, 0], 0, [0, 0], 1), cGetBookmark(2, false), cAssertPathBookmark([0, 0, 0], [1, 0, 0]), cSetCursor([0, 0], 0), cResolveBookmark, cAssertSelection([0, 0], 0, [0, 0], 1) ])), Logger.t('Get id bookmark', sBookmarkTest([ cSetupEditor('a
', [0, 0], 0, [0, 0], 1), cGetBookmark(3, false), cAssertStringPathBookmark('p[0]/text()[0],0', 'p[0]/text()[0],1'), cSetCursor([0, 0], 0), cResolveBookmark, cAssertSelection([0, 0], 0, [0, 0], 1) ])), Logger.t('Get persistent bookmark on element indexes', sBookmarkTest([ cSetupEditor('abc
', [0, 0], 1, [0, 0], 2), cGetBookmark(0, false), cAssertApproxRawContent('abc
'), cAssertSelection([0, 2], 0, [0, 2], 1), cAssertIdBookmark, cSetCursor([0, 1], 0), cResolveBookmark, cAssertApproxRawContent('abc
'), cAssertSelection([0, 0], 1, [0, 0], 2) ])), Logger.t('Get persistent bookmark marker spans on element indexes', sBookmarkTest([ cSetupEditor('', [0], 0, [0], 2), cGetBookmark(0, false), cAssertApproxRawContent(''), cAssertSelection([0], 1, [0], 3), cAssertIdBookmark, cSetCursor([0], 2), cResolveBookmark, cAssertApproxRawContent(''), cAssertSelection([0], 0, [0], 2) ])), Logger.t('Get persistent bookmark filled with marker spans on text offsets', sBookmarkTest([ cSetupEditor('
abc
', [0, 0], 1, [0, 0], 2), cGetFilledPersistentBookmark(0, true), cAssertApproxRawContent('a\ufeffb\ufeffc
'), cAssertSelection([0, 1, 0], 1, [0, 3, 0], 1), cAssertIdBookmark, cSetCursor([0, 1], 0), cResolveBookmark, cAssertApproxRawContent('abc
'), cAssertSelection([0, 0], 1, [0, 0], 2) ])), ], success, failure); });