diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 55 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.scss | 15 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 116 | ||||
-rw-r--r-- | src/server/authentication/models/current_user_utils.ts | 3 |
5 files changed, 116 insertions, 75 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index e5cee188f..34b8eb8e1 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,6 +1,6 @@ import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; -import { action, Lambda, observable, reaction } from "mobx"; +import { action, Lambda, observable, reaction, trace, computed } from "mobx"; import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; @@ -412,7 +412,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp } SelectionManager.DeselectAll(); } + CollectionDockingView.Instance._ignoreStateChange = JSON.stringify(CollectionDockingView.Instance._goldenLayout.toConfig()); tab.contentItem.remove(); + CollectionDockingView.Instance._ignoreStateChange = JSON.stringify(CollectionDockingView.Instance._goldenLayout.toConfig()); }); } @@ -569,33 +571,40 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc); } } - get content() { + @computed get docView() { if (!this._document) { return (null); } let resolvedDataDoc = this._document.layout instanceof Doc ? this._document : this._dataDoc; + return <DocumentView key={this._document[Id]} + Document={this._document} + DataDoc={resolvedDataDoc} + bringToFront={emptyFunction} + addDocument={undefined} + removeDocument={undefined} + ContentScaling={this.contentScaling} + PanelWidth={this.nativeWidth} + PanelHeight={this.nativeHeight} + ScreenToLocalTransform={this.ScreenToLocalTransform} + renderDepth={0} + selectOnLoad={false} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + focus={emptyFunction} + addDocTab={this.addDocTab} + ContainingCollectionView={undefined} + zoomToScale={emptyFunction} + getScale={returnOne} /> + } + + @computed get content() { + if (!this._document) { + return (null); + } return ( <div className="collectionDockingView-content" ref={this._mainCont} style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px) scale(${this.scaleToFitMultiplier})` }}> - <DocumentView key={this._document[Id]} - Document={this._document} - DataDoc={resolvedDataDoc} - bringToFront={emptyFunction} - addDocument={undefined} - removeDocument={undefined} - ContentScaling={this.contentScaling} - PanelWidth={this.nativeWidth} - PanelHeight={this.nativeHeight} - ScreenToLocalTransform={this.ScreenToLocalTransform} - renderDepth={0} - selectOnLoad={false} - parentActive={returnTrue} - whenActiveChanged={emptyFunction} - focus={emptyFunction} - addDocTab={this.addDocTab} - ContainingCollectionView={undefined} - zoomToScale={emptyFunction} - getScale={returnOne} /> + {this.docView} </div >); } @@ -604,7 +613,9 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { let theContent = this.content; return !this._document ? (null) : <Measure offset onResize={action((r: any) => { this._panelWidth = r.offset.width; this._panelHeight = r.offset.height; })}> - {({ measureRef }) => <div ref={measureRef}> {theContent} </div>} + {({ measureRef }) => <div ref={measureRef}> + {theContent} + </div>} </Measure>; } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a84fd9cfe..fe01103d6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -50,7 +50,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } overlays = (doc: Doc) => { - return doc.type === DocumentType.IMG ? { title: "title", caption: "caption" } : {}; + return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: "title", caption: "caption" } : {}; } getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) { diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index 55f2fe7c5..d651a8621 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -1,12 +1,17 @@ -.videoBox-cont, .videoBox-cont-interactive, .videoBox-cont-fullScreen { - width: 100%; +.videoBox-content-YouTube, .videoBox-content-YouTube-fullScreen, +.videoBox-content, .videoBox-content-interactive, .videoBox-cont-fullScreen { + width: 100%; +} + +.videoBox-content, .videoBox-content-interactive, .videoBox-content-fullScreen { height: Auto; } -.videoBox-cont-interactive { - pointer-events: all; +.videoBox-content-YouTube, .videoBox-content-YouTube-fullScreen { + height: 100%; } -.videoBox-cont-fullScreen { +.videoBox-content-interactive, .videoBox-content-fullScreen, +.videoBox-content-YouTube-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 1b9138cfd..c9179db47 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,21 +1,18 @@ import React = require("react"); -import { action, IReactionDisposer, observable, reaction } from "mobx"; +import { action, IReactionDisposer, observable, reaction, trace, computed } from "mobx"; import { observer } from "mobx-react"; -import * as rp from "request-promise"; import { makeInterface } from "../../../new_fields/Schema"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; -import { RouteStore } from "../../../server/RouteStore"; -import { DocServer } from "../../DocServer"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; import { DocComponent } from "../DocComponent"; +import { InkingControl } from "../InkingControl"; import { positionSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./VideoBox.scss"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { InkingControl } from "../InkingControl"; -import * as $ from "jquery"; +import { InkTool } from "../../../new_fields/InkField"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); @@ -23,6 +20,7 @@ const VideoDocument = makeInterface(positionSchema, pageSchema); @observer export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) { private _reactionDisposer?: IReactionDisposer; + private _youtubeReactionDisposer?: IReactionDisposer; private _youtubePlayer: any = undefined; private _videoRef: HTMLVideoElement | null = null; @observable _playTimer?: NodeJS.Timeout = undefined; @@ -47,45 +45,37 @@ 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, 500); - } else if (this._youtubePlayer) { - this._youtubePlayer.playVideo(); - if (!this._playTimer) this._playTimer = setInterval(this.updateYoutubeTimecode, 1000); + this.player && this.player.play(); + this._youtubePlayer && this._youtubePlayer.playVideo(); + !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 500)); + this._youtubeSeekTo = false; + } + + @action public Seek(time: number) { + if (this._youtubePlayer && !this.Playing) { + this._youtubeSeekTo = true; + this._youtubePlayer.seekTo(time); } } @action public Pause() { this.Playing = false; - if (this.player) { - this.player.pause(); - if (this._playTimer) { - clearInterval(this._playTimer); - this._playTimer = undefined; - } - } else if (this._youtubePlayer) { - // let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive"; - // this._youtubePlayer.getIframe().style.pointerEvents = interactive ? "all" : "none"; - this._youtubePlayer.pauseVideo(); - if (this._playTimer) { - clearInterval(this._playTimer); - this._playTimer = undefined; - } - } + this.player && this.player.pause(); + this._youtubePlayer && this._youtubePlayer.pauseVideo(); + this._playTimer && clearInterval(this._playTimer); + this._playTimer = undefined; + this._youtubeSeekTo = false; } @action public FullScreen() { this._fullScreen = true; this.player && this.player.requestFullscreen(); + this._youtubePlayer && this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab"); } @action updateTimecode = () => { this.player && (this.props.Document.curPage = this.player.currentTime); - } - @action - updateYoutubeTimecode = () => { this._youtubePlayer && (this.props.Document.curPage = this._youtubePlayer.getCurrentTime()); } componentDidMount() { @@ -108,9 +98,15 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD videoId: videoid.toString(), playerVars: { 'controls': VideoBox._showControls ? 1 : 0 }, events: { - 'onStateChange': this.onPlayerStateChange, + '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(), InkingControl.Instance.selectedTool], () => { + let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected(); + this._youtubePlayer.getIframe().style.pointerEvents = interactive ? "all" : "none"; + }, { fireImmediately: true }) // let iframe = $(document.getElementById(`${videoid}-player`)!); // iframe.on("load", function () { // iframe.contents().find("head") @@ -120,13 +116,30 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD } @action - onPlayerStateChange = (event: any) => { + 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; + } } componentWillUnmount() { this.Pause(); - if (this._reactionDisposer) this._reactionDisposer(); + this._reactionDisposer && this._reactionDisposer(); + this._youtubeReactionDisposer && this._youtubeReactionDisposer(); } @action @@ -143,6 +156,11 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD @observable static _showControls: boolean = false; + @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) { @@ -152,19 +170,25 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD } } - render() { + @computed get content() { let field = Cast(this.Document[this.props.fieldKey], VideoField); let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive"; - let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : interactive); - let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : ""; - - if (this._youtubePlayer) this._youtubePlayer.getIframe().style.pointerEvents = interactive ? "all" : "none"; + let style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive; return !field ? <div>Loading</div> : - videoid ? - <div id={`${videoid}-player`} className={`${style}`} style={{ height: "100%" }} /> : - <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} onContextMenu={this.specificContextMenu} controls={VideoBox._showControls}> - <source src={field.url.href} type="video/mp4" /> - Not supported. - </video>; + <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} controls={VideoBox._showControls}> + <source src={field.url.href} type="video/mp4" /> + Not supported. + </video>; + } + + @computed get youtubeContent() { + let style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : ""); + return <div id={`${this.youtubeVideoId}-player`} className={`${style}`} />; + } + + render() { + return <div style={{ pointerEvents: "all", width: "100%", height: "100%" }} onContextMenu={this.specificContextMenu}> + {this.youtubeVideoId ? this.youtubeContent : this.content} + </div>; } }
\ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 39a973e08..384c579de 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -10,7 +10,7 @@ import { CollectionView } from "../../../client/views/collections/CollectionView import { Doc } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { Cast, FieldValue } from "../../../new_fields/Types"; +import { Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { RouteStore } from "../../RouteStore"; export class CurrentUserUtils { @@ -69,6 +69,7 @@ export class CurrentUserUtils { sidebar.boxShadow = "1 1 3"; doc.sidebar = sidebar; } + StrCast(doc.title).indexOf("@") !== -1 && (doc.title = StrCast(doc.title).split("@")[0] + "'s Library"); } |