From ab67f6e257f6e8f08145a02a7b93550f99641be4 Mon Sep 17 00:00:00 2001
From: Joram Wilander <jwawilander@gmail.com>
Date: Sun, 18 Jun 2017 14:42:32 -0400
Subject: PLT-6215 Major post list refactor (#6501)

* Major post list refactor

* Fix post and thread deletion

* Fix preferences not selecting correctly

* Fix military time displaying

* Fix UP key for editing posts

* Fix ESLint error

* Various fixes and updates per feedback

* Fix for permalink view

* Revert to old scrolling method and various fixes

* Add floating timestamp, new message indicator, scroll arrows

* Update post loading for focus mode and add visibility limit

* Fix pinning posts and a react warning

* Add loading UI updates from Asaad

* Fix refreshing loop

* Temporarily bump post visibility limit

* Update infinite scrolling

* Remove infinite scrolling
---
 webapp/components/youtube_video/youtube_video.jsx | 243 ++++++++++++++++++++++
 1 file changed, 243 insertions(+)
 create mode 100644 webapp/components/youtube_video/youtube_video.jsx

(limited to 'webapp/components/youtube_video/youtube_video.jsx')

diff --git a/webapp/components/youtube_video/youtube_video.jsx b/webapp/components/youtube_video/youtube_video.jsx
new file mode 100644
index 000000000..5151e6576
--- /dev/null
+++ b/webapp/components/youtube_video/youtube_video.jsx
@@ -0,0 +1,243 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import WebClient from 'client/web_client.jsx';
+import * as Utils from 'utils/utils.jsx';
+
+const ytRegex = /(?:http|https):\/\/(?:www\.|m\.)?(?:(?:youtube\.com\/(?:(?:v\/)|(?:(?:watch|embed\/watch)(?:\/|.*v=))|(?:embed\/)|(?:user\/[^/]+\/u\/[0-9]\/)))|(?:youtu\.be\/))([^#&?]*)/;
+
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class YoutubeVideo extends React.PureComponent {
+    static propTypes = {
+        channelId: PropTypes.string.isRequired,
+        currentChannelId: PropTypes.string.isRequired,
+        link: PropTypes.string.isRequired,
+        show: PropTypes.bool.isRequired
+    }
+
+    constructor(props) {
+        super(props);
+
+        this.updateStateFromProps = this.updateStateFromProps.bind(this);
+        this.handleReceivedMetadata = this.handleReceivedMetadata.bind(this);
+        this.handleMetadataError = this.handleMetadataError.bind(this);
+        this.loadWithoutKey = this.loadWithoutKey.bind(this);
+
+        this.play = this.play.bind(this);
+        this.stop = this.stop.bind(this);
+
+        this.state = {
+            loaded: false,
+            failed: false,
+            playing: false,
+            title: ''
+        };
+    }
+
+    componentWillMount() {
+        this.updateStateFromProps(this.props);
+    }
+
+    componentWillReceiveProps(nextProps) {
+        this.updateStateFromProps(nextProps);
+    }
+
+    updateStateFromProps(props) {
+        const link = props.link;
+
+        const match = link.trim().match(ytRegex);
+        if (!match || match[1].length !== 11) {
+            return;
+        }
+
+        if (props.show === false) {
+            this.stop();
+        }
+
+        if (props.channelId !== props.currentChannelId) {
+            this.stop();
+        }
+
+        this.setState({
+            videoId: match[1],
+            time: this.handleYoutubeTime(link)
+        });
+    }
+
+    handleYoutubeTime(link) {
+        const timeRegex = /[\\?&]t=([0-9]+h)?([0-9]+m)?([0-9]+s?)/;
+
+        const time = link.match(timeRegex);
+        if (!time || !time[0]) {
+            return '';
+        }
+
+        const hours = time[1] ? time[1].match(/([0-9]+)h/) : null;
+        const minutes = time[2] ? time[2].match(/([0-9]+)m/) : null;
+        const seconds = time[3] ? time[3].match(/([0-9]+)s?/) : null;
+
+        let ticks = 0;
+
+        if (hours && hours[1]) {
+            ticks += parseInt(hours[1], 10) * 3600;
+        }
+
+        if (minutes && minutes[1]) {
+            ticks += parseInt(minutes[1], 10) * 60;
+        }
+
+        if (seconds && seconds[1]) {
+            ticks += parseInt(seconds[1], 10);
+        }
+
+        return '&start=' + ticks.toString();
+    }
+
+    componentDidMount() {
+        const key = global.window.mm_config.GoogleDeveloperKey;
+        if (key) {
+            WebClient.getYoutubeVideoInfo(key, this.state.videoId,
+                this.handleReceivedMetadata, this.handleMetadataError);
+        } else {
+            this.loadWithoutKey();
+        }
+    }
+
+    loadWithoutKey() {
+        this.setState({
+            loaded: true,
+            thumb: 'https://i.ytimg.com/vi/' + this.state.videoId + '/hqdefault.jpg'
+        });
+    }
+
+    handleMetadataError() {
+        this.setState({
+            failed: true,
+            loaded: true,
+            title: Utils.localizeMessage('youtube_video.notFound', 'Video not found')
+        });
+    }
+
+    handleReceivedMetadata(data) {
+        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;
+        }
+        const metadata = data.items[0].snippet;
+        let thumb = 'https://i.ytimg.com/vi/' + this.state.videoId + '/hqdefault.jpg';
+        if (metadata.liveBroadcastContent === 'live') {
+            thumb = 'https://i.ytimg.com/vi/' + this.state.videoId + '/hqdefault_live.jpg';
+        }
+
+        this.setState({
+            loaded: true,
+            receivedYoutubeData: true,
+            title: metadata.title,
+            thumb
+        });
+        return null;
+    }
+
+    play() {
+        this.setState({playing: true});
+    }
+
+    stop() {
+        this.setState({playing: false});
+    }
+
+    render() {
+        if (!this.state.loaded) {
+            return (
+                <div
+                    className='post__embed-container'
+                >
+                    <div className='video-loading'/>
+                </div>
+            );
+        }
+
+        let header;
+        if (this.state.title) {
+            header = (
+                <h4>
+                    <span className='video-type'>{'Youtube - '}</span>
+                    <span className='video-title'>
+                        <a
+                            href={this.props.link}
+                            target='blank'
+                            rel='noopener noreferrer'
+                        >
+                            {this.state.title}
+                        </a>
+                    </span>
+                </h4>
+            );
+        }
+
+        let content;
+        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}
+                    width='480px'
+                    height='360px'
+                    type='text/html'
+                    frameBorder='0'
+                    allowFullScreen='allowfullscreen'
+                />
+            );
+        } else {
+            content = (
+                <div className='embed-responsive embed-responsive-4by3 video-div__placeholder'>
+                    <div className='video-thumbnail__container'>
+                        <img
+                            className='video-thumbnail'
+                            src={this.state.thumb}
+                        />
+                        <div className='block'>
+                            <span className='play-button'><span/></span>
+                        </div>
+                    </div>
+                </div>
+            );
+        }
+
+        return (
+            <div
+                className='post__embed-container'
+            >
+                <div>
+                    {header}
+                    <div
+                        className='video-div embed-responsive-item'
+                        onClick={this.play}
+                    >
+                        {content}
+                    </div>
+                </div>
+            </div>
+        );
+    }
+
+    static isYoutubeLink(link) {
+        return link.trim().match(ytRegex);
+    }
+}
-- 
cgit v1.2.3-1-g7c22

