From 6df09d7d646c16e6469b198e7d270b6a1e45b0c7 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 24 Jun 2019 13:23:28 -0400 Subject: fixes for templates with annotations and more. --- src/client/views/InkingCanvas.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/client/views/InkingCanvas.tsx') diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 5d4ea76cd..fd7e5b07d 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -14,6 +14,7 @@ import { Cast, PromiseValue, NumCast } from "../../new_fields/Types"; interface InkCanvasProps { getScreenTransform: () => Transform; Document: Doc; + inkFieldKey: string; children: () => JSX.Element[]; } @@ -40,7 +41,7 @@ export class InkingCanvas extends React.Component { } componentDidMount() { - PromiseValue(Cast(this.props.Document.ink, InkField)).then(ink => runInAction(() => { + PromiseValue(Cast(this.props.Document[this.props.inkFieldKey], InkField)).then(ink => runInAction(() => { if (ink) { let bounds = Array.from(ink.inkData).reduce(([mix, max, miy, may], [id, strokeData]) => strokeData.pathData.reduce(([mix, max, miy, may], p) => @@ -55,12 +56,12 @@ export class InkingCanvas extends React.Component { @computed get inkData(): Map { - let map = Cast(this.props.Document.ink, InkField); + let map = Cast(this.props.Document[this.props.inkFieldKey], InkField); return !map ? new Map : new Map(map.inkData); } set inkData(value: Map) { - Doc.GetProto(this.props.Document).ink = new InkField(value); + Doc.GetProto(this.props.Document)[this.props.inkFieldKey] = new InkField(value); } @action -- cgit v1.2.3-70-g09d2 From 7b10d90d7e20a8a5f4572387c085fafcc2fd56f3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 11 Jul 2019 02:02:52 -0400 Subject: fixing template details. --- src/client/views/InkingCanvas.tsx | 2 +- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/client/views/InkingCanvas.tsx') diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index fd7e5b07d..2c54054a5 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -61,7 +61,7 @@ export class InkingCanvas extends React.Component { } set inkData(value: Map) { - Doc.GetProto(this.props.Document)[this.props.inkFieldKey] = new InkField(value); + this.props.Document[this.props.inkFieldKey] = new InkField(value); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c931c74bc..23572a823 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -54,7 +54,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } - public get isAnnotationOverlay() { return this.props.fieldExt === "annotations"; } + public get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } // fieldExt will be "" or "annotation". should maybe generalize this, or make it more specific (ie, 'annotation' instead of 'fieldExt') private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } private panX = () => this.props.fitToBox ? this.props.fitToBox()[0] : this.Document.panX || 0; private panY = () => this.props.fitToBox ? this.props.fitToBox()[1] : this.Document.panY || 0; @@ -86,7 +86,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }); } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.isAnnotationOverlay ? "dummy" : ""); } + @computed get annoExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc && (!this.props.Document.isTemplate || this.isAnnotationOverlay) ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.isAnnotationOverlay ? "dummy" : ""); } @undoBatch @@ -171,7 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); - let ink = Cast(this.extensionDoc.ink, InkField); + let ink = Cast(this.annoExtensionDoc.ink, InkField); if (ink && ink.inkData) { ink.inkData.forEach((value: StrokeData, key: string) => { let bounds = InkingCanvas.StrokeRect(value); @@ -344,7 +344,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps { - let resolvedDataDoc = this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; + let self = this; + let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; let layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc); return { DataDoc: resolvedDataDoc !== layoutDoc && resolvedDataDoc ? resolvedDataDoc : undefined, @@ -512,7 +513,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { - + {this.childViews} -- cgit v1.2.3-70-g09d2 From 6a477918f2f16bdc023c76d6a145bb6435e918a6 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 12 Jul 2019 16:06:15 -0400 Subject: fixed annotations on video timecodes. added start of youtube support. --- src/client/views/InkingCanvas.tsx | 7 +- src/client/views/MainView.tsx | 5 ++ src/client/views/collections/CollectionSubView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 98 +++++++++++----------- 5 files changed, 61 insertions(+), 55 deletions(-) (limited to 'src/client/views/InkingCanvas.tsx') diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 2c54054a5..37a6bbab7 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -13,6 +13,7 @@ import { Cast, PromiseValue, NumCast } from "../../new_fields/Types"; interface InkCanvasProps { getScreenTransform: () => Transform; + AnnotationDocument: Doc; Document: Doc; inkFieldKey: string; children: () => JSX.Element[]; @@ -41,7 +42,7 @@ export class InkingCanvas extends React.Component { } componentDidMount() { - PromiseValue(Cast(this.props.Document[this.props.inkFieldKey], InkField)).then(ink => runInAction(() => { + PromiseValue(Cast(this.props.AnnotationDocument[this.props.inkFieldKey], InkField)).then(ink => runInAction(() => { if (ink) { let bounds = Array.from(ink.inkData).reduce(([mix, max, miy, may], [id, strokeData]) => strokeData.pathData.reduce(([mix, max, miy, may], p) => @@ -56,12 +57,12 @@ export class InkingCanvas extends React.Component { @computed get inkData(): Map { - let map = Cast(this.props.Document[this.props.inkFieldKey], InkField); + let map = Cast(this.props.AnnotationDocument[this.props.inkFieldKey], InkField); return !map ? new Map : new Map(map.inkData); } set inkData(value: Map) { - this.props.Document[this.props.inkFieldKey] = new InkField(value); + this.props.AnnotationDocument[this.props.inkFieldKey] = new InkField(value); } @action diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ec5ec6e8b..f0e11a480 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -64,6 +64,11 @@ export class MainView extends React.Component { } componentWillMount() { + var tag = document.createElement('script'); + + tag.src = "https://www.youtube.com/iframe_api"; + var firstScriptTag = document.getElementsByTagName('script')[0]; + firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); window.removeEventListener("keydown", KeyManager.Instance.handle); window.addEventListener("keydown", KeyManager.Instance.handle); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 7ac8aee4c..b2c3fb7d0 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -179,8 +179,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { } } if (text && text.indexOf("www.youtube.com/watch") !== -1) { - const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/"); - this.props.addDocument(Docs.Create.WebDocument(url, { ...options, width: 300, height: 300 })); + const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");// + "?enablejsapi=1"; + this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, width: 400, height: 315 })); return; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f4e5c4384..e35546fec 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -524,7 +524,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { - + {this.childViews} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 895d9a422..9ee4d7942 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -3,7 +3,7 @@ import { action, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; import { makeInterface } from "../../../new_fields/Schema"; -import { Cast, FieldValue } from "../../../new_fields/Types"; +import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; import { RouteStore } from "../../../server/RouteStore"; import { DocServer } from "../../DocServer"; @@ -15,6 +15,7 @@ import "./VideoBox.scss"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { InkingControl } from "../InkingControl"; +import * as $ from "jquery"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); @@ -22,6 +23,7 @@ const VideoDocument = makeInterface(positionSchema, pageSchema); @observer export class VideoBox extends DocComponent(VideoDocument) { private _reactionDisposer?: IReactionDisposer; + private _youtubePlayer: any = undefined; private _videoRef: HTMLVideoElement | null = null; @observable _playTimer?: NodeJS.Timeout = undefined; @observable _fullScreen = false; @@ -67,12 +69,16 @@ export class VideoBox extends DocComponent(VideoD updateTimecode = () => { this.player && (this.props.Document.curPage = this.player.currentTime); } - + @action + updateYoutubeTimecode = () => { + this._youtubePlayer && (this.props.Document.curPage = this._youtubePlayer.getCurrentTime()); + } componentDidMount() { if (this.props.setVideoBox) this.props.setVideoBox(this); let field = Cast(this.Document[this.props.fieldKey], VideoField); - if (field && field.url.href.indexOf("youtube") !== -1) { + let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : ""; + if (videoid) { let youtubeaspect = 400 / 315; var nativeWidth = FieldValue(this.Document.nativeWidth, 0); var nativeHeight = FieldValue(this.Document.nativeHeight, 0); @@ -81,7 +87,42 @@ export class VideoBox extends DocComponent(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': 0 }, + events: { + //'onReady': this.onPlayerReady, + } + }); + // let iframe = $(document.getElementById(`${videoid}-player`)!); + // iframe.on("load", function () { + // iframe.contents().find("head") + // .append($("")); + // }); + reaction(() => this.props.isSelected(), (sel) => { + if (sel) { + this._youtubePlayer.playVideo(); + if (!this._playTimer) this._playTimer = setInterval(this.updateYoutubeTimecode, 1000); + } else { + let iframe = $(document.getElementById(`${videoid}-player`)!); + // .ytp-pause-overlay, .ytp-scroll-min { opacity : 0 !important; } + // $('iframe').load( function() { + // $('iframe').contents().find("head") + // .append($("")); + // }); + //this._youtubePlayer.cueVideoById(videoid, this._youtubePlayer.getCurrentTime()); + this._youtubePlayer.pauseVideo(); + if (this._playTimer) { + clearInterval(this._playTimer); + this._playTimer = undefined; + } + } + }); } + + } componentWillUnmount() { this.Pause(); @@ -100,39 +141,7 @@ export class VideoBox extends DocComponent(VideoD } } - 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); - } - }); - } + onPointerDown = (e: React.PointerEvent) => { } @@ -149,22 +158,13 @@ export class VideoBox extends DocComponent(VideoD render() { let field = Cast(this.Document[this.props.fieldKey], VideoField); - - // this.getMp4ForVideo().then((mp4) => { - // console.log(mp4); - // }).catch(e => { - // console.log("") - // }); - // // - let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive"; let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : interactive); - let videoid = field ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : ""; + let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : ""; + return !field ?
Loading
: - field.url.href.indexOf("youtube") !== -1 ? - - : + videoid ? +
: