我试图将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变量设置为可观察值吗? 其次,如果这是完全错误的方法,您能帮我找到实现此方法的正确方法吗?我很高兴在需要时提供更多信息,但是这篇文章已经很长了,因此我将在此结束。在此先感谢您可以提供的任何帮助。
答案 0 :(得分:0)
最后我选择了Quill和React-quill。它不需要更改webpack,并具有适合我适度需求的API。