diff options
author | Christopher Speller <crspeller@gmail.com> | 2016-02-24 08:35:34 -0500 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2016-02-24 08:35:34 -0500 |
commit | c5dc455a4c930c6521bd355d43b36a079dff8d55 (patch) | |
tree | 5b9768aa64d105c59226594dddd10ece52f71e31 /web | |
parent | 940b706ac8a790db9f089e000489d89426915fc9 (diff) | |
parent | 1dbe949ce8f65f1110e0f43797bd757bfa906ee0 (diff) | |
download | chat-c5dc455a4c930c6521bd355d43b36a079dff8d55.tar.gz chat-c5dc455a4c930c6521bd355d43b36a079dff8d55.tar.bz2 chat-c5dc455a4c930c6521bd355d43b36a079dff8d55.zip |
Merge pull request #2233 from hmhealey/plt2010
PLT-2010/PLT-2071 Refactored Post Embed Components
Diffstat (limited to 'web')
-rw-r--r-- | web/react/components/post_body.jsx | 137 | ||||
-rw-r--r-- | web/react/components/post_body_additional_content.jsx | 103 | ||||
-rw-r--r-- | web/react/components/post_image.jsx | 81 |
3 files changed, 154 insertions, 167 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 +}; |