summaryrefslogtreecommitdiffstats
path: root/webapp
diff options
context:
space:
mode:
authorHarrison Healey <harrisonmhealey@gmail.com>2017-08-04 14:03:41 -0400
committerChristopher Speller <crspeller@gmail.com>2017-08-04 11:03:41 -0700
commit399865923658319d6d12a7719bc3b5554218bbad (patch)
tree4e1d3d8dcd196a33b8b9daf03c1dc659c1025384 /webapp
parent2c8a5ffd971f00648e7bc5f48993fc187f3179f2 (diff)
downloadchat-399865923658319d6d12a7719bc3b5554218bbad.tar.gz
chat-399865923658319d6d12a7719bc3b5554218bbad.tar.bz2
chat-399865923658319d6d12a7719bc3b5554218bbad.zip
PLT-7267 Refactored tracking of recent emojis to hide deleted emojis (#7102)
* Fixed local ESLint error * PLT-7267 Refactored tracking of recent emojis to hide deleted emojis
Diffstat (limited to 'webapp')
-rw-r--r--webapp/actions/post_actions.jsx13
-rw-r--r--webapp/components/create_comment/create_comment.jsx20
-rw-r--r--webapp/components/create_post.jsx9
-rw-r--r--webapp/components/emoji_picker/components/emoji_picker_category.jsx3
-rw-r--r--webapp/components/emoji_picker/emoji_picker.jsx93
-rw-r--r--webapp/stores/emoji_store.jsx65
-rw-r--r--webapp/utils/emoticons.jsx4
7 files changed, 95 insertions, 112 deletions
diff --git a/webapp/actions/post_actions.jsx b/webapp/actions/post_actions.jsx
index e96e8306b..60913b171 100644
--- a/webapp/actions/post_actions.jsx
+++ b/webapp/actions/post_actions.jsx
@@ -11,8 +11,8 @@ import TeamStore from 'stores/team_store.jsx';
import {loadNewDMIfNeeded, loadNewGMIfNeeded} from 'actions/user_actions.jsx';
import {sendDesktopNotification} from 'actions/notification_actions.jsx';
-import Constants from 'utils/constants.jsx';
-const ActionTypes = Constants.ActionTypes;
+import {ActionTypes, Constants} from 'utils/constants.jsx';
+import {EMOJI_PATTERN} from 'utils/emoticons.jsx';
import {browserHistory} from 'react-router/es6';
@@ -164,6 +164,15 @@ export function removeReaction(channelId, postId, emojiName) {
}
export function createPost(post, files, success) {
+ // parse message and emit emoji event
+ const emojis = post.message.match(EMOJI_PATTERN);
+ if (emojis) {
+ for (const emoji of emojis) {
+ const trimmed = emoji.substring(1, emoji.length - 1);
+ emitEmojiPosted(trimmed);
+ }
+ }
+
PostActions.createPost(post, files)(dispatch, getState).then(() => {
if (post.root_id) {
PostStore.storeCommentDraft(post.root_id, null);
diff --git a/webapp/components/create_comment/create_comment.jsx b/webapp/components/create_comment/create_comment.jsx
index 62eff9e28..9370d7b48 100644
--- a/webapp/components/create_comment/create_comment.jsx
+++ b/webapp/components/create_comment/create_comment.jsx
@@ -31,7 +31,7 @@ import {browserHistory} from 'react-router/es6';
const ActionTypes = Constants.ActionTypes;
const KeyCodes = Constants.KeyCodes;
-import {REACTION_PATTERN, EMOJI_PATTERN} from 'components/create_post.jsx';
+import {REACTION_PATTERN} from 'components/create_post.jsx';
import PropTypes from 'prop-types';
import React from 'react';
@@ -87,9 +87,13 @@ export default class CreateComment extends React.Component {
if (this.state.message === '') {
this.setState({message: ':' + emojiAlias + ': '});
} else {
- //check whether there is already a blank at the end of the current message
- const newMessage = (/\s+$/.test(this.state.message)) ?
- this.state.message + ':' + emojiAlias + ': ' : this.state.message + ' :' + emojiAlias + ': ';
+ // Check whether there is already a blank at the end of the current message
+ let newMessage;
+ if ((/\s+$/).test(this.state.message)) {
+ newMessage = this.state.message + ':' + emojiAlias + ': ';
+ } else {
+ newMessage = this.state.message + ' :' + emojiAlias + ': ';
+ }
this.setState({message: newMessage});
}
@@ -230,14 +234,6 @@ export default class CreateComment extends React.Component {
GlobalActions.emitUserCommentedEvent(post);
- const emojiResult = post.message.match(EMOJI_PATTERN);
- if (emojiResult) {
- // parse message and emit emoji event
- emojiResult.forEach((emoji) => {
- PostActions.emitEmojiPosted(emoji);
- });
- }
-
PostActions.createPost(post, this.state.fileInfos);
this.setState({
diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx
index e5ead4e84..f822f46f4 100644
--- a/webapp/components/create_post.jsx
+++ b/webapp/components/create_post.jsx
@@ -41,7 +41,6 @@ import React from 'react';
import PropTypes from 'prop-types';
export const REACTION_PATTERN = /^(\+|-):([^:\s]+):\s*$/;
-export const EMOJI_PATTERN = /:[A-Za-z-_0-9]*:/g;
export default class CreatePost extends React.Component {
constructor(props) {
@@ -268,14 +267,6 @@ export default class CreatePost extends React.Component {
GlobalActions.emitUserPostedEvent(post);
- // parse message and emit emoji event
- const emojiResult = post.message.match(EMOJI_PATTERN);
- if (emojiResult) {
- emojiResult.forEach((emoji) => {
- PostActions.emitEmojiPosted(emoji);
- });
- }
-
PostActions.createPost(post, this.state.fileInfos,
() => GlobalActions.postListScrollChange(true),
(err) => {
diff --git a/webapp/components/emoji_picker/components/emoji_picker_category.jsx b/webapp/components/emoji_picker/components/emoji_picker_category.jsx
index 579aaed28..66146106b 100644
--- a/webapp/components/emoji_picker/components/emoji_picker_category.jsx
+++ b/webapp/components/emoji_picker/components/emoji_picker_category.jsx
@@ -1,8 +1,7 @@
-import PropTypes from 'prop-types';
-
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
+import PropTypes from 'prop-types';
import React from 'react';
export default class EmojiPickerCategory extends React.Component {
diff --git a/webapp/components/emoji_picker/emoji_picker.jsx b/webapp/components/emoji_picker/emoji_picker.jsx
index 8b5375000..49050a7d8 100644
--- a/webapp/components/emoji_picker/emoji_picker.jsx
+++ b/webapp/components/emoji_picker/emoji_picker.jsx
@@ -169,45 +169,57 @@ export default class EmojiPicker extends React.Component {
}
renderCategory(category, isLoaded, filter) {
- const items = [];
- let indices = [];
- let recentEmojis = [];
-
+ let emojis;
if (category === 'recent') {
- recentEmojis = EmojiStore.getRecentEmojis();
- indices = [...Array(recentEmojis.length).keys()];
+ const recentEmojis = [...EmojiStore.getRecentEmojis()];
- // reverse indices so most recently added is first
- indices.reverse();
+ // Reverse so most recently added is first
+ recentEmojis.reverse();
+
+ emojis = recentEmojis.filter((name) => {
+ return EmojiStore.has(name);
+ }).map((name) => {
+ return EmojiStore.get(name);
+ });
} else {
- indices = Emoji.EmojiIndicesByCategory.get(category) || [];
+ const indices = Emoji.EmojiIndicesByCategory.get(category) || [];
+
+ emojis = indices.map((index) => Emoji.Emojis[index]);
+
+ if (category === 'custom') {
+ emojis = emojis.concat([...EmojiStore.getCustomEmojiMap().values()]);
+ }
}
- for (const index of indices) {
- let emoji = {};
- if (category === 'recent') {
- emoji = recentEmojis[index];
- } else {
- emoji = Emoji.Emojis[index];
+ // Apply filter
+ emojis = emojis.filter((emoji) => {
+ if (emoji.name) {
+ return emoji.name.indexOf(filter) !== -1;
}
- if (filter) {
- let matches = false;
-
- for (const alias of emoji.aliases || [...emoji.name]) {
- if (alias.indexOf(filter) !== -1) {
- matches = true;
- break;
- }
- }
- if (!matches) {
- continue;
+ for (const alias of emoji.aliases) {
+ if (alias.indexOf(filter) !== -1) {
+ return true;
}
}
- items.push(
+ return false;
+ });
+
+ const items = emojis.map((emoji) => {
+ const name = emoji.name || emoji.aliases[0];
+ let key;
+ if (category === 'recent') {
+ key = 'system_recent_' + name;
+ } else if (category === 'custom' && emoji.name) {
+ key = 'custom_' + name;
+ } else {
+ key = 'system_' + name;
+ }
+
+ return (
<EmojiPickerItem
- key={'system_' + (category === 'recent' ? 'recent_' : '') + (emoji.name || emoji.aliases[0])}
+ key={key}
emoji={emoji}
category={category}
isLoaded={isLoaded}
@@ -217,30 +229,7 @@ export default class EmojiPicker extends React.Component {
onItemUnmount={this.handleItemUnmount}
/>
);
- }
-
- if (category === 'custom') {
- const customEmojis = EmojiStore.getCustomEmojiMap().values();
-
- for (const emoji of customEmojis) {
- if (filter && emoji.name.indexOf(filter) === -1) {
- continue;
- }
-
- items.push(
- <EmojiPickerItem
- key={'custom_' + emoji.name}
- emoji={emoji}
- category={category}
- onItemOver={this.handleItemOver}
- onItemOut={this.handleItemOut}
- onItemClick={this.handleItemClick}
- onItemUnmount={this.handleItemUnmount}
-
- />
- );
- }
- }
+ });
// Only render the header if there's any visible items
let header = null;
diff --git a/webapp/stores/emoji_store.jsx b/webapp/stores/emoji_store.jsx
index d8af75dbc..0ec3468ff 100644
--- a/webapp/stores/emoji_store.jsx
+++ b/webapp/stores/emoji_store.jsx
@@ -123,57 +123,54 @@ class EmojiStore extends EventEmitter {
return this.map.get(name);
}
- removeRecentEmoji(id) {
+ addRecentEmoji(alias) {
const recentEmojis = this.getRecentEmojis();
- for (let i = recentEmojis.length - 1; i >= 0; i--) {
- if (recentEmojis[i].id === id) {
- recentEmojis.splice(i, 1);
- break;
- }
- }
- localStorage.setItem(Constants.RECENT_EMOJI_KEY, JSON.stringify(recentEmojis));
- }
-
- addRecentEmoji(rawAlias) {
- const recentEmojis = this.getRecentEmojis();
-
- const alias = rawAlias.split(':').join('');
-
- let emoji = this.getCustomEmojiMap().get(alias);
+ let name;
+ const emoji = this.get(alias);
if (!emoji) {
- const emojiIndex = Emoji.EmojiIndicesByAlias.get(alias);
- emoji = Emoji.Emojis[emojiIndex];
- }
-
- if (!emoji) {
- // something is wrong, so we return
return;
+ } else if (emoji.name) {
+ name = emoji.name;
+ } else {
+ name = emoji.aliases[0];
}
- // odd workaround to the lack of array.findLastIndex - reverse looping & splice
- for (let i = recentEmojis.length - 1; i >= 0; i--) {
- if ((emoji.name && recentEmojis[i].name === emoji.name) ||
- (emoji.filename && recentEmojis[i].filename === emoji.filename)) {
- recentEmojis.splice(i, 1);
- break;
- }
+ const index = recentEmojis.indexOf(name);
+ if (index !== -1) {
+ recentEmojis.splice(index, 1);
}
- recentEmojis.push(emoji);
- // cut off the _top_ if it's over length (since new are added to end)
+ recentEmojis.push(name);
+
if (recentEmojis.length > MAXIMUM_RECENT_EMOJI) {
recentEmojis.splice(0, recentEmojis.length - MAXIMUM_RECENT_EMOJI);
}
+
localStorage.setItem(Constants.RECENT_EMOJI_KEY, JSON.stringify(recentEmojis));
}
getRecentEmojis() {
- const result = JSON.parse(localStorage.getItem(Constants.RECENT_EMOJI_KEY));
- if (!result) {
+ let recentEmojis;
+ try {
+ recentEmojis = JSON.parse(localStorage.getItem(Constants.RECENT_EMOJI_KEY));
+ } catch (e) {
+ // Errors are handled below
+ }
+
+ if (!recentEmojis) {
return [];
}
- return result;
+
+ if (recentEmojis.length > 0 && typeof recentEmojis[0] === 'object') {
+ // Prior to PLT-7267, recent emojis were stored with the entire object for the emoji, but this
+ // has been changed to store only the names of the emojis, so we need to change that
+ recentEmojis = recentEmojis.map((emoji) => {
+ return emoji.name || emoji.aliases[0];
+ });
+ }
+
+ return recentEmojis;
}
hasUnicode(codepoint) {
diff --git a/webapp/utils/emoticons.jsx b/webapp/utils/emoticons.jsx
index b13b50a77..8a10e254e 100644
--- a/webapp/utils/emoticons.jsx
+++ b/webapp/utils/emoticons.jsx
@@ -26,6 +26,8 @@ export const emoticonPatterns = {
thumbsdown: /(^|\s)(:-1:)(?=$|\s)/g // :-1:
};
+export const EMOJI_PATTERN = /(:([a-zA-Z0-9_-]+):)/g;
+
export function handleEmoticons(text, tokens, emojis) {
let output = text;
@@ -49,7 +51,7 @@ export function handleEmoticons(text, tokens, emojis) {
}
// match named emoticons like :goat:
- output = output.replace(/(:([a-zA-Z0-9_-]+):)/g, (fullMatch, matchText, name) => replaceEmoticonWithToken(fullMatch, '', matchText, name));
+ output = output.replace(EMOJI_PATTERN, (fullMatch, matchText, name) => replaceEmoticonWithToken(fullMatch, '', matchText, name));
// match text smilies like :D
for (const name of Object.keys(emoticonPatterns)) {