|
|
@@ -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 );
|
|
|
}
|