diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js
index a172ca4dbf..45c52c7f1d 100644
--- a/src/components/structures/UserSettings.js
+++ b/src/components/structures/UserSettings.js
@@ -93,6 +93,10 @@ const SETTINGS_LABELS = [
id: 'enableSyntaxHighlightLanguageDetection',
label: 'Enable automatic language detection for syntax highlighting',
},
+ {
+ id: 'MessageComposerInput.autoReplaceEmoji',
+ label: 'Automatically replace plain text Emoji',
+ },
/*
{
id: 'useFixedWidthFont',
diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js
index abe63ad491..acd49f6fb4 100644
--- a/src/components/views/rooms/MessageComposerInput.js
+++ b/src/components/views/rooms/MessageComposerInput.js
@@ -43,6 +43,11 @@ import Markdown from '../../../Markdown';
import ComposerHistoryManager from '../../../ComposerHistoryManager';
import MessageComposerStore from '../../../stores/MessageComposerStore';
+import {asciiRegexp, shortnameToUnicode, emojioneList, asciiList, mapUnicodeToShort} from 'emojione';
+const EMOJI_SHORTNAMES = Object.keys(emojioneList);
+const EMOJI_UNICODE_TO_SHORTNAME = mapUnicodeToShort();
+const REGEX_EMOJI_WHITESPACE = new RegExp('(' + asciiRegexp + ')\\s$');
+
const TYPING_USER_TIMEOUT = 10000, TYPING_SERVER_TIMEOUT = 30000;
const ZWS_CODE = 8203;
@@ -369,6 +374,32 @@ export default class MessageComposerInput extends React.Component {
editorState = EditorState.forceSelection(editorState, currentSelection);
}
+ // Automatic replacement of plaintext emoji to Unicode emoji
+ if (UserSettingsStore.getSyncedSetting('MessageComposerInput.autoReplaceEmoji', false)) {
+ // The first matched group includes just the matched plaintext emoji
+ const emojiMatch = REGEX_EMOJI_WHITESPACE.exec(text.slice(0, currentStartOffset));
+ if(emojiMatch) {
+ // plaintext -> hex unicode
+ const emojiUc = asciiList[emojiMatch[1]];
+ // hex unicode -> shortname -> actual unicode
+ const unicodeEmoji = shortnameToUnicode(EMOJI_UNICODE_TO_SHORTNAME[emojiUc]);
+ const newContentState = Modifier.replaceText(
+ editorState.getCurrentContent(),
+ currentSelection.merge({
+ anchorOffset: currentStartOffset - emojiMatch[0].length,
+ focusOffset: currentStartOffset,
+ }),
+ unicodeEmoji,
+ );
+ editorState = EditorState.push(
+ editorState,
+ newContentState,
+ 'insert-characters',
+ );
+ editorState = EditorState.forceSelection(editorState, newContentState.getSelectionAfter());
+ }
+ }
+
/* Since a modification was made, set originalEditorState to null, since newState is now our original */
this.setState({
editorState,
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index e041649906..4841f2f0de 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -955,5 +955,6 @@
"To join an exisitng group you'll have to know its group identifier; this will look something like +example:matrix.org.": "To join an exisitng group you'll have to know its group identifier; this will look something like +example:matrix.org.",
"Featured Rooms:": "Featured Rooms:",
"Error whilst fetching joined groups": "Error whilst fetching joined groups",
- "Featured Users:": "Featured Users:"
+ "Featured Users:": "Featured Users:",
+ "Automatically replace plain text Emoji": "Automatically replace plain text Emoji"
}