fulan-editor
Version:
An open source react editor based on draft-Js and ant design, good support HTML, markdown and Draft Raw format.
898 lines (834 loc) • 33 kB
JSX
/**
* Created by lizhen on 4/26/2016.
*/
import './components.css'
import '../global/supports/resources/system.css';
// import 'antd/dist/antd.css';
import React, {Component} from 'react';
import ReactDom from 'react-dom';
import {
AtomicBlockUtils,
Editor,
Entity,
convertToRaw,
convertFromRaw,
EditorState,
RichUtils,
Modifier,
ContentBlock,
convertFromHTML,
CompositeDecorator,
ContentState,
getDefaultKeyBinding,
KeyBindingUtil,
DraftPasteProcessor,
SelectionState
} from 'draft-js';
import {
Upload,
Modal,
Button,
Popconfirm,
Form,
Input,
message,
// Affix,
Icon
} from 'antd';
import {stateToHTML,stateFromHTML,stateToMD,stateFromMD} from './utils';
import getSelectedBlocks from './utils/stateUtils/getSelectedBlocks';
import {PRO_COMMON} from '../global/supports/publicDatas';
import {lang} from '../global/i18n';
import LinkDecorator from "./decorators/LinkDecorator";
import ImageDecorator from "./decorators/ImageDecorator";
import VideoDecorator from "./decorators/VideoDecorator";
import AudioDecorator from "./decorators/AudioDecorator";
import ImgStyleControls from "./toolBar/mediaImageUploader"
import VideoStyleControls from "./toolBar/medioVideoUploader"
import AudioStyleControls from "./toolBar/medioAudioUploader"
import ColorControls from "./toolBar/colorControls"
import AutoSaveControls from "./toolBar/autoSaveList"
import StyleButton from "./toolBar/styleButton"
import BlockStyleControls from "./toolBar/blockStyleControls"
import AlignmentControls from "./toolBar/alignmentControls"
import InlineStyleControls from "./toolBar/inlineStyleControls"
import PasteNoStyleControls from "./toolBar/pasteNoStyleControls"
import {AddUrl,CloseUrl} from "./toolBar/urlControls"
import {OpenFull,AutoSave,SourceEditor} from "./toolBar/cookieControls"
import RemoveStyleControls from "./toolBar/removeStyleControls"
import UndoRedo from "./toolBar/undoredoControls"
import {colorStyleMap} from "./utils/colorConfig"
import ExtendedRichUtils from "./utils/ExtendedRichUtils"
import isEmpty from 'lodash/isEmpty';
import trim from 'lodash/trim';
import Vnd from 'videoplugin';
const decorator = new CompositeDecorator([
LinkDecorator,
ImageDecorator,
VideoDecorator,
AudioDecorator
]);
class EditorConcist extends React.Component {
constructor(props) {
super(props);
this.state = {
openFullTest:"",
showSourceEditor:"",
showURLInput: false,
urlValue: '',
hasPasted:false,
autoSaveFun:null,
visible: false,
showMarkdownSource:false,
tempSouceContent:"",
language:"en",
editorState: (() => {
let originalString = this.props.importContent;
originalString = !originalString
? " "
: originalString;
if (!originalString) { //Error, do not user 'createEmpty' for the time been.
//this.state.alwaysEnterEmpty = true;
return EditorState.createEmpty(decorator);
} else {
const ConvertFormatProps = this.props.convertFormat;
let contentState;
if(ConvertFormatProps === 'html') {
contentState = stateFromHTML(originalString);
} else if (ConvertFormatProps === 'markdown') {
// console.log("markdown originalString",originalString)
contentState = stateFromMD(originalString);
} else if(ConvertFormatProps === 'raw'){
originalString=originalString.replace(/\s/g,"")?originalString:"{}";
let rawContent = JSON.parse(originalString);
if (isEmpty(rawContent)) {
return EditorState.createWithContent("", decorator);
}
contentState = convertFromRaw(rawContent);
}
return EditorState.createWithContent(contentState, decorator);
}
})()
};
this.onChange = (editorState) => {
this.setState({editorState});
let that = this;
if(that.timer){
clearTimeout(that.timer);
}
that.timer = setTimeout(function() {
//convert state to object.
let rawContentState = that.state.editorState.getCurrentContent()
//const rawContent = convertToRaw(rawContentState);
// console.log('rawContentState', rawContentState);
let content;
const ConvertFormatProps = that.props.convertFormat;
if(ConvertFormatProps === 'html') {
content = stateToHTML(rawContentState);
}else if (ConvertFormatProps === 'markdown') {
content = stateToMD(rawContentState);
}else if(ConvertFormatProps === 'raw') {
const rawContent = convertToRaw(rawContentState);
content = JSON.stringify(rawContent);
}
that.props.cbReceiver(content);
//NOTE: When you set 'active' as 'true' in the editor, DO NOT use 'this.forceUpdate();', or you could not have able to select the text in editor probably.
//富文本编辑器在设置active是true时,不可使用forceUpdate,否则会造成无法选中文本的问题!
}, 300);
};
this.handleKeyCommand = (command) => this._handleKeyCommand(command);
this.toggleBlockType = (type) => this._toggleBlockType(type);
this.toggleAlignment = (type) => this._toggleAlignment(type);
this.toggleInlineStyle = (style) => this._toggleInlineStyle(style);
this.customKeyBinding = this._customKeyBinding.bind(this);
this.handlePastedText=this._handlePastedText.bind(this);
/*VIDEO/AUDIO/IMAGE*/
this.logState = () => {
const content = this.state.editorState.getCurrentContent();
// console.log(convertToRaw(content));
};
this.addMedia = this._addMedia.bind(this);
this.addAudio = this._addAudio.bind(this);
this.addImage = this._addImage.bind(this);
this.addVideo = this._addVideo.bind(this);
this.undoRedo = this._undoRedo.bind(this);
this.removeStyle = this._removeStyle.bind(this);
this.pasteNoStyle = this._pasteNoStyle.bind(this);
this.choiceAutoSave=this._choiceAutoSave.bind(this);
this.toggleColor = (toggledColor) => this._toggleColor(toggledColor);
this.promptForLink = this._promptForLink.bind(this);
this.onURLChange = (e) => this.setState({urlValue: e.target.value});
this.confirmLink = this._confirmLink.bind(this);
this.onLinkInputKeyDown = this._onLinkInputKeyDown.bind(this);
this.removeLink = this._removeLink.bind(this);
this.openFull=this._openFull.bind(this);
this.toggleSource=this._toggleSource.bind(this);
this.handleOk = this.handleOk.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.solidHtml=this._solidHtml.bind(this);
this.changeMrakdownContent=this._changeMrakdownContent.bind(this);
}
get localLang(){
let lang= navigator.language||navigator.browserLanguage;
return{fullLang:lang,simpLang:lang.split("-")[0]}
}
componentDidMount() {
let currLang=this.localLang,language;
if (lang[this.props.lang]) {
language=this.props.lang;
}else if (lang[currLang.fullLang]) {
language=currLang.fullLang;
}else if (lang[currLang.simpLang]){
language=currLang.simpLang;
}
language=language||"en";
this.setState({language,
openFullTest:lang[language].fullScreen,
showSourceEditor:lang[language].sourceCode
});
let content = (this.props.importContent);
// const decorator = new CompositeDecorator([
// LinkDecorator,
// ImageDecorator
// ]);
const contentState = stateFromHTML(content);
// console.log("componentDidMount content",content);
// console.log("componentDidMount contentState",JSON.stringify(contentState));
// let values = EditorState.createWithContent(contentState, decorator);
// this.state.editorState = values;
this.state.autoSaveFun=setInterval(()=>{
// Automaticly save text to draft-box every minute.
//每分钟自动保存草稿一次
this.handleKeyCommand("editor-save");
},60000);
}
// This hook function will be called while you edit text in editor.
// 此钩子用作编辑时候的回调
componentWillReceiveProps(newProps) {
if (!newProps.active) {
return false;
}
if (newProps.importContent == this.props.importContent) {
return false;
}
const ConvertFormatProps = this.props.convertFormat;
let newContent ="";
// console.log("ConvertFormatProps",ConvertFormatProps)
if (ConvertFormatProps==="html") {
newContent = newProps.importContent.replace(/[\s\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]\>/g,">");
if (newContent == "undefined" ||!newContent) {
newContent = "<p> </p>";
}
} else if (ConvertFormatProps==="markdown") {
newContent = newProps.importContent||"";
this.state.tempSouceContent=newContent;
} else if (ConvertFormatProps==="raw") {
newContent = newProps.importContent||"{}";
}
/*const decorator = new CompositeDecorator([
LinkDecorator,
ImageDecorator,
VideoDecorator,
AudioDecorator
]);*/
// console.log("newContent",newContent)
let contentState;
if(ConvertFormatProps === 'html') {
contentState = stateFromHTML(newContent);
} else if (ConvertFormatProps === 'markdown') {
contentState = stateFromMD(newContent);
} else if(ConvertFormatProps === 'raw'){
let rawContent = JSON.parse(newContent);
contentState = convertFromRaw(rawContent);
}
// console.log("contentState",contentState)
// console.log("componentWillReceiveProps newContent",newContent);
// console.log("componentWillReceiveProps contentState",JSON.stringify(contentState));
let values = EditorState.createWithContent(contentState, decorator);
this.state.editorState = values;
}
componentWillUnmount(){
// console.log("componentWillUnmount! this.state.autoSaveFun",this.state.autoSaveFun);
clearInterval(this.state.autoSaveFun);
}
handleOk() {
this.setState({visible: false});
}
handleCancel(e) {
this.setState({visible: false});
}
_promptForLink(e) {
e.preventDefault();
const {editorState} = this.state;
const selection = editorState.getSelection();
if (!selection.isCollapsed()) {
let that = this;
this.setState({
showURLInput: true,
urlValue: '',
visible: true
}, () => {
});
} else {
message.error(lang[this.state.language].selectedText, 5);
}
}
_confirmLink(e) {
// console.log("_confirmLink urlValue", urlValue)
const {editorState, urlValue} = this.state;
const entityKey = Entity.create('LINK', 'MUTABLE', {url: urlValue});
this.onChange(RichUtils.toggleLink(editorState, editorState.getSelection(), entityKey));
this.setState({
showURLInput: false,
urlValue: ''
}, () => {
setTimeout(() => {
}, 0);
});
}
_onLinkInputKeyDown(e) {
if (e.which === 13) {
this._confirmLink(e);
return false;
}
}
_removeLink(e) {
e.preventDefault();
const {editorState} = this.state;
const selection = editorState.getSelection();
if (!selection.isCollapsed()) {
this.onChange(RichUtils.toggleLink(editorState, selection, null));
} else {
message.error(lang[this.state.language].selectedLink, 5);
}
}
_openFull(e){
e.preventDefault();
let ele=document.querySelector(".RichEditor-root");
// let affix=document.querySelector("#text-editor-affix"),affixToolBar=document.querySelector("#text-editor-affix>div");
if(ele.classList.contains("openFullAll")){
ele.className = ele.className.replace("openFullAll","");
// affix.style="";
// affixToolBar.className="";
// affixToolBar.style=""
this.setState({
openFullTest:lang[this.state.language].fullScreen
})
}else{
ele.className += ' openFullAll';
setTimeout(()=>{
// affix.style="width: "+affix.offsetWidth+"px; height: 0; margin-bottom: 70px;";
// affixToolBar.className="ant-affix";
// affixToolBar.style="position: fixed; top: 0; left: 0; width: "+affix.offsetWidth+"px;margin: 0 15px 15px;"
},500)
this.setState({
openFullTest:lang[this.state.language].quitFullScreen
})
}
}
_toggleSource(e){
e.preventDefault();
let ele=document.querySelector(".RichEditor-root")
if(ele.classList.contains("showSource")){
ele.className = ele.className.replace("showSource","");
this.setState({
showSourceEditor:lang[this.state.language].sourceCode,
showMarkdownSource:false
})
}else{
ele.className += ' showSource';
this.setState({
showSourceEditor:lang[this.state.language].preview,
showMarkdownSource:true
})
}
}
_changeMrakdownContent(e){
let markdownContent = e.target.value;
// console.log("markdownContent",markdownContent);
let contentState = stateFromMD(markdownContent);
let values = EditorState.createWithContent(contentState, decorator);
this.state.tempSouceContent=markdownContent;
this.state.editorState = values;
this.forceUpdate();
}
_handleKeyCommand(command) {
// console.log("command",command);
const {editorState} = this.state;
const newState = RichUtils.handleKeyCommand(editorState, command);
if (command === 'editor-save'&&this.props.autoSave==true) {
// window.localDB//start20Text
// let Data=PRO_COMMON.localDB.getter("grab_news_data") || [];
let rawContentState = editorState.getCurrentContent()
let content = "",newText="";
const ConvertFormatProps = this.props.convertFormat;
if(ConvertFormatProps === 'html') {
content = stateToHTML(rawContentState);
newText=content.replace(/<[^>]*>|&[^;]*;/g, "");
}else if (ConvertFormatProps === 'markdown') {
content = stateToMD(rawContentState);
}else if(ConvertFormatProps === 'raw') {
const rawContent = convertToRaw(rawContentState);
content = JSON.stringify(rawContent);
}
if (newText.length<30) {
return false;
}
let start30Text=newText.substr(0,30);
PRO_COMMON.localDB.setter("$d"+start30Text, content);
message.success(lang[this.state.language].successToDraftBox,5)
return true;
}else if(command==="editor-paste"){
return true;
}
if (newState) {
this.onChange(newState);
return true;
}
return false;
}
_customKeyBinding(e) {
const {hasCommandModifier} = KeyBindingUtil;
if (e.keyCode === 83/* `S` key */ && hasCommandModifier(e)) {
return 'editor-save';
}else if(e.keyCode === 86/* `V` key */ && hasCommandModifier(e)){
}
return getDefaultKeyBinding(e);
}
_solidHtml(html) {
// html=html.replace(/"((?:\\.|[^"\\])*)"/g,"");
//Remove all content in quote. e.g. style="" class=""
//去掉所有英文单引号里面的内容,比如 style="" class=""
let walk_the_DOM = function walk(node, func) {
func(node);
node = node.firstChild;
while (node) {
walk(node, func);
node = node.nextSibling;
}
};
let wrapper = document.createElement('div');
wrapper.innerHTML = html;
walk_the_DOM(wrapper.firstChild, function(element) {
if (element.removeAttribute) {
element.removeAttribute('id');
element.removeAttribute('style');
element.removeAttribute('class');
}
});
return wrapper.innerHTML;
}
_handlePastedText(text,sourceString){
sourceString = this.solidHtml(sourceString);
// console.log("_handlePastedText text",text);
// console.log("_handlePastedText sourceString",typeof(sourceString),sourceString);
if (text=="undefined"&&sourceString=="undefined") {
// console.log("_handlePastedText return false");
return false;
}
if (sourceString=="undefined"||!sourceString) {
this.pasteNoStyle(text)
return false;
}
const {editorState} = this.state;
let rawContentState = editorState.getCurrentContent()
let content = "",newText="";
const ConvertFormatProps = this.props.convertFormat;
if(ConvertFormatProps === 'html') {
content = stateToHTML(rawContentState);
newText=content.replace(/<[^>]*>|&[^;]*;/g, "");
}else if (ConvertFormatProps === 'markdown') {
content = stateToMD(rawContentState);
}else if(ConvertFormatProps === 'raw') {
const rawContent = convertToRaw(rawContentState);
content = JSON.stringify(rawContent);
}
if (this.state.hasPasted===true||trim(newText).length>0) {
const blockMap = ContentState.createFromText(text.trim()).blockMap;
const newState = Modifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), blockMap);
this.onChange(EditorState.push(editorState, newState, 'insert-fragment'));
return true;
}
this.state.hasPasted=true;
const decorator = new CompositeDecorator([
LinkDecorator,
ImageDecorator,
VideoDecorator,
AudioDecorator
]);
let contentState = "";
if(ConvertFormatProps === 'html') {
contentState = stateFromHTML(sourceString);
}else if (ConvertFormatProps === 'markdown') {
contentState = stateFromMD(sourceString);
}else if(ConvertFormatProps === 'raw') {
contentState = convertFromRaw(sourceString);
}
let values = EditorState.createWithContent(contentState, decorator);
this.state.editorState = values;
message.success(lang[this.state.language].successPasteCleanText,5);
this.forceUpdate();
return true;
//Override the default paste behavior of the editor
//覆盖编辑器的默认粘贴行为
}
_toggleBlockType(blockType) {
this.onChange(RichUtils.toggleBlockType(this.state.editorState, blockType));
}
_toggleAlignment(alignment) {
//This method only supports the data type like:
//这种方式仅支持的数据类型:
// https://github.com/facebook/draft-js/blob/master/src/model/constants/DraftBlockType.js
// const {editorState} = this.state;
// const selection = editorState.getSelection();
// const contentState = editorState.getCurrentContent();
// const alignBlock = Modifier.setBlockType(contentState, selection, alignment)
// this.setState({
// editorState: EditorState.push(editorState, alignBlock)
// })
// right way:
this.onChange(ExtendedRichUtils.toggleAlignment(this.state.editorState, alignment));
}
_toggleInlineStyle(inlineStyle) {
this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, inlineStyle));
}
/*VIDEO/AUDIO/IMAGE*/
_addMedia(type, Object) {
let src = Object.url;
if (!src) {
throw new Error(lang[this.state.language].errorUploadingFile);
return false;
}
const entityKey = Entity.create(type, 'IMMUTABLE', {src});
return AtomicBlockUtils.insertAtomicBlock(this.state.editorState, entityKey, ' ');
}
_addAudio(Objects) {
let that = this;
Objects.map((item, i) => {
setTimeout(() => {
return that.onChange(that.addMedia('audio', item));
}, i * 100);
})
}
_addImage(Objects) {
let that = this;
// console.log("Objects Objects", Objects);
Objects.map((item, i) => {
setTimeout(() => {
let imageObj=that.addMedia('image', item);
// console.log("imageObj",imageObj,JSON.stringify(imageObj));
return that.onChange(imageObj);
}, i * 100);
})
}
_addVideo(Objects) {
let that = this;
Objects.map((item, i) => {
setTimeout(() => {
return that.onChange(that.addMedia('video', item));
}, i * 100);
});
}
_pasteNoStyle(sourceString){
const decorator = new CompositeDecorator([
LinkDecorator,
ImageDecorator,
VideoDecorator,
AudioDecorator
]);
let contentState = "";
const ConvertFormatProps = this.props.convertFormat;
if(ConvertFormatProps === 'html') {
sourceString='<p>' + sourceString.replace(/\n([ \t]*\n)+/g, '</p><p>')
.replace('\n', '<br />') + '</p>'
contentState = stateFromHTML(sourceString);
}else if (ConvertFormatProps === 'markdown') {
contentState = stateFromMD(sourceString);
}else if(ConvertFormatProps === 'raw') {
contentState = convertFromRaw(sourceString);
}
// console.log("_pasteNoStyle sourceString",sourceString);
// console.log("_pasteNoStyle contentState",JSON.stringify(contentState));
let values = EditorState.createWithContent(contentState,decorator);
this.state.editorState = values;
this.forceUpdate();
}
_undoRedo(type){
if (this.state.editorState) {
let newEditorState=null;
if (type=="undo") {
newEditorState=EditorState.undo(this.state.editorState);
}else {
newEditorState=EditorState.redo(this.state.editorState);
}
this.setState({editorState:newEditorState});
}
}
_removeStyle() {
const {editorState} = this.state;
const selection = editorState.getSelection();
const contentState = editorState.getCurrentContent();
const styles = editorState.getCurrentInlineStyle();
const removeStyles = styles.reduce((state, style) => {
return Modifier.removeInlineStyle(state, selection, style)
}, contentState);
const removeBlock = Modifier.setBlockType(removeStyles, selection, 'unstyled')
this.setState({
editorState: EditorState.push(editorState, removeBlock)
})
}
_choiceAutoSave(savedImportContent){
const decorator = new CompositeDecorator([
LinkDecorator,
ImageDecorator,
VideoDecorator,
AudioDecorator
]);
const ConvertFormatProps = this.props.convertFormat;
let contentState = "";
if(ConvertFormatProps === 'html') {
contentState = stateFromHTML(savedImportContent);
} else if (ConvertFormatProps === 'markdown') {
contentState = stateFromMD(savedImportContent);
} else if(ConvertFormatProps === 'raw'){
let rawContent = JSON.parse(savedImportContent);
contentState = convertFromRaw(rawContent);
}
let values = EditorState.createWithContent(contentState, decorator);
this.state.editorState = values;
this.forceUpdate();
}
_toggleColor(toggledColor) {
const {editorState} = this.state;
const selection = editorState.getSelection();
// Let's just allow one color at a time. Turn off all active colors.
const nextContentState = Object.keys(colorStyleMap).reduce((contentState, color) => {
return Modifier.removeInlineStyle(contentState, selection, color)
}, editorState.getCurrentContent());
let nextEditorState = EditorState.push(editorState, nextContentState, 'change-inline-style');
const currentStyle = editorState.getCurrentInlineStyle();
// Unset style override for current color.
if (selection.isCollapsed()) {
nextEditorState = currentStyle.reduce((state, color) => {
return RichUtils.toggleInlineStyle(state, color);
}, nextEditorState);
}
// If the color is being toggled on, apply it.
if (!currentStyle.has(toggledColor)) {
nextEditorState = RichUtils.toggleInlineStyle(nextEditorState, toggledColor);
}
this.onChange(nextEditorState);
}
render() {
let urlInput;
// ref="urltext"
if (this.state.showURLInput) {
urlInput = <Modal
title={lang[this.state.language].directToURL}
visible={this.state.visible}
onOk={this.confirmLink}
onCancel={this.handleCancel}
closable={false}>
<Input
type="text"
onChange={this.onURLChange}
value={this.state.urlValue}
placeholder="http:// or https://"
onKeyDown={this.onLinkInputKeyDown}/>
<span style={{color:"red"}}>{lang[this.state.language].directToURLTip}</span>
</Modal>
}
const {editorState} = this.state;
// If the user changes block type before entering any text, we can either style the placeholder or hide it. Let's just
// hide it now.
let className = 'RichEditor-editor';
let contentState = editorState.getCurrentContent();
if (!contentState.hasText()) {
if (contentState.getBlockMap().first().getType() !== 'unstyled') {
className += ' RichEditor-hidePlaceholder';
}
}
// console.log("this.props.undoRedo",this.props.undoRedo)//https://gist.github.com/deanmcpherson/69f9962b744b273ffb64fe294ab71bc4
// <Affix offsetTop={0} id="text-editor-affix">
// </Affix>
return (
<div className="RichEditor-root editorHidden" content={this.state.HTML} id="text-editor-container">
<div>
{this.state.showMarkdownSource==false&&this.props.undoRedo&&<UndoRedo onToggle={this.undoRedo} lang={lang[this.state.language]}/>}
{this.state.showMarkdownSource==false&&this.props.removeStyle&&<RemoveStyleControls onToggle={this.removeStyle} lang={lang[this.state.language]}/>}
{this.state.showMarkdownSource==false&&this.props.pasteNoStyle&&<PasteNoStyleControls receiveText={this.pasteNoStyle} lang={lang[this.state.language]}/>}
{this.state.showMarkdownSource==false&&this.props.blockStyle&&<BlockStyleControls editorState={editorState} onToggle={this.toggleBlockType} lang={lang[this.state.language]}/>}
{this.props.alignment&&this.props.convertFormat!=="markdown"&&<AlignmentControls editorState={editorState} onToggle={this.toggleAlignment} lang={lang[this.state.language]}/>}
{this.state.showMarkdownSource==false&&this.props.inlineStyle&&<InlineStyleControls editorState={editorState} onToggle={this.toggleInlineStyle} lang={lang[this.state.language]}/>}
{this.props.color&&this.props.convertFormat!=="markdown"&&<ColorControls editorState={editorState} onToggle={this.toggleColor} lang={lang[this.state.language]}/>}
{this.state.showMarkdownSource==false&&this.props.image&&<ImgStyleControls uploadConfig={this.props.uploadConfig} receiveImage={this.addImage} watermarkImage={this.props.watermarkImage} lang={lang[this.state.language]}
uploadProps={this.props.uploadProps}/>}
{this.state.showMarkdownSource==false&&this.props.video&&<VideoStyleControls uploadConfig={this.props.uploadConfig} receiveVideo={this.addVideo} lang={lang[this.state.language]}
uploadProps={this.props.uploadProps}/>}
{this.state.showMarkdownSource==false&&this.props.audio&&<AudioStyleControls uploadConfig={this.props.uploadConfig} receiveAudio={this.addAudio} lang={lang[this.state.language]}
uploadProps={this.props.uploadProps}/>}
{this.state.showMarkdownSource==false&&this.props.urls&&<AddUrl editorState={editorState} onToggle={this.promptForLink} lang={lang[this.state.language]}/>}
{this.state.showMarkdownSource==false&&this.props.urls&&<CloseUrl editorState={editorState} onToggle={this.removeLink} lang={lang[this.state.language]}/>}
{this.state.showMarkdownSource==false&&this.props.autoSave&&<AutoSaveControls receiveSavedItem={this.choiceAutoSave} lang={lang[this.state.language]}/>}
{this.props.fullScreen&&<OpenFull editorState={editorState} onToggle={this.openFull} coverTitle={this.state.openFullTest} lang={lang[this.state.language]}/>}
{this.props.convertFormat=="markdown"&&<SourceEditor editorState={editorState} onToggle={this.toggleSource} coverTitle={this.state.showSourceEditor} lang={lang[this.state.language]}/>}
</div>
<div className={className} onClick={this.focus} style={{display:this.state.showMarkdownSource==true?"none":"block"}}>
<Editor
blockRendererFn={mediaBlockRenderer}
editorState={this.state.editorState}
blockStyleFn={getBlockStyle}
customStyleMap={styleMap}
customStyleMap={colorStyleMap}
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
keyBindingFn={this.customKeyBinding}
onChange={this.onChange}
handlePastedText={this.handlePastedText}
spellCheck={true}/>
</div>
<div style={{display:this.state.showMarkdownSource==true?"block":"none",height:"500px",width:"100%"}}>
<textarea
style={{height:"100%",width:"100%",overflowY:"visible" }}
onChange={this.changeMrakdownContent}
value={this.state.tempSouceContent||this.props.importContent}
placeholder={lang[this.state.language].markdownTip}/>
</div>
{urlInput}
</div>
);
// ref="editor"
}
}
// Custom overrides for "code" style.
const styleMap = {
CODE: {
backgroundColor: 'rgba(0, 0, 0, 0.05)',
fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
fontSize: 16,
padding: 2
}
};
function getBlockStyle(block) {
// console.log("getBlockStyle block",block,JSON.stringify(block))
let type=block.getType();
let data=block.getData();
let text=block.getText();
// console.log("getBlockStyle get data",JSON.stringify(data))
let mergedStyle="";
switch (type) {
case 'blockquote':
mergedStyle= 'RichEditor-blockquote';
break;
}
// console.log("getBlockStyle mergingStyle",mergedStyle)
if (!data.has("textAlignment")) {
return mergedStyle;
}
switch (data.get("textAlignment")) {
case 'left':
mergedStyle += ' RichEditor-alignment-left';
break;
case 'center':
mergedStyle += ' RichEditor-alignment-center';
break;
case 'right':
mergedStyle += ' RichEditor-alignment-right';
break;
case 'justify':
mergedStyle += ' RichEditor-alignment-justify';
break;
}
// console.log("getBlockStyle mergedStyle",mergedStyle)
return mergedStyle;
}
function mediaBlockRenderer(block) {
// console.log("block",block); console.log("1111111block.getType() ",block.getType());
if (block.getType() === 'atomic') {
// console.log("11112222block.getType() ",block.getType());
return {component: Media, editable: false};
}
return null;
}
const Audio = (props) => {
return <audio controls src={props.src} className="media"/>;
};
const Image = (props) => {
// console.log("props",props.src);
return <img src={props.src} className="media"/>;
};
const settings = {
definition: '16:9',
videoUrl: 'http://obukb5fdy.bkt.clouddn.com/icevideo/video/nayuta.mp4',
};
const Video = (props) => {
//return <Vnd {...settings} className="media"/>;
return <video src='http://obukb5fdy.bkt.clouddn.com/icevideo/video/nayuta.mp4' className="media"/>;
//return <IceVideo {...settings} className="media" />;
};
const Media = (props) => {
const entity = Entity.get(props.block.getEntityAt(0));
const {src} = entity.getData();
const type = entity.getType();
// console.log("Media type",src);
// console.log("Media entity",type);
let media;
if (type === 'audio') {
media = <Audio src={src}/>;
} else if (type === 'image') {
media = <Image src={src}/>;
} else if (type === 'video') {
media = <Video src={src}/>;
}
return media;
};
// Remove `propTypes` validation to fit React 16
// EditorConcist.propTypes = {
// active: React.PropTypes.bool,
// importContent: React.PropTypes.string,
// cbReceiver: React.PropTypes.func.isRequired,
// undoRedo: React.PropTypes.bool,
// removeStyle: React.PropTypes.bool,
// pasteNoStyle: React.PropTypes.bool,
// blockStyle: React.PropTypes.bool,
// alignment: React.PropTypes.bool,
// inlineStyle: React.PropTypes.bool,
// color: React.PropTypes.bool,
// image: React.PropTypes.bool,
// video: React.PropTypes.bool,
// audio: React.PropTypes.bool,
// urls: React.PropTypes.bool,
// autoSave: React.PropTypes.bool,
// fullScreen: React.PropTypes.bool,
// uploadConfig:React.PropTypes.shape({
// QINIU_URL: React.PropTypes.string.isRequired,
// QINIU_IMG_TOKEN_URL: React.PropTypes.string.isRequired,
// QINIU_PFOP:React.PropTypes.shape({
// url: React.PropTypes.string.isRequired
// }),
// QINIU_VIDEO_TOKEN_URL: React.PropTypes.string.isRequired,
// QINIU_FILE_TOKEN_URL: React.PropTypes.string.isRequired,
// QINIU_DOMAIN_IMG_URL: React.PropTypes.string.isRequired,
// QINIU_DOMAIN_VIDEO_URL: React.PropTypes.string.isRequired,
// QINIU_DOMAIN_FILE_URL: React.PropTypes.string.isRequired
// }),
// convertFormat: React.PropTypes.oneOf(['html', 'markdown', 'raw']),
// }
EditorConcist.defaultProps = {
undoRedo: true,
removeStyle: true,
pasteNoStyle: true,
blockStyle: true,
alignment: true,
inlineStyle: true,
color: true,
image: true,
video: true,
audio: true,
urls: true,
autoSave: true,
fullScreen:true,
convertFormat: 'html',
};
// export default EditorConcist;
module.exports = EditorConcist;