Explorar o código

Changed the attribute class, because it need to work with the collaborating editing so attributes need to be serializable and deserializable without loosing any important informations.

Piotr Jasiun %!s(int64=10) %!d(string=hai) anos
pai
achega
d0654222ef

+ 87 - 9
packages/ckeditor5-engine/src/document/attribute.js

@@ -5,14 +5,9 @@
 
 'use strict';
 
-CKEDITOR.define( function() {
+CKEDITOR.define( [ 'utils' ], function( utils ) {
 	/**
-	 * Linear data attribute. Attributes can store any additional information, its meaning is defined by the code which
-	 * use the.
-	 *
-	 *
-	 * Note that if two attributes has the same meaning the same `Attribute` instance should be used.
-	 * To handle this use {@link document.AttributeFactory}.
+	 * Attributes can store any additional information for nodes in the data model.
 	 *
 	 * @class Attribute
 	 */
@@ -25,7 +20,7 @@ CKEDITOR.define( function() {
 		 */
 		constructor( key, value ) {
 			/**
-			 * Attribute key
+			 * Attribute key.
 			 *
 			 * @readonly
 			 * @property {String} key
@@ -33,14 +28,97 @@ CKEDITOR.define( function() {
 			this.key = key;
 
 			/**
-			 * Attribute value
+			 * Attribute value. Note that value may be any type, including objects.
 			 *
 			 * @readonly
 			 * @property {Mixed} value
 			 */
 			this.value = value;
+
+			/**
+			 * Attribute hash. Used to compare attribute. Two attributes with the same key and value will have the same hash.
+			 *
+			 * @readonly
+			 * @private
+			 * @property {String} _hash
+			 */
+			this._hash = JSON.stringify( this.key ) + ': ' + JSON.stringify( this.value, sort );
+
+			// If attribute is registered the registered one should be returned.
+			if ( Attribute._register[ this._hash ] ) {
+				return Attribute._register[ this._hash ];
+			}
+
+			// We do no care about the order so collections with the same elements should return the same hash.
+			function sort( key, value ) {
+				if ( !utils.isArray( value ) && utils.isObject( value ) ) {
+					var sorted = {};
+
+					// Sort keys and fill up the sorted object.
+					Object.keys( value ).sort().forEach( function( key ) {
+						sorted[ key ] = value[ key ];
+					} );
+
+					return sorted;
+				} else {
+					return value;
+				}
+			}
+		}
+
+		/**
+		 * Compare two attributes. Returns true is two attributes have the same key and value even if the order of value
+		 * elements is different.
+		 *
+		 *	var attr1 = new Attribute( 'foo', { a: 1, b: 2 } );
+		 *	var attr2 = new Attribute( 'foo', { b: 2, a: 1 } );
+		 *	attr1.isEqual( attr2 ); // true
+		 *
+		 * @param {document.Attribute} otherAttr other attribute
+		 * @returns {Boolean} True if attributes equals.
+		 */
+		isEqual( otherAttr ) {
+			return this._hash === otherAttr._hash;
+		}
+
+		/**
+		 * To save memory common used attributes may be registered. If an attribute is registered the constructor will
+		 * always return the same instance of this attribute.
+		 *
+		 * Note that attributes are registered globally.
+		 *
+		 *	var attr1 = Attribute.register( 'bold', true );
+		 *	var attr2 = Attribute.register( 'bold', true );
+		 *	var attr3 = new Attribute( 'bold', true );
+		 *	attr1 === attr2 // true
+		 *	attr1 === attr3 // true
+		 *
+		 * @static
+		 * @param {String} key Attribute key
+		 * @param {Mixed} value Attribute value
+		 * @returns {document.Attribute} Registered attribute.
+		 */
+		static register( key, value ) {
+			var attr = new Attribute( key, value );
+
+			if ( this._register[ attr._hash ] ) {
+				return this._register[ attr._hash ];
+			} else {
+				this._register[ attr._hash ] = attr;
+
+				return attr;
+			}
 		}
 	}
 
+	/**
+	 * Attribute register where all registered attributes are stored.
+	 *
+	 * @static
+	 * @private
+	 * @property {String} _hash
+	 */
+	Attribute._register = {};
+
 	return Attribute;
 } );

+ 0 - 71
packages/ckeditor5-engine/src/document/attributefactory.js

@@ -1,71 +0,0 @@
-/**
- * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-CKEDITOR.define( [ 'document/attribute', 'utils' ], function( Attribute, utils ) {
-	/**
-	 * Factory to use the same attribute for the same key-values pair, so common attributes use the same object instance.
-	 *
-	 * @class document.AttributeFactory
-	 */
-	class AttributeFactory {
-		/**
-		 * Creates new attribute factory.
-		 */
-		constructor() {
-			this._stored = {};
-		}
-
-		/**
-		 * Create a new attribute or return the one which already exists. Calling `create` with the same key and value
-		 * the same object instance will be used. This methods should be used to get common attributes, like bold.
-		 *
-		 * @param {String} key Attribute key
-		 * @param {Mixed} value Attribute value
-		 * @returns {document.Attribute} New attribute or stored one.
-		 */
-		create( key, value ) {
-			var hash = this._stringify( key, value );
-
-			if ( !this._stored[ hash ] ) {
-				this._stored[ hash ] = new Attribute( key, value );
-			}
-
-			return this._stored[ hash ];
-		}
-
-		/**
-		 * Produce a string hash of an item.
-		 *
-		 * @private
-		 *
-		 * @param {String} key Attribute key
-		 * @param {Mixed} value Attribute value
-		 * @returns {document.Attribute} New attribute or stored one.
-		 */
-		_stringify( key, value ) {
-			return JSON.stringify( key ) + ': ' + JSON.stringify( value, sort );
-
-			// We do no care about the order so collections with the same elements should return the same hash.
-			function sort( key, value ) {
-				if ( !utils.isArray( value ) && utils.isObject( value ) ) {
-					var sorted = {};
-
-					// Sort keys and fill up the sorted object.
-					Object.keys( value ).sort().forEach( function( key ) {
-						sorted[ key ] = value[ key ];
-					} );
-
-					return sorted;
-				} else {
-					return value;
-				}
-			}
-		}
-	}
-
-	return AttributeFactory;
-} );

+ 65 - 1
packages/ckeditor5-engine/tests/document/attribute.js

@@ -9,7 +9,13 @@
 
 var modules = bender.amd.require( 'document/attribute' );
 
-describe( 'constructor', function() {
+describe( 'attribute', function() {
+	beforeEach( function() {
+		var Attribute = modules[ 'document/attribute' ];
+
+		Attribute._register = {};
+	} );
+
 	it( 'should create attribute', function() {
 		var Attribute = modules[ 'document/attribute' ];
 
@@ -18,4 +24,62 @@ describe( 'constructor', function() {
 		expect( attr ).to.have.property( 'key' ).that.equals( 'foo' );
 		expect( attr ).to.have.property( 'value' ).that.equals( 'bar' );
 	} );
+
+	it( 'should create equal instance even if object has different order', function() {
+		var Attribute = modules[ 'document/attribute' ];
+
+		var attr1 = new Attribute( 'foo', { a: 1, b: 2 } );
+		var attr2 = new Attribute( 'foo', { b: 2, a: 1 } );
+
+		expect( attr1.isEqual( attr2 ) ).to.be.true;
+	} );
+
+	it( 'should return the same object for registered objects', function() {
+		var Attribute = modules[ 'document/attribute' ];
+
+		Attribute.register( 'register', true );
+
+		var attr1 = new Attribute( 'register', true );
+		var attr2 = new Attribute( 'register', true );
+
+		expect( attr1 ).to.be.equals( attr2 );
+		expect( attr1.isEqual( attr2 ) ).to.be.true;
+	} );
+
+	it( 'should return different objects for different values', function() {
+		var Attribute = modules[ 'document/attribute' ];
+
+		Attribute.register( 'register', true );
+
+		var attr1 = new Attribute( 'register', true );
+		var attr2 = new Attribute( 'register', false );
+
+		expect( attr1 ).to.not.be.equals( attr2 );
+		expect( attr1.isEqual( attr2 ) ).to.not.be.true;
+	} );
+
+	it( 'should return different objects for not registered objects', function() {
+		var Attribute = modules[ 'document/attribute' ];
+
+		Attribute.register( 'register', true );
+
+		var attr1 = new Attribute( 'register', false );
+		var attr2 = new Attribute( 'register', false );
+
+		expect( attr1 ).to.not.be.equals( attr2 );
+		expect( attr1.isEqual( attr2 ) ).to.be.true;
+	} );
+
+	it( 'Attribute.register should return registered attribute', function() {
+		var Attribute = modules[ 'document/attribute' ];
+
+		var attr1 = new Attribute( 'register', true );
+		var attr2 = Attribute.register( 'register', true );
+		var attr3 = Attribute.register( 'register', true );
+		var attr4 = new Attribute( 'register', true );
+
+		expect( attr1 ).to.not.be.equals( attr2 );
+		expect( attr2 ).to.be.equals( attr3 );
+		expect( attr3 ).to.be.equals( attr4 );
+	} );
 } );

+ 0 - 55
packages/ckeditor5-engine/tests/document/attributefactory.js

@@ -1,55 +0,0 @@
-/**
- * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: document */
-
-'use strict';
-
-var modules = bender.amd.require( 'document/attributefactory' );
-
-describe( 'create', function() {
-	it( 'should create the same instance', function() {
-		var AttributeFactory = modules[ 'document/attributefactory' ];
-
-		var factory = new AttributeFactory();
-
-		var attr1 = factory.create( 'foo', 'bar' );
-		var attr2 = factory.create( 'foo', 'bar' );
-
-		expect( attr1 ).to.equals( attr2 );
-		expect( attr1 ).to.have.property( 'key' ).that.equals( 'foo' );
-		expect( attr1 ).to.have.property( 'value' ).that.equals( 'bar' );
-	} );
-
-	it( 'should create the same instance even if object has different order', function() {
-		var AttributeFactory = modules[ 'document/attributefactory' ];
-
-		var factory = new AttributeFactory();
-
-		var attr1 = factory.create( 'foo', { a: 1, b: 2 } );
-		var attr2 = factory.create( 'foo', { b: 2, a: 1 } );
-
-		expect( attr1 ).to.equals( attr2 );
-		expect( attr1 ).to.have.property( 'key' ).that.equals( 'foo' );
-		expect( attr1 ).to.have.property( 'value' ).that.deep.equals( { a: 1, b: 2 } );
-	} );
-
-	it( 'should create different objects', function() {
-		var AttributeFactory = modules[ 'document/attributefactory' ];
-
-		var factory = new AttributeFactory();
-
-		var attr1 = factory.create( 'foo', 'bar' );
-		var attr2 = factory.create( 'foo', 'baz' );
-
-		expect( attr1 ).to.not.equals( attr2 );
-
-		expect( attr1 ).to.have.property( 'key' ).that.equals( 'foo' );
-		expect( attr1 ).to.have.property( 'value' ).that.equals( 'bar' );
-
-		expect( attr1 ).to.have.property( 'key' ).that.equals( 'foo' );
-		expect( attr2 ).to.have.property( 'value' ).that.equals( 'baz' );
-	} );
-} );