Solución:
Sí, la carga de imágenes está incluida en todas las compilaciones disponibles. Sin embargo, para que funcione, debe configurar uno de los adaptadores de carga existentes o escribir uno propio. En resumen, el adaptador de carga es una clase simple cuya función es enviar un archivo a un servidor (de la forma que desee) y resolver la promesa devuelta una vez que se hace.
Puede leer más en la guía oficial de carga de imágenes o ver el breve resumen de las opciones disponibles a continuación.
Adaptadores de carga oficiales
Hay dos adaptadores integrados:
-
Para CKFinder que requieren que instale los conectores CKFinder en su servidor.
Una vez que tenga el conector instalado en su servidor, puede configurar CKEditor para cargar archivos a ese conector configurando el
config.ckfinder.uploadUrl
opción:ClassicEditor .create( editorElement, { ckfinder: { uploadUrl: '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files&responseType=json' } } ) .then( ... ) .catch( ... );
También puede habilitar la integración completa con el administrador de archivos del lado del cliente de CKFinder. Consulte las demostraciones de integración de CKFinder y lea más en la guía de integración de CKFinder.
-
Para el servicio Easy Image que forma parte de CKEditor Cloud Services.
Debe configurar una cuenta de servicios en la nube y, una vez que haya creado un punto final de token, configure el editor para usarlo:
ClassicEditor .create( editorElement, { cloudServices: { tokenUrl: 'https://example.com/cs-token-endpoint', uploadUrl: 'https://your-organization-id.cke-cs.com/easyimage/upload/' } } ) .then( ... ) .catch( ... );
Descargo de responsabilidad: Estos son servicios propietarios.
Adaptador de carga personalizado
También puede escribir su propio adaptador de carga que enviará archivos de la forma que desee a su servidor (o donde quiera enviarlos).
Consulte la guía del adaptador de carga de imágenes personalizadas para saber cómo implementarlo.
Un ejemplo de adaptador de carga (es decir, sin seguridad incorporada) puede verse así:
class MyUploadAdapter {
constructor( loader ) {
// CKEditor 5's FileLoader instance.
this.loader = loader;
// URL where to send files.
this.url="https://example.com/image/upload/path";
}
// Starts the upload process.
upload() {
return new Promise( ( resolve, reject ) => {
this._initRequest();
this._initListeners( resolve, reject );
this._sendRequest();
} );
}
// Aborts the upload process.
abort() {
if ( this.xhr ) {
this.xhr.abort();
}
}
// Example implementation using XMLHttpRequest.
_initRequest() {
const xhr = this.xhr = new XMLHttpRequest();
xhr.open( 'POST', this.url, true );
xhr.responseType="json";
}
// Initializes XMLHttpRequest listeners.
_initListeners( resolve, reject ) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText="Couldn"t upload file:' + ` ${ loader.file.name }.`;
xhr.addEventListener( 'error', () => reject( genericErrorText ) );
xhr.addEventListener( 'abort', () => reject() );
xhr.addEventListener( 'load', () => {
const response = xhr.response;
if ( !response || response.error ) {
return reject( response && response.error ? response.error.message : genericErrorText );
}
// If the upload is successful, resolve the upload promise with an object containing
// at least the "default" URL, pointing to the image on the server.
resolve( {
default: response.url
} );
} );
if ( xhr.upload ) {
xhr.upload.addEventListener( 'progress', evt => {
if ( evt.lengthComputable ) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
} );
}
}
// Prepares the data and sends the request.
_sendRequest() {
const data = new FormData();
data.append( 'upload', this.loader.file );
this.xhr.send( data );
}
}
Que luego se puede habilitar así:
function MyCustomUploadAdapterPlugin( editor ) {
editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader ) => {
return new MyUploadAdapter( loader );
};
}
ClassicEditor
.create( document.querySelector( '#editor' ), {
extraPlugins: [ MyCustomUploadAdapterPlugin ],
// ...
} )
.catch( error => {
console.log( error );
} );
NOTA: Lo anterior es solo un ejemplo de adaptador de carga. Como tal, no tiene mecanismos de seguridad integrados (como la protección CSRF).
Estaba buscando información sobre cómo usar este control y encontré la documentación oficial bastante mínima. Sin embargo, logré que funcionara después de muchas pruebas y errores, así que pensé en compartirlo.
Al final utilicé el adaptador de carga simple CKEditor 5 con Angular 8 y funciona bien. Sin embargo, es necesario crear una compilación personalizada de ckeditor que tenga instalado el adaptador de carga. Es bastante fácil de hacer. Supongo que ya tiene los archivos angulares de ckeditor.
Primero, cree un nuevo directorio de proyecto angular y llámelo “cKEditor-Custom-Build” o algo así. No ejecute ng new (Angular CLI), sino use npm para obtener la compilación base del editor que desea mostrar. Para este ejemplo, estoy usando el editor clásico.
https://github.com/ckeditor/ckeditor5-build-classic
Vaya a github y clone o descargue el proyecto en su nuevo directorio de compilación brillante.
si está utilizando el código VS, abra el directorio y abra una caja de terminal y obtenga las dependencias:
npm i
Ahora tiene la compilación base y necesita instalar un adaptador de carga. ckEditor tiene uno. instale este paquete para obtener el adaptador de carga simple:
npm install --save @ckeditor/ckeditor5-upload
.. una vez hecho esto, abra el archivo ckeditor.js en el proyecto. Está en el directorio “src”. Si ha estado jugando con ckEditor, su contenido le resultará familiar.
Importe el nuevo archivo js al archivo ckeditor.js. Habrá una gran cantidad de importaciones en este archivo y suéltelo hasta el final.
import SimpleUploadAdapter from '@ckeditor/ckeditor5-upload/src/adapters/simpleuploadadapter';
… A continuación, agregue la importación a su conjunto de complementos. Como estoy usando el editor clásico, mi sección se llama “ClassicEditor.builtinPlugins”, agréguela junto a TableToolbar. Eso es todo configurado. No se necesitan barras de herramientas ni configuraciones adicionales en este extremo.
Cree su ckeditor-custom-build.
npm run build
La magia de Angular hará lo suyo y se creará un directorio de “compilación” en su proyecto. Eso es para la construcción personalizada.
Ahora abra su proyecto angular y cree un directorio para que viva su nueva construcción. De hecho, puse el mío en el subdirectorio de activos, pero puede estar en cualquier lugar donde pueda hacer referencia a él.
Cree un directorio dentro de “src / assets” llamado algo así como “ngClassicEditor”, no importa cómo lo llame, y copie el archivo de compilación en él (que acaba de crear). A continuación, en el componente que desea utilizar en el editor, agregue una declaración de importación con la ruta a la nueva compilación.
import * as Editor from '@app/../src/assets/ngClassicEditor/build/ckeditor.js';
casi terminado…
El último bit es configurar el adaptador de carga con el punto final de la API que el adaptador debe usar para cargar imágenes. Cree una configuración en su clase de componente.
public editorConfig = {
simpleUpload: {
// The URL that the images are uploaded to.
uploadUrl: environment.postSaveRteImage,
// Headers sent along with the XMLHttpRequest to the upload server.
headers: {
'X-CSRF-TOKEN': 'CSFR-Token',
Authorization: 'Bearer <JSON Web Token>'
}
}
};
De hecho, estoy usando la transformación de entorno aquí cuando el URI cambia de desarrollo a producción, pero puede codificar una URL directa allí si lo desea.
La parte final es configurar su editor en la plantilla para usar sus nuevos valores de configuración. Abra su component.html y modifique su etiqueta de editor de ckeditor.
<ckeditor [editor]="Editor" [config]="editorConfig">
</ckeditor>
Eso es todo. Estás listo. prueba, prueba prueba.
Mi API es una API .Net y me complace compartirla si necesita algún código de muestra. Realmente espero que esto ayude.
Me está funcionando bien. gracias por todas las respuestas. esta es mi implementación.
myUploadAdapter.ts
import { environment } from "./../../../environments/environment";
export class MyUploadAdapter {
public loader: any;
public url: string;
public xhr: XMLHttpRequest;
public token: string;
constructor(loader) {
this.loader = loader;
// change "environment.BASE_URL" key and API path
this.url = `${environment.BASE_URL}/api/v1/upload/attachments`;
// change "token" value with your token
this.token = localStorage.getItem("token");
}
upload() {
return new Promise(async (resolve, reject) => {
this.loader.file.then((file) => {
this._initRequest();
this._initListeners(resolve, reject, file);
this._sendRequest(file);
});
});
}
abort() {
if (this.xhr) {
this.xhr.abort();
}
}
_initRequest() {
const xhr = (this.xhr = new XMLHttpRequest());
xhr.open("POST", this.url, true);
// change "Authorization" header with your header
xhr.setRequestHeader("Authorization", this.token);
xhr.responseType = "json";
}
_initListeners(resolve, reject, file) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText = "Couldn't upload file:" + ` ${file.name}.`;
xhr.addEventListener("error", () => reject(genericErrorText));
xhr.addEventListener("abort", () => reject());
xhr.addEventListener("load", () => {
const response = xhr.response;
if (!response || response.error) {
return reject(
response && response.error ? response.error.message : genericErrorText
);
}
// change "response.data.fullPaths[0]" with image URL
resolve({
default: response.data.fullPaths[0],
});
});
if (xhr.upload) {
xhr.upload.addEventListener("progress", (evt) => {
if (evt.lengthComputable) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
});
}
}
_sendRequest(file) {
const data = new FormData();
// change "attachments" key
data.append("attachments", file);
this.xhr.send(data);
}
}
componente.html
<ckeditor
(ready)="onReady($event)"
[editor]="editor"
[(ngModel)]="html"
></ckeditor>
componente.ts
import { MyUploadAdapter } from "./myUploadAdapter";
import { Component, OnInit } from "@angular/core";
import * as DecoupledEditor from "@ckeditor/ckeditor5-build-decoupled-document";
@Component({
selector: "xxx",
templateUrl: "xxx.html",
})
export class XXX implements OnInit {
public editor: DecoupledEditor;
public html: string;
constructor() {
this.editor = DecoupledEditor;
this.html = "";
}
public onReady(editor) {
editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
return new MyUploadAdapter(loader);
};
editor.ui
.getEditableElement()
.parentElement.insertBefore(
editor.ui.view.toolbar.element,
editor.ui.getEditableElement()
);
}
public ngOnInit() {}
}