From 729114c0867e3cc8d8e0668bae451976b387cb34 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 28 Apr 2024 13:08:09 -0400 Subject: simplified explore mode implementation --- src/client/views/DocComponent.tsx | 1 + src/client/views/LightboxView.tsx | 1 - .../views/collections/CollectionNoteTakingView.tsx | 3 +- .../views/collections/CollectionStackingView.tsx | 2 - src/client/views/collections/TabDocView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 44 +++++++--------------- .../collectionSchema/SchemaTableCell.tsx | 2 +- .../views/newlightbox/Header/LightboxHeader.tsx | 12 +----- src/client/views/newlightbox/NewLightboxView.tsx | 23 ++++++----- src/client/views/nodes/DocumentView.tsx | 35 ++++++++++------- src/client/views/nodes/FieldView.tsx | 1 - src/client/views/nodes/ImageBox.tsx | 18 ++++----- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 4 ++ .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/client/views/topbar/TopBar.tsx | 2 +- 16 files changed, 68 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index bbd902a96..fd0b4e83f 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -68,6 +68,7 @@ export interface ViewBoxInterface { removeDocument?: (doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean, dontAddToRemoved?: boolean) => boolean; // add a document (used only by collections) select?: (ctrlKey: boolean, shiftKey: boolean) => void; focus?: (textAnchor: Doc, options: FocusViewOptions) => Opt; + browseTo?: (clientX: number, clientY: number, browseTransitionTime: number) => boolean; // when in explore mode, this allows a component view to display itself in an easy to read way (ie, a document in a freeformview will zoom itself to mostly full screen) viewTransition?: () => Opt; // duration of a view transition animation isAnyChildContentActive?: () => boolean; // is any child content of the document active onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 0dd836f70..7bf6bb9e5 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -293,7 +293,6 @@ export class LightboxView extends ObservableReactComponent { whenChildContentsActiveChanged={emptyFunction} addDocTab={this.AddDocTab} pinToPres={TabDocView.PinDoc} - onBrowseClickScript={DocumentView.exploreMode} focus={emptyFunction} /> diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 2ba6f5bf4..9212a6609 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -59,7 +59,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } @computed get chromeHidden() { - return !!(BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClickScript?.()); + return BoolCast(this.layoutDoc.chromeHidden) || SnappingManager.ExploreMode; } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns @computed get colHeaderData() { @@ -283,7 +283,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { layout_showTitle={this._props.childlayout_showTitle} dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType} onClickScript={this.onChildClickHandler} - onBrowseClickScript={this._props.onBrowseClickScript} onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={noteTakingDocTransform} focus={this.focusDocument} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b79d660c6..c47fe915a 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -338,7 +338,6 @@ export class CollectionStackingView extends CollectionSubView { hideTitle={this._props.keyValue} Document={this._document} TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined} - onBrowseClickScript={DocumentView.exploreMode} waitForDoubleClickToClick={this.waitForDoubleClick} isContentActive={this.isContentActive} isDocumentActive={returnFalse} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index fa4dbf9a2..d3998aee8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -241,7 +241,6 @@ export class CollectionFreeFormView extends CollectionSubView this._keyframeEditing; - onBrowseClickHandler = () => this._props.onBrowseClickScript?.() || ScriptCast(this.layoutDoc.onBrowseClick); onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); elementFunc = () => this._layoutElements; @@ -726,11 +725,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this._lightboxDoc) this._lightboxDoc = undefined; if (ClientUtils.isClick(e.pageX, e.pageY, this._downX, this._downY, this._downTime)) { - if (this.onBrowseClickHandler()) { - this.onBrowseClickHandler().script.run({ documentView: this.DocumentView?.(), clientX: e.clientX, clientY: e.clientY }); - e.stopPropagation(); - e.preventDefault(); - } else if (this.isContentActive() && e.shiftKey) { + if (this.isContentActive() && e.shiftKey) { // reset zoom of freeform view to 1-to-1 on a shift + double click this.zoomSmoothlyAboutPt(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY), 1); e.stopPropagation(); @@ -1256,7 +1251,6 @@ export class CollectionFreeFormView extends CollectionSubView ); } + browseTo = (clientX: number, clientY: number, browseTransitionTime: number): boolean => { + if (!this.Document.isGroup) { + const dfltScale = this.isAnnotationOverlay ? 1 : 0.5; + if (this.layoutDoc[this.scaleFieldKey] !== dfltScale) { + this.zoomSmoothlyAboutPt(this.screenToFreeformContentsXf.transformPoint(clientX, clientY), dfltScale, browseTransitionTime); + return true; + } + return !!this.DocumentView?.() + .containerViewPath?.() + ?.some(cont => cont.ComponentView?.browseTo?.(clientX, clientY, browseTransitionTime)); + } + return false; + }; } @observer @@ -1995,28 +2001,6 @@ class CollectionFreeFormOverlayView extends React.Component<{ elements: () => Vi return this.props.elements().filter(ele => ele.bounds?.z).map(ele => ele.ele); // prettier-ignore } } - -export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY: number) { - const browseTransitionTime = 500; - SelectionManager.DeselectAll(); - dv && - DocumentManager.Instance.showDocument(dv.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { - if (!focused) { - const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; - const containers = dv.containerViewPath?.() ?? []; - let parFfview = dv.CollectionFreeFormView; - containers.forEach(cont => { - parFfview = parFfview ?? cont.CollectionFreeFormView; - }); - - while (parFfview?.Document.isGroup) parFfview = parFfview.DocumentView?.().CollectionFreeFormView; - const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview - ffview?.zoomSmoothlyAboutPt(ffview.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); - Doc.linkFollowHighlight(dv?.Document, false); - } - }); -} -ScriptingGlobals.add(CollectionBrowseClick); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { !readOnly && (SelectionManager.Views[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(); diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index b89ca3614..dfef3aa48 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -179,7 +179,7 @@ export class SchemaTableCell extends ObservableReactComponent; case ColumnType.Boolean: return ; case ColumnType.RTF: return ; - case ColumnType.Enumeration: return val.toString())} />; + case ColumnType.Enumeration: return Field.toString(val))} />; case ColumnType.Date: return ; default: return this.defaultCellContent; } diff --git a/src/client/views/newlightbox/Header/LightboxHeader.tsx b/src/client/views/newlightbox/Header/LightboxHeader.tsx index 76efe0185..f89d3173a 100644 --- a/src/client/views/newlightbox/Header/LightboxHeader.tsx +++ b/src/client/views/newlightbox/Header/LightboxHeader.tsx @@ -53,17 +53,7 @@ export const NewLightboxHeader = (props: INewLightboxHeader) => { setSaved(!saved)} color={Colors.DARK_GRAY} icon={saved ? : } />
-
); diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index dcbc9fc50..6de4efc0d 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -6,7 +6,7 @@ import { returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Clie import { emptyFunction } from '../../../Utils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { Cast, NumCast, StrCast, toList } from '../../../fields/Types'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; @@ -204,15 +204,19 @@ export class NewLightboxView extends React.Component { this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`); } } - public static AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc | string) => { + public static AddDocTab = (docsIn: Doc | Doc[], location: OpenWhere, layoutTemplate?: Doc | string) => { SelectionManager.DeselectAll(); - return NewLightboxView.SetNewLightboxDoc( - doc, - undefined, - [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '_annotations']).filter(anno => anno.annotationOn !== doc), ...(NewLightboxView._future ?? [])].sort( - (a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow) - ), - layoutTemplate + const doc = toList(docsIn).lastElement(); + return ( + doc && + NewLightboxView.SetNewLightboxDoc( + doc, + undefined, + [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '_annotations']).filter(anno => anno.annotationOn !== doc), ...(NewLightboxView._future ?? [])].sort( + (a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow) + ), + layoutTemplate + ) ); }; docFilters = () => NewLightboxView._docFilters || []; @@ -312,7 +316,6 @@ export class NewLightboxView extends React.Component { whenChildContentsActiveChanged={emptyFunction} addDocTab={this.addDocTab} pinToPres={TabDocView.PinDoc} - onBrowseClickScript={DocumentView.exploreMode} focus={emptyFunction} /> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5962cd09f..555b4ba92 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -165,7 +165,7 @@ export class DocumentViewInternal extends DocComponent this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined }; + onBrowseClick = (e: React.MouseEvent) => { + const browseTransitionTime = 500; + SelectionManager.DeselectAll(); + DocumentManager.Instance.showDocument(this.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { + if (!focused && this._docView) { + this._docView + .docViewPath() + .reverse() + .find(cont => cont.ComponentView?.browseTo?.(e.clientX, e.clientY, browseTransitionTime)); + Doc.linkFollowHighlight(this.Document, false); + } + }); + e.stopPropagation(); + }; onClick = action((e: React.MouseEvent | React.PointerEvent) => { if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; const documentView = this._docView; @@ -393,10 +407,8 @@ export class DocumentViewInternal extends DocComponent 0))) { // click events stop here if the document is active and no modes are overriding it // if this is part of a template, let the event go up to the template root unless right/ctrl clicking - if ( - // prettier-ignore - (this._props.isDocumentActive?.() || this._props.isContentActive?.()) && - !this._props.onBrowseClickScript?.() && + if ((this._props.isDocumentActive?.() || this._props.isContentActive?.()) && + !SnappingManager.ExploreMode && !this.Document.ignoreClick && e.button === 0 && !Doc.IsInMyOverlay(this.layoutDoc) @@ -408,7 +420,7 @@ export class DocumentViewInternal extends DocComponent (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} onPointerOver={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} @@ -1055,7 +1067,7 @@ export class DocumentViewInternal extends DocComponent { recorder.stop(); - DictationManager.Controls.stop(false); + DictationManager.Controls.stop(/* false */); dataDoc.audioAnnoState = AudioAnnoState.stopped; gumStream.getAudioTracks()[0].stop(); }; @@ -1086,9 +1098,6 @@ export class DocumentView extends DocComponent. used by LinkBox's Xanchor to find the arrowhead locations. public DocUniqueId = DocumentView.UniquifyId(LightboxView.Contains(this), this.Document[Id]); - @computed public static get exploreMode() { - return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); - } constructor(props: DocumentViewProps & { CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView }) { super(props); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 3f453eb93..c2f946a88 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -74,7 +74,6 @@ export interface FieldViewSharedProps { onDoubleClickScript?: () => ScriptField; onPointerDownScript?: () => ScriptField; onPointerUpScript?: () => ScriptField; - onBrowseClickScript?: () => ScriptField | undefined; // eslint-disable-next-line no-use-before-define onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; layout_fitWidth?: (doc: Doc) => boolean | undefined; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 90b4a6740..617c45715 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -70,7 +70,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl private _getAnchor: (savedAnnotations: Opt>, addAsAnnotation: boolean) => Opt = () => undefined; private _overlayIconRef = React.createRef(); private _marqueeref = React.createRef(); + private _mainCont: React.RefObject = React.createRef(); + private _annotationLayer: React.RefObject = React.createRef(); + @observable _savedAnnotations = new ObservableMap(); @observable _curSuffix = ''; + @observable _error = ''; + @observable _isHovering = false; // flag to switch between primary and alternate images on hover + _ffref = React.createRef(); constructor(props: FieldViewProps) { super(props); @@ -274,7 +280,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl } }; - choosePath(url: URL) { + choosePath = (url: URL) => { if (!url?.href) return ''; const lower = url.href.toLowerCase(); if (url.protocol === 'data') return url.href; @@ -283,7 +289,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl const ext = extname(url.href); return url.href.replace(ext, (this._error ? '_o' : this._curSuffix) + ext); - } + }; getScrollHeight = () => (this._props.layout_fitWidth?.(this.Document) !== false && NumCast(this.layoutDoc._freeform_scale, 1) === NumCast(this.dataDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined); @computed get nativeSize() { @@ -346,9 +352,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl return paths.length ? paths : [defaultUrl.href]; } - @observable _error = ''; - - @observable _isHovering = false; // flag to switch between primary and alternate images on hover @computed get content() { TraceMobx(); @@ -407,13 +410,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl ); } - private _mainCont: React.RefObject = React.createRef(); - private _annotationLayer: React.RefObject = React.createRef(); - @observable _savedAnnotations = new ObservableMap(); @computed get annotationLayer() { TraceMobx(); return
; } + browseTo = (clientX: number, clientY: number, browseTransitionTime: number) => !!this._ffref.current?.browseTo?.(clientX, clientY, browseTransitionTime); screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale); marqueeDown = (e: React.PointerEvent) => { if (!this.dataDoc[this.fieldKey]) { @@ -447,7 +448,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl }; focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); - _ffref = React.createRef(); savedAnnotations = () => this._savedAnnotations; render() { TraceMobx(); diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 67872efc3..c19528af6 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -802,7 +802,6 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent NativeHeight={returnOne} onKey={undefined} onDoubleClickScript={undefined} - onBrowseClickScript={undefined} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 4b80f2485..fd7997248 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -64,6 +64,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() impl private _annotationLayer: React.RefObject = React.createRef(); private _playRegionTimer: any = null; // timeout for playback private _controlsFadeTimer: any = null; // timeout for controls fade + private _ffref = React.createRef(); constructor(props: FieldViewProps) { super(props); @@ -978,6 +979,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent() impl this._props.bringToFront?.(cropping); return cropping; }; + browseTo = (clientX: number, clientY: number, browseTransitionTime: number) => !!this._ffref.current?.browseTo(clientX, clientY, browseTransitionTime); + focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); savedAnnotations = () => this._savedAnnotations; render() { const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding); @@ -1005,6 +1008,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() impl