如何将自定义图像选择器连接到CKeditor5在react js中插入图像

时间:2019-03-10 21:05:40

标签: javascript reactjs ecmascript-6 ckeditor5

我试图将CKeditor集成到自定义文档编辑器中,使用ckeditor5-react模块可以很容易地将状态集成到数据中,但是在我的特定用例中,插入图像的默认行为是不理想的。我在应用程序中内置了一个图像库,因此我想用CKeditor按钮打开我的图像库组件,以便用户可以从库中选择图像,然后将图像插入光标所在的位置。 在尝试使用常规的现成的ClassicEditor构建实现这一目标之后,我意识到这将是不可能的,因此我创建了一个自定义插件,该插件应该可以实现我想要的功能:

import ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';
import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
import Heading from '@ckeditor/ckeditor5-heading/src/heading';
import Image from '@ckeditor/ckeditor5-image/src/image';
import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';
import Link from '@ckeditor/ckeditor5-link/src/link';
import List from '@ckeditor/ckeditor5-list/src/list';
import MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';
import Table from '@ckeditor/ckeditor5-table/src/table';
import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';

import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
import mix from '@ckeditor/ckeditor5-utils/src/mix';

import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';

import imageIcon from '@ckeditor/ckeditor5-core/theme/icons/image.svg';

export default class ClassicEditor extends ClassicEditorBase {}

class InsertImage extends Plugin {
    init() {
    const editor = this.editor;

    editor.ui.componentFactory.add( 'insertImage', locale => {
      const view = new ButtonView( locale );

      view.set( {
        label: 'Insert image',
                icon: imageIcon,
        tooltip: true,
      } );

      // set observables on editor
      editor.set( { 
        insertImageRequested: false,
        imageFileRequested: null
      } );


        // Callback executed once the image button is clicked.
      view.on( 'execute', () => {
        // set observable to indicate a request to insert image has been made...
        editor.set( { insertImageRequested: true } );
      });

      // Now this waits for the user to have selected a file URL which should show up 
      // in the imageFileRequested observable
      editor.on( 'change:imageFileRequested', (evt, newShizz, oldShizz) => {
        // // Which then injects the image into the body...
        const imageUrl = editor.imageFileRequested;
        editor.model.change( writer => {
          const imageElement = writer.createElement( 'image', {
            src: imageUrl
          } );
          // Insert the image in the current selection location.
          editor.model.insertContent( imageElement, editor.model.document.selection );
        });

        // and unsets our observables back to their original state
        editor.set( { 
          insertImageRequested: false,
          imageFileRequested: null
        } );
      } )

            return view;
        } );
    }
}
mix( InsertImage, ObservableMixin );

// Plugins to include in the build.
ClassicEditor.builtinPlugins = [
    Essentials,
    Autoformat,
    Bold,
    Italic,
    BlockQuote,
    EasyImage,
    Heading,
    Image,
    ImageStyle,
    ImageToolbar,
    ImageUpload,
    Link,
    List,
    MediaEmbed,
    Paragraph,
    PasteFromOffice,
    Table,
    TableToolbar,
    InsertImage
];

// Editor configuration.
ClassicEditor.defaultConfig = {
    toolbar: {
        items: [
            'heading',
            '|',
            'bold',
            'italic',
            'link',
            'bulletedList',
            'numberedList',
            'blockQuote',
            'insertTable',
            'mediaEmbed',
            'undo',
            'redo',
            '|',
            'InsertImage'
        ]
    },
    image: {
        toolbar: [
            'imageStyle:full',
            'imageStyle:side',
            '|',
            'imageTextAlternative'
        ]
    },
    table: {
        contentToolbar: [
            'tableColumn',
            'tableRow',
            'mergeTableCells'
        ]
    },
    // This value must be kept in sync with the language defined in webpack.config.js.
    language: 'en'
};

从上面的代码中,您可以看到它使用CKeditor5的Observable事件功能来设置2个可观察对象:insertImageRequested(布尔)或imageFileRequested(空或字符串)。 现在,在我的react组件中,我接收到“ insertImageRequested”更改事件并更新我的状态,以便库应该打开,并且我的组件可以正常运行(但是光标确实移到了我不希望的文档开头)。问题是我似乎无法让编辑器允许我从编辑器外部使用选定的图像URL设置第二个Observable“ imageFileRequested”,因此我无法将fileURL字符串发送回自定义编辑器以设置Observable < / p>

import React from 'react';
import PropTypes from 'prop-types';

...

import CKEditor from '@ckeditor/ckeditor5-react';
//import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import CustomEditor from './customCKeditor/ckeditor.js';

import styles from './articleEditor.scss'; 

class ArticleEditor extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      insertImageRequested: false,
      imageFileRequested: null,
      eventLogData: null
    }

    ...

    this.imageClick = this.imageClick.bind(this);
  }

  ...

  imageClick(){
// Temp Data to be passed to custom Ckeditor
    let tempURL = "https://via.placeholder.com/350x150";
    this.setState({
      insertImageRequested: false,
      imageFileRequested: tempURL
    })

  // HOW DO I PASS 'tempURL' variable to editor so that I can set it as the value for the imageFileRequested observable (so CKeditor on change event is triggered as shown above)?

  }

  render() {
    return(
        <div className={styles.container}>
          <CKEditor
            editor={ CustomEditor }
            data={this.state.articleBody}
            name={'articleBody'}

            config={{
                toolbar: [ 'InsertImage', '|', 'heading', '|', 'bold', 'italic', '|', 'link', 'bulletedList', 'numberedList', 'blockQuote', '|', "mediaEmbed", '|', 'undo', 'redo', '|', "insertTable", "tableColumn", "tableRow", "mergeTableCells", '|' ],
                heading: {
                    options: [
                        { model: 'paragraph', title: 'Paragraph' },
                        { model: 'heading1', view: 'h1', title: 'Heading 1'},
                        { model: 'heading2', view: 'h2', title: 'Heading 2'},
                        { model: 'heading3', view: 'h3', title: 'Heading 3'},
                        { model: 'heading4', view: 'h4', title: 'Heading 4'},
                        { model: 'heading5', view: 'h5', title: 'Heading 5'},
                        { model: 'heading6', view: 'h6', title: 'Heading 6'}
                    ]
                }
            }}

            onInit={ editor => {
              // A request for a new image has been made
              editor.on( 'change:insertImageRequested', (evt, newShizz, oldShizz) => {
                //reflect that in the react app state
                this.setState({
                  insertImageRequested: true
                })
              } )
            } }

            onChange={ ( event, editor ) => {
                console.log(event);
                console.log(editor);
                //console.log(editor.insertImageRequested);
                const data = editor.getData();
                console.log( { event, editor, data } );
                this.updateArticleBodyState(data);
                this.eventLogger(editor);

                // THIS DOES NOT WORK
                // //if(editor.imageFileRequested != null){
                //     console.log("imagefilerequested is defined!")
                //     editor.set( { imageFileRequested: this.state.imageFileRequested } );
                // //}

            } }
            onBlur={ editor => {
                //console.log( 'Blur.', editor );
            } }
            onFocus={ editor => {
                //console.log( 'Focus.', editor );
            } }
          />
        </div>
    );
  }
}


...

经过2天的努力,解决方案从相对简单到不必要的复杂过程,我想到我这样做的方式很可能不正确,而我的整个方法都错了,所以我想我的问题是是双重的。首先,以上方法是否正确? 如果是这样,您能帮我在ckeditor中将tempUrl变量设置为可观察值吗? 其次,如果这是完全错误的方法,您能帮我找到实现此方法的正确方法吗?我很高兴在需要时提供更多信息,但是这篇文章已经很长了,因此我将在此结束。在此先感谢您可以提供的任何帮助。

1 个答案:

答案 0 :(得分:0)

最后我选择了Quill和React-quill。它不需要更改webpack,并具有适合我适度需求的API。