diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/ComparisonBox.scss | 90 | ||||
| -rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 152 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 3 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.scss | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/LabelBox.tsx | 5 | ||||
| -rw-r--r-- | src/client/views/nodes/PresBox.tsx | 7 | ||||
| -rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 9 | ||||
| -rw-r--r-- | src/client/views/nodes/WebBox.tsx | 2 |
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 = () => { |
