Parcourir la source

Merge branch 'master' into t/ckeditor5-upload/87

Krzysztof Krztoń il y a 7 ans
Parent
commit
d7a48a73b3

+ 33 - 33
packages/ckeditor5-image/docs/framework/guides/deep-dive/upload-adapter.md

@@ -6,51 +6,51 @@ menu-title: Custom upload adapter
 # Custom image upload adapter
 
 <info-box>
-	Check out the {@link features/image-upload comprehensive "Image upload" guide} to learn about other ways to upload images into CKEditor 5.
+	Check out the comprehensive {@link features/image-upload Image upload overview} to learn about other ways to upload images into CKEditor 5.
 </info-box>
 
 ## How does the image upload work?
 
-Before you can implement your own custom upload adapter, you should learn a little bit about the image upload process in CKEditor 5. The whole process boils down to the following steps:
+Before you can implement your own custom upload adapter, you should learn about the image upload process in CKEditor 5. The whole process boils down to the following steps:
 
-1. First, an image (or images) need to get into the editor content. There are many ways to do that, for instance:
+1. First, an image (or images) need to get into the rich-text editor content. There are many ways to do that, for instance:
 
-	* pasting from the clipboard,
+	* pasting an image from clipboard,
 	* dragging a file from the file system,
-	* selecting and image through a file system dialog.
+	* selecting an image through a file system dialog.
 
-	The images are intercepted by the {@link module:image/imageupload~ImageUpload image upload} plugin (which is enabled in all {@link builds/guides/overview editor builds}).
+	The images are intercepted by the {@link module:image/imageupload~ImageUpload image upload} plugin (which is enabled in all official {@link builds/guides/overview editor builds}).
 2. For every image, the image upload plugin {@link module:upload/filerepository~FileRepository#createLoader creates an instance of a file loader}.
 
 	* The role of the **file loader** is to read the file from the disk and upload it to the server by using the upload adapter.
 	* The role of the **upload adapter** is, therefore, to securely send the file to the server and pass the response from the server (e.g. the URL to the saved file) back to the file loader (or handle an error, if there was one).
 
-3. While the images are being uploaded, the image upload plugin
+3. While the images are being uploaded, the image upload plugin:
 
-	* creates placeholders of those images,
-	* inserts them into the editor,
-	* displays the progress bar on each of them,
-	* when an image is deleted from the editor content before upload finishes, aborts the upload process.
+	* Creates placeholders of these images.
+	* Inserts them into the editor.
+	* Displays the progress bar for each of them.
+	* When an image is deleted from the editor content before the upload finishes, it aborts the upload process.
 
-4. Once the file is uploaded, the upload adapter notifies the editor about this fact by resolving its `Promise`. It passes the URL (or URLs in case of responsive images) to the image upload plugin which replaces `src` and `srcset` attributes of the image placeholder in the editor content.
+4. Once the file is uploaded, the upload adapter notifies the editor about this fact by resolving its `Promise`. It passes the URL (or URLs in case of responsive images) to the image upload plugin which replaces the `src` and `srcset` attributes of the image placeholder in the editor content.
 
-This is just an overview of the image upload process. The truth is, the whole thing is more complicated. For instance, images can be copied and pasted within the editor (while the upload takes place) and all potential upload errors must be handled too. The good news is those tasks are handled transparently by the {@link module:image/imageupload~ImageUpload image upload} plugin so you do not have to worry about them.
+This is just an overview of the image upload process. The truth is, the whole thing is more complicated. For instance, images can be copied and pasted within the WYSIWYG editor (while the upload takes place) and all potential upload errors must be handled, too. The good news is these tasks are handled transparently by the {@link module:image/imageupload~ImageUpload image upload} plugin so you do not have to worry about them.
 
-To sum up, for the image upload to work in the editor, two conditions must be true:
+To sum up, for the image upload to work in the rich-text editor, two conditions must be true:
 
-* **The {@link module:image/imageupload~ImageUpload image upload} plugin must be enabled** in the editor. It is enabled in all {@link builds/guides/overview builds} by default, but if you are {@link builds/guides/development/custom-builds customizing} an editor, do not forget to include it.
-* **The upload adapter needs to be defined**. This can be done by using (enabling *and* configuring)
+* **The {@link module:image/imageupload~ImageUpload image upload} plugin must be enabled** in the editor. It is enabled by default in all official {@link builds/guides/overview builds}, but if you are {@link builds/guides/development/custom-builds customizing} CKEditor 5, do not forget to include it.
+* **The upload adapter needs to be defined**. This can be done by using (enabling *and* configuring):
 
-	* {@link features/image-upload#official-upload-adapters one of the existing upload adapters},
-	* [your custom upload adapter](#implementing-a-custom-upload-adapter) and handling uploaded files on your server back–end.
+	* {@link features/image-upload#official-upload-adapters One of the existing upload adapters}.
+	* [Your custom upload adapter](#implementing-a-custom-upload-adapter) and handling uploaded files on your server back–end.
 
 ## Implementing a custom upload adapter
 
-In this guide we are going to implement and enable a custom upload adapter that will allow you to take the **full control** over the process of sending the files to the server as well as passing the response from the server (e.g. the URL to the saved file) back to the editor.
+In this guide you are going to implement and enable a custom upload adapter that will allow you to take the **full control** over the process of sending the files to the server as well as passing the response from the server (e.g. the URL to the saved file) back to the rich-text editor.
 
 ### The anatomy of the adapter
 
-Let's define the `MyUploadAdapter` class and fill its internals step–by–step. The adapter will use the native `XMLHttpRequest` to send files returned by the loader to a pre–configured URL on a server, handling `error`, `abort`, `load`, and `progress` events fired by the request.
+Define the `MyUploadAdapter` class and fill its internals step–by–step. The adapter will use the native `XMLHttpRequest` to send files returned by the loader to a pre–configured URL on the server, handling `error`, `abort`, `load`, and `progress` events fired by the request.
 
 ```js
 class MyUploadAdapter {
@@ -68,12 +68,12 @@ class MyUploadAdapter {
 }
 ```
 
-Your custom upload adapter must implement the {@link module:upload/filerepository~UploadAdapter `UploadAdapter` interface} in order to work, i.e. bring own `upload()` and `abort()` methods.
+Your custom upload adapter must implement the {@link module:upload/filerepository~UploadAdapter `UploadAdapter` interface} in order to work, i.e. it must bring its own `upload()` and `abort()` methods.
 
 * The {@link module:upload/filerepository~UploadAdapter#upload `upload()`} method must return a promise:
-	* resolved by a successful image upload (with an object containing information about uploaded file),
+	* resolved by a successful image upload (with an object containing information about the uploaded file),
 	* rejected because of an error, in which case no image is inserted into the content.
-* The {@link module:upload/filerepository~UploadAdapter#abort `abort()`} must allow the editor to abort the upload process. It is necessary, for instance, when the image was removed from the content by the user before the upload finished.
+* The {@link module:upload/filerepository~UploadAdapter#abort `abort()`} method must allow the editor to abort the upload process. It is necessary, for instance, when the image was removed from the content by the user before the upload finished.
 
 ```js
 class MyUploadAdapter {
@@ -123,9 +123,9 @@ class MyUploadAdapter {
 	_initRequest() {
 		const xhr = this.xhr = new XMLHttpRequest();
 
-		// Note that you request may look different. It is up to you and you editor
+		// Note that your request may look different. It is up to you and your editor
 		// integration to choose the right communication channel. This example uses
-		// the POST request with a JSON as a data structure but your configuration
+		// the POST request with JSON as a data structure but your configuration
 		// could be different.
 		xhr.open( 'POST', this.url, true );
 		xhr.responseType = 'json';
@@ -133,7 +133,7 @@ class MyUploadAdapter {
 }
 ```
 
-Now let's focus on the `_initListeners()` method which attaches `error`, `abort`, `load`, and `progress` event listeners to the `XMLHttpRequest` object created in the last step.
+Now let's focus on the `_initListeners()` method which attaches the `error`, `abort`, `load`, and `progress` event listeners to the `XMLHttpRequest` object created in the last step.
 
 A successful image upload will finish when the upload promise is resolved upon the `load` event fired by the `XMLHttpRequest` request. The promise must be resolved with an object containing information about the image. See the documentation of the {@link module:upload/filerepository~UploadAdapter#upload `upload()`} method to learn more.
 
@@ -185,7 +185,7 @@ class MyUploadAdapter {
 			} );
 		} );
 
-		// Upload progress when it's supported. The FileLoader has the #uploadTotal and #uploaded
+		// Upload progress when it is supported. The FileLoader has the #uploadTotal and #uploaded
 		// properties which are used e.g. to display the upload progress bar in the editor
 		// user interface.
 		if ( xhr.upload ) {
@@ -200,7 +200,7 @@ class MyUploadAdapter {
 }
 ```
 
-Last but not least, the `_sendRequest()` method well... sends the `XMLHttpRequest`. In this example, the [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) interface is used to pass the file provided by the {@link module:upload/filerepository~FileRepository#createLoader file loader}.
+Last but not least, the `_sendRequest()` method sends the `XMLHttpRequest`. In this example, the [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) interface is used to pass the file provided by the {@link module:upload/filerepository~FileRepository#createLoader file loader}.
 
 ```js
 class MyUploadAdapter {
@@ -226,11 +226,11 @@ class MyUploadAdapter {
 
 	// Prepares the data and sends the request.
 	_sendRequest() {
-		// Prepare form data.
+		// Prepare the form data.
 		const data = new FormData();
 		data.append( 'upload', this.loader.file );
 
-		// Send request.
+		// Send the request.
 		this.xhr.send( data );
 	}
 }
@@ -240,7 +240,7 @@ class MyUploadAdapter {
 
 Having implemented the adapter, you must figure out how to enable it in the editor. The good news is that it is pretty easy, and you do not need to {@link builds/guides/development/custom-builds rebuild the editor} to do that!
 
-Crate a simple standalone plugin (`MyCustomUploadAdapterPlugin`) that will {@link module:upload/filerepository~FileRepository#createLoader create an instance of a file loader} and glue it with your custom `MyUploadAdapter`.
+Crate a simple standalone plugin (`MyCustomUploadAdapterPlugin`) that will {@link module:upload/filerepository~FileRepository#createLoader create an instance of the file loader} and glue it with your custom `MyUploadAdapter`.
 
 ```js
 import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
@@ -275,9 +275,9 @@ ClassicEditor
 	} );
 ```
 
-Run the editor and see if your implementation works. Drop an image into editor content and it should be uploaded to the server, handled by the `MyUploadAdapter`.
+Run the editor and see if your implementation works. Drop an image into the WYSIWYG editor content and it should be uploaded to the server thanks to the `MyUploadAdapter`.
 
 ## What's next?
 
-Check out the {@link features/image-upload comprehensive "Image upload" guide} to learn more about different ways of uploading images in CKEditor 5. See the {@link features/image Image feature} guide to find out more about handling images in CKEditor 5.
+Check out the comprehensive {@link features/image-upload Image upload overview} to learn more about different ways of uploading images in CKEditor 5. See the {@link features/image Image feature} guide to find out more about handling images in CKEditor 5.
 

+ 1 - 1
packages/ckeditor5-image/src/imageupload.js

@@ -15,7 +15,7 @@ import ImageUploadEditing from './imageupload/imageuploadediting';
 /**
  * The image upload plugin.
  *
- * For a detailed overview, check the {@glink features/image-upload image upload feature} documentation.
+ * For a detailed overview, check the {@glink features/image-upload/image-upload image upload feature} documentation.
  *
  * This plugin does not do anything directly, but it loads a set of specific plugins to enable image uploading:
  *

+ 21 - 19
packages/ckeditor5-image/src/imageupload/imageuploadediting.js

@@ -98,29 +98,31 @@ export default class ImageUploadEditing extends Plugin {
 		// For every image file, a new file loader is created and a placeholder image is
 		// inserted into the content. Then, those images are uploaded once they appear in the model
 		// (see Document#change listener below).
-		this.listenTo( editor.plugins.get( 'Clipboard' ), 'inputTransformation', ( evt, data ) => {
-			const fetchableImages = Array.from( editor.editing.view.createRangeIn( data.content ) )
-				.filter( value => isLocalImage( value.item ) && !value.item.getAttribute( 'uploadProcessed' ) )
-				.map( value => { return { promise: fetchLocalImage( value.item ), imageElement: value.item }; } );
-
-			if ( !fetchableImages.length ) {
-				return;
-			}
+		if ( editor.plugins.has( 'Clipboard' ) ) {
+			this.listenTo( editor.plugins.get( 'Clipboard' ), 'inputTransformation', ( evt, data ) => {
+				const fetchableImages = Array.from( editor.editing.view.createRangeIn( data.content ) )
+					.filter( value => isLocalImage( value.item ) && !value.item.getAttribute( 'uploadProcessed' ) )
+					.map( value => { return { promise: fetchLocalImage( value.item ), imageElement: value.item }; } );
+
+				if ( !fetchableImages.length ) {
+					return;
+				}
 
-			const writer = new UpcastWriter();
+				const writer = new UpcastWriter();
 
-			for ( const fetchableImage of fetchableImages ) {
-				// Set attribute marking that the image was processed already.
-				writer.setAttribute( 'uploadProcessed', true, fetchableImage.imageElement );
+				for ( const fetchableImage of fetchableImages ) {
+					// Set attribute marking that the image was processed already.
+					writer.setAttribute( 'uploadProcessed', true, fetchableImage.imageElement );
 
-				const loader = fileRepository.createLoader( fetchableImage.promise );
+					const loader = fileRepository.createLoader( fetchableImage.promise );
 
-				if ( loader ) {
-					writer.setAttribute( 'src', '', fetchableImage.imageElement );
-					writer.setAttribute( 'uploadId', loader.id, fetchableImage.imageElement );
+					if ( loader ) {
+						writer.setAttribute( 'src', '', fetchableImage.imageElement );
+						writer.setAttribute( 'uploadId', loader.id, fetchableImage.imageElement );
+					}
 				}
-			}
-		} );
+			} );
+		}
 
 		// Prevents from the browser redirecting to the dropped image.
 		editor.editing.view.document.on( 'dragover', ( evt, data ) => {
@@ -255,7 +257,7 @@ export default class ImageUploadEditing extends Plugin {
 		let maxWidth = 0;
 
 		const srcsetAttribute = Object.keys( data )
-			// Filter out keys that are not integers.
+		// Filter out keys that are not integers.
 			.filter( key => {
 				const width = parseInt( key, 10 );
 

+ 1 - 1
packages/ckeditor5-image/src/imageupload/imageuploadui.js

@@ -15,7 +15,7 @@ import { isImageType } from './utils';
 /**
  * The image upload button plugin.
  *
- * For a detailed overview, check the {@glink features/image-upload Image upload feature} documentation.
+ * For a detailed overview, check the {@glink features/image-upload/image-upload Image upload feature} documentation.
  *
  * Adds the `'imageUpload'` button to the {@link module:ui/componentfactory~ComponentFactory UI component factory}.
  *

+ 7 - 0
packages/ckeditor5-image/tests/imageupload/imageuploadediting.js

@@ -97,6 +97,13 @@ describe( 'ImageUploadEditing', () => {
 		expect( editor.commands.get( 'imageUpload' ) ).to.be.instanceOf( ImageUploadCommand );
 	} );
 
+	it( 'should not crash when Clipboard plugin is not available', () => {
+		return VirtualTestEditor
+			.create( {
+				plugins: [ ImageEditing, ImageUploadEditing, Paragraph, UndoEditing, UploadAdapterPluginMock ]
+			} );
+	} );
+
 	it( 'should insert image when is pasted', () => {
 		const fileMock = createNativeFileMock();
 		const dataTransfer = new DataTransfer( { files: [ fileMock ], types: [ 'Files' ] } );