import { afterEach, describe, it } from '@ephox/bedrock-client';
import { Arr, Fun } from '@ephox/katamari';
import { assert } from 'chai';
import DOMUtils from 'tinymce/core/api/dom/DOMUtils';
import DomSerializer from 'tinymce/core/api/dom/Serializer';
import * as TrimHtml from 'tinymce/core/dom/TrimHtml';
import * as Zwsp from 'tinymce/core/text/Zwsp';
import * as ViewBlock from '../../module/test/ViewBlock';
declare const escape: any;
describe('browser.tinymce.core.dom.SerializerTest', () => {
const DOM = DOMUtils.DOM;
const viewBlock = ViewBlock.bddSetup();
viewBlock.get().id = 'test';
afterEach(() => {
viewBlock.update('');
});
const setTestHtml = (html: string) =>
DOM.setHTML('test', html);
const getTestElement = () =>
DOM.get('test') as HTMLElement;
it('Schema rules', () => {
let ser = DomSerializer({ fix_list_elements: true });
ser.setRules('@[id|title|class|style],div,img[src|alt|-style|border],span,hr');
setTestHtml('
test
test
');
assert.equal(ser.serialize(getTestElement()), '', 'Output name and attribute rules');
ser.setRules('img[src|border=0|alt=]');
setTestHtml('
');
assert.equal(ser.serialize(getTestElement()), '
', 'Default attribute with empty value');
ser.setRules('img[src|border=0|alt=],div[style|id],*[*]');
setTestHtml('

');
assert.equal(
ser.serialize(getTestElement()),
'

'
);
});
it('allow_unsafe_link_target (default)', () => {
const ser = DomSerializer({ });
setTestHtml('ab');
assert.equal(
ser.serialize(getTestElement(), { getInner: true }),
'ab'
);
setTestHtml('ab');
assert.equal(
ser.serialize(getTestElement(), { getInner: true }),
'ab'
);
setTestHtml('ab');
assert.equal(
ser.serialize(getTestElement(), { getInner: true }),
'ab'
);
setTestHtml('a');
assert.equal(
ser.serialize(getTestElement(), { getInner: true }),
'a'
);
setTestHtml('a');
assert.equal(
ser.serialize(getTestElement(), { getInner: true }),
'a'
);
});
it('allow_unsafe_link_target (disabled)', () => {
const ser = DomSerializer({ allow_unsafe_link_target: true });
setTestHtml('ab');
assert.equal(
ser.serialize(getTestElement(), { getInner: true }),
'ab'
);
});
it('format tree', () => {
const ser = DomSerializer({ });
setTestHtml('a');
assert.equal(
ser.serialize(getTestElement(), { format: 'tree' }).name,
'body'
);
});
it('Entity encoding', () => {
let ser: DomSerializer;
ser = DomSerializer({ entity_encoding: 'numeric' });
setTestHtml('<>&" åäö');
assert.equal(ser.serialize(getTestElement(), { getInner: true }), '<>&" åäö');
ser = DomSerializer({ entity_encoding: 'named' });
setTestHtml('<>&" åäö');
assert.equal(ser.serialize(getTestElement(), { getInner: true }), '<>&" åäö');
ser = DomSerializer({ entity_encoding: 'named+numeric', entities: '160,nbsp,34,quot,38,amp,60,lt,62,gt' });
setTestHtml('<>&" åäö');
assert.equal(ser.serialize(getTestElement(), { getInner: true }), '<>&" åäö');
ser = DomSerializer({ entity_encoding: 'raw' });
setTestHtml('<>&" åäö');
assert.equal(ser.serialize(getTestElement(), { getInner: true }), '<>&"\u00a0\u00e5\u00e4\u00f6');
});
it('Form elements (general)', () => {
const ser = DomSerializer({ fix_list_elements: true });
ser.setRules(
'form[method],label[for],input[type|name|value|checked|disabled|readonly|length|maxlength],select[multiple],' +
'option[value|selected],textarea[name|disabled|readonly]'
);
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
// Edge will add an empty input value so remove that to normalize test since it doesn't break anything
assert.equal(
ser.serialize(getTestElement()).replace(/ value=""/g, ''),
''
);
});
it('Form elements (checkbox)', () => {
const ser = DomSerializer({ fix_list_elements: true });
ser.setRules('form[method],label[for],input[type|name|value|checked|disabled|readonly|length|maxlength],select[multiple],option[value|selected]');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
});
it('Form elements (select)', () => {
const ser = DomSerializer({ fix_list_elements: true });
ser.setRules('form[method],label[for],input[type|name|value|checked|disabled|readonly|length|maxlength],select[multiple],option[value|selected]');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
setTestHtml('');
assert.equal(ser.serialize(getTestElement()), '');
});
it('List elements', () => {
const ser = DomSerializer({ fix_list_elements: true });
ser.setRules('ul[compact],ol,li');
setTestHtml('test
'); assert.equal(ser.serialize(getTestElement()), 'test
'); }); it('Do not padd empty elements with padded children', () => { const ser = DomSerializer({ fix_list_elements: true }); ser.setRules('#p,#span,b'); setTestHtml('
'); assert.equal(ser.serialize(getTestElement()), '
'); }); it('Remove empty elements', () => { const ser = DomSerializer({ fix_list_elements: true }); ser.setRules('-p'); setTestHtml('
test
'); assert.equal(ser.serialize(getTestElement()), 'test
'); }); it('Script with non JS type attribute', () => { const ser = DomSerializer({ fix_list_elements: true }); ser.setRules('script[type|language|src]'); setTestHtml(''); assert.equal(ser.serialize(getTestElement()), '
'); }); it('Script with src attr', () => { const ser = DomSerializer({ fix_list_elements: true }); ser.setRules('script[type|language|src]'); setTestHtml(''); }); it('Script with block comment around cdata with element_format: xhtml', () => { const ser = DomSerializer({ fix_list_elements: true, element_format: 'xhtml' }); ser.setRules('script[type|language|src]'); setTestHtml(''); }); it('Script with html comment and block comment around cdata with element_format: xhtml', () => { const ser = DomSerializer({ fix_list_elements: true, element_format: 'xhtml' }); ser.setRules('script[type|language|src]'); setTestHtml(''); }); it('Script with line comment and html comment with element_format: xhtml', () => { const ser = DomSerializer({ fix_list_elements: true, element_format: 'xhtml' }); ser.setRules('script[type|language|src]'); setTestHtml(''); }); it('Script with block comment around html comment with element_format: xhtml', () => { const ser = DomSerializer({ fix_list_elements: true, element_format: 'xhtml' }); ser.setRules('script[type|language|src]'); setTestHtml(''); }); it('Protected blocks', () => { const ser = DomSerializer({ fix_list_elements: true }); ser.setRules('noscript[test]'); setTestHtml(''); assert.equal(ser.serialize(getTestElement()), ''); setTestHtml(''); assert.equal(ser.serialize(getTestElement()), ''); setTestHtml('
a
a
'); setTestHtml('aa
'); assert.equal(ser.serialize(getTestElement(), { getInner: 1 }), 'a
'); assert.equal(TrimHtml.trimExternal(ser, 'a
'), 'a
'); }); it('addTempAttr same attr twice', () => { const ser1 = DomSerializer({}); const ser2 = DomSerializer({}); ser1.addTempAttr('data-x'); ser2.addTempAttr('data-x'); setTestHtml('a
'); assert.equal(ser1.serialize(getTestElement(), { getInner: 1 }), 'a
'); assert.equal(TrimHtml.trimExternal(ser1, 'a
'), 'a
'); assert.equal(ser2.serialize(getTestElement(), { getInner: 1 }), 'a
'); assert.equal(TrimHtml.trimExternal(ser2, 'a
'), 'a
'); }); it('trim data-mce-bogus="all"', () => { const ser = DomSerializer({}); setTestHtml('ab
c'); assert.equal(ser.serialize(getTestElement(), { getInner: 1 }), 'ac'); assert.equal(TrimHtml.trimExternal(ser, 'ab
c'), 'ac'); }); it('zwsp should not be treated as contents', () => { const ser = DomSerializer({ }); setTestHtml('' + Zwsp.ZWSP + '
'); assert.equal( ser.serialize(getTestElement(), { getInner: true }), '' ); }); it('nested bookmark nodes', () => { const ser = DomSerializer({ }); setTestHtml('
' + '' + '' + '' + '' + 'a' + '' + '' + '' + '
'); assert.equal( ser.serialize(getTestElement(), { getInner: true }), 'a
' ); }); it('addNodeFilter/addAttributeFilter', () => { const ser = DomSerializer({ }); const nodeFilter = Fun.noop; const attrFilter = Fun.noop; ser.addNodeFilter('some-tag', nodeFilter); ser.addAttributeFilter('data-something', attrFilter); const lastNodeFilter = Arr.last(ser.getNodeFilters()).getOrDie('Failed to get filter'); const lastAttributeFilter = Arr.last(ser.getAttributeFilters()).getOrDie('Failed to get filter'); assert.equal(lastNodeFilter.name, 'some-tag', 'Should be the last registered filter element name'); assert.equal(lastNodeFilter.callbacks[0], nodeFilter, 'Should be the last registered node filter function'); assert.equal(lastAttributeFilter.name, 'data-something', 'Should be the last registered filter attribute name'); assert.equal(lastAttributeFilter.callbacks[0], attrFilter, 'Should be the last registered attribute filter function'); }); it('TINY-7847: removeNodeFilter/removeAttributeFilter', () => { const ser = DomSerializer({ }); const nodeFilter = Fun.noop; const attrFilter = Fun.noop; const numNodeFilters = ser.getNodeFilters().length; const numAttrFilters = ser.getAttributeFilters().length; ser.addNodeFilter('some-tag', nodeFilter); ser.addAttributeFilter('data-something', attrFilter); assert.lengthOf(ser.getNodeFilters(), numNodeFilters + 1, 'Number of node filters'); assert.lengthOf(ser.getAttributeFilters(), numAttrFilters + 1, 'Number of attribute filters'); ser.removeNodeFilter('some-tag', nodeFilter); ser.removeAttributeFilter('data-something', attrFilter); assert.lengthOf(ser.getNodeFilters(), numNodeFilters, 'Number of node filters'); assert.lengthOf(ser.getAttributeFilters(), numAttrFilters, 'Number of attribute filters'); }); it('TINY-9172: Should remove the internal data-mce-block attribute for transparent block elements', () => { const ser = DomSerializer({ }); setTestHtml('block
'); assert.equal( ser.serialize(getTestElement(), { getInner: true }), 'block
' ); }); });