Sfoglia il codice sorgente

Merge pull request #1711 from ckeditor/t/ckeditor5/1659

Feature: Introduced `Schema#setAttributeProperties()` and `Schema#getAttributeProperties()` methods. Closes ckeditor/ckeditor5#1659.
Piotrek Koszuliński 6 anni fa
parent
commit
fa29e979db

+ 70 - 0
packages/ckeditor5-engine/src/model/schema.js

@@ -39,6 +39,14 @@ export default class Schema {
 	constructor() {
 		this._sourceDefinitions = {};
 
+		/**
+		 * A dictionary containing attribute properties.
+		 *
+		 * @private
+		 * @member {Object.<String,String>}
+		 */
+		this._attributeProperties = {};
+
 		this.decorate( 'checkChild' );
 		this.decorate( 'checkAttribute' );
 
@@ -475,6 +483,58 @@ export default class Schema {
 		}, { priority: 'high' } );
 	}
 
+	/**
+	 * This method allows assigning additional metadata to the model attributes. For example,
+	 * {@link module:engine/model/schema~AttributeProperties `AttributeProperties#isFormatting` property} is
+	 * used to mark formatting attributes (like `bold` or `italic`).
+	 *
+	 *		// Mark bold as a formatting attribute.
+	 *		schema.setAttributeProperties( 'bold', {
+	 *			isFormatting: true
+	 *		} );
+	 *
+	 *		// Override code not to be considered a formatting markup.
+	 *		schema.setAttributeProperties( 'code', {
+	 *			isFormatting: false
+	 *		} );
+	 *
+	 * Properties are not limited to members defined in the
+	 * {@link module:engine/model/schema~AttributeProperties `AttributeProperties` type} and you can also use custom properties:
+	 *
+	 *		schema.setAttributeProperties( 'blockQuote', {
+	 *			customProperty: 'value'
+	 *		} );
+	 *
+	 * Subsequent calls with the same attribute will extend its custom properties:
+	 *
+	 *		schema.setAttributeProperties( 'blockQuote', {
+	 *			one: 1
+	 *		} );
+	 *
+	 *		schema.setAttributeProperties( 'blockQuote', {
+	 *			two: 2
+	 *		} );
+	 *
+	 *		console.log( schema.getAttributeProperties( 'blockQuote' ) );
+	 *		// Logs: { one: 1, two: 2 }
+	 *
+	 * @param {String} attributeName A name of the attribute to receive the properties.
+	 * @param {module:engine/model/schema~AttributeProperties} properties A dictionary of properties.
+	 */
+	setAttributeProperties( attributeName, properties ) {
+		this._attributeProperties[ attributeName ] = Object.assign( this.getAttributeProperties( attributeName ) || {}, properties );
+	}
+
+	/**
+	 * Returns properties associated with a given model attribute. See {@link #setAttributeProperties `setAttributeProperties()`}.
+	 *
+	 * @param {String} attributeName A name of the attribute.
+	 * @returns {module:engine/model/schema~AttributeProperties}
+	 */
+	getAttributeProperties( attributeName ) {
+		return this._attributeProperties[ attributeName ];
+	}
+
 	/**
 	 * Returns the lowest {@link module:engine/model/schema~Schema#isLimit limit element} containing the entire
 	 * selection/range/position or the root otherwise.
@@ -1285,6 +1345,16 @@ export class SchemaContext {
  * @typedef {Object} module:engine/model/schema~SchemaContextItem
  */
 
+/**
+ * A structure containing additional metadata describing the attribute.
+ *
+ * See {@link module:engine/model/schema~Schema#setAttributeProperties `Schema#setAttributeProperties()`} for usage examples.
+ *
+ * @typedef {Object} module:engine/model/schema~AttributeProperties
+ * @property {Boolean} [isFormatting] Indicates that the attribute should be considered as a visual formatting, like `bold`, `italic` or
+ * `fontSize` rather than semantic attribute (such as `src`, `listType`, etc.). For example, it is used by the "Remove format" feature.
+ */
+
 function compileBaseItemRule( sourceItemRules, itemName ) {
 	const itemRule = {
 		name: itemName,

+ 40 - 0
packages/ckeditor5-engine/tests/model/schema.js

@@ -96,6 +96,46 @@ describe( 'Schema', () => {
 		} );
 	} );
 
+	describe( 'setAttributeProperties()', () => {
+		beforeEach( () => {
+			schema.register( '$root' );
+			schema.register( 'paragraph', {
+				allowIn: '$root'
+			} );
+			schema.register( '$text', {
+				allowIn: 'paragraph'
+			} );
+			schema.extend( '$text', { allowAttributes: 'testAttribute' } );
+		} );
+
+		it( 'allows registering new properties', () => {
+			schema.setAttributeProperties( 'testAttribute', {
+				foo: 'bar',
+				baz: 'bom'
+			} );
+
+			expect( schema.getAttributeProperties( 'testAttribute' ) ).to.deep.equal( {
+				foo: 'bar',
+				baz: 'bom'
+			} );
+		} );
+
+		it( 'support adding properties in subsequent calls', () => {
+			schema.setAttributeProperties( 'testAttribute', {
+				first: 'foo'
+			} );
+
+			schema.setAttributeProperties( 'testAttribute', {
+				second: 'bar'
+			} );
+
+			expect( schema.getAttributeProperties( 'testAttribute' ) ).to.deep.equal( {
+				first: 'foo',
+				second: 'bar'
+			} );
+		} );
+	} );
+
 	describe( 'getDefinitions()', () => {
 		it( 'returns compiled definitions', () => {
 			schema.register( '$root' );