aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx55
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx2
-rw-r--r--src/client/views/nodes/VideoBox.scss15
-rw-r--r--src/client/views/nodes/VideoBox.tsx116
-rw-r--r--src/server/authentication/models/current_user_utils.ts3
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");
}