Преглед изворни кода

Support for keeping any value as fontSize attribute.

Kamil Piechaczek пре 5 година
родитељ
комит
b9f5a4e0de

+ 67 - 9
packages/ckeditor5-font/src/fontsize/fontsizeediting.js

@@ -48,7 +48,22 @@ export default class FontSizeEditing extends Plugin {
 				'default',
 				'big',
 				'huge'
-			]
+			],
+			disableValueMatching: false
+		} );
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	init() {
+		const editor = this.editor;
+
+		// Allow fontSize attribute on text nodes.
+		editor.model.schema.extend( '$text', { allowAttributes: FONT_SIZE } );
+		editor.model.schema.setAttributeProperties( FONT_SIZE, {
+			isFormatting: true,
+			copyOnEnter: true
 		} );
 
 		// Define view to model conversion.
@@ -56,23 +71,66 @@ export default class FontSizeEditing extends Plugin {
 		const definition = buildDefinition( FONT_SIZE, options );
 
 		// Set-up the two-way conversion.
-		editor.conversion.attributeToElement( definition );
+		if ( editor.config.get( 'fontSize.disableValueMatching' ) ) {
+			this._prepareAnyValueConverters();
+		} else {
+			editor.conversion.attributeToElement( definition );
+		}
 
 		// Add FontSize command.
 		editor.commands.add( FONT_SIZE, new FontSizeCommand( editor ) );
 	}
 
 	/**
-	 * @inheritDoc
+	 * Those converters enable keeping any value found as `style="font-size: *"` as a value of an attribute on a text even
+	 * if it isn't defined in the plugin configuration.
+	 *
+	 * @private
 	 */
-	init() {
+	_prepareAnyValueConverters() {
 		const editor = this.editor;
 
-		// Allow fontSize attribute on text nodes.
-		editor.model.schema.extend( '$text', { allowAttributes: FONT_SIZE } );
-		editor.model.schema.setAttributeProperties( FONT_SIZE, {
-			isFormatting: true,
-			copyOnEnter: true
+		editor.conversion.for( 'downcast' ).attributeToElement( {
+			model: FONT_SIZE,
+			view: ( attributeValue, writer ) => {
+				if ( !attributeValue ) {
+					return;
+				}
+
+				if ( String( attributeValue ).match( /^\d+/ ) ) {
+					if ( typeof attributeValue == 'number' ) {
+						attributeValue = `${ attributeValue }px`;
+					}
+
+					return writer.createAttributeElement( 'span', { style: 'font-size:' + attributeValue }, { priority: 7 } );
+				}
+
+				return writer.createAttributeElement( 'span', { class: 'text-' + attributeValue }, { priority: 7 } );
+			}
+		} );
+
+		editor.conversion.for( 'upcast' ).attributeToAttribute( {
+			model: {
+				key: FONT_SIZE,
+				value: viewElement => {
+					const fontSize = viewElement.getStyle( 'font-size' );
+
+					if ( fontSize ) {
+						return fontSize;
+					}
+
+					for ( const className of viewElement.getClassNames() ) {
+						if ( className.startsWith( 'text-' ) ) {
+							return className.replace( /^text-/, '' );
+						}
+					}
+
+					return null;
+				}
+			},
+			view: {
+				name: 'span'
+			}
 		} );
 	}
 }

+ 77 - 0
packages/ckeditor5-font/tests/fontsize/fontsizeediting.js

@@ -56,6 +56,83 @@ describe( 'FontSizeEditing', () => {
 		describe( 'default value', () => {
 			it( 'should be set', () => {
 				expect( editor.config.get( 'fontSize.options' ) ).to.deep.equal( [ 'tiny', 'small', 'default', 'big', 'huge' ] );
+				expect( editor.config.get( 'fontSize.disableValueMatching' ) ).to.equal( false );
+			} );
+		} );
+
+		describe( 'disableValueMatching=true', () => {
+			let editor, doc;
+
+			beforeEach( () => {
+				return VirtualTestEditor
+					.create( {
+						plugins: [ FontSizeEditing, Paragraph ],
+						fontSize: {
+							options: [
+								'default',
+							],
+							disableValueMatching: true
+						}
+					} )
+					.then( newEditor => {
+						editor = newEditor;
+
+						doc = editor.model;
+					} );
+			} );
+
+			afterEach( () => {
+				return editor.destroy();
+			} );
+
+			describe( 'editing pipeline conversion', () => {
+				it( 'should pass fontSize to data', () => {
+					setModelData( doc, '<paragraph>f<$text fontSize="10px">o</$text>o</paragraph>' );
+
+					expect( editor.getData() ).to.equal( '<p>f<span style="font-size:10px;">o</span>o</p>' );
+				} );
+
+				it( 'should add a unit to value if missing', () => {
+					setModelData( doc, '<paragraph>f<$text fontSize="10">o</$text>o</paragraph>' );
+
+					expect( editor.getData() ).to.equal( '<p>f<span style="font-size:10px;">o</span>o</p>' );
+				} );
+
+				it( 'should convert a text value as a class', () => {
+					setModelData( doc, '<paragraph>f<$text fontSize="large">o</$text>o</paragraph>' );
+
+					expect( editor.getData() ).to.equal( '<p>f<span class="text-large">o</span>o</p>' );
+				} );
+			} );
+
+			describe( 'data pipeline conversions', () => {
+				it( 'should convert from an element with defined style when with other styles', () => {
+					const data = '<p>f<span style="font-family: Other;font-size: 18px">o</span>o</p>';
+
+					editor.setData( data );
+
+					expect( getModelData( doc ) ).to.equal( '<paragraph>[]f<$text fontSize="18px">o</$text>o</paragraph>' );
+
+					expect( editor.getData() ).to.equal( '<p>f<span style="font-size:18px;">o</span>o</p>' );
+				} );
+
+				it( 'should convert an element if it has a class that starts with "text-"', () => {
+					const data = '<p>f<span class="text-huge">o</span>o</p>';
+
+					editor.setData( data );
+
+					expect( getModelData( doc ) ).to.equal( '<paragraph>[]f<$text fontSize="huge">o</$text>o</paragraph>' );
+
+					expect( editor.getData() ).to.equal( data );
+				} );
+
+				it( 'should ignore an element if does not have a class that starts with "text-"', () => {
+					editor.setData( '<p>f<span class="foo">o</span>o</p>' );
+
+					expect( getModelData( doc ) ).to.equal( '<paragraph>[]foo</paragraph>' );
+
+					expect( editor.getData() ).to.equal( '<p>foo</p>' );
+				} );
 			} );
 		} );
 	} );