From c56762a4e9ca25ce3467f2944729bfe9bb890114 Mon Sep 17 00:00:00 2001 From: Florian Orben Date: Sat, 7 Nov 2015 15:44:55 +0100 Subject: PLT-1049: Vine URLs should not generate preview links --- web/react/components/post_attachment_oembed.jsx | 83 ++++++++++++++++++++++ web/react/components/post_body.jsx | 71 +++++++++++++----- .../components/post_body_additional_content.jsx | 20 +++++- 3 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 web/react/components/post_attachment_oembed.jsx (limited to 'web/react/components') diff --git a/web/react/components/post_attachment_oembed.jsx b/web/react/components/post_attachment_oembed.jsx new file mode 100644 index 000000000..f544dbc88 --- /dev/null +++ b/web/react/components/post_attachment_oembed.jsx @@ -0,0 +1,83 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +export default class PostAttachmentOEmbed extends React.Component { + constructor(props) { + super(props); + this.fetchData = this.fetchData.bind(this); + + this.isLoading = false; + } + + componentWillMount() { + this.setState({data: {}}); + } + + componentWillReceiveProps(nextProps) { + this.fetchData(nextProps.link); + } + + fetchData(link) { + if (!this.isLoading) { + this.isLoading = true; + return $.ajax({ + url: 'https://noembed.com/embed?nowrap=on&url=' + encodeURIComponent(link), + dataType: 'jsonp', + success: (result) => { + this.isLoading = false; + if (result.error) { + this.setState({data: {}}); + } else { + this.setState({data: result}); + } + }, + error: () => { + this.setState({data: {}}); + } + }); + } + } + + render() { + if ($.isEmptyObject(this.state.data)) { + return
; + } + + return ( +
+
+
+

+ + {this.state.data.title} + +

+
+
+
+
+
+
+
+
+
+ ); + } +} + +PostAttachmentOEmbed.propTypes = { + link: React.PropTypes.string.isRequired +}; diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 5a157b792..c4f653f68 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -9,6 +9,8 @@ const TextFormatting = require('../utils/text_formatting.jsx'); const twemoji = require('twemoji'); const PostBodyAdditionalContent = require('./post_body_additional_content.jsx'); +const providers = require('../providers.json'); + export default class PostBody extends React.Component { constructor(props) { super(props); @@ -23,7 +25,7 @@ export default class PostBody extends React.Component { this.createYoutubeEmbed = this.createYoutubeEmbed.bind(this); const linkData = Utils.extractLinks(this.props.post.message); - this.state = {links: linkData.links, message: linkData.text}; + this.state = {links: linkData.links, message: linkData.text, post: this.props.post}; } getAllChildNodes(nodeIn) { @@ -45,6 +47,12 @@ export default class PostBody extends React.Component { twemoji.parse(ReactDOM.findDOMNode(this), {size: Constants.EMOJI_SIZE}); } + 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(); } @@ -55,19 +63,54 @@ export default class PostBody extends React.Component { 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.links[0]); + } this.setState({links: linkData.links, message: linkData.text}); } createEmbed(link) { - let embed = this.createYoutubeEmbed(link); + const post = this.state.post; + + if (!link) { + if (post.type === 'oEmbed') { + post.props.oEmbedLink = ''; + post.type = ''; + } + return null; + } + + const trimmedLink = link.trim(); + + if (this.checkForOembedContent(trimmedLink)) { + post.props.oEmbedLink = trimmedLink; + post.type = 'oEmbed'; + this.setState({post}); + return ''; + } + + const embed = this.createYoutubeEmbed(link); if (embed != null) { return embed; } - embed = this.createGifEmbed(link); + if (link.substring(link.length - 4) === '.gif') { + return this.createGifEmbed(link, this.state.gifLoaded); + } + + return null; + } - return embed; + checkForOembedContent(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 true; + } + } + } + return false; } loadGif(src) { @@ -80,18 +123,15 @@ export default class PostBody extends React.Component { const gif = new Image(); gif.onload = ( () => { + this.embed = this.createGifEmbed(src, true); this.setState({gifLoaded: true}); } ); gif.src = src; } - createGifEmbed(link) { - if (link.substring(link.length - 4) !== '.gif') { - return null; - } - - if (!this.state.gifLoaded) { + createGifEmbed(link, isLoaded) { + if (!isLoaded) { this.loadGif(link); return ( 0) { - embed = this.createEmbed(this.state.links[0]); - } - let fileAttachmentHolder = ''; if (filenames && filenames.length > 0) { fileAttachmentHolder = ( @@ -333,10 +368,10 @@ export default class PostBody extends React.Component { /> {fileAttachmentHolder} - {embed} + {this.embed} ); } diff --git a/web/react/components/post_body_additional_content.jsx b/web/react/components/post_body_additional_content.jsx index 8189ba2d3..0c2c44286 100644 --- a/web/react/components/post_body_additional_content.jsx +++ b/web/react/components/post_body_additional_content.jsx @@ -2,12 +2,14 @@ // See License.txt for license information. const PostAttachmentList = require('./post_attachment_list.jsx'); +const PostAttachmentOEmbed = require('./post_attachment_oembed.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); } @@ -25,17 +27,31 @@ export default class PostBodyAdditionalContent extends React.Component { ); } + getOembedAttachment() { + const link = this.props.post.props && this.props.post.props.oEmbedLink || ''; + return ( + + ); + } + getComponent() { - switch (this.state.type) { + switch (this.props.post.type) { case 'slack_attachment': return this.getSlackAttachment(); + case 'oEmbed': + return this.getOembedAttachment(); + default: + return ''; } } render() { let content = []; - if (this.state.shouldRender) { + if (Boolean(this.props.post.type)) { const component = this.getComponent(); if (component) { -- cgit v1.2.3-1-g7c22