diff options
Diffstat (limited to 'webapp')
-rw-r--r-- | webapp/components/youtube_video.jsx | 62 | ||||
-rw-r--r-- | webapp/i18n/en.json | 3 | ||||
-rw-r--r-- | webapp/i18n/es.json | 3 | ||||
-rw-r--r-- | webapp/sass/components/_videos.scss | 20 | ||||
-rw-r--r-- | webapp/utils/utils.jsx | 2 | ||||
-rw-r--r-- | webapp/utils/web_client.jsx | 13 |
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(); |