|
|
@@ -16,10 +16,24 @@ import DropdownButtonView from '@ckeditor/ckeditor5-ui/src/dropdown/button/dropd
|
|
|
import Model from '@ckeditor/ckeditor5-ui/src/model';
|
|
|
import Collection from '@ckeditor/ckeditor5-utils/src/collection';
|
|
|
|
|
|
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
|
|
|
+
|
|
|
+import iconSmall from '@ckeditor/ckeditor5-core/theme/icons/object-size-small.svg';
|
|
|
+import iconMedium from '@ckeditor/ckeditor5-core/theme/icons/object-size-medium.svg';
|
|
|
+import iconLarge from '@ckeditor/ckeditor5-core/theme/icons/object-size-large.svg';
|
|
|
+import iconFull from '@ckeditor/ckeditor5-core/theme/icons/object-size-full.svg';
|
|
|
+
|
|
|
+const RESIZE_ICONS = {
|
|
|
+ small: iconSmall,
|
|
|
+ medium: iconMedium,
|
|
|
+ large: iconLarge,
|
|
|
+ original: iconFull
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* The `ImageResizeUI` plugin.
|
|
|
*
|
|
|
- * It adds a possibility to resize each image using toolbar dropdown or separate buttons, depends on the plugin configuration.
|
|
|
+ * It adds a possibility to resize images using the toolbar dropdown or individual buttons, depending on the plugin configuration.
|
|
|
*
|
|
|
* @extends module:core/plugin~Plugin
|
|
|
*/
|
|
|
@@ -41,11 +55,27 @@ export default class ImageResizeUI extends Plugin {
|
|
|
/**
|
|
|
* @inheritDoc
|
|
|
*/
|
|
|
+ constructor( editor ) {
|
|
|
+ super( editor );
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The resize unit.
|
|
|
+ *
|
|
|
+ * @readonly
|
|
|
+ * @private
|
|
|
+ * @type {module:image/image~ImageConfig#resizeUnit}
|
|
|
+ * @default '%'
|
|
|
+ */
|
|
|
+ this._resizeUnit = editor.config.get( 'image.resizeUnit' ) || '%';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @inheritDoc
|
|
|
+ */
|
|
|
init() {
|
|
|
const editor = this.editor;
|
|
|
const options = editor.config.get( 'image.resizeOptions' );
|
|
|
const command = editor.commands.get( 'imageResize' );
|
|
|
- const resizeUnit = editor.config.get( 'image.resizeUnit' ) || '%';
|
|
|
|
|
|
if ( !options ) {
|
|
|
return;
|
|
|
@@ -54,44 +84,62 @@ export default class ImageResizeUI extends Plugin {
|
|
|
this.bind( 'isEnabled' ).to( command );
|
|
|
|
|
|
for ( const option of options ) {
|
|
|
- this._addButton( option, resizeUnit );
|
|
|
+ this._registerImageResizeButton( option );
|
|
|
}
|
|
|
|
|
|
- this._addDropdown( options, resizeUnit );
|
|
|
+ this._registerImageResizeDropdown( options );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* A helper function that creates a standalone button component for the plugin.
|
|
|
*
|
|
|
* @private
|
|
|
- *
|
|
|
* @param {module:image/imageresize/imageresizeui~ImageResizeOption} resizeOption A model of resize option.
|
|
|
- * @param {String} unit A resize unit.
|
|
|
*/
|
|
|
- _addButton( { name, label, value }, unit ) {
|
|
|
+ _registerImageResizeButton( option ) {
|
|
|
const editor = this.editor;
|
|
|
- const t = editor.t;
|
|
|
- const parsedValue = value ? value + unit : null;
|
|
|
+ const { name, value, icon } = option;
|
|
|
+ const optionValueWithUnit = value ? value + this._resizeUnit : null;
|
|
|
|
|
|
editor.ui.componentFactory.add( name, locale => {
|
|
|
const button = new ButtonView( locale );
|
|
|
const command = editor.commands.get( 'imageResize' );
|
|
|
- const commandCallback = setOptionOn( parsedValue );
|
|
|
+ const labelText = this._getOptionLabelValue( option, true );
|
|
|
+
|
|
|
+ if ( !RESIZE_ICONS[ icon ] ) {
|
|
|
+ /**
|
|
|
+ * When configuring {@link module:image/image~ImageConfig#resizeOptions `config.image.resizeOptions`} for standalone
|
|
|
+ * buttons, a valid `icon` token must be set for each option.
|
|
|
+ *
|
|
|
+ * See all valid options described in the
|
|
|
+ * {@link module:image/imageresize/imageresizeui~ImageResizeOption plugin configuration}.
|
|
|
+ *
|
|
|
+ * @error imageresizeui-missing-icon
|
|
|
+ * @param {module:image/imageresize/imageresizeui~ImageResizeOption} option Invalid image resize option.
|
|
|
+ */
|
|
|
+ throw new CKEditorError(
|
|
|
+ 'imageresizeui-missing-icon: ' +
|
|
|
+ 'The resize option "' + name + '" misses the "icon" property ' +
|
|
|
+ 'or the property value doesn\'t match any of available icons.',
|
|
|
+ editor,
|
|
|
+ option
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
button.set( {
|
|
|
- label: t( label ),
|
|
|
- withText: true,
|
|
|
- tooltip: parsedValue ? t( 'Resize image to' ) + ' ' + parsedValue : t( 'Resize image to the original size' ),
|
|
|
- isToggleable: true,
|
|
|
- commandValue: parsedValue
|
|
|
+ // Use the `label` property for a verbose description (because of ARIA).
|
|
|
+ label: labelText,
|
|
|
+ icon: RESIZE_ICONS[ icon ],
|
|
|
+ tooltip: labelText,
|
|
|
+ isToggleable: true
|
|
|
} );
|
|
|
|
|
|
// Bind button to the command.
|
|
|
button.bind( 'isEnabled' ).to( this );
|
|
|
- button.bind( 'isOn' ).to( command, 'value', commandCallback );
|
|
|
+ button.bind( 'isOn' ).to( command, 'value', getIsOnButtonCallback( optionValueWithUnit ) );
|
|
|
|
|
|
- this.listenTo( button, 'execute', evt => {
|
|
|
- editor.execute( 'imageResize', { width: evt.source.commandValue } );
|
|
|
+ this.listenTo( button, 'execute', () => {
|
|
|
+ editor.execute( 'imageResize', { width: optionValueWithUnit } );
|
|
|
} );
|
|
|
|
|
|
return button;
|
|
|
@@ -99,19 +147,16 @@ export default class ImageResizeUI extends Plugin {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * A helper function that creates a dropdown component for the plugin containing all resize options created through the
|
|
|
- * plugin configuration settings.
|
|
|
+ * A helper function that creates a dropdown component for the plugin containing all resize options defined in
|
|
|
+ * the editor configuration.
|
|
|
*
|
|
|
* @private
|
|
|
- *
|
|
|
- * @param {Array.<module:image/imageresize/imageresizeui~ImageResizeOption>} options An array of the configured options.
|
|
|
- * @param {String} unit A resize unit.
|
|
|
+ * @param {Array.<module:image/imageresize/imageresizeui~ImageResizeOption>} options An array of configured options.
|
|
|
*/
|
|
|
- _addDropdown( options, unit ) {
|
|
|
+ _registerImageResizeDropdown( options ) {
|
|
|
const editor = this.editor;
|
|
|
const t = editor.t;
|
|
|
- const firstOption = options[ 0 ];
|
|
|
- const resetOption = options.find( option => option.value === null );
|
|
|
+ const originalSizeOption = options.find( option => !option.value );
|
|
|
|
|
|
// Register dropdown.
|
|
|
editor.ui.componentFactory.add( 'imageResize', locale => {
|
|
|
@@ -121,19 +166,25 @@ export default class ImageResizeUI extends Plugin {
|
|
|
|
|
|
dropdownButton.set( {
|
|
|
tooltip: t( 'Resize image' ),
|
|
|
- commandValue: firstOption.value,
|
|
|
+ commandValue: originalSizeOption.value,
|
|
|
+ icon: iconMedium,
|
|
|
isToggleable: true,
|
|
|
- label: firstOption.label,
|
|
|
- withText: true
|
|
|
+ label: this._getOptionLabelValue( originalSizeOption ),
|
|
|
+ withText: true,
|
|
|
+ class: 'ck-resize-image-button'
|
|
|
} );
|
|
|
|
|
|
dropdownButton.bind( 'label' ).to( command, 'value', commandValue => {
|
|
|
- return commandValue && commandValue.width || resetOption.label;
|
|
|
+ if ( commandValue && commandValue.width ) {
|
|
|
+ return commandValue.width;
|
|
|
+ } else {
|
|
|
+ return this._getOptionLabelValue( originalSizeOption );
|
|
|
+ }
|
|
|
} );
|
|
|
dropdownView.bind( 'isOn' ).to( command );
|
|
|
dropdownView.bind( 'isEnabled' ).to( this );
|
|
|
|
|
|
- addListToDropdown( dropdownView, prepareListDefinitions( options, command, unit ) );
|
|
|
+ addListToDropdown( dropdownView, this._getResizeDropdownListItemDefinitions( options, command ) );
|
|
|
|
|
|
dropdownView.listView.ariaLabel = t( 'Image resize list' );
|
|
|
|
|
|
@@ -146,40 +197,73 @@ export default class ImageResizeUI extends Plugin {
|
|
|
return dropdownView;
|
|
|
} );
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-// A helper function for parsing resize options definitions.
|
|
|
-function prepareListDefinitions( definitions, command, resizeUnit ) {
|
|
|
- const itemDefinitions = new Collection();
|
|
|
-
|
|
|
- definitions.map( itemDefinition => {
|
|
|
- const parsedValue = itemDefinition.value ? itemDefinition.value + resizeUnit : null;
|
|
|
- const definition = {
|
|
|
- type: 'button',
|
|
|
- model: new Model( {
|
|
|
- commandName: 'imageResize',
|
|
|
- commandValue: parsedValue,
|
|
|
- label: itemDefinition.label,
|
|
|
- withText: true,
|
|
|
- icon: null
|
|
|
- } )
|
|
|
- };
|
|
|
-
|
|
|
- const commandCallback = setOptionOn( parsedValue );
|
|
|
-
|
|
|
- definition.model.bind( 'isOn' ).to( command, 'value', commandCallback );
|
|
|
+ /**
|
|
|
+ * A helper function for creating an option label value string.
|
|
|
+ *
|
|
|
+ * @private
|
|
|
+ * @param {module:image/imageresize/imageresizeui~ImageResizeOption} option A resize option object.
|
|
|
+ * @param {Boolean} [forTooltip] An optional flag for creating a tooltip label.
|
|
|
+ * @returns {String} A user-defined label, a label combined from the value and resize unit or the default label
|
|
|
+ * for reset options (`Original`).
|
|
|
+ */
|
|
|
+ _getOptionLabelValue( option, forTooltip ) {
|
|
|
+ const t = this.editor.t;
|
|
|
+
|
|
|
+ if ( option.label ) {
|
|
|
+ return option.label;
|
|
|
+ } else if ( forTooltip ) {
|
|
|
+ if ( option.value ) {
|
|
|
+ return t( 'Resize image to %0', option.value + this._resizeUnit );
|
|
|
+ } else {
|
|
|
+ return t( 'Resize image to the original size' );
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ( option.value ) {
|
|
|
+ return option.value + this._resizeUnit;
|
|
|
+ } else {
|
|
|
+ return t( 'Original' );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- itemDefinitions.add( definition );
|
|
|
- } );
|
|
|
+ /**
|
|
|
+ * A helper function that parses resize options and returns list item definitions ready for use in a dropdown.
|
|
|
+ *
|
|
|
+ * @private
|
|
|
+ * @param {Array.<module:image/imageresize/imageresizeui~ImageResizeOption>} options The resize options.
|
|
|
+ * @param {module:image/imageresize/imageresizecommand~ImageResizeCommand} command A resize image command.
|
|
|
+ * @returns {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} Dropdown item definitions.
|
|
|
+ */
|
|
|
+ _getResizeDropdownListItemDefinitions( options, command ) {
|
|
|
+ const itemDefinitions = new Collection();
|
|
|
+
|
|
|
+ options.map( option => {
|
|
|
+ const optionValueWithUnit = option.value ? option.value + this._resizeUnit : null;
|
|
|
+ const definition = {
|
|
|
+ type: 'button',
|
|
|
+ model: new Model( {
|
|
|
+ commandName: 'imageResize',
|
|
|
+ commandValue: optionValueWithUnit,
|
|
|
+ label: this._getOptionLabelValue( option ),
|
|
|
+ withText: true,
|
|
|
+ icon: null
|
|
|
+ } )
|
|
|
+ };
|
|
|
+
|
|
|
+ definition.model.bind( 'isOn' ).to( command, 'value', getIsOnButtonCallback( optionValueWithUnit ) );
|
|
|
+
|
|
|
+ itemDefinitions.add( definition );
|
|
|
+ } );
|
|
|
|
|
|
- return itemDefinitions;
|
|
|
+ return itemDefinitions;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-// A helper function for setting the `isOn` state used for creating a callback function in a value binding.
|
|
|
-function setOptionOn( value ) {
|
|
|
+// A helper function for setting the `isOn` state of buttons in value bindings.
|
|
|
+function getIsOnButtonCallback( value ) {
|
|
|
return commandValue => {
|
|
|
- // Set reseting option on when command equals `null`.
|
|
|
- if ( commandValue === value ) {
|
|
|
+ if ( value === null && commandValue === value ) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -188,12 +272,19 @@ function setOptionOn( value ) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * A resize option type.
|
|
|
+ * An image resize option used in the {@link module:image/image~ImageConfig#resizeOptions image resize configuration}.
|
|
|
*
|
|
|
* @typedef {Object} module:image/imageresize/imageresizeui~ImageResizeOption
|
|
|
- *
|
|
|
- * @property {String} resizeOption.name A name of the option used for creating a component.
|
|
|
- * You refer to that name later in the {@link module:image/image~ImageConfig#toolbar}.
|
|
|
- * @property {String} resizeOption.label A label to be displayed with a button.
|
|
|
- * @property {String} resizeOption.value A value of a resize option. `null` value is for resetting an image to its original size.
|
|
|
+ * @property {String} name A name of the UI component that changes the image size.
|
|
|
+ * * If you configure the feature using individual resize buttons, you can refer to this name in the
|
|
|
+ * {@link module:image/image~ImageConfig#toolbar image toolbar configuration}.
|
|
|
+ * * If you configure the feature using the resize dropdown, this name will be used for a list item in the dropdown.
|
|
|
+ * @property {String} value A value of a resize option without the unit
|
|
|
+ * ({@link module:image/image~ImageConfig#resizeUnit configured separately}). `null` resets an image to its original size.
|
|
|
+ * @property {String} [resizeOptions.icon] An icon used by an individual resize button (see the `name` property to learn more).
|
|
|
+ * Available icons are: `'small'`, `'medium'`, `'large'`, `'original'`.
|
|
|
+ * @property {String} [label] A label of the option displayed in the dropdown or, if the feature is configured using
|
|
|
+ * individual buttons, a {@link module:ui/button/buttonview~ButtonView#tooltip} and an ARIA attribute of a button.
|
|
|
+ * If not specified, the label is generated automatically based on the option `value` and the
|
|
|
+ * {@link module:image/image~ImageConfig#resizeUnit `config.image.resizeUnit`}.
|
|
|
*/
|