From 98bd031db9c6f6ce1eb9688b19e898c67baca724 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 15 Jul 2019 18:17:45 -0400
Subject: better but not working.

---
 src/client/views/nodes/VideoBox.tsx | 104 ++++++++++++++++++++----------------
 1 file changed, 58 insertions(+), 46 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 66844cdd6..552d3f188 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,5 +1,5 @@
 import React = require("react");
-import { action, IReactionDisposer, observable, reaction, trace, computed } from "mobx";
+import { action, IReactionDisposer, observable, reaction, trace, computed, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { makeInterface } from "../../../new_fields/Schema";
 import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
@@ -44,29 +44,25 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         }
     }
 
-    @action public Play = () => {
+    @action public Play = (update: boolean = true) => {
         this.Playing = true;
-        this.player && this.player.play();
-        this._youtubePlayer && this._youtubePlayer.playVideo();
+        update && this.player && this.player.play();
+        update && this._youtubePlayer && this._youtubePlayer.playVideo();
         !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 500));
-        this._youtubeSeekTo = false;
         this.updateTimecode();
     }
 
     @action public Seek(time: number) {
-        if (this._youtubePlayer && !this.Playing) {
-            this._youtubeSeekTo = true;
-            this._youtubePlayer.seekTo(time);
-        }
+        this._youtubePlayer && !this.Playing && this._youtubePlayer.seekTo(time);
     }
 
-    @action public Pause = () => {
+    @action public Pause = (update: boolean = true) => {
         this.Playing = false;
-        this.player && this.player.pause();
-        this._youtubePlayer && this._youtubePlayer.pauseVideo();
+        update && this.player && this.player.pause();
+        update && this._youtubePlayer && this._youtubePlayer.pauseVideo();
         this._playTimer && clearInterval(this._playTimer);
         this._playTimer = undefined;
-        this._youtubeSeekTo = false;
+        this.updateTimecode();
     }
 
     @action public FullScreen() {
@@ -77,15 +73,19 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
 
     @action
     updateTimecode = () => {
+        let ctime = this._youtubePlayer.getCurrentTime();
+        let otime = this.lastyoutube ? (this.lastyoutube as any).getCurrentTime() : -1;
+        console.log("Setting " + ctime + " " + otime);
         this.player && (this.props.Document.curPage = this.player.currentTime);
         this._youtubePlayer && (this.props.Document.curPage = this._youtubePlayer.getCurrentTime());
     }
+    static _staticCounter: number = 0;
+    counter: number = -1;
+    _startupTime: number = -1;
     componentDidMount() {
         if (this.props.setVideoBox) this.props.setVideoBox(this);
 
-        let field = Cast(this.Document[this.props.fieldKey], VideoField);
-        let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
-        if (videoid) {
+        if (this.youtubeVideoId) {
             let youtubeaspect = 400 / 315;
             var nativeWidth = FieldValue(this.Document.nativeWidth, 0);
             var nativeHeight = FieldValue(this.Document.nativeHeight, 0);
@@ -94,47 +94,28 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                 this.Document.nativeHeight = this.Document.nativeWidth / youtubeaspect;
                 this.Document.height = FieldValue(this.Document.width, 0) / youtubeaspect;
             }
-            this._youtubePlayer = new YT.Player(`${videoid}-player`, {
-                height: `${NumCast(this.props.Document.height)}`,
-                width: `${NumCast(this.props.Document.width)}`,
-                videoId: videoid.toString(),
-                playerVars: { 'controls': VideoBox._showControls ? 1 : 0 },
-                events: {
-                    'onStateChange': this.onYoutubePlayerStateChange,
-                    'onReady': this.onYoutubePlayerReady,
-                }
-            });
             this._reactionDisposer = reaction(() => this.props.Document.curPage, () => this.Seek(this.Document.curPage || 0), { fireImmediately: true });
             this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => {
                 let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting;
                 this._youtubePlayer.getIframe().style.pointerEvents = interactive ? "all" : "none";
             }, { fireImmediately: true })
-            // let iframe = $(document.getElementById(`${videoid}-player`)!);
-            // iframe.on("load", function () {
-            //     iframe.contents().find("head")
-            //         .append($("<style type='text/css'>  .ytp-pause-overlay, .ytp-scroll-min { opacity : 0 !important; }  </style>"));
-            // })
         }
     }
 
-    @action
-    onYoutubePlayerStateChange = (event: any) => {
-        console.log("event.data = " + event.data);
-        this.Playing = event.data == YT.PlayerState.PLAYING;
-        if (this._youtubeSeekTo && this.Playing) {
-            this._youtubePlayer.pauseVideo();
-            this._youtubeSeekTo = false;
-        } else this.Playing && !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 500));
-        event.data === YT.PlayerState.PAUSED && this._playTimer && clearInterval(this._playTimer);
-    }
-    _youtubeSeekTo = false;
     @action
     onYoutubePlayerReady = (event: any) => {
-        this.Playing = false;
         this._youtubePlayer && (this._youtubePlayer.getIframe().style.pointerEvents = "none");
         if (this.Document.curPage) {
-            this.Seek(this.Document.curPage);
-            this._youtubeSeekTo = true;
+            this.Playing = false;
+            if (this._startupTime !== -1) {
+                this.Seek(this.Document.curPage);
+            }
+            else {
+                let cpage = this.Document.curPage;
+                this.Pause();
+                this._startupTime = cpage;
+                this._youtubePlayer.seekTo(cpage);
+            }
         }
     }
 
@@ -183,12 +164,43 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
             </video>;
     }
 
+    times = 0;
+    lastyoutube = undefined;
+    @action load = () => {
+        let x = ++this.times;
+        console.log("LOADED " + x + " times = " + this.times);
+        let onYoutubePlayerStateChange = (event: any) => runInAction(() => {
+            console.log("STATE + " + event.data + "  times = " + this.times + " " + x);
+            //if (this.times !== x) return;
+            if (event.data === YT.PlayerState.UNSTARTED || event.data === YT.PlayerState.BUFFERING)
+                return;
+            if (this._startupTime !== -1) {
+                this._startupTime = -1;
+                if (event.data === YT.PlayerState.PLAYING) this.Pause();
+            }
+            if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
+            if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
+        });
+        let cpage = NumCast(this.Document.curPage);
+        this._startupTime = cpage;
+        this.lastyoutube = this._youtubePlayer;
+        this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this.counter}-player`, {
+            events: {
+                'onReady': this.onYoutubePlayerReady,
+                'onStateChange': onYoutubePlayerStateChange
+            }
+        });
+    }
+
     @computed get youtubeContent() {
+        this.counter = VideoBox._staticCounter++;
         let style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : "");
-        return <div id={`${this.youtubeVideoId}-player`} className={`${style}`} />;
+        return <iframe id={`${this.youtubeVideoId + this.counter.toString()}-player`} onLoad={this.load} className={`${style}`} width="640" height="390"
+            src={`http://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1`} />
     }
 
     render() {
+        trace();
         return <div style={{ pointerEvents: "all", width: "100%", height: "100%" }} onContextMenu={this.specificContextMenu}>
             {this.youtubeVideoId ? this.youtubeContent : this.content}
         </div>;
-- 
cgit v1.2.3-70-g09d2


From 005367a60410af854cad60ee59be642bd411c37e Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 16 Jul 2019 00:53:58 -0400
Subject: fixed youtube except for automatic update on scrubbing and hiding of
 related videos.

---
 src/client/views/nodes/VideoBox.tsx | 116 +++++++++++++++++-------------------
 1 file changed, 56 insertions(+), 60 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 552d3f188..864db0bfc 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -24,6 +24,11 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
     private _youtubeReactionDisposer?: IReactionDisposer;
     private _youtubePlayer: any = undefined;
     private _videoRef: HTMLVideoElement | null = null;
+    private _youtubeIframeId: number = -1;
+    private _youtubeContentCreated = false;
+    static _youtubeIframeCounter: number = 0;
+    @observable _forceCreateYouTubeIFrame = false;
+    @observable static _showControls: boolean;
     @observable _playTimer?: NodeJS.Timeout = undefined;
     @observable _fullScreen = false;
     @observable public Playing: boolean = false;
@@ -53,6 +58,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
     }
 
     @action public Seek(time: number) {
+        //if (this._youtubePlayer && this._youtubePlayer.getPlayerState() === 5) return;
         this._youtubePlayer && !this.Playing && this._youtubePlayer.seekTo(time);
     }
 
@@ -73,15 +79,10 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
 
     @action
     updateTimecode = () => {
-        let ctime = this._youtubePlayer.getCurrentTime();
-        let otime = this.lastyoutube ? (this.lastyoutube as any).getCurrentTime() : -1;
-        console.log("Setting " + ctime + " " + otime);
         this.player && (this.props.Document.curPage = this.player.currentTime);
         this._youtubePlayer && (this.props.Document.curPage = this._youtubePlayer.getCurrentTime());
     }
-    static _staticCounter: number = 0;
-    counter: number = -1;
-    _startupTime: number = -1;
+
     componentDidMount() {
         if (this.props.setVideoBox) this.props.setVideoBox(this);
 
@@ -94,28 +95,6 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                 this.Document.nativeHeight = this.Document.nativeWidth / youtubeaspect;
                 this.Document.height = FieldValue(this.Document.width, 0) / youtubeaspect;
             }
-            this._reactionDisposer = reaction(() => this.props.Document.curPage, () => this.Seek(this.Document.curPage || 0), { fireImmediately: true });
-            this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => {
-                let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting;
-                this._youtubePlayer.getIframe().style.pointerEvents = interactive ? "all" : "none";
-            }, { fireImmediately: true })
-        }
-    }
-
-    @action
-    onYoutubePlayerReady = (event: any) => {
-        this._youtubePlayer && (this._youtubePlayer.getIframe().style.pointerEvents = "none");
-        if (this.Document.curPage) {
-            this.Playing = false;
-            if (this._startupTime !== -1) {
-                this.Seek(this.Document.curPage);
-            }
-            else {
-                let cpage = this.Document.curPage;
-                this.Pause();
-                this._startupTime = cpage;
-                this._youtubePlayer.seekTo(cpage);
-            }
         }
     }
 
@@ -137,13 +116,6 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         }
     }
 
-    @observable static _showControls: boolean;
-
-    @computed get youtubeVideoId() {
-        let field = Cast(this.Document[this.props.fieldKey], VideoField);
-        return field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
-    }
-
     specificContextMenu = (e: React.MouseEvent): void => {
         let field = Cast(this.Document[this.props.fieldKey], VideoField);
         if (field) {
@@ -158,49 +130,73 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive";
         let style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive;
         return !field ? <div>Loading</div> :
-            <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} controls={VideoBox._showControls} onPlay={this.Play} onSeeked={this.updateTimecode} onPause={this.Pause}>
+            <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} controls={VideoBox._showControls}
+                onPlay={() => this.Play()} onSeeked={this.updateTimecode} onPause={() => this.Pause()}>
                 <source src={field.url.href} type="video/mp4" />
                 Not supported.
             </video>;
     }
 
-    times = 0;
-    lastyoutube = undefined;
-    @action load = () => {
-        let x = ++this.times;
-        console.log("LOADED " + x + " times = " + this.times);
+    @computed get youtubeVideoId() {
+        let field = Cast(this.Document[this.props.fieldKey], VideoField);
+        return field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
+    }
+
+    @action youtubeIframeLoaded = (e: any) => {
+        if (!this._youtubeContentCreated) {
+            this._forceCreateYouTubeIFrame = !this._forceCreateYouTubeIFrame;
+            return;
+        }
+        else this._youtubeContentCreated = false;
+
+        let iframe = e.target;
+        let startupTimecode = NumCast(this.Document.curPage);
         let onYoutubePlayerStateChange = (event: any) => runInAction(() => {
-            console.log("STATE + " + event.data + "  times = " + this.times + " " + x);
-            //if (this.times !== x) return;
-            if (event.data === YT.PlayerState.UNSTARTED || event.data === YT.PlayerState.BUFFERING)
-                return;
-            if (this._startupTime !== -1) {
-                this._startupTime = -1;
-                if (event.data === YT.PlayerState.PLAYING) this.Pause();
+            if (event.data !== YT.PlayerState.UNSTARTED && event.data !== YT.PlayerState.BUFFERING) {
+                if (startupTimecode !== -1) {
+                    startupTimecode = -1;
+                    if (event.data === YT.PlayerState.PLAYING) this.Pause();
+                }
+                if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
+                if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
             }
-            if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
-            if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
         });
-        let cpage = NumCast(this.Document.curPage);
-        this._startupTime = cpage;
-        this.lastyoutube = this._youtubePlayer;
-        this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this.counter}-player`, {
+        let onYoutubePlayerReady = (event: any) => {
+            this._reactionDisposer && this._reactionDisposer();
+            this._youtubeReactionDisposer && this._youtubeReactionDisposer();
+            this._reactionDisposer = reaction(() => this.props.Document.curPage, () => this.Seek(this.Document.curPage || 0));
+            this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => {
+                let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting;
+                iframe.style.pointerEvents = interactive ? "all" : "none";
+            }, { fireImmediately: true });
+            if (startupTimecode) {
+                this.Playing = false;
+                this.Seek(startupTimecode);
+            }
+        }
+        this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this._youtubeIframeId}-player`, {
+            playerVars: {
+                rel: 0,
+                start: NumCast(this.props.Document.curPage)
+            },
             events: {
-                'onReady': this.onYoutubePlayerReady,
-                'onStateChange': onYoutubePlayerStateChange
+                'onReady': onYoutubePlayerReady,
+                'onStateChange': onYoutubePlayerStateChange,
             }
         });
+
     }
 
     @computed get youtubeContent() {
-        this.counter = VideoBox._staticCounter++;
+        this._youtubeIframeId = VideoBox._youtubeIframeCounter++;
+        this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true;
         let style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : "");
-        return <iframe id={`${this.youtubeVideoId + this.counter.toString()}-player`} onLoad={this.load} className={`${style}`} width="640" height="390"
-            src={`http://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1`} />
+        return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId.toString()}-player`}
+            onLoad={this.youtubeIframeLoaded} className={`${style}`} width="640" height="390"
+            src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1`} />
     }
 
     render() {
-        trace();
         return <div style={{ pointerEvents: "all", width: "100%", height: "100%" }} onContextMenu={this.specificContextMenu}>
             {this.youtubeVideoId ? this.youtubeContent : this.content}
         </div>;
-- 
cgit v1.2.3-70-g09d2


From 162bad9f993d349f4baecd714ba51d0f4d0ba3a3 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 16 Jul 2019 08:50:12 -0400
Subject: trying to fix startup time

---
 src/client/views/nodes/VideoBox.tsx | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 864db0bfc..85e56ca7b 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -14,6 +14,7 @@ import { pageSchema } from "./ImageBox";
 import "./VideoBox.scss";
 import { InkTool } from "../../../new_fields/InkField";
 import { DocumentDecorations } from "../DocumentDecorations";
+import { addHiddenFinalProp } from "mobx/lib/internal";
 
 type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const VideoDocument = makeInterface(positionSchema, pageSchema);
@@ -153,10 +154,10 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         let startupTimecode = NumCast(this.Document.curPage);
         let onYoutubePlayerStateChange = (event: any) => runInAction(() => {
             if (event.data !== YT.PlayerState.UNSTARTED && event.data !== YT.PlayerState.BUFFERING) {
-                if (startupTimecode !== -1) {
-                    startupTimecode = -1;
-                    if (event.data === YT.PlayerState.PLAYING) this.Pause();
-                }
+                // if (startupTimecode !== -1) {
+                //     startupTimecode = -1;
+                //     if (event.data === YT.PlayerState.PLAYING) this.Pause();
+                // }
                 if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
                 if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
             }
@@ -169,15 +170,18 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                 let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting;
                 iframe.style.pointerEvents = interactive ? "all" : "none";
             }, { fireImmediately: true });
-            if (startupTimecode) {
-                this.Playing = false;
-                this.Seek(startupTimecode);
-            }
+            // if (startupTimecode) {
+            //     this.Playing = false;
+            //     this.Seek(startupTimecode);
+            // }
         }
         this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this._youtubeIframeId}-player`, {
             playerVars: {
                 rel: 0,
-                start: NumCast(this.props.Document.curPage)
+                start: NumCast(this.props.Document.curPage),
+                fs: 1,
+                modestbranding: 1, // Modest
+                controls: VideoBox._showControls ? 1 : 0// YT.Controls.ShowLoadPlayer : YT.Controls.Hide
             },
             events: {
                 'onReady': onYoutubePlayerReady,
@@ -193,7 +197,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         let style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : "");
         return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId.toString()}-player`}
             onLoad={this.youtubeIframeLoaded} className={`${style}`} width="640" height="390"
-            src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1`} />
+            src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1&fs=1&rel=0&start=32&controls=0`} />
     }
 
     render() {
-- 
cgit v1.2.3-70-g09d2


From bbfc935958b88c7ecaeb9a1e06a255cac958ec4c Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 16 Jul 2019 11:58:16 -0400
Subject: added extendsDoc to extension doc's  fixed folllowing links to video
 locations.  fixed aspects of youtube integration.

---
 .../views/collections/CollectionVideoView.tsx      |  4 +--
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/nodes/LinkMenuItem.tsx            |  5 +--
 src/client/views/nodes/VideoBox.tsx                | 42 +++++++++-------------
 src/new_fields/Doc.ts                              |  6 +++-
 5 files changed, 27 insertions(+), 32 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index f731c4cef..faf507496 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -88,14 +88,14 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
                 canvas.width = 640;
                 canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth);
                 var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions
-                ctx && ctx.drawImage(this._videoBox!.player!, 0, 0, canvas.width, canvas.height);
+                this._videoBox!.player && ctx && ctx.drawImage(this._videoBox!.player!, 0, 0, canvas.width, canvas.height);
 
                 //convert to desired file format
                 var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png'
                 // if you want to preview the captured image,
 
                 let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, "");
-                SearchBox.convertDataUri(dataUrl, filename).then((returnedFilename) => {
+                SearchBox.convertDataUri(dataUrl, filename).then(returnedFilename => {
                     if (returnedFilename) {
                         let url = DocServer.prepend(returnedFilename);
                         let imageSummary = Docs.Create.ImageDocument(url, {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index a4a6881f8..b765517a2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -147,7 +147,6 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
         PreviewCursor.Visible = false;
         this.cleanupInteractions(true);
         if (e.button === 2 || (e.button === 0 && e.altKey)) {
-            if (!this.props.container.props.active()) this.props.selectDocuments([this.props.container.props.Document]);
             document.addEventListener("pointermove", this.onPointerMove, true);
             document.addEventListener("pointerup", this.onPointerUp, true);
             document.addEventListener("keydown", this.marqueeCommand, true);
@@ -181,6 +180,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
 
     @action
     onPointerUp = (e: PointerEvent): void => {
+        if (!this.props.container.props.active()) this.props.selectDocuments([this.props.container.props.Document]);
         // console.log("pointer up!");
         if (this._visible) {
             // console.log("visible");
diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx
index 9728671c0..6a18a4e7b 100644
--- a/src/client/views/nodes/LinkMenuItem.tsx
+++ b/src/client/views/nodes/LinkMenuItem.tsx
@@ -7,7 +7,7 @@ import { undoBatch } from "../../util/UndoManager";
 import './LinkMenu.scss';
 import React = require("react");
 import { Doc } from '../../../new_fields/Doc';
-import { StrCast, Cast, BoolCast, FieldValue } from '../../../new_fields/Types';
+import { StrCast, Cast, BoolCast, FieldValue, NumCast } from '../../../new_fields/Types';
 import { observable, action } from 'mobx';
 import { LinkManager } from '../../util/LinkManager';
 import { DragLinkAsDocument } from '../../util/DragManager';
@@ -38,7 +38,8 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             jumpToDoc = pdfDoc;
         }
         if (DocumentManager.Instance.getDocumentView(jumpToDoc)) {
-            DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey);
+            let self = this;
+            DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, undefined, undefined, NumCast((this.props.destinationDoc === self.props.linkDoc.anchor2 ? self.props.linkDoc.anchor2Page : self.props.linkDoc.anchor1Page)));
         } else {
             CollectionDockingView.Instance.AddRightSplit(jumpToDoc, undefined);
         }
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 85e56ca7b..3ade3396e 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,5 +1,5 @@
 import React = require("react");
-import { action, IReactionDisposer, observable, reaction, trace, computed, runInAction } from "mobx";
+import { action, IReactionDisposer, observable, reaction, trace, computed, runInAction, untracked } from "mobx";
 import { observer } from "mobx-react";
 import { makeInterface } from "../../../new_fields/Schema";
 import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
@@ -14,7 +14,6 @@ import { pageSchema } from "./ImageBox";
 import "./VideoBox.scss";
 import { InkTool } from "../../../new_fields/InkField";
 import { DocumentDecorations } from "../DocumentDecorations";
-import { addHiddenFinalProp } from "mobx/lib/internal";
 
 type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const VideoDocument = makeInterface(positionSchema, pageSchema);
@@ -53,18 +52,21 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
     @action public Play = (update: boolean = true) => {
         this.Playing = true;
         update && this.player && this.player.play();
+        console.log("PLAYING = " + update);
         update && this._youtubePlayer && this._youtubePlayer.playVideo();
         !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 500));
         this.updateTimecode();
     }
 
     @action public Seek(time: number) {
+        console.log("Seeking " + time);
         //if (this._youtubePlayer && this._youtubePlayer.getPlayerState() === 5) return;
-        this._youtubePlayer && !this.Playing && this._youtubePlayer.seekTo(time);
+        this._youtubePlayer && this._youtubePlayer.seekTo(Math.round(time), true);
     }
 
     @action public Pause = (update: boolean = true) => {
         this.Playing = false;
+        console.log("PAUSING = " + update);
         update && this.player && this.player.pause();
         update && this._youtubePlayer && this._youtubePlayer.pauseVideo();
         this._playTimer && clearInterval(this._playTimer);
@@ -122,6 +124,8 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         if (field) {
             let subitems: ContextMenuProps[] = [];
             subitems.push({ description: "Toggle Show Controls", event: action(() => VideoBox._showControls = !VideoBox._showControls), icon: "expand-arrows-alt" });
+            subitems.push({ description: "GOTO 3", event: action(() => this.Seek(3)), icon: "expand-arrows-alt" });
+            subitems.push({ description: "PLAY", event: action(() => this.Play()), icon: "expand-arrows-alt" });
             ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems });
         }
     }
@@ -151,38 +155,22 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         else this._youtubeContentCreated = false;
 
         let iframe = e.target;
-        let startupTimecode = NumCast(this.Document.curPage);
         let onYoutubePlayerStateChange = (event: any) => runInAction(() => {
-            if (event.data !== YT.PlayerState.UNSTARTED && event.data !== YT.PlayerState.BUFFERING) {
-                // if (startupTimecode !== -1) {
-                //     startupTimecode = -1;
-                //     if (event.data === YT.PlayerState.PLAYING) this.Pause();
-                // }
-                if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
-                if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
-            }
+            console.log("Event  " + event.data);
+            if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
+            if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
         });
         let onYoutubePlayerReady = (event: any) => {
+            console.log("READY!");
             this._reactionDisposer && this._reactionDisposer();
             this._youtubeReactionDisposer && this._youtubeReactionDisposer();
-            this._reactionDisposer = reaction(() => this.props.Document.curPage, () => this.Seek(this.Document.curPage || 0));
+            this._reactionDisposer = reaction(() => this.props.Document.curPage, () => !this.Playing && this.Seek(this.Document.curPage || 0));
             this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => {
                 let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting;
                 iframe.style.pointerEvents = interactive ? "all" : "none";
             }, { fireImmediately: true });
-            // if (startupTimecode) {
-            //     this.Playing = false;
-            //     this.Seek(startupTimecode);
-            // }
         }
         this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this._youtubeIframeId}-player`, {
-            playerVars: {
-                rel: 0,
-                start: NumCast(this.props.Document.curPage),
-                fs: 1,
-                modestbranding: 1, // Modest
-                controls: VideoBox._showControls ? 1 : 0// YT.Controls.ShowLoadPlayer : YT.Controls.Hide
-            },
             events: {
                 'onReady': onYoutubePlayerReady,
                 'onStateChange': onYoutubePlayerStateChange,
@@ -195,9 +183,11 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         this._youtubeIframeId = VideoBox._youtubeIframeCounter++;
         this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true;
         let style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : "");
-        return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId.toString()}-player`}
+        let start = untracked(() => Math.round(NumCast(this.props.Document.curPage)));
+        return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId}-player`}
             onLoad={this.youtubeIframeLoaded} className={`${style}`} width="640" height="390"
-            src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1&fs=1&rel=0&start=32&controls=0`} />
+            src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1&rel=0&showinfo=1&autoplay=1&start=${start}&modestbranding=1&controls=${VideoBox._showControls ? 1 : 0}`}
+        ></iframe>;
     }
 
     render() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index c5f9e7adf..0d9fa540f 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -312,16 +312,20 @@ export namespace Doc {
     }
 
     export function UpdateDocumentExtensionForField(doc: Doc, fieldKey: string) {
-        if (doc[fieldKey + "_ext"] === undefined) {
+        let extensionDoc = doc[fieldKey + "_ext"];
+        if (extensionDoc === undefined) {
             setTimeout(() => {
                 let docExtensionForField = new Doc(doc[Id] + fieldKey, true);
                 docExtensionForField.title = "Extension of " + doc.title + "'s field:" + fieldKey;
+                docExtensionForField.extendsDoc = doc;
                 let proto: Doc | undefined = doc;
                 while (proto && !Doc.IsPrototype(proto)) {
                     proto = proto.proto;
                 }
                 (proto ? proto : doc)[fieldKey + "_ext"] = docExtensionForField;
             }, 0);
+        } else if (extensionDoc instanceof Doc && extensionDoc.extendsDoc === undefined) {
+            setTimeout(() => (extensionDoc as Doc).extendsDoc = doc, 0);
         }
     }
     export function MakeAlias(doc: Doc) {
-- 
cgit v1.2.3-70-g09d2


From b10e8e0c22bdc27e39c365cae1a1592bc714b547 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samuel_wilkins@brown.edu>
Date: Tue, 16 Jul 2019 12:23:10 -0400
Subject: linter

---
 src/client/views/nodes/VideoBox.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 3ade3396e..972e6875d 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -157,8 +157,8 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         let iframe = e.target;
         let onYoutubePlayerStateChange = (event: any) => runInAction(() => {
             console.log("Event  " + event.data);
-            if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
-            if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
+            if (event.data === YT.PlayerState.PLAYING && !this.Playing) this.Play(false);
+            if (event.data === YT.PlayerState.PAUSED && this.Playing) this.Pause(false);
         });
         let onYoutubePlayerReady = (event: any) => {
             console.log("READY!");
@@ -169,7 +169,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                 let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting;
                 iframe.style.pointerEvents = interactive ? "all" : "none";
             }, { fireImmediately: true });
-        }
+        };
         this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this._youtubeIframeId}-player`, {
             events: {
                 'onReady': onYoutubePlayerReady,
-- 
cgit v1.2.3-70-g09d2

