| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /**
- * @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 upload/adapters/simpleuploadadapter
- */
- /* globals XMLHttpRequest, FormData, console */
- import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
- import FileRepository from '../filerepository';
- import { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
- /**
- * The Simple upload adapter allows uploading images to an application running on your server using
- * the [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) API with a
- * minimal {@link module:upload/adapters/simpleuploadadapter~SimpleUploadConfig editor configuration}.
- *
- * ClassicEditor
- * .create( document.querySelector( '#editor' ), {
- * simpleUpload: {
- * uploadUrl: 'http://example.com',
- * headers: {
- * ...
- * }
- * }
- * } )
- * .then( ... )
- * .catch( ... );
- *
- * See the {@glink features/image-upload/simple-upload-adapter "Simple upload adapter"} guide to learn how to
- * learn more about the feature (configuration, server–side requirements, etc.).
- *
- * Check out the {@glink features/image-upload/image-upload comprehensive "Image upload overview"} to learn about
- * other ways to upload images into CKEditor 5.
- *
- * @extends module:core/plugin~Plugin
- */
- export default class SimpleUploadAdapter extends Plugin {
- /**
- * @inheritDoc
- */
- static get requires() {
- return [ FileRepository ];
- }
- /**
- * @inheritDoc
- */
- static get pluginName() {
- return 'SimpleUploadAdapter';
- }
- /**
- * @inheritDoc
- */
- init() {
- const options = this.editor.config.get( 'simpleUpload' );
- if ( !options ) {
- return;
- }
- if ( !options.uploadUrl ) {
- /**
- * The {@link module:upload/adapters/simpleuploadadapter~SimpleUploadConfig#uploadUrl `config.simpleUpload.uploadUrl`}
- * configuration required by the {@link module:upload/adapters/simpleuploadadapter~SimpleUploadAdapter `SimpleUploadAdapter`}
- * is missing. Make sure the correct URL is specified for the image upload to work properly.
- *
- * @error simple-upload-adapter-missing-uploadUrl
- */
- console.warn( attachLinkToDocumentation(
- 'simple-upload-adapter-missing-uploadUrl: Missing the "uploadUrl" property in the "simpleUpload" editor configuration.'
- ) );
- return;
- }
- this.editor.plugins.get( FileRepository ).createUploadAdapter = loader => {
- return new Adapter( loader, options );
- };
- }
- }
- /**
- * Upload adapter.
- *
- * @private
- * @implements module:upload/filerepository~UploadAdapter
- */
- class Adapter {
- /**
- * Creates a new adapter instance.
- *
- * @param {module:upload/filerepository~FileLoader} loader
- * @param {module:upload/adapters/simpleuploadadapter~SimpleUploadConfig} options
- */
- constructor( loader, options ) {
- /**
- * FileLoader instance to use during the upload.
- *
- * @member {module:upload/filerepository~FileLoader} #loader
- */
- this.loader = loader;
- /**
- * The configuration of the adapter.
- *
- * @member {module:upload/adapters/simpleuploadadapter~SimpleUploadConfig} #options
- */
- this.options = options;
- }
- /**
- * Starts the upload process.
- *
- * @see module:upload/filerepository~UploadAdapter#upload
- * @returns {Promise}
- */
- upload() {
- return this.loader.file
- .then( file => new Promise( ( resolve, reject ) => {
- this._initRequest();
- this._initListeners( resolve, reject, file );
- this._sendRequest( file );
- } ) );
- }
- /**
- * Aborts the upload process.
- *
- * @see module:upload/filerepository~UploadAdapter#abort
- * @returns {Promise}
- */
- abort() {
- if ( this.xhr ) {
- this.xhr.abort();
- }
- }
- /**
- * Initializes the `XMLHttpRequest` object using the URL specified as
- * {@link module:upload/adapters/simpleuploadadapter~SimpleUploadConfig#uploadUrl `simpleUpload.uploadUrl`} in the editor's
- * configuration.
- *
- * @private
- */
- _initRequest() {
- const xhr = this.xhr = new XMLHttpRequest();
- xhr.open( 'POST', this.options.uploadUrl, true );
- xhr.responseType = 'json';
- }
- /**
- * Initializes XMLHttpRequest listeners
- *
- * @private
- * @param {Function} resolve Callback function to be called when the request is successful.
- * @param {Function} reject Callback function to be called when the request cannot be completed.
- * @param {File} file Native File object.
- */
- _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 ? response.error.message : genericErrorText );
- }
- resolve( response.url ? { default: response.url } : response.urls );
- } );
- // Upload progress when it is supported.
- /* istanbul ignore else */
- 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.
- *
- * @private
- * @param {File} file File instance to be uploaded.
- */
- _sendRequest( file ) {
- // Set headers if specified.
- const headers = this.options.headers || {};
- // Use the withCredentials flag if specified.
- const withCredentials = this.options.withCredentials || false;
- for ( const headerName of Object.keys( headers ) ) {
- this.xhr.setRequestHeader( headerName, headers[ headerName ] );
- }
- this.xhr.withCredentials = withCredentials;
- // Prepare the form data.
- const data = new FormData();
- data.append( 'upload', file );
- // Send the request.
- this.xhr.send( data );
- }
- }
- /**
- * The configuration of the {@link module:upload/adapters/simpleuploadadapter~SimpleUploadAdapter simple upload adapter}.
- *
- * ClassicEditor
- * .create( editorElement, {
- * simpleUpload: {
- * // The URL the images are uploaded to.
- * uploadUrl: 'http://example.com',
- *
- * // Headers sent along with the XMLHttpRequest to the upload server.
- * headers: {
- * ...
- * }
- * }
- * } );
- * .then( ... )
- * .catch( ... );
- *
- * See the {@glink features/image-upload/simple-upload-adapter "Simple upload adapter"} guide to learn more.
- *
- * See {@link module:core/editor/editorconfig~EditorConfig all editor configuration options}.
- *
- * @interface SimpleUploadConfig
- */
- /**
- * The configuration of the {@link module:upload/adapters/simpleuploadadapter~SimpleUploadAdapter simple upload adapter}.
- *
- * Read more in {@link module:upload/adapters/simpleuploadadapter~SimpleUploadConfig}.
- *
- * @member {module:upload/adapters/simpleuploadadapter~SimpleUploadConfig} module:core/editor/editorconfig~EditorConfig#simpleUpload
- */
- /**
- * The path (URL) to the server (application) which handles the file upload. When specified, enables the automatic
- * upload of resources (images) inserted into the editor content.
- *
- * Learn more about the server application requirements in the
- * {@glink features/image-upload/simple-upload-adapter#server-side-configuration "Server-side configuration"} section
- * of the feature guide.
- *
- * @member {String} module:upload/adapters/simpleuploadadapter~SimpleUploadConfig#uploadUrl
- */
- /**
- * An object that defines additional [headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) sent with
- * the request to the server during the upload. This is the right place to implement security mechanisms like
- * authentication and [CSRF](https://developer.mozilla.org/en-US/docs/Glossary/CSRF) protection.
- *
- * ClassicEditor
- * .create( editorElement, {
- * simpleUpload: {
- * headers: {
- * 'X-CSRF-TOKEN': 'CSRF-Token',
- * Authorization: 'Bearer <JSON Web Token>'
- * }
- * }
- * } );
- * .then( ... )
- * .catch( ... );
- *
- * Learn more about the server application requirements in the
- * {@glink features/image-upload/simple-upload-adapter#server-side-configuration "Server-side configuration"} section
- * of the feature guide.
- *
- * @member {Object.<String, String>} module:upload/adapters/simpleuploadadapter~SimpleUploadConfig#headers
- */
- /**
- * This flag enables the
- * [`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)
- * property of the request sent to the server during the upload. It affects cross-site requests only and, for instance,
- * allows credentials such as cookies to be sent along with the request.
- *
- * ClassicEditor
- * .create( editorElement, {
- * simpleUpload: {
- * withCredentials: true
- * }
- * } );
- * .then( ... )
- * .catch( ... );
- *
- * Learn more about the server application requirements in the
- * {@glink features/image-upload/simple-upload-adapter#server-side-configuration "Server-side configuration"} section
- * of the feature guide.
- *
- * @member {Boolean} [module:upload/adapters/simpleuploadadapter~SimpleUploadConfig#withCredentials=false]
- */
|