diff options
| author | Zachary Zhang <zacharyzhang7@gmail.com> | 2024-08-31 00:46:29 -0400 |
|---|---|---|
| committer | Zachary Zhang <zacharyzhang7@gmail.com> | 2024-08-31 00:46:29 -0400 |
| commit | 196294f331496262bef256da8b8e9dbc80288bea (patch) | |
| tree | 85ff27b7a8070585f9a5ef71dff63566e03232ba /src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | |
| parent | 0cf61501ec9be34294935f01973c1bd9cad6d267 (diff) | |
| parent | c36607691e0b7f5c04f3209a64958f5e51ddd785 (diff) | |
Merge branch 'master' into zach-starter
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 160 |
1 files changed, 77 insertions, 83 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d611db1f8..c4cf8dee7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,16 +1,14 @@ /* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; +import { Property } from 'csstype'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { ClientUtils, DashColor, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, UpdateIcon } from '../../../../ClientUtils'; import { DateField } from '../../../../fields/DateField'; -import { Doc, DocListCast, Field, FieldType, Opt } from '../../../../fields/Doc'; -import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView'; +import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc'; import { DocData, Height, Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkData, InkField, InkTool, Segment } from '../../../../fields/InkField'; @@ -33,20 +31,20 @@ import { CompileScript } from '../../../util/Scripting'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { freeformScrollMode, SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; +import { undoable, UndoManager } from '../../../util/UndoManager'; import { Timeline } from '../../animationtimeline/Timeline'; import { ContextMenu } from '../../ContextMenu'; import { InkingStroke } from '../../InkingStroke'; import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; -import { ActiveFillColor, DocumentView } from '../../nodes/DocumentView'; +import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, DocumentView, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FocusViewOptions } from '../../nodes/FocusViewOptions'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { OpenWhere, OpenWhereMod } from '../../nodes/OpenWhere'; import { PinDocView, PinProps } from '../../PinFuncs'; import { StyleProp } from '../../StyleProp'; -import { CollectionSubView } from '../CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeViewType'; import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid'; import { CollectionFreeFormClusters } from './CollectionFreeFormClusters'; @@ -71,7 +69,7 @@ export interface collectionFreeformViewProps { childPointerEvents?: () => string | undefined; viewField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) - engineProps?: any; + engineProps?: unknown; getScrollHeight?: () => number | undefined; } @@ -83,13 +81,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection public unprocessedDocs: Doc[] = []; public static collectionsWithUnprocessedInk = new Set<CollectionFreeFormView>(); public static from(dv?: DocumentView): CollectionFreeFormView | undefined { - const parent = CollectionFreeFormDocumentView.from(dv)?._props.parent; + const parent = CollectionFreeFormDocumentView.from(dv)?._props.reactParent; return parent instanceof CollectionFreeFormView ? parent : undefined; } private _clusters = new CollectionFreeFormClusters(this); - private _oldWheel: any; - private _panZoomTransitionTimer: any; + private _oldWheel: HTMLDivElement | null = null; + private _panZoomTransitionTimer: NodeJS.Timeout | undefined = undefined; + private _brushtimer: NodeJS.Timeout | undefined = undefined; + private _brushtimer1: NodeJS.Timeout | undefined = undefined; private _lastX: number = 0; private _lastY: number = 0; private _downX: number = 0; @@ -98,8 +98,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection private _disposers: { [name: string]: IReactionDisposer } = {}; private _renderCutoffData = observable.map<string, boolean>(); private _batch: UndoManager.Batch | undefined = undefined; - private _brushtimer: any; - private _brushtimer1: any; private _keyTimer: NodeJS.Timeout | undefined; // timer for turning off transition flag when key frame change has completed. Need to clear this if you do a second navigation before first finishes, or else first timer can go off during second naviation. private _presEaseFunc: string = 'ease'; @@ -123,14 +121,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observable _marqueeViewRef = React.createRef<MarqueeView>(); @observable _brushedView: { width: number; height: number; panX: number; panY: number } | undefined = undefined; // highlighted region of freeform canvas used by presentations to indicate a region @observable GroupChildDrag: boolean = false; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. - @observable _childPointerEvents: 'none' | 'all' | 'visiblepainted' | undefined = undefined; + @observable _childPointerEvents: Property.PointerEvents | undefined = undefined; @observable _lightboxDoc: Opt<Doc> = undefined; @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, ''); @observable _keyframeEditing = false; @observable _eraserX: number = 0; @observable _eraserY: number = 0; @observable _showEraserCircle: boolean = false; // to determine whether the radius eraser should show - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -140,12 +138,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @computed get childPointerEvents() { return SnappingManager.IsResizing ? 'none' - : this._props.childPointerEvents?.() ?? + : (this._props.childPointerEvents?.() ?? (this._props.viewDefDivClick || // (this.layoutEngine === computePassLayout.name && !this._props.isSelected()) || this.isContentActive() === false ? 'none' - : this._props.pointerEvents?.()); + : this._props.pointerEvents?.())); } @computed get contentViews() { const viewsMask = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask !== -1 && ele.inkMask !== undefined).map(ele => ele.ele); @@ -185,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection .transform(this.panZoomXf); } @computed get backgroundColor() { - return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor); + return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string; } @computed get fitWidth() { return this._props.fitWidth?.(this.Document) ?? this.layoutDoc.layout_fitWidth; @@ -357,7 +355,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection * @param options * @returns */ - focus = (anchor: Doc, options: FocusViewOptions): any => { + focus = (anchor: Doc, options: FocusViewOptions) => { if (anchor.isGroup && !options.docTransform && options.contextPath?.length) { // don't focus on group if there's a context path because we're about to focus on a group item // which will override any group focus. (If we allowed the group to focus, it would mark didMove even if there were no net movement) @@ -374,14 +372,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const xfToCollection = options?.docTransform ?? Transform.Identity(); const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; const cantTransform = this.fitContentsToBox || ((this.Document.isGroup || this.layoutDoc._lockedTransform) && !DocumentView.LightboxDoc()); - const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? options?.zoomScale ?? 0.75 : undefined); + const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? (options?.zoomScale ?? 0.75) : undefined); // focus on the document in the collection const didMove = !cantTransform && !anchor.z && (panX !== savedState.panX || panY !== savedState.panY || scale !== savedState.scale); if (didMove) options.didMove = true; // glr: freeform transform speed can be set by adjusting presentation_transition field - needs a way of knowing when presentation is not active... if (didMove) { - const focusTime = options?.instant ? 0 : options.zoomTime ?? 500; + const focusTime = options?.instant ? 0 : (options.zoomTime ?? 500); (options.zoomScale ?? options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale); this.setPan(panX, panY, focusTime); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow return focusTime; @@ -443,8 +441,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return true; } - @undoBatch - internalAnchorAnnoDrop(e: Event, de: DragManager.DropEvent, annoDragData: DragManager.AnchorAnnoDragData) { + internalAnchorAnnoDrop = undoable((e: Event, de: DragManager.DropEvent, annoDragData: DragManager.AnchorAnnoDragData) => { const dropCreator = annoDragData.dropDocCreator; const [xp, yp] = this.screenToFreeformContentsXf.transformPoint(de.x, de.y); annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => { @@ -457,10 +454,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return dropDoc || this.Document; }; return true; - } + }, 'anchor drop'); - @undoBatch - internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData) { + internalLinkDrop = undoable((e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData) => { if (this.DocumentView?.() && linkDragData.linkDragView.containerViewPath?.().includes(this.DocumentView())) { const [x, y] = this.screenToFreeformContentsXf.transformPoint(de.x, de.y); // do nothing if link is dropped into any freeform view parent of dragged document @@ -476,9 +472,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return added; } return false; - } + }, 'link drop'); - onInternalDrop = (e: Event, de: DragManager.DropEvent) => { + onInternalDrop = (e: Event, de: DragManager.DropEvent): boolean => { if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de, de.complete.annoDragData); if (de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData); if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData); @@ -524,8 +520,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } }; - @undoBatch - onGesture = (e: Event, ge: GestureUtils.GestureEvent) => { + onGesture = undoable((e: Event, ge: GestureUtils.GestureEvent) => { switch (ge.gesture) { case Gestures.Text: if (ge.text) { @@ -568,7 +563,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection e.stopPropagation(); } } - }; + }, 'gesture'); @action onEraserUp = (): void => { this._deleteList.lastElement()?._props.removeDocument?.(this._deleteList.map(ink => ink.Document)); @@ -699,8 +694,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return false; }; - forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData, text?: any) => { - this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, InkField.getBounds(points), text)); + forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData) => { + this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, InkField.getBounds(points))); }; onPointerMove = (e: PointerEvent) => { @@ -1178,6 +1173,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection // for some reason bezier.js doesn't handle the case of intersecting a linear curve, so we wrap the intersection // call in a test for linearity bintersects = (curve: Bezier, otherCurve: Bezier) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((curve as any)._linear) { // bezier.js doesn't intersect properly if the curve is actually a line -- so get intersect other curve against this line, then figure out the t coordinates of the intersection on this line const intersections = otherCurve.lineIntersects({ p1: curve.points[0], p2: curve.points[3] }); @@ -1187,6 +1183,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return intT ? [intT] : []; } } + // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((otherCurve as any)._linear) { return curve.lineIntersects({ p1: otherCurve.points[0], p2: otherCurve.points[3] }); } @@ -1478,17 +1475,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return ret; }; childPointerEventsFunc = () => this._childPointerEvents; - childContentsActive = () => (this._props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)(); + childContentsActive = () => ((this._props.childContentsActive ?? this.isContentActive() === false) ? returnFalse : emptyFunction)(); getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; return ( <CollectionFreeFormDocumentView - // eslint-disable-next-line react/jsx-props-no-spreading - {...OmitKeys(entry, ['replica', 'pair']).omit} + // eslint-disable-next-line react/jsx-props-no-spreading, @typescript-eslint/no-explicit-any + {...(OmitKeys(entry, ['replica', 'pair']).omit as any)} key={childLayout[Id] + (entry.replica || '')} Document={childLayout} - parent={this} + reactParent={this} containerViewPath={this.DocumentView?.().docViewPath} styleProvider={this._clusters.styleProvider} TemplateDataDocument={childData} @@ -1603,7 +1600,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; } - onViewDefDivClick = (e: React.MouseEvent, payload: any) => { + onViewDefDivClick = (e: React.MouseEvent, payload: unknown) => { (this._props.viewDefDivClick || ScriptCast(this.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload }); e.stopPropagation(); }; @@ -1637,7 +1634,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection ele: ( <div className="collectionFreeform-customDiv" - title={viewDef.payload?.join(' ')} + title={StrListCast(viewDef.payload as string).join(' ')} key={'div' + x + y + z + viewDef.payload} onClick={e => this.onViewDefDivClick(e, viewDef)} style={{ width, height, backgroundColor: color, transform }} @@ -1654,11 +1651,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection * since rendering a large collection of documents can be slow, at startup, docs are rendered in batches. * each doc's render() method will call the cutoff provider which will let the doc know if it should render itself yet, or wait */ - renderCutoffProvider = computedFn((doc: Doc) => (this.Document.isTemplateDoc ? false : !this._renderCutoffData.get(doc[Id] + ''))); + renderCutoffProvider = computedFn((doc: Doc) => (this.Document.isTemplateDoc || this.Document.isTemplateForField ? false : !this._renderCutoffData.get(doc[Id] + ''))); doEngineLayout( poolData: Map<string, PoolData>, - engine: (poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[] + engine: (poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: unknown) => ViewDefResult[] ) { return engine(poolData, this.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); } @@ -1688,7 +1685,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection .forEach(entry => elements.push({ ele: this.getChildDocView(entry[1]), - bounds: (entry[1].opacity === 0 ? { ...entry[1], width: 0, height: 0 } : { ...entry[1] }) as any, + bounds: entry[1].opacity === 0 ? { payload: undefined, type: '', ...entry[1], width: 0, height: 0 } : { payload: undefined, type: '', ...entry[1] }, inkMask: BoolCast(entry[1].pair.layout.stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1, }) ); @@ -1771,7 +1768,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._disposers.pointerevents = reaction( () => this.childPointerEvents, pointerevents => { - this._childPointerEvents = pointerevents as any; + this._childPointerEvents = pointerevents as Property.PointerEvents | undefined; }, { fireImmediately: true } ); @@ -1810,24 +1807,27 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection Object.values(this._disposers).forEach(disposer => disposer?.()); } - updateIcon = () => - UpdateIcon( - this.layoutDoc[Id] + '-icon' + new Date().getTime(), - this.DocumentView?.().ContentDiv!, - NumCast(this.layoutDoc._width), - NumCast(this.layoutDoc._height), - this._props.PanelWidth(), - this._props.PanelHeight(), - 0, - 1, - false, - '', - (iconFile, nativeWidth, nativeHeight) => { - this.dataDoc.icon = new ImageField(iconFile); - this.dataDoc.icon_nativeWidth = nativeWidth; - this.dataDoc.icon_nativeHeight = nativeHeight; - } - ); + updateIcon = () => { + const contentDiv = this.DocumentView?.().ContentDiv; + contentDiv && + UpdateIcon( + this.layoutDoc[Id] + '-icon' + new Date().getTime(), + contentDiv, + NumCast(this.layoutDoc._width), + NumCast(this.layoutDoc._height), + this._props.PanelWidth(), + this._props.PanelHeight(), + 0, + 1, + false, + '', + (iconFile, nativeWidth, nativeHeight) => { + this.dataDoc.icon = new ImageField(iconFile); + this.dataDoc.icon_nativeWidth = nativeWidth; + this.dataDoc.icon_nativeHeight = nativeHeight; + } + ); + }; @action onCursorMove = (e: React.PointerEvent) => { @@ -1846,8 +1846,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._showEraserCircle = true; }; - @undoBatch - promoteCollection = () => { + promoteCollection = undoable(() => { const childDocs = this.childDocs.slice(); childDocs.forEach(docIn => { const doc = docIn; @@ -1856,10 +1855,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection doc.y = scr?.[1]; }); this._props.addDocTab(childDocs, OpenWhere.inParentFromScreen); - }; + }, 'promote collection'); - @undoBatch - layoutDocsInGrid = () => { + layoutDocsInGrid = undoable(() => { const docs = this.childLayoutPairs.map(pair => pair.layout); const width = Math.max(...docs.map(doc => NumCast(doc._width))) + 20; const height = Math.max(...docs.map(doc => NumCast(doc._height))) + 20; @@ -1869,40 +1867,37 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection doc.x = NumCast(this.Document[this.panXFieldKey]) + (i % dim) * width - (width * dim) / 2; doc.y = NumCast(this.Document[this.panYFieldKey]) + Math.floor(i / dim) * height - (height * dim) / 2; }); - }; + }, 'layout docs in grid'); - @undoBatch - toggleNativeDimensions = () => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight); + toggleNativeDimensions = undoable(() => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight), 'toggle native dimensions'); /// /// resetView restores a freeform collection to unit scale and centered at (0,0) UNLESS /// the view is a group, in which case this does nothing (since Groups calculate their own scale and center) /// - @undoBatch - resetView = () => { + resetView = undoable(() => { this.layoutDoc[this.panXFieldKey] = NumCast(this.dataDoc[this.panXFieldKey + '_reset']); this.layoutDoc[this.panYFieldKey] = NumCast(this.dataDoc[this.panYFieldKey + '_reset']); this.layoutDoc[this.scaleFieldKey] = NumCast(this.dataDoc[this.scaleFieldKey + '_reset'], 1); - }; + }, 'reset view'); /// /// resetView restores a freeform collection to unit scale and centered at (0,0) UNLESS /// the view is a group, in which case this does nothing (since Groups calculate their own scale and center) /// - @undoBatch - toggleResetView = () => { + toggleResetView = undoable(() => { this.dataDoc[this.autoResetFieldKey] = !this.dataDoc[this.autoResetFieldKey]; if (this.dataDoc[this.autoResetFieldKey]) { this.dataDoc[this.panXFieldKey + '_reset'] = this.layoutDoc[this.panXFieldKey]; this.dataDoc[this.panYFieldKey + '_reset'] = this.layoutDoc[this.panYFieldKey]; this.dataDoc[this.scaleFieldKey + '_reset'] = this.layoutDoc[this.scaleFieldKey]; } - }; + }, 'toggle reset view'); onContextMenu = () => { if (this._props.isAnnotationOverlay || !ContextMenu.Instance) return; const appearance = ContextMenu.Instance.findByDescription('Appearance...'); - const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : []; + const appearanceItems = appearance?.subitems ?? []; !this.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' }); !this.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' }); if (this._props.setContentViewBox === emptyFunction) { @@ -1929,7 +1924,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection !appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); const options = ContextMenu.Instance.findByDescription('Options...'); - const optionItems = options && 'subitems' in options ? options.subitems : []; + const optionItems = options?.subitems ?? []; !this._props.isAnnotationOverlay && !Doc.noviceMode && optionItems.push({ @@ -1953,12 +1948,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } !options && ContextMenu.Instance.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' }); const mores = ContextMenu.Instance.findByDescription('More...'); - const moreItems = mores && 'subitems' in mores ? mores.subitems : []; + const moreItems = mores?.subitems ?? []; !mores && ContextMenu.Instance.addItem({ description: 'More...', subitems: moreItems, icon: 'eye' }); }; - @undoBatch - transcribeStrokes = () => { + transcribeStrokes = undoable(() => { if (this.Document.isGroup && this.Document.transcription) { const text = StrCast(this.Document.transcription); const lines = text.split('\n'); @@ -1966,7 +1960,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height })); } - }; + }, 'transcribe strokes'); @action dragEnding = () => { @@ -2008,7 +2002,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection incrementalRender = action(() => { if (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.())) { const layoutUnrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); - const loadIncrement = this.Document.isTemplateDoc ? Number.MAX_VALUE : 5; + const loadIncrement = this.Document.isTemplateDoc || this.Document.isTemplateForField ? Number.MAX_VALUE : 5; for (let i = 0; i < Math.min(layoutUnrendered.length, loadIncrement); i++) { this._renderCutoffData.set(layoutUnrendered[i][Id] + '', true); } @@ -2132,7 +2126,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection onDragOver={e => e.preventDefault()} onContextMenu={this.onContextMenu} style={{ - pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : (this._props.pointerEvents?.() as any), + pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : this._props.pointerEvents?.(), textAlign: this.isAnnotationOverlay ? 'initial' : undefined, transform: `scale(${this.nativeDimScaling})`, width: `${100 / this.nativeDimScaling}%`, |
