aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/VideoBox.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-05-15 10:55:17 -0400
committerbobzel <zzzman@gmail.com>2024-05-15 10:55:17 -0400
commit213e5c5ab7dcb7a92a2d6c0e2ca10433ddc3141f (patch)
tree01a4c5501ce4e6ce8fb74c4a64acb6bc77c5562e /src/client/views/nodes/VideoBox.tsx
parentc329d7719ed60d71bec4a8ac7309e33081c3373c (diff)
parent0b1d434ad7f0d057456631ac786ed338c84a7f41 (diff)
merged with new eslint code
Diffstat (limited to 'src/client/views/nodes/VideoBox.tsx')
-rw-r--r--src/client/views/nodes/VideoBox.tsx246
1 files changed, 145 insertions, 101 deletions
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 4773a21c9..fe7600fa3 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,36 +1,36 @@
+/* eslint-disable jsx-a11y/media-has-caption */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { basename } from 'path';
import * as React from 'react';
+import { ClientUtils, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents } from '../../../ClientUtils';
import { Doc, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, NumCast, StrCast, toList } from '../../../fields/Types';
import { AudioField, ImageField, VideoField } from '../../../fields/URLField';
-import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
-import { Docs, DocUtils } from '../../documents/Documents';
+import { emptyFunction, formatTime } from '../../../Utils';
+import { Docs } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
-import { DocumentManager } from '../../util/DocumentManager';
-import { dropActionType } from '../../util/DragManager';
-import { FollowLinkScript } from '../../util/LinkFollower';
-import { LinkManager } from '../../util/LinkManager';
-import { ReplayMovements } from '../../util/ReplayMovements';
+import { DocUtils, FollowLinkScript } from '../../documents/DocUtils';
+import { dropActionType } from '../../util/DropActionTypes';
import { undoBatch } from '../../util/UndoManager';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { VideoThumbnails } from '../global/globalEnums';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
import { AnchorMenu } from '../pdf/AnchorMenu';
-import { StyleProp } from '../StyleProvider';
+import { PinDocView, PinProps } from '../PinFuncs';
+import { StyleProp } from '../StyleProp';
import { DocumentView } from './DocumentView';
-import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView';
-import { RecordingBox } from './RecordingBox';
-import { PinProps, PresBox } from './trails';
+import { FieldView, FieldViewProps } from './FieldView';
+import { FocusViewOptions } from './FocusViewOptions';
import './VideoBox.scss';
/**
@@ -46,12 +46,11 @@ import './VideoBox.scss';
*/
@observer
-export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
+export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(VideoBox, fieldKey);
}
static heightPercent = 80; // height of video relative to videoBox when timeline is open
- static numThumbnails = 20;
private unmounting = false;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _videoRef: HTMLVideoElement | null = null; // <video> ref
@@ -62,6 +61,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
private _playRegionTimer: any = null; // timeout for playback
private _controlsFadeTimer: any = null; // timeout for controls fade
+ private _ffref = React.createRef<CollectionFreeFormView>();
constructor(props: FieldViewProps) {
super(props);
@@ -84,7 +84,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
@observable _scrubbing: boolean = false;
@computed get links() {
- return LinkManager.Links(this.dataDoc);
+ return Doc.Links(this.dataDoc);
}
@computed get heightPercent() {
return NumCast(this.layoutDoc._layout_timelineHeightPercent, 100);
@@ -99,18 +99,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
return field?.url.href ?? vfield?.url.href ?? '';
}
- // returns the presentation data if it exists, null otherwise
- @computed get presentation() {
- const data = this.dataDoc[this.fieldKey + '_presentation'];
- return data ? JSON.parse(StrCast(data)) : null;
- }
-
@computed private get timeline() {
return this._stackedTimeline;
}
private get transition() {
return this._clicking ? 'left 0.5s, width 0.5s, height 0.5s' : '';
} // css transition for hiding/showing timeline
+
public get player(): HTMLVideoElement | null {
return this._videoRef;
}
@@ -120,10 +115,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
this._props.setContentViewBox?.(this); // this tells the DocumentView that this VideoBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the VideoBox when making a link.
this.player && this.setPlayheadTime(this.timeline?.clipStart || 0);
document.addEventListener('keydown', this.keyEvents, true);
-
- if (this.presentation) {
- ReplayMovements.Instance.setVideoBox(this);
- }
}
componentWillUnmount() {
@@ -132,12 +123,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
this.Pause();
Object.keys(this._disposers).forEach(d => this._disposers[d]?.());
document.removeEventListener('keydown', this.keyEvents, true);
-
- if (this.presentation) {
- ReplayMovements.Instance.removeVideoBox();
- }
}
+ override PlayerTime = () => this.player?.currentTime;
+ override Pause = (update: boolean = true) => {
+ this.pause(update);
+ !this._keepCurrentlyPlaying && this.removeCurrentlyPlaying();
+ };
+
// handles key events, when timeline scrubs fade controls
@action
keyEvents = (e: KeyboardEvent) => {
@@ -152,11 +145,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
clearTimeout(this._controlsFadeTimer);
this._scrubbing = true;
this._controlsFadeTimer = setTimeout(
- action(() => (this._scrubbing = false)),
+ action(() => {
+ this._scrubbing = false;
+ }),
500
);
e.stopPropagation();
break;
+ default:
}
}
};
@@ -203,7 +199,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
else {
this._keepCurrentlyPlaying = true;
this.pause();
- setTimeout(() => (this._keepCurrentlyPlaying = false));
+ setTimeout(() => {
+ this._keepCurrentlyPlaying = false;
+ });
}
};
@@ -223,10 +221,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
}
this._playRegionTimer = undefined;
};
- @action Pause = (update: boolean = true) => {
- this.pause(update);
- !this._keepCurrentlyPlaying && this.removeCurrentlyPlaying();
- };
// toggles video full screen
@action public FullScreen = () => {
@@ -246,7 +240,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
clearTimeout(this._controlsFadeTimer);
this._controlsVisible = true;
this._controlsFadeTimer = setTimeout(
- action(() => (this._controlsVisible = false)),
+ action(() => {
+ this._controlsVisible = false;
+ }),
3000
);
}
@@ -262,7 +258,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
setupMoveUpEvents(
e.target,
e,
- action((e, down, delta) => {
+ action((moveEv, down, delta) => {
if (this._controlsTransform) {
this._controlsTransform.X = Math.max(0, Math.min(delta[0] + this._controlsTransform.X, window.innerWidth));
this._controlsTransform.Y = Math.max(0, Math.min(delta[1] + this._controlsTransform.Y, window.innerHeight));
@@ -280,7 +276,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
const canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = (640 * Doc.NativeHeight(this.layoutDoc)) / (Doc.NativeWidth(this.layoutDoc) || 1);
- const ctx = canvas.getContext('2d'); //draw image to canvas. scale to target dimensions
+ const ctx = canvas.getContext('2d'); // draw image to canvas. scale to target dimensions
if (ctx) {
this._videoRef && ctx.drawImage(this._videoRef, 0, 0, canvas.width, canvas.height);
}
@@ -297,13 +293,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
this._props.addDocument?.(b);
DocUtils.MakeLink(b, this.Document, { link_relationship: 'video snapshot' });
} else {
- //convert to desired file format
+ // convert to desired file format
const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png'
// if you want to preview the captured image,
- const retitled = StrCast(this.Document.title).replace(/[ -\.:]/g, '');
- const encodedFilename = encodeURIComponent(('snapshot' + retitled + '_' + (this.layoutDoc._layout_currentTimecode || 0).toString()).replace(/[\.\/\?\=]/g, '_'));
+ const retitled = StrCast(this.Document.title).replace(/[ -.:]/g, '');
+ const encodedFilename = encodeURIComponent(('snapshot' + retitled + '_' + (this.layoutDoc._layout_currentTimecode || 0).toString()).replace(/[./?=]/g, '_'));
const filename = basename(encodedFilename);
- Utils.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createSnapshotLink)(returnedFilename, downX, downY));
+ ClientUtils.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createSnapshotLink)(returnedFilename, downX, downY));
}
};
@@ -318,7 +314,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
// creates link for snapshot
createSnapshotLink = (imagePath: string, downX?: number, downY?: number) => {
- const url = !imagePath.startsWith('/') ? Utils.CorsProxy(imagePath) : imagePath;
+ const url = !imagePath.startsWith('/') ? ClientUtils.CorsProxy(imagePath) : imagePath;
const width = NumCast(this.layoutDoc._width) || 1;
const height = NumCast(this.layoutDoc._height);
const imageSnapshot = Docs.Create.ImageDocument(url, {
@@ -334,9 +330,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
Doc.SetNativeWidth(imageSnapshot[DocData], Doc.NativeWidth(this.layoutDoc));
Doc.SetNativeHeight(imageSnapshot[DocData], Doc.NativeHeight(this.layoutDoc));
this._props.addDocument?.(imageSnapshot);
- const link = DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' });
+ DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' });
// link && (DocCast(link.link_anchor_2)[DocData].timecodeToHide = NumCast(DocCast(link.link_anchor_2).timecodeToShow) + 3); // do we need to set an end time? should default to +0.1
- setTimeout(() => downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, dropActionType.move, true));
+ setTimeout(() => downX !== undefined && downY !== undefined && DocumentView.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, dropActionType.move, true));
};
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
@@ -345,9 +341,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
if (!addAsAnnotation && marquee) marquee.backgroundColor = 'transparent';
const anchor =
addAsAnnotation && marquee
- ? CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.annotationKey, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || this.Document
+ ? CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.annotationKey, timecode || undefined, undefined, marquee, addAsAnnotation) || this.Document
: Docs.Create.ConfigDocument({ title: '#' + timecode, _timecodeToShow: timecode, annotationOn: this.Document });
- PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true, pannable: true } }, this.Document);
+ PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true, pannable: true } }, this.Document);
return anchor;
};
@@ -375,12 +371,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
if (this._stackedTimeline?.makeDocUnfiltered(doc)) {
if (this.heightPercent === 100) {
// do we want to always open up the timeline when followin a link? kind of clunky visually
- //this.layoutDoc._layout_timelineHeightPercent = VideoBox.heightPercent;
+ // this.layoutDoc._layout_timelineHeightPercent = VideoBox.heightPercent;
options.didMove = true;
}
return this._stackedTimeline.getView(doc, options);
}
- return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
+ return new Promise<Opt<DocumentView>>(res => {
+ DocumentView.addViewRenderedCb(doc, dv => res(dv));
+ });
};
// extracts video thumbnails and saves them as field of doc
@@ -390,21 +388,25 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
const thumbnailPromises: Promise<any>[] = [];
const video = document.createElement('video');
- video.onloadedmetadata = () => (video.currentTime = 0);
+ video.onloadedmetadata = () => {
+ video.currentTime = 0;
+ };
video.onseeked = () => {
const canvas = document.createElement('canvas');
canvas.height = 100;
canvas.width = 100;
canvas.getContext('2d')?.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, 100, 100);
- const retitled = StrCast(this.Document.title).replace(/[ -\.:]/g, '');
+ const retitled = StrCast(this.Document.title).replace(/[ -.:]/g, '');
const encodedFilename = encodeURIComponent('thumbnail' + retitled + '_' + video.currentTime.toString().replace(/\./, '_'));
- thumbnailPromises?.push(Utils.convertDataUri(canvas.toDataURL(), basename(encodedFilename), true));
- const newTime = video.currentTime + video.duration / (VideoBox.numThumbnails - 1);
+ thumbnailPromises?.push(ClientUtils.convertDataUri(canvas.toDataURL(), basename(encodedFilename), true));
+ const newTime = video.currentTime + video.duration / (VideoThumbnails.DENSE - 1);
if (newTime < video.duration) {
video.currentTime = newTime;
} else {
- Promise.all(thumbnailPromises).then(thumbnails => (this.dataDoc[this.fieldKey + '_thumbnails'] = new List<string>(thumbnails)));
+ Promise.all(thumbnailPromises).then(thumbnails => {
+ this.dataDoc[this.fieldKey + '_thumbnails'] = new List<string>(thumbnails);
+ });
}
};
@@ -423,11 +425,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
this._disposers.reactionDisposer?.();
this._disposers.reactionDisposer = reaction(
() => NumCast(this.layoutDoc._layout_currentTimecode),
- time => !this._playing && (vref.currentTime = time),
+ time => {
+ !this._playing && (vref.currentTime = time);
+ },
{ fireImmediately: true }
);
- (!this.dataDoc[this.fieldKey + '_thumbnails'] || StrListCast(this.dataDoc[this.fieldKey + '_thumbnails']).length != VideoBox.numThumbnails) && this.getVideoThumbnails();
+ (!this.dataDoc[this.fieldKey + '_thumbnails'] || StrListCast(this.dataDoc[this.fieldKey + '_thumbnails']).length !== VideoThumbnails.DENSE) && this.getVideoThumbnails();
}
};
@@ -436,7 +440,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
setContentRef = (cref: HTMLDivElement | null) => {
this._contentRef = cref;
if (cref) {
- cref.onfullscreenchange = action(e => {
+ cref.onfullscreenchange = action(() => {
this._fullScreen = document.fullscreenElement === cref;
this._controlsVisible = true;
this._scrubbing = false;
@@ -451,7 +455,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
};
// context menu
- specificContextMenu = (e: React.MouseEvent): void => {
+ specificContextMenu = (): void => {
const field = Cast(this.dataDoc[this._props.fieldKey], VideoField);
if (field) {
const url = field.url.href;
@@ -462,34 +466,50 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
subitems.push({
description: 'Screen Capture',
event: async () => {
- runInAction(() => (this._screenCapture = !this._screenCapture));
+ runInAction(() => {
+ this._screenCapture = !this._screenCapture;
+ });
this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
},
icon: 'expand-arrows-alt',
});
- subitems.push({ description: (this.layoutDoc.dontAutoFollowLinks ? '' : "Don't") + ' follow links when encountered', event: () => (this.layoutDoc.dontAutoFollowLinks = !this.layoutDoc.dontAutoFollowLinks), icon: 'expand-arrows-alt' });
+ subitems.push({
+ description: (this.layoutDoc.dontAutoFollowLinks ? '' : "Don't") + ' follow links when encountered',
+ event: () => {
+ this.layoutDoc.dontAutoFollowLinks = !this.layoutDoc.dontAutoFollowLinks;
+ },
+ icon: 'expand-arrows-alt',
+ });
subitems.push({
description: (this.layoutDoc.dontAutoPlayFollowedLinks ? '' : "Don't") + ' play when link is selected',
- event: () => (this.layoutDoc.dontAutoPlayFollowedLinks = !this.layoutDoc.dontAutoPlayFollowedLinks),
+ event: () => {
+ this.layoutDoc.dontAutoPlayFollowedLinks = !this.layoutDoc.dontAutoPlayFollowedLinks;
+ },
+ icon: 'expand-arrows-alt',
+ });
+ subitems.push({
+ description: (this.layoutDoc.autoPlayAnchors ? "Don't auto play" : 'Auto play') + ' anchors onClick',
+ event: () => {
+ this.layoutDoc.autoPlayAnchors = !this.layoutDoc.autoPlayAnchors;
+ },
icon: 'expand-arrows-alt',
});
- subitems.push({ description: (this.layoutDoc.autoPlayAnchors ? "Don't auto play" : 'Auto play') + ' anchors onClick', event: () => (this.layoutDoc.autoPlayAnchors = !this.layoutDoc.autoPlayAnchors), icon: 'expand-arrows-alt' });
// subitems.push({ description: "Start Trim All", event: () => this.startTrim(TrimScope.All), icon: "expand-arrows-alt" });
// subitems.push({ description: "Start Trim Clip", event: () => this.startTrim(TrimScope.Clip), icon: "expand-arrows-alt" });
// subitems.push({ description: "Stop Trim", event: () => this.finishTrim(), icon: "expand-arrows-alt" });
subitems.push({
description: 'Copy path',
event: () => {
- Utils.CopyText(url);
+ ClientUtils.CopyText(url);
},
icon: 'expand-arrows-alt',
});
// if the videobox was turned from a recording box
- if (this.dataDoc[this.fieldKey + '_recorded'] === true) {
+ if (this.dataDoc[this.fieldKey + '_recorded']) {
subitems.push({
description: 'Recreate recording',
event: () => {
- this.dataDoc.layout = RecordingBox.LayoutString(this.fieldKey);
+ this.dataDoc.layout = StrCast(this.dataDoc[this.fieldKey + '_recorded']); // restore the saed recording layout
// delete assoicated video data
this.dataDoc[this._props.fieldKey] = '';
this.dataDoc[this.fieldKey + '_duration'] = '';
@@ -504,7 +524,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
};
// ref for updating time
- setAudioRef = (e: HTMLAudioElement | null) => (this._audioPlayer = e);
+ setAudioRef = (e: HTMLAudioElement | null) => {
+ this._audioPlayer = e;
+ };
// renders the video and audio
@computed get content() {
@@ -570,8 +592,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
setupMoveUpEvents(
this,
e,
- e => {
- this.Snapshot(e.clientX, e.clientY);
+ moveEv => {
+ this.Snapshot(moveEv.clientX, moveEv.clientY);
return true;
},
emptyFunction,
@@ -586,7 +608,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
setupMoveUpEvents(
this,
e,
- action(encodeURIComponent => {
+ action(() => {
this._clicking = false;
if (this._props.isContentActive()) {
// const local = this.ScreenToLocalTransform().scale(this._props.scaling?.() || 1).transformPoint(e.clientX, e.clientY);
@@ -600,7 +622,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
() => {
this.layoutDoc._layout_timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent;
setTimeout(
- action(() => (this._clicking = false)),
+ action(() => {
+ this._clicking = false;
+ }),
500
);
},
@@ -613,30 +637,32 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
@action
removeCurrentlyPlaying = () => {
const docView = this.DocumentView?.();
- if (CollectionStackedTimeline.CurrentlyPlaying && docView) {
- const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView);
- index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1);
+ if (DocumentView.CurrentlyPlaying && docView) {
+ const index = DocumentView.CurrentlyPlaying.indexOf(docView);
+ index !== -1 && DocumentView.CurrentlyPlaying.splice(index, 1);
}
};
// adds doc to currently playing display
@action
addCurrentlyPlaying = () => {
const docView = this.DocumentView?.();
- if (!CollectionStackedTimeline.CurrentlyPlaying) {
- CollectionStackedTimeline.CurrentlyPlaying = [];
+ if (!DocumentView.CurrentlyPlaying) {
+ DocumentView.CurrentlyPlaying = [];
}
- if (docView && CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView) === -1) {
- CollectionStackedTimeline.CurrentlyPlaying.push(docView);
+ if (docView && DocumentView.CurrentlyPlaying.indexOf(docView) === -1) {
+ DocumentView.CurrentlyPlaying.push(docView);
}
};
// for annotating, adds doc with time info
@action.bound
- addDocWithTimecode(doc: Doc | Doc[]): boolean {
- const docs = doc instanceof Doc ? [doc] : doc;
+ addDocWithTimecode(docIn: Doc | Doc[]): boolean {
+ const docs = toList(docIn);
const curTime = NumCast(this.layoutDoc._layout_currentTimecode);
- docs.forEach(doc => (doc._timecodeToHide = (doc._timecodeToShow = curTime) + 1));
- return this.addDocument(doc);
+ docs.forEach(doc => {
+ doc._timecodeToHide = (doc._timecodeToShow = curTime) + 1;
+ });
+ return this.addDocument(docs);
}
// play back the audio from seekTimeInSeconds, fullPlay tells whether clip is being played to end vs link range
@@ -644,7 +670,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
playFrom = (seekTimeInSeconds: number, endTime?: number, fullPlay: boolean = false) => {
clearTimeout(this._playRegionTimer);
this._playRegionTimer = undefined;
- if (Number.isNaN(this.player?.duration)) {
+ if (this.player?.duration === undefined || isNaN(this.player.duration)) {
setTimeout(() => this.playFrom(seekTimeInSeconds, endTime), 500);
} else if (this.player) {
// trimBounds override requested playback bounds
@@ -696,7 +722,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
e,
returnFalse,
returnFalse,
- action((e: PointerEvent, doubleTap?: boolean) => {
+ action((clickEv: PointerEvent, doubleTap?: boolean) => {
if (doubleTap) {
this.startTrim(TrimScope.All);
} else if (this.timeline) {
@@ -731,11 +757,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
// stretches vertically or horizontally depending on video orientation so video fits full screen
fullScreenSize() {
if (this._videoRef && this._videoRef.videoHeight / this._videoRef.videoWidth > 1) {
- //prettier-ignore
- return ({ height: '100%' });
+ return { height: '100%' };
}
- //prettier-ignore
- return ({ width: '100%' });
+ return ({ width: '100%' }); // prettier-ignore
}
// for zoom slider, sets timeline waveform zoom
@@ -757,9 +781,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
setupMoveUpEvents(
this,
e,
- action(e => {
+ action(moveEv => {
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
- this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]);
+ this._marqueeref.current?.onInitiateSelection([moveEv.clientX, moveEv.clientY]);
return true;
}),
returnFalse,
@@ -777,7 +801,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
this._props.select(true);
};
- timelineWhenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
+ timelineWhenChildContentsActiveChanged = action((isActive: boolean) => {
+ this._isAnyChildContentActive = isActive;
+ this._props.whenChildContentsActiveChanged(isActive);
+ });
timelineScreenToLocal = () =>
this._props
@@ -785,7 +812,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
.scale(this.scaling())
.translate(0, (-this.heightPercent / 100) * this._props.PanelHeight());
- setPlayheadTime = (time: number) => (this.player!.currentTime = this.layoutDoc._layout_currentTimecode = time);
+ setPlayheadTime = (time: number) => {
+ this.player!.currentTime = this.layoutDoc._layout_currentTimecode = time;
+ };
timelineHeight = () => (this._props.PanelHeight() * (100 - this.heightPercent)) / 100;
@@ -806,7 +835,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0];
- timelineDocFilter = () => [`_isTimelineLabel:true,${Utils.noRecursionHack}:x`];
+ timelineDocFilter = () => [`_isTimelineLabel:true,${ClientUtils.noRecursionHack}:x`];
// renders video controls
componentUI = (boundsLeft: number, boundsTop: number) => {
@@ -848,7 +877,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
return (
<div className="videoBox-stackPanel" style={{ transition: this.transition, height: `${100 - this.heightPercent}%`, display: this.heightPercent === 100 ? 'none' : '' }}>
<CollectionStackedTimeline
- ref={action((r: any) => (this._stackedTimeline = r))}
+ ref={action((r: any) => {
+ this._stackedTimeline = r;
+ })}
+ // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
dataFieldKey={this.fieldKey}
fieldKey={this.annotationKey}
@@ -886,7 +918,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
}
crop = (region: Doc | undefined, addCrop?: boolean) => {
- if (!region) return;
+ if (!region) return undefined;
const cropping = Doc.MakeCopy(region, true);
const regionData = region[DocData];
regionData.backgroundColor = 'transparent';
@@ -915,8 +947,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
croppingProto.type = DocumentType.VID;
croppingProto.layout = VideoBox.LayoutString('data');
croppingProto.data = ObjectField.MakeCopy(this.dataDoc[this.fieldKey] as ObjectField);
- croppingProto['data_nativeWidth'] = anchw;
- croppingProto['data_nativeHeight'] = anchh;
+ croppingProto.data_nativeWidth = anchw;
+ croppingProto.data_nativeHeight = anchh;
croppingProto.videoCrop = true;
croppingProto.layout_currentTimecode = this.layoutDoc._layout_currentTimecode;
croppingProto.freeform_scale = viewScale;
@@ -933,6 +965,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
this._props.bringToFront?.(cropping);
return cropping;
};
+ focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
savedAnnotations = () => this._savedAnnotations;
render() {
const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding);
@@ -958,14 +991,16 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
left: (this._props.PanelWidth() - this.panelWidth()) / 2,
}}>
<CollectionFreeFormView
+ // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
+ ref={this._ffref}
setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
renderDepth={this._props.renderDepth + 1}
fieldKey={this.annotationKey}
- isAnnotationOverlay={true}
- annotationLayerHostsContent={true}
+ isAnnotationOverlay
+ annotationLayerHostsContent
PanelWidth={this._props.PanelWidth}
PanelHeight={this._props.PanelHeight}
isAnyChildContentActive={returnFalse}
@@ -1049,12 +1084,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
</div>
)}
- <div className="videobox-button" title={'full screen'} onPointerDown={this.onFullDown}>
+ <div className="videobox-button" title="full screen" onPointerDown={this.onFullDown}>
<FontAwesomeIcon icon="expand" />
</div>
{!this._fullScreen && width > 300 && (
- <div className="videobox-button" title={'show timeline'} onPointerDown={this.onTimelineHdlDown}>
+ <div className="videobox-button" title="show timeline" onPointerDown={this.onTimelineHdlDown}>
<FontAwesomeIcon icon="eye" />
</div>
)}
@@ -1113,3 +1148,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
);
}
}
+
+Docs.Prototypes.TemplateMap.set(DocumentType.VID, {
+ layout: { view: VideoBox, dataField: 'data' },
+ options: { acl: '', _layout_currentTimecode: 0, systemIcon: 'BsFileEarmarkPlayFill' },
+});
+Docs.Prototypes.TemplateMap.set(DocumentType.REC, {
+ layout: { view: VideoBox, dataField: 'data' },
+ options: { acl: '', _height: 100, backgroundColor: 'pink', systemIcon: 'BsFillMicFill' },
+});