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
Этот коммит содержится в:
Harrison Healey
2017-08-04 14:03:41 -04:00
коммит произвёл Christopher Speller
родитель 2c8a5ffd97
Коммит 3998659236
7 изменённых файлов: 96 добавлений и 113 удалений

Просмотреть файл

@@ -11,8 +11,8 @@ import TeamStore from 'stores/team_store.jsx';
import {loadNewDMIfNeeded, loadNewGMIfNeeded} from 'actions/user_actions.jsx'; import {loadNewDMIfNeeded, loadNewGMIfNeeded} from 'actions/user_actions.jsx';
import {sendDesktopNotification} from 'actions/notification_actions.jsx'; import {sendDesktopNotification} from 'actions/notification_actions.jsx';
import Constants from 'utils/constants.jsx'; import {ActionTypes, Constants} from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes; import {EMOJI_PATTERN} from 'utils/emoticons.jsx';
import {browserHistory} from 'react-router/es6'; import {browserHistory} from 'react-router/es6';
@@ -164,6 +164,15 @@ export function removeReaction(channelId, postId, emojiName) {
} }
export function createPost(post, files, success) { 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(() => { PostActions.createPost(post, files)(dispatch, getState).then(() => {
if (post.root_id) { if (post.root_id) {
PostStore.storeCommentDraft(post.root_id, null); PostStore.storeCommentDraft(post.root_id, null);

Просмотреть файл

@@ -31,7 +31,7 @@ import {browserHistory} from 'react-router/es6';
const ActionTypes = Constants.ActionTypes; const ActionTypes = Constants.ActionTypes;
const KeyCodes = Constants.KeyCodes; 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 PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
@@ -87,9 +87,13 @@ export default class CreateComment extends React.Component {
if (this.state.message === '') { if (this.state.message === '') {
this.setState({message: ':' + emojiAlias + ': '}); this.setState({message: ':' + emojiAlias + ': '});
} else { } else {
//check whether there is already a blank at the end of the current message // Check whether there is already a blank at the end of the current message
const newMessage = (/\s+$/.test(this.state.message)) ? let newMessage;
this.state.message + ':' + emojiAlias + ': ' : this.state.message + ' :' + emojiAlias + ': '; if ((/\s+$/).test(this.state.message)) {
newMessage = this.state.message + ':' + emojiAlias + ': ';
} else {
newMessage = this.state.message + ' :' + emojiAlias + ': ';
}
this.setState({message: newMessage}); this.setState({message: newMessage});
} }
@@ -230,14 +234,6 @@ export default class CreateComment extends React.Component {
GlobalActions.emitUserCommentedEvent(post); 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); PostActions.createPost(post, this.state.fileInfos);
this.setState({ this.setState({

Просмотреть файл

@@ -41,7 +41,6 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
export const REACTION_PATTERN = /^(\+|-):([^:\s]+):\s*$/; export const REACTION_PATTERN = /^(\+|-):([^:\s]+):\s*$/;
export const EMOJI_PATTERN = /:[A-Za-z-_0-9]*:/g;
export default class CreatePost extends React.Component { export default class CreatePost extends React.Component {
constructor(props) { constructor(props) {
@@ -268,14 +267,6 @@ export default class CreatePost extends React.Component {
GlobalActions.emitUserPostedEvent(post); 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, PostActions.createPost(post, this.state.fileInfos,
() => GlobalActions.postListScrollChange(true), () => GlobalActions.postListScrollChange(true),
(err) => { (err) => {

Просмотреть файл

@@ -1,8 +1,7 @@
import PropTypes from 'prop-types';
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information. // See License.txt for license information.
import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
export default class EmojiPickerCategory extends React.Component { export default class EmojiPickerCategory extends React.Component {

Просмотреть файл

@@ -169,45 +169,57 @@ export default class EmojiPicker extends React.Component {
} }
renderCategory(category, isLoaded, filter) { renderCategory(category, isLoaded, filter) {
const items = []; let emojis;
let indices = [];
let recentEmojis = [];
if (category === 'recent') { if (category === 'recent') {
recentEmojis = EmojiStore.getRecentEmojis(); const recentEmojis = [...EmojiStore.getRecentEmojis()];
indices = [...Array(recentEmojis.length).keys()];
// reverse indices so most recently added is first // Reverse so most recently added is first
indices.reverse(); recentEmojis.reverse();
emojis = recentEmojis.filter((name) => {
return EmojiStore.has(name);
}).map((name) => {
return EmojiStore.get(name);
});
} else { } 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) { // Apply filter
let emoji = {}; emojis = emojis.filter((emoji) => {
if (emoji.name) {
return emoji.name.indexOf(filter) !== -1;
}
for (const alias of emoji.aliases) {
if (alias.indexOf(filter) !== -1) {
return true;
}
}
return false;
});
const items = emojis.map((emoji) => {
const name = emoji.name || emoji.aliases[0];
let key;
if (category === 'recent') { if (category === 'recent') {
emoji = recentEmojis[index]; key = 'system_recent_' + name;
} else if (category === 'custom' && emoji.name) {
key = 'custom_' + name;
} else { } else {
emoji = Emoji.Emojis[index]; key = 'system_' + name;
}
if (filter) {
let matches = false;
for (const alias of emoji.aliases || [...emoji.name]) {
if (alias.indexOf(filter) !== -1) {
matches = true;
break;
}
}
if (!matches) {
continue;
}
} }
items.push( return (
<EmojiPickerItem <EmojiPickerItem
key={'system_' + (category === 'recent' ? 'recent_' : '') + (emoji.name || emoji.aliases[0])} key={key}
emoji={emoji} emoji={emoji}
category={category} category={category}
isLoaded={isLoaded} isLoaded={isLoaded}
@@ -217,30 +229,7 @@ export default class EmojiPicker extends React.Component {
onItemUnmount={this.handleItemUnmount} 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 // Only render the header if there's any visible items
let header = null; let header = null;

Просмотреть файл

@@ -123,57 +123,54 @@ class EmojiStore extends EventEmitter {
return this.map.get(name); 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 recentEmojis = this.getRecentEmojis();
const alias = rawAlias.split(':').join(''); let name;
const emoji = this.get(alias);
let emoji = this.getCustomEmojiMap().get(alias);
if (!emoji) { if (!emoji) {
const emojiIndex = Emoji.EmojiIndicesByAlias.get(alias);
emoji = Emoji.Emojis[emojiIndex];
}
if (!emoji) {
// something is wrong, so we return
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 const index = recentEmojis.indexOf(name);
for (let i = recentEmojis.length - 1; i >= 0; i--) { if (index !== -1) {
if ((emoji.name && recentEmojis[i].name === emoji.name) || recentEmojis.splice(index, 1);
(emoji.filename && recentEmojis[i].filename === emoji.filename)) {
recentEmojis.splice(i, 1);
break;
}
} }
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) { if (recentEmojis.length > MAXIMUM_RECENT_EMOJI) {
recentEmojis.splice(0, recentEmojis.length - MAXIMUM_RECENT_EMOJI); recentEmojis.splice(0, recentEmojis.length - MAXIMUM_RECENT_EMOJI);
} }
localStorage.setItem(Constants.RECENT_EMOJI_KEY, JSON.stringify(recentEmojis)); localStorage.setItem(Constants.RECENT_EMOJI_KEY, JSON.stringify(recentEmojis));
} }
getRecentEmojis() { getRecentEmojis() {
const result = JSON.parse(localStorage.getItem(Constants.RECENT_EMOJI_KEY)); let recentEmojis;
if (!result) { try {
recentEmojis = JSON.parse(localStorage.getItem(Constants.RECENT_EMOJI_KEY));
} catch (e) {
// Errors are handled below
}
if (!recentEmojis) {
return []; 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) { hasUnicode(codepoint) {

Просмотреть файл

@@ -26,6 +26,8 @@ export const emoticonPatterns = {
thumbsdown: /(^|\s)(:-1:)(?=$|\s)/g // :-1: thumbsdown: /(^|\s)(:-1:)(?=$|\s)/g // :-1:
}; };
export const EMOJI_PATTERN = /(:([a-zA-Z0-9_-]+):)/g;
export function handleEmoticons(text, tokens, emojis) { export function handleEmoticons(text, tokens, emojis) {
let output = text; let output = text;
@@ -49,7 +51,7 @@ export function handleEmoticons(text, tokens, emojis) {
} }
// match named emoticons like :goat: // 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 // match text smilies like :D
for (const name of Object.keys(emoticonPatterns)) { for (const name of Object.keys(emoticonPatterns)) {