import { context, describe, it } from '@ephox/bedrock-client'; import { Arr } from '@ephox/katamari'; import { Hierarchy, Html, Insert, Remove, SugarBody, SugarElement, SugarNode } from '@ephox/sugar'; import { assert } from 'chai'; import AstNode from 'tinymce/core/api/html/Node'; import Schema from 'tinymce/core/api/html/Schema'; import * as TransparentElements from 'tinymce/core/content/TransparentElements'; describe('browser.tinymce.core.content.TransparentElementsTest', () => { const schema = Schema(); const transparentElements = TransparentElements.elementNames(schema.getTransparentElements()); const textBlockElements = TransparentElements.elementNames(schema.getTextBlockElements()); it('TINY-9172: makeElementList', () => { assert.deepEqual(TransparentElements.elementNames({ a: {}, h1: {}, A: {}, H1: {}}), [ 'a', 'h1' ]); }); it('TINY-9230: hasBlockAttr', () => { assert.isTrue(TransparentElements.hasBlockAttr(SugarElement.fromHtml('').dom)); assert.isFalse(TransparentElements.hasBlockAttr(SugarElement.fromHtml('').dom)); }); context('updateChildren/updateCaret', () => { const withScratchDiv = (html: string, f: (el: SugarElement) => void) => { const root = SugarElement.fromTag('div'); Html.set(root, html); Insert.append(SugarBody.body(), root); f(root); Remove.remove(root); }; const testUpdateChildren = (testCase: { input: string; expected: string }) => { withScratchDiv(testCase.input, (root) => { TransparentElements.updateChildren(schema, root.dom); assert.equal(Html.get(root), testCase.expected); }); }; const testUpdateCaret = (testCase: { input: string; path: number[]; expected: string }) => { withScratchDiv(testCase.input, (root) => { const scope = Hierarchy.follow(root, testCase.path).filter(SugarNode.isElement).getOrDie(); TransparentElements.updateCaret(schema, root.dom, scope.dom); assert.equal(Html.get(root), testCase.expected); }); }; it('TINY-9172: Should add data-mce-block on transparent elements if the contain blocks', () => { const blockLinks = Arr.map(textBlockElements, (name) => `<${name}>link`).join(''); const expectedBlockLinks = Arr.map(textBlockElements, (name) => `<${name}>link`).join(''); testUpdateChildren({ input: `link
${blockLinks}
${blockLinks}
link
`, expected: `link
${expectedBlockLinks}
${expectedBlockLinks}
link
` }); }); it('TINY-9231: Should unwrap invalid children', () => { withScratchDiv('', (root) => { const anchor = SugarElement.fromHtml(''); Html.set(anchor, '

link

'); Insert.append(root, anchor); assert.equal(Html.get(root), '

link

', 'Check that the setup worked'); TransparentElements.updateChildren(schema, root.dom); assert.equal(Html.get(root), '

link

', 'Should unwrap the inner anchor'); }); }); it('TINY-9172: Should add data-mce-block on transparent block elements that wrap blocks and also remove data-mce-selected="inline-boundary"', () => testUpdateChildren({ input: '

link

', expected: '

link

' })); it('TINY-9232: Should split the H1 at the P element and remove any empty nodes that gets produced', () => testUpdateChildren({ input: '

link

', expected: '

link

' })); it('TINY-9232: Should split the H1 at the P element and keep the contents that is around the paragraph', () => testUpdateChildren({ input: '

a

b

c

', expected: '

a

b

c

' })); it('TINY-9232: Should split the H1 and the P element but not split the parent div element', () => testUpdateChildren({ input: '

a

b

c

', expected: '

a

b

c

' })); it('TINY-9172: Should update all anchors in element closest to the root only', () => testUpdateCaret({ input: '

link

link

not this

not this

', path: [ 0, 0, 0 ], expected: '

link

link

not this

not this

' })); it('TINY-9172: Should update anchor closest to root', () => testUpdateCaret({ input: '

link

', path: [ 0 ], expected: '

link

' })); it('TINY-9172: Should update anchor even if target element is in another branch', () => testUpdateCaret({ input: '

link

target
', path: [ 0, 1, 0 ], expected: '

link

target
' })); it('TINY-9172: Split the H1 at the P point within the DIV but ignore the other P not in the caret scope', () => testUpdateCaret({ input: '

link

link

', path: [ 0, 0, 0, 0 ], expected: '

link

link

' })); }); context('isTransparentElementName', () => { it('TINY-9172: Should return true for any transparent element name', () => { Arr.each(transparentElements, (name) => { assert.isTrue(TransparentElements.isTransparentElementName(schema, name)); }); }); it('TINY-9172: Should return false for any non transparent element names', () => { assert.isFalse(TransparentElements.isTransparentElementName(schema, 'p')); assert.isFalse(TransparentElements.isTransparentElementName(schema, 'span')); }); }); context('isTransparentBlock', () => { it('TINY-9172: Should return true for any transparent element with data-mce-block', () => { Arr.each(transparentElements, (name) => { const elm = document.createElement(name); elm.setAttribute('data-mce-block', 'true'); assert.isTrue(TransparentElements.isTransparentBlock(schema, elm)); }); }); it('TINY-9172: Should return false for any transparent element without data-mce-block', () => { Arr.each(transparentElements, (name) => { assert.isFalse(TransparentElements.isTransparentBlock(schema, document.createElement(name))); }); }); it('TINY-9172: Should return false for any non element', () => { assert.isFalse(TransparentElements.isTransparentBlock(schema, document.createTextNode(''))); assert.isFalse(TransparentElements.isTransparentBlock(schema, document.createComment(''))); }); it('TINY-9172: Should return false for any non transparent element', () => { assert.isFalse(TransparentElements.isTransparentBlock(schema, document.createElement('p'))); assert.isFalse(TransparentElements.isTransparentBlock(schema, document.createElement('span'))); }); }); context('isTransparentInline', () => { it('TINY-9172: Should return false for any transparent element with data-mce-block', () => { Arr.each(transparentElements, (name) => { const elm = document.createElement(name); elm.setAttribute('data-mce-block', 'true'); assert.isFalse(TransparentElements.isTransparentInline(schema, elm)); }); }); it('TINY-9172: Should return true for any transparent element without data-mce-block', () => { Arr.each(transparentElements, (name) => { assert.isTrue(TransparentElements.isTransparentInline(schema, document.createElement(name))); }); }); it('TINY-9172: Should return false for any non element', () => { assert.isFalse(TransparentElements.isTransparentInline(schema, document.createTextNode(''))); assert.isFalse(TransparentElements.isTransparentInline(schema, document.createComment(''))); }); it('TINY-9172: Should return false for any non transparent element', () => { assert.isFalse(TransparentElements.isTransparentInline(schema, document.createElement('p'))); assert.isFalse(TransparentElements.isTransparentInline(schema, document.createElement('span'))); }); }); context('isTransparentAstBlock', () => { it('TINY-9172: Should return true for any transparent element with data-mce-block', () => { Arr.each(transparentElements, (name) => { const elm = AstNode.create(name); elm.attr('data-mce-block', 'true'); assert.isTrue(TransparentElements.isTransparentAstBlock(schema, elm)); }); }); it('TINY-9172: Should return false for any transparent element without data-mce-block', () => { Arr.each(transparentElements, (name) => assert.isFalse(TransparentElements.isTransparentAstBlock(schema, AstNode.create(name))) ); }); it('TINY-9172: Should return false for any non element', () => { assert.isFalse(TransparentElements.isTransparentAstBlock(schema, AstNode.create('#text'))); assert.isFalse(TransparentElements.isTransparentAstBlock(schema, AstNode.create('#comment'))); }); it('TINY-9172: Should return false for any non transparent element', () => { assert.isFalse(TransparentElements.isTransparentAstBlock(schema, AstNode.create('p'))); assert.isFalse(TransparentElements.isTransparentAstBlock(schema, AstNode.create('span'))); }); }); context('isTransparentAstInline', () => { it('TINY-9172: Should return false for any transparent element with data-mce-block', () => { Arr.each(transparentElements, (name) => { const elm = AstNode.create(name); elm.attr('data-mce-block', 'true'); assert.isFalse(TransparentElements.isTransparentAstInline(schema, elm)); }); }); it('TINY-9172: Should return true for any transparent element without data-mce-block', () => { Arr.each(transparentElements, (name) => assert.isTrue(TransparentElements.isTransparentAstInline(schema, AstNode.create(name))) ); }); it('TINY-9172: Should return false for any non element', () => { assert.isFalse(TransparentElements.isTransparentAstInline(schema, AstNode.create('#text'))); assert.isFalse(TransparentElements.isTransparentAstInline(schema, AstNode.create('#comment'))); }); it('TINY-9172: Should return false for any non transparent element', () => { assert.isFalse(TransparentElements.isTransparentAstInline(schema, AstNode.create('p'))); assert.isFalse(TransparentElements.isTransparentAstInline(schema, AstNode.create('span'))); }); }); });