diff options
Diffstat (limited to 'src/client/views/nodes')
27 files changed, 331 insertions, 292 deletions
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 908cd5dc0..1729af191 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -211,7 +211,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // removes from currently playing display @action removeCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (CollectionStackedTimeline.CurrentlyPlaying && docView) { const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView); index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1); @@ -221,7 +221,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // adds doc to currently playing display @action addCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (!CollectionStackedTimeline.CurrentlyPlaying) { CollectionStackedTimeline.CurrentlyPlaying = []; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index ad5aabc21..83cabf355 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -15,7 +15,7 @@ import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import './CollectionFreeFormDocumentView.scss'; -import { DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView'; +import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; import { FieldViewProps } from './FieldView'; export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { @@ -149,7 +149,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF return this._props.CollectionFreeFormView; } - styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { if (doc === this.layoutDoc) { switch (property) { case StyleProp.Opacity: return this._props.w_Opacity(); // only change the opacity for this specific document, not its children @@ -229,7 +229,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF @action public float = () => { const topDoc = this.Document; - const containerDocView = this._props.docViewPath().lastElement(); + const containerDocView = this._props.containerViewPath?.().lastElement(); const screenXf = containerDocView?.screenToContentsTransform(); if (screenXf) { SelectionManager.DeselectAll(); @@ -252,7 +252,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF }; nudge = (x: number, y: number) => { - const [locX, locY] = this.ScreenToLocalBoxXf().transformDirection(x, y); + const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y); this._props.Document.x = this._props.w_X() + locX; this._props.Document.y = this._props.w_Y() + locY; }; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 5e7e568b0..b171db17c 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -11,7 +11,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from './DocumentView'; +import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @@ -148,7 +148,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl e => this.clearDoc(which) ); }; - docStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => { if (property === StyleProp.PointerEvents) return 'none'; return this._props.styleProvider?.(doc, props, property); }; @@ -178,6 +178,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl {...this._props} Document={targetDoc} TemplateDataDocument={undefined} + containerViewPath={this.docViewPathFunc} moveDocument={which.endsWith('1') ? this.moveDoc1 : this.moveDoc2} removeDocument={which.endsWith('1') ? this.remDoc1 : this.remDoc2} NativeWidth={returnZero} diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 5a55ca764..5ceec98cb 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Colors, Toggle, ToggleType, Type } from 'browndash-components'; -import { ObservableMap, action, computed, observable, runInAction } from 'mobx'; +import { ObservableMap, action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils'; @@ -14,10 +14,9 @@ import { TraceMobx } from '../../../../fields/util'; import { Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { UndoManager, undoable } from '../../../util/UndoManager'; -import { ViewBoxAnnotatableComponent } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; import { MarqueeAnnotator } from '../../MarqueeAnnotator'; import { SidebarAnnos } from '../../SidebarAnnos'; -import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup'; import { DocFocusOptions, DocumentView } from '../DocumentView'; @@ -37,22 +36,28 @@ export enum DataVizView { } @observer -export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { +export class DataVizBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() { private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); - private _ffref = React.createRef<CollectionFreeFormView>(); private _marqueeref = React.createRef<MarqueeAnnotator>(); private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); anchorMenuClick?: () => undefined | ((anchor: Doc) => void); crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined; - @observable schemaDataVizChildren: any = undefined; + @observable _schemaDataVizChildren: any = undefined; @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); + + constructor(props: ViewBoxAnnotatableProps & FieldViewProps) { + super(props); + makeObservable(this); + this._props.setContentView?.(this); + } + @computed get annotationLayer() { TraceMobx(); return <div className="dataVizBox-annotationLayer" style={{ height: this._props.PanelHeight(), width: this._props.PanelWidth() }} ref={this._annotationLayer} />; } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -211,12 +216,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { .ScreenToLocalTransform() .scale(this._props.NativeDimScaling?.() || 1) .transformDirection(delta[0], delta[1]); - const fullWidth = this._props.width; - const mapWidth = fullWidth! - this.sidebarWidth(); + const fullWidth = NumCast(this.layoutDoc._width); + const mapWidth = fullWidth - this.sidebarWidth(); if (this.sidebarWidth() + localDelta[0] > 0) { this.layoutDoc._layout_showSidebar = true; - this.layoutDoc._width = fullWidth! + localDelta[0]; - this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth! + localDelta[0])).toString() + '%'; + this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%'; + this.layoutDoc._width = fullWidth + localDelta[0]; } else { this.layoutDoc._layout_showSidebar = false; this.layoutDoc._width = mapWidth; @@ -269,12 +274,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { axes: this.axes, //width: this.SidebarShown? this._props.PanelWidth()*.9/1.2: this._props.PanelWidth() * 0.9, height: (this._props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9, - width: (this._props.PanelWidth() / scale) * 0.9, + width: ((this._props.PanelWidth() - this.sidebarWidth()) / scale) * 0.9, margin: { top: 10, right: 25, bottom: 75, left: 45 }, }; if (!this.records.length) return 'no data/visualization'; switch (this.dataVizView) { - case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this._props.DocumentView} selectAxes={this.selectAxes} />; + case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this.DocumentView} selectAxes={this.selectAxes} />; case DataVizView.LINECHART: return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} vizBox={this} />; case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />; case DataVizView.PIECHART: return <PieChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} @@ -285,7 +290,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @action onPointerDown = (e: React.PointerEvent): void => { if ((this.Document._freeform_scale || 1) !== 1) return; - if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this._props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -345,7 +350,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { render() { if (this.layoutDoc && this.layoutDoc.dataViz_asSchema) { - this.schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length; + this._schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length; this.updateSchemaViz(); } @@ -366,7 +371,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }} onWheel={e => e.stopPropagation()} ref={this._mainCont}> - <div className={'datatype-button'}> + <div className="datatype-button"> <Toggle text={' TABLE '} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz === DataVizView.TABLE} /> <Toggle text={'LINECHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz === DataVizView.LINECHART} /> <Toggle text={'HISTOGRAM'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz === DataVizView.HISTOGRAM} /> @@ -414,7 +419,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { </div> {this.sidebarHandle} {this.annotationLayer} - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( <MarqueeAnnotator ref={this._marqueeref} Document={this.Document} @@ -422,7 +427,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { scrollTop={0} annotationLayerScrollTop={NumCast(this.Document._layout_scrollTop)} scaling={returnOne} - docView={this._props.DocumentView!} + docView={this.DocumentView} addDocument={this.sidebarAddDocument} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 4cc7fe4c8..0d76959af 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -116,11 +116,12 @@ export class HTMLtag extends React.Component<HTMLtagProps> { @observer export class DocumentContentsView extends ObservableReactComponent< - DocumentViewProps & - FieldViewProps & { - setHeight?: (height: number) => void; - layout_fieldKey: string; - } + FieldViewProps & { + layout_fieldKey: string; + LayoutTemplateString?: string; + onClick?: () => ScriptField; + LayoutTemplate?: () => Opt<Doc>; + } > { constructor(props: any) { super(props); diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index dfd610581..25f56e69a 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -25,7 +25,7 @@ export class DocumentIcon extends ObservableReactComponent<DocumentIconProps> { } static get DocViews() { - return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v._props.docViewPath())) : DocumentManager.Instance.DocumentViews; + return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v.docViewPath)) : DocumentManager.Instance.DocumentViews; } render() { const view = this._props.view; diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index c549a146a..f5949a451 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -152,8 +152,8 @@ export class DocumentLinksButton extends ObservableReactComponent<DocumentLinksB DocumentLinksButton.AnnotationUri = undefined; //!this._props.StartLink } else if (startLink !== endLink) { - endLink = endLinkView?.docView?._componentView?.getAnchor?.(true, pinProps) || endLink; - startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink; + endLink = endLinkView?.ComponentView?.getAnchor?.(true, pinProps) || endLink; + startLink = DocumentLinksButton.StartLinkView?.ComponentView?.getAnchor?.(true) || startLink; const linkDoc = DocUtils.MakeLink(startLink, endLink, { link_relationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined }); LinkManager.currentLink = linkDoc; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6cc61ec62..5345ef0d8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -109,7 +109,7 @@ export interface DocFocusOptions { easeFunc?: 'linear' | 'ease'; // transition method for scrolling } export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => Opt<number>; -export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => any; +export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => any; export interface DocComponentView { fieldKey?: string; annotationKey?: string; @@ -143,20 +143,31 @@ export interface DocComponentView { snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number }; search?: (str: string, bwd?: boolean, clear?: boolean) => boolean; } -// These props are passed to both FieldViews and DocumentViews +/** + * props that DocumentViews, DocumentInternalViews and FieldViews all can use + * */ export interface DocumentViewSharedProps { - renderDepth: number; Document: Doc; TemplateDataDocument?: Doc; + renderDepth: number; scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document - DocumentView?: () => DocumentView; + treeViewDoc?: Doc; + xPadding?: number; + yPadding?: number; + dontRegisterView?: boolean; + dropAction?: dropActionType; + dragAction?: dropActionType; + forceAutoHeight?: boolean; + ignoreAutoHeight?: boolean; + disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document isGroupActive?: () => string | undefined; // is this document part of a group that is active setContentView?: (view: DocComponentView) => any; PanelWidth: () => number; PanelHeight: () => number; - docViewPath: () => DocumentView[]; + isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events + isContentActive: () => boolean | undefined; // whether document contents should handle pointer events childFilters: () => string[]; childFiltersByRanges: () => string[]; styleProvider: Opt<StyleProviderFunc>; @@ -178,29 +189,12 @@ export interface DocumentViewSharedProps { waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; defaultDoubleClick?: () => 'default' | 'ignore' | undefined; pointerEvents?: () => Opt<string>; - treeViewDoc?: Doc; - xPadding?: number; - yPadding?: number; - dontRegisterView?: boolean; - childHideDecorationTitle?: boolean; - childHideResizeHandles?: boolean; - childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar. - dropAction?: dropActionType; - dragAction?: dropActionType; - dragWhenActive?: boolean; - dontHideOnDrag?: boolean; - hideLinkButton?: boolean; - hideCaptions?: boolean; - ignoreAutoHeight?: boolean; - forceAutoHeight?: boolean; - suppressSetHeight?: boolean; - disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. - onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected } -// these props are specific to DocuentViews +/** + * props that are used by DocumentViews and DocumentInternalViews but not by the contents of those views (FieldViews). + */ export interface DocumentViewProps extends DocumentViewSharedProps { - // properties specific to DocumentViews but not to FieldView hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings @@ -209,15 +203,22 @@ export interface DocumentViewProps extends DocumentViewSharedProps { hideOpenButton?: boolean; hideDeleteButton?: boolean; hideLinkAnchors?: boolean; + hideLinkButton?: boolean; + hideCaptions?: boolean; contentPointerEvents?: 'none' | 'all' | undefined; // 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 LayoutTemplateString?: string; dontCenter?: 'x' | 'y' | 'xy'; - isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events - isContentActive: () => boolean | undefined; // whether document contents should handle pointer events + childHideDecorationTitle?: boolean; + childHideResizeHandles?: boolean; + childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar. + dragWhenActive?: boolean; + dontHideOnDrag?: boolean; + suppressSetHeight?: boolean; + onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected NativeWidth?: () => number; NativeHeight?: () => number; - NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to FieldViewProps LayoutTemplate?: () => Opt<Doc>; + containerViewPath?: () => DocumentView[]; contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[]; onClick?: () => ScriptField; onDoubleClick?: () => ScriptField; @@ -229,12 +230,18 @@ export interface DocumentViewProps extends DocumentViewSharedProps { dragEnding?: () => void; } -// these props are only available in DocumentViewIntenral -export interface DocumentViewInternalProps extends DocumentViewProps { - isSelected: () => boolean; +/** + * props used by DocInternalViews and FieldViews but not DocumentViews + * these props correspond to things that the DocumentView creates and thus doesn't need to receive as a prop + */ +export interface DocumentViewInternalSharedProps { + DocumentView?: () => DocumentView; select: (ctrlPressed: boolean, shiftPress?: boolean) => void; - DocumentView: () => DocumentView; - viewPath: () => DocumentView[]; + isSelected: () => boolean; + NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal +} +export interface DocumentViewInternalProps extends DocumentViewProps, DocumentViewInternalSharedProps { + docViewPath: () => DocumentView[]; } @observer @@ -265,17 +272,24 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps return this._animateScaleTime ?? 100; } public get displayName() { - return 'DocumentViewInternal(' + this._props.Document.title + ')'; + return 'DocumentViewInternal(' + this.Document.title + ')'; } // this makes mobx trace() statements more descriptive + public get DocumentView() { + return this._props.DocumentView!; + } + public get ContentDiv() { return this._mainCont.current; } public get LayoutFieldKey() { return Doc.LayoutFieldKey(this.layoutDoc); } + @computed get styleProps(): FieldViewProps { + return { ...this._props, fieldKey: '' }; + } @computed get layout_showTitle() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.ShowTitle) as Opt<string>; + return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.ShowTitle) as Opt<string>; } @computed get NativeDimScaling() { return this._props.NativeDimScaling?.() || 1; @@ -284,32 +298,32 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png'); } @computed get opacity() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Opacity); + return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.Opacity); } @computed get boxShadow() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow); + return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BoxShadow); } @computed get borderRounding() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding); + return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BorderRounding); } @computed get widgetDecorations() { TraceMobx(); - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Decorations); + return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.Decorations); } @computed get backgroundBoxColor() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor + ':box'); + return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BackgroundColor + ':box'); } @computed get docContents() { - return this._props.styleProvider?.(this.Document, this._props, StyleProp.DocContents); + return this._props.styleProvider?.(this.Document, this.styleProps, StyleProp.DocContents); } @computed get headerMargin() { - return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) || 0; + return this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.HeaderMargin) || 0; } @computed get layout_showCaption() { - return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.ShowCaption) || 0; + return this._props?.hideCaptions ? undefined : this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.ShowCaption) || 0; } @computed get titleHeight() { - return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.TitleHeight) || 0; + return this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.TitleHeight) || 0; } @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined { @@ -363,7 +377,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps { fireImmediately: true } ); this._disposers.pointerevents = reaction( - () => this._props.styleProvider?.(this.Document, this._props, StyleProp.PointerEvents), + () => this._props.styleProvider?.(this.Document, this.styleProps, StyleProp.PointerEvents), pointerevents => (this._pointerEvents = pointerevents), { fireImmediately: true } ); @@ -378,32 +392,32 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps setupHandlers() { this.cleanupHandlers(false); if (this._mainCont.current) { - this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this._props.Document, this.preDropFunc); + this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.Document, this.preDropFunc); } } cleanupHandlers(unbrush: boolean) { this._dropDisposer?.(); - unbrush && Doc.UnBrushDoc(this._props.Document); + unbrush && Doc.UnBrushDoc(this.Document); Object.values(this._disposers).forEach(disposer => disposer?.()); } startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) { if (this._mainCont.current) { - const views = SelectionManager.Views.filter(dv => dv.docView?._mainCont.current); - const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this._props.DocumentView()]; + const views = SelectionManager.Views.filter(dv => dv.ContentDiv); + const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this.DocumentView()]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); - const screenXf = this.props.DocumentView().screenToViewTransform(); + const screenXf = this.DocumentView().screenToViewTransform(); const [left, top] = screenXf.inverse().transformPoint(0, 0); dragData.offset = screenXf.transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.treeViewDoc = this._props.treeViewDoc; dragData.removeDocument = this._props.removeDocument; dragData.moveDocument = this._props.moveDocument; - dragData.draggedViews = [this._props.DocumentView()]; + dragData.draggedViews = [this.DocumentView()]; dragData.canEmbed = this.Document.dragAction ?? this._props.dragAction ? true : false; DragManager.StartDocumentDrag( - selected.map(dv => dv.docView!._mainCont.current!), + selected.map(dv => dv.ContentDiv!), dragData, x, y, @@ -443,7 +457,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps const func = () => this.onDoubleClickHandler.script.run( { this: this.Document, scriptContext: this._props.scriptContext, - documentView: this._props.DocumentView(), + documentView: this.DocumentView(), clientX, clientY, altKey, shiftKey, ctrlKey, value: undefined, }, console.log ); @@ -451,7 +465,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps } else if (!Doc.IsSystem(this.Document) && (defaultDblclick === undefined || defaultDblclick === 'default')) { UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap'); SelectionManager.DeselectAll(); - Doc.UnBrushDoc(this._props.Document); + Doc.UnBrushDoc(this.Document); } else { this._singleClickFunc?.(); } @@ -474,7 +488,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps this: this.Document, _readOnly_: false, scriptContext: this._props.scriptContext, - documentView: this._props.DocumentView(), + documentView: this.DocumentView(), clientX, clientY, shiftKey, @@ -498,7 +512,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps const sendToBack = e.altKey; this._singleClickFunc = // prettier-ignore - clickFunc ?? (() => (sendToBack ? this._props.DocumentView()._props.bringToFront(this.Document, true) : + clickFunc ?? (() => (sendToBack ? this.DocumentView()._props.bringToFront(this.Document, true) : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this._props.select(e.ctrlKey||e.shiftKey, e.metaKey))); const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; @@ -522,7 +536,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps this._props.select(false); } }, 1000); - if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._props.DocumentView(); + if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this.DocumentView(); this._downX = e.clientX; this._downY = e.clientY; @@ -600,7 +614,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps this.Document.onClick = Doc.GetProto(this.Document).onClick = undefined; }; - @undoBatch deleteClicked = () => this._props.removeDocument?.(this._props.Document); + @undoBatch deleteClicked = () => this._props.removeDocument?.(this.Document); @undoBatch setToggleDetail = () => (this.Document.onClick = ScriptField.MakeScript( `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) @@ -612,7 +626,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps @undoBatch drop = (e: Event, de: DragManager.DropEvent) => { if (this._props.dontRegisterView || this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false; - if (this._props.Document === Doc.ActiveDashboard) { + if (this.Document === Doc.ActiveDashboard) { e.stopPropagation(); e.preventDefault(); alert( @@ -634,7 +648,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]); if (de.complete.linkDocument) { de.complete.linkDocument.layout_isSvg = true; - this._props.DocumentView().CollectionFreeFormView?.addDocument(de.complete.linkDocument); + this.DocumentView().CollectionFreeFormView?.addDocument(de.complete.linkDocument); } } e.stopPropagation(); @@ -646,16 +660,16 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps @undoBatch makeIntoPortal = () => { - const portalLink = this.allLinks.find(d => d.link_anchor_1 === this._props.Document && d.link_relationship === 'portal to:portal from'); + const portalLink = this.allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from'); if (!portalLink) { DocUtils.MakeLink( - this._props.Document, + this.Document, Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: Math.max(NumCast(this.layoutDoc._height), NumCast(this.layoutDoc._width) + 10), _isLightbox: true, _layout_fitWidth: true, - title: StrCast(this._props.Document.title) + ' [Portal]', + title: StrCast(this.Document.title) + ' [Portal]', }), { link_relationship: 'portal to:portal from' } ); @@ -686,7 +700,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps if (e && this.layoutDoc._layout_hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); - //!this._props.isSelected(true) && SelectionManager.SelectView(this._props.DocumentView(), false); + //!this._props.isSelected(true) && SelectionManager.SelectView(this.DocumentView(), false); } // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 if (e) { @@ -708,7 +722,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps if (e && !(e.nativeEvent as any).dash) { const onDisplay = () => { - if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this._props.isSelected() && SelectionManager.SelectView(this._props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this._props.isSelected() && SelectionManager.SelectView(this.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -719,14 +733,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps return; } - const customScripts = Cast(this._props.Document.contextMenuScripts, listSpec(ScriptField), []); + const customScripts = Cast(this.Document.contextMenuScripts, listSpec(ScriptField), []); StrListCast(this.Document.contextMenuLabels).forEach((label, i) => cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this._props.scriptContext }), icon: 'sticky-note' }) ); this._props.contextMenuItems?.().forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.Document, scriptContext: this._props.scriptContext }), icon: item.icon as IconProp })); - if (!this._props.Document.isFolder) { - const templateDoc = Cast(this._props.Document[StrCast(this._props.Document.layout_fieldKey)], Doc, null); + if (!this.Document.isFolder) { + const templateDoc = Cast(this.Document[StrCast(this.Document.layout_fieldKey)], Doc, null); const appearance = cm.findByDescription('Appearance...'); const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : []; @@ -764,7 +778,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' }); onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' }); - !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this._props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); + !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } else if (LinkManager.Links(this.Document).length) { onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' }); @@ -786,15 +800,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps const moreItems = more && 'subitems' in more ? more.subitems : []; if (!Doc.IsSystem(this.Document)) { if (!Doc.noviceMode) { - moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this._props.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); + moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => (this.Document._chromeHidden = !this.Document._chromeHidden), icon: 'project-diagram' }); - if (Cast(Doc.GetProto(this._props.Document).data, listSpec(Doc))) { - moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this._props.Document }).then(console.log), icon: 'caret-square-right' }); - moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this._props.Document), icon: 'caret-square-right' }); - moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this._props.Document), icon: 'caret-square-right' }); + if (Cast(Doc.GetProto(this.Document).data, listSpec(Doc))) { + moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.Document }).then(console.log), icon: 'caret-square-right' }); + moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this.Document), icon: 'caret-square-right' }); + moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this.Document), icon: 'caret-square-right' }); } - moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this._props.Document)), icon: 'fingerprint' }); + moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' }); } } @@ -802,14 +816,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps } const constantItems: ContextMenuProps[] = []; if (!Doc.IsSystem(this.Document) && this.Document._type_collection !== CollectionViewType.Docking) { - constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this._props.Document) }); - (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this._props.DocumentView()), icon: 'users' }); - if (this._props.removeDocument && Doc.ActiveDashboard !== this._props.Document) { + constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this.Document) }); + (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.DocumentView()), icon: 'users' }); + if (this._props.removeDocument && Doc.ActiveDashboard !== this.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); } } - constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this._props.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' }); + constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' }); cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); const help = cm.findByDescription('Help...'); @@ -820,7 +834,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps let documentationDescription: string | undefined = undefined; let documentationLink: string | undefined = undefined; - switch (this._props.Document.type) { + switch (this.Document.type) { case DocumentType.COL: documentationDescription = 'See collection documentation'; documentationLink = 'https://brown-dash.github.io/Dash-Documentation/views/'; @@ -874,7 +888,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps } rootSelected = () => this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; - screenToLocalContent = () => this.ScreenToLocalBoxXf().translate(0, -this.headerMargin); + screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); @@ -912,7 +926,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps {...this._props} fieldKey="" pointerEvents={this.contentPointerEvents} - docViewPath={this._props.viewPath} setContentView={this.setContentView} childFilters={this.childFilters} PanelHeight={this.panelHeight} @@ -931,7 +944,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps anchorPanelWidth = () => this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + anchorStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => { // prettier-ignore switch (property.split(':')[0]) { case StyleProp.ShowTitle: return ''; @@ -976,7 +989,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps {...this._props} isContentActive={returnFalse} Document={link} - docViewPath={this._props.viewPath} + containerViewPath={this._props.docViewPath} PanelWidth={this.anchorPanelWidth} PanelHeight={this.anchorPanelHeight} dontRegisterView={false} @@ -1066,7 +1079,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps } }; - captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); + captionStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); @observable _changingTitleField = false; @observable _dropDownInnerWidth = 0; fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { @@ -1266,10 +1279,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps } } @computed get highlighting() { - return this._props.styleProvider?.(this.Document, this._props, StyleProp.Highlighting); + return this._props.styleProvider?.(this.Document, { ...this._props, fieldKey: '' }, StyleProp.Highlighting); } @computed get borderPath() { - return this._props.styleProvider?.(this.Document, this._props, StyleProp.BorderPath); + return this._props.styleProvider?.(this.Document, { ...this._props, fieldKey: '' }, StyleProp.BorderPath); } render() { TraceMobx(); @@ -1332,14 +1345,13 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { @computed public static get exploreMode() { return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); } - @observable public docView: DocumentViewInternal | undefined | null = undefined; - @observable public textHtmlOverlay: Opt<string> = undefined; - @observable public textHtmlOverlayTime: Opt<number> = undefined; + @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined; + @observable private _htmlOverlayText: Opt<string> = undefined; @observable private _isHovering = false; + private _htmlOverlayEffect: Opt<Doc>; - public htmlOverlayEffect: Opt<Doc>; public get displayName() { - return 'DocumentView(' + this._props.Document?.title + ')'; + return 'DocumentView(' + this.Document?.title + ')'; } // this makes mobx trace() statements more descriptive public ContentRef = React.createRef<HTMLDivElement>(); public ViewTimer: NodeJS.Timeout | undefined; // timer for res @@ -1349,10 +1361,26 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { this.ViewTimer && clearTimeout(this.ViewTimer); this.layoutDoc._viewTransition = undefined; }; - public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource); - - public showContextMenu = (pageX: number, pageY: number) => this.docView?.onContextMenu(undefined, pageX, pageY); - + playAnnotation = () => this._docViewInternal?.playAnnotation(); + noOnClick = () => this._docViewInternal?.noOnClick(); + makeIntoPortal = () => this._docViewInternal?.makeIntoPortal(); + setToggleDetail = () => this._docViewInternal?.setToggleDetail(); + onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); + cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); + public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + + public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); + + public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => { + this._htmlOverlayText = text; + this._htmlOverlayEffect = effect; + }); + public setAnimateScaling = action((scale: number, time?: number) => { + if (this._docViewInternal) { + this._docViewInternal._animateScalingTo = scale; + this._docViewInternal._animateScaleTime = time; + } + }); public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer); this.Document[Animation] = presEffect; @@ -1391,10 +1419,11 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { DocServer.GetRefField(docId).then(docx => LightboxView.Instance.SetLightboxDoc( (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection - Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) + Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) ) ); } + toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle); get Document() { return this._props.Document; @@ -1403,19 +1432,19 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { return this._props.renderDepth === 0; } get dataDoc() { - return this.docView?.dataDoc ?? this.Document; + return this._docViewInternal?.dataDoc ?? this.Document; } get ContentDiv() { - return this.docView?.ContentDiv; + return this._docViewInternal?.ContentDiv; } get ComponentView() { - return this.docView?._componentView; + return this._docViewInternal?._componentView; } get allLinks() { - return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); + return (this._docViewInternal?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); } get LayoutFieldKey() { - return this.docView?.LayoutFieldKey || 'layout'; + return this._docViewInternal?.LayoutFieldKey || 'layout'; } @computed get layout_fitWidth() { return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; @@ -1439,8 +1468,17 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { @computed get linkCountView() { return <DocumentLinksButton hideCount={this.hideLinkCount} View={this} scaling={this.screenToLocalScale} OnHover={true} Bottom={this.topMost} ShowCount={true} />; } + /** + * path of DocumentViews terminating in the DocumentView that contains this DocumentView + */ + @computed get containerViewPath() { + return this._props.containerViewPath; + } + /** + * path of DocumentViews terminating in this DocumentView + */ @computed get docViewPath(): DocumentView[] { - return this._props.docViewPath ? [...this._props.docViewPath(), this] : [this]; + return this.containerViewPath ? [...this.containerViewPath(), this] : [this]; } @computed get layoutDoc() { return Doc.Layout(this.Document, this._props.LayoutTemplate?.()); @@ -1502,19 +1540,19 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { return this._props.CollectionFreeFormDocumentView?.(); } - public toggleNativeDimensions = () => this.docView && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this._props.PanelWidth(), this._props.PanelHeight()); + public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this._docViewInternal.NativeDimScaling, this._props.PanelWidth(), this._props.PanelHeight()); public getBounds = () => { - if (!this.docView?.ContentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this._props.Document, Doc.UserDoc())) { + if (!this._docViewInternal?.ContentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) { return undefined; } - if (this.docView._componentView?.screenBounds?.()) { - return this.docView._componentView.screenBounds(); + if (this._docViewInternal._componentView?.screenBounds?.()) { + return this._docViewInternal._componentView.screenBounds(); } - const xf = this.docView.ScreenToLocalBoxXf().scale(this.nativeScaling).inverse(); + const xf = this._docViewInternal._props.ScreenToLocalTransform().scale(this.nativeScaling).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; - if (this.docView._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); + if (this._docViewInternal._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { + const docuBox = this._docViewInternal.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined }; } return { left, top, right, bottom }; @@ -1522,11 +1560,11 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { public iconify(finished?: () => void, animateTime?: number) { this.ComponentView?.updateIcon?.(); - const animTime = this.docView?._animateScaleTime; - runInAction(() => this.docView && animateTime !== undefined && (this.docView._animateScaleTime = animateTime)); + const animTime = this._docViewInternal?._animateScaleTime; + runInAction(() => this._docViewInternal && animateTime !== undefined && (this._docViewInternal._animateScaleTime = animateTime)); const finalFinished = action(() => { finished?.(); - this.docView && (this.docView._animateScaleTime = animTime); + this._docViewInternal && (this._docViewInternal._animateScaleTime = animTime); }); const layout_fieldKey = Cast(this.Document.layout_fieldKey, 'string', null); if (layout_fieldKey !== 'layout_icon') { @@ -1541,12 +1579,12 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { } @undoBatch setCustomView = (custom: boolean, layout: string): void => { - Doc.setNativeView(this._props.Document); - custom && DocUtils.makeCustomViewClicked(this._props.Document, Docs.Create.StackingDocument, layout, undefined); + Doc.setNativeView(this.Document); + custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined); }; switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => { - runInAction(() => this.docView && (this.docView._animateScalingTo = 0.1)); // shrink doc + runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc setTimeout( action(() => { if (useExistingLayout && custom && this.Document['layout_' + view]) { @@ -1554,16 +1592,16 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { } else { this.setCustomView(custom, view); } - this.docView && (this.docView._animateScalingTo = 1); // expand it + this._docViewInternal && (this._docViewInternal._animateScalingTo = 1); // expand it setTimeout( action(() => { - this.docView && (this.docView._animateScalingTo = 0); + this._docViewInternal && (this._docViewInternal._animateScalingTo = 0); finished?.(); }), - this.docView ? Math.max(0, this.docView.animateScaleTime - 10) : 0 + this._docViewInternal ? Math.max(0, this._docViewInternal.animateScaleTime - 10) : 0 ); }), - this.docView ? Math.max(0, this.docView?.animateScaleTime - 10) : 0 + this._docViewInternal ? Math.max(0, this._docViewInternal?.animateScaleTime - 10) : 0 ); }; @@ -1606,29 +1644,21 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { componentDidMount() { runInAction(() => this.Document[DocViews].add(this)); - this._disposers.updateContentsScript = reaction(() => ScriptCast(this.Document.updateContentsScript)?.script?.run({ this: this.Document }).result, emptyFunction); - this._disposers.height = reaction( - // increase max auto height if document has been resized to be greater than current max - () => NumCast(this.layoutDoc._height), - action(height => { - const docMax = NumCast(this.layoutDoc.layout_maxAutoHeight); - if (docMax && docMax < height) this.layoutDoc.layout_maxAutoHeight = height; - }) - ); - !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); + this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); } componentWillUnmount() { - this.Document[DocViews].delete(this); + runInAction(() => this.Document[DocViews].delete(this)); Object.values(this._disposers).forEach(disposer => disposer?.()); - !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed. // unfortunately, CSS can't transition animate any properties for something that is display 'none'. // so we need to first activate the div, then, after a render timeout, start the opacity transition. @observable enableHtmlOverlayTransitions: boolean = false; @computed get htmlOverlay() { - const effect = StrCast(this.htmlOverlayEffect?.presentation_effect, StrCast(this.htmlOverlayEffect?.followLinkAnimEffect)); + const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect)); return ( <div className="documentView-htmlOverlay" @@ -1638,13 +1668,13 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { setTimeout(action(() => (this.enableHtmlOverlayTransitions = val))); } }} - style={{ display: !this.textHtmlOverlay ? 'none' : undefined }}> + style={{ display: !this._htmlOverlayText ? 'none' : undefined }}> <div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this.enableHtmlOverlayTransitions ? 0.9 : 0 }}> {DocumentViewInternal.AnimationEffect( <div className="webBox-textHighlight"> - <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} /> + <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} /> </div>, - { ...(this.htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, + { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, this.Document )} </div> @@ -1663,7 +1693,7 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { return ( <div className="contentFittingDocumentView" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))}> - {!this._props.Document || !this._props.PanelWidth() ? null : ( + {!this.Document || !this._props.PanelWidth() ? null : ( <div className="contentFittingDocumentView-previewDoc" ref={this.ContentRef} @@ -1676,7 +1706,7 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { <DocumentViewInternal {...this._props} DocumentView={this.selfView} - viewPath={this.docViewPathFunc} + docViewPath={this.docViewPathFunc} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} NativeWidth={this.NativeWidth} @@ -1687,7 +1717,7 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> { layout_fitWidth={this.layout_fitWidthFunc} ScreenToLocalTransform={this.screenToContentsTransform} focus={this._props.focus || emptyFunction} - ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} + ref={action((r: DocumentViewInternal | null) => r && (this._docViewInternal = r))} /> {this.htmlOverlay} {this.infoUI} diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index ff92c701f..ebad257ac 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -27,7 +27,7 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() { componentDidMount() { this._props.setContentView?.(this); - if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) { + if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath))) { this._props.select(false); this._ref.current!.mathField.focus(); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 008f10f26..b456807d7 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -6,23 +6,18 @@ import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ScriptField } from '../../../fields/ScriptField'; import { WebField } from '../../../fields/URLField'; -import { DocumentViewSharedProps } from './DocumentView'; +import { DocumentView, DocumentViewInternalSharedProps, DocumentViewSharedProps } from './DocumentView'; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. // See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. // -export interface FieldViewProps extends DocumentViewSharedProps { +export interface FieldViewProps extends DocumentViewSharedProps, DocumentViewInternalSharedProps { // FieldView specific props that are not part of DocumentView props fieldKey: string; - select: (isCtrlPressed: boolean) => void; - isContentActive: (outsideReaction?: boolean) => boolean | undefined; - isDocumentActive?: () => boolean | undefined; - isSelected: () => boolean; setHeight?: (height: number) => void; - NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps onBrowseClick?: () => ScriptField | undefined; onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; pointerEvents?: () => Opt<string>; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index a5853499f..4483d12ce 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -158,7 +158,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @undoBatch setNativeSize = action(() => { - const scaling = (this._props.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); + const scaling = (this.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); const nscale = NumCast(this._props.PanelWidth()) / scaling; const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; @@ -368,7 +368,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp } screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale); marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -444,7 +444,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp {this.content} </CollectionFreeFormView> {this.annotationLayer} - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( <MarqueeAnnotator Document={this.Document} ref={this._marqueeref} @@ -452,7 +452,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp annotationLayerScrollTop={0} scaling={returnOne} annotationLayerScaling={this._props.NativeDimScaling} - docView={this._props.DocumentView!} + docView={this.DocumentView} addDocument={this.addDocument} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 7bc9d3f85..b2aab2422 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -61,33 +61,11 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> { }; render() { - const props: FieldViewProps = { - Document: this._props.doc, - childFilters: returnEmptyFilter, - childFiltersByRanges: returnEmptyFilter, - searchFilterDocs: returnEmptyDoclist, - styleProvider: DefaultStyleProvider, - docViewPath: returnEmptyDoclist, - fieldKey: this._props.keyName, - isSelected: returnFalse, - setHeight: returnFalse, - select: emptyFunction, - bringToFront: emptyFunction, - renderDepth: 1, - isContentActive: returnFalse, - whenChildContentsActiveChanged: emptyFunction, - ScreenToLocalTransform: Transform.Identity, - focus: emptyFunction, - PanelWidth: this._props.PanelWidth, - PanelHeight: this._props.PanelHeight, - addDocTab: returnFalse, - pinToPres: returnZero, - }; // let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")"; let protoCount = 0; - let doc: Doc | undefined = props.Document; + let doc = this._props.doc; while (doc) { - if (Object.keys(doc).includes(props.fieldKey)) { + if (Object.keys(doc).includes(this._props.keyName)) { break; } protoCount++; @@ -106,17 +84,17 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> { style={hover} className="keyValuePair-td-key-delete" onClick={undoBatch(() => { - if (Object.keys(props.Document).indexOf(props.fieldKey) !== -1) { - delete props.Document[props.fieldKey]; - } else delete DocCast(props.Document.proto)?.[props.fieldKey]; + if (Object.keys(this._props.doc).indexOf(this._props.keyName) !== -1) { + delete this._props.doc[this._props.keyName]; + } else delete DocCast(this._props.doc.proto)?.[this._props.keyName]; })}> X </button> <input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} /> - <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === props.fieldKey)?.[1].description ?? ''}> - <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (props.fieldKey.match(/_/g)?.length || 0), color: keyStyle }}> + <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === this._props.keyName)?.[1].description ?? ''}> + <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (this._props.keyName.match(/_/g)?.length || 0), color: keyStyle }}> {'('.repeat(parenCount)} - {props.fieldKey} + {this._props.keyName} {')'.repeat(parenCount)} </div> </Tooltip> @@ -124,7 +102,32 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> { </td> <td className="keyValuePair-td-value" style={{ width: `${100 - this._props.keyWidth}%` }} onContextMenu={this.onContextMenu}> <div className="keyValuePair-td-value-container"> - <EditableView contents={undefined} fieldContents={props} GetValue={() => Field.toKeyValueString(props.Document, props.fieldKey)} SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)} /> + <EditableView + contents={undefined} + fieldContents={{ + Document: this._props.doc, + childFilters: returnEmptyFilter, + childFiltersByRanges: returnEmptyFilter, + searchFilterDocs: returnEmptyDoclist, + styleProvider: DefaultStyleProvider, + fieldKey: this._props.keyName, + isSelected: returnFalse, + setHeight: returnFalse, + select: emptyFunction, + bringToFront: emptyFunction, + renderDepth: 1, + isContentActive: returnFalse, + whenChildContentsActiveChanged: emptyFunction, + ScreenToLocalTransform: Transform.Identity, + focus: emptyFunction, + PanelWidth: this._props.PanelWidth, + PanelHeight: this._props.PanelHeight, + addDocTab: returnFalse, + pinToPres: returnZero, + }} + GetValue={() => Field.toKeyValueString(this._props.doc, this._props.keyName)} + SetValue={(value: string) => KeyValueBox.SetField(this._props.doc, this._props.keyName, value)} + /> </div> </td> </tr> diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index b86ba72a0..864c1955b 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -7,13 +7,13 @@ import { TraceMobx } from '../../../fields/util'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { SelectionManager } from '../../util/SelectionManager'; -import { ViewBoxBaseComponent } from '../DocComponent'; +import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkInfo } from './LinkDocPreview'; const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore -export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { +export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps & ViewBoxBaseProps>() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); } @@ -33,12 +33,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { } @computed get linkSource() { - return this._props.docViewPath()[this._props.docViewPath().length - 2].Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource); + return this.containerViewPath?.().lastElement().Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource); } onPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { - if (doubleTap) LinkFollower.FollowLink(this.Document, this.linkSource, false); + const linkSource = this.linkSource; + linkSource && setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { + if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false); else this._props.select(false); }); }; @@ -86,7 +87,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { className={`linkAnchorBox-cont${small ? '-small' : ''}`} onPointerEnter={e => LinkInfo.SetLinkInfo({ - docProps: this._props, + DocumentView: this.DocumentView, + styleProvider: this._props.styleProvider, linkSrc: this.linkSource, linkDoc: this.Document, showHeader: true, diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 7f1d41547..4221f464d 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -29,12 +29,12 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() { @computed get anchor1() { const anchor1 = DocCast(this.dataDoc.link_anchor_1); const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1; - return DocumentManager.Instance.getDocumentView(anchor_1, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_1, this.containerViewPath?.().lastElement()); } @computed get anchor2() { const anchor2 = DocCast(this.dataDoc.link_anchor_2); const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2; - return DocumentManager.Instance.getDocumentView(anchor_2, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_2, this.containerViewPath?.().lastElement()); } screenBounds = () => { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { @@ -66,7 +66,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() { const a = (this.anchor1 ?? this.anchor2)!; const b = (this.anchor2 ?? this.anchor1)!; - const parxf = this._props.docViewPath()[this._props.docViewPath().length - 2].ComponentView as CollectionFreeFormView; + const parxf = this.containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView; const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform(); const a_invXf = a.screenToViewTransform().inverse(); const b_invXf = b.screenToViewTransform().inverse(); @@ -161,12 +161,11 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() { return ( <div className={`linkBox-container${this._props.isContentActive() ? '-interactive' : ''}`} style={{ background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) }}> <ComparisonBox - {...this._props} + {...this._props} // fieldKey="link_anchor" setHeight={emptyFunction} dontRegisterView={true} renderDepth={this._props.renderDepth + 1} - isContentActive={this._props.isContentActive} addDocument={returnFalse} removeDocument={returnFalse} moveDocument={returnFalse} diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index ea23ecbea..ed4878d9d 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -18,8 +18,9 @@ import { SearchUtil } from '../../util/SearchUtil'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; import { ObservableReactComponent } from '../ObservableReactComponent'; -import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; +import { DocumentView, DocumentViewSharedProps, OpenWhere, StyleProviderFunc } from './DocumentView'; import './LinkDocPreview.scss'; +import { FieldViewProps } from './FieldView'; export class LinkInfo { private static _instance: Opt<LinkInfo>; @@ -43,7 +44,8 @@ export class LinkInfo { interface LinkDocPreviewProps { linkDoc?: Doc; linkSrc?: Doc; - docProps: DocumentViewSharedProps; + DocumentView?: () => DocumentView; + styleProvider?: StyleProviderFunc; location: number[]; hrefs?: string[]; showHeader?: boolean; @@ -152,7 +154,7 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps action(() => { LinkManager.currentLink = this._linkDoc; LinkManager.currentLinkAnchor = this._linkSrc; - this._props.docProps.DocumentView?.().select(false); + this._props.DocumentView?.().select(false); if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) { SettingsManager.Instance.propertiesWidth = 250; } @@ -269,8 +271,8 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps }} Document={this._targetDoc!} moveDocument={returnFalse} - styleProvider={this._props.docProps?.styleProvider} - docViewPath={returnEmptyDoclist} + styleProvider={this._props.styleProvider} + containerViewPath={returnEmptyDoclist} ScreenToLocalTransform={Transform.Identity} isDocumentActive={returnFalse} isContentActive={returnFalse} diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 3575b21e4..56fb157da 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -379,11 +379,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }); const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); docView && DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx index 34e237007..fc5b4dd18 100644 --- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx +++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx @@ -18,10 +18,10 @@ export class MapPushpinBox extends ViewBoxBaseComponent<FieldViewProps>() { } get mapBoxView() { - return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox; + return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBox; } get mapBox() { - return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document; + return this.DocumentView?.().containerViewPath?.().lastElement()?.Document; } render() { diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index ea8496c99..e079f7457 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -228,11 +228,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata }); const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); docView && DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 959d5d88d..71c1b6a4c 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -102,7 +102,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps Doc.GetProto(region).followLinkToggle = true; this.addDocument(region); - const docViewContent = this._props.docViewPath().lastElement().ContentDiv!; + const docViewContent = this.DocumentView?.().ContentDiv!; const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; newDiv.style.width = NumCast(this.layoutDoc._width).toString(); newDiv.style.height = NumCast(this.layoutDoc._height).toString(); @@ -163,7 +163,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps updateIcon = () => { // currently we render pdf icons as text labels - const docViewContent = this._props.docViewPath().lastElement().ContentDiv!; + const docViewContent = this.DocumentView?.().ContentDiv!; const filename = this.layoutDoc[Id] + '-icon' + new Date().getTime(); this._pdfViewer?._mainCont.current && CollectionFreeFormView.UpdateIcon( @@ -304,7 +304,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps setPdfViewer = (pdfViewer: PDFViewer) => { this._pdfViewer = pdfViewer; - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (this._initialScrollTarget && docView) { this.focus(this._initialScrollTarget, { instant: true }); this._initialScrollTarget = undefined; @@ -525,7 +525,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps removeDocument={this.removeDocument} /> ) : ( - <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}> + <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}> <ComponentTag {...this._props} setContentView={emptyFunction} // override setContentView to do nothing diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index fb42286af..1913ab032 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -21,7 +21,7 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; @@ -44,7 +44,7 @@ import './VideoBox.scss'; */ @observer -export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { +export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } @@ -608,7 +608,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // removes from currently playing display @action removeCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (CollectionStackedTimeline.CurrentlyPlaying && docView) { const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView); index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1); @@ -617,7 +617,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // adds doc to currently playing display @action addCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (!CollectionStackedTimeline.CurrentlyPlaying) { CollectionStackedTimeline.CurrentlyPlaying = []; } @@ -749,7 +749,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // starts marquee selection marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -941,7 +941,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { style={{ pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined, borderRadius, - overflow: this._props.docViewPath?.().slice(-1)[0].layout_fitWidth ? 'auto' : undefined, + overflow: this.DocumentView?.().layout_fitWidth ? 'auto' : undefined, }}> <div className="videoBox-viewer" onPointerDown={this.marqueeDown}> <div @@ -978,7 +978,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { </CollectionFreeFormView> </div> {this.annotationLayer} - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( <MarqueeAnnotator ref={this._marqueeref} Document={this.Document} @@ -986,7 +986,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { annotationLayerScrollTop={0} scaling={returnOne} annotationLayerScaling={this._props.NativeDimScaling} - docView={this._props.DocumentView!} + docView={this.DocumentView} containerOffset={this.marqueeOffset} addDocument={this.addDocWithTimecode} finishMarquee={this.finishMarquee} @@ -1004,7 +1004,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } @computed get UIButtons() { - const bounds = this._props.docViewPath().lastElement().getBounds(); + const bounds = this.DocumentView?.().getBounds(); const width = (bounds?.right || 0) - (bounds?.left || 0); const curTime = NumCast(this.layoutDoc._layout_currentTimecode); return ( diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c3be2b390..86709e4d7 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -33,7 +33,7 @@ import { Annotation } from '../pdf/Annotation'; import { GPTPopup } from '../pdf/GPTPopup/GPTPopup'; import { SidebarAnnos } from '../SidebarAnnos'; import { StyleProp } from '../StyleProvider'; -import { DocComponentView, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView'; +import { DocComponentView, DocFocusOptions, DocumentView, OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { LinkInfo } from './LinkDocPreview'; import { PinProps, PresBox } from './trails'; @@ -250,7 +250,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @action createTextAnnotation = (sel: Selection, selRange: Range | undefined) => { if (this._mainCont.current && selRange) { - if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; + if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); @@ -274,7 +274,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps // clear selection this._textAnnotationCreator = undefined; - if (sel.empty) sel.empty(); // Chrome + if (sel.empty) + sel.empty(); // Chrome else if (sel.removeAllRanges) sel.removeAllRanges(); // Firefox return this._savedAnnotations; }; @@ -297,8 +298,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @action getView = (doc: Doc, options: DocFocusOptions) => { - if (Doc.AreProtosEqual(doc, this.Document)) return new Promise<Opt<DocumentView>>(res => res(this._props.DocumentView?.())); - if (this.Document.layout_fieldKey === 'layout_icon') this._props.DocumentView?.().iconify(); + if (Doc.AreProtosEqual(doc, this.Document)) return new Promise<Opt<DocumentView>>(res => res(this.DocumentView?.())); + if (this.Document.layout_fieldKey === 'layout_icon') this.DocumentView?.().iconify(); const webUrl = WebCast(doc.config_data)?.url; if (this._url && webUrl && webUrl.href !== this._url) this.setData(webUrl.href); if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false); @@ -343,7 +344,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps iframeUp = (e: PointerEvent) => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; // need to save AnchorMenu's getAnchor since a subsequent selection on another doc will overwrite this value this._textAnnotationCreator = undefined; - this._props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here. + this.DocumentView?.()?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here. if (this._iframe?.contentWindow && this._iframe.contentDocument && !this._iframe.contentWindow.getSelection()?.isCollapsed) { const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); const scale = (this._props.NativeDimScaling?.() || 1) * mainContBounds.scale; @@ -364,7 +365,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps e.stopPropagation(); const sel = window.getSelection(); this._textAnnotationCreator = undefined; - if (sel?.empty) sel.empty(); // Chrome + if (sel?.empty) + sel.empty(); // Chrome else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox // bcz: NEED TO unrotate e.clientX and e.clientY const word = getWordAtPoint(e.target, e.clientX, e.clientY); @@ -556,7 +558,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps clearStyleSheetRules(WebBox.webStyleSheet); this._scrollTimer = undefined; const newScrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop; - if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) { + if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath))) { this.layoutDoc.thumb = undefined; this.layoutDoc.thumbScrollTop = undefined; this.layoutDoc.thumbNativeWidth = undefined; @@ -723,10 +725,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps onMarqueeDown = (e: React.PointerEvent) => { const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection(); this._textAnnotationCreator = undefined; - if (sel?.empty) sel.empty(); // Chrome + if (sel?.empty) + sel.empty(); // Chrome else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox this.marqueeing = [e.clientX, e.clientY]; - if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -750,7 +753,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this.marqueeing = undefined; this._textAnnotationCreator = undefined; const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection(); - if (sel?.empty) sel.empty(); // Chrome + if (sel?.empty) + sel.empty(); // Chrome else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox this._setPreviewCursor?.(x ?? 0, y ?? 0, false, !this._marqueeref.current?.isEmpty, this.Document); if (x !== undefined && y !== undefined) { @@ -762,7 +766,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps setTimeout(() => { // if menu comes up right away, the down event can still be active causing a menu item to be selected this.specificContextMenu(undefined as any); - this._props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y); + this.DocumentView?.().onContextMenu(undefined, x, y); }); } } @@ -908,7 +912,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }); @action onZoomWheel = (e: React.WheelEvent) => { - if (this._props.isContentActive(true)) { + if (this._props.isContentActive()) { e.stopPropagation(); } }; @@ -1065,7 +1069,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [Utils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc)) return 'none'; } @@ -1099,7 +1103,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps onContextMenu={this.specificContextMenu}> {this.webpage} </div> - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( <div style={{ position: 'absolute', height: '100%', width: '100%', pointerEvents: this.marqueeing ? 'all' : 'none' }}> <MarqueeAnnotator ref={this._marqueeref} @@ -1109,7 +1113,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps annotationLayerScrollTop={0} scaling={this._props.NativeDimScaling} addDocument={this.addDocumentWrapper} - docView={this._props.DocumentView!} + docView={this.DocumentView} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotationsCreator} selectionText={this.selectionText} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 6a2cd359c..cc58c2071 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -6,7 +6,7 @@ import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { NumCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse, Utils } from '../../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnFalse, Utils } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; @@ -207,7 +207,7 @@ export class DashDocViewInternal extends ObservableReactComponent<IDashDocViewIn isDocumentActive={returnFalse} isContentActive={this.isContentActive} styleProvider={this._textBox._props.styleProvider} - docViewPath={this._textBox._props.docViewPath} + containerViewPath={this._textBox.docViewPathFunc ?? returnEmptyDoclist} ScreenToLocalTransform={this.getDocTransform} addDocTab={this._textBox._props.addDocTab} pinToPres={returnFalse} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 555b752f0..3f2ab0ec5 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -148,7 +148,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi } createPivotForField = (e: React.MouseEvent) => { - let container = this._props.tbox._props.DocumentView?.()._props.docViewPath().lastElement(); + let container = this._props.tbox.containerViewPath?.().lastElement(); if (container) { const embedding = Doc.MakeEmbedding(container.Document); embedding._type_collection = CollectionViewType.Time; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ae26f170b..6a6cec094 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -42,7 +42,7 @@ import { CollectionStackingView } from '../../collections/CollectionStackingView import { CollectionTreeView } from '../../collections/CollectionTreeView'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; -import { ViewBoxAnnotatableComponent } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; @@ -71,7 +71,7 @@ import { SummaryView } from './SummaryView'; export interface FormattedTextBoxProps {} @observer -export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps & FormattedTextBoxProps>() { +export class FormattedTextBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & FormattedTextBoxProps>() { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); } @@ -123,7 +123,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps } @computed get noSidebar() { - return this._props.docViewPath().lastElement()?._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar; + return this.DocumentView?.()._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar; } @computed get layout_sidebarWidthPercent() { return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); @@ -310,7 +310,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps return target; }; - DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this._props.docViewPath().lastElement(), () => this.getAnchor(true), targetCreator), e.pageX, e.pageY); + DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.DocumentView?.()!, () => this.getAnchor(true), targetCreator), e.pageX, e.pageY); }); const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to); this._props.rootSelected?.() && AnchorMenu.Instance.jumpTo(coordsB.left, coordsB.bottom); @@ -1410,7 +1410,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps (this._editorView as any).TextView = this; } - const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, FormattedTextBox.SelectOnLoad) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath())); + const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, FormattedTextBox.SelectOnLoad) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath)); if (this._editorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) { const selLoadChar = FormattedTextBox.SelectOnLoadChar; FormattedTextBox.SelectOnLoad = undefined; @@ -1531,7 +1531,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps } if (!state || !editor || !this.ProseRef?.children[0].className.includes('-focused')) return; if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu(); - else if (this._props.isContentActive(true)) { + else if (this._props.isContentActive()) { const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY }); let xpos = pcords?.pos || 0; while (xpos > 0 && !state.doc.resolve(xpos).node()?.isTextblock) { @@ -1764,7 +1764,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps return toNum(height) + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom)); }; const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + toHgt(child), margins); - const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight); + const scrollHeight = this.ProseRef && proseHeight; if (this._props.setHeight && scrollHeight && !this._props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation const setScrollHeight = () => (this.dataDoc[this.fieldKey + '_scrollHeight'] = scrollHeight); @@ -1852,7 +1852,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps setHeight={this.setSidebarHeight} /> ) : ( - <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}> + <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}> <ComponentTag {...this._props} ref={this._sidebarTagRef as any} diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index be8736525..ce17af6ca 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -134,7 +134,8 @@ export class FormattedTextBoxComment { //nbef && naft && LinkInfo.SetLinkInfo({ - docProps: textBox.props, + DocumentView: textBox.DocumentView, + styleProvider: textBox._props.styleProvider, linkSrc: textBox.Document, linkDoc: linkDoc ? (DocServer.GetCachedRefField(linkDoc) as Doc) : undefined, location: (pos => [pos.left, pos.top + 25])(view.coordsAtPos(state.selection.from - Math.max(0, nbef - 1))), diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 6fa64a765..645ac08e1 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -294,13 +294,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { listItemDoc.presentation_effect = this.activeItem.presBulletEffect; listItemDoc.presentation_transition = 500; targetView?.setAnimEffect(listItemDoc, 500); - if (targetView?.docView && this.activeItem.presBulletExpand) { - targetView.docView._animateScalingTo = 1.2; - targetView.docView._animateScaleTime = 400; - Doc.AddUnHighlightWatcher(() => { - targetView.docView!._animateScaleTime = undefined; - targetView!.docView!._animateScalingTo = 0; - }); + if (targetView && this.activeItem.presBulletExpand) { + targetView.setAnimateScaling(1.2, 400); + Doc.AddUnHighlightWatcher(() => targetView?.setAnimateScaling(0, undefined)); } listItemDoc.opacity = undefined; this.activeItem.presentation_indexed = presIndexed + 1; @@ -2622,7 +2618,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { ScreenToLocalTransform={this.getTransform} AddToMap={this.AddToMap} RemFromMap={this.RemFromMap} - hierarchyIndex={emptyPath} + hierarchyIndex={emptyPath as any as number[]} /> ) : null} </div> diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 4945d66c8..8cf01b9de 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -19,7 +19,7 @@ import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocumentView } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { StyleProp } from '../../StyleProvider'; import { PresBox } from './PresBox'; @@ -50,7 +50,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { // the presentation view that renders this slide @computed get presBoxView() { - return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as PresBox; + return this.containerViewPath?.().lastElement()?.ComponentView as PresBox; } // the presentation view document that renders this slide @@ -97,7 +97,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { presExpandDocumentClick = () => (this.slideDoc.presentation_expandInlineButton = !this.slideDoc.presentation_expandInlineButton); embedHeight = () => this.collapsedHeight + this.expandViewHeight; embedWidth = () => this._props.PanelWidth() / 2; - styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => { return property === StyleProp.Opacity ? 1 : this._props.styleProvider?.(doc, props, property); }; /** @@ -116,7 +116,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { hideLinkButton={true} ScreenToLocalTransform={Transform.Identity} renderDepth={this._props.renderDepth + 1} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} childFilters={this._props.childFilters} childFiltersByRanges={this._props.childFiltersByRanges} searchFilterDocs={this._props.searchFilterDocs} @@ -196,7 +196,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { const dragArray = this.presBoxView?._dragArray ?? []; const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.slideDoc); - dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this._props.DocumentView?.()?._props.treeViewDoc; + dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this.DocumentView?.()?._props.treeViewDoc; dragData.moveDocument = this._props.moveDocument; const dragItem: HTMLElement[] = []; const classesToRestore = new Map<HTMLElement, string>(); |
