aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/DocumentView.tsx12
-rw-r--r--src/client/views/nodes/FilterBox.tsx30
-rw-r--r--src/client/views/nodes/ImageBox.tsx25
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx3
-rw-r--r--src/client/views/nodes/VideoBox.scss67
-rw-r--r--src/client/views/nodes/VideoBox.tsx91
-rw-r--r--src/client/views/nodes/WebBox.tsx88
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx2
8 files changed, 154 insertions, 164 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ae3107b08..6ab25dd6a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -89,6 +89,8 @@ export interface DocComponentView {
setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
playFrom?: (time: number, endTime?: number) => void;
setFocus?: () => void;
+ fieldKey?: string;
+ annotationKey?: string;
}
export interface DocumentViewSharedProps {
renderDepth: number;
@@ -183,7 +185,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
_componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class
- private get topMost() { return this.props.renderDepth === 0; }
+ private get topMost() { return this.props.renderDepth === 0 && !LightboxView.LightboxDoc; }
public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
public get ContentDiv() { return this._mainCont.current; }
public get LayoutFieldKey() { return Doc.LayoutFieldKey(this.layoutDoc); }
@@ -778,7 +780,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onClickFunc = () => this.onClickHandler;
setHeight = (height: number) => this.layoutDoc._height = height;
setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view;
- isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() ? true : false;
+ isContentActive = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || this.props.isContentActive() ? true : false;
@computed get contents() {
TraceMobx();
const audioView = !this.layoutDoc._showAudio ? (null) :
@@ -793,7 +795,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>;
return <div className="documentView-contentsView"
style={{
- pointerEvents: this.props.contentPointerEvents as any,
+ pointerEvents: (this.props.contentPointerEvents as any) || (CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() || this.isContentActive() ? "all" : "none"),
height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
}}>
<DocumentContentsView key={1} {...this.props}
@@ -810,7 +812,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
layoutKey={this.finalLayoutKey} />
{this.layoutDoc.hideAllLinks ? (null) : this.allLinkEndpoints}
{this.hideLinkButton ? (null) :
- <DocumentLinksButton View={this.props.DocumentView()} Offset={[this.topMost ? 0 : -15, undefined, undefined, this.topMost ? 10 : -20]} />}
+ <div style={{ transformOrigin: "top left", transform: `scale(${Math.min(1, this.props.ScreenToLocalTransform().scale(this.props.ContentScaling?.() || 1).Scale)})` }}>
+ <DocumentLinksButton View={this.props.DocumentView()} Offset={[this.topMost ? 0 : -15, undefined, undefined, this.topMost ? 10 : -20]} />
+ </div>}
{audioView}
</div>;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index beefc4a82..1e13d1b5a 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -79,10 +79,19 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
* @returns the relevant doc according to the value of FilterBox._filterScope i.e. either the Current Dashboard or the Current Collection
*/
@computed static get targetDoc() {
+ return SelectionManager.Views().length ? SelectionManager.Views()[0].Document : CurrentUserUtils.ActiveDashboard;
+ }
+ @computed static get targetDocChildKey() {
+ if (SelectionManager.Views().length) {
+ return SelectionManager.Views()[0].ComponentView?.annotationKey || SelectionManager.Views()[0].ComponentView?.fieldKey || "data";
+ }
+ return "data";
+ }
+ @computed static get targetDocChildren() {
if (SelectionManager.Views().length) {
- return SelectionManager.Views()[0]?.Document.type === DocumentType.COL ? SelectionManager.Views()[0].Document : SelectionManager.Views()[0]?.props.ContainingCollectionDoc!;
+ return DocListCast(FilterBox.targetDoc[FilterBox.targetDocChildKey]);
}
- return CurrentUserUtils.ActiveDashboard;
+ return DocListCast(CurrentUserUtils.ActiveDashboard.data);
}
@observable _loaded = false;
@@ -100,7 +109,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
const targetDoc = FilterBox.targetDoc;
if (this._loaded && targetDoc) {
const allDocs = new Set<Doc>();
- const activeTabs = DocListCast(targetDoc.data);
+ const activeTabs = FilterBox.targetDocChildren;
SearchBox.foreachRecursiveDoc(activeTabs, (depth, doc) => allDocs.add(doc));
setTimeout(action(() => this._allDocs = Array.from(allDocs)));
}
@@ -133,8 +142,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
return this.activeAttributes.map(attribute => StrCast(attribute.title));
}
- gatherFieldValues(dashboard: Doc, facetKey: string) {
- const childDocs = DocListCast(dashboard.data);
+ gatherFieldValues(childDocs: Doc[], facetKey: string) {
const valueSet = new Set<string>();
let rtFields = 0;
childDocs.forEach((d) => {
@@ -194,13 +202,13 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
* Responds to clicking the check box in the flyout menu
*/
facetClick = (facetHeader: string) => {
- const { targetDoc } = FilterBox;
+ const { targetDoc, targetDocChildren } = FilterBox;
const found = this.activeAttributes.findIndex(doc => doc.title === facetHeader);
if (found !== -1) {
this.removeFilter(facetHeader);
} else {
- const allCollectionDocs = DocListCast((targetDoc.data as any)?.[0].data);
- const facetValues = this.gatherFieldValues(targetDoc, facetHeader);
+ const allCollectionDocs = targetDocChildren;
+ const facetValues = this.gatherFieldValues(targetDocChildren, facetHeader);
let nonNumbers = 0;
let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE;
@@ -248,7 +256,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
newFacet.layoutKey = "layout";
newFacet.type = DocumentType.COL;
newFacet.target = targetDoc;
- newFacet.data = ComputedField.MakeFunction(`readFacetData(self.target, "${facetHeader}")`);
+ newFacet.data = ComputedField.MakeFunction(`readFacetData(self.target, "${FilterBox.targetDocChildKey}", "${facetHeader}")`);
}
newFacet.hideContextMenu = true;
Doc.AddDocToList(this.dataDoc, this.props.fieldKey, newFacet);
@@ -479,9 +487,9 @@ Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader:
}
return undefined;
});
-Scripting.addGlobal(function readFacetData(layoutDoc: Doc, facetHeader: string) {
+Scripting.addGlobal(function readFacetData(layoutDoc: Doc, childKey: string, facetHeader: string) {
const allCollectionDocs = new Set<Doc>();
- const activeTabs = DocListCast(layoutDoc.data);
+ const activeTabs = DocListCast(layoutDoc[childKey]);
SearchBox.foreachRecursiveDoc(activeTabs, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
const set = new Set<string>();
if (facetHeader === "tags") allCollectionDocs.forEach(child => Field.toString(child[facetHeader] as Field).split(":").forEach(key => set.add(key)));
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 2c0106960..c4e74ebd2 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,19 +1,21 @@
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from 'mobx';
import { observer } from "mobx-react";
import { DataSym, Doc, DocListCast, WidthSym } from '../../../fields/Doc';
import { documentSchema } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
+import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
import { createSchema, makeInterface } from '../../../fields/Schema';
import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, NumCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, OmitKeys, returnOne, Utils, returnFalse } from '../../../Utils';
+import { emptyFunction, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils';
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
import { Networking } from '../../Network';
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { DragManager } from '../../util/DragManager';
import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from "../../views/ContextMenu";
@@ -21,15 +23,13 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
+import { AnchorMenu } from '../pdf/AnchorMenu';
import { StyleProp } from '../StyleProvider';
import { FaceRectangles } from './FaceRectangles';
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
import React = require("react");
-import { InkTool } from '../../../fields/InkField';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
-import { AnchorMenu } from '../pdf/AnchorMenu';
-import { Docs } from '../../documents/Documents';
+import { SnappingManager } from '../../util/SnappingManager';
const path = require('path');
export const pageSchema = createSchema({
@@ -294,7 +294,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
<div className="imageBox-fader" >
<img key="paths" ref={this._imgRef}
src={srcpath}
- style={{ transform, transformOrigin }} draggable={false}
+ style={{ transform, transformOrigin }}
+ draggable={false}
width={nativeWidth} />
{fadepath === srcpath ? (null) : <div className="imageBox-fadeBlocker">
<img className="imageBox-fadeaway" key={"fadeaway"} ref={this._imgRef}
@@ -330,11 +331,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
TraceMobx();
return <div className="imageBox-annotationLayer" style={{ height: this.props.PanelHeight() }} ref={this._annotationLayer} />;
}
- @action
marqueeDown = (e: React.PointerEvent) => {
if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
- this._marqueeing = [e.clientX, e.clientY];
- e.stopPropagation();
+ setupMoveUpEvents(this, e, action(e => {
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations)
+ this._marqueeing = [e.clientX, e.clientY];
+ return true;
+ }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false);
}
}
@action
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index f0db0b594..7ad96bf05 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -175,8 +175,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
@computed get content() {
if (this.rootDoc.videoWall) return (null);
- const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
- return <video className={"videoBox-content" + interactive} key="video"
+ return <video className={"videoBox-content"} key="video"
ref={r => {
this._videoRef = r;
setTimeout(() => {
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index f593f74fb..cdd36eb3b 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -49,63 +49,28 @@
// pointer-events: all;
// }
-.videoBox-time{
- color : white;
- top :25px;
- left : 25px;
+.videoBox-ui {
position: absolute;
- background-color: rgba(50, 50, 50, 0.2);
- transform-origin: left top;
- pointer-events:all;
+ flex-direction: row;
+ right: 5px;
+ top: 5px;
+ display: none;
+ background-color: rgba(0, 0, 0, 0.6);
}
-.videoBox-snapshot{
+.videoBox-time, .videoBox-snapshot, .videoBox-timelineButton, .videoBox-play, .videoBox-full {
color : white;
- top :25px;
- right : 25px;
- position: absolute;
- background-color:rgba(50, 50, 50, 0.2);
+ position: relative;
transform-origin: left top;
pointer-events:all;
- cursor: default;
-}
-
-.videoBox-timelineButton {
- position: absolute;
- display: flex;
- align-items: center;
- z-index: 1010;
- bottom: 5px;
- right: 5px;
- color: white;
+ padding-right: 5px;
cursor: pointer;
- background: dimgrey;
- width: 20px;
- height: 20px;
-}
-.videoBox-play {
- width: 25px;
- height: 20px;
- bottom: 25px;
- left : 25px;
- position: absolute;
- color : white;
- background-color: rgba(50, 50, 50, 0.2);
- border-radius: 4px;
- text-align: center;
- transform-origin: left bottom;
- pointer-events:all;
+ &:hover {
+ background-color: gray;
+ }
}
-.videoBox-full {
- width: 25px;
- height: 20px;
- bottom: 25px;
- right : 25px;
- position: absolute;
- color : white;
- background-color: rgba(50, 50, 50, 0.2);
- border-radius: 4px;
- text-align: center;
- transform-origin: right bottom;
- pointer-events:all;
+.videoBox:hover {
+ .videoBox-ui {
+ display: flex;
+ }
} \ No newline at end of file
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index ce45c01e6..d4df30b48 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -9,7 +9,7 @@ import { InkTool } from "../../../fields/InkField";
import { makeInterface } from "../../../fields/Schema";
import { Cast, NumCast, StrCast } from "../../../fields/Types";
import { AudioField, nullAudio, VideoField } from "../../../fields/URLField";
-import { emptyFunction, formatTime, OmitKeys, returnOne, setupMoveUpEvents, Utils } from "../../../Utils";
+import { emptyFunction, formatTime, OmitKeys, returnOne, setupMoveUpEvents, Utils, returnFalse } from "../../../Utils";
import { Docs, DocUtils } from "../../documents/Documents";
import { Networking } from "../../Network";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -28,6 +28,8 @@ import { LinkDocPreview } from "./LinkDocPreview";
import "./VideoBox.scss";
import { DragManager } from "../../util/DragManager";
import { DocumentManager } from "../../util/DocumentManager";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { Tooltip } from "@material-ui/core";
const path = require('path');
type VideoDocument = makeInterface<[typeof documentSchema]>;
@@ -49,7 +51,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
private _playRegionTimer: any = null;
private _playRegionDuration = 0;
- @observable static _showControls: boolean;
+ @observable static _nativeControls: boolean;
@observable _marqueeing: number[] | undefined;
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@observable _screenCapture = false;
@@ -125,7 +127,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this.updateTimecode();
}
- @action public FullScreen() {
+ @action public FullScreen = () => {
this._fullScreen = true;
this.player && this.player.requestFullscreen();
try {
@@ -137,7 +139,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@action public Snapshot(downX?: number, downY?: number) {
const width = (this.layoutDoc._width || 0);
- const height = (this.layoutDoc._height || 0);
const canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 640 * Doc.NativeHeight(this.layoutDoc) / (Doc.NativeWidth(this.layoutDoc) || 1);
@@ -208,11 +209,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
componentDidMount() {
this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
- this._disposers.selection = reaction(() => this.props.isSelected(),
- selected => !selected && setTimeout(() => {
- Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove()));
- this._savedAnnotations.clear();
- }));
this._disposers.triggerVideo = reaction(
() => !LinkDocPreview.LinkInfo && this.props.renderDepth !== -1 ? NumCast(this.Document._triggerVideo, null) : undefined,
time => time !== undefined && setTimeout(() => {
@@ -281,10 +277,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
if (field) {
const url = field.url.href;
const subitems: ContextMenuProps[] = [];
- subitems.push({ description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt" });
- subitems.push({ description: "Toggle Show Controls", event: action(() => VideoBox._showControls = !VideoBox._showControls), icon: "expand-arrows-alt" });
- subitems.push({ description: "Take Snapshot", event: () => this.Snapshot(), icon: "expand-arrows-alt" });
- subitems.push({
+ subitems.push({ description: "Full Screen", event: this.FullScreen, icon: "expand" });
+ subitems.push({ description: "Take Snapshot", event: this.Snapshot, icon: "expand-arrows-alt" });
+ this.rootDoc.type === DocumentType.SCREENSHOT && subitems.push({
description: "Screen Capture", event: (async () => {
runInAction(() => this._screenCapture = !this._screenCapture);
this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
@@ -292,6 +287,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
});
subitems.push({ description: (this.layoutDoc.dontAutoPlayFollowedLinks ? "" : "Don't") + " play when link is selected", 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: "Toggle Native Controls", event: action(() => VideoBox._nativeControls = !VideoBox._nativeControls), icon: "expand-arrows-alt" });
+ subitems.push({ description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt" });
ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" });
}
}
@@ -315,7 +312,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
<video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef}
style={{ height: "100%", width: "auto", display: "flex", margin: "auto" }}
onCanPlay={this.videoLoad}
- controls={VideoBox._showControls}
+ controls={VideoBox._nativeControls}
onPlay={() => this.Play()}
onSeeked={this.updateTimecode}
onPause={() => this.Pause()}
@@ -380,26 +377,36 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
private get uIButtons() {
const curTime = (this.layoutDoc._currentTimecode || 0);
- return ([<div className="videoBox-time" key="time" onPointerDown={this.onResetDown} >
- <span>{"" + formatTime(curTime)}</span>
- <span style={{ fontSize: 8 }}>{" " + Math.round((curTime - Math.trunc(curTime)) * 100)}</span>
- </div>,
- <div className="videoBox-snapshot" key="snap" onPointerDown={this.onSnapshotDown} >
- <FontAwesomeIcon icon="camera" size="lg" />
- </div>,
- <div className="videoBox-timelineButton" key="timeline" onPointerDown={this.onTimelineHdlDown} style={{ bottom: `${100 - this.heightPercent}%` }}>
- <FontAwesomeIcon icon={"eye"} size="lg" />
- </div>,
- VideoBox._showControls ? (null) : [
- // <div className="control-background">
- <div className="videoBox-play" key="play" onPointerDown={this.onPlayDown} >
- <FontAwesomeIcon icon={this._playing ? "pause" : "play"} size="lg" />
- </div>,
- <div className="videoBox-full" key="full" onPointerDown={this.onFullDown} >
- F
- {/* </div> */}
- </div>
- ]]);
+ const nonNativeControls = [
+ <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} placement="bottom">
+ <div className="videoBox-play" key="play" onPointerDown={this.onPlayDown} >
+ <FontAwesomeIcon icon={this._playing ? "pause" : "play"} size="lg" />
+ </div>
+ </Tooltip>,
+ <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} placement="bottom">
+ <div className="videoBox-time" onPointerDown={this.onResetDown} >
+ <span>{formatTime(curTime)}</span>
+ <span style={{ fontSize: 8 }}>{" " + Math.floor((curTime - Math.trunc(curTime)) * 100).toString().padStart(2, "0")}</span>
+ </div>
+ </Tooltip>,
+ <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} placement="bottom">
+ <div className="videoBox-full" onPointerDown={this.FullScreen}>
+ <FontAwesomeIcon icon="expand" size="lg" />
+ </div>
+ </Tooltip>];
+ return <div className="videoBox-ui">
+ {[...(VideoBox._nativeControls ? [] : nonNativeControls),
+ <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} placement="bottom">
+ <div className="videoBox-snapshot" onPointerDown={this.onSnapshotDown} >
+ <FontAwesomeIcon icon="camera" size="lg" />
+ </div>
+ </Tooltip>,
+ <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} placement="bottom">
+ <div className="videoBox-timelineButton" onPointerDown={this.onTimelineHdlDown}>
+ <FontAwesomeIcon icon="eye" size="lg" />
+ </div>
+ </Tooltip>,]}
+ </div>;
}
onPlayDown = () => this._playing ? this.Pause() : this.Play();
@@ -453,7 +460,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId}-player`}
onPointerLeave={this.updateTimecode}
onLoad={this.youtubeIframeLoaded} className={`${style}`} 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._showControls ? 1 : 0}`} />;
+ 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}`} />;
}
@action.bound
@@ -538,9 +545,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
return <div className="imageBox-annotationLayer" style={{ transition: this.transition, height: `${this.heightPercent}%` }} ref={this._annotationLayer} />;
}
- marqueeDown = action((e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) this._marqueeing = [e.clientX, e.clientY];
- });
+ marqueeDown = (e: React.PointerEvent) => {
+ if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
+ setupMoveUpEvents(this, e, action(e => {
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
+ this._marqueeing = [e.clientX, e.clientY];
+ return true;
+ }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false);
+ }
+ }
finishMarquee = action(() => {
this._marqueeing = undefined;
@@ -610,4 +623,4 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
}
-VideoBox._showControls = true; \ No newline at end of file
+VideoBox._nativeControls = false; \ No newline at end of file
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 2ff41c73a..cdc79678a 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -44,7 +44,7 @@ const WebDocument = makeInterface(documentSchema);
export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, WebDocument>(WebDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
public static openSidebarWidth = 250;
- private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void);
+ private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _outerRef: React.RefObject<HTMLDivElement> = React.createRef();
private _disposers: { [name: string]: IReactionDisposer } = {};
@@ -52,16 +52,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
private _keyInput = React.createRef<HTMLInputElement>();
private _initialScroll: Opt<number>;
private _sidebarRef = React.createRef<SidebarAnnos>();
- @observable private _urlHash: string = "";
@observable private _scrollTimer: any;
@observable private _overlayAnnoInfo: Opt<Doc>;
@observable private _marqueeing: number[] | undefined;
- @observable private _url: string = "hello";
@observable private _isAnnotating = false;
@observable private _iframeClick: HTMLIFrameElement | undefined = undefined;
@observable private _iframe: HTMLIFrameElement | null = null;
@observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@observable private _scrollHeight = 1500;
+ @computed get _url() { return this.webField?.toString() || ""; }
+ @computed get _urlHash() { return this._url ? WebBox.urlHash(this._url) + "" : ""; }
@computed get scrollHeight() { return this._scrollHeight; }
@computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); }
@computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
@@ -82,9 +82,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
runInAction(() => {
- this._url = this.webField?.toString() || "";
- this._urlHash = WebBox.urlHash(this._url) + "";
- this._annotationKey = this._urlHash + "-annotations";
+ this._annotationKeySuffix = () => this._urlHash + "-annotations";
// bcz: need to make sure that doc.data-annotations points to the currently active web page's annotations (this could/should be when the doc is created)
this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`);
this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`);
@@ -214,6 +212,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
const scale = (this.props.scaling?.() || 1) * mainContBounds.scale;
const word = getWordAtPoint(e.target, e.clientX, e.clientY);
+ this._setPreviewCursor?.(e.clientX, e.clientY, false, true);
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeing = [e.clientX * scale + mainContBounds.translateX,
e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale];
if (word) {
@@ -306,9 +306,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), []);
if (future.length) {
this.dataDoc[this.fieldKey + "-history"] = new List<string>([...history, this._url]);
- this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = future.pop()!));
- this._urlHash = WebBox.urlHash(this._url) + "";
- this._annotationKey = this._urlHash + "-annotations";
+ this.dataDoc[this.fieldKey] = new WebField(new URL(future.pop()!));
return true;
}
return false;
@@ -321,9 +319,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (history.length) {
if (future === undefined) this.dataDoc[this.fieldKey + "-future"] = new List<string>([this._url]);
else this.dataDoc[this.fieldKey + "-future"] = new List<string>([...future, this._url]);
- this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = history.pop()!));
- this._urlHash = WebBox.urlHash(this._url) + "";
- this._annotationKey = this._urlHash + "-annotations";
+ this.dataDoc[this.fieldKey] = new WebField(new URL(history.pop()!));
return true;
}
return false;
@@ -342,17 +338,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"));
const url = this.webField?.toString();
if (url && !preview) {
- if (history === undefined) {
- this.dataDoc[this.fieldKey + "-history"] = new List<string>([url]);
- } else {
- this.dataDoc[this.fieldKey + "-history"] = new List<string>([...history, url]);
- }
+ this.dataDoc[this.fieldKey + "-history"] = new List<string>([...(history || []), url]);
this.layoutDoc._scrollTop = 0;
future && (future.length = 0);
}
- this._url = newUrl;
- this._urlHash = WebBox.urlHash(this._url) + "";
- this._annotationKey = this._urlHash + "-annotations";
if (!preview) this.dataDoc[this.fieldKey] = new WebField(new URL(newUrl));
} catch (e) {
console.log("WebBox URL error:" + this._url);
@@ -413,15 +402,18 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
onMarqueeDown = (e: React.PointerEvent) => {
if (!e.altKey && e.button === 0 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
- this._marqueeing = [e.clientX, e.clientY];
- this.props.select(false);
+ setupMoveUpEvents(this, e, action(e => {
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
+ this._marqueeing = [e.clientX, e.clientY];
+ return true;
+ }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false);
}
}
@action finishMarquee = (x?: number, y?: number) => {
this._marqueeing = undefined;
this._isAnnotating = false;
this._iframeClick = undefined;
- x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false);
+ x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false);
}
@computed
@@ -511,7 +503,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; }
showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno);
- setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func;
+ setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func;
panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
@@ -520,6 +512,29 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined;
const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
const scale = previewScale * (this.props.scaling?.() || 1);
+ const renderAnnotations = (docFilters: () => string[]) =>
+ <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
+ renderDepth={this.props.renderDepth + 1}
+ isAnnotationOverlay={true}
+ fieldKey={this.annotationKey}
+ CollectionView={undefined}
+ setPreviewCursor={this.setPreviewCursor}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight}
+ ScreenToLocalTransform={this.scrollXf}
+ scaling={returnOne}
+ dropAction={"alias"}
+ docFilters={docFilters}
+ select={emptyFunction}
+ isContentActive={returnFalse}
+ ContentScaling={returnOne}
+ bringToFront={emptyFunction}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.sidebarAddDocument}
+ childPointerEvents={true}
+ pointerEvents={CurrentUserUtils.SelectedTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
return (
<div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.isContentActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
<div className={`webBox-container`} style={{ pointerEvents }} onContextMenu={this.specificContextMenu}>
@@ -537,27 +552,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
>
<div className={"webBox-innerContent"} style={{ height: NumCast(this.scrollHeight, 50), pointerEvents }}>
{this.content}
- <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
- renderDepth={this.props.renderDepth + 1}
- isAnnotationOverlay={true}
- fieldKey={this.annotationKey}
- CollectionView={undefined}
- setPreviewCursor={this.setPreviewCursor}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight}
- ScreenToLocalTransform={this.scrollXf}
- scaling={returnOne}
- dropAction={"alias"}
- select={emptyFunction}
- isContentActive={returnFalse}
- ContentScaling={returnOne}
- bringToFront={emptyFunction}
- whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- removeDocument={this.removeDocument}
- moveDocument={this.moveDocument}
- addDocument={this.sidebarAddDocument}
- childPointerEvents={true}
- pointerEvents={this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />
+ <div style={{ mixBlendMode: "multiply" }}>
+ {renderAnnotations(Utils.IsTransparentFilter)}
+ </div>
+ {renderAnnotations(Utils.IsOpaqueFilter)}
{this.annotationLayer}
</div>
</div>
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 5cb9866f8..cfc3e75cc 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -605,7 +605,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.layoutDoc.presStatus = PresStatus.Edit;
Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
CollectionDockingView.AddSplit(this.rootDoc, "right");
- } else if (this.layoutDoc.context && docView) {
+ } else if ((true || this.layoutDoc.context) && docView) {
console.log("case 2");
this.layoutDoc.presStatus = PresStatus.Edit;
clearTimeout(this._presTimer);