Skip to content
Snippets Groups Projects
Select Git revision
  • e037c4597a531d33cf6b657a79b7f6a4a055f9c4
  • main default protected
2 results

show.js

Blame
  • TextEditor.js 3.72 KiB
    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    import { Editor, EditorState, RichUtils } from 'draft-js';
    import ToggleButton from '@material-ui/lab/ToggleButton';
    import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
    import BoldIcon from '@material-ui/icons/FormatBold';
    import ItalicIcon from '@material-ui/icons/FormatItalic';
    import { withStyles } from '@material-ui/core/styles';
    import { stateToHTML } from 'draft-js-export-html';
    import { stateFromHTML } from 'draft-js-import-html';
    
    /** */
    class TextEditor extends Component {
      /** */
      constructor(props) {
        super(props);
        this.state = {
          editorState: EditorState.createWithContent(stateFromHTML(props.annoHtml)),
        };
        this.onChange = this.onChange.bind(this);
        this.handleKeyCommand = this.handleKeyCommand.bind(this);
        this.handleFormating = this.handleFormating.bind(this);
        this.handleFocus = this.handleFocus.bind(this);
        this.editorRef = React.createRef();
      }
    
      /**
       * This is a kinda silly hack (but apparently recommended approach) to
       * making sure the whole visible editor area is clickable, not just the first line.
       */
      handleFocus() {
        if (this.editorRef.current) this.editorRef.current.focus();
      }
    
      /** */
      handleFormating(e, newFormat) {
        const { editorState } = this.state;
        this.onChange(RichUtils.toggleInlineStyle(editorState, newFormat));
      }
    
      /** */
      handleKeyCommand(command, editorState) {
        const newState = RichUtils.handleKeyCommand(editorState, command);
        if (newState) {
          this.onChange(newState);
          return 'handled';
        }
        return 'not-handled';
      }
    
      /** */
      onChange(editorState) {
        const { updateAnnotationBody } = this.props;
        this.setState({ editorState });
        if (updateAnnotationBody) {
          const options = {
            inlineStyles: {
              BOLD: { element: 'b' },
              ITALIC: { element: 'i' },
            },
          };
          updateAnnotationBody(stateToHTML(editorState.getCurrentContent(), options).toString());
        }
      }
    
      /** */
      render() {
        const { classes } = this.props;
        const { editorState } = this.state;
        const currentStyle = editorState.getCurrentInlineStyle();
    
        return (
            <div>
              <div className={classes.editorRoot} onClick={this.handleFocus}>
                <Editor
                    editorState={editorState}
                    handleKeyCommand={this.handleKeyCommand}
                    onChange={this.onChange}
                    ref={this.editorRef}
                />
              </div>
              <ToggleButtonGroup
                  size="small"
                  value={currentStyle.toArray()}
              >
                <ToggleButton
                    onClick={this.handleFormating}
                    value="BOLD"
                >
                  <BoldIcon/>
                </ToggleButton>
                <ToggleButton
                    onClick={this.handleFormating}
                    value="ITALIC"
                >
                  <ItalicIcon/>
                </ToggleButton>
              </ToggleButtonGroup>
            </div>
        );
      }
    }
    
    /** */
    const styles = (theme) => ({
      editorRoot: {
        borderColor: theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)',
        borderRadius: theme.shape.borderRadius,
        borderStyle: 'solid',
        borderWidth: 1,
        fontFamily: theme.typography.fontFamily,
        marginBottom: theme.spacing(1),
        marginTop: theme.spacing(1),
        minHeight: theme.typography.fontSize * 6,
        padding: theme.spacing(1),
      },
    });
    
    TextEditor.propTypes = {
      annoHtml: PropTypes.string,
      classes: PropTypes.shape({
        editorRoot: PropTypes.string,
      }).isRequired,
      updateAnnotationBody: PropTypes.func,
    };
    
    TextEditor.defaultProps = {
      annoHtml: '',
      updateAnnotationBody: () => {},
    };
    
    export default withStyles(styles)(TextEditor);