Ver código fonte

Init ImageResizeUI component

panr 5 anos atrás
pai
commit
c7de16e462

+ 213 - 0
packages/ckeditor5-image/src/imageresizeui.js

@@ -0,0 +1,213 @@
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/**
+ * @module image/imageresizeui
+ */
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import ImageResize from './imageresize';
+import { createDropdown, addListToDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';
+import DropdownButtonView from '@ckeditor/ckeditor5-ui/src/dropdown/button/dropdownbuttonview';
+
+import Model from '@ckeditor/ckeditor5-ui/src/model';
+import Collection from '@ckeditor/ckeditor5-utils/src/collection';
+
+// TODO
+import linkIcon from '../theme/icons/image_resize.svg';
+
+/**
+ * The `ImageResizeUI` plugin.
+ *
+ * It adds a possibility to resize each image using toolbar dropdown or separate buttons, depends on the plugin configuration.
+ *
+ * @extends module:core/plugin~Plugin
+ */
+export default class ImageResizeUI extends Plugin {
+	/**
+	 * @inheritDoc
+	 */
+	static get requires() {
+		return [ ImageResize ];
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	static get pluginName() {
+		return 'ImageResizeUI';
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	constructor( editor ) {
+		super( editor );
+
+		/**
+		 * A state of resize unit configured by the user.
+		 * If not set, it takes "%" as a default value.
+		 *
+		 * @private
+		 *
+		 * @member {module:image/image~ImageConfig#resizeUnit}
+		 */
+		this._resizeUnit = editor.config.get( 'image.resizeUnit' ) || '%';
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	init() {
+		const editor = this.editor;
+		const options = editor.config.get( 'image.imageResizeOptions' );
+		const command = editor.commands.get( 'imageResize' );
+
+		this.bind( 'isEnabled' ).to( command );
+
+		for ( const option of options ) {
+			this._addButton( option );
+		}
+
+		this._addDropdown( options );
+	}
+
+	/**
+	 * A helper function that creates a standalone button component for the plugin.
+	 *
+	 * @private
+	 *
+	 * @param {module:image/imageresizeui~resizeOption} resizeOption A model of resize option.
+	 */
+	_addButton( { name, label, value } ) {
+		const editor = this.editor;
+		const t = editor.t;
+		const parsedValue = 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 );
+
+			button.set( {
+				label: t( label ),
+				withText: true,
+				icon: linkIcon,
+				tooltip: t( 'Resize Image' ),
+				isToggleable: true,
+				commandValue: parsedValue
+			} );
+
+			// Bind button to the command.
+			button.bind( 'isEnabled' ).to( this );
+			button.bind( 'isOn' ).to( command, 'value', commandCallback );
+
+			this.listenTo( button, 'execute', evt => {
+				editor.execute( 'imageResize', { width: evt.source.commandValue } );
+			} );
+
+			return button;
+		} );
+	}
+
+	/**
+	 * A helper function that creates a dropdown component for the plugin containing all resize options created through the
+	 * plugin configuration settings.
+	 *
+	 * @private
+	 *
+	 * @param {Array.<module:image/imageresizeui~resizeOption>} options An array of the configured options.
+	 */
+	_addDropdown( options ) {
+		const editor = this.editor;
+		const t = editor.t;
+		const firstOption = options[ 0 ];
+		const resetOption = options.find( option => option.value === null );
+
+		// Register dropdown.
+		editor.ui.componentFactory.add( 'imageResize', locale => {
+			const command = editor.commands.get( 'imageResize' );
+			const dropdownView = createDropdown( locale, DropdownButtonView );
+			const dropdownButton = dropdownView.buttonView;
+
+			dropdownButton.set( {
+				tooltip: t( 'Resize Image' ),
+				icon: linkIcon,
+				commandValue: firstOption.value,
+				isToggleable: true,
+				label: firstOption.label,
+				withText: true
+			} );
+
+			dropdownButton.bind( 'label' ).to( command, 'value', commandValue => {
+				return commandValue && commandValue.width || resetOption.label;
+			} );
+			dropdownView.bind( 'isOn' ).to( command );
+			dropdownView.bind( 'isEnabled' ).to( this );
+
+			addListToDropdown( dropdownView, prepareListDefinitions( options, command, this._resizeUnit ) );
+
+			dropdownView.listView.ariaLabel = t( 'Image resize list' );
+
+			// Execute command when an item from the dropdown is selected.
+			this.listenTo( dropdownView, 'execute', evt => {
+				editor.execute( evt.source.commandName, { width: evt.source.commandValue } );
+				editor.editing.view.focus();
+			} );
+
+			return dropdownView;
+		} );
+	}
+}
+
+// A helper function for parsing resize options definitions.
+function prepareListDefinitions( definitions, command, resizeUnit ) {
+	const itemDefinitions = new Collection();
+
+	definitions.map( definition => {
+		const parsedValue = definition.value ? definition.value + resizeUnit : null;
+		const def = {
+			type: 'button',
+			model: new Model( {
+				commandName: 'imageResize',
+				commandValue: parsedValue,
+				label: definition.label,
+				withText: true,
+				icon: null
+			} )
+		};
+
+		const commandCallback = setOptionOn( parsedValue );
+
+		def.model.bind( 'isOn' ).to( command, 'value', commandCallback );
+
+		itemDefinitions.add( def );
+	} );
+
+	return itemDefinitions;
+}
+
+// A helper function for setting the `isOn` state used for creating a callback function in a value binding.
+function setOptionOn( value ) {
+	return commandValue => {
+		// Set reseting option on when command equals `null`.
+		if ( commandValue === value ) {
+			return true;
+		}
+
+		return commandValue && commandValue.width === value;
+	};
+}
+
+/**
+ * A resize option type.
+ *
+ * @typedef {Object} module:image/imageresizeui~resizeOption
+ *
+ * @property {String} resizeOption.name A name of the option used for creating a component.
+ * @property {String} resizeOption.label A label to be displayed with a button.
+ * @property {String} resizeOption.value A value of a resize option.
+ */

+ 15 - 0
packages/ckeditor5-image/tests/manual/imageresizeui.html

@@ -0,0 +1,15 @@
+<style>
+	.fancy-editor-wrapper figure {
+		padding: 20px;
+	}
+</style>
+
+<div id="editor">
+	<h2>Responsive image (width style: not set, width attribute present on the image)</h2>
+
+	<figure class="image">
+		<img alt="Picture of the Warsaw Old Town." width="488" srcset="https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_430 430w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_860 860w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_1290 1290w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_1720 1720w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_2150 2150w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_2580 2580w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_3010 3010w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_3440 3440w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_3870 3870w, https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg/w_4288 4288w" sizes="100vw" src="https://33333.cdn.cke-cs.com/0fNqCUeBSal4ENvGfd7K/images/c12cb88e596270d8d963b7c87bef1767880f42d94fb2ec43_warsaw01.jpg">
+	</figure>
+
+	<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus consequat placerat. Vestibulum id telluset mauris sagittis tincidunt quis id mauris. Curabitur consectetur lectus sit amet tellus mattis, non lobortisleo interdum. </p>
+</div>

+ 61 - 0
packages/ckeditor5-image/tests/manual/imageresizeui.js

@@ -0,0 +1,61 @@
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* global document, console, window */
+
+import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
+import ImageResizeUI from '../../src/imageresizeui';
+import Indent from '@ckeditor/ckeditor5-indent/src/indent';
+import IndentBlock from '@ckeditor/ckeditor5-indent/src/indentblock';
+import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
+
+import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
+
+const commonConfig = {
+	plugins: [
+		ArticlePluginSet,
+		ImageResizeUI,
+		Indent,
+		IndentBlock,
+		EasyImage
+	],
+	toolbar: [ 'heading', '|', 'bold', 'italic', 'link',
+		'bulletedList', 'numberedList', 'blockQuote', 'insertTable', 'undo', 'redo', 'outdent', 'indent' ],
+	image: {
+		imageResize: [
+			{
+				name: 'imageResize:50',
+				label: 'Resize image of 50%',
+				value: '50%'
+			},
+			{
+				name: 'imageResize:75',
+				label: 'Resize image of 75%',
+				value: '75%'
+			}
+		],
+		toolbar: [ 'imageStyle:alignLeft', 'imageStyle:full', 'imageStyle:side', '|', 'imageResize' ],
+		styles: [
+			'full',
+			'alignLeft',
+			'side' // Purposely using side image instead right aligned image to make sure it works well with both style types.
+		]
+	},
+	table: {
+		contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ],
+		tableToolbar: [ 'bold', 'italic' ]
+	},
+	cloudServices: CS_CONFIG
+};
+
+ClassicEditor
+	.create( document.querySelector( '#editor' ), commonConfig )
+	.then( editor => {
+		window.editor = editor;
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );

+ 1 - 0
packages/ckeditor5-image/tests/manual/imageresizeui.md

@@ -0,0 +1 @@
+## TODO

+ 6 - 0
packages/ckeditor5-image/theme/icons/image_resize.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
+  <g fill="none" fill-rule="evenodd">
+    <polygon fill="#000" fill-rule="nonzero" points="7.25 12 8.311 13.061 4.561 16.81 7.75 16.811 7.75 18.311 2 18.311 2 12.561 3.5 12.561 3.5 15.749"/>
+    <polygon fill="#000" fill-rule="nonzero" points="17.25 2 18.311 3.061 14.561 6.81 17.75 6.811 17.75 8.311 12 8.311 12 2.561 13.5 2.561 13.5 5.749" transform="rotate(-180 15.155 5.155)"/>
+  </g>
+</svg>