summaryrefslogtreecommitdiffstats
path: root/web/react
diff options
context:
space:
mode:
Diffstat (limited to 'web/react')
-rw-r--r--web/react/components/post_body.jsx137
-rw-r--r--web/react/components/post_body_additional_content.jsx103
-rw-r--r--web/react/components/post_image.jsx81
-rw-r--r--web/react/components/posts_view.jsx2
-rw-r--r--web/react/components/rhs_thread.jsx5
-rw-r--r--web/react/components/search_results.jsx10
-rw-r--r--web/react/components/search_results_item.jsx8
7 files changed, 173 insertions, 173 deletions
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index 506b38ce6..70cf86748 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -6,13 +6,9 @@ import UserStore from '../stores/user_store.jsx';
import * as Utils from '../utils/utils.jsx';
import * as Emoji from '../utils/emoticons.jsx';
import Constants from '../utils/constants.jsx';
-const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
import * as TextFormatting from '../utils/text_formatting.jsx';
import twemoji from 'twemoji';
import PostBodyAdditionalContent from './post_body_additional_content.jsx';
-import YoutubeVideo from './youtube_video.jsx';
-
-import providers from './providers.json';
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
@@ -31,19 +27,7 @@ class PostBody extends React.Component {
constructor(props) {
super(props);
- this.isImgLoading = false;
-
this.parseEmojis = this.parseEmojis.bind(this);
- this.createEmbed = this.createEmbed.bind(this);
- this.createImageEmbed = this.createImageEmbed.bind(this);
- this.loadImg = this.loadImg.bind(this);
-
- const linkData = Utils.extractLinks(this.props.post.message);
-
- this.state = {
- links: linkData,
- post: this.props.post
- };
}
getAllChildNodes(nodeIn) {
@@ -69,120 +53,10 @@ class PostBody extends React.Component {
});
}
- componentWillMount() {
- if (this.props.post.filenames.length === 0 && this.state.links && this.state.links.length > 0) {
- this.embed = this.createEmbed(this.state.links[0]);
- }
- }
-
componentDidMount() {
this.parseEmojis();
}
- componentDidUpdate() {
- this.parseEmojis();
- }
-
- componentWillReceiveProps(nextProps) {
- const linkData = Utils.extractLinks(nextProps.post.message);
- if (this.props.post.filenames.length === 0 && this.state.links && this.state.links.length > 0) {
- this.embed = this.createEmbed(linkData[0]);
- }
- this.setState({
- links: linkData
- });
- }
-
- createEmbed(link) {
- const post = this.state.post;
-
- if (!link) {
- if (post.type === 'oEmbed') {
- post.props.oEmbedLink = '';
- post.type = '';
- }
- return null;
- }
-
- const trimmedLink = link.trim();
-
- if (Utils.isFeatureEnabled(PreReleaseFeatures.EMBED_PREVIEW)) {
- const provider = this.getOembedProvider(trimmedLink);
- if (provider != null) {
- post.props.oEmbedLink = trimmedLink;
- post.type = 'oEmbed';
- this.setState({post, provider});
- return '';
- }
- }
-
- if (YoutubeVideo.isYoutubeLink(link)) {
- return (
- <YoutubeVideo
- channelId={post.channel_id}
- link={link}
- />
- );
- }
-
- for (let i = 0; i < Constants.IMAGE_TYPES.length; i++) {
- const imageType = Constants.IMAGE_TYPES[i];
- const suffix = link.substring(link.length - (imageType.length + 1));
- if (suffix === '.' + imageType || suffix === '=' + imageType) {
- return this.createImageEmbed(link, this.state.imgLoaded);
- }
- }
-
- return null;
- }
-
- getOembedProvider(link) {
- for (let i = 0; i < providers.length; i++) {
- for (let j = 0; j < providers[i].patterns.length; j++) {
- if (link.match(providers[i].patterns[j])) {
- return providers[i];
- }
- }
- }
- return null;
- }
-
- loadImg(src) {
- if (this.isImgLoading) {
- return;
- }
-
- this.isImgLoading = true;
-
- const img = new Image();
- img.onload = (
- () => {
- this.embed = this.createImageEmbed(src, true);
- this.setState({imgLoaded: true});
- }
- );
- img.src = src;
- }
-
- createImageEmbed(link, isLoaded) {
- if (!isLoaded) {
- this.loadImg(link);
- return (
- <img
- className='img-div placeholder'
- height='500px'
- />
- );
- }
-
- return (
- <img
- className='img-div'
- src={link}
- />
- );
- }
-
render() {
const {formatMessage} = this.props.intl;
const post = this.props.post;
@@ -295,6 +169,7 @@ class PostBody extends React.Component {
}
let message;
+ let additionalContent = null;
if (this.props.post.state === Constants.POST_DELETED) {
message = (
<FormattedMessage
@@ -309,6 +184,10 @@ class PostBody extends React.Component {
dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message)}}
/>
);
+
+ additionalContent = (
+ <PostBodyAdditionalContent post={this.props.post}/>
+ );
}
return (
@@ -323,12 +202,8 @@ class PostBody extends React.Component {
{loading}
{message}
</div>
- <PostBodyAdditionalContent
- post={this.state.post}
- provider={this.state.provider}
- />
{fileAttachmentHolder}
- {this.embed}
+ {additionalContent}
</div>
</div>
);
diff --git a/web/react/components/post_body_additional_content.jsx b/web/react/components/post_body_additional_content.jsx
index 4871eea4f..a76c59fb3 100644
--- a/web/react/components/post_body_additional_content.jsx
+++ b/web/react/components/post_body_additional_content.jsx
@@ -3,72 +3,103 @@
import PostAttachmentList from './post_attachment_list.jsx';
import PostAttachmentOEmbed from './post_attachment_oembed.jsx';
+import PostImage from './post_image.jsx';
+import YoutubeVideo from './youtube_video.jsx';
+
+import Constants from '../utils/constants.jsx';
+import OEmbedProviders from './providers.json';
+import * as Utils from '../utils/utils.jsx';
export default class PostBodyAdditionalContent extends React.Component {
constructor(props) {
super(props);
this.getSlackAttachment = this.getSlackAttachment.bind(this);
- this.getOembedAttachment = this.getOembedAttachment.bind(this);
- this.getComponent = this.getComponent.bind(this);
+ this.getOEmbedProvider = this.getOEmbedProvider.bind(this);
}
- componentWillMount() {
- this.setState({type: this.props.post.type, shouldRender: Boolean(this.props.post.type)});
+ shouldComponentUpdate(nextProps) {
+ if (!Utils.areObjectsEqual(nextProps.post, this.props.post)) {
+ return true;
+ }
+
+ return false;
}
getSlackAttachment() {
- const attachments = this.props.post.props && this.props.post.props.attachments || [];
+ let attachments = [];
+ if (this.props.post.props && this.props.post.props.attachments) {
+ attachments = this.props.post.props.attachments;
+ }
+
return (
<PostAttachmentList
- key={'post_body_additional_content' + this.props.post.id}
attachments={attachments}
/>
);
}
- getOembedAttachment() {
- const link = this.props.post.props && this.props.post.props.oEmbedLink || '';
- return (
- <PostAttachmentOEmbed
- key={'post_body_additional_content' + this.props.post.id}
- provider={this.props.provider}
- link={link}
- />
- );
+ getOEmbedProvider(link) {
+ for (let i = 0; i < OEmbedProviders.length; i++) {
+ for (let j = 0; j < OEmbedProviders[i].patterns.length; j++) {
+ if (link.match(OEmbedProviders[i].patterns[j])) {
+ return OEmbedProviders[i];
+ }
+ }
+ }
+
+ return null;
}
- getComponent() {
- switch (this.props.post.type) {
- case 'slack_attachment':
+ render() {
+ if (this.props.post.type === 'slack_attachment') {
return this.getSlackAttachment();
- case 'oEmbed':
- return this.getOembedAttachment();
- default:
- return '';
}
- }
- render() {
- let content = [];
+ const link = Utils.extractLinks(this.props.post.message)[0];
+ if (!link) {
+ return null;
+ }
- if (this.props.post.type) {
- const component = this.getComponent();
+ if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMBED_PREVIEW)) {
+ const provider = this.getOEmbedProvider(link);
- if (component) {
- content = component;
+ if (provider) {
+ return (
+ <PostAttachmentOEmbed
+ provider={provider}
+ link={link}
+ />
+ );
}
}
- return (
- <div>
- {content}
- </div>
- );
+ if (YoutubeVideo.isYoutubeLink(link)) {
+ return (
+ <YoutubeVideo
+ channelId={this.props.post.channel_id}
+ link={link}
+ />
+ );
+ }
+
+ for (let i = 0; i < Constants.IMAGE_TYPES.length; i++) {
+ const imageType = Constants.IMAGE_TYPES[i];
+ const suffix = link.substring(link.length - (imageType.length + 1));
+ if (suffix === '.' + imageType || suffix === '=' + imageType) {
+ return (
+ <PostImage
+ channelId={this.props.post.channel_id}
+ link={link}
+ />
+ );
+ }
+ }
+
+ return null;
}
}
PostBodyAdditionalContent.propTypes = {
- post: React.PropTypes.object.isRequired,
- provider: React.PropTypes.object
+ post: React.PropTypes.object.isRequired
};
diff --git a/web/react/components/post_image.jsx b/web/react/components/post_image.jsx
new file mode 100644
index 000000000..da4a25794
--- /dev/null
+++ b/web/react/components/post_image.jsx
@@ -0,0 +1,81 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+export default class PostImageEmbed extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleLoadComplete = this.handleLoadComplete.bind(this);
+ this.handleLoadError = this.handleLoadError.bind(this);
+
+ this.state = {
+ loaded: false,
+ errored: false
+ };
+ }
+
+ componentWillMount() {
+ this.loadImg(this.props.link);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.link !== this.props.link) {
+ this.setState({
+ loaded: false,
+ errored: false
+ });
+ }
+ }
+
+ componentDidUpdate(prevProps) {
+ if (!this.state.loaded && prevProps.link !== this.props.link) {
+ this.loadImg(this.props.link);
+ }
+ }
+
+ loadImg(src) {
+ const img = new Image();
+ img.onload = this.handleLoadComplete;
+ img.onerror = this.handleLoadError;
+ img.src = src;
+ }
+
+ handleLoadComplete() {
+ this.setState({
+ loaded: true
+ });
+ }
+
+ handleLoadError() {
+ this.setState({
+ errored: true,
+ loaded: true
+ });
+ }
+
+ render() {
+ if (this.state.errored) {
+ return null;
+ }
+
+ if (!this.state.loaded) {
+ return (
+ <img
+ className='img-div placeholder'
+ height='500px'
+ />
+ );
+ }
+
+ return (
+ <img
+ className='img-div'
+ src={this.props.link}
+ />
+ );
+ }
+}
+
+PostImageEmbed.propTypes = {
+ link: React.PropTypes.string.isRequired
+};
diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx
index 3a84b51f0..1ea7711ea 100644
--- a/web/react/components/posts_view.jsx
+++ b/web/react/components/posts_view.jsx
@@ -145,7 +145,7 @@ export default class PostsView extends React.Component {
const postCtls = [];
let previousPostDay = new Date(0);
const userId = UserStore.getCurrentId();
- const profiles = this.props.profiles;
+ const profiles = this.props.profiles || {};
let renderedLastViewed = false;
diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx
index 975a39171..d007dd47f 100644
--- a/web/react/components/rhs_thread.jsx
+++ b/web/react/components/rhs_thread.jsx
@@ -109,6 +109,7 @@ export default class RhsThread extends React.Component {
render() {
const posts = this.state.posts;
const selected = this.state.selected;
+ const profiles = this.state.profiles || {};
if (posts == null || selected == null) {
return (
@@ -162,7 +163,7 @@ export default class RhsThread extends React.Component {
if (UserStore.getCurrentId() === selected.user_id) {
profile = UserStore.getCurrentUser();
} else {
- profile = this.state.profiles[selected.user_id];
+ profile = profiles[selected.user_id];
}
return (
@@ -187,7 +188,7 @@ export default class RhsThread extends React.Component {
if (UserStore.getCurrentId() === selected.user_id) {
p = UserStore.getCurrentUser();
} else {
- p = this.state.profiles[selected.user_id];
+ p = profiles[selected.user_id];
}
return (
<Comment
diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx
index d10c5be27..55ece2c97 100644
--- a/web/react/components/search_results.jsx
+++ b/web/react/components/search_results.jsx
@@ -40,12 +40,14 @@ export default class SearchResults extends React.Component {
this.mounted = false;
this.onChange = this.onChange.bind(this);
+ this.onUserChange = this.onUserChange.bind(this);
this.resize = this.resize.bind(this);
this.handleResize = this.handleResize.bind(this);
const state = getStateFromStores();
state.windowWidth = Utils.windowWidth();
state.windowHeight = Utils.windowHeight();
+ state.profiles = JSON.parse(JSON.stringify(UserStore.getProfiles()));
this.state = state;
}
@@ -53,6 +55,7 @@ export default class SearchResults extends React.Component {
this.mounted = true;
SearchStore.addSearchChangeListener(this.onChange);
ChannelStore.addChangeListener(this.onChange);
+ UserStore.addChangeListener(this.onUserChange);
this.resize();
window.addEventListener('resize', this.handleResize);
}
@@ -68,6 +71,7 @@ export default class SearchResults extends React.Component {
componentWillUnmount() {
SearchStore.removeSearchChangeListener(this.onChange);
ChannelStore.removeChangeListener(this.onChange);
+ UserStore.removeChangeListener(this.onUserChange);
this.mounted = false;
window.removeEventListener('resize', this.handleResize);
}
@@ -85,6 +89,10 @@ export default class SearchResults extends React.Component {
}
}
+ onUserChange() {
+ this.setState({profiles: JSON.parse(JSON.stringify(UserStore.getProfiles()))});
+ }
+
resize() {
$('#search-items-container').scrollTop(0);
if (this.state.windowWidth > 768) {
@@ -101,6 +109,7 @@ export default class SearchResults extends React.Component {
}
var noResults = (!results || !results.order || !results.order.length);
var searchTerm = SearchStore.getSearchTerm();
+ const profiles = this.state.profiles || {};
var ctls = null;
@@ -140,6 +149,7 @@ export default class SearchResults extends React.Component {
key={post.id}
channel={this.state.channels.get(post.channel_id)}
post={post}
+ user={profiles[post.user_id]}
term={searchTerm}
isMentionSearch={this.props.isMentionSearch}
/>
diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx
index 3363c97f7..05292b7b3 100644
--- a/web/react/components/search_results_item.jsx
+++ b/web/react/components/search_results_item.jsx
@@ -36,9 +36,10 @@ export default class SearchResultsItem extends React.Component {
}
render() {
- var channelName = null;
+ let channelName = null;
const channel = this.props.channel;
- var timestamp = UserStore.getCurrentUser().update_at;
+ const timestamp = UserStore.getCurrentUser().update_at;
+ const user = this.props.user || {};
if (channel) {
channelName = channel.display_name;
@@ -84,7 +85,7 @@ export default class SearchResultsItem extends React.Component {
</div>
<div>
<ul className='post__header'>
- <li className='col__name'><strong><UserProfile userId={this.props.post.user_id}/></strong></li>
+ <li className='col__name'><strong><UserProfile user={user}/></strong></li>
<li className='col'>
<time className='search-item-time'>
<FormattedDate
@@ -135,6 +136,7 @@ export default class SearchResultsItem extends React.Component {
SearchResultsItem.propTypes = {
post: React.PropTypes.object,
+ user: React.PropTypes.object,
channel: React.PropTypes.object,
isMentionSearch: React.PropTypes.bool,
term: React.PropTypes.string