diff options
Diffstat (limited to 'web/react')
-rw-r--r-- | web/react/components/create_post.jsx | 7 | ||||
-rw-r--r-- | web/react/components/delete_post_modal.jsx | 2 | ||||
-rw-r--r-- | web/react/components/post_body.jsx | 30 | ||||
-rw-r--r-- | web/react/components/post_info.jsx | 25 | ||||
-rw-r--r-- | web/react/dispatcher/event_helpers.jsx | 25 | ||||
-rw-r--r-- | web/react/stores/post_store.jsx | 92 | ||||
-rw-r--r-- | web/react/stores/socket_store.jsx | 4 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 5 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 4 |
9 files changed, 103 insertions, 91 deletions
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 20892898e..265cd68be 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -40,10 +40,6 @@ const holders = defineMessages({ write: { id: 'create_post.write', defaultMessage: 'Write a message...' - }, - deleteMsg: { - id: 'create_post.deleteMsg', - defaultMessage: '(message deleted)' } }); @@ -70,7 +66,6 @@ class CreatePost extends React.Component { this.sendMessage = this.sendMessage.bind(this); PostStore.clearDraftUploads(); - PostStore.deleteMessage(this.props.intl.formatMessage(holders.deleteMsg)); const draft = this.getCurrentDraft(); @@ -506,4 +501,4 @@ CreatePost.propTypes = { intl: intlShape.isRequired }; -export default injectIntl(CreatePost);
\ No newline at end of file +export default injectIntl(CreatePost); diff --git a/web/react/components/delete_post_modal.jsx b/web/react/components/delete_post_modal.jsx index 34fd724f5..9d7dcb3e5 100644 --- a/web/react/components/delete_post_modal.jsx +++ b/web/react/components/delete_post_modal.jsx @@ -88,7 +88,7 @@ export default class DeletePostModal extends React.Component { } } - PostStore.removePost(this.state.post.id, this.state.post.channel_id); + PostStore.deletePost(this.state.post); AsyncClient.getPosts(this.state.post.channel_id); }, (err) => { diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 16f8528b2..d71ac6ec7 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -44,7 +44,6 @@ class PostBody extends React.Component { this.state = { links: linkData.links, - message: linkData.text, post: this.props.post, hasUserProfiles: profiles && Object.keys(profiles).length > 1 }; @@ -106,7 +105,9 @@ class PostBody extends React.Component { if (this.props.post.filenames.length === 0 && this.state.links && this.state.links.length > 0) { this.embed = this.createEmbed(linkData.links[0]); } - this.setState({links: linkData.links, message: linkData.text}); + this.setState({ + links: linkData.links + }); } createEmbed(link) { @@ -310,6 +311,23 @@ class PostBody extends React.Component { ); } + let message; + if (this.props.post.state === Constants.POST_DELETED) { + message = ( + <FormattedMessage + id='post_body.deleted' + defaultMessage='(message deleted)' + /> + ); + } else { + message = ( + <span + onClick={TextFormatting.handleClick} + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message)}} + /> + ); + } + return ( <div> {comment} @@ -320,11 +338,7 @@ class PostBody extends React.Component { className={postClass} > {loading} - <span - ref='message_span' - onClick={TextFormatting.handleClick} - dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}} - /> + {message} </div> <PostBodyAdditionalContent post={this.state.post} @@ -346,4 +360,4 @@ PostBody.propTypes = { handleCommentClick: React.PropTypes.func.isRequired }; -export default injectIntl(PostBody);
\ No newline at end of file +export default injectIntl(PostBody); diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index ddb393520..b1bc8ca14 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -23,13 +23,14 @@ export default class PostInfo extends React.Component { }; this.handlePermalinkCopy = this.handlePermalinkCopy.bind(this); + this.removePost = this.removePost.bind(this); } createDropdown() { var post = this.props.post; var isOwner = UserStore.getCurrentId() === post.user_id; var isAdmin = Utils.isAdmin(UserStore.getCurrentUser().roles); - if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.state === Constants.POST_DELETED) { + if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || Utils.isPostEphemeral(post)) { return ''; } @@ -166,6 +167,25 @@ export default class PostInfo extends React.Component { this.setState({copiedLink: false}); } } + removePost() { + EventHelpers.emitRemovePost(this.props.post); + } + createRemovePostButton(post) { + if (!Utils.isPostEphemeral(post)) { + return null; + } + + return ( + <a + href='#' + className='post__remove theme' + type='button' + onClick={this.removePost} + > + {'×'} + </a> + ); + } render() { var post = this.props.post; var comments = ''; @@ -178,7 +198,7 @@ export default class PostInfo extends React.Component { commentCountText = ''; } - if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && post.state !== Constants.POST_DELETED) { + if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && !Utils.isPostEphemeral(post)) { comments = ( <a href='#' @@ -264,6 +284,7 @@ export default class PostInfo extends React.Component { > {permalinkOverlay} </Overlay> + {this.createRemovePostButton(post)} </li> </ul> ); diff --git a/web/react/dispatcher/event_helpers.jsx b/web/react/dispatcher/event_helpers.jsx index 5eb319320..c1041e438 100644 --- a/web/react/dispatcher/event_helpers.jsx +++ b/web/react/dispatcher/event_helpers.jsx @@ -9,6 +9,7 @@ import Constants from '../utils/constants.jsx'; const ActionTypes = Constants.ActionTypes; import * as AsyncClient from '../utils/async_client.jsx'; import * as Client from '../utils/client.jsx'; +import * as Utils from '../utils/utils.jsx'; export function emitChannelClickEvent(channel) { AsyncClient.getChannels(true); @@ -180,3 +181,27 @@ export function emitPreferenceChangedEvent(preference) { preference }); } + +export function emitRemovePost(post) { + AppDispatcher.handleViewAction({ + type: Constants.ActionTypes.REMOVE_POST, + post + }); +} + +export function sendEphemeralPost(message, channelId) { + const timestamp = Utils.getTimestamp(); + const post = { + id: Utils.generateId(), + user_id: '0', + channel_id: channelId || ChannelStore.getCurrentId(), + message, + type: Constants.POST_TYPE_EPHEMERAL, + create_at: timestamp, + update_at: timestamp, + filenames: [], + props: {} + }; + + emitPostRecievedEvent(post); +} diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx index 08ffef822..8ff58f685 100644 --- a/web/react/stores/post_store.jsx +++ b/web/react/stores/post_store.jsx @@ -57,6 +57,7 @@ class PostStoreClass extends EventEmitter { this.clearFocusedPost = this.clearFocusedPost.bind(this); this.clearChannelVisibility = this.clearChannelVisibility.bind(this); + this.deletePost = this.deletePost.bind(this); this.removePost = this.removePost.bind(this); this.getPendingPosts = this.getPendingPosts.bind(this); @@ -65,10 +66,6 @@ class PostStoreClass extends EventEmitter { this.clearPendingPosts = this.clearPendingPosts.bind(this); this.updatePendingPost = this.updatePendingPost.bind(this); - this.storeUnseenDeletedPost = this.storeUnseenDeletedPost.bind(this); - this.getUnseenDeletedPosts = this.getUnseenDeletedPosts.bind(this); - this.clearUnseenDeletedPosts = this.clearUnseenDeletedPosts.bind(this); - // These functions are bad and work should be done to remove this system when the RHS dies this.storeSelectedPost = this.storeSelectedPost.bind(this); this.getSelectedPost = this.getSelectedPost.bind(this); @@ -211,28 +208,6 @@ class PostStoreClass extends EventEmitter { postList.order = this.postsInfo[id].pendingPosts.order.concat(postList.order); } - // Add deleted posts - if (this.postsInfo[id].hasOwnProperty('deletedPosts')) { - Object.assign(postList.posts, this.postsInfo[id].deletedPosts); - - for (const postID in this.postsInfo[id].deletedPosts) { - if (this.postsInfo[id].deletedPosts.hasOwnProperty(postID)) { - postList.order.push(postID); - } - } - - // Merge would be faster - postList.order.sort((a, b) => { - if (postList.posts[a].create_at > postList.posts[b].create_at) { - return -1; - } - if (postList.posts[a].create_at < postList.posts[b].create_at) { - return 1; - } - return 0; - }); - } - return postList; } @@ -286,15 +261,6 @@ class PostStoreClass extends EventEmitter { if (combinedPosts.order.indexOf(pid) === -1) { combinedPosts.order.push(pid); } - } else { - if (pid in combinedPosts.posts) { - Reflect.deleteProperty(combinedPosts.posts, pid); - } - - const index = combinedPosts.order.indexOf(pid); - if (index !== -1) { - combinedPosts.order.splice(index, 1); - } } } } @@ -365,6 +331,22 @@ class PostStoreClass extends EventEmitter { this.postsInfo[id].atBottom = atBottom; } + deletePost(post) { + const postList = this.postsInfo[post.channel_id].postList; + + if (isPostListNull(postList)) { + return; + } + + if (post.id in postList.posts) { + // make sure to copy the post so that component state changes work properly + postList.posts[post.id] = Object.assign({}, post, { + state: Constants.POST_DELETED, + filenames: [] + }); + } + } + removePost(post) { const channelId = post.channel_id; this.makePostsInfo(channelId); @@ -439,37 +421,6 @@ class PostStoreClass extends EventEmitter { this.emitChange(); } - storeUnseenDeletedPost(post) { - let posts = this.getUnseenDeletedPosts(post.channel_id); - - if (!posts) { - posts = {}; - } - - post.message = this.delete_message; - post.state = Constants.POST_DELETED; - post.filenames = []; - - posts[post.id] = post; - - this.makePostsInfo(post.channel_id); - this.postsInfo[post.channel_id].deletedPosts = posts; - } - - getUnseenDeletedPosts(channelId) { - if (this.postsInfo.hasOwnProperty(channelId)) { - return this.postsInfo[channelId].deletedPosts; - } - - return null; - } - - clearUnseenDeletedPosts(channelId) { - if (this.postsInfo.hasOwnProperty(channelId)) { - Reflect.deleteProperty(this.postsInfo[channelId], 'deletedPosts'); - } - } - storeSelectedPost(postList) { this.selectedPost = postList; } @@ -581,9 +532,6 @@ class PostStoreClass extends EventEmitter { return commentCount; } - deleteMessage(msg) { - this.delete_message = msg; - } } var PostStore = new PostStoreClass(); @@ -615,7 +563,6 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => { case ActionTypes.CLICK_CHANNEL: PostStore.clearFocusedPost(); PostStore.clearChannelVisibility(action.id, true); - PostStore.clearUnseenDeletedPosts(action.prev); break; case ActionTypes.CREATE_POST: PostStore.storePendingPost(action.post); @@ -623,7 +570,10 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => { PostStore.jumpPostsViewToBottom(); break; case ActionTypes.POST_DELETED: - PostStore.storeUnseenDeletedPost(action.post); + PostStore.deletePost(action.post); + PostStore.emitChange(); + break; + case ActionTypes.REMOVE_POST: PostStore.removePost(action.post); PostStore.emitChange(); break; diff --git a/web/react/stores/socket_store.jsx b/web/react/stores/socket_store.jsx index 744c2c8e5..33604f44b 100644 --- a/web/react/stores/socket_store.jsx +++ b/web/react/stores/socket_store.jsx @@ -109,6 +109,7 @@ class SocketStoreClass extends EventEmitter { handleMessage(msg) { switch (msg.action) { case SocketEvents.POSTED: + case SocketEvents.EPHEMERAL_MESSAGE: handleNewPostEvent(msg, this.translations); break; @@ -179,7 +180,6 @@ function handleNewPostEvent(msg, translations) { mentions = JSON.parse(msg.props.mentions); } - const channelType = msgProps.channel_type; const channel = ChannelStore.get(msg.channel_id); const user = UserStore.getCurrentUser(); const member = ChannelStore.getMember(msg.channel_id); @@ -191,7 +191,7 @@ function handleNewPostEvent(msg, translations) { if (notifyLevel === 'none') { return; - } else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channelType !== Constants.DM_CHANNEL) { + } else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== Constants.DM_CHANNEL) { return; } diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 11a8da669..c1bd41b88 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -12,6 +12,7 @@ export default { LEAVE_CHANNEL: null, CREATE_POST: null, POST_DELETED: null, + REMOVE_POST: null, RECIEVED_CHANNELS: null, RECIEVED_CHANNEL: null, @@ -78,7 +79,8 @@ export default { USER_ADDED: 'user_added', USER_REMOVED: 'user_removed', TYPING: 'typing', - PREFERENCE_CHANGED: 'preference_changed' + PREFERENCE_CHANGED: 'preference_changed', + EPHEMERAL_MESSAGE: 'ephemeral_message' }, //SPECIAL_MENTIONS: ['all', 'channel'], @@ -126,6 +128,7 @@ export default { POST_LOADING: 'loading', POST_FAILED: 'failed', POST_DELETED: 'deleted', + POST_TYPE_EPHEMERAL: 'system_ephemeral', POST_TYPE_JOIN_LEAVE: 'system_join_leave', SYSTEM_MESSAGE_PREFIX: 'system_', SYSTEM_MESSAGE_PROFILE_NAME: 'System', diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 494c38bdb..e8cfc82bc 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -1355,3 +1355,7 @@ export function languages() { ] ); } + +export function isPostEphemeral(post) { + return post.type === Constants.POST_TYPE_EPHEMERAL || post.state === Constants.POST_DELETED; +} |