@@ -18,14 +18,19 @@ import stateToMarkdown from '../../helpers/stateToMarkdown'
1818import 'draft-js-link-plugin/lib/plugin.css'
1919import EditorIcons from './EditorIcons'
2020import './RichTextArea.scss'
21+ import 'draft-js-mention-plugin/lib/plugin.css'
22+ import createMentionPlugin , { defaultSuggestionsFilter } from 'draft-js-mention-plugin'
23+ import _ from 'lodash'
2124
2225const linkPlugin = createLinkPlugin ( )
2326const blockDndPlugin = createBlockDndPlugin ( )
27+ const mentionPlugin = createMentionPlugin ( { mentionPrefix : '@' } )
28+
2429const decorator = composeDecorators (
2530 blockDndPlugin . decorator
2631)
2732const allowImages = false
28- const plugins = [ linkPlugin , blockDndPlugin ]
33+ const plugins = [ linkPlugin , blockDndPlugin , mentionPlugin ]
2934if ( allowImages ) {
3035 const imagePlugin = createImagePlugin ( { decorator } )
3136 plugins . push ( handleDropPlugin )
@@ -51,7 +56,8 @@ const blocks = [
5156class RichTextArea extends React . Component {
5257 constructor ( props ) {
5358 super ( props )
54- this . state = { editorExpanded : false , editorState : EditorState . createEmpty ( ) , titleValue : '' }
59+ this . mentions = _ . map ( _ . values ( this . props . allMembers ) , ( e ) => { return { name : e . firstName + ' ' + e . lastName , handle : e . handle , userId : e . userId } } )
60+ this . state = { editorExpanded : false , editorState : EditorState . createEmpty ( ) , titleValue : '' , suggestions : this . mentions , mentions : [ ] }
5561 this . onTitleChange = this . onTitleChange . bind ( this )
5662 this . onEditorChange = this . onEditorChange . bind ( this )
5763 this . handleKeyCommand = this . handleKeyCommand . bind ( this )
@@ -201,12 +207,42 @@ class RichTextArea extends React.Component {
201207 return
202208 }
203209 const title = this . state . titleValue
204- const content = this . state . currentMDContent
210+
211+ var that = this
212+ const replaceMentionWithUserID = ( content ) =>
213+ {
214+ const encodeContent = ( text ) => {
215+ return text . replace ( / [ * _ ` ] / g, '\\$&' )
216+ }
217+
218+ const userIdMap = _ . reduce ( that . mentions , ( obj , item ) => {
219+ obj [ encodeContent ( item . name ) ] = encodeContent ( item . handle )
220+ return obj
221+ } , { } )
222+
223+ for ( var item in userIdMap )
224+ {
225+ content = content . replace ( '@' + item , '@' + userIdMap [ item ] )
226+ }
227+ return content
228+ }
229+
230+ const content = replaceMentionWithUserID ( this . state . currentMDContent )
231+
205232 if ( ( this . props . disableTitle || title ) && content ) {
206233 this . props . onPost ( { title, content} )
207234 }
208235 }
209236
237+ onSearchChange = ( { value } ) => {
238+ this . setState ( {
239+ suggestions : defaultSuggestionsFilter ( value , this . mentions ) ,
240+ } ) ;
241+ } ;
242+
243+ onAddMention = ( mention ) => {
244+ }
245+
210246 cancelEdit ( ) {
211247 this . props . cancelEdit ( )
212248 }
@@ -220,6 +256,7 @@ class RichTextArea extends React.Component {
220256 this . setState ( { uploading} )
221257 }
222258 render ( ) {
259+ const { MentionSuggestions} = mentionPlugin
223260 const { className, avatarUrl, authorName, titlePlaceholder, contentPlaceholder, editMode, isCreating, isGettingComment, disableTitle} = this . props
224261 const { editorExpanded, editorState, titleValue, oldMDContent, currentMDContent, uploading} = this . state
225262 let canSubmit = ( disableTitle || titleValue . trim ( ) )
@@ -232,6 +269,28 @@ class RichTextArea extends React.Component {
232269 const currentEntity = getCurrentEntity ( editorState )
233270 const disableForCodeBlock = blockType === 'code-block'
234271
272+ const Entry = ( props ) => {
273+ const {
274+ mention,
275+ theme,
276+ searchValue, // eslint-disable-line no-unused-vars
277+ isFocused, // eslint-disable-line no-unused-vars
278+ ...parentProps
279+ } = props ;
280+
281+ return (
282+ < div { ...parentProps } >
283+ < div className = { theme . mentionSuggestionsEntryContainer } >
284+ < div className = { theme . mentionSuggestionsEntryContainerRight } >
285+ < div className = { theme . mentionSuggestionsEntryText } >
286+ { mention . get ( 'handle' ) }
287+ </ div >
288+ </ div >
289+ </ div >
290+ </ div >
291+ ) ;
292+ } ;
293+
235294 return (
236295 < div className = { cn ( className , 'rich-editor' , { expanded : editorExpanded || editMode } ) } ref = "richEditor" >
237296 { ( isCreating || isGettingComment ) &&
@@ -258,15 +317,23 @@ class RichTextArea extends React.Component {
258317 />
259318 < div className = "draftjs-editor tc-textarea" >
260319 { ! isGettingComment &&
261- < Editor
262- ref = "editor"
263- placeholder = { contentPlaceholder }
264- editorState = { editorState }
265- onChange = { this . onEditorChange }
266- handleKeyCommand = { this . handleKeyCommand }
267- plugins = { plugins }
268- setUploadState = { this . setUploadState }
269- />
320+ < div >
321+ < Editor
322+ ref = "editor"
323+ placeholder = { contentPlaceholder }
324+ editorState = { editorState }
325+ onChange = { this . onEditorChange }
326+ handleKeyCommand = { this . handleKeyCommand }
327+ plugins = { plugins }
328+ setUploadState = { this . setUploadState }
329+ />
330+ < MentionSuggestions
331+ onSearchChange = { this . onSearchChange }
332+ suggestions = { this . state . suggestions }
333+ onAddMention = { this . onAddMention }
334+ entryComponent = { Entry }
335+ />
336+ </ div >
270337 }
271338 < div className = "textarea-footer" >
272339 < div className = "textarea-buttons" >
@@ -358,7 +425,8 @@ RichTextArea.propTypes = {
358425 oldTitle : PropTypes . string ,
359426 oldContent : PropTypes . string ,
360427 title : PropTypes . string ,
361- content : PropTypes . string
428+ content : PropTypes . string ,
429+ allMembers : PropTypes . object
362430}
363431
364432export default RichTextArea
0 commit comments