Przeglądaj źródła

Add AttributeList.

Szymon Cofalik 10 lat temu
rodzic
commit
fa2775420b

+ 119 - 0
packages/ckeditor5-engine/src/treemodel/attributelist.js

@@ -0,0 +1,119 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+CKEDITOR.define( [ 'treemodel/attribute' ], ( Attribute ) => {
+	/**
+	 * List of attributes. Used to manage a set of attributes added to and removed from an object containing
+	 * AttributeList.
+	 *
+	 * @class treeModel.AttributeList
+	 */
+	class AttributeList {
+		/**
+		 * Creates a list of attributes.
+		 *
+		 * @param {Iterable.<treeModel.Attribute>} [attrs] Attributes to initialize this list with.
+		 * @constructor
+		 */
+		constructor( attrs ) {
+			/**
+			 * Internal set containing the attributes stored by this list.
+			 *
+			 * @private
+			 * @property {Set.<treeModel.Attribute>}
+			 */
+			this._attrs = new Set( attrs );
+		}
+
+		/**
+		 * Returns value of an attribute with given key or null if there are no attributes with given key.
+		 *
+		 * @param {String} key The attribute key.
+		 * @returns {*|null} Value of found attribute or null if attribute with given key has not been found.
+		 */
+		getAttr( key ) {
+			for ( let attr of this._attrs ) {
+				if ( attr.key == key ) {
+					return attr.value;
+				}
+			}
+
+			return null;
+		}
+
+		/**
+		 * Returns attribute iterator.
+		 *
+		 * @returns {Iterable.<treeModel.Attribute>} Attribute iterator.
+		 */
+		getAttrs() {
+			return this._attrs[ Symbol.iterator ]();
+		}
+
+		/**
+		 * Returns `true` if the object contains given {@link treeModel.Attribute attribute} or
+		 * an attribute with the same key if passed parameter was a string.
+		 *
+		 * @param {treeModel.Attribute|String} attrOrKey An attribute or a key to look for.
+		 * @returns {Boolean} True if object contains given attribute or an attribute with the given key.
+		 */
+		hasAttr( attrOrKey ) {
+			if ( attrOrKey instanceof Attribute ) {
+				for ( let attr of this._attrs ) {
+					if ( attr.isEqual( attrOrKey ) ) {
+						return true;
+					}
+				}
+			} else {
+				for ( let attr of this._attrs ) {
+					if ( attr.key == attrOrKey ) {
+						return true;
+					}
+				}
+			}
+
+			return false;
+		}
+
+		/**
+		 * Removes attribute from the list of attributes.
+		 *
+		 * @param {String} key The attribute key.
+		 */
+		removeAttr( key ) {
+			for ( let attr of this._attrs ) {
+				if ( attr.key == key ) {
+					this._attrs.delete( attr );
+
+					return;
+				}
+			}
+		}
+
+		/**
+		 * Sets a given attribute. If the attribute with the same key already exists it will be removed.
+		 *
+		 * @param {treeModel.Attribute} attr Attribute to set.
+		 */
+		setAttr( attr ) {
+			this.removeAttr( attr.key );
+
+			this._attrs.add( attr );
+		}
+
+		/**
+		 * Removes all attributes and sets passed attributes.
+		 *
+		 * @param {Iterable.<treeModel.Attribute>} attrs Array of attributes to set.
+		 */
+		setAttrsTo( attrs ) {
+			this._attrs = new Set( attrs );
+		}
+	}
+
+	return AttributeList;
+} );

+ 161 - 0
packages/ckeditor5-engine/tests/treemodel/attributelist.js

@@ -0,0 +1,161 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: treemodel */
+
+/* bender-include: ../_tools/tools.js */
+
+'use strict';
+
+const getIteratorCount = bender.tools.core.getIteratorCount;
+
+const modules = bender.amd.require(
+	'treemodel/attributelist',
+	'treemodel/attribute',
+	'utils'
+);
+
+describe( 'AttributeList', () => {
+	let AttributeList, Attribute, utils;
+
+	before( () => {
+		AttributeList = modules[ 'treemodel/attributelist' ];
+		Attribute = modules[ 'treemodel/attribute' ];
+		utils = modules.utils;
+	} );
+
+	let list, attrFooBar;
+
+	beforeEach( () => {
+		list = new AttributeList();
+		attrFooBar = new Attribute( 'foo', 'bar' );
+	} );
+
+	describe( 'setAttr', () => {
+		it( 'should insert an attribute', () => {
+			list.setAttr( attrFooBar );
+
+			expect( getIteratorCount( list.getAttrs() ) ).to.equal( 1 );
+			expect( list.getAttr( attrFooBar.key ) ).to.equal( attrFooBar.value );
+		} );
+
+		it( 'should overwrite attribute with the same key', () => {
+			list.setAttr( attrFooBar );
+
+			expect( getIteratorCount( list.getAttrs() ) ).to.equal( 1 );
+			expect( list.getAttr( 'foo' ) ).to.equal( 'bar' );
+
+			let attrFooXyz = new Attribute( 'foo', 'xyz' );
+
+			list.setAttr( attrFooXyz );
+
+			expect( getIteratorCount( list.getAttrs() ) ).to.equal( 1 );
+			expect( list.getAttr( 'foo' ) ).to.equal( 'xyz' );
+		} );
+	} );
+
+	describe( 'setAttrsTo', () => {
+		it( 'should remove all attributes and set passed ones', () => {
+			list.setAttr( attrFooBar );
+
+			let attrs = [ new Attribute( 'abc', true ), new Attribute( 'xyz', false ) ];
+
+			list.setAttrsTo( attrs );
+
+			expect( getIteratorCount( list.getAttrs() ) ).to.equal( 2 );
+			expect( list.getAttr( 'foo' ) ).to.be.null;
+			expect( list.getAttr( 'abc' ) ).to.be.true;
+			expect( list.getAttr( 'xyz' ) ).to.be.false;
+		} );
+
+		it( 'should copy attributes array, not pass by reference', () => {
+			let attrs = [ new Attribute( 'attr', true ) ];
+
+			list.setAttrsTo( attrs );
+
+			attrs.pop();
+
+			expect( getIteratorCount( list.getAttrs() ) ).to.equal( 1 );
+		} );
+	} );
+
+	describe( 'getAttr', () => {
+		beforeEach( () => {
+			list.setAttr( attrFooBar );
+		} );
+
+		it( 'should return attribute value if key of previously set attribute has been passed', () => {
+			expect( list.getAttr( 'foo' ) ).to.equal( attrFooBar.value );
+		} );
+
+		it( 'should return null if attribute with given key has not been found', () => {
+			expect( list.getAttr( 'bar' ) ).to.be.null;
+		} );
+	} );
+
+	describe( 'removeAttr', () => {
+		it( 'should remove an attribute', () => {
+			let attrA = new Attribute( 'a', 'A' );
+			let attrB = new Attribute( 'b', 'B' );
+			let attrC = new Attribute( 'c', 'C' );
+
+			list.setAttr( attrA );
+			list.setAttr( attrB );
+			list.setAttr( attrC );
+
+			list.removeAttr( attrB.key );
+
+			expect( getIteratorCount( list.getAttrs() ) ).to.equal( 2 );
+			expect( list.getAttr( attrA.key ) ).to.equal( attrA.value );
+			expect( list.getAttr( attrC.key ) ).to.equal( attrC.value );
+			expect( list.getAttr( attrB.key ) ).to.be.null;
+		} );
+	} );
+
+	describe( 'hasAttr', () => {
+		it( 'should check attribute by key', () => {
+			list.setAttr( attrFooBar );
+			expect( list.hasAttr( 'foo' ) ).to.be.true;
+		} );
+
+		it( 'should return false if attribute was not found by key', () => {
+			expect( list.hasAttr( 'bar' ) ).to.be.false;
+		} );
+
+		it( 'should check attribute by object', () => {
+			list.setAttr( attrFooBar );
+			expect( list.hasAttr( attrFooBar ) ).to.be.true;
+		} );
+
+		it( 'should return false if attribute was not found by object', () => {
+			expect( list.hasAttr( attrFooBar ) ).to.be.false;
+		} );
+	} );
+
+	describe( 'getAttrs', () => {
+		it( 'should return all set attributes', () => {
+			let attrA = new Attribute( 'a', 'A' );
+			let attrB = new Attribute( 'b', 'B' );
+			let attrC = new Attribute( 'c', 'C' );
+
+			list.setAttrsTo( [
+				attrA,
+				attrB,
+				attrC
+			] );
+
+			list.removeAttr( attrB.key );
+
+			let attrsIt = list.getAttrs();
+			let attrs = [];
+
+			for ( let attr of attrsIt ) {
+				attrs.push( attr );
+			}
+
+			expect( [ attrA, attrC ] ).to.deep.equal( attrs );
+		} );
+	} );
+} );