2018-03-05 14:30:28 +01:00
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* Wysiwyg
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import React from 'react';
|
2018-03-16 14:52:17 +01:00
|
|
|
import showdown from 'showdown';
|
2018-03-08 12:56:44 +01:00
|
|
|
import {
|
2018-03-14 22:47:56 +01:00
|
|
|
ContentBlock,
|
2018-03-08 12:56:44 +01:00
|
|
|
ContentState,
|
|
|
|
|
convertFromHTML,
|
|
|
|
|
EditorState,
|
|
|
|
|
getDefaultKeyBinding,
|
2018-03-14 22:47:56 +01:00
|
|
|
genKey,
|
2018-03-08 18:55:49 +01:00
|
|
|
Modifier,
|
2018-03-08 12:56:44 +01:00
|
|
|
RichUtils,
|
2018-03-20 13:27:42 +01:00
|
|
|
SelectionState,
|
2018-03-08 12:56:44 +01:00
|
|
|
} from 'draft-js';
|
2018-03-16 11:45:21 +01:00
|
|
|
// import { stateFromMarkdown } from 'draft-js-import-markdown';
|
2018-03-14 22:47:56 +01:00
|
|
|
import { List } from 'immutable';
|
2018-03-05 14:30:28 +01:00
|
|
|
import PropTypes from 'prop-types';
|
2018-03-19 18:22:09 +01:00
|
|
|
import { isEmpty, isNaN, replace, trimEnd, trimStart, words } from 'lodash';
|
2018-03-05 14:30:28 +01:00
|
|
|
import cn from 'classnames';
|
2018-03-06 18:20:05 +01:00
|
|
|
import Controls from 'components/WysiwygInlineControls';
|
2018-03-14 22:20:39 +01:00
|
|
|
import Drop from 'components/WysiwygDropUpload';
|
2018-03-12 13:26:07 +01:00
|
|
|
import Select from 'components/InputSelect';
|
|
|
|
|
import WysiwygBottomControls from 'components/WysiwygBottomControls';
|
2018-03-12 14:02:34 +01:00
|
|
|
import WysiwygEditor from 'components/WysiwygEditor';
|
2018-03-14 22:47:56 +01:00
|
|
|
import request from 'utils/request';
|
2018-03-20 13:27:42 +01:00
|
|
|
// import { ToggleMode } from './components';
|
|
|
|
|
import { CONTROLS, SELECT_OPTIONS } from './constants';
|
2018-03-19 18:22:09 +01:00
|
|
|
import { getBlockStyle, getInnerText, getOffSets } from './helpers';
|
2018-03-13 13:12:06 +01:00
|
|
|
import styles from './styles.scss';
|
2018-03-06 18:20:05 +01:00
|
|
|
|
2018-03-08 12:56:44 +01:00
|
|
|
/* eslint-disable react/jsx-handler-names */
|
2018-03-15 19:10:02 +01:00
|
|
|
/* eslint-disable react/sort-comp */
|
2018-03-05 14:30:28 +01:00
|
|
|
class Wysiwyg extends React.Component {
|
2018-03-06 18:20:05 +01:00
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
2018-03-08 15:50:28 +01:00
|
|
|
this.state = {
|
|
|
|
|
editorState: EditorState.createEmpty(),
|
|
|
|
|
isFocused: false,
|
|
|
|
|
initialValue: '',
|
2018-03-14 22:20:39 +01:00
|
|
|
isDraging: false,
|
2018-03-16 11:45:21 +01:00
|
|
|
isPreviewMode: false,
|
2018-03-08 15:50:28 +01:00
|
|
|
headerValue: '',
|
2018-03-12 14:02:34 +01:00
|
|
|
toggleFullScreen: false,
|
2018-03-08 15:50:28 +01:00
|
|
|
};
|
2018-03-13 21:39:27 +01:00
|
|
|
|
2018-03-06 18:20:05 +01:00
|
|
|
this.focus = () => {
|
|
|
|
|
this.setState({ isFocused: true });
|
2018-03-09 12:45:37 +01:00
|
|
|
return this.domEditor.focus();
|
2018-03-09 16:41:24 +01:00
|
|
|
};
|
2018-03-19 12:30:04 +01:00
|
|
|
|
|
|
|
|
this.blur = () => {
|
|
|
|
|
this.setState({ isFocused: false });
|
|
|
|
|
return this.domEditor.blur();
|
|
|
|
|
};
|
2018-03-06 18:20:05 +01:00
|
|
|
}
|
2018-03-05 14:30:28 +01:00
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
if (this.props.autoFocus) {
|
|
|
|
|
this.focus();
|
|
|
|
|
}
|
2018-03-05 19:23:06 +01:00
|
|
|
|
|
|
|
|
if (!isEmpty(this.props.value)) {
|
|
|
|
|
this.setInitialValue(this.props);
|
|
|
|
|
}
|
2018-03-15 18:10:19 +01:00
|
|
|
document.addEventListener('keydown', this.handleTabKey);
|
2018-03-05 19:23:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
|
if (nextProps.value !== this.props.value && !this.state.hasInitialValue) {
|
|
|
|
|
this.setInitialValue(nextProps);
|
|
|
|
|
}
|
2018-03-06 21:32:48 +01:00
|
|
|
|
|
|
|
|
// Handle reset props
|
|
|
|
|
if (nextProps.value === this.state.initialValue && this.state.hasInitialValue) {
|
|
|
|
|
this.setInitialValue(nextProps);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 18:10:19 +01:00
|
|
|
componentWillUnmount() {
|
|
|
|
|
document.removeEventListener('keydown', this.handleTabKey);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-14 09:59:42 +01:00
|
|
|
/**
|
|
|
|
|
* Init the editor with data from
|
|
|
|
|
* @param {[type]} props [description]
|
|
|
|
|
*/
|
|
|
|
|
setInitialValue = (props) => {
|
|
|
|
|
const contentState = ContentState.createFromText(props.value);
|
|
|
|
|
let editorState = EditorState.createWithContent(contentState);
|
|
|
|
|
|
|
|
|
|
// Get the cursor at the end
|
|
|
|
|
editorState = EditorState.moveFocusToEnd(editorState);
|
|
|
|
|
this.setState({ editorState, hasInitialValue: true, initialValue: props.value });
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 19:10:02 +01:00
|
|
|
addSimpleBlock = (content, style) => {
|
|
|
|
|
const selectedText = this.getSelectedText();
|
|
|
|
|
const defaultContent = style === 'code-block' ? 'code block' : 'quote';
|
|
|
|
|
const innerContent = selectedText === '' ? replace(content, 'innerText', defaultContent) : replace(content, 'innerText', selectedText);
|
|
|
|
|
const newBlock = this.createNewBlock(innerContent);
|
|
|
|
|
const newContentState = this.createNewContentStateFromBlock(newBlock);
|
|
|
|
|
const newEditorState = this.createNewEditorState(newContentState, innerContent);
|
|
|
|
|
|
|
|
|
|
return this.setState({ editorState: EditorState.moveFocusToEnd(newEditorState) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addLink = () => {
|
|
|
|
|
const selectedText = this.getSelectedText();
|
|
|
|
|
const link = selectedText === '' ? ' [text](link)' : `[text](${selectedText})`;
|
|
|
|
|
const text = Modifier.replaceText(this.getEditorState().getCurrentContent(), this.getSelection(), link);
|
|
|
|
|
const newEditorState = EditorState.push(this.getEditorState(), text, 'insert-characters');
|
|
|
|
|
|
2018-03-19 19:01:05 +01:00
|
|
|
if (selectedText !== '') {
|
|
|
|
|
return this.setState({ editorState: EditorState.moveFocusToEnd(newEditorState) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cursorPosition = getOffSets(this.getSelection()).start;
|
|
|
|
|
const anchorOffset = cursorPosition - trimStart(link, ' [text](').length + link.length;
|
|
|
|
|
const focusOffset = cursorPosition + trimEnd(link, ')').length;
|
|
|
|
|
const updatedSelection = this.getSelection().merge({
|
|
|
|
|
anchorOffset,
|
|
|
|
|
focusOffset,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return this.setState({
|
|
|
|
|
editorState: EditorState.forceSelection(newEditorState, updatedSelection),
|
|
|
|
|
});
|
2018-03-15 19:10:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addLinkMediaBlockWithSelection = () => {
|
|
|
|
|
const selectedText = this.getSelectedText();
|
|
|
|
|
const link = selectedText === '' ? '' : ``;
|
|
|
|
|
const newBlock = this.createNewBlock(link);
|
|
|
|
|
const newContentState = this.createNewContentStateFromBlock(newBlock);
|
2018-03-20 13:27:42 +01:00
|
|
|
const anchorOffset = link.length - trimStart(link, '.length;
|
|
|
|
|
const focusOffset = trimEnd(link, ')`').length;
|
|
|
|
|
let newEditorState = this.createNewEditorState(newContentState, link);
|
|
|
|
|
let updatedSelection = new SelectionState({
|
|
|
|
|
anchorKey: newBlock.getKey(),
|
|
|
|
|
anchorOffset,
|
|
|
|
|
focusOffset,
|
|
|
|
|
focusKey: newBlock.getKey(),
|
|
|
|
|
isBackward: false,
|
|
|
|
|
});
|
2018-03-15 19:10:02 +01:00
|
|
|
|
2018-03-20 13:27:42 +01:00
|
|
|
if (getOffSets(this.getSelection()).start === 0) {
|
|
|
|
|
updatedSelection = this.getSelection().merge({
|
|
|
|
|
anchorOffset,
|
|
|
|
|
focusOffset,
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-03-15 19:10:02 +01:00
|
|
|
|
2018-03-20 13:27:42 +01:00
|
|
|
newEditorState = EditorState.acceptSelection(newEditorState, updatedSelection);
|
2018-03-15 19:10:02 +01:00
|
|
|
|
2018-03-20 13:27:42 +01:00
|
|
|
return this.setState({ editorState: EditorState.forceSelection(newEditorState, newEditorState.getSelection()) });
|
2018-03-15 19:10:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addEntity = (text, style) => {
|
2018-03-15 20:21:21 +01:00
|
|
|
const editorState = this.getEditorState();
|
|
|
|
|
const selectedText = this.getSelectedText();
|
|
|
|
|
|
|
|
|
|
// Don't handle selection
|
|
|
|
|
if (selectedText !== '') {
|
|
|
|
|
const textWithEntity = Modifier.replaceText(editorState.getCurrentContent(), this.getSelection(), replace(text, 'innerText', selectedText));
|
|
|
|
|
const newEditorState = EditorState.push(editorState, textWithEntity, 'insert-characters');
|
|
|
|
|
|
|
|
|
|
return this.setState({
|
|
|
|
|
editorState: EditorState.moveFocusToEnd(newEditorState),
|
|
|
|
|
}, () => {
|
|
|
|
|
this.focus();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cursorPosition = getOffSets(this.getSelection()).start;
|
|
|
|
|
const textWithEntity = Modifier.replaceText(editorState.getCurrentContent(), this.getSelection(), getInnerText(style));
|
2018-03-20 13:27:42 +01:00
|
|
|
const anchorOffset = cursorPosition - trimStart(getInnerText(style), '*_~`>').length + getInnerText(style).length;
|
|
|
|
|
const focusOffset = cursorPosition + trimEnd(getInnerText(style), '*_~`').length;
|
2018-03-15 20:21:21 +01:00
|
|
|
const updatedSelection = this.getSelection().merge({
|
2018-03-15 19:10:02 +01:00
|
|
|
anchorOffset,
|
|
|
|
|
focusOffset,
|
|
|
|
|
});
|
2018-03-15 20:21:21 +01:00
|
|
|
const newEditorState = EditorState.push(editorState, textWithEntity, 'insert-character');
|
|
|
|
|
|
|
|
|
|
return this.setState({
|
|
|
|
|
editorState: EditorState.forceSelection(newEditorState, updatedSelection),
|
2018-03-15 19:10:02 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addOlBlock = () => {
|
2018-03-19 18:06:48 +01:00
|
|
|
const currentBlockKey = this.getCurrentAnchorKey();
|
|
|
|
|
const previousContent = this.getEditorState().getCurrentContent().getBlockForKey(currentBlockKey).getText();
|
2018-03-15 19:10:02 +01:00
|
|
|
const number = previousContent ? parseInt(previousContent.split('.')[0], 10) : 0;
|
|
|
|
|
const liNumber = isNaN(number) ? 1 : number + 1;
|
|
|
|
|
const selectedText = this.getSelectedText();
|
|
|
|
|
const li = selectedText === '' ? `${liNumber}. ` : `${liNumber}. ${selectedText}`;
|
|
|
|
|
|
2018-03-20 14:49:49 +01:00
|
|
|
return this.addBlock(li);
|
2018-03-15 19:10:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addUlBlock = () => {
|
|
|
|
|
const selectedText = this.getSelectedText();
|
|
|
|
|
const li = selectedText === '' ? '- ' : `- ${selectedText}`;
|
2018-03-20 14:49:49 +01:00
|
|
|
|
|
|
|
|
return this.addBlock(li);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addBlock = (text) => {
|
|
|
|
|
const nextBlockKey = this.getNextBlockKey(this.getCurrentAnchorKey()) || genKey();
|
|
|
|
|
const newBlock = this.createNewBlock(text, 'block-list', nextBlockKey);
|
2018-03-15 19:10:02 +01:00
|
|
|
const newContentState = this.createNewContentStateFromBlock(newBlock);
|
2018-03-20 14:49:49 +01:00
|
|
|
const newEditorState = this.createNewEditorState(newContentState, text);
|
2018-03-15 19:10:02 +01:00
|
|
|
|
|
|
|
|
return this.setState({ editorState: EditorState.moveFocusToEnd(newEditorState) });
|
2018-03-20 14:49:49 +01:00
|
|
|
|
2018-03-15 19:10:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createNewEditorState = (newContentState, text) => {
|
|
|
|
|
let newEditorState;
|
|
|
|
|
|
|
|
|
|
if (getOffSets(this.getSelection()).start !== 0) {
|
|
|
|
|
newEditorState = EditorState.push(
|
|
|
|
|
this.getEditorState(),
|
|
|
|
|
newContentState,
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
const textWithEntity = Modifier.replaceText(this.getEditorState().getCurrentContent(), this.getSelection(), text);
|
|
|
|
|
newEditorState = EditorState.push(this.getEditorState(), textWithEntity, 'insert-characters');
|
|
|
|
|
}
|
|
|
|
|
return newEditorState;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-19 18:06:48 +01:00
|
|
|
createNewBlock = (text = '', type = 'unstyled', key = genKey()) => (
|
2018-03-15 19:10:02 +01:00
|
|
|
new ContentBlock({
|
2018-03-19 18:06:48 +01:00
|
|
|
key,
|
2018-03-15 19:10:02 +01:00
|
|
|
type,
|
|
|
|
|
text,
|
|
|
|
|
charaterList: List([]),
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
createNewBlockMap = (newBlock, contentState) => contentState.getBlockMap().set(newBlock.key, newBlock);
|
|
|
|
|
|
|
|
|
|
createNewContentStateFromBlock = (newBlock, contentState = this.getEditorState().getCurrentContent()) => (
|
|
|
|
|
ContentState
|
|
|
|
|
.createFromBlockArray(this.createNewBlockMap(newBlock, contentState).toArray())
|
|
|
|
|
.set('selectionBefore', contentState.getSelectionBefore())
|
|
|
|
|
.set('selectionAfter', contentState.getSelectionAfter())
|
|
|
|
|
)
|
|
|
|
|
|
2018-03-15 18:58:40 +01:00
|
|
|
getCharactersNumber = (editorState = this.getEditorState()) => {
|
|
|
|
|
const plainText = editorState.getCurrentContent().getPlainText();
|
|
|
|
|
const spacesNumber = plainText.split(' ').length;
|
|
|
|
|
|
|
|
|
|
return words(plainText).join('').length + spacesNumber - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 11:31:07 +01:00
|
|
|
getEditorState = () => this.state.editorState;
|
|
|
|
|
|
|
|
|
|
getSelection = () => this.getEditorState().getSelection();
|
|
|
|
|
|
2018-03-19 18:06:48 +01:00
|
|
|
getCurrentAnchorKey = () => this.getSelection().getAnchorKey();
|
|
|
|
|
|
2018-03-15 16:54:28 +01:00
|
|
|
getCurrentBlockMap = () => this.getEditorState().getCurrentContent().getBlockMap().toJS();
|
|
|
|
|
|
2018-03-15 11:31:07 +01:00
|
|
|
getCurrentContentBlock = () => this.getEditorState().getCurrentContent().getBlockForKey(this.getSelection().getAnchorKey());
|
|
|
|
|
|
2018-03-19 18:06:48 +01:00
|
|
|
getNextBlockKey = (currentBlockKey) => this.getEditorState().getCurrentContent().getKeyAfter(currentBlockKey);
|
|
|
|
|
|
2018-03-15 11:31:07 +01:00
|
|
|
getSelectedText = () => {
|
|
|
|
|
const { start, end } = getOffSets(this.getSelection());
|
|
|
|
|
|
|
|
|
|
return this.getCurrentContentBlock().getText().slice(start, end);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-14 09:59:42 +01:00
|
|
|
handleChangeSelect = ({ target }) => {
|
|
|
|
|
this.setState({ headerValue: target.value });
|
2018-03-15 18:10:19 +01:00
|
|
|
const selectedText = this.getSelectedText();
|
|
|
|
|
const title = selectedText === '' ? `${target.value} ` : `${target.value} ${selectedText}`;
|
2018-03-20 14:49:49 +01:00
|
|
|
this.addBlock(title);
|
2018-03-15 18:10:19 +01:00
|
|
|
|
2018-03-20 14:49:49 +01:00
|
|
|
return this.setState({ headerValue: '' });
|
2018-03-14 09:59:42 +01:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 11:45:21 +01:00
|
|
|
handleClickPreview = () => this.setState({ isPreviewMode: !this.state.isPreviewMode });
|
|
|
|
|
|
2018-03-14 22:47:56 +01:00
|
|
|
handleDragEnter = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
|
|
if (!this.state.isDraging) {
|
|
|
|
|
this.setState({ isDraging: true });
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-14 22:20:39 +01:00
|
|
|
|
|
|
|
|
handleDragLeave = () => this.setState({ isDraging: false });
|
|
|
|
|
|
|
|
|
|
handleDragOver = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleDrop = (e) => {
|
|
|
|
|
e.preventDefault();
|
2018-03-14 22:47:56 +01:00
|
|
|
const { dataTransfer: { files} } = e;
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
formData.append('files', files[0]);
|
|
|
|
|
const headers = {
|
|
|
|
|
'X-Forwarded-Host': 'strapi',
|
|
|
|
|
};
|
2018-03-14 22:20:39 +01:00
|
|
|
|
2018-03-14 22:47:56 +01:00
|
|
|
return request('/upload', {method: 'POST', headers, body: formData }, false, false)
|
|
|
|
|
.then(response => {
|
2018-03-20 13:27:42 +01:00
|
|
|
const { editorState } = this.state;
|
2018-03-14 22:47:56 +01:00
|
|
|
const link = ``;
|
2018-03-20 13:27:42 +01:00
|
|
|
const newBlock = this.createNewBlock(link);
|
|
|
|
|
const newContentState = this.createNewContentStateFromBlock(newBlock);
|
|
|
|
|
const newEditorState = EditorState.push(
|
|
|
|
|
editorState,
|
|
|
|
|
newContentState,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this.setState({ editorState: EditorState.moveFocusToEnd(newEditorState) });
|
2018-03-14 22:47:56 +01:00
|
|
|
})
|
|
|
|
|
.catch(err => {
|
|
|
|
|
console.log('error', err.response);
|
|
|
|
|
})
|
|
|
|
|
.finally(() => {
|
|
|
|
|
this.setState({ isDraging: false });
|
|
|
|
|
});
|
2018-03-14 22:20:39 +01:00
|
|
|
}
|
|
|
|
|
|
2018-03-15 16:54:28 +01:00
|
|
|
handleKeyCommand = (command, editorState) => {
|
|
|
|
|
const newState = RichUtils.handleKeyCommand(editorState, command);
|
|
|
|
|
const selection = editorState.getSelection();
|
|
|
|
|
const currentBlock = editorState.getCurrentContent().getBlockForKey(selection.getStartKey());
|
|
|
|
|
|
|
|
|
|
if (currentBlock.getText().split('')[0] === '-' && command === 'split-block') {
|
|
|
|
|
this.addUlBlock();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 17:18:05 +01:00
|
|
|
if (currentBlock.getText().split('.').length > 1 && !isNaN(parseInt(currentBlock.getText().split('.')[0], 10)) && command === 'split-block') {
|
2018-03-15 16:54:28 +01:00
|
|
|
this.addOlBlock();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newState) {
|
|
|
|
|
this.onChange(newState);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 18:10:19 +01:00
|
|
|
|
|
|
|
|
handleTabKey = (e) => {
|
|
|
|
|
if (e.keyCode === 9 /* TAB */ && this.state.isFocused) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const textWithEntity = Modifier.replaceText(this.getEditorState().getCurrentContent(), this.getSelection(), ' ');
|
|
|
|
|
const newEditorState = EditorState.push(this.getEditorState(), textWithEntity, 'insert-characters');
|
|
|
|
|
|
|
|
|
|
return this.setState({ editorState: EditorState.moveFocusToEnd(newEditorState) });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-14 09:59:42 +01:00
|
|
|
mapKeyToEditorCommand = (e) => {
|
|
|
|
|
if (e.keyCode === 9 /* TAB */) {
|
|
|
|
|
const newEditorState = RichUtils.onTab(
|
|
|
|
|
e,
|
|
|
|
|
this.state.editorState,
|
|
|
|
|
4, /* maxDepth */
|
|
|
|
|
);
|
|
|
|
|
if (newEditorState !== this.state.editorState) {
|
|
|
|
|
this.onChange(newEditorState);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return getDefaultKeyBinding(e);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 20:21:21 +01:00
|
|
|
onChange = (editorState) => {
|
|
|
|
|
// Update the state and force the focus
|
2018-03-19 12:30:04 +01:00
|
|
|
this.setState({ editorState });
|
2018-03-15 20:21:21 +01:00
|
|
|
this.props.onChange({ target: {
|
|
|
|
|
value: editorState.getCurrentContent().getPlainText(),
|
|
|
|
|
name: this.props.name,
|
|
|
|
|
type: 'textarea',
|
|
|
|
|
}});
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 19:10:02 +01:00
|
|
|
// NOTE: this need to be changed to preview markdown
|
|
|
|
|
previewHTML = () => {
|
2018-03-16 14:52:17 +01:00
|
|
|
const converter = new showdown.Converter();
|
|
|
|
|
// TODO: parse html to add empty blocks
|
|
|
|
|
// TODO handle img
|
|
|
|
|
const html = converter.makeHtml(this.props.value);
|
|
|
|
|
const blocksFromHTML = convertFromHTML(html);
|
2018-03-15 19:10:02 +01:00
|
|
|
// Make sure blocksFromHTML.contentBlocks !== null
|
|
|
|
|
if (blocksFromHTML.contentBlocks) {
|
|
|
|
|
const contentState = ContentState.createFromBlockArray(blocksFromHTML);
|
|
|
|
|
return EditorState.createWithContent(contentState);
|
2018-03-15 17:18:05 +01:00
|
|
|
}
|
|
|
|
|
|
2018-03-15 19:10:02 +01:00
|
|
|
// Prevent errors if value is empty
|
|
|
|
|
return EditorState.createEmpty();
|
2018-03-15 16:54:28 +01:00
|
|
|
}
|
|
|
|
|
|
2018-03-12 14:02:34 +01:00
|
|
|
toggleFullScreen = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.setState({
|
|
|
|
|
toggleFullScreen: !this.state.toggleFullScreen,
|
|
|
|
|
}, () => {
|
|
|
|
|
this.focus();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-08 12:56:44 +01:00
|
|
|
componentDidCatch(error, info) {
|
|
|
|
|
console.log('err', error);
|
|
|
|
|
console.log('info', info);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-05 14:30:28 +01:00
|
|
|
render() {
|
2018-03-16 11:45:21 +01:00
|
|
|
const { editorState, isPreviewMode } = this.state;
|
2018-03-05 14:30:28 +01:00
|
|
|
|
|
|
|
|
return (
|
2018-03-14 22:20:39 +01:00
|
|
|
<div
|
|
|
|
|
className={cn(
|
|
|
|
|
styles.editorWrapper,
|
|
|
|
|
this.state.isFocused && styles.editorFocus,
|
|
|
|
|
)}
|
|
|
|
|
onDragEnter={this.handleDragEnter}
|
|
|
|
|
onDragOver={this.handleDragOver}
|
|
|
|
|
>
|
|
|
|
|
{this.state.isDraging && (
|
|
|
|
|
<Drop onDrop={this.handleDrop} onDragOver={this.handleDragOver} onDragLeave={this.handleDragLeave} />
|
|
|
|
|
)}
|
2018-03-08 12:56:44 +01:00
|
|
|
<div className={styles.controlsContainer}>
|
2018-03-16 11:45:21 +01:00
|
|
|
<div style={{ minWidth: '161px', marginLeft: '8px', marginRight: '5px' }}>
|
2018-03-08 18:55:49 +01:00
|
|
|
<Select
|
|
|
|
|
name="headerSelect"
|
|
|
|
|
onChange={this.handleChangeSelect}
|
|
|
|
|
value={this.state.headerValue}
|
|
|
|
|
selectOptions={SELECT_OPTIONS}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2018-03-20 13:27:42 +01:00
|
|
|
{CONTROLS.map((value, key) => (
|
2018-03-08 12:56:44 +01:00
|
|
|
<Controls
|
|
|
|
|
key={key}
|
|
|
|
|
buttons={value}
|
|
|
|
|
editorState={editorState}
|
2018-03-08 14:24:26 +01:00
|
|
|
handlers={{
|
2018-03-12 12:05:29 +01:00
|
|
|
addEntity: this.addEntity,
|
2018-03-15 18:58:40 +01:00
|
|
|
addLink: this.addLink,
|
2018-03-15 11:31:07 +01:00
|
|
|
addLinkMediaBlockWithSelection: this.addLinkMediaBlockWithSelection,
|
2018-03-15 16:54:28 +01:00
|
|
|
addOlBlock: this.addOlBlock,
|
2018-03-15 18:27:18 +01:00
|
|
|
addSimpleBlock: this.addSimpleBlock,
|
2018-03-15 12:01:58 +01:00
|
|
|
addUlBlock: this.addUlBlock,
|
2018-03-08 14:24:26 +01:00
|
|
|
}}
|
2018-03-08 12:56:44 +01:00
|
|
|
onToggle={this.toggleInlineStyle}
|
|
|
|
|
onToggleBlock={this.toggleBlockType}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
2018-03-16 11:45:21 +01:00
|
|
|
<div className={styles.toggleModeWrapper}>
|
2018-03-20 13:27:42 +01:00
|
|
|
{/*}<ToggleMode isPreviewMode={isPreviewMode} onClick={this.handleClickPreview} />*/}
|
2018-03-16 11:45:21 +01:00
|
|
|
</div>
|
2018-03-08 12:56:44 +01:00
|
|
|
</div>
|
2018-03-16 13:48:32 +01:00
|
|
|
{isPreviewMode? (
|
2018-03-19 09:47:56 +01:00
|
|
|
<div className={styles.editor}>
|
2018-03-16 13:48:32 +01:00
|
|
|
<WysiwygEditor
|
|
|
|
|
blockStyleFn={getBlockStyle}
|
2018-03-16 14:52:17 +01:00
|
|
|
editorState={this.previewHTML()}
|
2018-03-16 13:48:32 +01:00
|
|
|
onChange={() => {}}
|
|
|
|
|
placeholder={this.props.placeholder}
|
|
|
|
|
spellCheck
|
|
|
|
|
/>
|
|
|
|
|
<input className={styles.editorInput} value="" tabIndex="-1" />
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className={styles.editor} onClick={this.focus}>
|
|
|
|
|
<WysiwygEditor
|
|
|
|
|
blockStyleFn={getBlockStyle}
|
|
|
|
|
editorState={editorState}
|
2018-03-19 18:06:48 +01:00
|
|
|
handleBeforeInput={this.handleBeforeInput}
|
2018-03-16 13:48:32 +01:00
|
|
|
handleKeyCommand={this.handleKeyCommand}
|
|
|
|
|
keyBindingFn={this.mapKeyToEditorCommand}
|
2018-03-19 12:30:04 +01:00
|
|
|
onBlur={this.blur}
|
2018-03-16 13:48:32 +01:00
|
|
|
onChange={this.onChange}
|
|
|
|
|
placeholder={this.props.placeholder}
|
|
|
|
|
setRef={(editor) => this.domEditor = editor}
|
|
|
|
|
spellCheck
|
|
|
|
|
/>
|
|
|
|
|
<input className={styles.editorInput} value="" tabIndex="-1" />
|
|
|
|
|
</div>
|
|
|
|
|
) }
|
2018-03-15 18:58:40 +01:00
|
|
|
<WysiwygBottomControls charactersNumber={this.getCharactersNumber()} onClick={this.toggleFullScreen} />
|
2018-03-06 18:20:05 +01:00
|
|
|
</div>
|
2018-03-05 14:30:28 +01:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-13 21:39:27 +01:00
|
|
|
// NOTE: handle defaultProps!
|
2018-03-05 14:30:28 +01:00
|
|
|
Wysiwyg.defaultProps = {
|
2018-03-05 19:23:06 +01:00
|
|
|
autoFocus: false,
|
2018-03-08 12:56:44 +01:00
|
|
|
onChange: () => {},
|
2018-03-06 18:20:05 +01:00
|
|
|
placeholder: '',
|
2018-03-08 12:56:44 +01:00
|
|
|
value: '',
|
2018-03-05 14:30:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Wysiwyg.propTypes = {
|
|
|
|
|
autoFocus: PropTypes.bool,
|
2018-03-08 12:56:44 +01:00
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
|
onChange: PropTypes.func,
|
2018-03-05 14:30:28 +01:00
|
|
|
placeholder: PropTypes.string,
|
2018-03-08 12:56:44 +01:00
|
|
|
value: PropTypes.string,
|
2018-03-05 14:30:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default Wysiwyg;
|