PLT-3145 Custom Emojis (#3381)
* Reorganized Backstage code to use a view controller and separated it from integrations code * Renamed InstalledIntegrations component to BackstageList * Added EmojiList page * Added AddEmoji page * Added custom emoji to autocomplete and text formatter * Moved system emoji to EmojiStore * Stopped trying to get emoji before logging in * Rerender posts when emojis change * Fixed submit handler on backstage pages to properly support enter * Removed debugging code * Updated javascript driver * Fixed unit tests * Fixed backstage routes * Added clientside validation to prevent users from creating an emoji with the same name as a system one * Fixed AddEmoji page to properly redirect when an emoji is created successfully * Fixed updating emoji list when an emoji is deleted * Added type prop to BackstageList to properly support using a table for the list * Added help text to EmojiList * Fixed backstage on smaller screen sizes * Disable custom emoji by default * Improved restrictions on creating emojis * Fixed non-admin users seeing the option to delete each other's emojis * Fixing gofmt * Fixed emoji unit tests * Fixed trying to get emoji from the server when it's disabled
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
a65f1fc266
Коммит
dc2f2a8001
@@ -84,6 +84,10 @@ export default class Post extends React.Component {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextProps.emojis !== this.props.emojis) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
render() {
|
||||
@@ -200,6 +204,7 @@ export default class Post extends React.Component {
|
||||
handleCommentClick={this.handleCommentClick}
|
||||
compactDisplay={this.props.compactDisplay}
|
||||
previewCollapsed={this.props.previewCollapsed}
|
||||
emojis={this.props.emojis}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -225,5 +230,6 @@ Post.propTypes = {
|
||||
compactDisplay: React.PropTypes.bool,
|
||||
previewCollapsed: React.PropTypes.string,
|
||||
commentCount: React.PropTypes.number,
|
||||
useMilitaryTime: React.PropTypes.bool.isRequired
|
||||
useMilitaryTime: React.PropTypes.bool.isRequired,
|
||||
emojis: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -37,6 +37,10 @@ export default class PostBody extends React.Component {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextProps.emojis !== this.props.emojis) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -151,7 +155,7 @@ export default class PostBody extends React.Component {
|
||||
message = (
|
||||
<span
|
||||
onClick={TextFormatting.handleClick}
|
||||
dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message)}}
|
||||
dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message, {emojis: this.props.emojis})}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -199,5 +203,6 @@ PostBody.propTypes = {
|
||||
retryPost: React.PropTypes.func.isRequired,
|
||||
handleCommentClick: React.PropTypes.func.isRequired,
|
||||
compactDisplay: React.PropTypes.bool,
|
||||
previewCollapsed: React.PropTypes.string
|
||||
previewCollapsed: React.PropTypes.string,
|
||||
emojis: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -35,6 +35,9 @@ export default class PostBodyAdditionalContent extends React.Component {
|
||||
if (!Utils.areObjectsEqual(nextProps.post, this.props.post)) {
|
||||
return true;
|
||||
}
|
||||
if (!Utils.areObjectsEqual(nextProps.message, this.props.message)) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.embedVisible !== this.state.embedVisible) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -265,6 +265,7 @@ export default class PostList extends React.Component {
|
||||
compactDisplay={this.props.compactDisplay}
|
||||
previewCollapsed={this.props.previewsCollapsed}
|
||||
useMilitaryTime={this.props.useMilitaryTime}
|
||||
emojis={this.props.emojis}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -527,5 +528,6 @@ PostList.propTypes = {
|
||||
compactDisplay: React.PropTypes.bool,
|
||||
previewsCollapsed: React.PropTypes.string,
|
||||
useMilitaryTime: React.PropTypes.bool.isRequired,
|
||||
isFocusPost: React.PropTypes.bool
|
||||
isFocusPost: React.PropTypes.bool,
|
||||
emojis: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import PostList from './components/post_list.jsx';
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
|
||||
import EmojiStore from 'stores/emoji_store.jsx';
|
||||
import PostStore from 'stores/post_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
@@ -20,6 +21,7 @@ export default class PostFocusView extends React.Component {
|
||||
this.onChannelChange = this.onChannelChange.bind(this);
|
||||
this.onPostsChange = this.onPostsChange.bind(this);
|
||||
this.onUserChange = this.onUserChange.bind(this);
|
||||
this.onEmojiChange = this.onEmojiChange.bind(this);
|
||||
this.onPostListScroll = this.onPostListScroll.bind(this);
|
||||
|
||||
const focusedPostId = PostStore.getFocusedPostId();
|
||||
@@ -38,7 +40,8 @@ export default class PostFocusView extends React.Component {
|
||||
currentChannel: ChannelStore.getCurrentId().slice(),
|
||||
scrollPostId: focusedPostId,
|
||||
atTop: PostStore.getVisibilityAtTop(focusedPostId),
|
||||
atBottom: PostStore.getVisibilityAtBottom(focusedPostId)
|
||||
atBottom: PostStore.getVisibilityAtBottom(focusedPostId),
|
||||
emojis: EmojiStore.getEmojis()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,12 +49,14 @@ export default class PostFocusView extends React.Component {
|
||||
ChannelStore.addChangeListener(this.onChannelChange);
|
||||
PostStore.addChangeListener(this.onPostsChange);
|
||||
UserStore.addChangeListener(this.onUserChange);
|
||||
EmojiStore.addChangeListener(this.onEmojiChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ChannelStore.removeChangeListener(this.onChannelChange);
|
||||
PostStore.removeChangeListener(this.onPostsChange);
|
||||
UserStore.removeChangeListener(this.onUserChange);
|
||||
EmojiStore.removeChangeListener(this.onEmojiChange);
|
||||
}
|
||||
|
||||
onChannelChange() {
|
||||
@@ -87,6 +92,12 @@ export default class PostFocusView extends React.Component {
|
||||
this.setState({currentUser: UserStore.getCurrentUser(), profiles: JSON.parse(JSON.stringify(profiles))});
|
||||
}
|
||||
|
||||
onEmojiChange() {
|
||||
this.setState({
|
||||
emojis: EmojiStore.getEmojis()
|
||||
});
|
||||
}
|
||||
|
||||
onPostListScroll() {
|
||||
this.setState({scrollType: ScrollTypes.FREE});
|
||||
}
|
||||
@@ -116,6 +127,7 @@ export default class PostFocusView extends React.Component {
|
||||
showMoreMessagesBottom={!this.state.atBottom}
|
||||
postsToHighlight={postsToHighlight}
|
||||
isFocusPost={true}
|
||||
emojis={this.state.emojis}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import PostList from './components/post_list.jsx';
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
|
||||
import EmojiStore from 'stores/emoji_store.jsx';
|
||||
import PreferenceStore from 'stores/preference_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import PostStore from 'stores/post_store.jsx';
|
||||
@@ -24,6 +25,7 @@ export default class PostViewController extends React.Component {
|
||||
this.onPreferenceChange = this.onPreferenceChange.bind(this);
|
||||
this.onUserChange = this.onUserChange.bind(this);
|
||||
this.onPostsChange = this.onPostsChange.bind(this);
|
||||
this.onEmojisChange = this.onEmojisChange.bind(this);
|
||||
this.onPostsViewJumpRequest = this.onPostsViewJumpRequest.bind(this);
|
||||
this.onPostListScroll = this.onPostListScroll.bind(this);
|
||||
this.onActivate = this.onActivate.bind(this);
|
||||
@@ -53,7 +55,8 @@ export default class PostViewController extends React.Component {
|
||||
displayPostsInCenter: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED,
|
||||
compactDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
|
||||
previewsCollapsed: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSE_DISPLAY, 'false'),
|
||||
useMilitaryTime: PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false)
|
||||
useMilitaryTime: PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false),
|
||||
emojis: EmojiStore.getEmojis()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -102,11 +105,18 @@ export default class PostViewController extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
onEmojisChange() {
|
||||
this.setState({
|
||||
emojis: EmojiStore.getEmojis()
|
||||
});
|
||||
}
|
||||
|
||||
onActivate() {
|
||||
PreferenceStore.addChangeListener(this.onPreferenceChange);
|
||||
UserStore.addChangeListener(this.onUserChange);
|
||||
PostStore.addChangeListener(this.onPostsChange);
|
||||
PostStore.addPostsViewJumpListener(this.onPostsViewJumpRequest);
|
||||
EmojiStore.addChangeListener(this.onEmojisChange);
|
||||
}
|
||||
|
||||
onDeactivate() {
|
||||
@@ -114,6 +124,7 @@ export default class PostViewController extends React.Component {
|
||||
UserStore.removeChangeListener(this.onUserChange);
|
||||
PostStore.removeChangeListener(this.onPostsChange);
|
||||
PostStore.removePostsViewJumpListener(this.onPostsViewJumpRequest);
|
||||
EmojiStore.removeChangeListener(this.onEmojisChange);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
@@ -265,6 +276,7 @@ export default class PostViewController extends React.Component {
|
||||
previewsCollapsed={this.state.previewsCollapsed}
|
||||
useMilitaryTime={this.state.useMilitaryTime}
|
||||
lastViewed={this.state.lastViewed}
|
||||
emojis={this.state.emojis}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user