UNPKG

@ckeditor/ckeditor5-image

Version:

Image feature for CKEditor 5.

101 lines (100 loc) 4.12 kB
/** * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ import { FileRepository } from 'ckeditor5/src/upload'; import { Command } from 'ckeditor5/src/core'; import { toArray } from 'ckeditor5/src/utils'; /** * @module image/imageupload/uploadimagecommand */ /** * The upload image command. * * The command is registered by the {@link module:image/imageupload/imageuploadediting~ImageUploadEditing} plugin as `uploadImage` * and it is also available via aliased `imageUpload` name. * * In order to upload an image at the current selection position * (according to the {@link module:widget/utils~findOptimalInsertionRange} algorithm), * execute the command and pass the native image file instance: * * ```ts * this.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => { * // Assuming that only images were pasted: * const images = Array.from( data.dataTransfer.files ); * * // Upload the first image: * editor.execute( 'uploadImage', { file: images[ 0 ] } ); * } ); * ``` * * It is also possible to insert multiple images at once: * * ```ts * editor.execute( 'uploadImage', { * file: [ * file1, * file2 * ] * } ); * ``` */ export default class UploadImageCommand extends Command { /** * @inheritDoc */ refresh() { const editor = this.editor; const imageUtils = editor.plugins.get('ImageUtils'); const selectedElement = editor.model.document.selection.getSelectedElement(); // TODO: This needs refactoring. this.isEnabled = imageUtils.isImageAllowed() || imageUtils.isImage(selectedElement); } /** * Executes the command. * * @fires execute * @param options Options for the executed command. * @param options.file The image file or an array of image files to upload. */ execute(options) { const files = toArray(options.file); const selection = this.editor.model.document.selection; const imageUtils = this.editor.plugins.get('ImageUtils'); // In case of multiple files, each file (starting from the 2nd) will be inserted at a position that // follows the previous one. That will move the selection and, to stay on the safe side and make sure // all images inherit the same selection attributes, they are collected beforehand. // // Applying these attributes ensures, for instance, that inserting an (inline) image into a link does // not split that link but preserves its continuity. // // Note: Selection attributes that do not make sense for images will be filtered out by insertImage() anyway. const selectionAttributes = Object.fromEntries(selection.getAttributes()); files.forEach((file, index) => { const selectedElement = selection.getSelectedElement(); // Inserting of an inline image replace the selected element and make a selection on the inserted image. // Therefore inserting multiple inline images requires creating position after each element. if (index && selectedElement && imageUtils.isImage(selectedElement)) { const position = this.editor.model.createPositionAfter(selectedElement); this._uploadImage(file, selectionAttributes, position); } else { this._uploadImage(file, selectionAttributes); } }); } /** * Handles uploading single file. */ _uploadImage(file, attributes, position) { const editor = this.editor; const fileRepository = editor.plugins.get(FileRepository); const loader = fileRepository.createLoader(file); const imageUtils = editor.plugins.get('ImageUtils'); // Do not throw when upload adapter is not set. FileRepository will log an error anyway. if (!loader) { return; } imageUtils.insertImage({ ...attributes, uploadId: loader.id }, position); } }