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/CollectionFreeFormDocumentView.tsx1
-rw-r--r--src/client/views/nodes/ComparisonBox.scss90
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx152
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx3
-rw-r--r--src/client/views/nodes/DocumentView.scss1
-rw-r--r--src/client/views/nodes/DocumentView.tsx1
-rw-r--r--src/client/views/nodes/ImageBox.tsx1
-rw-r--r--src/client/views/nodes/LabelBox.tsx5
-rw-r--r--src/client/views/nodes/PresBox.tsx7
-rw-r--r--src/client/views/nodes/VideoBox.tsx9
-rw-r--r--src/client/views/nodes/WebBox.tsx2
11 files changed, 251 insertions, 21 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 5f0e28db2..57f484214 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -14,7 +14,6 @@ import { List } from "../../../fields/List";
import { numberRange } from "../../../Utils";
import { ComputedField } from "../../../fields/ScriptField";
import { listSpec } from "../../../fields/Schema";
-import { docs } from "googleapis/build/src/apis/docs";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss
new file mode 100644
index 000000000..3d48d96e2
--- /dev/null
+++ b/src/client/views/nodes/ComparisonBox.scss
@@ -0,0 +1,90 @@
+.comparisonBox-interactive, .comparisonBox {
+ border-radius: inherit;
+ width: 100%;
+ height: 100%;
+ background-color: grey;
+ position: absolute;
+ z-index: 0;
+ pointer-events: none;
+
+ .clip-div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ overflow: hidden;
+
+ .beforeBox-cont {
+ height: 100%;
+ overflow: hidden;
+ background-color: rgb(240, 240, 240);
+ }
+ }
+
+ .slide-bar {
+ position: absolute;
+ height: 100%;
+ width: 3px;
+ display: inline-block;
+ background: gray;
+ cursor: ew-resize;
+ .slide-handle {
+ position: absolute;
+ display: none;
+ height: 20px;
+ width: 30px;
+ bottom: 0px;
+ left: -10.5px;
+ .left-handle, .right-handle{
+ width: 15px;
+ }
+ }
+ }
+
+ .afterBox-cont {
+ position: absolute;
+ top: 0;
+ right: 0;
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ background-color: lightgray;
+ }
+
+ .clear-button {
+ position: absolute;
+ top: 3px;
+ opacity: 0.8;
+ pointer-events: all;
+ cursor: pointer;
+ }
+
+ .clear-button.before {
+ left: 3px;
+ }
+
+ .clear-button.after {
+ right: 3px;
+ }
+
+ .placeholder {
+ width: 50%;
+ height: 50%;
+ margin-top: 25%;
+ margin-left: 25%;
+
+ .upload-icon {
+ width: 100%;
+ height: 100%;
+ opacity: 0.5;
+ }
+ }
+}
+.comparisonBox-interactive {
+ pointer-events: unset;
+ .slide-bar {
+ .slide-handle {
+ display: flex;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
new file mode 100644
index 000000000..7a4d40db1
--- /dev/null
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -0,0 +1,152 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faEye } from '@fortawesome/free-regular-svg-icons';
+import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush, faTimes, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, runInAction, Lambda } from 'mobx';
+import { observer } from "mobx-react";
+import { Doc } from '../../../fields/Doc';
+import { documentSchema } from '../../../fields/documentSchemas';
+import { createSchema, makeInterface } from '../../../fields/Schema';
+import { NumCast, Cast } from '../../../fields/Types';
+import { DragManager } from '../../util/DragManager';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import "./ComparisonBox.scss";
+import React = require("react");
+import { ContentFittingDocumentView } from './ContentFittingDocumentView';
+import { undoBatch } from '../../util/UndoManager';
+import { setupMoveUpEvents, emptyFunction } from '../../../Utils';
+import { SnappingManager } from '../../util/SnappingManager';
+
+library.add(faImage, faEye as any, faPaintBrush, faBrain);
+library.add(faFileAudio, faAsterisk);
+
+export const comparisonSchema = createSchema({});
+
+type ComparisonDocument = makeInterface<[typeof comparisonSchema, typeof documentSchema]>;
+const ComparisonDocument = makeInterface(comparisonSchema, documentSchema);
+
+@observer
+export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, ComparisonDocument>(ComparisonDocument) {
+ protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
+
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); }
+
+ private _beforeDropDisposer?: DragManager.DragDropDisposer;
+ private _afterDropDisposer?: DragManager.DragDropDisposer;
+ private resizeUpdater: Lambda | undefined;
+
+ protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string) => {
+ if (ele) {
+ return DragManager.MakeDropTarget(ele, (event, dropEvent) => this.dropHandler(event, dropEvent, fieldKey), this.layoutDoc);
+ }
+ }
+
+ @undoBatch
+ private dropHandler = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
+ event.stopPropagation();
+ const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
+ if (droppedDocs?.length) {
+ this.dataDoc[fieldKey] = droppedDocs[0];
+ droppedDocs[0].isBackgound = true;
+ }
+ }
+
+ componentWillMount() {
+ this.dataDoc.clipWidth = this.props.PanelWidth() / 2;
+
+ //preserve before/after ratio during resizing
+ this.resizeUpdater = computed(() => this.props.PanelWidth()).observe(({ oldValue, newValue }) =>
+ this.dataDoc.clipWidth = NumCast(this.dataDoc.clipWidth) / (oldValue || 0) * newValue
+ );
+ }
+
+ componentWillUnmount() {
+ this.resizeUpdater?.();
+ }
+
+ private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, action(() => {
+ this._animating = true;
+ this.dataDoc.clipWidth = targetWidth;
+ setTimeout(action(() => this._animating = false), 1000);
+ }), false);
+ }
+
+ @action
+ private onPointerMove = ({ movementX }: PointerEvent) => {
+ const width = movementX * this.props.ScreenToLocalTransform().Scale + NumCast(this.dataDoc.clipWidth);
+ if (width && width > 5 && width < this.props.PanelWidth()) {
+ this.dataDoc.clipWidth = width;
+ }
+ return false;
+ }
+
+ @undoBatch
+ clearDoc = (e: React.MouseEvent, fieldKey: string) => {
+ e.stopPropagation;
+ e.preventDefault;
+ delete this.dataDoc[fieldKey];
+ }
+
+ @observable _animating = false;
+ render() {
+ const beforeDoc = Cast(this.dataDoc.beforeDoc, Doc, null);
+ const afterDoc = Cast(this.dataDoc.afterDoc, Doc, null);
+ const clipWidth = NumCast(this.dataDoc.clipWidth);
+ return (
+ <div className={`comparisonBox${this.active() || SnappingManager.GetIsDragging() ? "-interactive" : ""}`}>
+ <div className="afterBox-cont" key={"after"} onPointerDown={e => this.registerSliding(e, this.props.PanelWidth() - 5)}
+ ref={(ele) => {
+ this._afterDropDisposer?.();
+ this._afterDropDisposer = this.createDropTarget(ele, "afterDoc");
+ }}>
+ {afterDoc ? <>
+ <ContentFittingDocumentView {...this.props}
+ Document={afterDoc}
+ pointerEvents={false}
+ parentActive={this.props.active}
+ />
+ <div className="clear-button after" onClick={e => this.clearDoc(e, "afterDoc")}>
+ <FontAwesomeIcon className="clear-button after" icon={faTimes} size="sm" />
+ </div>
+ </> :
+ <div className="placeholder">
+ <FontAwesomeIcon className="upload-icon" icon={faCloudUploadAlt} size="lg" />
+ </div>}
+ </div>
+ <div className="clip-div" onPointerDown={e => this.registerSliding(e, 5)} style={{ width: clipWidth + "px", transition: this._animating ? "all 1s" : undefined }}>
+ {/* wraps around before image and slider bar */}
+ <div
+ className="beforeBox-cont"
+ key={"before"}
+ ref={(ele) => {
+ this._beforeDropDisposer?.();
+ this._beforeDropDisposer = this.createDropTarget(ele, "beforeDoc");
+ }}
+ style={{ width: this.props.PanelWidth() }}>
+ {
+ beforeDoc ?
+ <>
+ <ContentFittingDocumentView {...this.props}
+ Document={beforeDoc}
+ pointerEvents={false}
+ parentActive={this.props.active} />
+ <div className="clear-button before" onClick={e => this.clearDoc(e, "beforeDoc")}>
+ <FontAwesomeIcon className="clear-button before" icon={faTimes} size="sm" />
+ </div>
+ </>
+ :
+ <div className="placeholder">
+ <FontAwesomeIcon className="upload-icon" icon={faCloudUploadAlt} size="lg" />
+ </div>
+ }
+ </div>
+ </div>
+
+ <div className="slide-bar" style={{ left: `calc(${NumCast(this.dataDoc.clipWidth) * 100 / this.props.PanelWidth()}% - 0.5px)` }}>
+ <div className="slide-handle" />
+ </div>
+ </div >);
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index f4785bb0c..ef56e6fcd 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -30,6 +30,7 @@ import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
import { LinkAnchorBox } from "./LinkAnchorBox";
import { PresElementBox } from "../presentationview/PresElementBox";
import { ScreenshotBox } from "./ScreenshotBox";
+import { ComparisonBox } from "./ComparisonBox";
import { VideoBox } from "./VideoBox";
import { WebBox } from "./WebBox";
import { InkingStroke } from "../InkingStroke";
@@ -194,7 +195,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
- RecommendationsBox, ScreenshotBox, HTMLtag
+ RecommendationsBox, ScreenshotBox, HTMLtag, ComparisonBox
}}
bindings={bindings}
jsx={layoutFrame}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index dea09cb30..b7726f7ba 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -94,6 +94,7 @@
text-align: center;
text-overflow: ellipsis;
white-space: pre;
+ position: absolute;
}
.documentView-titleWrapper-hover {
display:none;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8dbd0232b..993cabc36 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -12,7 +12,6 @@ import { listSpec } from "../../../fields/Schema";
import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { ImageField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils";
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 47e7607d6..77abfef1d 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -19,7 +19,6 @@ import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_ser
import { Docs } from '../../documents/Documents';
import { Networking } from '../../Network';
import { DragManager } from '../../util/DragManager';
-import { SelectionManager } from '../../util/SelectionManager';
import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from "../../views/ContextMenu";
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 2d27ec441..ad9e49369 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,5 +1,3 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit } from '@fortawesome/free-regular-svg-icons';
import { action } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -16,9 +14,6 @@ import { ViewBoxBaseComponent } from '../DocComponent';
import { FieldView, FieldViewProps } from './FieldView';
import './LabelBox.scss';
-
-library.add(faEdit as any);
-
const LabelSchema = createSchema({});
type LabelDocument = makeInterface<[typeof LabelSchema, typeof documentSchema]>;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 09c03fb30..aeb77a894 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -1,6 +1,6 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import { Doc, DocListCast, DocCastAsync } from "../../../fields/Doc";
import { InkTool } from "../../../fields/InkField";
@@ -15,8 +15,7 @@ import { InkingControl } from "../InkingControl";
import { FieldView, FieldViewProps } from './FieldView';
import "./PresBox.scss";
import { ViewBoxBaseComponent } from "../DocComponent";
-import { makeInterface, listSpec } from "../../../fields/Schema";
-import { List } from "../../../fields/List";
+import { makeInterface } from "../../../fields/Schema";
import { Docs } from "../../documents/Documents";
import { PrefetchProxy } from "../../../fields/Proxy";
import { ScriptField } from "../../../fields/ScriptField";
@@ -213,7 +212,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.hideIfNotPresented(index);
this.showAfterPresented(index);
}
- })
+ });
//The function that starts or resets presentaton functionally, depending on status flag.
startOrResetPres = () => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 6b1e6ae18..9d02239fc 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,6 +1,4 @@
import React = require("react");
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faVideo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, IReactionDisposer, observable, reaction, runInAction, untracked } from "mobx";
import { observer } from "mobx-react";
@@ -8,7 +6,6 @@ import * as rp from 'request-promise';
import { Doc } from "../../../fields/Doc";
import { InkTool } from "../../../fields/InkField";
import { createSchema, makeInterface } from "../../../fields/Schema";
-import { ScriptField } from "../../../fields/ScriptField";
import { Cast, StrCast } from "../../../fields/Types";
import { VideoField } from "../../../fields/URLField";
import { Utils, emptyFunction, returnOne, returnZero } from "../../../Utils";
@@ -31,8 +28,6 @@ export const timeSchema = createSchema({
type VideoDocument = makeInterface<[typeof documentSchema, typeof timeSchema]>;
const VideoDocument = makeInterface(documentSchema, timeSchema);
-library.add(faVideo);
-
@observer
export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoDocument>(VideoDocument) {
static _youtubeIframeCounter: number = 0;
@@ -181,8 +176,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
componentWillUnmount() {
this.Pause();
- this._reactionDisposer && this._reactionDisposer();
- this._youtubeReactionDisposer && this._youtubeReactionDisposer();
+ this._reactionDisposer?.();
+ this._youtubeReactionDisposer?.();
}
@action
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c73b88ef7..f80cea941 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
urlHash(s: string) {
- return s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a }, 0);
+ return s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0);
}
@action
submitURL = () => {