client/src/components/SlateEditor.js
changeset 26 930e486ad0a8
parent 25 e04714a1d4eb
child 35 97106bacb24e
equal deleted inserted replaced
25:e04714a1d4eb 26:930e486ad0a8
     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 Portal from 'react-portal'
     3 import Portal from 'react-portal'
     4 import moment from 'moment'
     4 import moment from 'moment'
       
     5 import Immutable from 'immutable'
     5 import HtmlSerializer from '../HtmlSerializer'
     6 import HtmlSerializer from '../HtmlSerializer'
     6 import AnnotationPlugin from '../AnnotationPlugin'
     7 import AnnotationPlugin from '../AnnotationPlugin'
     7 import CategoriesTooltip from './CategoriesTooltip'
     8 import CategoriesTooltip from './CategoriesTooltip'
     8 
     9 
     9 const plugins = [];
    10 const plugins = [];
    78       state: Plain.deserialize(''),
    79       state: Plain.deserialize(''),
    79       startedAt: null,
    80       startedAt: null,
    80       finishedAt: null,
    81       finishedAt: null,
    81       currentSelectionText: '',
    82       currentSelectionText: '',
    82       hoveringMenu: null,
    83       hoveringMenu: null,
    83       isPortalOpen: false
    84       isPortalOpen: false,
       
    85       categories: Immutable.List([]),
    84     };
    86     };
    85   }
    87   }
    86 
    88 
    87   componentDidMount = () => {
    89   componentDidMount = () => {
    88     this.updateMenu();
    90     this.updateMenu();
   162     return Raw.serialize(this.state.state);
   164     return Raw.serialize(this.state.state);
   163   }
   165   }
   164 
   166 
   165   asHtml = () => {
   167   asHtml = () => {
   166     return HtmlSerializer.serialize(this.state.state);
   168     return HtmlSerializer.serialize(this.state.state);
       
   169   }
       
   170 
       
   171   asCategories = () => {
       
   172     return this.state.categories
       
   173   }
       
   174 
       
   175   removeCategory = (categories, key, text) => {
       
   176     const categoryIndex = categories.findIndex(category => category.key === key && category.text === text)
       
   177     return categories.delete(categoryIndex)
   167   }
   178   }
   168 
   179 
   169   clear = () => {
   180   clear = () => {
   170     const state = Plain.deserialize('');
   181     const state = Plain.deserialize('');
   171     this.onChange(state);
   182     this.onChange(state);
   219    */
   230    */
   220 
   231 
   221   onClickMark = (e, type) => {
   232   onClickMark = (e, type) => {
   222     e.preventDefault()
   233     e.preventDefault()
   223     const { state } = this.state
   234     const { state } = this.state
       
   235     let { categories } = this.state
   224     const transform = state.transform()
   236     const transform = state.transform()
   225 
   237 
   226     let isPortalOpen = false;
   238     let isPortalOpen = false;
   227 
   239 
   228     if (type === 'category') {
   240     if (type === 'category') {
   229       // Can't use toggleMark here, because it expects the same object
   241       // Can't use toggleMark here, because it expects the same object
   230       // @see https://github.com/ianstormtaylor/slate/issues/873
   242       // @see https://github.com/ianstormtaylor/slate/issues/873
   231       if (this.hasMark('category')) {
   243       if (this.hasMark('category')) {
   232         state.marks.forEach(mark => transform.removeMark(mark));
   244         const categoryMarks = state.marks.filter(mark => mark.type === 'category')
       
   245         categoryMarks.forEach(mark => {
       
   246           const key = mark.data.get('key');
       
   247           const text = mark.data.get('text');
       
   248 
       
   249           categories = this.removeCategory(categories, key, text)
       
   250           transform.removeMark(mark)
       
   251         })
       
   252 
   233       } else {
   253       } else {
   234         isPortalOpen = !this.state.isPortalOpen;
   254         isPortalOpen = !this.state.isPortalOpen;
   235       }
   255       }
   236     } else {
   256     } else {
   237       transform.toggleMark(type)
   257       transform.toggleMark(type)
   238     }
   258     }
   239 
   259 
   240     this.setState({
   260     this.setState({
   241       state: transform.apply(),
   261       state: transform.apply(),
   242       isPortalOpen: isPortalOpen
   262       isPortalOpen: isPortalOpen,
       
   263       categories: categories
   243     })
   264     })
   244   }
   265   }
   245 
   266 
   246   /**
   267   /**
   247    * When a block button is clicked, toggle the block type.
   268    * When a block button is clicked, toggle the block type.
   316     })
   337     })
   317   }
   338   }
   318 
   339 
   319   onCategoryClick = (category) => {
   340   onCategoryClick = (category) => {
   320 
   341 
   321     const { state } = this.state;
   342     const { state, currentSelectionText } = this.state;
       
   343     let { categories } = this.state;
   322     const transform = state.transform();
   344     const transform = state.transform();
   323 
   345 
   324     state.marks.forEach(mark => transform.removeMark(mark));
   346     const categoryMarks = state.marks.filter(mark => mark.type === 'category')
       
   347     categoryMarks.forEach(mark => transform.removeMark(mark));
       
   348 
   325     transform.addMark({
   349     transform.addMark({
   326       type: 'category',
   350       type: 'category',
   327       data: {
   351       data: {
   328         text: this.state.currentSelectionText,
   352         text: currentSelectionText,
   329         color: category.color,
   353         color: category.color,
   330         key: category.key
   354         key: category.key
   331       }
   355       }
   332     })
   356     })
   333 
   357 
       
   358     Object.assign(category, {
       
   359       text: currentSelectionText
       
   360     });
       
   361     categories = categories.push(category);
       
   362 
   334     this.setState({
   363     this.setState({
   335       state: transform.apply(),
   364       state: transform.apply(),
   336       isPortalOpen: false
   365       isPortalOpen: false,
       
   366       categories: categories
   337     });
   367     });
   338   }
   368   }
   339 
   369 
   340   /**
   370   /**
   341    * Render.
   371    * Render.