@@ -25,6 +25,11 @@ import {autoCompleteCreator} from '../../../editor/parts';
2525import { renderModel } from '../../../editor/render' ;
2626import { Room } from 'matrix-js-sdk' ;
2727import TypingStore from "../../../stores/TypingStore" ;
28+ import EMOJIBASE from 'emojibase-data/en/compact.json' ;
29+ import SettingsStore from "../../../settings/SettingsStore" ;
30+ import EMOTICON_REGEX from 'emojibase-regex/emoticon' ;
31+
32+ const REGEX_EMOTICON_WHITESPACE = new RegExp ( '(?:^|\\s)(' + EMOTICON_REGEX . source + ')\\s$' ) ;
2833
2934const IS_MAC = navigator . platform . indexOf ( "Mac" ) !== - 1 ;
3035
@@ -70,6 +75,28 @@ export default class BasicMessageEditor extends React.Component {
7075 this . _modifiedFlag = false ;
7176 }
7277
78+ _replaceEmoticon = ( caret , inputType , diff ) => {
79+ const { model} = this . props ;
80+ const range = model . startRange ( caret ) ;
81+ // expand range max 8 characters backwards from caret
82+ let n = 8 ;
83+ range . expandBackwardsWhile ( ( index , offset ) => {
84+ const part = model . parts [ index ] ;
85+ n -= 1 ;
86+ return n >= 0 && ( part . type === "plain" || part . type === "pill-candidate" ) ;
87+ } ) ;
88+ const emoticonMatch = REGEX_EMOTICON_WHITESPACE . exec ( range . text ) ;
89+ if ( emoticonMatch ) {
90+ const query = emoticonMatch [ 1 ] . toLowerCase ( ) . replace ( "-" , "" ) ;
91+ const data = EMOJIBASE . find ( e => e . emoticon ? e . emoticon . toLowerCase ( ) === query : false ) ;
92+ if ( data ) {
93+ // + 1 because index is reported without preceding space
94+ range . moveStart ( emoticonMatch . index + 1 ) ;
95+ return range . replace ( [ this . props . model . partCreator . plain ( data . unicode + " " ) ] ) ;
96+ }
97+ }
98+ }
99+
73100 _updateEditorState = ( caret , inputType , diff ) => {
74101 renderModel ( this . _editorRef , this . props . model ) ;
75102 if ( caret ) {
@@ -262,6 +289,9 @@ export default class BasicMessageEditor extends React.Component {
262289 componentDidMount ( ) {
263290 const model = this . props . model ;
264291 model . setUpdateCallback ( this . _updateEditorState ) ;
292+ if ( SettingsStore . getValue ( 'MessageComposerInput.autoReplaceEmoji' ) ) {
293+ model . setTransformCallback ( this . _replaceEmoticon ) ;
294+ }
265295 const partCreator = model . partCreator ;
266296 // TODO: does this allow us to get rid of EditorStateTransfer?
267297 // not really, but we could not serialize the parts, and just change the autoCompleter
0 commit comments