ソースを参照

Docs: Update FontFamily documentation.

Maciej Gołaszewski 8 年 前
コミット
f813768f08

+ 107 - 60
packages/ckeditor5-font/src/fontfamily/fontfamilyediting.js

@@ -27,9 +27,8 @@ export default class FontFamilyEditing extends Plugin {
 	constructor( editor ) {
 		super( editor );
 
-		// Define default configuration using named presets
 		editor.config.define( 'fontFamily', {
-			items: [
+			options: [
 				'default',
 				'Arial, Helvetica, sans-serif',
 				'Courier New, Courier, monospace',
@@ -41,46 +40,43 @@ export default class FontFamilyEditing extends Plugin {
 				'Verdana, Geneva, sans-serif'
 			]
 		} );
-
-		// Get configuration
-		const data = editor.data;
-		const editing = editor.editing;
-
-		// Add converters from view to model.
-		const items = this.configuredItems.filter( item => item.model );
-
-		for ( const item of items ) {
-			viewToModelAttribute( 'fontFamily', item, [ data.viewToModel ] );
-		}
-
-		// Covert from model to view.
-		modelAttributeToViewAttributeElement( 'fontFamily', items, [ data.modelToView, editing.modelToView ] );
-
-		// Add FontSize command.
-		editor.commands.add( 'fontFamily', new FontFamilyCommand( editor ) );
 	}
 
-	get configuredItems() {
+	/**
+	 * Returns {@link module:font/fontfamily/fontfamilyediting~FontFamilyConfig#options} array with options normalized in the
+	 * {@link module:font/fontfamily/fontfamilyediting~FontFamilyOption} format, translated
+	 * `title` for each style.
+	 *
+	 * @readonly
+	 * @type {Array.<module:font/fontfamily/fontfamilyediting/imagestyleengine~ImageStyleFormat>}
+	 */
+	get configuredOptions() {
 		// Cache value
-		if ( this._cachedItems ) {
-			return this._cachedItems;
+		if ( this._cachedOptions ) {
+			return this._cachedOptions;
 		}
 
-		const items = [];
 		const editor = this.editor;
-		const config = editor.config;
+		const t = editor.t;
 
-		const configuredItems = config.get( 'fontFamily.items' );
+		const options = [];
+		const configuredOptions = editor.config.get( 'fontFamily.options' );
 
-		for ( const item of configuredItems ) {
+		for ( const item of configuredOptions ) {
 			const itemDefinition = getItemDefinition( item );
 
+			// Set only valid definitions.
 			if ( itemDefinition ) {
-				items.push( itemDefinition );
+				// Localize the "Default" title if set.
+				if ( itemDefinition.title === 'Default' ) {
+					itemDefinition.title = t( 'Default' );
+				}
+
+				options.push( itemDefinition );
 			}
 		}
 
-		return ( this._cachedItems = items );
+		return ( this._cachedOptions = options );
 	}
 
 	/**
@@ -88,29 +84,45 @@ export default class FontFamilyEditing extends Plugin {
 	 */
 	init() {
 		const editor = this.editor;
+		const data = editor.data;
+		const editing = editor.editing;
 
 		// Allow highlight attribute on all elements
 		editor.model.schema.allow( { name: '$inline', attributes: 'fontFamily', inside: '$block' } );
 		// Temporary workaround. See https://github.com/ckeditor/ckeditor5/issues/477.
 		editor.model.schema.allow( { name: '$inline', attributes: 'fontFamily', inside: '$clipboardHolder' } );
+
+		// Get configured font family options without "default" option.
+		const fontFamilyOptions = this.configuredOptions.filter( item => item.model );
+
+		// Define view to model conversion.
+		for ( const item of fontFamilyOptions ) {
+			viewToModelAttribute( 'fontFamily', item, [ data.viewToModel ] );
+		}
+
+		// Define model to view conversion.
+		modelAttributeToViewAttributeElement( 'fontFamily', fontFamilyOptions, [ data.modelToView, editing.modelToView ] );
+
+		editor.commands.add( 'fontFamily', new FontFamilyCommand( editor ) );
 	}
 }
 
 // Returns item definition from preset
 function getItemDefinition( item ) {
-	// Probably it is full item definition so return it
+	// Probably it is full item definition so return it.
 	if ( typeof item === 'object' ) {
 		return item;
 	}
 
+	// Handle 'default' string as a special case. It will be used to remove the fontFamily attribute.
 	if ( item === 'default' ) {
 		return {
-			title: 'Default', // TODO localize us
+			title: 'Default',
 			model: undefined
 		};
 	}
 
-	// Ignore falsy values
+	// Ignore values that we cannot parse to a definition.
 	if ( typeof item !== 'string' ) {
 		return;
 	}
@@ -118,21 +130,33 @@ function getItemDefinition( item ) {
 	return generateFontPreset( item );
 }
 
-// Creates a predefined preset for pixel size.
-function generateFontPreset( font ) {
-	// Remove quotes from font names
-	const fontNames = font.replace( /"|'/g, '' ).split( ',' );
-
-	const cssFontNames = fontNames.map( normalizeFontName );
+// Creates a predefined preset for pixel size. It deconstructs font-family like string into full configuration option.
+// A font definition is passed as coma delimited set of font family names. Font names might be quoted.
+//
+// @param {String} A font definition form configuration.
+function generateFontPreset( fontDefinition ) {
+	// Remove quotes from font names - will be normalized later.
+	const fontNames = fontDefinition.replace( /"|'/g, '' ).split( ',' );
 
+	// The first matched font name will be used as dropdown list item title and as model value
 	const firstFontName = fontNames[ 0 ];
 
-	const quotesMatch = '("|\'|&qout;|\\W){0,2}';
+	const cssFontNames = fontNames.map( normalizeFontName );
 
+	// TODO: Maybe we can come with something better here?
+	// TODO: Also document this behavior in engine as it uses matcher~Pattern not ViewElementDefinition.
+	// TODO: Maybe a better solution will be a callback here? (also needs documentation)
+	// This will match any quote type with whitespace.
+	const quotesMatch = '("|\'|&qout;|\\W){0,2}';
+	// Full regex will catch any style of quotation used in view.
+	// Example:
+	// from string: "Font Foo Foo, Font Bar"
+	// it will create a regex that will match any quotation mix:
+	//     - "Font Foo Foo", Font Bar
+	//     - 'Font Foo Foo', "Font Bar"
+	//     - ... etc.
 	const regexString = `${ quotesMatch }${ fontNames.map( n => n.trim() ).join( `${ quotesMatch },${ quotesMatch }` ) }${ quotesMatch }`;
 
-	const fontFamilyRegexp = new RegExp( regexString );
-
 	return {
 		title: firstFontName,
 		model: firstFontName,
@@ -146,21 +170,21 @@ function generateFontPreset( font ) {
 			{
 				name: 'span',
 				style: {
-					'font-family': fontFamilyRegexp
+					'font-family': new RegExp( regexString )
 				}
 			}
 		]
 	};
 }
 
-/**
- *
- * @param fontName
- * @returns {string|*}
- */
+// Normalizes font name for the view style attribute.
+//
+// @param {String} fontName
+// @returns {String}
 function normalizeFontName( fontName ) {
 	fontName = fontName.trim();
 
+	// Compound font names should be quoted.
 	if ( fontName.indexOf( ' ' ) > 0 ) {
 		fontName = `'${ fontName }'`;
 	}
@@ -169,17 +193,22 @@ function normalizeFontName( fontName ) {
 }
 
 /**
- * Font family option descriptor.
+ * Font family option. Compatible with {@link module:engine/conversion/definition-based-converters~ConverterDefinition}.
  *
  * @typedef {Object} module:font/fontfamily/fontfamilyediting~FontFamilyOption
  *
- * @property {String} title TODO me
- * @property {String} model TODO me
- * @property {module:engine/view/viewelementdefinition~ViewElementDefinition} view View element configuration.
+ * @property {String} model The `fontFamily` attribute value in the model.
+ * @property {module:engine/view/viewelementdefinition~ViewElementDefinition} view The view representation for that option.
+ * @property {String} title The user-readable title of the option.
+ * @property {String} [uiStyle] The style which will be added to the dropdown item representing this option.
+ * Defaults to `view.style[ 'font-family' ]`.
+ * @property {Array.<module:engine/view/viewelementdefinition~ViewElementDefinition>} acceptAlso An array with all matched elements that
+ * view to model conversion should also accept.
  */
 
 /**
- * The configuration of the heading feature. Introduced by the {@link module:font/fontfamily/fontfamilyediting~FontSizeEditing} feature.
+ * The configuration of the font family feature.
+ * Introduced by the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} feature.
  *
  * Read more in {@link module:font/fontfamily/fontfamilyediting~FontFamilyConfig}.
  *
@@ -188,14 +217,14 @@ function normalizeFontName( fontName ) {
 
 /**
  * The configuration of the font family feature.
- * The option is used by the {@link module:font/fontfamily/fontfamilyediting~FontSizeEditing} feature.
+ * The option is used by the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} feature.
  *
- *        ClassicEditor
- *            .create( {
+ *		ClassicEditor
+ *			.create( {
  * 				fontFamily: ... // Font family feature config.
  *			} )
- *            .then( ... )
- *            .catch( ... );
+ *			.then( ... )
+ *			.catch( ... );
  *
  * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.
  *
@@ -206,9 +235,27 @@ function normalizeFontName( fontName ) {
  * Available font family options. Defined either as array of strings.
  *
  * The default value is
- * TODO code
- * which configures
  *
- * @member {Array.<String|Number|module:font/fontfamily/fontfamilyediting~FontFamilyOption>}
- *  module:font/fontfamily/fontfamilyediting~FontFamilyConfig#items
+ *		const fontFamilyConfig = {
+ *			options: [
+ *				'default',
+ *				'Arial, Helvetica, sans-serif',
+ *				'Courier New, Courier, monospace',
+ *				'Georgia, serif',
+ *				'Lucida Sans Unicode, Lucida Grande, sans-serif',
+ *				'Tahoma, Geneva, sans-serif',
+ *				'Times New Roman, Times, serif',
+ *				'Trebuchet MS, Helvetica, sans-serif',
+ *				'Verdana, Geneva, sans-serif'
+ *			]
+ *		};
+ *
+ * which configures 8 font family options and a default option that will remove font family to text default setting (defaulting to content
+ * CSS styles).
+ *
+ * TODO: what 'default' does.
+ * TODO: how those string are translated to configuration
+ *
+ * @member {Array.<String|module:font/fontfamily/fontfamilyediting~FontFamilyOption>}
+ *  module:font/fontfamily/fontfamilyediting~FontFamilyConfig#options
  */

+ 2 - 2
packages/ckeditor5-font/src/fontfamily/fontfamilyui.js

@@ -105,9 +105,9 @@ export default class FontFamilyUI extends Plugin {
 		};
 
 		// TODO this is not nice :/ in terms of feature split.
-		const items = editor.plugins.get( FontFamilyEditing ).configuredItems;
+		const options = editor.plugins.get( FontFamilyEditing ).configuredOptions;
 
-		return items.map( option => {
+		return options.map( option => {
 			const title = localizedTitles[ option.title ];
 
 			if ( title && title != option.title ) {

+ 10 - 10
packages/ckeditor5-font/tests/fontfamily/fontfamilyediting.js

@@ -37,7 +37,7 @@ describe( 'FontFamilyEditing', () => {
 	describe( 'config', () => {
 		describe( 'default value', () => {
 			it( 'should be set', () => {
-				expect( editor.config.get( 'fontFamily.items' ) ).to.deep.equal( [
+				expect( editor.config.get( 'fontFamily.options' ) ).to.deep.equal( [
 					'default',
 					'Arial, Helvetica, sans-serif',
 					'Courier New, Courier, monospace',
@@ -52,13 +52,13 @@ describe( 'FontFamilyEditing', () => {
 		} );
 	} );
 
-	describe( 'configuredItems', () => {
+	describe( 'configuredOptions', () => {
 		it( 'should discard unparsable values', () => {
 			return VirtualTestEditor
 				.create( {
 					plugins: [ FontFamilyEditing ],
 					fontFamily: {
-						items: [ () => {}, 0, true ]
+						options: [ () => {}, 0, true ]
 					}
 				} )
 				.then( newEditor => {
@@ -66,7 +66,7 @@ describe( 'FontFamilyEditing', () => {
 
 					const plugin = editor.plugins.get( FontFamilyEditing );
 
-					expect( plugin.configuredItems ).to.deep.equal( [] );
+					expect( plugin.configuredOptions ).to.deep.equal( [] );
 				} );
 		} );
 
@@ -75,7 +75,7 @@ describe( 'FontFamilyEditing', () => {
 				.create( {
 					plugins: [ FontFamilyEditing ],
 					fontFamily: {
-						items: [
+						options: [
 							'default',
 							{
 								title: 'Comic Sans',
@@ -95,7 +95,7 @@ describe( 'FontFamilyEditing', () => {
 
 					const plugin = editor.plugins.get( FontFamilyEditing );
 
-					expect( plugin.configuredItems ).to.deep.equal( [
+					expect( plugin.configuredOptions ).to.deep.equal( [
 						{
 							model: undefined,
 							title: 'Default'
@@ -120,7 +120,7 @@ describe( 'FontFamilyEditing', () => {
 					.create( {
 						plugins: [ FontFamilyEditing ],
 						fontFamily: {
-							items: [
+							options: [
 								'Arial',
 								'"Comic Sans MS", sans-serif',
 								'Lucida Console, \'Courier New\', Courier, monospace'
@@ -132,7 +132,7 @@ describe( 'FontFamilyEditing', () => {
 
 						const plugin = editor.plugins.get( FontFamilyEditing );
 
-						expect( plugin.configuredItems ).to.deep.equal( [
+						expect( plugin.configuredOptions ).to.deep.equal( [
 							{
 								title: 'Arial',
 								model: 'Arial',
@@ -207,7 +207,7 @@ describe( 'FontFamilyEditing', () => {
 				.create( {
 					plugins: [ FontFamilyEditing, Paragraph ],
 					fontFamily: {
-						items: [
+						options: [
 							'Arial',
 							'Lucida Sans Unicode, Lucida Grande, sans-serif',
 							{
@@ -260,7 +260,7 @@ describe( 'FontFamilyEditing', () => {
 				.create( {
 					plugins: [ FontFamilyEditing, Paragraph ],
 					fontFamily: {
-						items: [
+						options: [
 							'Lucida Sans Unicode, Lucida Grande, sans-serif',
 							{
 								title: 'My other setting',