summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--webapp/components/youtube_video.jsx62
-rw-r--r--webapp/i18n/en.json3
-rw-r--r--webapp/i18n/es.json3
-rw-r--r--webapp/sass/components/_videos.scss20
-rw-r--r--webapp/utils/utils.jsx2
-rw-r--r--webapp/utils/web_client.jsx13
6 files changed, 87 insertions, 16 deletions
diff --git a/webapp/components/youtube_video.jsx b/webapp/components/youtube_video.jsx
index f96504e88..04a10bc31 100644
--- a/webapp/components/youtube_video.jsx
+++ b/webapp/components/youtube_video.jsx
@@ -1,13 +1,13 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import $ from 'jquery';
import ChannelStore from 'stores/channel_store.jsx';
+import WebClient from 'utils/web_client.jsx';
+import * as Utils from 'utils/utils.jsx';
const ytRegex = /(?:http|https):\/\/(?:www\.)?(?:(?:youtube\.com\/(?:(?:v\/)|(\/u\/\w\/)|(?:(?:watch|embed\/watch)(?:\/|.*v=))|(?:embed\/)|(?:user\/[^\/]+\/u\/[0-9]\/)))|(?:youtu\.be\/))([^#&\?]*)/;
import React from 'react';
-import {Link} from 'react-router';
export default class YoutubeVideo extends React.Component {
constructor(props) {
@@ -15,12 +15,15 @@ export default class YoutubeVideo extends React.Component {
this.updateStateFromProps = this.updateStateFromProps.bind(this);
this.handleReceivedMetadata = this.handleReceivedMetadata.bind(this);
+ this.handleMetadataError = this.handleMetadataError.bind(this);
this.play = this.play.bind(this);
this.stop = this.stop.bind(this);
this.stopOnChannelChange = this.stopOnChannelChange.bind(this);
this.state = {
+ loaded: false,
+ failed: global.window.mm_config.GoogleDeveloperKey === '',
playing: false,
title: ''
};
@@ -78,23 +81,33 @@ export default class YoutubeVideo extends React.Component {
}
componentDidMount() {
- if (global.window.mm_config.GoogleDeveloperKey) {
- $.ajax({
- async: true,
- url: 'https://www.googleapis.com/youtube/v3/videos',
- type: 'GET',
- data: {part: 'snippet', id: this.state.videoId, key: global.window.mm_config.GoogleDeveloperKey},
- success: this.handleReceivedMetadata
- });
+ const key = global.window.mm_config.GoogleDeveloperKey;
+ if (key) {
+ WebClient.getYoutubeVideoInfo(key, this.state.videoId,
+ this.handleReceivedMetadata, this.handleMetadataError);
}
}
+ handleMetadataError() {
+ this.setState({
+ failed: true,
+ loaded: true,
+ title: Utils.localizeMessage('youtube_video.notFound', 'Video not found')
+ });
+ }
+
handleReceivedMetadata(data) {
- if (!data.items.length || !data.items[0].snippet) {
+ if (!data || !data.items || !data.items.length || !data.items[0].snippet) {
+ this.setState({
+ failed: true,
+ loaded: true,
+ title: Utils.localizeMessage('youtube_video.notFound', 'Video not found')
+ });
return null;
}
var metadata = data.items[0].snippet;
this.setState({
+ loaded: true,
receivedYoutubeData: true,
title: metadata.title
});
@@ -120,13 +133,28 @@ export default class YoutubeVideo extends React.Component {
}
render() {
+ if (!this.state.loaded) {
+ return <div className='video-loading'/>;
+ }
+
let header = 'Youtube';
if (this.state.title) {
header = header + ' - ';
}
let content;
- if (this.state.playing) {
+ if (this.state.failed) {
+ content = (
+ <div>
+ <div className='video-thumbnail__container'>
+ <div className='video-thumbnail__error'>
+ <div><i className='fa fa-warning fa-2x'/></div>
+ <div>{Utils.localizeMessage('youtube_video.notFound', 'Video not found')}</div>
+ </div>
+ </div>
+ </div>
+ );
+ } else if (this.state.playing) {
content = (
<iframe
src={'https://www.youtube.com/embed/' + this.state.videoId + '?autoplay=1&autohide=1&border=0&wmode=opaque&fs=1&enablejsapi=1' + this.state.time}
@@ -157,7 +185,15 @@ export default class YoutubeVideo extends React.Component {
<div>
<h4>
<span className='video-type'>{header}</span>
- <span className='video-title'><Link to={this.props.link}>{this.state.title}</Link></span>
+ <span className='video-title'>
+ <a
+ href={this.props.link}
+ target='blank'
+ rel='noopener noreferrer'
+ >
+ {this.state.title}
+ </a>
+ </span>
</h4>
<div
className='video-div embed-responsive-item'
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index de5a72107..bff8ab8aa 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -1455,5 +1455,6 @@
"web.footer.privacy": "Privacy",
"web.footer.terms": "Terms",
"web.header.back": "Back",
- "web.root.singup_info": "All team communication in one place, searchable and accessible anywhere"
+ "web.root.singup_info": "All team communication in one place, searchable and accessible anywhere",
+ "youtube_video.notFound": "Video not found"
}
diff --git a/webapp/i18n/es.json b/webapp/i18n/es.json
index ac6e6be94..b6c45cbfa 100644
--- a/webapp/i18n/es.json
+++ b/webapp/i18n/es.json
@@ -1454,5 +1454,6 @@
"web.footer.privacy": "Privacidad",
"web.footer.terms": "Términos",
"web.header.back": "Atrás",
- "web.root.singup_info": "Todas las comunicaciones del equipo en un sólo lugar, con búsquedas y accesible desde cualquier parte"
+ "web.root.singup_info": "Todas las comunicaciones del equipo en un sólo lugar, con búsquedas y accesible desde cualquier parte",
+ "youtube_video.notFound": "Video no encontrado"
}
diff --git a/webapp/sass/components/_videos.scss b/webapp/sass/components/_videos.scss
index e009e6538..b2230f71d 100644
--- a/webapp/sass/components/_videos.scss
+++ b/webapp/sass/components/_videos.scss
@@ -10,6 +10,22 @@
max-width: 100%;
}
+ .video-thumbnail__error {
+ height: 100%;
+ line-height: 2;
+ padding: 110px 0;
+ text-align: center;
+ width: 100%;
+
+ .fa {
+ @include opacity(.5);
+ }
+
+ div {
+ font-size: 1.2em;
+ }
+ }
+
.block {
background-color: alpha-color($black, .5);
border-radius: 10px;
@@ -67,3 +83,7 @@
height: 500px;
}
}
+
+.video-loading {
+ height: 360px;
+} \ No newline at end of file
diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx
index 596b1ae06..e2ca06837 100644
--- a/webapp/utils/utils.jsx
+++ b/webapp/utils/utils.jsx
@@ -682,7 +682,7 @@ export function applyTheme(theme) {
changeCss('.app__body .post-list__arrows', 'fill:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
changeCss('.app__body .sidebar--left, .app__body .sidebar--right .sidebar--right__header, .app__body .suggestion-list__content .command', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
changeCss('.app__body .app__content, .app__body .post-create__container .post-create-body .btn-file, .app__body .post-create__container .post-create-footer .msg-typing, .app__body .suggestion-list__content .command, .app__body .modal .modal-content, .app__body .dropdown-menu, .app__body .popover, .app__body .mentions__name, .app__body .tip-overlay', 'color:' + theme.centerChannelColor, 1);
- changeCss('.app__body #archive-link-home', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
+ changeCss('.app__body #archive-link-home, .video-div .video-thumbnail__error', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
changeCss('.app__body #post-create', 'color:' + theme.centerChannelColor, 2);
changeCss('.app__body .mentions--top, .app__body .suggestion-list', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 3);
changeCss('.app__body .mentions--top, .app__body .suggestion-list', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 2);
diff --git a/webapp/utils/web_client.jsx b/webapp/utils/web_client.jsx
index 04fba0c5b..f6e2d6ac5 100644
--- a/webapp/utils/web_client.jsx
+++ b/webapp/utils/web_client.jsx
@@ -6,6 +6,8 @@ import TeamStore from '../stores/team_store.jsx';
import BrowserStore from '../stores/browser_store.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
+import request from 'superagent';
+
const HTTP_UNAUTHORIZED = 401;
class WebClientClass extends Client {
@@ -82,6 +84,17 @@ class WebClientClass extends Client {
}
);
}
+
+ getYoutubeVideoInfo(googleKey, videoId, success, error) {
+ request.get('https://www.googleapis.com/youtube/v3/videos').
+ query({part: 'snippet', id: videoId, key: googleKey}).
+ end((err, res) => {
+ if (err) {
+ return error(err);
+ }
+ return success(res.body);
+ });
+ }
}
var WebClient = new WebClientClass();