Как отобразить HTML из сохраненного содержимого React - DraftJS Editor? - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть один компонент для текстового редактора:

enter image description here

import React,{Component} from 'react'
import {Editor, EditorState,RichUtils,convertToRaw} from 'draft-js';

class TextEditor extends Component {
    constructor(props) {
      super(props);
      this.state = { editorState: EditorState.createEmpty() };
      this.focus = () => this.refs.editor.focus();
      this.onChange = (editorState) => {
        this.setState({editorState});
          const content = editorState.getCurrentContent();
          const editorValue = JSON.stringify(convertToRaw(content));
          this.props.update(editorValue);
      }
      this.handleKeyCommand = (command) => this._handleKeyCommand(command);
      this.onTab = (e) => this._onTab(e);
      this.toggleBlockType = (type) => this._toggleBlockType(type);
      this.toggleInlineStyle = (style) => this._toggleInlineStyle(style);
    }


    _handleKeyCommand(command) {
      const {editorState} = this.state;
      const newState = RichUtils.handleKeyCommand(editorState, command);
      if (newState) {
        this.onChange(newState);
        return true;
      }
      return false;
    }

    _onTab(e) {
      const maxDepth = 4;
      this.onChange(RichUtils.onTab(e, this.state.editorState, maxDepth));
    }

    _toggleBlockType(blockType) {
      this.onChange(RichUtils.toggleBlockType(this.state.editorState, blockType));
    }

    _toggleInlineStyle(inlineStyle) {
      this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, inlineStyle));
    }

    render() {
      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';
      var contentState = editorState.getCurrentContent();
      if (!contentState.hasText()) {
        if (contentState.getBlockMap().first().getType() !== 'unstyled') {
          className += ' RichEditor-hidePlaceholder';
        }
      }
      return (
        <div>
          <div className="RichEditor-root">
            <BlockStyleControls
              editorState={editorState}
              onToggle={this.toggleBlockType}
            />
            <InlineStyleControls
              editorState={editorState}
              onToggle={this.toggleInlineStyle}
            />
            <div className={className} onClick={this.focus}>
              <Editor
                blockStyleFn={getBlockStyle}
                customStyleMap={styleMap}
                editorState={editorState}
                handleKeyCommand={this.handleKeyCommand}
                onChange={this.onChange}
                onTab={this.onTab}
                placeholder="Project Description"
                ref="editor"
                spellCheck={true}
              />
            </div>
          </div>
        </div>
      );
    }
  }
  // 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) {
    switch (block.getType()) {
      case 'blockquote':
        return 'RichEditor-blockquote';
      default:
        return null;
    }
  }

  class StyleButton extends React.Component {
    constructor() {
      super();
      this.onToggle = (e) => {
        e.preventDefault();
        this.props.onToggle(this.props.style);
      };
    }
    render() {
      let className = 'RichEditor-styleButton';
      if (this.props.active) {
        className += ' RichEditor-activeButton';
      }
      return (
        <span className={className} onMouseDown={this.onToggle}>
          {this.props.label}
        </span>
      );
    }
  }

  const BLOCK_TYPES = [
    {
      label: 'H1',
      style: 'header-one'
    }, {
      label: 'H2',
      style: 'header-two'
    }, {
      label: 'H3',
      style: 'header-three'
    }, {
      label: 'H4',
      style: 'header-four'
    }, {
      label: 'H5',
      style: 'header-five'
    }, {
      label: 'H6',
      style: 'header-six'
    }, {
      label: 'Blockquote',
      style: 'blockquote'
    }, {
      label: 'UL',
      style: 'unordered-list-item'
    }, {
      label: 'OL',
      style: 'ordered-list-item'
    }, {
      label: 'Code Block',
      style: 'code-block'
    }
  ];

  const BlockStyleControls = (props) => {
    const {editorState} = props;
    const selection = editorState.getSelection();
    const blockType = editorState.getCurrentContent().getBlockForKey(selection.getStartKey()).getType();
    return (
      <div className="RichEditor-controls">
        {BLOCK_TYPES.map(
          (type) => <StyleButton
            key={type.label}
            active={type.style === blockType}
            label={type.label}
            onToggle={props.onToggle}
            style={type.style}
          />
        )}
      </div>
    );
  };

  const INLINE_STYLES = [
    {
      label: 'Bold',
      style: 'BOLD'
    }, {
      label: 'Italic',
      style: 'ITALIC'
    }, {
      label: 'Underline',
      style: 'UNDERLINE'
    }, {
      label: 'Monospace',
      style: 'CODE'
    }
  ];

  const InlineStyleControls = (props) => {
    var currentStyle = props.editorState.getCurrentInlineStyle();
    return (
      <div className="RichEditor-controls">
        {INLINE_STYLES.map(
          type => <StyleButton
            key={type.label}
            active={currentStyle.has(type.style)}
            label={type.label}
            onToggle={props.onToggle}
            style={type.style}
          />
        )}
      </div>
    );
  };

export default TextEditor;

Я использую вышеуказанный компонент в ProjectCreateForm.js

import React, { Component } from 'react'
import { connect } from 'react-redux';
import { Field ,reduxForm} from 'redux-form';
import {bindActionCreators} from 'redux';
import {createProject} from '../../actions/projectActions'
import TextField from '../ui/TextField';
import TextEditor from '../ui/TextEditor';
import Switch from '../ui/Switch';
import MyDatePicker from '../ui/MyDatePicker'
import {Editor, EditorState,} from 'draft-js';


class ProjectCreateForm extends Component {

    constructor() {
        super();
        this.state={
            description:''
        }
    }


    submitCreateProjectForm=(values)=>{
        values.description=this.state.description;
        return this.props.createProject(values,this.props.history);
    }

    update=(editorValue)=> {
         this.setState({
            description:editorValue
        });
    }

    render() {
        const {handleSubmit,submitting}= this.props;
        return(
            <div className="row">

                <div className="col-lg-10" style={{marginTop:'78px'}}>
                        <div className="container">
                        <h3 className="mb-3">Create New Project</h3>

                                <div className="card bg-light">
                                    <div className="card-body">
                                         <form method="POST" noValidate className="needs-validation" onSubmit={handleSubmit(this.submitCreateProjectForm)}>
                                             <Field name="name" id="name"  placeholder="Project Name" component={TextField} required/>
                                             <Field name="identifier" id="identifier" placeholder="Project Identifier (Example : MYPROJECT)" component={TextField} required/>
                                             <Field name="description" id="description" placeholder="Project Description" component={TextEditor} update={ this.update }/>
                                             <Field name="is_public" id="is_public" label="Project Access" label_off="Private" label_on="Public" component={Switch}/>
                                             <Field name="start_date" id="start_Date" component={MyDatePicker} />
                                             <button type="submit" className="btn btn-primary" disabled={submitting}>CREATE PROJECT</button>
                                         </form>
                                    </div>
                                </div>

                        </div>
                </div>
            </div>
        )
    }
}

const mapStateToProps = (state, ownProps) => ({
    project:state.project
})

const mapDispatchToProps =dispatch=>{
   return bindActionCreators({
        createProject
    },dispatch)
}

ProjectCreateForm=connect(mapStateToProps,mapDispatchToProps)(ProjectCreateForm);
ProjectCreateForm=reduxForm({form:'createProjectForm'})(ProjectCreateForm);
export default ProjectCreateForm; 

После JSON.stringify содержимое сохранено в БД.

enter image description here

Теперь у меня есть ProjectSummary компонент, здесь я хочу отобразить сохраненное описание в HTML.

import React, { Component } from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {getProjectByID} from '../../actions/projectActions'
import Loader from '../ui/Loader'
import {Editor, ConvertFromRaw} from 'draft-js'
import TextEditor from '../ui/TextEditor'
import {stateToHTML} from 'draft-js-export-html';


class ProjectSummary extends Component {

  componentDidMount() {
    let id = this.props.match.params.projectid;
    this.props.getProjectByID(id,this.props.history)
  }

  render() {
    const {current_project,loading} = this.props.projects
    let content;
    if(current_project==null)
    {
        content=<Loader style={{marginTop:'120px'}}/>
    }else{
      //const storedState = ConvertFromRaw(JSON.parse(current_project.description));
      console.log(stateToHTML(current_project.description));
        content=(
          <div>
          <div className="row">

              <div className="col-lg-10" style={{marginTop:'78px'}}>
                      <div className="container">
                      <h3 className="mb-3 pb-2 border-bottom">{current_project.name}</h3>


                      </div>
              </div>
          </div>

          </div>
        )
    }
    return content;
  }
}

const mapStateToProps = (state, ownProps) => ({
   projects:state.projects
})

const mapDispatchToProps =dispatch=> {
    return bindActionCreators({
      getProjectByID
    },dispatch) 
}

export default connect(mapStateToProps,mapDispatchToProps)(ProjectSummary);

Я искал много похожих вопросов:

React & Draft.js - convertFromRaw не работает

Визуализация HTML, сохраненного из draft-js

Я пробовал выше, но у меня не работает. Ошибка ниже:

enter image description here

также пробовал: https://www.npmjs.com/package/draft-js-export-html

но получил ошибку: enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...