client/src/components/SlateEditor/index.js
changeset 171 03334a31130a
parent 170 7da1d5137b0b
child 172 4b780ebbedc6
equal deleted inserted replaced
170:7da1d5137b0b 171:03334a31130a
     1 import { Value } from 'slate'
     1 import { Value } from 'slate';
     2 import Plain from 'slate-plain-serializer'
     2 import Plain from 'slate-plain-serializer';
     3 import { Editor } from 'slate-react'
     3 import { Editor } from 'slate-react';
     4 import React from 'react'
     4 import React from 'react';
     5 import { Portal } from 'react-portal'
     5 import { Portal } from 'react-portal';
     6 import HtmlSerializer from './HtmlSerializer'
     6 import { Trans, withNamespaces } from 'react-i18next';
     7 import AnnotationPlugin from './AnnotationPlugin'
     7 import * as R from 'ramda';
     8 import CategoriesTooltip from './CategoriesTooltip'
     8 import HtmlSerializer from './HtmlSerializer';
       
     9 import AnnotationPlugin from './AnnotationPlugin';
       
    10 import CategoriesTooltip from './CategoriesTooltip';
     9 import './SlateEditor.css';
    11 import './SlateEditor.css';
    10 import { now } from '../../utils';
    12 import { now } from '../../utils';
    11 import { defaultAnnotationsCategories } from '../../constants';
    13 import { defaultAnnotationsCategories } from '../../constants';
    12 
    14 
    13 const plugins = [];
    15 const plugins = [];
   112       isPortalOpen: false,
   114       isPortalOpen: false,
   113       categories: [],
   115       categories: [],
   114       isCheckboxChecked: false,
   116       isCheckboxChecked: false,
   115       enterKeyValue: 0,
   117       enterKeyValue: 0,
   116     };
   118     };
       
   119 
       
   120     this.editor = React.createRef();
   117   }
   121   }
   118 
   122 
   119   componentDidMount = () => {
   123   componentDidMount = () => {
   120     this.updateMenu();
   124     this.updateMenu();
   121     this.focus();
   125     this.focus();
   153     // Store start time once when the first character is typed
   157     // Store start time once when the first character is typed
   154     if (!isEmpty && this.state.startedAt === null) {
   158     if (!isEmpty && this.state.startedAt === null) {
   155       Object.assign(newState, { startedAt: now() });
   159       Object.assign(newState, { startedAt: now() });
   156     }
   160     }
   157 
   161 
       
   162     const oldState = R.clone(this.state);
   158     this.setState(newState)
   163     this.setState(newState)
   159 
   164 
   160     if (typeof this.props.onChange === 'function') {
   165     if (typeof this.props.onChange === 'function') {
   161       this.props.onChange(newState);
   166       this.props.onChange(R.clone(this.state), oldState, newState);
   162     }
   167     }
   163   }
   168   }
   164 
   169 
   165   /**
   170   /**
   166    * Check if the current selection has a mark with `type` in it.
   171    * Check if the current selection has a mark with `type` in it.
   170    */
   175    */
   171 
   176 
   172   hasMark = type => {
   177   hasMark = type => {
   173     const { value } = this.state
   178     const { value } = this.state
   174     return value.activeMarks.some(mark => mark.type === type)
   179     return value.activeMarks.some(mark => mark.type === type)
   175 }
   180   }
   176 
   181 
   177   /**
   182   /**
   178    * Check if the any of the currently selected blocks are of `type`.
   183    * Check if the any of the currently selected blocks are of `type`.
   179    *
   184    *
   180    * @param {String} type
   185    * @param {String} type
   182    */
   187    */
   183 
   188 
   184   hasBlock = type => {
   189   hasBlock = type => {
   185     const { value } = this.state
   190     const { value } = this.state
   186     return value.blocks.some(node => node.type === type)
   191     return value.blocks.some(node => node.type === type)
   187 }
   192   }
   188 
   193 
   189   asPlain = () => {
   194   asPlain = () => {
   190     return Plain.serialize(this.state.value);
   195     return Plain.serialize(this.state.value);
   191   }
   196   }
   192 
   197 
   211     const value = Plain.deserialize('');
   216     const value = Plain.deserialize('');
   212     this.onChange({value});
   217     this.onChange({value});
   213   }
   218   }
   214 
   219 
   215   focus = () => {
   220   focus = () => {
   216     this.refs.editor.focus();
   221     if(this.editor.current) {
   217   }
   222       this.editor.current.focus();
   218 
   223     }
   219       /**
   224   }
       
   225 
       
   226   /**
   220    * When a mark button is clicked, toggle the current mark.
   227    * When a mark button is clicked, toggle the current mark.
   221    *
   228    *
   222    * @param {Event} e
   229    * @param {Event} e
   223    * @param {String} type
   230    * @param {String} type
   224    */
   231    */
   514 
   521 
   515   renderToolbarCheckbox = () => {
   522   renderToolbarCheckbox = () => {
   516     return (
   523     return (
   517       <div className="checkbox float-right">
   524       <div className="checkbox float-right">
   518         <label className="mr-2">
   525         <label className="mr-2">
   519           <input type="checkbox" checked={this.props.isChecked} onChange={this.onCheckboxChange} /><small className="text-muted ml-1"> Appuyer sur <kbd className="bg-irinotes-form text-muted ml-1">Entrée</kbd> pour ajouter une note</small>
   526           <input type="checkbox" checked={this.props.isChecked} onChange={this.onCheckboxChange} /><small className="text-muted ml-1"><Trans i18nKey="slate_editor.press_enter_msg">Appuyer sur <kbd className="bg-irinotes-form text-muted ml-1">Entrée</kbd> pour ajouter une note</Trans></small>
   520         </label>
   527         </label>
   521       </div>
   528       </div>
   522     )
   529     )
   523   }
   530   }
   524 
   531 
   525   renderToolbarButtons = () => {
   532   renderToolbarButtons = () => {
       
   533     const t = this.props.t;
   526     return (
   534     return (
   527       <div>
   535       <div>
   528         <button type="button" id="btn-editor" className="btn btn-primary btn-sm text-secondary font-weight-bold float-right" disabled={this.props.isButtonDisabled} onClick={this.onButtonClick}>
   536         <button type="button" id="btn-editor" className="btn btn-primary btn-sm text-secondary font-weight-bold float-right text-capitalize" disabled={this.props.isButtonDisabled} onClick={this.onButtonClick}>
   529           { this.props.note ? 'Sauvegarder' : 'Ajouter' }
   537           { this.props.note ? t('common.save') : t('common.add') }
   530         </button>
   538         </button>
   531         { !this.props.note && this.renderToolbarCheckbox() }
   539         { !this.props.note && this.renderToolbarCheckbox() }
   532       </div>
   540       </div>
   533     );
   541     );
   534   }
   542   }
   625    *
   633    *
   626    * @return {Element}
   634    * @return {Element}
   627    */
   635    */
   628 
   636 
   629   renderEditor = () => {
   637   renderEditor = () => {
       
   638     const t = this.props.t;
   630     return (
   639     return (
   631       <div className="editor-slatejs p-2">
   640       <div className="editor-slatejs p-2">
   632         {this.renderHoveringMenu()}
   641         {this.renderHoveringMenu()}
   633         <Editor
   642         <Editor
   634           ref="editor"
   643           ref={this.editor}
   635           spellCheck
   644           spellCheck
   636           placeholder={'Votre espace de prise de note...'}
   645           placeholder={t('slate_editor.placeholder')}
   637           schema={schema}
   646           schema={schema}
   638           plugins={plugins}
   647           plugins={plugins}
   639           value={this.state.value}
   648           value={this.state.value}
   640           onChange={this.onChange}
   649           onChange={this.onChange}
   641           onKeyDown={this.onKeyDown}
   650           onKeyDown={this.onKeyDown}
   689 
   698 
   690 /**
   699 /**
   691  * Export.
   700  * Export.
   692  */
   701  */
   693 
   702 
   694 export default SlateEditor
   703 export default withNamespaces("", {
       
   704   innerRef: (ref) => {
       
   705     const editorRef = (ref && ref.props) ? ref.props.editorRef : null;
       
   706     if(editorRef && editorRef.hasOwnProperty('current')) {
       
   707       editorRef.current = ref;
       
   708     }
       
   709   }
       
   710 })(SlateEditor);
       
   711 // export default SlateEditor;