浏览代码

Made Model observable.

fredck 10 年之前
父节点
当前提交
3d21d89d23
共有 2 个文件被更改,包括 52 次插入6 次删除
  1. 11 4
      packages/ckeditor5-utils/src/mvc/model.js
  2. 41 2
      packages/ckeditor5-utils/tests/mvc/model/model.js

+ 11 - 4
packages/ckeditor5-utils/src/mvc/model.js

@@ -9,9 +9,10 @@
  * The base MVC model class.
  *
  * @class Model
+ * @mixins Emitter
  */
 
-CKEDITOR.define( [ 'utils' ], function( utils ) {
+CKEDITOR.define( [ 'emitter', 'utils' ], function( EmitterMixin, utils ) {
 	/**
 	 * Creates a new Model instance.
 	 *
@@ -41,7 +42,7 @@ CKEDITOR.define( [ 'utils' ], function( utils ) {
 		}
 	}
 
-	utils.extend( Model.prototype, {
+	utils.extend( Model.prototype, EmitterMixin, {
 		/**
 		 * Creates and sets the value of a model property of this object. This property will be part of the model state
 		 * and are observable.
@@ -70,11 +71,17 @@ CKEDITOR.define( [ 'utils' ], function( utils ) {
 				},
 
 				set: function( value ) {
-					this._attributes[ name ] = value;
+					var oldValue = this._attributes[ name ];
+
+					if ( oldValue !== value ) {
+						this._attributes[ name ] = value;
+						this.fire( 'change', this, name, value, oldValue );
+						this.fire( 'change:' + name, this, value, oldValue );
+					}
 				}
 			} );
 
-			this._attributes[ name ] = value;
+			this[ name ] = value;
 		}
 	} );
 

+ 41 - 2
packages/ckeditor5-utils/tests/mvc/model/model.js

@@ -3,11 +3,11 @@
  * For licensing, see LICENSE.md.
  */
 
-/* globals describe, it, expect, beforeEach, bender */
+/* globals describe, it, expect, beforeEach, bender, sinon */
 
 'use strict';
 
-var modules = bender.amd.require( 'mvc/model' );
+var modules = bender.amd.require( 'mvc/model', 'eventinfo' );
 
 var car;
 
@@ -71,5 +71,44 @@ describe( 'Model', function() {
 				wheels: 4
 			} );
 		} );
+
+		it( 'should fire "change"', function() {
+			var EventInfo = modules.eventinfo;
+
+			var spy = sinon.spy();
+			var spyColor = sinon.spy();
+			var spyYear = sinon.spy();
+			var spyWheels = sinon.spy();
+
+			car.on( 'change', spy );
+			car.on( 'change:color', spyColor );
+			car.on( 'change:year', spyYear );
+			car.on( 'change:wheels', spyWheels );
+
+			// Set property in all possible ways.
+			car.color = 'blue';
+			car.set( { year: 2003 } );
+			car.set( 'wheels', 4 );
+
+			// Check number of calls.
+			sinon.assert.calledThrice( spy );
+			sinon.assert.calledOnce( spyColor );
+			sinon.assert.calledOnce( spyYear );
+			sinon.assert.calledOnce( spyWheels );
+
+			// Check context.
+			sinon.assert.alwaysCalledOn( spy, car );
+			sinon.assert.calledOn( spyColor, car );
+			sinon.assert.calledOn( spyYear, car );
+			sinon.assert.calledOn( spyWheels, car );
+
+			// Check params.
+			sinon.assert.calledWithExactly( spy, sinon.match.instanceOf( EventInfo ), car, 'color', 'blue', 'red' );
+			sinon.assert.calledWithExactly( spy, sinon.match.instanceOf( EventInfo ), car, 'year', 2003, 2015 );
+			sinon.assert.calledWithExactly( spy, sinon.match.instanceOf( EventInfo ), car, 'wheels', 4, sinon.match.typeOf( 'undefined' ) );
+			sinon.assert.calledWithExactly( spyColor, sinon.match.instanceOf( EventInfo ), car, 'blue', 'red' );
+			sinon.assert.calledWithExactly( spyYear, sinon.match.instanceOf( EventInfo ), car, 2003, 2015 );
+			sinon.assert.calledWithExactly( spyWheels, sinon.match.instanceOf( EventInfo ), car, 4, sinon.match.typeOf( 'undefined' ) );
+		} );
 	} );
 } );