scripts/core/editor3/react.tsx
import React from 'react';
import createEditorStore from './store';
import {Editor3} from './components';
import {Provider} from 'react-redux';
import ng from 'core/services/ng';
import {ContentState, RawDraftContentState, convertFromRaw, EditorState, convertToRaw} from 'draft-js';
import {setReadOnly, changeEditorState} from './actions/editor3';
import {isEqual} from 'lodash';
import {RICH_FORMATTING_OPTION} from 'superdesk-api';
interface IProps {
// If set, it will be used to make sure the toolbar is always
// visible when scrolling. If not set, window object is used as reference.
// Any valid jQuery selector will do.
scrollContainer?: any;
// Whether this editor is the target for find & replace
// operations. The Find & Replace service can only have one editor as
// target.
findReplaceTarget: boolean;
// If true, allows inline highlights (commenting, annotating, etc.).
highlights: boolean;
// Editor format options that are enabled and should be displayed
// in the toolbar.
editorFormat: Array<RICH_FORMATTING_OPTION>;
rawDraftContentState: RawDraftContentState;
onChange(contentState: RawDraftContentState): void;
// HTML value of editor. If contentState is not set, this is used.
html: string;
readOnly: boolean;
singleLine: boolean;
onChangeDebounce: 100;
// Spellchecker's language.
language?: string;
// If true, images may have an editable title.
showTitle: boolean;
tabindex: number;
}
/**
* @ngdoc React
* @name Editor
* @description Editor as a React component. Standalone means that it isn't connected to article item.
*/
export class Editor3Standalone extends React.Component<IProps> {
static defaultProps = {
findReplaceTarget: false,
highlights: false,
editorFormat: [],
html: '',
readOnly: false,
singleLine: false,
onChangeDebounce: 100,
showTitle: false,
tabindex: 0,
};
store: any;
constructor(props: IProps) {
super(props);
this.onChangeInterceptor = this.onChangeInterceptor.bind(this);
const {
language,
readOnly,
singleLine,
tabindex,
showTitle,
editorFormat,
} = this.props;
const store = createEditorStore(
{
language: language,
readOnly: readOnly,
singleLine: singleLine,
tabindex: tabindex,
showTitle: showTitle,
editorFormat: editorFormat,
editorState: this.props.rawDraftContentState,
onChange: this.onChangeInterceptor,
},
null,
true,
);
if (props.findReplaceTarget) {
ng.get('editor3').setStore(store);
}
this.store = store;
}
onChangeInterceptor(contentState: ContentState): void {
// ensure that onChange value is of the same type as received from the props
const rawState = convertToRaw(contentState);
this.props.onChange(rawState);
}
componentDidUpdate(prevProps: IProps) {
if (this.props.readOnly !== prevProps.readOnly) {
this.store.dispatch(setReadOnly(this.props.readOnly));
}
const rawStateFromStore = convertToRaw(this.store.getState().editorState.getCurrentContent());
if (isEqual(this.props.rawDraftContentState, rawStateFromStore) === false) {
// This component holds it's own state which is derived from props
// internal state is reloaded when it doesn't match with what's in the props
this.store.dispatch(
changeEditorState(EditorState.createWithContent(convertFromRaw(this.props.rawDraftContentState)), true),
);
}
}
render() {
const {scrollContainer, singleLine} = this.props;
return (
<Provider store={this.store}>
<Editor3 scrollContainer={scrollContainer} singleLine={singleLine} />
</Provider>
);
}
}