Explorar el Código

Simplified the implementation and extended configuration options.

Kamil Piechaczek hace 5 años
padre
commit
80d529fcfe

+ 2 - 24
packages/ckeditor5-font/src/fontsize/fontsizeediting.js

@@ -10,7 +10,7 @@
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 
 import FontSizeCommand from './fontsizecommand';
-import { normalizeOptions, FONT_SIZE_PRESET_UNITS } from './utils';
+import { normalizeOptions } from './utils';
 import { buildDefinition, FONT_SIZE } from '../utils';
 
 /**
@@ -100,10 +100,6 @@ export default class FontSizeEditing extends Plugin {
 					return;
 				}
 
-				if ( typeof attributeValue == 'number' ) {
-					attributeValue = `${ attributeValue }px`;
-				}
-
 				return writer.createAttributeElement( 'span', { style: 'font-size:' + attributeValue }, { priority: 7 } );
 			}
 		} );
@@ -111,25 +107,7 @@ export default class FontSizeEditing extends Plugin {
 		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-' ) ) {
-							const presetName = className.replace( /^text-/, '' );
-
-							if ( FONT_SIZE_PRESET_UNITS[ presetName ] ) {
-								return FONT_SIZE_PRESET_UNITS[ presetName ];
-							}
-						}
-					}
-
-					return null;
-				}
+				value: viewElement => viewElement.getStyle( 'font-size' ),
 			},
 			view: {
 				name: 'span'

+ 131 - 57
packages/ckeditor5-font/src/fontsize/utils.js

@@ -7,6 +7,8 @@
  * @module font/fontsize/utils
  */
 
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 /**
  * Normalizes and translates the {@link module:font/fontsize~FontSizeConfig#options configuration options}
  * to the {@link module:font/fontsize~FontSizeOption} format.
@@ -34,43 +36,51 @@ export const FONT_SIZE_PRESET_UNITS = {
 	huge: '1.8em'
 };
 
-// Default named presets map.
+// Default named presets map. Always create a new instance of the preset object in order to avoid modifying references.
 const namedPresets = {
-	tiny: {
-		title: 'Tiny',
-		model: 'tiny',
-		view: {
-			name: 'span',
-			classes: 'text-tiny',
-			priority: 7
-		}
+	get tiny() {
+		return {
+			title: 'Tiny',
+			model: 'tiny',
+			view: {
+				name: 'span',
+				classes: 'text-tiny',
+				priority: 7
+			}
+		};
 	},
-	small: {
-		title: 'Small',
-		model: 'small',
-		view: {
-			name: 'span',
-			classes: 'text-small',
-			priority: 7
-		}
+	get small() {
+		return {
+			title: 'Small',
+			model: 'small',
+			view: {
+				name: 'span',
+				classes: 'text-small',
+				priority: 7
+			}
+		};
 	},
-	big: {
-		title: 'Big',
-		model: 'big',
-		view: {
-			name: 'span',
-			classes: 'text-big',
-			priority: 7
-		}
+	get big() {
+		return {
+			title: 'Big',
+			model: 'big',
+			view: {
+				name: 'span',
+				classes: 'text-big',
+				priority: 7
+			}
+		};
 	},
-	huge: {
-		title: 'Huge',
-		model: 'huge',
-		view: {
-			name: 'span',
-			classes: 'text-huge',
-			priority: 7
-		}
+	get huge() {
+		return {
+			title: 'Huge',
+			model: 'huge',
+			view: {
+				name: 'span',
+				classes: 'text-huge',
+				priority: 7
+			}
+		};
 	}
 };
 
@@ -82,20 +92,20 @@ const namedPresets = {
 // @param {Boolean} disableValueMatching
 // @returns {undefined|module:font/fontsize~FontSizeOption}
 function getOptionDefinition( option, disableValueMatching ) {
-	// Treat any object as full item definition provided by user in configuration.
-	if ( typeof option === 'object' ) {
-		return option;
+	// Check whether passed option is a full item definition provided by user in configuration.
+	if ( isFullItemDefinition( option ) ) {
+		return attachPriority( option );
 	}
 
-	// Item is a named preset.
-	if ( namedPresets[ option ] ) {
-		const preset = namedPresets[ option ];
+	const preset = findPreset( option );
 
+	// Item is a named preset.
+	if ( preset ) {
 		if ( disableValueMatching ) {
 			preset.model = FONT_SIZE_PRESET_UNITS[ option ];
 		}
 
-		return preset;
+		return attachPriority( preset );
 	}
 
 	// 'Default' font size. It will be used to remove the fontSize attribute.
@@ -107,33 +117,97 @@ function getOptionDefinition( option, disableValueMatching ) {
 	}
 
 	// At this stage we probably have numerical value to generate a preset so parse it's value.
-	const sizePreset = parseFloat( option );
-
 	// Discard any faulty values.
-	if ( isNaN( sizePreset ) ) {
+	if ( isNumericalDefinition( option ) ) {
 		return;
 	}
 
 	// Return font size definition from size value.
-	return generatePixelPreset( sizePreset );
+	return generatePixelPreset( option );
 }
 
 // Creates a predefined preset for pixel size.
 //
-// @param {Number} size Font size in pixels.
+// @param {Number} definition Font size in pixels.
 // @returns {module:font/fontsize~FontSizeOption}
-function generatePixelPreset( size ) {
-	const sizeName = String( size );
-
-	return {
-		title: sizeName,
-		model: size,
-		view: {
-			name: 'span',
-			styles: {
-				'font-size': `${ size }px`
-			},
-			priority: 7
+function generatePixelPreset( definition ) {
+	// Extend a short (numeric value) definition.
+	if ( typeof definition === 'number' || typeof definition === 'string' ) {
+		definition = {
+			title: String( definition ),
+			model: `${ parseFloat( definition ) }px`
+		};
+	}
+
+	definition.view = {
+		name: 'span',
+		styles: {
+			'font-size': definition.model
 		}
 	};
+
+	return attachPriority( definition );
+}
+
+// Adds the priority to the view element definition if missing. It's required due to ckeditor/ckeditor5#2291
+//
+// @param {Object} definition
+// @param {Object} definition.title
+// @param {Object} definition.model
+// @param {Object} definition.view
+// @returns {Object}
+function attachPriority( definition ) {
+	if ( !definition.view.priority ) {
+		definition.view.priority = 7;
+	}
+
+	return definition;
+}
+
+// Returns a prepared preset definition. If passed an object, a name of preset should be defined as `model` value.
+//
+// @param {String|Object} definition
+// @param {String} definition.model A preset name.
+// @returns {Object|undefined}
+function findPreset( definition ) {
+	return namedPresets[ definition ] || namedPresets[ definition.model ];
+}
+
+// We treat `definition` as completed if it is an object that contains `title`, `model` and `view` values.
+//
+// @param {Object} definition
+// @param {String} definition.title
+// @param {String} definition.model
+// @param {Object} definition.view
+// @returns {Boolean}
+function isFullItemDefinition( definition ) {
+	return typeof definition === 'object' && definition.title && definition.model && definition.view;
+}
+
+// We treat `definition` as numerical if it is a number, number-like (string) or an object with the `title` key.
+//
+// @param {Object|Number|String} definition
+// @param {Object} definition.title
+// @returns {Boolean}
+function isNumericalDefinition( definition ) {
+	let numberValue;
+
+	if ( typeof definition === 'object' ) {
+		if ( !definition.model ) {
+			/**
+			 * Provided value as an option for {@link module:font/fontsize~FontSize} seems to invalid.
+			 *
+			 * See valid examples described in the {@link module:font/fontsize~FontSizeConfig#options plugin configuration}.
+			 *
+			 * @error font-size-invalid-definition
+			 */
+			throw new CKEditorError( 'font-size-invalid-definition: Provided font size definition is invalid.', null, definition );
+		} else {
+			numberValue = parseFloat( definition.model );
+		}
+	} else {
+		numberValue = parseFloat( definition );
+	}
+
+	return isNaN( numberValue );
 }