1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React from 'react';
import {default as EmojiStore, EmojiMap} from 'stores/emoji_store.jsx';
import * as Emoticons from 'utils/emoticons.jsx';
import SuggestionStore from 'stores/suggestion_store.jsx';
import Suggestion from './suggestion.jsx';
import store from 'stores/redux_store.jsx';
import {getCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
const MIN_EMOTICON_LENGTH = 2;
class EmoticonSuggestion extends Suggestion {
render() {
const text = this.props.term;
const emoji = this.props.item.emoji;
let className = 'emoticon-suggestion';
if (this.props.isSelection) {
className += ' suggestion--selected';
}
return (
<div
className={className}
onClick={this.handleClick}
>
<div className='pull-left'>
<img
alt={text}
className='emoticon-suggestion__image'
src={EmojiStore.getEmojiImageUrl(emoji)}
title={text}
/>
</div>
<div className='pull-left'>
{text}
</div>
</div>
);
}
}
export default class EmoticonProvider {
handlePretextChanged(suggestionId, pretext) {
let hasSuggestions = false;
// look for the potential emoticons at the start of the text, after whitespace, and at the start of emoji reaction commands
const captured = (/(^|\s|^\+|^-)(:([^:\s]*))$/g).exec(pretext);
if (captured) {
const prefix = captured[1];
const text = captured[2];
const partialName = captured[3];
if (partialName.length < MIN_EMOTICON_LENGTH) {
SuggestionStore.clearSuggestions(suggestionId);
return false;
}
const matched = [];
// check for text emoticons if this isn't for an emoji reaction
if (prefix !== '-' && prefix !== '+') {
for (const emoticon of Object.keys(Emoticons.emoticonPatterns)) {
if (Emoticons.emoticonPatterns[emoticon].test(text)) {
SuggestionStore.addSuggestion(suggestionId, text, EmojiStore.get(emoticon), EmoticonSuggestion, text);
hasSuggestions = true;
}
}
}
const emojis = new EmojiMap(getCustomEmojisByName(store.getState()));
// check for named emoji
for (const [name, emoji] of emojis) {
if (emoji.aliases) {
// This is a system emoji so it may have multiple names
for (const alias of emoji.aliases) {
if (alias.indexOf(partialName) !== -1) {
matched.push({name: alias, emoji});
break;
}
}
} else if (name.indexOf(partialName) !== -1) {
// This is a custom emoji so it only has one name
matched.push({name, emoji});
}
}
// sort the emoticons so that emoticons starting with the entered text come first
matched.sort((a, b) => {
const aName = a.name;
const bName = b.name;
const aPrefix = aName.startsWith(partialName);
const bPrefix = bName.startsWith(partialName);
if (aPrefix === bPrefix) {
return aName.localeCompare(bName);
} else if (aPrefix) {
return -1;
}
return 1;
});
const terms = matched.map((item) => ':' + item.name + ':');
SuggestionStore.clearSuggestions(suggestionId);
if (terms.length > 0) {
SuggestionStore.addSuggestions(suggestionId, terms, matched, EmoticonSuggestion, text);
hasSuggestions = true;
}
}
if (hasSuggestions) {
// force the selection to be cleared since the order of elements may have changed
SuggestionStore.clearSelection(suggestionId);
return true;
}
return false;
}
}
|