|
@@ -9,39 +9,22 @@
|
|
|
'use strict';
|
|
'use strict';
|
|
|
|
|
|
|
|
var modules = bender.amd.require( 'ckeditor', 'ui/view', 'ui/region', 'ckeditorerror', 'model' );
|
|
var modules = bender.amd.require( 'ckeditor', 'ui/view', 'ui/region', 'ckeditorerror', 'model' );
|
|
|
|
|
+var View, TestView;
|
|
|
|
|
+var view;
|
|
|
|
|
|
|
|
bender.tools.createSinonSandbox();
|
|
bender.tools.createSinonSandbox();
|
|
|
|
|
+beforeEach( createViewInstance );
|
|
|
|
|
|
|
|
-describe( 'View', function() {
|
|
|
|
|
- var view;
|
|
|
|
|
- var View;
|
|
|
|
|
- var TestView;
|
|
|
|
|
-
|
|
|
|
|
- beforeEach( 'Create a test view instance', function() {
|
|
|
|
|
- View = modules[ 'ui/view' ];
|
|
|
|
|
-
|
|
|
|
|
- view = new View( {
|
|
|
|
|
- a: 'foo',
|
|
|
|
|
- b: 42
|
|
|
|
|
- } );
|
|
|
|
|
-
|
|
|
|
|
- class T extends View {
|
|
|
|
|
- constructor() {
|
|
|
|
|
- super();
|
|
|
|
|
- this.template = { tag: 'a' };
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TestView = T;
|
|
|
|
|
- } );
|
|
|
|
|
-
|
|
|
|
|
|
|
+describe( 'constructor', function() {
|
|
|
it( 'accepts the model', function() {
|
|
it( 'accepts the model', function() {
|
|
|
expect( view.model ).to.be.an.instanceof( modules.model );
|
|
expect( view.model ).to.be.an.instanceof( modules.model );
|
|
|
|
|
|
|
|
expect( view ).to.have.deep.property( 'model.a', 'foo' );
|
|
expect( view ).to.have.deep.property( 'model.a', 'foo' );
|
|
|
expect( view ).to.have.deep.property( 'model.b', 42 );
|
|
expect( view ).to.have.deep.property( 'model.b', 42 );
|
|
|
} );
|
|
} );
|
|
|
|
|
+} );
|
|
|
|
|
|
|
|
|
|
+describe( 'instance', function() {
|
|
|
it( 'has no default element', function() {
|
|
it( 'has no default element', function() {
|
|
|
expect( () => view.el ).to.throw( modules.ckeditorerror );
|
|
expect( () => view.el ).to.throw( modules.ckeditorerror );
|
|
|
} );
|
|
} );
|
|
@@ -53,9 +36,11 @@ describe( 'View', function() {
|
|
|
it( 'has no default regions', function() {
|
|
it( 'has no default regions', function() {
|
|
|
expect( view.regions ).to.have.length( 0 );
|
|
expect( view.regions ).to.have.length( 0 );
|
|
|
} );
|
|
} );
|
|
|
|
|
+} );
|
|
|
|
|
|
|
|
- it( 'provides binding to the model', function() {
|
|
|
|
|
- var spy = sinon.spy();
|
|
|
|
|
|
|
+describe( 'bind', function() {
|
|
|
|
|
+ it( 'returns a function that passes arguments', function() {
|
|
|
|
|
+ var spy = bender.sinon.spy();
|
|
|
var callback = view.bind( 'a', spy );
|
|
var callback = view.bind( 'a', spy );
|
|
|
|
|
|
|
|
expect( spy.called ).to.be.false;
|
|
expect( spy.called ).to.be.false;
|
|
@@ -64,20 +49,125 @@ describe( 'View', function() {
|
|
|
sinon.assert.calledOnce( spy );
|
|
sinon.assert.calledOnce( spy );
|
|
|
sinon.assert.calledWithExactly( spy, 'el', 'foo' );
|
|
sinon.assert.calledWithExactly( spy, 'el', 'foo' );
|
|
|
|
|
|
|
|
- spy.reset();
|
|
|
|
|
view.model.a = 'bar';
|
|
view.model.a = 'bar';
|
|
|
- sinon.assert.calledOnce( spy );
|
|
|
|
|
- sinon.assert.calledWithExactly( spy, 'el', 'bar' );
|
|
|
|
|
|
|
+ sinon.assert.calledTwice( spy );
|
|
|
|
|
+ expect( spy.secondCall.calledWithExactly( 'el', 'bar' ) ).to.be.true;
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'allows binding attribute to the model', function() {
|
|
|
|
|
+ class TestView extends View {
|
|
|
|
|
+ constructor( model ) {
|
|
|
|
|
+ super( model );
|
|
|
|
|
+
|
|
|
|
|
+ this.template = {
|
|
|
|
|
+ tag: 'p',
|
|
|
|
|
+ attributes: {
|
|
|
|
|
+ 'class': this.bind( 'foo' )
|
|
|
|
|
+ },
|
|
|
|
|
+ text: 'abc'
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ view = new TestView( { foo: 'bar' } );
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p class="bar">abc</p>' );
|
|
|
|
|
+
|
|
|
|
|
+ view.model.foo = 'baz';
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p class="baz">abc</p>' );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'allows binding "text" to the model', function() {
|
|
|
|
|
+ class TestView extends View {
|
|
|
|
|
+ constructor( model ) {
|
|
|
|
|
+ super( model );
|
|
|
|
|
+
|
|
|
|
|
+ this.template = {
|
|
|
|
|
+ tag: 'p',
|
|
|
|
|
+ children: [
|
|
|
|
|
+ {
|
|
|
|
|
+ tag: 'b',
|
|
|
|
|
+ text: 'baz'
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ text: this.bind( 'foo' )
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ view = new TestView( { foo: 'bar' } );
|
|
|
|
|
+
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p>bar<b>baz</b></p>' );
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: A solution to avoid nuking the children?
|
|
|
|
|
+ view.model.foo = 'qux';
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p>qux</p>' );
|
|
|
} );
|
|
} );
|
|
|
|
|
|
|
|
- it( 'renders element from template', function() {
|
|
|
|
|
|
|
+ it( 'allows binding to the model with value processing', function() {
|
|
|
|
|
+ class TestView extends View {
|
|
|
|
|
+ constructor( model ) {
|
|
|
|
|
+ super( model );
|
|
|
|
|
+
|
|
|
|
|
+ var callback = ( el, value ) =>
|
|
|
|
|
+ ( value > 0 ? 'positive' : 'negative' );
|
|
|
|
|
+
|
|
|
|
|
+ this.template = {
|
|
|
|
|
+ tag: 'p',
|
|
|
|
|
+ attributes: {
|
|
|
|
|
+ 'class': this.bind( 'foo', callback )
|
|
|
|
|
+ },
|
|
|
|
|
+ text: this.bind( 'foo', callback )
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ view = new TestView( { foo: 3 } );
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p class="positive">positive</p>' );
|
|
|
|
|
+
|
|
|
|
|
+ view.model.foo = -7;
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p class="negative">negative</p>' );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'allows binding to the model with custom callback', function() {
|
|
|
|
|
+ class TestView extends View {
|
|
|
|
|
+ constructor( model ) {
|
|
|
|
|
+ super( model );
|
|
|
|
|
+
|
|
|
|
|
+ this.template = {
|
|
|
|
|
+ tag: 'p',
|
|
|
|
|
+ attributes: {
|
|
|
|
|
+ 'class': this.bind( 'foo', ( el, value ) => {
|
|
|
|
|
+ el.innerHTML = value;
|
|
|
|
|
+
|
|
|
|
|
+ if ( value == 'changed' ) {
|
|
|
|
|
+ return value;
|
|
|
|
|
+ }
|
|
|
|
|
+ } )
|
|
|
|
|
+ },
|
|
|
|
|
+ text: 'bar'
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ view = new TestView( { foo: 'moo' } );
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p>moo</p>' );
|
|
|
|
|
+
|
|
|
|
|
+ view.model.foo = 'changed';
|
|
|
|
|
+ expect( view.el.outerHTML ).to.be.equal( '<p class="changed">changed</p>' );
|
|
|
|
|
+ } );
|
|
|
|
|
+} );
|
|
|
|
|
+
|
|
|
|
|
+describe( 'render', function() {
|
|
|
|
|
+ it( 'creates an element from template', function() {
|
|
|
view = new TestView( { a: 1 } );
|
|
view = new TestView( { a: 1 } );
|
|
|
|
|
|
|
|
expect( view.el ).to.be.an.instanceof( HTMLElement );
|
|
expect( view.el ).to.be.an.instanceof( HTMLElement );
|
|
|
expect( view.el.nodeName ).to.be.equal( 'A' );
|
|
expect( view.el.nodeName ).to.be.equal( 'A' );
|
|
|
} );
|
|
} );
|
|
|
|
|
+} );
|
|
|
|
|
|
|
|
- it( 'destroys properly', function() {
|
|
|
|
|
|
|
+describe( 'destroys', function() {
|
|
|
|
|
+ it( 'destroys the view', function() {
|
|
|
view = new TestView( { a: 1 } );
|
|
view = new TestView( { a: 1 } );
|
|
|
|
|
|
|
|
// Append the views's element to some container.
|
|
// Append the views's element to some container.
|
|
@@ -108,3 +198,17 @@ describe( 'View', function() {
|
|
|
expect( spy.calledOnce ).to.be.true;
|
|
expect( spy.calledOnce ).to.be.true;
|
|
|
} );
|
|
} );
|
|
|
} );
|
|
} );
|
|
|
|
|
+
|
|
|
|
|
+function createViewInstance() {
|
|
|
|
|
+ View = modules[ 'ui/view' ];
|
|
|
|
|
+ view = new View( { a: 'foo', b: 42 } );
|
|
|
|
|
+
|
|
|
|
|
+ class T extends View {
|
|
|
|
|
+ constructor() {
|
|
|
|
|
+ super();
|
|
|
|
|
+ this.template = { tag: 'a' };
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TestView = T;
|
|
|
|
|
+}
|