aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-01-04 13:11:22 -0500
committerbobzel <zzzman@gmail.com>2024-01-04 13:11:22 -0500
commitae27dd1689ae1716591aab094e6d41f3a0160fef (patch)
tree09735c798abde4fd0b8f234c48375bd6cb1112a4 /src
parentebf32ac65d35053f847fb2cf60f915eb29d6fdd5 (diff)
fixed ffmpeg for uploading videos. fixed getView() to take focus options so that if a sidebar or timeline has to be opened, the didMove flag can be set properly. added video snapshot frame to top menu. fixed using '^' to stop and start a selection region on timelines.
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/util/CurrentUserUtils.ts12
-rw-r--r--src/client/util/DocumentManager.ts2
-rw-r--r--src/client/util/PingManager.ts20
-rw-r--r--src/client/views/GlobalKeyHandler.ts8
-rw-r--r--src/client/views/UndoStack.tsx10
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx40
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx4
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx2
-rw-r--r--src/client/views/global/globalScripts.ts11
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx9
-rw-r--r--src/client/views/nodes/DocumentView.tsx9
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx9
-rw-r--r--src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx9
-rw-r--r--src/client/views/nodes/PDFBox.tsx7
-rw-r--r--src/client/views/nodes/VideoBox.scss6
-rw-r--r--src/client/views/nodes/VideoBox.tsx158
-rw-r--r--src/client/views/nodes/WebBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx7
-rw-r--r--src/server/DashUploadUtils.ts15
21 files changed, 129 insertions, 215 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 79285deb5..92a9ddfe8 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -209,7 +209,7 @@ export class DocumentOptions {
author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable
author_date?: DATEt = new DateInfo('date the document was created', true);
annotationOn?: DOCt = new DocInfo('document annotated by this document', false);
- embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false);
+ _embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false);
rootDocument?: DOCt = new DocInfo('document that supplies the information needed for a rendering template (eg, pres slide for PresElement)');
color?: STRt = new StrInfo('foreground color data doc', false);
hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3f28f44fc..4391e87d6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -309,7 +309,7 @@ export class CurrentUserUtils {
{ toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
{ toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} },
{ toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '<ScriptingRepl />' as any, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script
- // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "<UndoStack>" as any, openFactoryLocation: OpenWhere.overlay},
+ // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "<UndoStack />" as any, openFactoryLocation: OpenWhere.overlay},
].map(tuple => (
{ openFactoryLocation: OpenWhere.addRight,
scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)',
@@ -695,11 +695,16 @@ export class CurrentUserUtils {
static webTools() {
return [
- { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", scripts: { onClick: '{ return webBack(_readOnly_); }' }},
- { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", scripts: { onClick: '{ return webForward(_readOnly_); }'}},
+ { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", scripts: { onClick: '{ return webBack(); }' }},
+ { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", scripts: { onClick: '{ return webForward(); }'}},
{ title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, scripts: { script: '{ return webSetURL(value, _readOnly_); }'} },
];
}
+ static videoTools() {
+ return [
+ { title: "Snapshot",toolTip: "Take snapshot of current frame", btnType: ButtonType.ClickButton, icon: "camera", scripts: { onClick: '{ return videoSnapshot(); }' }},
+ ];
+ }
static contextMenuTools():Button[] {
return [
{ btnList: new List<string>([CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree,
@@ -721,6 +726,7 @@ export class CurrentUserUtils {
{ title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
{ title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
{ title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
+ { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
{ title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected
];
}
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 0fab42895..7fef5cc79 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -281,7 +281,7 @@ export class DocumentManager {
docContextPath.shift();
const childViewIterator = async (docView: DocumentView) => {
const innerDoc = docContextPath.shift();
- return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined };
+ return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc, options)) ?? this.getDocumentView(innerDoc) : undefined };
};
if (rootContextView) {
diff --git a/src/client/util/PingManager.ts b/src/client/util/PingManager.ts
index 865f8bc02..7638e2ce0 100644
--- a/src/client/util/PingManager.ts
+++ b/src/client/util/PingManager.ts
@@ -4,11 +4,20 @@ import { CurrentUserUtils } from './CurrentUserUtils';
export class PingManager {
// create static instance and getter for global use
@observable static _instance: PingManager;
+ @observable IsBeating = true;
static get Instance(): PingManager {
return PingManager._instance;
}
- @observable IsBeating = true;
+ // not used now, but may need to clear interval
+ private _interval: NodeJS.Timeout | null = null;
+ INTERVAL_SECONDS = 1;
+ constructor() {
+ makeObservable(this);
+ PingManager._instance = this;
+ this._interval = setInterval(this.sendPing, this.INTERVAL_SECONDS * 1000);
+ }
+
private setIsBeating = action((status: boolean) => {
this.IsBeating = status;
setTimeout(this.showAlert, 100);
@@ -28,13 +37,4 @@ export class PingManager {
}
}
};
-
- // not used now, but may need to clear interval
- private _interval: NodeJS.Timeout | null = null;
- INTERVAL_SECONDS = 1;
- constructor() {
- makeObservable(this);
- PingManager._instance = this;
- this._interval = setInterval(this.sendPing, this.INTERVAL_SECONDS * 1000);
- }
}
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 77b831e51..d134d9e7b 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -128,10 +128,12 @@ export class KeyManager {
var doDeselect = true;
if (SnappingManager.IsDragging) {
DragManager.AbortDrag();
- } else if (CollectionDockingView.Instance?.HasFullScreen) {
+ }
+ if (CollectionDockingView.Instance?.HasFullScreen) {
CollectionDockingView.Instance?.CloseFullScreen();
- } else if (CollectionStackedTimeline.SelectingRegion) {
- CollectionStackedTimeline.SelectingRegion = undefined;
+ }
+ if (CollectionStackedTimeline.SelectingRegions.size) {
+ CollectionStackedTimeline.StopSelecting();
doDeselect = false;
} else {
doDeselect = !ContextMenu.Instance.closeMenu();
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index ea038250e..068143225 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -8,19 +8,13 @@ import { SettingsManager } from '../util/SettingsManager';
import { UndoManager } from '../util/UndoManager';
import './UndoStack.scss';
-interface UndoStackProps {
- width?: number;
- height?: number;
- inline?: boolean;
-}
+interface UndoStackProps {}
@observer
export class UndoStack extends React.Component<UndoStackProps> {
- @observable static HideInline: boolean = false;
- @observable static Expand: boolean = false;
render() {
const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userVariantColor;
const color = UndoManager.batchCounter.get() ? 'black' : SettingsManager.userColor;
- return this.props.inline && UndoStack.HideInline ? null : (
+ return (
<Tooltip title={'undo stack (if it stays yellow, undo is broken - you should reload Dash)'}>
<div>
<div className="undoStack-outerContainer">
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c46f54c70..874cdffd9 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -615,7 +615,7 @@ ScriptingGlobals.add(
// prettier-ignore
switch (doc) {
case '<ScriptingRepl />': return OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
- case "<UndoStack>": return OverlayView.Instance.addWindow(<UndoStack />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
+ case "<UndoStack />": return OverlayView.Instance.addWindow(<UndoStack />, { x: 300, y: 100, width: 200, height: 200, title: 'Undo stack' });
}
Doc.AddToMyOverlay(doc);
}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index d99b4f9de..22a67c501 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -56,8 +56,11 @@ export enum TrimScope {
@observer
export class CollectionStackedTimeline extends CollectionSubView<CollectionStackedTimelineProps>() {
- @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined;
- @observable public static CurrentlyPlaying: DocumentView[] = [];
+ public static SelectingRegions: Set<CollectionStackedTimeline> = new Set();
+ public static StopSelecting() {
+ this.SelectingRegions.forEach(action(region => (region._selectingRegion = false)));
+ this.SelectingRegions.clear();
+ }
constructor(props: any) {
super(props);
makeObservable(this);
@@ -69,6 +72,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
private _timeline: HTMLDivElement | null = null; // ref to actual timeline div
private _timelineWrapper: HTMLDivElement | null = null; // ref to timeline wrapper div for zooming and scrolling
private _markerStart: number = 0;
+ @observable public static CurrentlyPlaying: DocumentView[] = [];
+ @observable _selectingRegion = false;
@observable _markerEnd: number | undefined = undefined;
@observable _trimming: number = TrimScope.None;
@observable _trimStart: number = 0; // trim controls start pos
@@ -123,8 +128,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
componentWillUnmount() {
document.removeEventListener('keydown', this.keyEvents, true);
- if (CollectionStackedTimeline.SelectingRegion === this) {
- runInAction(() => (CollectionStackedTimeline.SelectingRegion = undefined));
+ if (this._selectingRegion) {
+ runInAction(() => (this._selectingRegion = false));
+ CollectionStackedTimeline.SelectingRegions.delete(this);
}
}
@@ -154,6 +160,15 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._zoomFactor = zoom;
}
+ makeDocUnfiltered = (doc: Doc) => this.childDocList?.some(item => item === doc);
+
+ getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> =>
+ new Promise<Opt<DocumentView>>(res => {
+ if (doc.hidden) options.didMove = !(doc.hidden = false);
+ const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
+ findDoc(dv => res(dv));
+ });
+
anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this._props.startTag]));
anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this._props.endTag], val) ?? null);
@@ -191,14 +206,16 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._props.playing() ? this._props.Pause() : this._props.Play();
break;
case '^':
- if (!CollectionStackedTimeline.SelectingRegion) {
+ if (!this._selectingRegion) {
this._markerStart = this._markerEnd = this.currentTime;
- CollectionStackedTimeline.SelectingRegion = this;
+ this._selectingRegion = true;
+ CollectionStackedTimeline.SelectingRegions.add(this);
} else {
this._markerEnd = this.currentTime;
CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this._props.fieldKey, this._markerStart, this._markerEnd, undefined, true);
this._markerEnd = undefined;
- CollectionStackedTimeline.SelectingRegion = undefined;
+ this._selectingRegion = false;
+ CollectionStackedTimeline.SelectingRegions.delete(this);
}
e.stopPropagation();
break;
@@ -405,6 +422,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
backgroundColor: 'rgba(128, 128, 128, 0.5)',
layout_hideLinkButton: true,
onClick: FollowLinkScript(),
+ _embedContainer: doc,
annotationOn: doc,
_isTimelineLabel: true,
layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined,
@@ -511,7 +529,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
// renders selection region on timeline
@computed get selectionContainer() {
- const markerEnd = CollectionStackedTimeline.SelectingRegion === this ? this.currentTime : this._markerEnd;
+ const markerEnd = this._selectingRegion ? this.currentTime : this._markerEnd;
return markerEnd === undefined ? null : (
<div
className="collectionStackedTimeline-selector"
@@ -532,9 +550,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
anchorEndTime: number;
level: number;
}[] = [];
- const drawAnchors = this.childDocs.map(anchor => ({
- level: this.getLevel(anchor, overlaps),
- anchor,
+ const drawAnchors = this.childLayoutPairs.map(pair => ({
+ level: this.getLevel(pair.layout, overlaps),
+ anchor: pair.layout,
}));
const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
return this.clipDuration === 0 ? null : (
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a3cedb9a0..8268a47d8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -321,9 +321,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
};
- getView = async (doc: Doc): Promise<Opt<DocumentView>> =>
+ getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> =>
new Promise<Opt<DocumentView>>(res => {
- if (doc.hidden && this._lightboxDoc !== doc) doc.hidden = false;
+ if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false);
const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
findDoc(dv => res(dv));
});
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index f1fb68003..d105b04f7 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -147,7 +147,7 @@ export class CollectionLinearView extends CollectionSubView() {
switch (doc.layout) {
case '<LinkingUI>': return this.getLinkUI();
case '<CurrentlyPlayingUI>': return this.getCurrentlyPlayingUI();
- case '<UndoStack>': return <UndoStack key={doc[Id]} width={200} height={40} inline={true} />;
+ case '<UndoStack>': return <UndoStack />;
case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager /> : null;
}
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 989dd1db0..e57ef4871 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -19,6 +19,7 @@ import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocum
import { DocumentView } from '../nodes/DocumentView';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
import { WebBox } from '../nodes/WebBox';
+import { VideoBox } from '../nodes/VideoBox';
ScriptingGlobals.add(function IsNoneSelected() {
return SelectionManager.Views.length <= 0;
@@ -390,14 +391,16 @@ ScriptingGlobals.add(function webForward(checkResult?: boolean) {
}
selected?.forward();
});
-ScriptingGlobals.add(function webBack(checkResult?: boolean) {
+ScriptingGlobals.add(function webBack() {
const selected = SelectionManager.Views.lastElement()?.ComponentView as WebBox;
- if (checkResult) {
- return selected?.back(checkResult) ? undefined : 'lightGray';
- }
selected?.back();
});
+ScriptingGlobals.add(function videoSnapshot() {
+ const selected = SelectionManager.Views.lastElement()?.ComponentView as VideoBox;
+ selected?.Snapshot();
+});
+
/** Schema
* toggleSchemaPreview
**/
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 76cc010f6..5a55ca764 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -20,7 +20,7 @@ import { SidebarAnnos } from '../../SidebarAnnos';
import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
import { AnchorMenu } from '../../pdf/AnchorMenu';
import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
-import { DocumentView } from '../DocumentView';
+import { DocFocusOptions, DocumentView } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
import './DataVizBox.scss';
@@ -228,8 +228,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
() => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar')
);
};
- getView = async (doc: Doc) => {
- if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar();
+ getView = async (doc: Doc, options: DocFocusOptions) => {
+ if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
+ options.didMove = true;
+ this.toggleSidebar();
+ }
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
};
@computed get sidebarWidthPercent() {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7f1e547e4..6cc61ec62 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -43,7 +43,6 @@ import { GestureOverlay } from '../GestureOverlay';
import { LightboxView } from '../LightboxView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProvider';
-import { UndoStack } from '../UndoStack';
import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView';
import { DocumentLinksButton } from './DocumentLinksButton';
@@ -119,7 +118,7 @@ export interface DocComponentView {
restoreView?: (viewSpec: Doc) => boolean;
scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt<number>; // returns the duration of the focus
brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms)
- getView?: (doc: Doc) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined
+ getView?: (doc: Doc, options: DocFocusOptions) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined
addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox
addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections)
select?: (ctrlKey: boolean, shiftKey: boolean) => void;
@@ -520,11 +519,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
this._longPressSelector = setTimeout(() => {
if (DocumentView.LongPress) {
- if (this.Document.undoIgnoreFields) {
- runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline));
- } else {
- this._props.select(false);
- }
+ this._props.select(false);
}
}, 1000);
if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._props.DocumentView();
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 41befbbfe..3575b21e4 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -27,7 +27,7 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocC
import { SidebarAnnos } from '../../SidebarAnnos';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { Colors } from '../../global/globalEnums';
-import { DocumentView } from '../DocumentView';
+import { DocFocusOptions, DocumentView } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import { FormattedTextBox } from '../formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../trails';
@@ -504,8 +504,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
};
- getView = async (doc: Doc) => {
- if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar();
+ getView = async (doc: Doc, options: DocFocusOptions) => {
+ if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
+ this.toggleSidebar();
+ options.didMove = true;
+ }
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
};
/*
diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
index 8b22a1531..ea8496c99 100644
--- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
+++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
@@ -20,7 +20,7 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocC
import { SidebarAnnos } from '../../SidebarAnnos';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { Colors } from '../../global/globalEnums';
-import { DocumentView } from '../DocumentView';
+import { DocFocusOptions, DocumentView } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import { MapAnchorMenu } from '../MapBox/MapAnchorMenu';
import { FormattedTextBox } from '../formattedText/FormattedTextBox';
@@ -374,8 +374,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
}
};
- getView = async (doc: Doc) => {
- if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar();
+ getView = async (doc: Doc, options: DocFocusOptions) => {
+ if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
+ this.toggleSidebar();
+ options.didMove = true;
+ }
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
};
/*
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 55a459a5c..959d5d88d 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -224,8 +224,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options);
};
- getView = async (doc: Doc) => {
- if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false);
+ getView = async (doc: Doc, options: DocFocusOptions) => {
+ if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
+ options.didMove = true;
+ this.toggleSidebar(false);
+ }
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
};
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index ae923ad60..460155446 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -180,9 +180,9 @@
}
}
-video::-webkit-media-controls {
- display: none !important;
-}
+// video::-webkit-media-controls {
+// display: none !important;
+// }
input[type='range'] {
-webkit-appearance: none;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index ce73d9f37..fb42286af 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,9 +1,9 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx';
+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 { Doc, StrListCast } from '../../../fields/Doc';
+import { Doc, Opt, StrListCast } from '../../../fields/Doc';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
@@ -12,23 +12,20 @@ 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 { DocumentType } from '../../documents/DocumentTypes';
-import { Networking } from '../../Network';
import { DocumentManager } from '../../util/DocumentManager';
import { FollowLinkScript } from '../../util/LinkFollower';
import { LinkManager } from '../../util/LinkManager';
import { ReplayMovements } from '../../util/ReplayMovements';
-import { SelectionManager } from '../../util/SelectionManager';
-import { SnappingManager } from '../../util/SnappingManager';
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, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
import { AnchorMenu } from '../pdf/AnchorMenu';
import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, DocumentView, OpenWhere } from './DocumentView';
+import { DocFocusOptions, DocumentView } from './DocumentView';
import { FieldView, FieldViewProps } from './FieldView';
import { RecordingBox } from './RecordingBox';
import { PinProps, PresBox } from './trails';
@@ -40,7 +37,7 @@ import './VideoBox.scss';
* Supporting Components: CollectionStackedTimeline
*
* VideoBox is a node that supports the playback of video files in Dash.
- * When a video file or YouTube video is importeed into Dash, it is immediately rendered as a VideoBox document.
+ * When a video file is importeed into Dash, it is immediately rendered as a VideoBox document.
* CollectionStackedTimline handles AudioBox and VideoBox shared behavior, but VideoBox handles playing, pausing, etc because it contains <video> element
* User can trim video: nondestructive, just sets new bounds for playback and rendering timeline
* Like images, users can zoom and pan and it has an overlay layer allowing for annotations on top of the video at different times
@@ -51,16 +48,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(VideoBox, fieldKey);
}
- static _youtubeIframeCounter: number = 0;
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 _youtubePlayer: YT.Player | undefined = undefined;
private _videoRef: HTMLVideoElement | null = null; // <video> ref
private _contentRef: HTMLDivElement | null = null; // ref to div that wraps video and controls for full screen
- private _youtubeIframeId: number = -1;
- private _youtubeContentCreated = false;
private _audioPlayer: HTMLAudioElement | null = null;
private _marqueeref = React.createRef<MarqueeAnnotator>();
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); // outermost div
@@ -74,12 +67,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._props.setContentView?.(this);
}
- @observable _stackedTimeline: any = undefined; // CollectionStackedTimeline ref
- @observable static _nativeControls: boolean = false; // default html controls
+ @observable _stackedTimeline: CollectionStackedTimeline | undefined = undefined; // CollectionStackedTimeline ref
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@observable _screenCapture = false;
@observable _clicking = false; // used for transition between showing/hiding timeline
- @observable _forceCreateYouTubeIFrame = false;
@observable _playTimer?: NodeJS.Timeout = undefined;
@observable _fullScreen = false;
@observable _playing = false;
@@ -99,11 +90,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// @computed get rawDuration() { return NumCast(this.dataDoc[this.fieldKey + "_duration"]); }
@observable rawDuration: number = 0;
- @computed get youtubeVideoId() {
- const field = Cast(this.dataDoc[this._props.fieldKey], VideoField);
- return field && field.url.href.indexOf('youtube') !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split('/')) : '';
- }
-
// returns the path of the audio file
@computed get audiopath() {
const field = Cast(this.Document[this._props.fieldKey + '_audio'], AudioField, null);
@@ -130,17 +116,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
componentDidMount() {
this.unmounting = false;
this._props.setContentView?.(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.
- if (this.youtubeVideoId) {
- const youtubeaspect = 400 / 315;
- const nativeWidth = Doc.NativeWidth(this.layoutDoc);
- const nativeHeight = Doc.NativeHeight(this.layoutDoc);
- if (!nativeWidth || !nativeHeight) {
- if (!nativeWidth) Doc.SetNativeWidth(this.dataDoc, 600);
- Doc.SetNativeHeight(this.dataDoc, (nativeWidth || 600) / youtubeaspect);
- this.layoutDoc._height = NumCast(this.layoutDoc._width) / youtubeaspect;
- }
- }
- this.player && this.setPlayheadTime(this.timeline.clipStart || 0);
+ this.player && this.setPlayheadTime(this.timeline?.clipStart || 0);
document.addEventListener('keydown', this.keyEvents, true);
if (this.presentation) {
@@ -201,8 +177,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._audioPlayer && this.player && (this._audioPlayer.currentTime = this.player?.currentTime);
update && this.player && this.playFrom(start, undefined, true);
update && this._audioPlayer?.play();
- update && this._youtubePlayer?.playVideo();
- this._youtubePlayer && !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 5));
} catch (e) {
console.log('Video Play Exception:', e);
}
@@ -212,11 +186,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// goes to time
@action public Seek(time: number) {
- try {
- this._youtubePlayer?.seekTo(Math.round(time), true);
- } catch (e) {
- console.log('Video Seek Exception:', e);
- }
this.player && (this.player.currentTime = time);
this._audioPlayer && (this._audioPlayer.currentTime = time);
// TODO: revisit this and clean it
@@ -242,13 +211,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
try {
update && this.player?.pause();
update && this._audioPlayer?.pause();
- update && this._youtubePlayer?.pauseVideo();
- this._youtubePlayer && this._playTimer && clearInterval(this._playTimer);
- this._youtubePlayer?.seekTo(this._youtubePlayer?.getCurrentTime(), true);
} catch (e) {
console.log('Video Pause Exception:', e);
}
- this._youtubePlayer && SelectionManager.DeselectAll(); // if we don't deselect the player, then we get an annoying YouTube spinner I guess telling us we're paused.
this._playTimer = undefined;
this.updateTimecode();
if (!this._finished) {
@@ -270,11 +235,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._fullScreen = true;
this.player && this._contentRef && this._contentRef.requestFullscreen();
}
- try {
- this._youtubePlayer && this._props.addDocTab(this.Document, OpenWhere.add);
- } catch (e) {
- console.log('Video FullScreen Exception:', e);
- }
};
// fades out controls in fullscreen after mouse stops moving
@@ -334,22 +294,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
});
this._props.addDocument?.(b);
DocUtils.MakeLink(b, this.Document, { link_relationship: 'video snapshot' });
- Networking.PostToServer('/youtubeScreenshot', {
- id: this.youtubeVideoId,
- timecode: this.layoutDoc._layout_currentTimecode,
- }).then(response => {
- const resolved = response?.accessPaths?.agnostic?.client;
- if (resolved) {
- this._props.removeDocument?.(b);
- this.createSnapshotLink(resolved);
- }
- });
} else {
//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(/\./, '_'));
+ 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));
}
@@ -416,16 +366,18 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
updateTimecode = () => {
!this.unmounting && this.player && (this.layoutDoc._layout_currentTimecode = this.player.currentTime);
- try {
- this._youtubePlayer && (this.layoutDoc._layout_currentTimecode = this._youtubePlayer.getCurrentTime?.());
- } catch (e) {
- console.log('Video Timecode Exception:', e);
- }
};
- // getView = async (doc: Doc) => {
- // return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
- // };
+ getView = (doc: Doc, options: DocFocusOptions) => {
+ if (this._stackedTimeline?.makeDocUnfiltered(doc)) {
+ if (this.heightPercent === 100) {
+ 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)));
+ };
// extracts video thumbnails and saves them as field of doc
getVideoThumbnails = () => {
@@ -518,7 +470,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
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: "Toggle Native Controls", event: action(() => VideoBox._nativeControls = !VideoBox._nativeControls), 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" });
@@ -581,7 +532,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
ref={this.setVideoRef}
style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.layoutDoc._freeform_scale)})`, transformOrigin: 'top left' } : {}}
onCanPlay={this.videoLoad}
- controls={VideoBox._nativeControls}
+ controls={false}
onPlay={() => this.Play()}
onSeeked={this.updateTimecode}
onPause={() => this.Pause()}
@@ -600,54 +551,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
);
}
- @action youtubeIframeLoaded = (e: any) => {
- if (!this._youtubeContentCreated) {
- this._forceCreateYouTubeIFrame = !this._forceCreateYouTubeIFrame;
- return;
- } else this._youtubeContentCreated = false;
-
- this.loadYouTube(e.target);
- };
-
- loadYouTube = (iframe: any) => {
- let started = true;
- const onYoutubePlayerStateChange = (event: any) =>
- runInAction(() => {
- if (started && event.data === YT.PlayerState.PLAYING) {
- started = false;
- this._youtubePlayer?.unMute();
- //this.Pause();
- return;
- }
- if (event.data === YT.PlayerState.PLAYING && !this._playing) this.Play(false);
- if (event.data === YT.PlayerState.PAUSED && this._playing) this.Pause(false);
- });
- const onYoutubePlayerReady = (event: any) => {
- this._disposers.reactionDisposer?.();
- this._disposers.youtubeReactionDisposer?.();
- this._disposers.reactionDisposer = reaction(
- () => this.layoutDoc._layout_currentTimecode,
- () => !this._playing && this.Seek(NumCast(this.layoutDoc._layout_currentTimecode))
- );
- this._disposers.youtubeReactionDisposer = reaction(
- () => Doc.ActiveTool === InkTool.None && this._props.isSelected() && !SnappingManager.IsDragging && !SnappingManager.IsResizing,
- interactive => (iframe.style.pointerEvents = interactive ? 'all' : 'none'),
- { fireImmediately: true }
- );
- };
- if (typeof YT === undefined) setTimeout(() => this.loadYouTube(iframe), 100);
- else {
- (YT as any)?.ready(() => {
- this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this._youtubeIframeId}-player`, {
- events: {
- onReady: this._props.dontRegisterView ? undefined : onYoutubePlayerReady,
- onStateChange: this._props.dontRegisterView ? undefined : onYoutubePlayerStateChange,
- },
- });
- });
- }
- };
-
// for play button
onPlayDown = () => (this._playing ? this.Pause() : this.Play());
@@ -723,25 +626,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
};
- @computed get youtubeContent() {
- this._youtubeIframeId = VideoBox._youtubeIframeCounter++;
- this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true;
- const classname = 'videoBox-content-YouTube' + (this._fullScreen ? '-fullScreen' : '');
- const start = untracked(() => Math.round(NumCast(this.layoutDoc._layout_currentTimecode)));
- return (
- <iframe
- key={this._youtubeIframeId}
- id={`${this.youtubeVideoId + this._youtubeIframeId}-player`}
- onPointerLeave={this.updateTimecode}
- onLoad={this.youtubeIframeLoaded}
- className={classname}
- width={Doc.NativeWidth(this.layoutDoc) || 640}
- height={Doc.NativeHeight(this.layoutDoc) || 390}
- src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1&rel=0&showinfo=1&autoplay=0&mute=1&start=${start}&modestbranding=1&controls=${VideoBox._nativeControls ? 1 : 0}`}
- />
- );
- }
-
// for annotating, adds doc with time info
@action.bound
addDocWithTimecode(doc: Doc | Doc[]): boolean {
@@ -1090,7 +974,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
removeDocument={this.removeDocument}
moveDocument={this.moveDocument}
addDocument={this.addDocWithTimecode}>
- {this.youtubeVideoId ? this.youtubeContent : this.content}
+ {this.content}
</CollectionFreeFormView>
</div>
{this.annotationLayer}
@@ -1225,5 +1109,3 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
);
}
}
-
-VideoBox._nativeControls = false;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 3ad9f7634..c3be2b390 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -296,7 +296,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
@action
- getView = (doc: Doc) => {
+ getView = (doc: Doc, options: DocFocusOptions) => {
if (Doc.AreProtosEqual(doc, this.Document)) return new Promise<Opt<DocumentView>>(res => res(this._props.DocumentView?.()));
if (this.Document.layout_fieldKey === 'layout_icon') this._props.DocumentView?.().iconify();
const webUrl = WebCast(doc.config_data)?.url;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 66802d198..3be3aeba3 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1056,9 +1056,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return anchorDoc ?? this.Document;
}
- getView = async (doc: Doc) => {
+ getView = async (doc: Doc, options: DocFocusOptions) => {
if (DocListCast(this.dataDoc[this.SidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
- !this.SidebarShown && this.toggleSidebar(false);
+ if (!this.SidebarShown) {
+ this.toggleSidebar(false);
+ options.didMove = true;
+ }
setTimeout(() => this._sidebarRef?.current?.makeDocUnfiltered(doc));
}
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 50f202e69..b1a7a9c5e 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -2,7 +2,7 @@ import axios from 'axios';
import { green, red } from 'colors';
import { ExifImage } from 'exif';
import * as exifr from 'exifr';
-import { FfmpegCommand, ffprobe } from 'fluent-ffmpeg';
+import * as ffmpeg from 'fluent-ffmpeg';
import * as formidable from 'formidable';
import { File } from 'formidable';
import * as fs from 'fs';
@@ -95,9 +95,8 @@ export namespace DashUploadUtils {
const outputFilePath = path.join(pathToDirectory(Directory.videos), outputFileName);
// concatenate the videos
- await new Promise((resolve, reject) => {
- var merge = new FfmpegCommand();
- merge
+ await new Promise((resolve, reject) =>
+ ffmpeg()
.input(textFilePath)
.inputOptions(['-f concat', '-safe 0'])
// .outputOptions('-c copy')
@@ -107,8 +106,8 @@ export namespace DashUploadUtils {
console.log(err);
reject();
})
- .on('end', resolve);
- });
+ .on('end', resolve)
+ );
// delete concat.txt from the file system
unlinkSync(textFilePath);
@@ -221,7 +220,7 @@ export namespace DashUploadUtils {
if (format.includes('x-matroska')) {
console.log('case video');
await new Promise(res =>
- new FfmpegCommand(file.filepath)
+ ffmpeg(file.filepath)
.videoCodec('copy') // this will copy the data instead of reencode it
.save(file.filepath.replace('.mkv', '.mp4'))
.on('end', res)
@@ -233,7 +232,7 @@ export namespace DashUploadUtils {
if (format.includes('quicktime')) {
let abort = false;
await new Promise<void>(res =>
- ffprobe(file.filepath, (err: any, metadata: any) => {
+ ffmpeg.ffprobe(file.filepath, (err: any, metadata: any) => {
if (metadata.streams.some((stream: any) => stream.codec_name === 'hevc')) {
abort = true;
}