|
|
@@ -8,6 +8,7 @@
|
|
|
|
|
|
import testUtils from '/tests/core/_utils/utils.js';
|
|
|
import Template from '/ckeditor5/ui/template.js';
|
|
|
+import View from '/ckeditor5/ui/view.js';
|
|
|
import Model from '/ckeditor5/ui/model.js';
|
|
|
import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
|
|
|
import EmitterMixin from '/ckeditor5/utils/emittermixin.js';
|
|
|
@@ -131,323 +132,360 @@ describe( 'Template', () => {
|
|
|
} ).to.throw( CKEditorError, /ui-template-wrong-syntax/ );
|
|
|
} );
|
|
|
|
|
|
- it( 'creates HTMLElement', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- } ).render();
|
|
|
+ describe( 'DOM Node', () => {
|
|
|
+ it( 'creates HTMLElement', () => {
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( el ).to.be.instanceof( HTMLElement );
|
|
|
- expect( el.parentNode ).to.be.null;
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p></p>' );
|
|
|
- expect( el.namespaceURI ).to.equal( 'http://www.w3.org/1999/xhtml' );
|
|
|
- } );
|
|
|
+ expect( el ).to.be.instanceof( HTMLElement );
|
|
|
+ expect( el.parentNode ).to.be.null;
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p></p>' );
|
|
|
+ expect( el.namespaceURI ).to.equal( 'http://www.w3.org/1999/xhtml' );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'creates an element in a custom namespace', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- ns: 'foo'
|
|
|
- } ).render();
|
|
|
+ it( 'creates an element in a custom namespace', () => {
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ ns: 'foo'
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( el.namespaceURI ).to.equal( 'foo' );
|
|
|
- } );
|
|
|
+ expect( el.namespaceURI ).to.equal( 'foo' );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'renders HTMLElement attributes', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- 'class': [ 'a', 'b' ],
|
|
|
- x: 'bar'
|
|
|
- },
|
|
|
- children: [ 'foo' ]
|
|
|
- } ).render();
|
|
|
+ it( 'creates a Text node', () => {
|
|
|
+ const node = new Template( { text: 'foo' } ).render();
|
|
|
|
|
|
- expect( el ).to.be.instanceof( HTMLElement );
|
|
|
- expect( el.parentNode ).to.be.null;
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p class="a b" x="bar">foo</p>' );
|
|
|
- expect( el.attributes.getNamedItem( 'class' ).namespaceURI ).to.be.null;
|
|
|
+ expect( node.nodeType ).to.equal( 3 );
|
|
|
+ expect( node.textContent ).to.equal( 'foo' );
|
|
|
+ } );
|
|
|
} );
|
|
|
|
|
|
- it( 'renders HTMLElement attributes – empty', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- class: '',
|
|
|
- x: [ '', '' ]
|
|
|
- },
|
|
|
- children: [ 'foo' ]
|
|
|
- } ).render();
|
|
|
+ describe( 'attributes', () => {
|
|
|
+ it( 'renders HTMLElement attributes', () => {
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ 'class': [ 'a', 'b' ],
|
|
|
+ x: 'bar'
|
|
|
+ },
|
|
|
+ children: [ 'foo' ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p>foo</p>' );
|
|
|
- } );
|
|
|
+ expect( el ).to.be.instanceof( HTMLElement );
|
|
|
+ expect( el.parentNode ).to.be.null;
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p class="a b" x="bar">foo</p>' );
|
|
|
+ expect( el.attributes.getNamedItem( 'class' ).namespaceURI ).to.be.null;
|
|
|
+ } );
|
|
|
|
|
|
- it( 'renders HTMLElement attributes – falsy values', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- class: false,
|
|
|
- x: [ '', null, undefined, false ],
|
|
|
- y: [ 'foo', null, undefined, false ]
|
|
|
- },
|
|
|
- children: [ 'foo' ]
|
|
|
- } ).render();
|
|
|
+ it( 'renders HTMLElement attributes – empty', () => {
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ class: '',
|
|
|
+ x: [ '', '' ]
|
|
|
+ },
|
|
|
+ children: [ 'foo' ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p y="foo">foo</p>' );
|
|
|
- } );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p>foo</p>' );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'renders HTMLElement attributes in a custom namespace', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- class: {
|
|
|
- ns: 'foo',
|
|
|
- value: [ 'a', 'b' ]
|
|
|
+ it( 'renders HTMLElement attributes – falsy values', () => {
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ class: false,
|
|
|
+ x: [ '', null, undefined, false ],
|
|
|
+ y: [ 'foo', null, undefined, false ]
|
|
|
},
|
|
|
- x: {
|
|
|
- ns: 'abc',
|
|
|
- value: 'bar'
|
|
|
- }
|
|
|
- },
|
|
|
- children: [ 'foo' ]
|
|
|
- } ).render();
|
|
|
+ children: [ 'foo' ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p class="a b" x="bar">foo</p>' );
|
|
|
- expect( el.attributes.getNamedItem( 'class' ).namespaceURI ).to.equal( 'foo' );
|
|
|
- expect( el.attributes.getNamedItem( 'x' ).namespaceURI ).to.equal( 'abc' );
|
|
|
- } );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p y="foo">foo</p>' );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'creates HTMLElement children', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- a: 'A'
|
|
|
- },
|
|
|
- children: [
|
|
|
- {
|
|
|
- tag: 'b',
|
|
|
- children: [ 'B' ]
|
|
|
+ it( 'renders HTMLElement attributes in a custom namespace', () => {
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ class: {
|
|
|
+ ns: 'foo',
|
|
|
+ value: [ 'a', 'b' ]
|
|
|
+ },
|
|
|
+ x: {
|
|
|
+ ns: 'abc',
|
|
|
+ value: 'bar'
|
|
|
+ }
|
|
|
},
|
|
|
- {
|
|
|
- tag: 'i',
|
|
|
- children: [
|
|
|
- 'C',
|
|
|
- {
|
|
|
- tag: 'b',
|
|
|
- children: [ 'D' ]
|
|
|
- }
|
|
|
- ]
|
|
|
- }
|
|
|
- ]
|
|
|
- } ).render();
|
|
|
+ children: [ 'foo' ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p a="A"><b>B</b><i>C<b>D</b></i></p>' );
|
|
|
- } );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p class="a b" x="bar">foo</p>' );
|
|
|
+ expect( el.attributes.getNamedItem( 'class' ).namespaceURI ).to.equal( 'foo' );
|
|
|
+ expect( el.attributes.getNamedItem( 'x' ).namespaceURI ).to.equal( 'abc' );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'creates a Text node', () => {
|
|
|
- const node = new Template( { text: 'foo' } ).render();
|
|
|
+ describe( 'style', () => {
|
|
|
+ let observable, emitter, bind;
|
|
|
|
|
|
- expect( node.nodeType ).to.equal( 3 );
|
|
|
- expect( node.textContent ).to.equal( 'foo' );
|
|
|
- } );
|
|
|
+ beforeEach( () => {
|
|
|
+ observable = new Model( {
|
|
|
+ width: '10px',
|
|
|
+ backgroundColor: 'yellow'
|
|
|
+ } );
|
|
|
|
|
|
- it( 'creates a child Text Node (different syntaxes)', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- children: [
|
|
|
- 'foo',
|
|
|
- { text: 'bar' }
|
|
|
- ]
|
|
|
- } ).render();
|
|
|
+ emitter = Object.create( EmitterMixin );
|
|
|
+ bind = Template.bind( observable, emitter );
|
|
|
+ } );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p>foobar</p>' );
|
|
|
- } );
|
|
|
+ it( 'renders as a static value', () => {
|
|
|
+ setElement( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ style: 'color: red'
|
|
|
+ }
|
|
|
+ } );
|
|
|
|
|
|
- it( 'creates multiple child Text Nodes', () => {
|
|
|
- const el = new Template( {
|
|
|
- tag: 'p',
|
|
|
- children: [
|
|
|
- 'a',
|
|
|
- 'b',
|
|
|
- { text: 'c' },
|
|
|
- 'd',
|
|
|
- { text: [ 'e', 'f' ] }
|
|
|
- ]
|
|
|
- } ).render();
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="color:red;"></p>' );
|
|
|
+ } );
|
|
|
|
|
|
- expect( el.childNodes ).to.have.length( 5 );
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p>abcdef</p>' );
|
|
|
- } );
|
|
|
+ it( 'renders as a static value (Array of values)', () => {
|
|
|
+ setElement( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ style: [ 'color: red;', 'display: block;' ]
|
|
|
+ }
|
|
|
+ } );
|
|
|
|
|
|
- it( 'activates model bindings – root', () => {
|
|
|
- const observable = new Model( {
|
|
|
- foo: 'bar'
|
|
|
- } );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="color:red;display:block;"></p>' );
|
|
|
+ } );
|
|
|
|
|
|
- const emitter = Object.create( EmitterMixin );
|
|
|
- const bind = Template.bind( observable, emitter );
|
|
|
- const el = new Template( {
|
|
|
- tag: 'div',
|
|
|
- attributes: {
|
|
|
- class: bind.to( 'foo' )
|
|
|
- }
|
|
|
- } ).render();
|
|
|
+ it( 'renders as a value bound to the model', () => {
|
|
|
+ setElement( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ style: bind.to( 'width', w => `width: ${ w }` )
|
|
|
+ }
|
|
|
+ } );
|
|
|
|
|
|
- expect( el.getAttribute( 'class' ) ).to.equal( 'bar' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:10px;"></p>' );
|
|
|
|
|
|
- observable.foo = 'baz';
|
|
|
- expect( el.getAttribute( 'class' ) ).to.equal( 'baz' );
|
|
|
- } );
|
|
|
+ observable.width = '1em';
|
|
|
|
|
|
- it( 'activates model bindings – children', () => {
|
|
|
- const observable = new Model( {
|
|
|
- foo: 'bar'
|
|
|
- } );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:1em;"></p>' );
|
|
|
+ } );
|
|
|
|
|
|
- const emitter = Object.create( EmitterMixin );
|
|
|
- const bind = Template.bind( observable, emitter );
|
|
|
- const el = new Template( {
|
|
|
- tag: 'div',
|
|
|
- children: [
|
|
|
- {
|
|
|
- tag: 'span',
|
|
|
- children: [
|
|
|
- {
|
|
|
- text: [
|
|
|
- bind.to( 'foo' ),
|
|
|
- 'static'
|
|
|
- ]
|
|
|
+ it( 'renders as a value bound to the model (Array of bindings)', () => {
|
|
|
+ setElement( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ style: [
|
|
|
+ bind.to( 'width', w => `width: ${ w };` ),
|
|
|
+ bind.to( 'backgroundColor', c => `background-color: ${ c };` )
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:10px;background-color:yellow;"></p>' );
|
|
|
+
|
|
|
+ observable.width = '1em';
|
|
|
+
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:1em;background-color:yellow;"></p>' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ describe( 'object', () => {
|
|
|
+ it( 'renders with static and bound attributes', () => {
|
|
|
+ setElement( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ style: {
|
|
|
+ width: bind.to( 'width' ),
|
|
|
+ height: '10px',
|
|
|
+ backgroundColor: bind.to( 'backgroundColor' )
|
|
|
+ }
|
|
|
}
|
|
|
- ]
|
|
|
- }
|
|
|
- ]
|
|
|
- } ).render();
|
|
|
+ } );
|
|
|
|
|
|
- expect( el.firstChild.textContent ).to.equal( 'bar static' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:10px;height:10px;background-color:yellow;"></p>' );
|
|
|
|
|
|
- observable.foo = 'baz';
|
|
|
- expect( el.firstChild.textContent ).to.equal( 'baz static' );
|
|
|
- } );
|
|
|
+ observable.width = '20px';
|
|
|
+ observable.backgroundColor = 'green';
|
|
|
|
|
|
- describe( 'style attribute', () => {
|
|
|
- let observable, emitter, bind;
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:20px;height:10px;background-color:green;"></p>' );
|
|
|
+ } );
|
|
|
|
|
|
- beforeEach( () => {
|
|
|
- observable = new Model( {
|
|
|
- width: '10px',
|
|
|
- backgroundColor: 'yellow'
|
|
|
- } );
|
|
|
+ it( 'renders with empty string attributes', () => {
|
|
|
+ setElement( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ style: {
|
|
|
+ width: '',
|
|
|
+ backgroundColor: bind.to( 'backgroundColor' )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } );
|
|
|
|
|
|
- emitter = Object.create( EmitterMixin );
|
|
|
- bind = Template.bind( observable, emitter );
|
|
|
- } );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="background-color:yellow;"></p>' );
|
|
|
|
|
|
- it( 'renders as a static value', () => {
|
|
|
- setElement( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- style: 'color: red'
|
|
|
- }
|
|
|
- } );
|
|
|
+ observable.backgroundColor = '';
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="color:red;"></p>' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p></p>' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'renders with falsy values', () => {
|
|
|
+ setElement( {
|
|
|
+ tag: 'p',
|
|
|
+ attributes: {
|
|
|
+ style: {
|
|
|
+ width: null,
|
|
|
+ height: false,
|
|
|
+ color: undefined
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } );
|
|
|
+
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p></p>' );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
} );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'renders as a static value (Array of values)', () => {
|
|
|
- setElement( {
|
|
|
+ describe( 'children', () => {
|
|
|
+ it( 'creates HTMLElement children', () => {
|
|
|
+ const el = new Template( {
|
|
|
tag: 'p',
|
|
|
attributes: {
|
|
|
- style: [ 'color: red;', 'display: block;' ]
|
|
|
- }
|
|
|
- } );
|
|
|
+ a: 'A'
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: 'b',
|
|
|
+ children: [ 'B' ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ tag: 'i',
|
|
|
+ children: [
|
|
|
+ 'C',
|
|
|
+ {
|
|
|
+ tag: 'b',
|
|
|
+ children: [ 'D' ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="color:red;display:block;"></p>' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p a="A"><b>B</b><i>C<b>D</b></i></p>' );
|
|
|
} );
|
|
|
|
|
|
- it( 'renders as a value bound to the model', () => {
|
|
|
- setElement( {
|
|
|
+ it( 'creates a child Text Node (different syntaxes)', () => {
|
|
|
+ const el = new Template( {
|
|
|
tag: 'p',
|
|
|
- attributes: {
|
|
|
- style: bind.to( 'width', w => `width: ${ w }` )
|
|
|
- }
|
|
|
- } );
|
|
|
+ children: [
|
|
|
+ 'foo',
|
|
|
+ { text: 'bar' }
|
|
|
+ ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:10px;"></p>' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p>foobar</p>' );
|
|
|
+ } );
|
|
|
|
|
|
- observable.width = '1em';
|
|
|
+ it( 'creates multiple child Text Nodes', () => {
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ children: [
|
|
|
+ 'a',
|
|
|
+ 'b',
|
|
|
+ { text: 'c' },
|
|
|
+ 'd',
|
|
|
+ { text: [ 'e', 'f' ] }
|
|
|
+ ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:1em;"></p>' );
|
|
|
+ expect( el.childNodes ).to.have.length( 5 );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p>abcdef</p>' );
|
|
|
} );
|
|
|
|
|
|
- it( 'renders as a value bound to the model (Array of bindings)', () => {
|
|
|
- setElement( {
|
|
|
- tag: 'p',
|
|
|
+ it( 'renders view children', () => {
|
|
|
+ const v1 = getView( {
|
|
|
+ tag: 'span',
|
|
|
attributes: {
|
|
|
- style: [
|
|
|
- bind.to( 'width', w => `width: ${ w };` ),
|
|
|
- bind.to( 'backgroundColor', c => `background-color: ${ c };` )
|
|
|
+ class: [
|
|
|
+ 'v1'
|
|
|
]
|
|
|
}
|
|
|
} );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:10px;background-color:yellow;"></p>' );
|
|
|
+ const v2 = getView( {
|
|
|
+ tag: 'span',
|
|
|
+ attributes: {
|
|
|
+ class: [
|
|
|
+ 'v2'
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ } );
|
|
|
|
|
|
- observable.width = '1em';
|
|
|
+ const tpl = new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ children: [ v1, v2 ]
|
|
|
+ } );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:1em;background-color:yellow;"></p>' );
|
|
|
+ expect( tpl.children.get( 0 ) ).to.equal( v1.template );
|
|
|
+ expect( tpl.children.get( 1 ) ).to.equal( v2.template );
|
|
|
+ expect( normalizeHtml( tpl.render().outerHTML ) ).to.equal( '<p><span class="v1"></span><span class="v2"></span></p>' );
|
|
|
} );
|
|
|
+ } );
|
|
|
|
|
|
- describe( 'object', () => {
|
|
|
- it( 'renders with static and bound attributes', () => {
|
|
|
- setElement( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- style: {
|
|
|
- width: bind.to( 'width' ),
|
|
|
- height: '10px',
|
|
|
- backgroundColor: bind.to( 'backgroundColor' )
|
|
|
- }
|
|
|
- }
|
|
|
- } );
|
|
|
-
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:10px;height:10px;background-color:yellow;"></p>' );
|
|
|
-
|
|
|
- observable.width = '20px';
|
|
|
- observable.backgroundColor = 'green';
|
|
|
-
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="width:20px;height:10px;background-color:green;"></p>' );
|
|
|
+ describe( 'bindings', () => {
|
|
|
+ it( 'activates model bindings – root', () => {
|
|
|
+ const observable = new Model( {
|
|
|
+ foo: 'bar'
|
|
|
} );
|
|
|
|
|
|
- it( 'renders with empty string attributes', () => {
|
|
|
- setElement( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- style: {
|
|
|
- width: '',
|
|
|
- backgroundColor: bind.to( 'backgroundColor' )
|
|
|
- }
|
|
|
- }
|
|
|
- } );
|
|
|
+ const emitter = Object.create( EmitterMixin );
|
|
|
+ const bind = Template.bind( observable, emitter );
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ attributes: {
|
|
|
+ class: bind.to( 'foo' )
|
|
|
+ }
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p style="background-color:yellow;"></p>' );
|
|
|
+ expect( el.getAttribute( 'class' ) ).to.equal( 'bar' );
|
|
|
|
|
|
- observable.backgroundColor = '';
|
|
|
+ observable.foo = 'baz';
|
|
|
+ expect( el.getAttribute( 'class' ) ).to.equal( 'baz' );
|
|
|
+ } );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p></p>' );
|
|
|
+ it( 'activates model bindings – children', () => {
|
|
|
+ const observable = new Model( {
|
|
|
+ foo: 'bar'
|
|
|
} );
|
|
|
|
|
|
- it( 'renders with falsy values', () => {
|
|
|
- setElement( {
|
|
|
- tag: 'p',
|
|
|
- attributes: {
|
|
|
- style: {
|
|
|
- width: null,
|
|
|
- height: false,
|
|
|
- color: undefined
|
|
|
- }
|
|
|
+ const emitter = Object.create( EmitterMixin );
|
|
|
+ const bind = Template.bind( observable, emitter );
|
|
|
+ const el = new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: 'span',
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ text: [
|
|
|
+ bind.to( 'foo' ),
|
|
|
+ 'static'
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
}
|
|
|
- } );
|
|
|
+ ]
|
|
|
+ } ).render();
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<p></p>' );
|
|
|
- } );
|
|
|
+ expect( el.firstChild.textContent ).to.equal( 'bar static' );
|
|
|
+
|
|
|
+ observable.foo = 'baz';
|
|
|
+ expect( el.firstChild.textContent ).to.equal( 'baz static' );
|
|
|
} );
|
|
|
} );
|
|
|
} );
|
|
|
@@ -493,165 +531,189 @@ describe( 'Template', () => {
|
|
|
expect( text.textContent ).to.equal( '' );
|
|
|
} );
|
|
|
|
|
|
- it( 'applies textContent to a Text Node', () => {
|
|
|
- new Template( {
|
|
|
- text: 'abc'
|
|
|
- } ).apply( text );
|
|
|
-
|
|
|
- expect( text.textContent ).to.equal( 'abc' );
|
|
|
- } );
|
|
|
+ describe( 'text', () => {
|
|
|
+ it( 'applies textContent to a Text Node', () => {
|
|
|
+ new Template( {
|
|
|
+ text: 'abc'
|
|
|
+ } ).apply( text );
|
|
|
|
|
|
- it( 'applies attributes to an HTMLElement', () => {
|
|
|
- new Template( {
|
|
|
- tag: 'div',
|
|
|
- attributes: {
|
|
|
- 'class': [ 'a', 'b' ],
|
|
|
- x: 'bar'
|
|
|
- }
|
|
|
- } ).apply( el );
|
|
|
+ expect( text.textContent ).to.equal( 'abc' );
|
|
|
+ } );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="a b" x="bar"></div>' );
|
|
|
- } );
|
|
|
+ it( 'applies new textContent to an existing Text Node of an HTMLElement', () => {
|
|
|
+ el.textContent = 'bar';
|
|
|
|
|
|
- it( 'doesn\'t apply new child to an HTMLElement – Text Node', () => {
|
|
|
- new Template( {
|
|
|
- tag: 'div',
|
|
|
- children: [ 'foo' ]
|
|
|
- } ).apply( el );
|
|
|
+ new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ children: [ 'foo' ]
|
|
|
+ } ).apply( el );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div></div>' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div>foo</div>' );
|
|
|
+ } );
|
|
|
} );
|
|
|
|
|
|
- it( 'doesn\'t apply new child to an HTMLElement – HTMLElement', () => {
|
|
|
- new Template( {
|
|
|
- tag: 'div',
|
|
|
- children: [
|
|
|
- {
|
|
|
- tag: 'span'
|
|
|
+ describe( 'attributes', () => {
|
|
|
+ it( 'applies attributes to an HTMLElement', () => {
|
|
|
+ new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ attributes: {
|
|
|
+ 'class': [ 'a', 'b' ],
|
|
|
+ x: 'bar'
|
|
|
}
|
|
|
- ]
|
|
|
- } ).apply( el );
|
|
|
+ } ).apply( el );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div></div>' );
|
|
|
- } );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="a b" x="bar"></div>' );
|
|
|
+ } );
|
|
|
|
|
|
- it( 'applies new textContent to an existing Text Node of an HTMLElement', () => {
|
|
|
- el.textContent = 'bar';
|
|
|
+ it( 'applies attributes and TextContent to a DOM tree', () => {
|
|
|
+ el.textContent = 'abc';
|
|
|
+ el.appendChild( document.createElement( 'span' ) );
|
|
|
|
|
|
- new Template( {
|
|
|
- tag: 'div',
|
|
|
- children: [ 'foo' ]
|
|
|
- } ).apply( el );
|
|
|
+ new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ attributes: {
|
|
|
+ 'class': 'parent'
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ 'Children:',
|
|
|
+ {
|
|
|
+ tag: 'span',
|
|
|
+ attributes: {
|
|
|
+ class: 'child'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ } ).apply( el );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div>foo</div>' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="parent">Children:<span class="child"></span></div>' );
|
|
|
+ } );
|
|
|
} );
|
|
|
|
|
|
- it( 'applies attributes and TextContent to a DOM tree', () => {
|
|
|
- el.textContent = 'abc';
|
|
|
- el.appendChild( document.createElement( 'span' ) );
|
|
|
+ describe( 'children', () => {
|
|
|
+ it( 'doesn\'t apply new child to an HTMLElement – Text Node', () => {
|
|
|
+ new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ children: [ 'foo' ]
|
|
|
+ } ).apply( el );
|
|
|
|
|
|
- new Template( {
|
|
|
- tag: 'div',
|
|
|
- attributes: {
|
|
|
- 'class': 'parent'
|
|
|
- },
|
|
|
- children: [
|
|
|
- 'Children:',
|
|
|
- {
|
|
|
- tag: 'span',
|
|
|
- attributes: {
|
|
|
- class: 'child'
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div></div>' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'doesn\'t apply new child to an HTMLElement – HTMLElement', () => {
|
|
|
+ new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: 'span'
|
|
|
}
|
|
|
+ ]
|
|
|
+ } ).apply( el );
|
|
|
+
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div></div>' );
|
|
|
+ } );
|
|
|
+
|
|
|
+ it( 'doesn\'t apply new child to an HTMLElement – view', () => {
|
|
|
+ const view = getView( {
|
|
|
+ tag: 'span',
|
|
|
+ attributes: {
|
|
|
+ class: [
|
|
|
+ 'v1'
|
|
|
+ ]
|
|
|
}
|
|
|
- ]
|
|
|
- } ).apply( el );
|
|
|
+ } );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="parent">Children:<span class="child"></span></div>' );
|
|
|
- } );
|
|
|
+ new Template( {
|
|
|
+ tag: 'p',
|
|
|
+ children: [ view ]
|
|
|
+ } ).apply( el );
|
|
|
|
|
|
- it( 'should work for deep DOM structure', () => {
|
|
|
- const childA = document.createElement( 'a' );
|
|
|
- const childB = document.createElement( 'b' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div></div>' );
|
|
|
+ } );
|
|
|
|
|
|
- childA.textContent = 'anchor';
|
|
|
- childB.textContent = 'bold';
|
|
|
+ it( 'should work for deep DOM structure', () => {
|
|
|
+ const childA = document.createElement( 'a' );
|
|
|
+ const childB = document.createElement( 'b' );
|
|
|
|
|
|
- el.appendChild( childA );
|
|
|
- el.appendChild( childB );
|
|
|
+ childA.textContent = 'anchor';
|
|
|
+ childB.textContent = 'bold';
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div><a>anchor</a><b>bold</b></div>' );
|
|
|
+ el.appendChild( childA );
|
|
|
+ el.appendChild( childB );
|
|
|
|
|
|
- const spy1 = testUtils.sinon.spy();
|
|
|
- const spy2 = testUtils.sinon.spy();
|
|
|
- const spy3 = testUtils.sinon.spy();
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div><a>anchor</a><b>bold</b></div>' );
|
|
|
|
|
|
- observable.on( 'ku', spy1 );
|
|
|
- observable.on( 'kd', spy2 );
|
|
|
- observable.on( 'mo', spy3 );
|
|
|
+ const spy1 = testUtils.sinon.spy();
|
|
|
+ const spy2 = testUtils.sinon.spy();
|
|
|
+ const spy3 = testUtils.sinon.spy();
|
|
|
|
|
|
- new Template( {
|
|
|
- tag: 'div',
|
|
|
- children: [
|
|
|
- {
|
|
|
- tag: 'a',
|
|
|
- on: {
|
|
|
- keyup: bind.to( 'ku' )
|
|
|
- },
|
|
|
- attributes: {
|
|
|
- class: bind.to( 'foo', val => 'applied-A-' + val ),
|
|
|
- id: 'applied-A'
|
|
|
- },
|
|
|
- children: [ 'Text applied to childA.' ]
|
|
|
- },
|
|
|
- {
|
|
|
- tag: 'b',
|
|
|
- on: {
|
|
|
- keydown: bind.to( 'kd' )
|
|
|
+ observable.on( 'ku', spy1 );
|
|
|
+ observable.on( 'kd', spy2 );
|
|
|
+ observable.on( 'mo', spy3 );
|
|
|
+
|
|
|
+ new Template( {
|
|
|
+ tag: 'div',
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: 'a',
|
|
|
+ on: {
|
|
|
+ keyup: bind.to( 'ku' )
|
|
|
+ },
|
|
|
+ attributes: {
|
|
|
+ class: bind.to( 'foo', val => 'applied-A-' + val ),
|
|
|
+ id: 'applied-A'
|
|
|
+ },
|
|
|
+ children: [ 'Text applied to childA.' ]
|
|
|
},
|
|
|
- attributes: {
|
|
|
- class: bind.to( 'baz', val => 'applied-B-' + val ),
|
|
|
- id: 'applied-B'
|
|
|
+ {
|
|
|
+ tag: 'b',
|
|
|
+ on: {
|
|
|
+ keydown: bind.to( 'kd' )
|
|
|
+ },
|
|
|
+ attributes: {
|
|
|
+ class: bind.to( 'baz', val => 'applied-B-' + val ),
|
|
|
+ id: 'applied-B'
|
|
|
+ },
|
|
|
+ children: [ 'Text applied to childB.' ]
|
|
|
},
|
|
|
- children: [ 'Text applied to childB.' ]
|
|
|
+ 'Text which is not to be applied because it does NOT exist in original element.'
|
|
|
+ ],
|
|
|
+ on: {
|
|
|
+ 'mouseover@a': bind.to( 'mo' )
|
|
|
},
|
|
|
- 'Text which is not to be applied because it does NOT exist in original element.'
|
|
|
- ],
|
|
|
- on: {
|
|
|
- 'mouseover@a': bind.to( 'mo' )
|
|
|
- },
|
|
|
- attributes: {
|
|
|
- id: bind.to( 'foo', val => val.toUpperCase() ),
|
|
|
- class: bind.to( 'baz', val => 'applied-parent-' + val )
|
|
|
- }
|
|
|
- } ).apply( el );
|
|
|
+ attributes: {
|
|
|
+ id: bind.to( 'foo', val => val.toUpperCase() ),
|
|
|
+ class: bind.to( 'baz', val => 'applied-parent-' + val )
|
|
|
+ }
|
|
|
+ } ).apply( el );
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="applied-parent-qux" id="BAR">' +
|
|
|
- '<a class="applied-A-bar" id="applied-A">Text applied to childA.</a>' +
|
|
|
- '<b class="applied-B-qux" id="applied-B">Text applied to childB.</b>' +
|
|
|
- '</div>' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="applied-parent-qux" id="BAR">' +
|
|
|
+ '<a class="applied-A-bar" id="applied-A">Text applied to childA.</a>' +
|
|
|
+ '<b class="applied-B-qux" id="applied-B">Text applied to childB.</b>' +
|
|
|
+ '</div>' );
|
|
|
|
|
|
- observable.foo = 'updated';
|
|
|
+ observable.foo = 'updated';
|
|
|
|
|
|
- expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="applied-parent-qux" id="UPDATED">' +
|
|
|
- '<a class="applied-A-updated" id="applied-A">Text applied to childA.</a>' +
|
|
|
- '<b class="applied-B-qux" id="applied-B">Text applied to childB.</b>' +
|
|
|
- '</div>' );
|
|
|
+ expect( normalizeHtml( el.outerHTML ) ).to.equal( '<div class="applied-parent-qux" id="UPDATED">' +
|
|
|
+ '<a class="applied-A-updated" id="applied-A">Text applied to childA.</a>' +
|
|
|
+ '<b class="applied-B-qux" id="applied-B">Text applied to childB.</b>' +
|
|
|
+ '</div>' );
|
|
|
|
|
|
- document.body.appendChild( el );
|
|
|
+ document.body.appendChild( el );
|
|
|
|
|
|
- // Test "mouseover@a".
|
|
|
- dispatchEvent( el, 'mouseover' );
|
|
|
- dispatchEvent( childA, 'mouseover' );
|
|
|
+ // Test "mouseover@a".
|
|
|
+ dispatchEvent( el, 'mouseover' );
|
|
|
+ dispatchEvent( childA, 'mouseover' );
|
|
|
|
|
|
- // Test "keyup".
|
|
|
- dispatchEvent( childA, 'keyup' );
|
|
|
+ // Test "keyup".
|
|
|
+ dispatchEvent( childA, 'keyup' );
|
|
|
|
|
|
- // Test "keydown".
|
|
|
- dispatchEvent( childB, 'keydown' );
|
|
|
+ // Test "keydown".
|
|
|
+ dispatchEvent( childB, 'keydown' );
|
|
|
|
|
|
- sinon.assert.calledOnce( spy1 );
|
|
|
- sinon.assert.calledOnce( spy2 );
|
|
|
- sinon.assert.calledOnce( spy3 );
|
|
|
+ sinon.assert.calledOnce( spy1 );
|
|
|
+ sinon.assert.calledOnce( spy2 );
|
|
|
+ sinon.assert.calledOnce( spy3 );
|
|
|
+ } );
|
|
|
} );
|
|
|
} );
|
|
|
|
|
|
@@ -2104,3 +2166,11 @@ function dispatchEvent( el, domEvtName ) {
|
|
|
bubbles: true
|
|
|
} ) );
|
|
|
}
|
|
|
+
|
|
|
+function getView( def ) {
|
|
|
+ const view = new View();
|
|
|
+
|
|
|
+ view.template = new Template( def );
|
|
|
+
|
|
|
+ return view;
|
|
|
+}
|