ckeditor5-image-upload-base64
Version:
The development environment of CKEditor 5 – the best browser-based rich text editor.
172 lines (145 loc) • 5.52 kB
JavaScript
/**
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/
/* global window */
import Babel from 'babel-standalone';
// Imports necessary to run a React application.
import React from 'react';
import ReactDOM from 'react-dom';
// The official <CKEditor> component for React.
import CKEditor from '@ckeditor/ckeditor5-react';
// The base editor class and features required to run the editor.
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
import Heading from '@ckeditor/ckeditor5-heading/src/heading';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline';
import Link from '@ckeditor/ckeditor5-link/src/link';
import Table from '@ckeditor/ckeditor5-table/src/table';
import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import Command from '@ckeditor/ckeditor5-core/src/command';
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
// ckeditor/productpreviewediting.js
class ProductPreviewEditing extends Plugin {
static get requires() {
return [ Widget ];
}
init() {
this._defineSchema();
this._defineConverters();
this.editor.commands.add( 'insertProduct', new InsertProductPreviewCommand( this.editor ) );
}
_defineSchema() {
const schema = this.editor.model.schema;
schema.register( 'productPreview', {
// Behaves like a self-contained object (e.g. an image).
isObject: true,
// Allow in places where other blocks are allowed (e.g. directly in the root).
allowWhere: '$block',
// Each product preview has an ID. A unique ID tells the application which
// product it represents and makes it possible to render it inside a widget.
allowAttributes: [ 'id' ]
} );
}
_defineConverters() {
const editor = this.editor;
const conversion = editor.conversion;
const renderProduct = editor.config.get( 'products' ).productRenderer;
// <productPreview> converters ((data) view → model)
conversion.for( 'upcast' ).elementToElement( {
view: {
name: 'section',
classes: 'product'
},
model: ( viewElement, modelWriter ) => {
// Read the "data-id" attribute from the view and set it as the "id" in the model.
return modelWriter.createElement( 'productPreview', {
id: parseInt( viewElement.getAttribute( 'data-id' ) )
} );
}
} );
// <productPreview> converters (model → data view)
conversion.for( 'dataDowncast' ).elementToElement( {
model: 'productPreview',
view: ( modelElement, viewWriter ) => {
// In the data view, the model <productPreview> corresponds to:
//
// <section class="product" data-id="..."></section>
return viewWriter.createEmptyElement( 'section', {
class: 'product',
'data-id': modelElement.getAttribute( 'id' )
} );
}
} );
// <productPreview> converters (model → editing view)
conversion.for( 'editingDowncast' ).elementToElement( {
model: 'productPreview',
view: ( modelElement, viewWriter ) => {
// In the editing view, the model <productPreview> corresponds to:
//
// <section class="product" data-id="...">
// <div class="product__react-wrapper">
// <ProductPreview /> (React component)
// </div>
// </section>
const id = modelElement.getAttribute( 'id' );
// The outermost <section class="product" data-id="..."></section> element.
const section = viewWriter.createContainerElement( 'section', {
class: 'product',
'data-id': id
} );
// The inner <div class="product__react-wrapper"></div> element.
// This element will host a React <ProductPreview /> component.
const reactWrapper = viewWriter.createRawElement( 'div', {
class: 'product__react-wrapper'
}, function( domElement ) {
// This the place where React renders the actual product preview hosted
// by a UIElement in the view. you are using a function (renderer) passed as
// editor.config.products#productRenderer.
renderProduct( id, domElement );
} );
viewWriter.insert( viewWriter.createPositionAt( section, 0 ), reactWrapper );
return toWidget( section, viewWriter, { label: 'product preview widget' } );
}
} );
}
}
// ckeditor/insertproductpreviewcommand.js
class InsertProductPreviewCommand extends Command {
execute( id ) {
this.editor.model.change( writer => {
// Insert <productPreview id="...">*</productPreview> at the current selection position
// in a way which will result in creating a valid model structure.
this.editor.model.insertContent( writer.createElement( 'productPreview', { id } ) );
} );
}
refresh() {
const model = this.editor.model;
const selection = model.document.selection;
const allowedIn = model.schema.findAllowedParent( selection.getFirstPosition(), 'productPreview' );
this.isEnabled = allowedIn !== null;
}
}
Object.assign( window, {
Babel,
React,
ReactDOM,
CKEditor,
ClassicEditor,
Essentials,
Heading,
Bold,
Italic,
Underline,
Link,
Table,
TableToolbar,
Paragraph,
ProductPreviewEditing,
InsertProductPreviewCommand
} );