summaryrefslogtreecommitdiffstats
path: root/web/react/components/post_body.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components/post_body.jsx')
-rw-r--r--web/react/components/post_body.jsx186
1 files changed, 122 insertions, 64 deletions
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index 61a0c3e2d..dcbe56399 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -1,26 +1,30 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-const FileAttachmentList = require('./file_attachment_list.jsx');
-const UserStore = require('../stores/user_store.jsx');
-const Utils = require('../utils/utils.jsx');
-const Constants = require('../utils/constants.jsx');
-const TextFormatting = require('../utils/text_formatting.jsx');
-const twemoji = require('twemoji');
-const PostBodyAdditionalContent = require('./post_body_additional_content.jsx');
+import FileAttachmentList from './file_attachment_list.jsx';
+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 providers from './providers.json';
export default class PostBody extends React.Component {
constructor(props) {
super(props);
this.receivedYoutubeData = false;
- this.isGifLoading = false;
+ this.isImgLoading = false;
this.handleUserChange = this.handleUserChange.bind(this);
this.parseEmojis = this.parseEmojis.bind(this);
this.createEmbed = this.createEmbed.bind(this);
- this.createGifEmbed = this.createGifEmbed.bind(this);
- this.loadGif = this.loadGif.bind(this);
+ this.createImageEmbed = this.createImageEmbed.bind(this);
+ this.loadImg = this.loadImg.bind(this);
this.createYoutubeEmbed = this.createYoutubeEmbed.bind(this);
const linkData = Utils.extractLinks(this.props.post.message);
@@ -29,6 +33,7 @@ export default class PostBody extends React.Component {
this.state = {
links: linkData.links,
message: linkData.text,
+ post: this.props.post,
hasUserProfiles: profiles && Object.keys(profiles).length > 1
};
}
@@ -49,7 +54,17 @@ export default class PostBody extends React.Component {
}
parseEmojis() {
- twemoji.parse(ReactDOM.findDOMNode(this), {size: Constants.EMOJI_SIZE});
+ twemoji.parse(ReactDOM.findDOMNode(this), {
+ className: 'emoji twemoji',
+ base: '',
+ folder: Emoji.getImagePathForEmoticon()
+ });
+ }
+
+ 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() {
@@ -76,47 +91,86 @@ 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 (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 '';
+ }
+ }
+
+ const embed = this.createYoutubeEmbed(link);
if (embed != null) {
return embed;
}
- embed = this.createGifEmbed(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;
+ }
- return embed;
+ 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;
}
- loadGif(src) {
- if (this.isGifLoading) {
+ loadImg(src) {
+ if (this.isImgLoading) {
return;
}
- this.isGifLoading = true;
+ this.isImgLoading = true;
- const gif = new Image();
- gif.onload = (
+ const img = new Image();
+ img.onload = (
() => {
- this.setState({gifLoaded: true});
+ this.embed = this.createImageEmbed(src, true);
+ this.setState({imgLoaded: true});
}
);
- gif.src = src;
+ img.src = src;
}
- createGifEmbed(link) {
- if (link.substring(link.length - 4) !== '.gif') {
- return null;
- }
-
- if (!this.state.gifLoaded) {
- this.loadGif(link);
+ createImageEmbed(link, isLoaded) {
+ if (!isLoaded) {
+ this.loadImg(link);
return (
<img
- className='gif-div placeholder'
+ className='img-div placeholder'
height='500px'
/>
);
@@ -124,7 +178,7 @@ export default class PostBody extends React.Component {
return (
<img
- className='gif-div'
+ className='img-div'
src={link}
/>
);
@@ -133,7 +187,7 @@ export default class PostBody extends React.Component {
handleYoutubeTime(link) {
const timeRegex = /[\\?&]t=([0-9hms]+)/;
- const time = link.trim().match(timeRegex);
+ const time = link.match(timeRegex);
if (!time || !time[1]) {
return '';
}
@@ -160,14 +214,14 @@ export default class PostBody extends React.Component {
}
createYoutubeEmbed(link) {
- const ytRegex = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|watch\?(?:[a-zA-Z-_]+=[a-zA-Z0-9-_]+&)+v=)([^#\&\?]*).*/;
+ const ytRegex = /(?:http|https):\/\/(?:www\.)?(?:(?:youtube\.com\/(?:(?:v\/)|(\/u\/\w\/)|(?:(?:watch|embed\/watch)(?:\/|.*v=))|(?:embed\/)|(?:user\/[^\/]+\/u\/[0-9]\/)))|(?:youtu\.be\/))([^#\&\?]*)/;
const match = link.trim().match(ytRegex);
- if (!match || match[1].length !== 11) {
+ if (!match || match[2].length !== 11) {
return null;
}
- const youtubeId = match[1];
+ const youtubeId = match[2];
const time = this.handleYoutubeTime(link);
function onClick(e) {
@@ -212,7 +266,7 @@ export default class PostBody extends React.Component {
}
return (
- <div className='post-comment'>
+ <div>
<h4>
<span className='video-type'>{header}</span>
<span className='video-title'><a href={link}>{this.state.youtubeTitle}</a></span>
@@ -255,7 +309,15 @@ export default class PostBody extends React.Component {
let apostrophe = '';
let name = '...';
if (profile != null) {
- if (profile.username.slice(-1) === 's') {
+ let username = profile.username;
+ if (parentPost.props &&
+ parentPost.props.from_webhook &&
+ parentPost.props.override_username &&
+ global.window.mm_config.EnablePostUsernameOverride === 'true') {
+ username = parentPost.props.override_username;
+ }
+
+ if (username.slice(-1) === 's') {
apostrophe = '\'';
} else {
apostrophe = '\'s';
@@ -263,9 +325,9 @@ export default class PostBody extends React.Component {
name = (
<a
className='theme'
- onClick={Utils.searchForTerm.bind(null, profile.username)}
+ onClick={Utils.searchForTerm.bind(null, username)}
>
- {profile.username}
+ {username}
</a>
);
}
@@ -284,7 +346,7 @@ export default class PostBody extends React.Component {
}
comment = (
- <p className='post-link'>
+ <div className='post__link'>
<span>
{'Commented on '}{name}{apostrophe}{' message: '}
<a
@@ -294,15 +356,13 @@ export default class PostBody extends React.Component {
{message}
</a>
</span>
- </p>
+ </div>
);
-
- postClass += ' post-comment';
}
let loading;
if (post.state === Constants.POST_FAILED) {
- postClass += ' post-fail';
+ postClass += ' post--fail';
loading = (
<a
className='theme post-retry pull-right'
@@ -322,11 +382,6 @@ export default class PostBody extends React.Component {
);
}
- let embed;
- if (filenames.length === 0 && this.state.links && this.state.links.length > 0) {
- embed = this.createEmbed(this.state.links[0]);
- }
-
let fileAttachmentHolder = '';
if (filenames && filenames.length > 0) {
fileAttachmentHolder = (
@@ -339,25 +394,28 @@ export default class PostBody extends React.Component {
}
return (
- <div className='post-body'>
+ <div>
{comment}
- <div
- key={`${post.id}_message`}
- id={`${post.id}_message`}
- className={postClass}
- >
- {loading}
- <span
- ref='message_span'
- onClick={TextFormatting.handleClick}
- dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}}
+ <div className='post__body'>
+ <div
+ key={`${post.id}_message`}
+ id={`${post.id}_message`}
+ className={postClass}
+ >
+ {loading}
+ <span
+ ref='message_span'
+ onClick={TextFormatting.handleClick}
+ dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}}
+ />
+ </div>
+ <PostBodyAdditionalContent
+ post={this.state.post}
+ provider={this.state.provider}
/>
+ {fileAttachmentHolder}
+ {this.embed}
</div>
- <PostBodyAdditionalContent
- post={post}
- />
- {fileAttachmentHolder}
- {embed}
</div>
);
}