|
|
@@ -392,111 +392,6 @@ export class MyComponent {
|
|
|
|
|
|
If you want to make changes on just created editor then the better option would be getting instance of CKEditor 5 editor on the [`ready`](#ready) event.
|
|
|
|
|
|
-## Implementing an Upload Adapter based on Angular HttpClient
|
|
|
-
|
|
|
-An Upload Adapter can be used with CKEditor 5 so that when a user adds an image to a document it is encoded as a link to the image. The image itself is stored separately from the document. Read more in the {@link framework/guides/deep-dive/upload-adapter Upload Adapter guide}.
|
|
|
-
|
|
|
-If you are familiar with Angular you have probably already used the [`HTTPClient`](https://angular.io/guide/http) service which wraps the JavaScript XMLHttpRequest and provides a more concise API around it. Let's make a use of it to give Angular the control over the image upload process (e.g. for easier mocking and testing later):
|
|
|
-
|
|
|
-```ts
|
|
|
-import { Subscription, Observable } from 'rxjs';
|
|
|
-import { HttpClient, HttpEventType, HttpRequest, HttpEvent } from '@angular/common/http';
|
|
|
-// ...
|
|
|
-
|
|
|
-@Component()
|
|
|
-export class MyComponent {
|
|
|
- constructor( private httpClient: HttpClient ){}
|
|
|
-
|
|
|
- public config = {
|
|
|
- extraPlugins: [ UploadAdapterPlugin ],
|
|
|
- uploadAdapter: {
|
|
|
- httpClient: this.httpClient
|
|
|
- }
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-class UploadAdapterPlugin {
|
|
|
- constructor( editor: any ) {
|
|
|
- const { httpClient } = editor.config.get( 'uploadAdapter' );
|
|
|
-
|
|
|
- editor.plugins.get( 'FileRepository' ).createUploadAdapter = loader => {
|
|
|
- // Modify for your endpoint URL.
|
|
|
- return new UploadAdapter( loader, httpClient, 'http://example.com/image/upload/path' );
|
|
|
- };
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-class UploadAdapter {
|
|
|
- private sub: Subscription;
|
|
|
-
|
|
|
- constructor(
|
|
|
- private loader: UploadLoader,
|
|
|
- private httpClient: HttpClient,
|
|
|
- private url: string
|
|
|
- ) { }
|
|
|
-
|
|
|
- public async upload(): Promise<{ default: string }> {
|
|
|
- const file = await this.loader.file;
|
|
|
-
|
|
|
- return new Promise( ( resolve, reject ) => {
|
|
|
- const formData = new FormData();
|
|
|
- formData.append( 'file', file );
|
|
|
-
|
|
|
- this.sub = this.uploadImage( formData ).subscribe( event => {
|
|
|
- if ( event.type === HttpEventType.Response ) {
|
|
|
- const response = event.body;
|
|
|
-
|
|
|
- if ( response.error ) {
|
|
|
- return reject( response.error.message );
|
|
|
- }
|
|
|
-
|
|
|
- resolve( { default: response.url } );
|
|
|
- } else if ( event.type === HttpEventType.UploadProgress ) {
|
|
|
- this.loader.uploaded = event.loaded;
|
|
|
- this.loader.uploadTotal = event.total;
|
|
|
- }
|
|
|
- }, err => {
|
|
|
- reject( err.body.message );
|
|
|
- } );
|
|
|
- } );
|
|
|
- }
|
|
|
-
|
|
|
- public abort() {
|
|
|
- if ( this.sub ) {
|
|
|
- this.sub.unsubscribe();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private uploadImage( formData: FormData ): Observable<HttpEvent<ImageEndpointResponse>> {
|
|
|
- const request = new HttpRequest(
|
|
|
- 'POST',
|
|
|
- this.url,
|
|
|
- formData,
|
|
|
- {
|
|
|
- withCredentials: true,
|
|
|
- reportProgress: true
|
|
|
- }
|
|
|
- );
|
|
|
-
|
|
|
- return this.httpClient.request( request );
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// Modify to align your endpoint response.
|
|
|
-interface ImageEndpointResponse {
|
|
|
- url: string;
|
|
|
- error?: { message: string };
|
|
|
-}
|
|
|
-
|
|
|
-interface UploadLoader {
|
|
|
- uploaded: number;
|
|
|
- uploadTotal: number;
|
|
|
- readonly file: string;
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-The `UploadAdapter` class will be instantiated each time when CKEditor 5 needs it. Note that the functions in this class will run outside the `NgZone`, which means that if it makes changes to variables bound to HTML elements, the shadow-DOM logic of Angular won't detect those changes.
|
|
|
-
|
|
|
## Localization
|
|
|
|
|
|
The CKEditor 5 rich text editor component can be localized in two steps.
|