Merge pull request #1582 from hmhealey/emojiautocomplete
Emoji autocomplete
Этот коммит содержится в:
74
web/react/components/suggestion/emoticon_provider.jsx
Обычный файл
74
web/react/components/suggestion/emoticon_provider.jsx
Обычный файл
@@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import SuggestionStore from '../../stores/suggestion_store.jsx';
|
||||||
|
import * as Emoticons from '../../utils/emoticons.jsx';
|
||||||
|
|
||||||
|
const MAX_EMOTICON_SUGGESTIONS = 40;
|
||||||
|
|
||||||
|
class EmoticonSuggestion extends React.Component {
|
||||||
|
render() {
|
||||||
|
const text = this.props.term;
|
||||||
|
const name = this.props.item;
|
||||||
|
|
||||||
|
let className = 'emoticon-suggestion';
|
||||||
|
if (this.props.isSelection) {
|
||||||
|
className += ' suggestion--selected';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={className}
|
||||||
|
onClick={this.props.onClick}
|
||||||
|
>
|
||||||
|
<div className='pull-left'>
|
||||||
|
<img
|
||||||
|
alt={text}
|
||||||
|
className='emoticon-suggestion__image'
|
||||||
|
src={Emoticons.getImagePathForEmoticon(name)}
|
||||||
|
title={text}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='pull-left'>
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmoticonSuggestion.propTypes = {
|
||||||
|
item: React.PropTypes.string.isRequired,
|
||||||
|
term: React.PropTypes.string.isRequired,
|
||||||
|
isSelection: React.PropTypes.bool,
|
||||||
|
onClick: React.PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class EmoticonProvider {
|
||||||
|
handlePretextChanged(suggestionId, pretext) {
|
||||||
|
const captured = (/(?:^|\s)(:([a-zA-Z0-9_+\-]*))$/g).exec(pretext);
|
||||||
|
if (captured) {
|
||||||
|
const text = captured[1];
|
||||||
|
const partialName = captured[2];
|
||||||
|
|
||||||
|
const terms = [];
|
||||||
|
const names = [];
|
||||||
|
|
||||||
|
for (const emoticon of Emoticons.emoticonMap.keys()) {
|
||||||
|
if (emoticon.indexOf(partialName) !== -1) {
|
||||||
|
terms.push(':' + emoticon + ':');
|
||||||
|
names.push(emoticon);
|
||||||
|
|
||||||
|
if (terms.length >= MAX_EMOTICON_SUGGESTIONS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terms.length > 0) {
|
||||||
|
SuggestionStore.setMatchedPretext(suggestionId, text);
|
||||||
|
SuggestionStore.addSuggestions(suggestionId, terms, names, EmoticonSuggestion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,6 +100,7 @@ export default class SuggestionList extends React.Component {
|
|||||||
key={term}
|
key={term}
|
||||||
ref={term}
|
ref={term}
|
||||||
item={item}
|
item={item}
|
||||||
|
term={term}
|
||||||
isSelection={isSelection}
|
isSelection={isSelection}
|
||||||
onClick={this.handleItemClick.bind(this, term)}
|
onClick={this.handleItemClick.bind(this, term)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import AtMentionProvider from './suggestion/at_mention_provider.jsx';
|
import AtMentionProvider from './suggestion/at_mention_provider.jsx';
|
||||||
import CommandProvider from './suggestion/command_provider.jsx';
|
import CommandProvider from './suggestion/command_provider.jsx';
|
||||||
|
import EmoticonProvider from './suggestion/emoticon_provider.jsx';
|
||||||
import SuggestionList from './suggestion/suggestion_list.jsx';
|
import SuggestionList from './suggestion/suggestion_list.jsx';
|
||||||
import SuggestionBox from './suggestion/suggestion_box.jsx';
|
import SuggestionBox from './suggestion/suggestion_box.jsx';
|
||||||
import ErrorStore from '../stores/error_store.jsx';
|
import ErrorStore from '../stores/error_store.jsx';
|
||||||
@@ -29,7 +30,7 @@ export default class Textbox extends React.Component {
|
|||||||
connection: ''
|
connection: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
this.suggestionProviders = [new AtMentionProvider()];
|
this.suggestionProviders = [new AtMentionProvider(), new EmoticonProvider()];
|
||||||
if (props.supportsCommands) {
|
if (props.supportsCommands) {
|
||||||
this.suggestionProviders.push(new CommandProvider());
|
this.suggestionProviders.push(new CommandProvider());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,19 +116,19 @@ function initializeEmoticonMap() {
|
|||||||
const out = new Map();
|
const out = new Map();
|
||||||
|
|
||||||
for (let i = 0; i < emoticonNames.length; i++) {
|
for (let i = 0; i < emoticonNames.length; i++) {
|
||||||
out[emoticonNames[i]] = true;
|
out.set(emoticonNames[i], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emoticonMap = initializeEmoticonMap();
|
export const emoticonMap = initializeEmoticonMap();
|
||||||
|
|
||||||
export function handleEmoticons(text, tokens) {
|
export function handleEmoticons(text, tokens) {
|
||||||
let output = text;
|
let output = text;
|
||||||
|
|
||||||
function replaceEmoticonWithToken(fullMatch, prefix, matchText, name) {
|
function replaceEmoticonWithToken(fullMatch, prefix, matchText, name) {
|
||||||
if (emoticonMap[name]) {
|
if (emoticonMap.has(name)) {
|
||||||
const index = tokens.size;
|
const index = tokens.size;
|
||||||
const alias = `MM_EMOTICON${index}`;
|
const alias = `MM_EMOTICON${index}`;
|
||||||
|
|
||||||
|
|||||||
@@ -45,3 +45,19 @@
|
|||||||
.command-desc {
|
.command-desc {
|
||||||
color: #a7a8ab;
|
color: #a7a8ab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emoticon-suggestion {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoticon-suggestion__image {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
margin-right: 6px;
|
||||||
|
padding: 2px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user