import { describe, it } from '@ephox/bedrock-client'; import { Arr } from '@ephox/katamari'; import { LegacyUnit } from '@ephox/wrap-mcagar'; import { assert } from 'chai'; import CaretPosition from 'tinymce/core/caret/CaretPosition'; import * as CaretUtils from 'tinymce/core/caret/CaretUtils'; import * as Zwsp from 'tinymce/core/text/Zwsp'; import * as CaretAsserts from '../../module/test/CaretAsserts'; import * as ViewBlock from '../../module/test/ViewBlock'; describe('browser.tinymce.core.CaretUtilTest', () => { const assertRange = CaretAsserts.assertRange; const createRange = CaretAsserts.createRange; const viewBlock = ViewBlock.bddSetup(); const ZWSP = Zwsp.ZWSP; const getRoot = viewBlock.get; const setupHtml = (html: string) => { viewBlock.get().contentEditable = 'true'; viewBlock.update(html); // IE messes zwsp up on innerHTML so we need to first set markers then replace then using dom operations viewBlock.get().innerHTML = html.replace(new RegExp(ZWSP, 'g'), '__ZWSP__'); replaceWithZwsp(viewBlock.get()); }; const replaceWithZwsp = (node: Node) => { Arr.each(node.childNodes, (childNode) => { if (childNode.nodeType === 3) { childNode.nodeValue = (childNode as Text).data.replace(/__ZWSP__/, ZWSP); } else { replaceWithZwsp(childNode); } }); }; const findElm = (selector: string) => getRoot().querySelector(selector); it('isForwards', () => { assert.isTrue(CaretUtils.isForwards(1)); assert.isTrue(CaretUtils.isForwards(10)); assert.isFalse(CaretUtils.isForwards(0)); assert.isFalse(CaretUtils.isForwards(-1)); assert.isFalse(CaretUtils.isForwards(-10)); }); it('isBackwards', () => { assert.isFalse(CaretUtils.isBackwards(1)); assert.isFalse(CaretUtils.isBackwards(10)); assert.isFalse(CaretUtils.isBackwards(0)); assert.isTrue(CaretUtils.isBackwards(-1)); assert.isTrue(CaretUtils.isBackwards(-10)); }); it('findNode', () => { setupHtml('abc123def'); const isBold = (node: Node | null) => { return node?.nodeName === 'B'; }; const isText = (node: Node | null) => { return node?.nodeType === 3; }; LegacyUnit.equalDom(CaretUtils.findNode(getRoot(), 1, isBold, getRoot()) as Node, getRoot().firstChild as HTMLElement); LegacyUnit.equalDom(CaretUtils.findNode(getRoot(), 1, isText, getRoot()) as Node, getRoot().firstChild?.firstChild as Text); assert.isNull(CaretUtils.findNode(getRoot().childNodes[1], 1, isBold, getRoot().childNodes[1])); assert.equal(CaretUtils.findNode(getRoot().childNodes[1], 1, isText, getRoot().childNodes[1])?.nodeName, '#text'); LegacyUnit.equalDom(CaretUtils.findNode(getRoot(), -1, isBold, getRoot()) as Node, getRoot().childNodes[1]); LegacyUnit.equalDom(CaretUtils.findNode(getRoot(), -1, isText, getRoot()) as Node, getRoot().lastChild as Text); }); it('getEditingHost', () => { setupHtml(''); LegacyUnit.equalDom(CaretUtils.getEditingHost(getRoot(), getRoot()), getRoot()); LegacyUnit.equalDom(CaretUtils.getEditingHost(getRoot().firstChild as HTMLSpanElement, getRoot()), getRoot()); LegacyUnit.equalDom(CaretUtils.getEditingHost(getRoot().firstChild?.firstChild as Text, getRoot()), getRoot().firstChild as HTMLSpanElement); }); it('getParentBlock', () => { setupHtml('

abc

'); LegacyUnit.equalDom(CaretUtils.getParentBlock(findElm('p:first-of-type')) as HTMLParagraphElement, findElm('p:first-of-type') as HTMLParagraphElement); LegacyUnit.equalDom(CaretUtils.getParentBlock(findElm('td:first-of-type')?.firstChild as Text) as HTMLTableCellElement, findElm('td:first-of-type') as HTMLTableCellElement); LegacyUnit.equalDom(CaretUtils.getParentBlock(findElm('td:first-of-type')) as HTMLTableCellElement, findElm('td:first-of-type') as HTMLTableCellElement); LegacyUnit.equalDom(CaretUtils.getParentBlock(findElm('table')) as HTMLElement, findElm('table') as HTMLElement); }); it('isInSameBlock', () => { setupHtml('

abc

defghj

'); assert.isFalse(CaretUtils.isInSameBlock( CaretPosition(findElm('p:first-of-type')?.firstChild as Text, 0), CaretPosition(findElm('p:last-of-type')?.firstChild as Text, 0) )); assert.isTrue(CaretUtils.isInSameBlock( CaretPosition(findElm('p:first-of-type')?.firstChild as Text, 0), CaretPosition(findElm('p:first-of-type')?.firstChild as Text, 0) )); assert.isTrue(CaretUtils.isInSameBlock( CaretPosition(findElm('p:last-of-type')?.firstChild as Text, 0), CaretPosition(findElm('b')?.firstChild as Text, 0) )); }); it('isInSameEditingHost', () => { setupHtml( '

abc

' + 'def' + '' + 'ghi' + 'jkl' + '' ); assert.isTrue(CaretUtils.isInSameEditingHost( CaretPosition(findElm('p:first-of-type')?.firstChild as Text, 0), CaretPosition(findElm('p:first-of-type')?.firstChild as Text, 1), getRoot() )); assert.isTrue(CaretUtils.isInSameEditingHost( CaretPosition(findElm('p:first-of-type')?.firstChild as Text, 0), CaretPosition(getRoot().childNodes[1], 1), getRoot() )); assert.isTrue(CaretUtils.isInSameEditingHost( CaretPosition(findElm('span span:first-of-type')?.firstChild as Text, 0), CaretPosition(findElm('span span:first-of-type')?.firstChild as Text, 1), getRoot() )); assert.isFalse(CaretUtils.isInSameEditingHost( CaretPosition(findElm('p:first-of-type')?.firstChild as Text, 0), CaretPosition(findElm('span span:first-of-type')?.firstChild as Text, 1), getRoot() )); assert.isFalse(CaretUtils.isInSameEditingHost( CaretPosition(findElm('span span:first-of-type')?.firstChild as Text, 0), CaretPosition(findElm('span span:last-of-type')?.firstChild as Text, 1), getRoot() )); }); it('normalizeRange', () => { setupHtml( 'abc1def' ); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().firstChild as Text, 2)), createRange(getRoot().firstChild as Text, 2)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().firstChild as Text, 3)), createRange(getRoot(), 1)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().lastChild as Text, 2)), createRange(getRoot().lastChild as Text, 2)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().lastChild as Text, 0)), createRange(getRoot(), 2)); }); it('normalizeRange deep', () => { setupHtml( 'abc1def' ); assertRange( CaretUtils.normalizeRange(1, getRoot(), createRange(findElm('b')?.firstChild as Text, 2)), createRange(findElm('b')?.firstChild as Text, 2) ); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(findElm('b')?.firstChild as Text, 3)), createRange(getRoot(), 1)); assertRange( CaretUtils.normalizeRange(-1, getRoot(), createRange(findElm('i:last-of-type b')?.firstChild as Text, 1)), createRange(findElm('i:last-of-type b')?.firstChild as Text, 1) ); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(findElm('i:last-of-type b')?.firstChild as Text, 0)), createRange(getRoot(), 2)); }); it('normalizeRange break at candidate', () => { setupHtml( '

abc

1

abc

' ); assertRange( CaretUtils.normalizeRange(1, getRoot(), createRange(findElm('b')?.firstChild as Text, 3)), createRange(findElm('b')?.firstChild as Text, 3) ); assertRange( CaretUtils.normalizeRange(1, getRoot(), createRange(findElm('b:last-of-type')?.lastChild as Text, 0)), createRange(findElm('b:last-of-type')?.lastChild as Text, 0) ); }); it('normalizeRange at block caret container', () => { setupHtml( '

\u00a0

1

\u00a0

' ); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(findElm('p:first-of-type')?.firstChild as Text, 0)), createRange(getRoot(), 1)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(findElm('p:first-of-type')?.firstChild as Text, 1)), createRange(getRoot(), 1)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(findElm('p:last-of-type')?.firstChild as Text, 0)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(findElm('p:last-of-type')?.firstChild as Text, 1)), createRange(getRoot(), 2)); }); it('normalizeRange at inline caret container', () => { setupHtml( 'abc1def' ); getRoot().insertBefore(document.createTextNode(ZWSP), getRoot().childNodes[1]); getRoot().insertBefore(document.createTextNode(ZWSP), getRoot().childNodes[3]); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().firstChild as Text, 3)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().childNodes[1], 0)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().childNodes[1], 1)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().lastChild as Text, 0)), createRange(getRoot(), 3)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().childNodes[3], 0)), createRange(getRoot(), 3)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().childNodes[3], 1)), createRange(getRoot(), 3)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().firstChild as Text, 3)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().childNodes[1], 0)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().childNodes[1], 1)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().lastChild as Text, 0)), createRange(getRoot(), 3)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().childNodes[3], 0)), createRange(getRoot(), 3)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().childNodes[3], 1)), createRange(getRoot(), 3)); }); it('normalizeRange at inline caret container (combined)', () => { setupHtml( 'abc' + ZWSP + '1' + ZWSP + 'def' ); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().firstChild as Text, 3)), createRange(getRoot(), 1)); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().firstChild as Text, 4)), createRange(getRoot(), 1)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().lastChild as Text, 0)), createRange(getRoot(), 2)); assertRange(CaretUtils.normalizeRange(-1, getRoot(), createRange(getRoot().lastChild as Text, 1)), createRange(getRoot(), 2)); }); it('normalizeRange at inline caret container after block', () => { setupHtml( '

1

' + ZWSP + 'abc' ); assertRange(CaretUtils.normalizeRange(1, getRoot(), createRange(getRoot().lastChild as Text, 0)), createRange(getRoot().lastChild as Text, 0)); }); });
X