client/src/components/SlateEditor.js
changeset 19 f1b125b95fe9
parent 17 877d8796b86d
child 21 284e866f55c7
equal deleted inserted replaced
18:dab2a16500e0 19:f1b125b95fe9
     1 import { Editor, Plain, Raw } from 'slate'
     1 import { Editor, Plain, Raw } from 'slate'
     2 import React from 'react'
     2 import React from 'react'
     3 import moment from 'moment';
     3 import moment from 'moment';
     4 import HtmlSerializer from '../HtmlSerializer'
     4 import HtmlSerializer from '../HtmlSerializer'
       
     5 import AnnotationPlugin from '../AnnotationPlugin';
       
     6 
       
     7 const plugins = [];
     5 
     8 
     6 /**
     9 /**
     7  * Define the default node type.
    10  * Define the default node type.
     8  */
    11  */
     9 
    12 
    15  * @type {Object}
    18  * @type {Object}
    16  */
    19  */
    17 
    20 
    18 const schema = {
    21 const schema = {
    19   nodes: {
    22   nodes: {
    20     'block-quote': props => <blockquote {...props.attributes}>{props.children}</blockquote>,
       
    21     'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
    23     'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
    22     'heading-one': props => <h1 {...props.attributes}>{props.children}</h1>,
       
    23     'heading-two': props => <h2 {...props.attributes}>{props.children}</h2>,
       
    24     'list-item': props => <li {...props.attributes}>{props.children}</li>,
    24     'list-item': props => <li {...props.attributes}>{props.children}</li>,
    25     'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>,
    25     'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>,
    26   },
    26   },
    27   marks: {
    27   marks: {
    28     bold: {
    28     bold: {
    29       fontWeight: 'bold'
    29       fontWeight: 'bold'
    30     },
    30     },
    31     code: {
    31     // TODO Check if we can move this to the plugin using the schema option
    32       fontFamily: 'monospace',
    32     // https://docs.slatejs.org/reference/plugins/plugin.html#schema
    33       backgroundColor: '#eee',
    33     annotation: {
    34       padding: '3px',
    34       textDecoration: 'underline',
    35       borderRadius: '4px'
    35       textDecorationStyle: 'dotted',
       
    36       backgroundColor: 'yellow',
    36     },
    37     },
    37     italic: {
    38     italic: {
    38       fontStyle: 'italic'
    39       fontStyle: 'italic'
    39     },
    40     },
    40     underlined: {
    41     underlined: {
    56    *
    57    *
    57    * @type {Object}
    58    * @type {Object}
    58    */
    59    */
    59   constructor(props) {
    60   constructor(props) {
    60     super(props);
    61     super(props);
       
    62 
       
    63     const annotationPlugin = AnnotationPlugin({
       
    64       onChange: (text) => {
       
    65         this.setState({ currentSelectionText: text });
       
    66       }
       
    67     });
       
    68 
       
    69     plugins.push(annotationPlugin);
       
    70 
    61     this.state = {
    71     this.state = {
    62       state: Plain.deserialize(''),
    72       state: Plain.deserialize(''),
    63       startedAt: null,
    73       startedAt: null,
    64       finishedAt: null
    74       finishedAt: null,
       
    75       currentSelectionText: ''
    65     };
    76     };
    66   }
    77   }
    67 
    78 
    68   componentDidMount() {
    79   componentDidMount() {
    69     this.focus();
    80     this.focus();
   172         mark = 'italic'
   183         mark = 'italic'
   173         break
   184         break
   174       case 'u':
   185       case 'u':
   175         mark = 'underlined'
   186         mark = 'underlined'
   176         break
   187         break
   177       case '`':
       
   178         mark = 'code'
       
   179         break
       
   180       default:
   188       default:
   181         return
   189         return
   182     }
   190     }
   183 
   191 
   184     state = state
   192     state = state
   199 
   207 
   200   onClickMark = (e, type) => {
   208   onClickMark = (e, type) => {
   201     e.preventDefault()
   209     e.preventDefault()
   202     let { state } = this.state
   210     let { state } = this.state
   203 
   211 
       
   212     let toggleMarkOptions;
       
   213     if (type === 'annotation') {
       
   214       toggleMarkOptions = { type: type, data: { text: this.state.currentSelectionText } }
       
   215     } else {
       
   216       toggleMarkOptions = type;
       
   217     }
       
   218 
   204     state = state
   219     state = state
   205       .transform()
   220       .transform()
   206       .toggleMark(type)
   221       .toggleMark(toggleMarkOptions)
   207       .apply()
   222       .apply()
   208 
   223 
   209     this.setState({ state })
   224     this.setState({ state })
   210   }
   225   }
   211 
   226 
   292     return (
   307     return (
   293       <div className="menu toolbar-menu">
   308       <div className="menu toolbar-menu">
   294         {this.renderMarkButton('bold', 'format_bold')}
   309         {this.renderMarkButton('bold', 'format_bold')}
   295         {this.renderMarkButton('italic', 'format_italic')}
   310         {this.renderMarkButton('italic', 'format_italic')}
   296         {this.renderMarkButton('underlined', 'format_underlined')}
   311         {this.renderMarkButton('underlined', 'format_underlined')}
   297         {this.renderMarkButton('code', 'code')}
   312         {this.renderMarkButton('annotation', 'label')}
   298         {this.renderBlockButton('heading-one', 'looks_one')}
   313 
   299         {this.renderBlockButton('heading-two', 'looks_two')}
       
   300         {this.renderBlockButton('block-quote', 'format_quote')}
       
   301         {this.renderBlockButton('numbered-list', 'format_list_numbered')}
   314         {this.renderBlockButton('numbered-list', 'format_list_numbered')}
   302         {this.renderBlockButton('bulleted-list', 'format_list_bulleted')}
   315         {this.renderBlockButton('bulleted-list', 'format_list_bulleted')}
   303       </div>
   316       </div>
   304     )
   317     )
   305   }
   318   }
   354         <Editor
   367         <Editor
   355           ref="editor"
   368           ref="editor"
   356           spellCheck
   369           spellCheck
   357           placeholder={'Enter some rich text...'}
   370           placeholder={'Enter some rich text...'}
   358           schema={schema}
   371           schema={schema}
       
   372           plugins={plugins}
   359           state={this.state.state}
   373           state={this.state.state}
   360           onChange={this.onChange}
   374           onChange={this.onChange}
   361           onKeyDown={this.onKeyDown}
   375           onKeyDown={this.onKeyDown}
   362         />
   376         />
   363       </div>
   377       </div>