From 0103346e8bae5113f5ea6f34d2745addac3a192e Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Sat, 11 May 2019 22:55:44 -0400
Subject: Changed measure params that we use

---
 src/client/views/nodes/VideoBox.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 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 422508f90..97c5d8818 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -35,7 +35,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
             // bcz: the nativeHeight should really be set when the document is imported.
             var nativeWidth = FieldValue(this.Document.nativeWidth, 0);
             var nativeHeight = FieldValue(this.Document.nativeHeight, 0);
-            var newNativeHeight = nativeWidth * r.entry.height / r.entry.width;
+            var newNativeHeight = nativeWidth * r.offset.height / r.offset.width;
             if (!nativeHeight && newNativeHeight !== nativeHeight && !isNaN(newNativeHeight)) {
                 this.Document.height = newNativeHeight / nativeWidth * FieldValue(this.Document.width, 0);
                 this.Document.nativeHeight = newNativeHeight;
@@ -71,7 +71,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         let content = this.videoContent(field.url.href);
         return NumCast(this.props.Document.nativeHeight) ?
             content :
-            <Measure onResize={this.setScaling}>
+            <Measure offset onResize={this.setScaling}>
                 {({ measureRef }) =>
                     <div style={{ width: "100%", height: "auto" }} ref={measureRef}>
                         {content}
-- 
cgit v1.2.3-70-g09d2


From a96b2d61fe05eacaaad793f2d9e19c3d99708137 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 14 May 2019 10:03:03 -0400
Subject: added non-working mp4 youtube video streamer

---
 src/client/views/nodes/PDFBox.tsx   | 35 ++++++++--------------------
 src/client/views/nodes/VideoBox.tsx | 46 +++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 25 deletions(-)

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

diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index ff8737192..6cbf066ca 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -53,8 +53,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     public static LayoutString() { return FieldView.LayoutString(PDFBox); }
 
     private _mainDiv = React.createRef<HTMLDivElement>();
+    private renderHeight = 2400;
 
     @observable private _renderAsSvg = true;
+    @observable private _alt = false;
 
     private _reactionDisposer: Opt<IReactionDisposer>;
 
@@ -65,8 +67,8 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @observable private _interactive: boolean = false;
     @observable private _loaded: boolean = false;
 
-    @computed private get curPage() { return FieldValue(this.Document.curPage, 1); }
-    @computed private get thumbnailPage() { return Cast(this.props.Document.thumbnailPage, "number", -1); }
+    @computed private get curPage() { return NumCast(this.Document.curPage, 1); }
+    @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); }
 
     componentDidMount() {
         this._reactionDisposer = reaction(
@@ -162,10 +164,8 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         let index: any;
         this._pageInfo.divs.forEach((obj: any) => {
             obj.spans.forEach((element: any) => {
-                if (element === span) {
-                    if (!index) {
-                        index = this._pageInfo.divs.indexOf(obj);
-                    }
+                if (element === span && !index) {
+                    index = this._pageInfo.divs.indexOf(obj);
                 }
             });
         });
@@ -243,7 +243,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
 
 
-
     @action
     saveThumbnail = () => {
         this._renderAsSvg = false;
@@ -284,20 +283,16 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             this.props.Document.nativeHeight = nativeHeight;
         }
     }
-    renderHeight = 2400;
     @computed
     get pdfPage() {
         return <Page height={this.renderHeight} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />;
     }
     @computed
     get pdfContent() {
-        let page = this.curPage;
-        const renderHeight = 2400;
         let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField);
         if (!pdfUrl) {
             return <p>No pdf url to render</p>;
         }
-        let xf = FieldValue(this.Document.nativeHeight, 0) / renderHeight;
         let body = NumCast(this.props.Document.nativeHeight) ?
             this.pdfPage :
             <Measure offset onResize={this.setScaling}>
@@ -307,6 +302,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                     </div>
                 }
             </Measure>;
+        let xf = NumCast(this.Document.nativeHeight) / this.renderHeight;
         return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}>
             <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl.url}`} renderMode={this._renderAsSvg ? "svg" : "canvas"}>
                 {body}
@@ -339,22 +335,11 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         }
         return (null);
     }
-    @observable _alt = false;
-    @action
-    onKeyDown = (e: React.KeyboardEvent) => {
-        if (e.key === "Alt") {
-            this._alt = true;
-        }
-    }
-    @action
-    onKeyUp = (e: React.KeyboardEvent) => {
-        if (e.key === "Alt") {
-            this._alt = false;
-        }
-    }
+    @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true);
+    @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false);
     render() {
         trace();
-        let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
+        let classname = "pdfBox-cont"; // + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
             <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} >
                 {this.pdfRenderer}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 97c5d8818..740d4cc1b 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,6 +1,7 @@
 import React = require("react");
 import { observer } from "mobx-react";
 import { FieldView, FieldViewProps } from './FieldView';
+import * as rp from "request-promise";
 import "./VideoBox.scss";
 import { action, computed, trace } from "mobx";
 import { DocComponent } from "../DocComponent";
@@ -12,6 +13,8 @@ import { VideoField } from "../../../new_fields/URLField";
 import Measure from "react-measure";
 import "./VideoBox.scss";
 import { Field, FieldResult, Opt } from "../../../new_fields/Doc";
+import { RouteStore } from "../../../server/RouteStore";
+import { DocServer } from "../../DocServer";
 
 type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const VideoDocument = makeInterface(positionSchema, pageSchema);
@@ -63,11 +66,54 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         </video>;
     }
 
+    getMp4ForVideo(videoId: string = "JN5beCVArMs") {
+        return new Promise(async (resolve, reject) => {
+            const videoInfoRequestConfig = {
+                headers: {
+                    connection: 'keep-alive',
+                    "user-agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/46.0',
+                },
+
+            }
+            try {
+                let responseSchema: any = {};
+                const videoInfoResponse = await rp.get(DocServer.prepend(RouteStore.corsProxy + "/" + `https://www.youtube.com/watch?v=${videoId}`), videoInfoRequestConfig)
+                const dataHtml = videoInfoResponse;
+                const start = dataHtml.indexOf('ytplayer.config = ') + 18;
+                const end = dataHtml.indexOf(';ytplayer.load');
+                const subString = dataHtml.substring(start, end)
+                const subJson = JSON.parse(subString);
+                const stringSub = subJson.args.player_response;
+                const stringSubJson = JSON.parse(stringSub);
+                const adaptiveFormats = stringSubJson.streamingData.adaptiveFormats;
+                const videoDetails = stringSubJson.videoDetails
+                responseSchema["adaptiveFormats"] = adaptiveFormats;
+                responseSchema["videoDetails"] = videoDetails;
+                resolve(responseSchema)
+            }
+            catch (err) {
+                console.log(`
+                --- Youtube ---
+                Function: getMp4ForVideo
+                Error: `, err)
+                reject(err)
+            }
+        })
+    }
+
+
     render() {
         let field = Cast(this.Document[this.props.fieldKey], VideoField);
         if (!field) {
             return <div>Loading</div>;
         }
+
+        // this.getMp4ForVideo().then((mp4) => {
+        //     console.log(mp4);
+        // }).catch(e => {
+        //     console.log("")
+        // });
+        // //
         let content = this.videoContent(field.url.href);
         return NumCast(this.props.Document.nativeHeight) ?
             content :
-- 
cgit v1.2.3-70-g09d2


From 0b677567dce5673bc45f08704485901801c90646 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 14 May 2019 22:46:08 -0400
Subject: fixed following links to video frames

---
 src/client/util/DocumentManager.ts                 | 12 ++---
 .../views/collections/CollectionBaseView.tsx       |  2 +-
 .../views/collections/CollectionSchemaView.scss    |  2 +-
 .../views/collections/CollectionVideoView.tsx      | 51 +++++++--------------
 src/client/views/collections/CollectionView.tsx    |  2 -
 src/client/views/nodes/KeyValuePair.scss           |  2 +-
 src/client/views/nodes/PDFBox.tsx                  |  7 +--
 src/client/views/nodes/VideoBox.scss               |  6 ++-
 src/client/views/nodes/VideoBox.tsx                | 53 ++++++++++++++++++----
 9 files changed, 76 insertions(+), 61 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 49c5d8c19..51f5fbe9f 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -111,19 +111,19 @@ export class DocumentManager {
 
     @undoBatch
     public jumpToDocument = async (doc: Doc): Promise<void> => {
+        const page = NumCast(doc.page, undefined);
+        const contextDoc = await Cast(doc.annotationOn, Doc);
+        if (contextDoc) {
+            const curPage = NumCast(contextDoc.curPage, page);
+            if (page !== curPage) contextDoc.curPage = page;
+        }
         let docView = DocumentManager.Instance.getDocumentView(doc);
         if (docView) {
             docView.props.focus(docView.props.Document);
         } else {
-            const contextDoc = await Cast(doc.annotationOn, Doc);
             if (!contextDoc) {
                 CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(doc));
             } else {
-                const page = NumCast(doc.page, undefined);
-                const curPage = NumCast(contextDoc.curPage, undefined);
-                if (page !== curPage) {
-                    contextDoc.curPage = page;
-                }
                 let contextView = DocumentManager.Instance.getDocumentView(contextDoc);
                 if (contextView) {
                     contextDoc.panTransformType = "Ease";
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 645296d27..31bdf213e 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -87,7 +87,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
     @action.bound
     addDocument(doc: Doc, allowDuplicates: boolean = false): boolean {
         let props = this.props;
-        var curPage = Cast(props.Document.curPage, "number", -1);
+        var curPage = NumCast(props.Document.curPage, -1);
         Doc.SetOnPrototype(doc, "page", curPage);
         if (curPage >= 0) {
             Doc.SetOnPrototype(doc, "annotationOn", props.Document);
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index b9ed99155..5e9d2ac67 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -127,7 +127,7 @@
                 max-width: 100%;
                 height: 100%;
             }
-            .videobox-cont {
+            .videoBox-cont {
                 object-fit: contain;
                 width: auto;
                 height: 100%;
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index cb3fd1ba4..16121bb1b 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -9,27 +9,26 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import { emptyFunction } from "../../../Utils";
 import { Id } from "../../../new_fields/RefField";
 import { VideoBox } from "../nodes/VideoBox";
+import { NumCast } from "../../../new_fields/Types";
 
 
 @observer
 export class CollectionVideoView extends React.Component<FieldViewProps> {
-    private _videoBox: VideoBox | undefined = undefined;
-    @observable _playTimer?: NodeJS.Timeout = undefined;
-
-    @observable _currentTimecode: number = 0;
+    private _videoBox?: VideoBox;
 
     public static LayoutString(fieldKey: string = "data") {
         return FieldView.LayoutString(CollectionVideoView, fieldKey);
     }
     private get uIButtons() {
         let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().Scale);
+        let curTime = NumCast(this.props.Document.curPage);
         return ([
             <div className="collectionVideoView-time" key="time" onPointerDown={this.onResetDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
-                <span>{"" + Math.round(this._currentTimecode)}</span>
-                <span style={{ fontSize: 8 }}>{" " + Math.round((this._currentTimecode - Math.trunc(this._currentTimecode)) * 100)}</span>
+                <span>{"" + Math.round(curTime)}</span>
+                <span style={{ fontSize: 8 }}>{" " + Math.round((curTime - Math.trunc(curTime)) * 100)}</span>
             </div>,
             <div className="collectionVideoView-play" key="play" onPointerDown={this.onPlayDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
-                {this._playTimer ? "\"" : ">"}
+                {this._videoBox && this._videoBox.Playing ? "\"" : ">"}
             </div>,
             <div className="collectionVideoView-full" key="full" onPointerDown={this.onFullDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
                 F
@@ -37,37 +36,21 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
         ]);
     }
 
-    @action
-    updateTimecode = () => {
-        if (this._videoBox && this._videoBox.player) {
-            this._currentTimecode = this._videoBox.player.currentTime;
-            this.props.Document.curPage = Math.round(this._currentTimecode);
-        }
-    }
-
-    componentDidMount() { this.updateTimecode(); }
-
-    componentWillUnmount() { if (this._playTimer) clearInterval(this._playTimer); }
-
     @action
     onPlayDown = () => {
         if (this._videoBox && this._videoBox.player) {
-            if (this._videoBox.player.paused) {
-                this._videoBox.player.play();
-                if (!this._playTimer) this._playTimer = setInterval(this.updateTimecode, 1000);
+            if (this._videoBox.Playing) {
+                this._videoBox.Pause();
             } else {
-                this._videoBox.player.pause();
-                if (this._playTimer) clearInterval(this._playTimer);
-                this._playTimer = undefined;
-
+                this._videoBox.Play();
             }
         }
     }
 
     @action
     onFullDown = (e: React.PointerEvent) => {
-        if (this._videoBox && this._videoBox.player) {
-            this._videoBox.player.requestFullscreen();
+        if (this._videoBox) {
+            this._videoBox.FullScreen();
             e.stopPropagation();
             e.preventDefault();
         }
@@ -75,12 +58,9 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
 
     @action
     onResetDown = () => {
-        if (this._videoBox && this._videoBox.player) {
-            this._videoBox.player.pause();
-            this._videoBox.player.currentTime = 0;
-            if (this._playTimer) clearInterval(this._playTimer);
-            this._playTimer = undefined;
-            this.updateTimecode();
+        if (this._videoBox) {
+            this._videoBox.Pause();
+            this.props.Document.curPage = 0;
         }
     }
 
@@ -90,7 +70,7 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
         }
     }
 
-    setVideoBox = (player: VideoBox) => { this._videoBox = player; };
+    setVideoBox = (videoBox: VideoBox) => { this._videoBox = videoBox; };
 
     private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => {
         let props = { ...this.props, ...renderProps };
@@ -101,6 +81,7 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
     }
 
     render() {
+        trace();
         return (
             <CollectionBaseView {...this.props} className="collectionVideoView-cont" onContextMenu={this.onContextMenu}>
                 {this.subView}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 8c1442d38..55fd2a284 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -9,9 +9,7 @@ import { ContextMenu } from '../ContextMenu';
 import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
 import { observer } from 'mobx-react';
 import { undoBatch } from '../../util/UndoManager';
-import { trace } from 'mobx';
 import { Id } from '../../../new_fields/RefField';
-import { Main } from '../Main';
 
 @observer
 export class CollectionView extends React.Component<FieldViewProps> {
diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss
index 4f305dc91..a1c5d5537 100644
--- a/src/client/views/nodes/KeyValuePair.scss
+++ b/src/client/views/nodes/KeyValuePair.scss
@@ -30,7 +30,7 @@
         max-height: 36px;
         width: auto;
     }
-    .videobox-cont{
+    .videoBox-cont{
         width: auto; 
         max-height: 36px; 
     }
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 6cbf066ca..14fe2df80 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -58,7 +58,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @observable private _renderAsSvg = true;
     @observable private _alt = false;
 
-    private _reactionDisposer: Opt<IReactionDisposer>;
+    private _reactionDisposer?: IReactionDisposer;
 
     @observable private _perPageInfo: Object[] = []; //stores pageInfo
     @observable private _pageInfo: any = { area: [], divs: [], anno: [] }; //divs is array of objects linked to anno
@@ -84,9 +84,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
 
     componentWillUnmount() {
-        if (this._reactionDisposer) {
-            this._reactionDisposer();
-        }
+        if (this._reactionDisposer) this._reactionDisposer();
     }
 
     /**
@@ -338,7 +336,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true);
     @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false);
     render() {
-        trace();
         let classname = "pdfBox-cont"; // + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
             <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} >
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index 76bbeb37c..35db64cf4 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -1,4 +1,8 @@
-.videobox-cont{
+.videoBox-cont, .videoBox-cont-fullScreen{
     width: 100%; 
     height: Auto; 
+}
+
+.videoBox-cont-fullScreen {
+    pointer-events: all;
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 740d4cc1b..96dc884c8 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -3,16 +3,15 @@ import { observer } from "mobx-react";
 import { FieldView, FieldViewProps } from './FieldView';
 import * as rp from "request-promise";
 import "./VideoBox.scss";
-import { action, computed, trace } from "mobx";
+import { action, IReactionDisposer, reaction, observable } from "mobx";
 import { DocComponent } from "../DocComponent";
 import { positionSchema } from "./DocumentView";
 import { makeInterface } from "../../../new_fields/Schema";
 import { pageSchema } from "./ImageBox";
-import { Cast, FieldValue, NumCast, ToConstructor, ListSpec } from "../../../new_fields/Types";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
 import { VideoField } from "../../../new_fields/URLField";
 import Measure from "react-measure";
 import "./VideoBox.scss";
-import { Field, FieldResult, Opt } from "../../../new_fields/Doc";
 import { RouteStore } from "../../../server/RouteStore";
 import { DocServer } from "../../DocServer";
 
@@ -21,10 +20,12 @@ const VideoDocument = makeInterface(positionSchema, pageSchema);
 
 @observer
 export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) {
-
+    private _reactionDisposer?: IReactionDisposer;
     private _videoRef: HTMLVideoElement | null = null;
     private _loaded: boolean = false;
-    private get initialTimecode() { return FieldValue(this.Document.curPage, -1); }
+    @observable _playTimer?: NodeJS.Timeout = undefined;
+    @observable _fullScreen = false;
+    @observable public Playing: boolean = false;
     public static LayoutString() { return FieldView.LayoutString(VideoBox); }
 
     public get player(): HTMLVideoElement | undefined {
@@ -48,19 +49,50 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         }
     }
 
+    @action public Play() {
+        this.Playing = true;
+        if (this.player) this.player.play();
+        if (!this._playTimer) this._playTimer = setInterval(this.updateTimecode, 1000);
+    }
+
+    @action public Pause() {
+        this.Playing = false;
+        if (this.player) this.player.pause();
+        if (this._playTimer) {
+            clearInterval(this._playTimer);
+            this._playTimer = undefined;
+        }
+    }
+
+    @action public FullScreen() {
+        this._fullScreen = true;
+        this.player && this.player.requestFullscreen();
+    }
+
+    @action
+    updateTimecode = () => this.player && (this.props.Document.curPage = this.player.currentTime);
+
     componentDidMount() {
         if (this.props.setVideoBox) this.props.setVideoBox(this);
     }
+    componentWillUnmount() {
+        this.Pause();
+        if (this._reactionDisposer) this._reactionDisposer();
+    }
 
     @action
     setVideoRef = (vref: HTMLVideoElement | null) => {
         this._videoRef = vref;
-        if (this.initialTimecode >= 0 && vref) {
-            vref.currentTime = this.initialTimecode;
+        if (vref) {
+            vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
+            if (this._reactionDisposer) this._reactionDisposer();
+            this._reactionDisposer = reaction(() => this.props.Document.curPage, () =>
+                vref.currentTime = NumCast(this.props.Document.curPage, 0), { fireImmediately: true });
         }
     }
     videoContent(path: string) {
-        return <video className="videobox-cont" ref={this.setVideoRef}>
+        let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : "");
+        return <video className={`${style}`} ref={this.setVideoRef} onPointerDown={this.onPointerDown}>
             <source src={path} type="video/mp4" />
             Not supported.
         </video>;
@@ -100,7 +132,10 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
             }
         })
     }
-
+    onPointerDown = (e: React.PointerEvent) => {
+        e.preventDefault();
+        e.stopPropagation();
+    }
 
     render() {
         let field = Cast(this.Document[this.props.fieldKey], VideoField);
-- 
cgit v1.2.3-70-g09d2

