diff options
| author | usodhi <61431818+usodhi@users.noreply.github.com> | 2021-04-04 13:38:55 -0400 |
|---|---|---|
| committer | usodhi <61431818+usodhi@users.noreply.github.com> | 2021-04-04 13:38:55 -0400 |
| commit | 15c1c952c50bb2de972c614e46c5f33c2b2952cc (patch) | |
| tree | e8d7330336b80939e82749290c22ef5a05b01224 /src/client/views/nodes | |
| parent | 479dff344ff2cf92ace9c68c3ce6d03e6e6dce22 (diff) | |
| parent | ee17752109ba1238d645a4df7cee1cf60855f8df (diff) | |
merging
Diffstat (limited to 'src/client/views/nodes')
22 files changed, 192 insertions, 174 deletions
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 06a27c22a..85899578c 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -17,7 +17,7 @@ import { SnappingManager } from "../../util/SnappingManager"; import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import "./AudioBox.scss"; import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from "./LinkDocPreview"; @@ -29,7 +29,7 @@ type AudioDocument = makeInterface<[typeof documentSchema]>; const AudioDocument = makeInterface(documentSchema); @observer -export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioDocument>(AudioDocument) { +export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, AudioDocument>(AudioDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); } public static Enabled = false; static playheadWidth = 30; // width of playhead @@ -63,7 +63,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD @computed get pauseTime() { return this._pauseEnd - this._pauseStart; } // total time paused to update the correct time @computed get heightPercent() { return AudioBox.heightPercent; } - constructor(props: Readonly<FieldViewProps>) { + constructor(props: Readonly<ViewBoxAnnotatableProps & FieldViewProps>) { super(props); AudioBox.Instance = this; @@ -267,7 +267,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD // returns the html audio element @computed get audio() { - return <audio ref={this.setRef} className={`audiobox-control${this.active() ? "-interactive" : ""}`}> + return <audio ref={this.setRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}> <source src={this.path} type="audio/mpeg" /> Not supported. </audio>; @@ -311,8 +311,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD } } - isActiveChild = () => this._isChildActive; - timelineWhenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(runInAction(() => this._isChildActive = isActive)); + isActiveChild = () => this._isAnyChildContentActive; + timelineWhenChildContentsActiveChanged = (isActive: boolean) => this.props.whenChildContentsActiveChanged(runInAction(() => this._isAnyChildContentActive = isActive)); timelineScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-AudioBox.playheadWidth, -(100 - this.heightPercent) / 200 * this.props.PanelHeight()); setAnchorTime = (time: number) => this._ele!.currentTime = this.layoutDoc._currentTimecode = time; timelineHeight = () => this.props.PanelHeight() * this.heightPercent / 100 * this.heightPercent / 100; // panelHeight * heightPercent is player height. * heightPercent is timeline height (as per css inline) @@ -320,6 +320,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD @computed get renderTimeline() { return <CollectionStackedTimeline ref={this._stackedTimeline} {...this.props} fieldKey={this.annotationKey} + dictationKey={this.fieldKey + "-dictation"} mediaPath={this.path} renderDepth={this.props.renderDepth + 1} startTag={"_timecodeToShow" /* audioStart */} @@ -331,13 +332,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD playFrom={this.playFrom} setTime={this.setAnchorTime} playing={this.playing} - whenActiveChanged={this.timelineWhenActiveChanged} + whenChildContentsActiveChanged={this.timelineWhenChildContentsActiveChanged} removeDocument={this.removeDocument} ScreenToLocalTransform={this.timelineScreenToLocal} - isChildActive={this.isActiveChild} Play={this.Play} Pause={this.Pause} - active={this.active} + isContentActive={this.isContentActive} playLink={this.playLink} PanelWidth={this.timelineWidth} PanelHeight={this.timelineHeight} @@ -345,7 +345,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD } render() { - const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; + const interactive = SnappingManager.GetIsDragging() || this.isContentActive() ? "-interactive" : ""; return <div className="audiobox-container" onContextMenu={this.specificContextMenu} onClick={!this.path && !this._recorder ? this.recordAudioAnnotation : undefined} @@ -370,7 +370,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD RECORD </button>} </div> : - <div className="audiobox-controls" style={{ pointerEvents: this._isChildActive || this.active() ? "all" : "none" }} > + <div className="audiobox-controls" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }} > <div className="audiobox-dictation" /> <div className="audiobox-player" style={{ height: `${AudioBox.heightPercent}%` }} > <div className="audiobox-playhead" style={{ width: AudioBox.playheadWidth }} title={this.mediaState === "paused" ? "play" : "pause"} onClick={this.Play}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.mediaState === "paused" ? "play" : "pause"} size={"1x"} /></div> diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index e96fc088e..1fda4cc5e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -49,7 +49,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF @computed get dataProvider() { return this.props.dataProvider?.(this.props.Document, this.props.replica); } @computed get sizeProvider() { return this.props.sizeProvider?.(this.props.Document, this.props.replica); } - styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => { if (property === StyleProp.Opacity && doc === this.layoutDoc) return this.Opacity; // only change the opacity for this specific document, not its children return this.props.styleProvider?.(doc, props, property); } diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 59a26f323..46c599abe 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -2,21 +2,20 @@ import React = require("react"); import { action } from "mobx"; import { observer } from "mobx-react"; import { ColorState, SketchPicker } from 'react-color'; -import { Doc, WidthSym, HeightSym } from '../../../fields/Doc'; -import { Utils } from "../../../Utils"; +import { Doc, HeightSym, WidthSym } from '../../../fields/Doc'; import { documentSchema } from "../../../fields/documentSchemas"; import { InkTool } from "../../../fields/InkField"; import { makeInterface } from "../../../fields/Schema"; import { StrCast } from "../../../fields/Types"; +import { DocumentType } from "../../documents/DocumentTypes"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { SelectionManager } from "../../util/SelectionManager"; import { undoBatch } from "../../util/UndoManager"; import { ViewBoxBaseComponent } from "../DocComponent"; -import { ActiveInkPen, ActiveInkWidth, ActiveInkBezierApprox, SetActiveInkColor, SetActiveInkWidth, SetActiveBezierApprox, ActiveInkColor } from "../InkingStroke"; +import { ActiveInkColor, ActiveInkWidth, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke"; import "./ColorBox.scss"; import { FieldView, FieldViewProps } from './FieldView'; -import { DocumentType } from "../../documents/DocumentTypes"; import { RichTextMenu } from "./formattedText/RichTextMenu"; -import { CurrentUserUtils } from "../../util/CurrentUserUtils"; type ColorDocument = makeInterface<[typeof documentSchema]>; const ColorDocument = makeInterface(documentSchema); @@ -50,7 +49,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument render() { const scaling = Math.min(this.layoutDoc.fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]()); - return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`} + return <div className={`colorBox-container${this.isContentActive() ? "-interactive" : ""}`} onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()} onClick={e => e.stopPropagation()} style={{ transform: `scale(${scaling})`, width: `${100 * scaling}%`, height: `${100 * scaling}%` }} > diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index b1bbc9506..153176afc 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -9,7 +9,7 @@ import { emptyFunction, OmitKeys, setupMoveUpEvents } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; -import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import "./ComparisonBox.scss"; import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; @@ -21,7 +21,7 @@ type ComparisonDocument = makeInterface<[typeof comparisonSchema, typeof documen const ComparisonDocument = makeInterface(comparisonSchema, documentSchema); @observer -export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, ComparisonDocument>(ComparisonDocument) { +export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ComparisonDocument>(ComparisonDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined]; @@ -86,8 +86,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, C <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} Document={whichDoc} DataDoc={undefined} - pointerEvents={"none"} - parentActive={this.props.active} /> + pointerEvents={"none"} /> {clearButton(which)} </> : // placeholder image if doc is missing <div className="placeholder"> @@ -103,7 +102,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, C }; return ( - <div className={`comparisonBox${this.active() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}> + <div className={`comparisonBox${this.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}> {displayBox("after", 1, this.props.PanelWidth() - 3)} <div className="clip-div" style={{ width: clipWidth, transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, "gray") }}> {displayBox("before", 0, 0)} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 2f7923574..b53827371 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -40,6 +40,7 @@ import React = require("react"); import { TraceMobx, GetEffectiveAcl } from "../../../fields/util"; import { ScriptField } from "../../../fields/ScriptField"; import XRegExp = require("xregexp"); +import { DocumentType } from "../../documents/DocumentTypes"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? @@ -158,7 +159,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo "onPointerUp", ]; const list = { - ...OmitKeys(this.props, [...docOnlyProps], "", (obj: any) => obj.active = this.props.parentActive).omit, + ...OmitKeys(this.props, [...docOnlyProps], "").omit, RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 231c9ff38..1c4008a55 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,18 +1,19 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable, runInAction, reaction, IReactionDisposer } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast } from "../../../fields/Doc"; import { Document } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from "../../../fields/List"; +import { ObjectField } from "../../../fields/ObjectField"; import { listSpec } from "../../../fields/Schema"; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; import { AudioField } from "../../../fields/URLField"; import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; import { MobileInterface } from '../../../mobile/MobileInterface'; -import { emptyFunction, hasDescendantTarget, OmitKeys, returnFalse, returnVal, Utils } from "../../../Utils"; +import { emptyFunction, hasDescendantTarget, OmitKeys, returnVal, Utils } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; @@ -34,19 +35,18 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from "../DocComponent"; import { EditableView } from '../EditableView'; import { InkingStroke } from "../InkingStroke"; +import { LightboxView } from "../LightboxView"; import { StyleLayers, StyleProp } from "../StyleProvider"; import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; import { DocumentContentsView } from "./DocumentContentsView"; import { DocumentLinksButton } from './DocumentLinksButton'; import "./DocumentView.scss"; -import { FieldViewProps } from "./FieldView"; import { LinkAnchorBox } from './LinkAnchorBox'; import { LinkDocPreview } from "./LinkDocPreview"; import { PresBox } from './PresBox'; import { RadialMenu } from './RadialMenu'; import React = require("react"); -import { ObjectField } from "../../../fields/ObjectField"; -import { LightboxView } from "../LightboxView"; +import { ScriptingBox } from "./ScriptingBox"; const { Howl } = require('howler'); interface Window { @@ -75,7 +75,7 @@ export interface DocFocusOptions { } export type DocAfterFocusFunc = (notFocused: boolean) => Promise<ViewAdjustment>; export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void; -export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => any; +export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any; export interface DocComponentView { getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) scrollFocus?: (doc: Doc, smooth: boolean) => Opt<number>; // returns the duration of the focus @@ -86,6 +86,7 @@ export interface DocComponentView { getKeyFrameEditing?: () => boolean; // 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) 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; } export interface DocumentViewSharedProps { renderDepth: number; @@ -106,11 +107,10 @@ export interface DocumentViewSharedProps { docFilters: () => string[]; docRangeFilters: () => string[]; searchFilterDocs: () => Doc[]; - contentsActive?: (setActive: () => boolean) => void; - parentActive: (outsideReaction: boolean) => boolean; - whenActiveChanged: (isActive: boolean) => void; + whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected addDocTab: (doc: Doc, where: string) => boolean; + filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) addDocument?: (doc: Doc | Doc[]) => boolean; removeDocument?: (doc: Doc | Doc[]) => boolean; moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; @@ -119,8 +119,9 @@ export interface DocumentViewSharedProps { bringToFront: (doc: Doc, sendToBack?: boolean) => void; dropAction?: dropActionType; dontRegisterView?: boolean; + hideLinkButton?: boolean; ignoreAutoHeight?: boolean; - cantBrush?: boolean; // whether the document doesn't show brush highlighting + disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. pointerEvents?: string; scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document createNewFilterDoc?: () => void; @@ -133,6 +134,8 @@ export interface DocumentViewProps extends DocumentViewSharedProps { hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings hideDecorationTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings treeViewDoc?: Doc; + isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events + isContentActive: () => boolean | undefined; // whether a document should handle pointer events contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents radialMenu?: String[]; LayoutTemplateString?: string; @@ -177,7 +180,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class private get topMost() { return this.props.renderDepth === 0; } - private get active() { return this.props.isSelected(true) || this.props.parentActive(true); } 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); } @@ -281,7 +283,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps this._downX = touch.clientX; this._downY = touch.clientY; if (!e.nativeEvent.cancelBubble) { - if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation(); + if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation(); this.removeMoveListeners(); this.addMoveListeners(); this.removeEndListeners(); @@ -292,10 +294,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps } handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => { - if (e.cancelBubble && this.active) { + if (e.cancelBubble && this.props.isDocumentActive?.()) { this.removeMoveListeners(); } - else if (!e.cancelBubble && (this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { const touch = me.touchEvent.changedTouches.item(0); if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { @@ -407,9 +409,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true), 0); else if (!this._titleRef.current.setIsFocused(true)) { // if focus didn't change, focus on interior text... this._titleRef.current?.setIsFocused(false); - const any = (this._mainCont.current?.getElementsByClassName("ProseMirror")?.[0] as any); - any.keeplocation = true; - any?.focus(); + this._componentView?.setFocus?.(); } } } @@ -440,16 +440,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps clearTimeout(this._timeout); this._timeout = undefined; } - if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name)) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + const { clientX, clientY, shiftKey } = e; const func = () => this.onDoubleClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, scriptContext: this.props.scriptContext, thisContainer: this.props.ContainingCollectionDoc, documentView: this.props.DocumentView(), - clientX: e.clientX, - clientY: e.clientY, - shiftKey: e.shiftKey + clientX, clientY, shiftKey }, console.log); UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on double click"); } else if (!Doc.IsSystem(this.rootDoc)) { @@ -459,28 +458,23 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps } Doc.UnBrushDoc(this.props.Document); } - } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself - const shiftKey = e.shiftKey; - const clientX = e.clientX; - const clientY = e.clientY; + } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name)) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + const { clientX, clientY, shiftKey } = e; const func = () => this.onClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, scriptContext: this.props.scriptContext, thisContainer: this.props.ContainingCollectionDoc, documentView: this.props.DocumentView(), - clientX: clientX, - clientY: clientY, - shiftKey - }, console.log); - const clickFunc = () => this.props.Document.dontUndo ? func() : - UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on click"); + clientX, clientY, shiftKey + }, console.log).result?.select === true ? this.props.select(false) : ""; + const clickFunc = () => this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, "on click"); if (this.onDoubleClickHandler) { this._timeout = setTimeout(() => { this._timeout = undefined; clickFunc(); }, 350); } else clickFunc(); } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself this.props.addDocTab(DocUtils.makeCustomViewClicked(Doc.MakeAlias(this.props.Document), undefined, "onClick"), "add:right"); - } else if (this.allLinks && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { + } else if (this.allLinks && this.Document.type !== DocumentType.LINK && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { this.allLinks.length && LinkManager.FollowLink(undefined, this.props.Document, this.props, e.altKey); } else { if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part @@ -512,7 +506,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps if ((!e.nativeEvent.cancelBubble || this.onClickHandler || this.layoutDoc.onDragStart) && // if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) { - if ((this.active || this.layoutDoc.onDragStart) && + if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { @@ -529,10 +523,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps onPointerMove = (e: PointerEvent): void => { if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return; - if (e.cancelBubble && this.active) { + if (e.cancelBubble && this.props.isDocumentActive?.()) { document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView) } - else if (!e.cancelBubble && (this.active || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); @@ -757,14 +751,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps rootSelected = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; panelHeight = () => this.props.PanelHeight() - this.headerMargin; - parentActive = (outsideReaction: boolean) => this.props.layerProvider?.(this.layoutDoc) === false ? this.props.parentActive(outsideReaction) : false; screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin); contentScaling = () => this.ContentScale; onClickFunc = () => this.onClickHandler; setHeight = (height: number) => this.layoutDoc._height = height; setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view; - @observable contentsActive: () => boolean = returnFalse; - @action setContentsActive = (setActive: () => boolean) => this.contentsActive = setActive; + isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() ? true : false; @computed get contents() { TraceMobx(); const audioView = !this.layoutDoc._showAudio ? (null) : @@ -788,8 +780,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps scaling={this.contentScaling} PanelHeight={this.panelHeight} setHeight={this.setHeight} - contentsActive={this.setContentsActive} - parentActive={this.parentActive} + isContentActive={this.isContentActive} ScreenToLocalTransform={this.screenToLocal} rootSelected={this.rootSelected} onClick={this.onClickFunc} @@ -813,8 +804,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true) anchorPanelWidth = () => this.props.PanelWidth() || 1; anchorPanelHeight = () => this.props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => { - return property !== StyleProp.LinkSource ? this.props.styleProvider?.(doc, props, property + ":anchor") : this.props.Document; // pass the LinkSource to the LinkAnchorBox + anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => { + switch (property) { + case StyleProp.PointerEvents: return "none"; + case StyleProp.LinkSource: return this.props.Document;// pass the LinkSource to the LinkAnchorBox + default: return this.props.styleProvider?.(doc, props, property); + } } @computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); } @computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); } @@ -961,7 +956,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"])[highlightIndex]; const highlightStyle = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"][highlightIndex]; const excludeTypes = !this.props.treeViewDoc ? [DocumentType.FONTICON, DocumentType.INK] : [DocumentType.FONTICON]; - let highlighting = !this.props.cantBrush && highlightIndex && !excludeTypes.includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear; + let highlighting = !this.props.disableDocBrushing && highlightIndex && !excludeTypes.includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way const boxShadow = highlighting && this.borderRounding && highlightStyle !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColor}` : @@ -1040,7 +1035,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { @computed get centeringY() { return this.fitWidth || this.props.dontCenter?.includes("y") ? 0 : this.Yshift; } toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight()); - contentsActive = () => this.docView?.contentsActive(); focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options); getBounds = () => { if (!this.docView || !this.docView.ContentDiv || this.docView.props.renderDepth === 0 || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 97f53aac0..0fc7a752f 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -18,8 +18,8 @@ export interface FieldViewProps extends DocumentViewSharedProps { fieldKey: string; scrollOverflow?: boolean; // bcz: would like to think this can be avoided -- need to look at further - active: (outsideReaction?: boolean) => boolean; select: (isCtrlPressed: boolean) => void; + isContentActive: (outsideReaction?: boolean) => boolean; isSelected: (outsideReaction?: boolean) => boolean; scaling?: () => number; setHeight: (height: number) => void; diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index b9a981e77..1d3f6a7cc 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -20,6 +20,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import './FilterBox.scss'; import { Scripting } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; +import { CollectionView } from "../collections/CollectionView"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -258,9 +259,11 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" }); } else { newFacet = new Doc(); - newFacet.sytem = true; + newFacet.system = true; newFacet.title = facetHeader; newFacet.treeViewOpen = true; + newFacet.layout = CollectionView.LayoutString("data"); + newFacet.layoutKey = "layout"; newFacet.type = DocumentType.COL; // const capturedVariables = { layoutDoc: targetDoc, system: true, _stayInCollection: true, _hideContextMenu: true, dataDoc: (targetDoc.data as any)[0][DataSym] }; // newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, "${facetHeader}")`, {}, capturedVariables); @@ -415,7 +418,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc DataDoc={Doc.GetProto(facetCollection)} fieldKey={this.props.fieldKey} CollectionView={undefined} - cantBrush={true} + disableDocBrushing={true} setHeight={returnFalse} // if the tree view can trigger the height of the filter box to change, then this needs to be filled in. onChildClick={this.suppressChildClick} docFilters={returnEmptyFilter} @@ -434,9 +437,8 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc isSelected={returnFalse} select={returnFalse} bringToFront={emptyFunction} - active={returnTrue} - parentActive={returnFalse} - whenActiveChanged={returnFalse} + isContentActive={returnTrue} + whenChildContentsActiveChanged={returnFalse} treeViewHideTitle={true} focus={returnFalse} treeViewHideHeaderFields={true} diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 4be7d1c37..b00f97236 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -80,7 +80,7 @@ export class FunctionPlotBox extends ViewBoxBaseComponent<FieldViewProps, Equati TraceMobx(); return (<div style={{ - pointerEvents: !this.active() ? "all" : undefined, + pointerEvents: !this.isContentActive() ? "all" : undefined, width: this.props.PanelWidth(), height: this.props.PanelHeight() }} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 9426f6afc..8a6946b78 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -20,7 +20,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { StyleProp } from '../StyleProvider'; import { FaceRectangles } from './FaceRectangles'; @@ -46,7 +46,7 @@ const uploadIcons = { }; @observer -export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) { +export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ImageDocument>(ImageDocument) { protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } private _imgRef: React.RefObject<HTMLImageElement> = React.createRef(); @@ -319,7 +319,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD } @action marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.active(true)) this._marqueeing = [e.clientX, e.clientY]; + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true)) this._marqueeing = [e.clientX, e.clientY]; } @action finishMarquee = () => { @@ -358,8 +358,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD focus={this.props.focus} isSelected={this.props.isSelected} select={emptyFunction} - active={this.annotationsActive} - whenActiveChanged={this.whenActiveChanged}> + isContentActive={this.isContentActive} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}> {this.contentFunc} </CollectionFreeFormView> {this.annotationLayer} diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 83a49a393..881cbf2bb 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -72,9 +72,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> { dropAction: "alias", bringToFront: emptyFunction, renderDepth: 1, - parentActive: returnFalse, - active: returnFalse, - whenActiveChanged: emptyFunction, + isContentActive: returnFalse, + whenChildContentsActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, PanelWidth: this.props.PanelWidth, diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 3d72d047e..8f9959693 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -120,7 +120,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch const x = NumCast(this.rootDoc[this.fieldKey + "_x"], 100); const y = NumCast(this.rootDoc[this.fieldKey + "_y"], 100); const linkSource = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource); - const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor); + const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ":anchor"); const anchor = this.fieldKey === "anchor1" ? "anchor2" : "anchor1"; const anchorScale = !this.dataDoc[this.fieldKey + "-useLinkSmallAnchor"] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .25; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index f542652d0..c65ba9c69 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -1,14 +1,13 @@ import React = require("react"); import { observer } from "mobx-react"; import { documentSchema } from "../../../fields/documentSchemas"; -import { makeInterface, listSpec } from "../../../fields/Schema"; -import { returnFalse, returnZero } from "../../../Utils"; +import { makeInterface } from "../../../fields/Schema"; +import { returnFalse } from "../../../Utils"; import { CollectionTreeView } from "../collections/CollectionTreeView"; import { ViewBoxBaseComponent } from "../DocComponent"; +import { StyleProp } from "../StyleProvider"; import { FieldView, FieldViewProps } from './FieldView'; import "./LinkBox.scss"; -import { Cast } from "../../../fields/Types"; -import { StyleProp } from "../StyleProvider"; type LinkDocument = makeInterface<[typeof documentSchema]>; const LinkDocument = makeInterface(documentSchema); @@ -16,16 +15,22 @@ const LinkDocument = makeInterface(documentSchema); @observer export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(LinkDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); } + isContentActiveFunc = () => this.isContentActive() ? true : false; render() { - return <div className={`linkBox-container${this.active() ? "-interactive" : ""}`} - style={{ background: this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BackgroundColor) }} > - + if (this.dataDoc.treeViewOpen === undefined) setTimeout(() => this.dataDoc.treeViewOpen = true); + return <div className={`linkBox-container${this.isContentActive() ? "-interactive" : ""}`} + style={{ background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor) }} > <CollectionTreeView {...this.props} childDocuments={[this.dataDoc]} - treeViewSkipFields={Cast(this.props.Document.linkBoxExcludedKeys, listSpec("string"), null)} + treeViewOpen={true} + treeViewExpandedView={"fields"} + treeViewHideTitle={true} + treeViewSkipFields={["treeViewExpandedView", "aliases", "_removeDropProperties", + "treeViewOpen", "aliasNumber", "isPrototype", "creationDate", "author"]} dontRegisterView={true} renderDepth={this.props.renderDepth + 1} CollectionView={undefined} + isContentActive={this.isContentActiveFunc} addDocument={returnFalse} removeDocument={returnFalse} moveDocument={returnFalse}> diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 3fe164f8a..45e3c8382 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -164,7 +164,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { layerProvider={this.props.docProps?.layerProvider} docViewPath={returnEmptyDoclist} ScreenToLocalTransform={Transform.Identity} - parentActive={returnFalse} + isDocumentActive={returnFalse} + isContentActive={returnFalse} addDocument={returnFalse} removeDocument={returnFalse} addDocTab={returnFalse} @@ -179,7 +180,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { PanelWidth={this.width} PanelHeight={this.height} focus={DocUtils.DefaultFocus} - whenActiveChanged={returnFalse} + whenChildContentsActiveChanged={returnFalse} bringToFront={returnFalse} NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined} NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined} diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index f27a34e36..d55156057 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -9,14 +9,14 @@ import { makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { PdfField } from "../../../fields/URLField"; import { TraceMobx } from '../../../fields/util'; -import { Utils } from '../../../Utils'; +import { Utils, setupMoveUpEvents, emptyFunction } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { KeyCodes } from '../../util/KeyCodes'; import { undoBatch } from '../../util/UndoManager'; import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { PDFViewer } from "../pdf/PDFViewer"; import { SidebarAnnos } from '../SidebarAnnos'; import { FieldView, FieldViewProps } from './FieldView'; @@ -28,7 +28,7 @@ type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, t const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @observer -export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocument>(PdfDocument) { +export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, PdfDocument>(PdfDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } private _searchString: string = ""; private _initialScrollTarget: Opt<Doc>; @@ -150,6 +150,20 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum if (!this.layoutDoc._showSidebar) this.toggleSidebar(); return this.addDocument(doc, sidebarKey); } + sidebarBtnDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, (e, down, delta) => { + const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]); + const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); + const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); + const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; + if (ratio >= 1) { + this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]; + this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + } + return false; + }, emptyFunction, this.toggleSidebar); + } toggleSidebar = action(() => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth; @@ -171,9 +185,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum </>; const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`; const curPage = this.Document._curPage || 1; - return !this.active() ? (null) : + return !this.isContentActive() ? (null) : <div className="pdfBox-ui" onKeyDown={e => [KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true} - onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none" }}> + onPointerDown={e => e.stopPropagation()} style={{ display: this.isContentActive() ? "flex" : "none" }}> <div className="pdfBox-overlayCont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}> <button className="pdfBox-overlayButton" title={searchTitle} /> <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} @@ -203,8 +217,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum {this._pageControls ? pageBtns : (null)} </div> <button className="pdfBox-sidebarBtn" title="Toggle Sidebar" - style={{ right: this.sidebarWidth() + 7, display: !this.active() ? "none" : undefined }} - onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} > + style={{ display: !this.isContentActive() ? "none" : undefined }} + onPointerDown={this.sidebarBtnDown} > <FontAwesomeIcon icon={"chevron-left"} size="sm" /> </button> </div>; @@ -221,7 +235,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum } @computed get renderTitleBox() { - const classname = "pdfBox" + (this.active() ? "-interactive" : ""); + const classname = "pdfBox" + (this.isContentActive() ? "-interactive" : ""); return <div className={classname} > <div className="pdfBox-title-outer"> <strong className="pdfBox-title" >{this.props.Document.title}</strong> @@ -238,28 +252,31 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum }}> <div className="pdfBox-background" /> <PDFViewer {...this.props} + rootDoc={this.rootDoc} + layoutDoc={this.layoutDoc} + dataDoc={this.dataDoc} pdf={this._pdf!} url={this.pdfUrl!.url.pathname} - active={this.active} + isContentActive={this.isContentActive} anchorMenuClick={this._sidebarRef.current?.anchorMenuClick} loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined} setPdfViewer={this.setPdfViewer} addDocument={this.addDocument} - whenActiveChanged={this.whenActiveChanged} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} startupLive={true} ContentScaling={this.props.scaling} sidebarWidth={this.sidebarWidth} /> <SidebarAnnos ref={this._sidebarRef} {...this.props} - annotationsActive={this.annotationsActive} rootDoc={this.rootDoc} layoutDoc={this.layoutDoc} dataDoc={this.dataDoc} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} sidebarAddDocument={this.sidebarAddDocument} moveDocument={this.moveDocument} removeDocument={this.removeDocument} - active={this.active} + isContentActive={this.isContentActive} /> {this.settingsPanel()} </div>; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 2aba461e0..8c5f77550 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -711,10 +711,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> return output; }); - whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); + whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive)); // For dragging documents into the presentation trail - addDocumentFilter = (doc: Doc | Doc[]) => { - const docs = doc instanceof Doc ? [doc] : doc; + addDocumentFilter = (docs: Doc[]) => { docs.forEach((doc, i) => { if (doc.presentationTargetDoc) return true; if (doc.type === DocumentType.LABEL) { @@ -749,7 +748,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; - active = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) && + isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) /** diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index c00c79eb9..8163b652c 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -19,7 +19,7 @@ import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline"; import { ContextMenu } from "../ContextMenu"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { FieldView, FieldViewProps } from './FieldView'; import "./ScreenshotBox.scss"; import { VideoBox } from "./VideoBox"; @@ -33,7 +33,7 @@ type ScreenshotDocument = makeInterface<[typeof documentSchema]>; const ScreenshotDocument = makeInterface(documentSchema); @observer -export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScreenshotDocument>(ScreenshotDocument) { +export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScreenshotDocument>(ScreenshotDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } private _videoRef = React.createRef<HTMLVideoElement>(); private _audioRec: any; @@ -159,9 +159,9 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps, S isSelected={this.props.isSelected} isAnnotationOverlay={true} select={emptyFunction} - active={returnFalse} + isContentActive={returnFalse} scaling={returnOne} - whenActiveChanged={emptyFunction} + whenChildContentsActiveChanged={emptyFunction} removeDocument={returnFalse} moveDocument={returnFalse} addDocument={returnFalse} @@ -181,11 +181,11 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps, S isSelected={this.props.isSelected} isAnnotationOverlay={true} select={emptyFunction} - active={returnFalse} + isContentActive={returnFalse} scaling={returnOne} xMargin={25} yMargin={10} - whenActiveChanged={emptyFunction} + whenChildContentsActiveChanged={emptyFunction} removeDocument={returnFalse} moveDocument={returnFalse} addDocument={returnFalse} diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index f1f2cd7d3..183140cd7 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -15,7 +15,7 @@ import { InteractionUtils } from "../../util/InteractionUtils"; import { CompileScript, Scripting, ScriptParam } from "../../util/Scripting"; import { ScriptManager } from "../../util/ScriptManager"; import { ContextMenu } from "../ContextMenu"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { EditableView } from "../EditableView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { OverlayView } from "../OverlayView"; @@ -29,7 +29,7 @@ type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentS const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema); @observer -export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) { +export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScriptingDocument>(ScriptingDocument) { private dropDisposer?: DragManager.DragDropDisposer; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index efcddd7b3..fb58ddefc 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -19,7 +19,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; import { MarqueeAnnotator } from "../MarqueeAnnotator"; import { StyleProp } from "../StyleProvider"; @@ -32,7 +32,7 @@ type VideoDocument = makeInterface<[typeof documentSchema]>; const VideoDocument = makeInterface(documentSchema); @observer -export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoDocument>(VideoDocument) { +export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, VideoDocument>(VideoDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } static _youtubeIframeCounter: number = 0; static Instance: VideoBox; @@ -63,7 +63,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD private get transition() { return this._clicking ? "left 0.5s, width 0.5s, height 0.5s" : ""; } public get player(): HTMLVideoElement | null { return this._videoRef; } - constructor(props: Readonly<FieldViewProps>) { + constructor(props: Readonly<ViewBoxAnnotatableProps & FieldViewProps>) { super(props); VideoBox.Instance = this; } @@ -309,7 +309,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive"; const style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive; return !field ? <div key="loading">Loading</div> : - <div className="container" key="container" style={{ pointerEvents: this._isChildActive || this.active() ? "all" : "none" }}> + <div className="container" key="container" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }}> <div className={`${style}`} style={{ width: "100%", height: "100%", left: "0px" }}> <video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef} style={{ height: "100%", width: "auto", display: "flex", margin: "auto" }} @@ -323,7 +323,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD Not supported. </video> {!this.audiopath || this.audiopath === field.url.href ? (null) : - <audio ref={this.setAudioRef} className={`audiobox-control${this.active() ? "-interactive" : ""}`}> + <audio ref={this.setAudioRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}> <source src={this.audiopath} type="audio/mpeg" /> Not supported. </audio>} @@ -420,7 +420,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD setupMoveUpEvents(this, e, action((e: PointerEvent) => { this._clicking = false; - if (this.active()) { + if (this.isContentActive()) { const local = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformPoint(e.clientX, e.clientY); this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100)); } @@ -429,7 +429,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD () => { this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent; setTimeout(action(() => this._clicking = false), 500); - }, this.active(), this.active()); + }, this.isContentActive(), this.isContentActive()); }); onResetDown = (e: React.PointerEvent) => { @@ -501,8 +501,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD } playing = () => this._playing; - isActiveChild = () => this._isChildActive; - timelineWhenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); + timelineWhenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)); timelineScreenToLocal = () => this.props.ScreenToLocalTransform().scale(this.scaling()).translate(0, -this.heightPercent / 100 * this.props.PanelHeight()); setAnchorTime = (time: number) => this.player!.currentTime = this.layoutDoc._currentTimecode = time; timelineHeight = () => this.props.PanelHeight() * (100 - this.heightPercent) / 100; @@ -510,6 +509,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD return <div className="videoBox-stackPanel" style={{ transition: this.transition, height: `${100 - this.heightPercent}%` }}> <CollectionStackedTimeline ref={this._stackedTimeline} {...this.props} fieldKey={this.annotationKey} + dictationKey={this.fieldKey + "-dictation"} mediaPath={this.audiopath} renderDepth={this.props.renderDepth + 1} startTag={"_timecodeToShow" /* videoStart */} @@ -520,13 +520,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD playFrom={this.playFrom} setTime={this.setAnchorTime} playing={this.playing} - whenActiveChanged={this.timelineWhenActiveChanged} + whenChildContentsActiveChanged={this.timelineWhenChildContentsActiveChanged} removeDocument={this.removeDocument} ScreenToLocalTransform={this.timelineScreenToLocal} - isChildActive={this.isActiveChild} Play={this.Play} Pause={this.Pause} - active={this.active} + isContentActive={this.isContentActive} playLink={this.playLink} PanelHeight={this.timelineHeight} /> @@ -538,7 +537,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD } marqueeDown = action((e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.active(true)) this._marqueeing = [e.clientX, e.clientY]; + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true)) this._marqueeing = [e.clientX, e.clientY]; }); finishMarquee = action(() => { @@ -572,13 +571,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD isAnnotationOverlay={true} annotationLayerHostsContent={true} select={emptyFunction} - active={this.annotationsActive} + isContentActive={this.isContentActive} scaling={returnOne} docFilters={this.timelineDocFilter} PanelWidth={this.panelWidth} PanelHeight={this.panelHeight} ScreenToLocalTransform={this.screenToLocalTransform} - whenActiveChanged={this.whenActiveChanged} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} addDocument={this.addDocWithTimecode} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 3337865a5..ab178c60b 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -12,7 +12,7 @@ import { makeInterface, listSpec } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { WebField } from "../../../fields/URLField"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, getWordAtPoint, OmitKeys, returnOne, smoothScroll, Utils } from "../../../Utils"; +import { emptyFunction, getWordAtPoint, OmitKeys, returnOne, smoothScroll, Utils, setupMoveUpEvents } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; @@ -21,7 +21,7 @@ import { undoBatch } from "../../util/UndoManager"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; import { LightboxView } from "../LightboxView"; import { MarqueeAnnotator } from "../MarqueeAnnotator"; @@ -39,7 +39,7 @@ type WebDocument = makeInterface<[typeof documentSchema]>; const WebDocument = makeInterface(documentSchema); @observer -export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocument>(WebDocument) { +export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, WebDocument>(WebDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); @@ -391,7 +391,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum @action onMarqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.active(true)) { + if (!e.altKey && e.button === 0 && this.isContentActive(true)) { this._marqueeing = [e.clientX, e.clientY]; this.props.select(false); } @@ -429,6 +429,20 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum if (!this.layoutDoc._showSidebar) this.toggleSidebar(); return this.addDocument(doc, sidebarKey); } + sidebarBtnDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, (e, down, delta) => { + const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]); + const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); + const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); + const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; + if (ratio >= 1) { + this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]; + this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + } + return false; + }, emptyFunction, this.toggleSidebar); + } toggleSidebar = action(() => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth; @@ -440,7 +454,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum sidebarWidth = () => !this.layoutDoc._showSidebar ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); @computed get content() { - return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.active() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")} + return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")} style={{ width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || `${100 / (this.props.scaling?.() || 1)}%`, }}> {this.urlContent} </div>; @@ -464,7 +478,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum const inactiveLayer = this.props.layerProvider?.(this.layoutDoc) === false; const scale = this.props.scaling?.() || 1; return ( - <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.annotationsActive() ? "all" : this.active() || SnappingManager.GetIsDragging() ? undefined : "none" }} > + <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.isContentActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} > <div className={`webBox-container`} style={{ pointerEvents: inactiveLayer ? "none" : undefined }} onContextMenu={this.specificContextMenu}> @@ -493,10 +507,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum PanelHeight={this.panelHeight} dropAction={"alias"} select={emptyFunction} - active={this.active} + isContentActive={this.isContentActive} ContentScaling={returnOne} bringToFront={emptyFunction} - whenActiveChanged={this.whenActiveChanged} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} addDocument={this.sidebarAddDocument} @@ -523,23 +537,22 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} />} </div > - <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar" - style={{ right: this.sidebarWidth() + 7, display: !this.active() ? "none" : undefined }} - onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} > - <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" /> - </button> <SidebarAnnos ref={this._sidebarRef} {...this.props} fieldKey={this.annotationKey} - annotationsActive={this.annotationsActive} rootDoc={this.rootDoc} layoutDoc={this.layoutDoc} dataDoc={this.dataDoc} sidebarAddDocument={this.sidebarAddDocument} moveDocument={this.moveDocument} removeDocument={this.removeDocument} - active={this.active} + isContentActive={this.isContentActive} /> + <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar" + style={{ display: !this.isContentActive() ? "none" : undefined }} + onPointerDown={this.sidebarBtnDown} > + <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" /> + </button> </div>); } }
\ No newline at end of file diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 0eade44ac..8915d7c47 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -2,7 +2,7 @@ import { IReactionDisposer, reaction, observable, action } from "mobx"; import { NodeSelection } from "prosemirror-state"; import { Doc, HeightSym, WidthSym } from "../../../../fields/Doc"; import { Cast, StrCast } from "../../../../fields/Types"; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, Utils } from "../../../../Utils"; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, Utils, returnTransparent } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; @@ -166,6 +166,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> { addDocument={returnFalse} rootSelected={this._textBox.props.isSelected} removeDocument={this.removeDoc} + isDocumentActive={returnFalse} + isContentActive={this._textBox.props.isContentActive} layerProvider={this._textBox.props.layerProvider} styleProvider={this._textBox.props.styleProvider} docViewPath={this._textBox.props.docViewPath} @@ -176,8 +178,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> { PanelWidth={this._finalLayout[WidthSym]} PanelHeight={this._finalLayout[HeightSym]} focus={this.outerFocus} - parentActive={returnFalse} - whenActiveChanged={returnFalse} + whenChildContentsActiveChanged={returnFalse} bringToFront={emptyFunction} dontRegisterView={false} docFilters={this.props.tbox?.props.docFilters} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index abfc63b40..26e78cfbf 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -145,7 +145,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }; } - public static FocusedBox: FormattedTextBox | undefined; public static PasteOnLoad: ClipboardEvent | undefined; public static SelectOnLoad = ""; public static DontSelectInitialText = false; // whether initial text should be selected or not @@ -782,7 +781,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp 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.props.contentsActive?.(this.active); this._cachedLinks = DocListCast(this.Document.links); this._disposers.breakupDictation = reaction(() => DocumentManager.Instance.RecordingEvent, this.breakupDictation); this._disposers.autoHeight = reaction(() => this.autoHeight, autoHeight => autoHeight && this.tryUpdateScrollHeight()); @@ -1192,7 +1190,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if ((e.nativeEvent as any).formattedHandled) { console.log("handled"); } - if (!(e.nativeEvent as any).formattedHandled && this.active(true)) { + if (!(e.nativeEvent as any).formattedHandled && this.isContentActive(true)) { const editor = this._editorView!; const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY }); !this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0)))); @@ -1225,26 +1223,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp e.stopPropagation(); } } + setFocus = () => { + const pos = this._editorView?.state.selection.$from.pos || 1; + (this.ProseRef?.children?.[0] as any).focus(); + setTimeout(() => this._editorView?.dispatch(this._editorView?.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos)))); + } @action onFocused = (e: React.FocusEvent): void => { - FormattedTextBox.FocusedBox = this; //applyDevTools.applyDevTools(this._editorView); - - // see if we need to preserve the insertion point - const prosediv = this.ProseRef?.children?.[0] as any; - const keeplocation = prosediv?.keeplocation; - prosediv && (prosediv.keeplocation = undefined); - const pos = this._editorView?.state.selection.$from.pos || 1; - keeplocation && setTimeout(() => this._editorView?.dispatch(this._editorView?.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos)))); - this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props); } - onPointerWheel = (e: React.WheelEvent): void => { - // if a text note is selected and scrollable, stop event to prevent, say, outer collection from zooming. - if ((this.props.rootSelected(true) || this.props.isSelected(true)) || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { - e.stopPropagation(); - } - } + onClick = (e: React.MouseEvent): void => { if (Math.abs(e.clientX - this._downX) > 4 || Math.abs(e.clientY - this._downY) > 4) { this._forceDownNode = undefined; @@ -1447,7 +1436,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @computed get sidebarHandle() { TraceMobx(); const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length; - return (!annotated && !this.active()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} + return (!annotated && !this.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : "")) @@ -1467,9 +1456,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp scaleField={this.SidebarKey + "-scale"} isAnnotationOverlay={false} select={emptyFunction} - active={this.annotationsActive} + isContentActive={this.isContentActive} scaling={this.sidebarContentScaling} - whenActiveChanged={this.whenActiveChanged} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} removeDocument={this.sidebarRemDocument} moveDocument={this.sidebarMoveDocument} addDocument={this.sidebarAddDocument} @@ -1489,7 +1478,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp render() { TraceMobx(); const selected = this.props.isSelected(); - const active = this.active(); + const active = this.isContentActive(); const scale = this.props.hideOnLeave ? 1 : (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false); @@ -1501,6 +1490,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : ""; return ( <div className="formattedTextBox-cont" + onWheel={e => this.isContentActive() && e.stopPropagation()} style={{ transform: `scale(${scale})`, transformOrigin: "top left", @@ -1529,7 +1519,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp onPointerUp={this.onPointerUp} onPointerDown={this.onPointerDown} onMouseUp={this.onMouseUp} - onWheel={this.onPointerWheel} onDoubleClick={this.onDoubleClick} > <div className={`formattedTextBox-outer${selected ? "-selected" : ""}`} ref={this._scrollRef} |
