aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionVideoView.tsx108
-rw-r--r--src/client/views/collections/CollectionView.tsx6
-rw-r--r--src/client/views/nodes/LinkBox.tsx21
-rw-r--r--src/client/views/nodes/PDFBox.tsx21
-rw-r--r--src/client/views/nodes/VideoBox.tsx29
-rw-r--r--src/fields/KeyStore.ts2
7 files changed, 120 insertions, 69 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 39b284d8e..d4f510f5d 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -191,7 +191,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
@action
onPointerDown = (e: React.PointerEvent): void => {
var className = (e.target as any).className;
- if ((className == "lm_title" || className == "lm_tab lm_active") && e.ctrlKey) {
+ if ((className == "lm_title" || className == "lm_tab lm_active") && (e.ctrlKey || e.altKey)) {
e.stopPropagation();
e.preventDefault();
let docid = (e.target as any).DashDocId;
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index a3921696f..470a853e3 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable } from "mobx";
+import { action, computed, observable, trace } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { KeyStore } from "../../../fields/KeyStore";
@@ -12,24 +12,26 @@ import "./CollectionVideoView.scss"
@observer
export class CollectionVideoView extends React.Component<CollectionViewProps> {
+ private _intervalTimer: any = undefined;
+ private _player: HTMLVideoElement | undefined = undefined;
+
+ @observable _currentTimecode: number = 0;
+ @observable _isPlaying: boolean = false;
public static LayoutString(fieldKey: string = "DataKey") {
return `<${CollectionVideoView.name} Document={Document}
ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings}
isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`;
}
-
- private _mainCont = React.createRef<HTMLDivElement>();
-
private get uIButtons() {
let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]);
return ([
<div className="collectionVideoView-time" key="time" onPointerDown={this.onResetDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
- <span>{"" + Math.round(this.ctime)}</span>
- <span style={{ fontSize: 8 }}>{" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)}</span>
+ <span>{"" + Math.round(this._currentTimecode)}</span>
+ <span style={{ fontSize: 8 }}>{" " + Math.round((this._currentTimecode - Math.trunc(this._currentTimecode)) * 100)}</span>
</div>,
<div className="collectionVideoView-play" key="play" onPointerDown={this.onPlayDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
- {this.playing ? "\"" : ">"}
+ {this._isPlaying ? "\"" : ">"}
</div>,
<div className="collectionVideoView-full" key="full" onPointerDown={this.onFullDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
F
@@ -37,64 +39,54 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> {
]);
}
-
- // "inherited" CollectionView API starts here...
-
- @observable
- public SelectedDocs: FieldId[] = []
- public active: () => boolean = () => CollectionView.Active(this);
-
- addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); }
- removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
-
- specificContextMenu = (e: React.MouseEvent): void => {
- if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
- ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } });
+ @action
+ mainCont = (ele: HTMLDivElement | null) => {
+ if (ele) {
+ this._player = ele!.getElementsByTagName("video")[0];
+ if (this.props.Document.GetNumber(KeyStore.CurPage, -1) >= 0) {
+ this._currentTimecode = this.props.Document.GetNumber(KeyStore.CurPage, -1);
+ }
}
}
- get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; }
- get subView(): any { return CollectionView.SubView(this); }
-
componentDidMount() {
- this.updateTimecode();
+ this._intervalTimer = setInterval(this.updateTimecode, 1000);
}
- get player(): HTMLVideoElement | undefined {
- return this._mainCont.current ? this._mainCont.current.getElementsByTagName("video")[0] : undefined;
+ componentWillUnmount() {
+ clearInterval(this._intervalTimer);
}
@action
updateTimecode = () => {
- if (this.player) {
- this.ctime = this.player.currentTime;
- this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this.ctime));
+ if (this._player) {
+ if ((this._player as any).AHackBecauseSomethingResetsTheVideoToZero != -1) {
+ this._player.currentTime = (this._player as any).AHackBecauseSomethingResetsTheVideoToZero;
+ (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1;
+ } else {
+ this._currentTimecode = this._player.currentTime;
+ this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this._currentTimecode));
+ }
}
- setTimeout(() => this.updateTimecode(), 100)
}
-
- @observable
- ctime: number = 0
- @observable
- playing: boolean = false;
-
@action
onPlayDown = () => {
- if (this.player) {
- if (this.player.paused) {
- this.player.play();
- this.playing = true;
+ if (this._player) {
+ if (this._player.paused) {
+ this._player.play();
+ this._isPlaying = true;
} else {
- this.player.pause();
- this.playing = false;
+ this._player.pause();
+ this._isPlaying = false;
}
}
}
+
@action
onFullDown = (e: React.PointerEvent) => {
- if (this.player) {
- this.player.requestFullscreen();
+ if (this._player) {
+ this._player.requestFullscreen();
e.stopPropagation();
e.preventDefault();
}
@@ -102,15 +94,35 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> {
@action
onResetDown = () => {
- if (this.player) {
- this.player.pause();
- this.player.currentTime = 0;
+ if (this._player) {
+ this._player.pause();
+ this._player.currentTime = 0;
}
}
+ // "inherited" CollectionView API starts here...
+
+ @observable
+ public SelectedDocs: FieldId[] = []
+ public active: () => boolean = () => CollectionView.Active(this);
+
+ addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); }
+ removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
+
+ specificContextMenu = (e: React.MouseEvent): void => {
+ if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
+ ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } });
+ }
+ }
+
+ get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; }
+ get subView(): any { return CollectionView.SubView(this); }
+
+
render() {
- return (<div className="collectionVideoView-cont" ref={this._mainCont} onContextMenu={this.specificContextMenu}>
+ trace();
+ return (<div className="collectionVideoView-cont" ref={this.mainCont} onContextMenu={this.specificContextMenu}>
{this.subView}
{this.props.isSelected() ? this.uIButtons : (null)}
</div>)
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a740865ad..2fa2c9086 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -68,7 +68,11 @@ export class CollectionView extends React.Component<CollectionViewProps> {
@action
public static AddDocument(props: CollectionViewProps, doc: Document, allowDuplicates: boolean): boolean {
- doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, -1));
+ var curPage = props.Document.GetNumber(KeyStore.CurPage, -1);
+ doc.SetNumber(KeyStore.Page, curPage);
+ if (curPage > 0) {
+ doc.Set(KeyStore.AnnotationOn, props.Document);
+ }
if (props.Document.Get(props.fieldKey) instanceof Field) {
//TODO This won't create the field if it doesn't already exist
const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index dd2f71b59..638d3b5a7 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -17,6 +17,8 @@ import { faEye } from '@fortawesome/free-solid-svg-icons';
import { faEdit } from '@fortawesome/free-solid-svg-icons';
import { faTimes } from '@fortawesome/free-solid-svg-icons';
import { undoBatch } from "../../util/UndoManager";
+import { FieldWaiting } from "../../../fields/Field";
+import { NumberField } from "../../../fields/NumberField";
library.add(faEye);
@@ -41,7 +43,24 @@ export class LinkBox extends React.Component<Props> {
if (docView) {
docView.props.focus(this.props.pairedDoc);
} else {
- CollectionDockingView.Instance.AddRightSplit(this.props.pairedDoc)
+ this.props.pairedDoc.GetAsync(KeyStore.AnnotationOn, (contextDoc: any) => {
+ if (!contextDoc) {
+ CollectionDockingView.Instance.AddRightSplit(this.props.pairedDoc);
+ } else if (contextDoc instanceof Document) {
+ this.props.pairedDoc.GetTAsync(KeyStore.Page, NumberField).then((pfield: any) => {
+ contextDoc.GetTAsync(KeyStore.CurPage, NumberField).then((cfield: any) => {
+ if (pfield != cfield)
+ contextDoc.SetNumber(KeyStore.CurPage, pfield.Data);
+ let contextView = DocumentManager.Instance.getDocumentView(contextDoc);
+ if (contextView) {
+ contextView.props.focus(contextDoc);
+ } else {
+ CollectionDockingView.Instance.AddRightSplit(contextDoc);
+ }
+ })
+ });
+ }
+ });
}
}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 3a0ef2d32..e273b0b4f 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,5 +1,5 @@
import * as htmlToImage from "html-to-image";
-import { action, computed, observable, reaction, IReactionDisposer, trace } from 'mobx';
+import { action, computed, observable, reaction, IReactionDisposer, trace, keys } from 'mobx';
import { observer } from "mobx-react";
import 'react-image-lightbox/style.css';
import Measure from "react-measure";
@@ -18,6 +18,7 @@ import "./PDFBox.scss";
import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here
import React = require("react")
import { RouteStore } from "../../../server/RouteStore";
+import { NumberField } from "../../../fields/NumberField";
/** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
* This method renders PDF and puts all kinds of functionalities such as annotation, highlighting,
@@ -60,7 +61,6 @@ export class PDFBox extends React.Component<FieldViewProps> {
//very useful for keeping track of X and y position throughout the PDF Canvas
private initX: number = 0;
private initY: number = 0;
- private initPage: boolean = false;
//checks if tool is on
private _toolOn: boolean = false; //checks if tool is on
@@ -88,17 +88,15 @@ export class PDFBox extends React.Component<FieldViewProps> {
@observable private _loaded: boolean = false;
@computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, -1); }
+ @computed private get thumbnailPage() { return this.props.doc.GetNumber(KeyStore.ThumbnailPage, -1); }
componentDidMount() {
this._reactionDisposer = reaction(
- () => this.curPage,
+ () => [this.curPage, this.thumbnailPage],
() => {
- if (this.curPage && this.initPage) {
+ if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage != this.thumbnailPage) {
this.saveThumbnail();
this._interactive = true;
- } else {
- if (this.curPage > 0)
- this.initPage = true;
}
},
{ fireImmediately: true });
@@ -384,6 +382,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
{ width: me.props.doc.GetNumber(KeyStore.NativeWidth, 0), height: me.props.doc.GetNumber(KeyStore.NativeHeight, 0), quality: 0.5 })
.then(function (dataUrl: string) {
me.props.doc.SetData(KeyStore.Thumbnail, new URL(dataUrl), ImageField);
+ me.props.doc.SetNumber(KeyStore.ThumbnailPage, me.props.doc.GetNumber(KeyStore.CurPage, -1));
})
.catch(function (error: any) {
console.error('oops, something went wrong!', error);
@@ -473,10 +472,10 @@ export class PDFBox extends React.Component<FieldViewProps> {
@computed
get imageProxyRenderer() {
- let field = this.props.doc.Get(KeyStore.Thumbnail);
- if (field) {
- let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
- field instanceof ImageField ? field.Data.href : "http://cs.brown.edu/people/bcz/prairie.jpg";
+ let thumbField = this.props.doc.Get(KeyStore.Thumbnail);
+ if (thumbField) {
+ let path = thumbField == FieldWaiting || this.thumbnailPage != this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
+ thumbField instanceof ImageField ? thumbField.Data.href : "http://cs.brown.edu/people/bcz/prairie.jpg";
return <img src={path} width="100%" />;
}
return (null);
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 09ae95183..7c0db83a8 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,23 +1,27 @@
import React = require("react")
import { observer } from "mobx-react";
-import { FieldWaiting } from '../../../fields/Field';
+import { FieldWaiting, Opt } from '../../../fields/Field';
import { VideoField } from '../../../fields/VideoField';
import { FieldView, FieldViewProps } from './FieldView';
import "./VideoBox.scss";
import Measure from "react-measure";
-import { action, trace, observable } from "mobx";
+import { action, trace, observable, IReactionDisposer, computed, reaction } from "mobx";
import { KeyStore } from "../../../fields/KeyStore";
import { number } from "prop-types";
@observer
export class VideoBox extends React.Component<FieldViewProps> {
+ private _reactionDisposer: Opt<IReactionDisposer>;
+ private _videoRef = React.createRef<HTMLVideoElement>()
public static LayoutString() { return FieldView.LayoutString(VideoBox) }
constructor(props: FieldViewProps) {
super(props);
}
+ @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, -1); }
+
_loaded: boolean = false;
@@ -39,7 +43,17 @@ export class VideoBox extends React.Component<FieldViewProps> {
}
}
+ get player(): HTMLVideoElement | undefined {
+ return this._videoRef.current ? this._videoRef.current.getElementsByTagName("video")[0] : undefined;
+ }
+ @action
+ setVideoRef = (vref: HTMLVideoElement | null) => {
+ if (this.curPage >= 0 && vref) {
+ vref!.currentTime = this.curPage;
+ (vref! as any).AHackBecauseSomethingResetsTheVideoToZero = this.curPage;
+ }
+ }
render() {
let field = this.props.doc.GetT(this.props.fieldKey, VideoField);
@@ -47,15 +61,16 @@ export class VideoBox extends React.Component<FieldViewProps> {
return <div>Loading</div>
}
let path = field.Data.href;
-
- //setTimeout(action(() => this._loaded = true), 500);
+ trace();
return (
<Measure onResize={this.setScaling}>
{({ measureRef }) =>
- <video className="videobox-cont" onClick={() => { }} ref={measureRef}>
- <source src={path} type="video/mp4" />
- Not supported.
+ <div style={{ width: "100%", height: "auto" }} ref={measureRef}>
+ <video className="videobox-cont" onClick={() => { }} ref={this.setVideoRef}>
+ <source src={path} type="video/mp4" />
+ Not supported.
</video>
+ </div>
}
</Measure>
)
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index 611e2951b..f9684b212 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -36,7 +36,9 @@ export namespace KeyStore {
export const LinkDescription = new Key("LinkDescription");
export const LinkTags = new Key("LinkTag");
export const Thumbnail = new Key("Thumbnail");
+ export const ThumbnailPage = new Key("ThumbnailPage");
export const CurPage = new Key("CurPage");
+ export const AnnotationOn = new Key("AnnotationOn");
export const NumPages = new Key("NumPages");
export const Ink = new Key("Ink");
export const Cursors = new Key("Cursors");