UNPKG

ckeditor5-image-upload-base64

Version:

The development environment of CKEditor 5 – the best browser-based rich text editor.

170 lines (139 loc) 5.52 kB
/** * @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 image/image/utils */ import { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; /** * Converts a given {@link module:engine/view/element~Element} to an image widget: * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the image widget element. * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator. * * @param {module:engine/view/element~Element} viewElement * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer. * @param {String} label The element's label. It will be concatenated with the image `alt` attribute if one is present. * @returns {module:engine/view/element~Element} */ export function toImageWidget( viewElement, writer, label ) { writer.setCustomProperty( 'image', true, viewElement ); return toWidget( viewElement, writer, { label: labelCreator } ); function labelCreator() { const imgElement = getViewImgFromWidget( viewElement ); const altText = imgElement.getAttribute( 'alt' ); return altText ? `${ altText } ${ label }` : label; } } /** * Checks if a given view element is an image widget. * * @param {module:engine/view/element~Element} viewElement * @returns {Boolean} */ export function isImageWidget( viewElement ) { return !!viewElement.getCustomProperty( 'image' ) && isWidget( viewElement ); } /** * Returns an image widget editing view element if one is selected. * * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection * @returns {module:engine/view/element~Element|null} */ export function getSelectedImageWidget( selection ) { const viewElement = selection.getSelectedElement(); if ( viewElement && isImageWidget( viewElement ) ) { return viewElement; } return null; } /** * Checks if the provided model element is an `image`. * * @param {module:engine/model/element~Element} modelElement * @returns {Boolean} */ export function isImage( modelElement ) { return !!modelElement && modelElement.is( 'element', 'image' ); } /** * Handles inserting single file. This method unifies image insertion using {@link module:widget/utils~findOptimalInsertionPosition} method. * * model.change( writer => { * insertImage( writer, model, { src: 'path/to/image.jpg' } ); * } ); * * @param {module:engine/model/writer~Writer} writer * @param {module:engine/model/model~Model} model * @param {Object} [attributes={}] Attributes of inserted image */ export function insertImage( writer, model, attributes = {} ) { const imageElement = writer.createElement( 'image', attributes ); const insertAtSelection = findOptimalInsertionPosition( model.document.selection, model ); model.insertContent( imageElement, insertAtSelection ); // Inserting an image might've failed due to schema regulations. if ( imageElement.parent ) { writer.setSelection( imageElement, 'on' ); } } /** * Checks if image can be inserted at current model selection. * * @param {module:engine/model/model~Model} model * @returns {Boolean} */ export function isImageAllowed( model ) { const schema = model.schema; const selection = model.document.selection; return isImageAllowedInParent( selection, schema, model ) && !checkSelectionOnObject( selection, schema ) && isInOtherImage( selection ); } /** * Get view `<img>` element from the view widget (`<figure>`). * * Assuming that image is always a first child of a widget (ie. `figureView.getChild( 0 )`) is unsafe as other features might * inject their own elements to the widget. * * The `<img>` can be wrapped to other elements, e.g. `<a>`. Nested check required. * * @param {module:engine/view/element~Element} figureView * @returns {module:engine/view/element~Element} */ export function getViewImgFromWidget( figureView ) { const figureChildren = []; for ( const figureChild of figureView.getChildren() ) { figureChildren.push( figureChild ); if ( figureChild.is( 'element' ) ) { figureChildren.push( ...figureChild.getChildren() ); } } return figureChildren.find( viewChild => viewChild.is( 'element', 'img' ) ); } // Checks if image is allowed by schema in optimal insertion parent. // // @returns {Boolean} function isImageAllowedInParent( selection, schema, model ) { const parent = getInsertImageParent( selection, model ); return schema.checkChild( parent, 'image' ); } // Check if selection is on object. // // @returns {Boolean} function checkSelectionOnObject( selection, schema ) { const selectedElement = selection.getSelectedElement(); return selectedElement && schema.isObject( selectedElement ); } // Checks if selection is placed in other image (ie. in caption). function isInOtherImage( selection ) { return [ ...selection.focus.getAncestors() ].every( ancestor => !ancestor.is( 'element', 'image' ) ); } // Returns a node that will be used to insert image with `model.insertContent` to check if image can be placed there. function getInsertImageParent( selection, model ) { const insertAt = findOptimalInsertionPosition( selection, model ); const parent = insertAt.parent; if ( parent.isEmpty && !parent.is( 'element', '$root' ) ) { return parent.parent; } return parent; }