From 46cf6c823ca8ab628cd8c5bd7fdfe8945344a014 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 16 May 2023 14:50:29 -0400
Subject: fixed bugs with goldenlayout dragging and undoing.  fixed searching
 for filter values in sidebars.  Stopped creating empty list for collections
 when datafield() is accessed because it messes up undo of a collection. fixed
 tab title editing.  from marquee.  Added UndoStack UI and additional naming
 support in code.

---
 src/client/views/nodes/AudioBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 8e83cf121..410e0bbdc 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -447,7 +447,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     timelineScreenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -AudioBox.topControlsHeight);
 
-    setPlayheadTime = (time: number) => (this._ele!.currentTime = this.layoutDoc._layout_currentTimecode = time);
+    setPlayheadTime = (time: number) => (this._ele!.currentTime /*= this.layoutDoc._layout_currentTimecode*/ = time);
 
     playing = () => this.mediaState === media_state.Playing;
 
-- 
cgit v1.2.3-70-g09d2


From da5184d2113935df25633a6015e177a51e88df2f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 17 May 2023 16:18:20 -0400
Subject: fixed scrolling/panning on fitWidth images.  fixed drag/zoom
 conflicts for overlayDocs that are pannable.

---
 src/client/documents/Documents.ts                  |  6 +-
 src/client/util/DocumentManager.ts                 |  2 +-
 src/client/views/DocumentDecorations.tsx           |  6 +-
 src/client/views/MarqueeAnnotator.tsx              |  6 +-
 src/client/views/OverlayView.tsx                   |  5 +-
 src/client/views/PropertiesView.tsx                |  8 +--
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 src/client/views/collections/CollectionMenu.tsx    |  1 -
 src/client/views/collections/TabDocView.tsx        |  5 +-
 src/client/views/collections/TreeView.tsx          |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 71 +++++++++++-----------
 .../collectionSchema/CollectionSchemaView.tsx      | 21 ++++---
 src/client/views/nodes/AudioBox.tsx                |  4 +-
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/KeyValuePair.scss           |  4 --
 src/client/views/nodes/KeyValuePair.tsx            |  2 +-
 src/client/views/nodes/VideoBox.tsx                | 12 ++--
 src/client/views/nodes/WebBox.tsx                  |  1 +
 .../views/nodes/formattedText/FormattedTextBox.tsx | 29 ++++-----
 src/client/views/nodes/trails/PresBox.scss         |  1 +
 src/client/views/nodes/trails/PresBox.tsx          | 24 ++++----
 src/client/views/nodes/trails/PresElementBox.tsx   | 18 +++---
 src/fields/Doc.ts                                  |  9 +++
 23 files changed, 124 insertions(+), 117 deletions(-)

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5aa69e499..35747f746 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -450,7 +450,7 @@ export namespace Docs {
                 DocumentType.IMG,
                 {
                     layout: { view: ImageBox, dataField: defaultDataKey },
-                    options: {},
+                    options: {freeform: '',},
                 },
             ],
             [
@@ -464,7 +464,7 @@ export namespace Docs {
                 DocumentType.COL,
                 {
                     layout: { view: CollectionView, dataField: defaultDataKey },
-                    options: { _layout_fitWidth: true, _freeform_panX: 0, _freeform_panY: 0, _freeform_scale: 1 },
+                    options: { _layout_fitWidth: true, freeform: '', _freeform_panX: 0, _freeform_panY: 0, _freeform_scale: 1 },
                 },
             ],
             [
@@ -1035,7 +1035,7 @@ export namespace Docs {
         // }
 
         export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
-            const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, freeform: '', ...options, _type_collection: CollectionViewType.Freeform }, id);
+            const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20,  ...options, _type_collection: CollectionViewType.Freeform }, id);
             documents.forEach(d => (d.embedContainer = inst));
             return inst;
         }
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ea5770b6a..642ea26da 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -318,7 +318,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe
         if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
             DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
         } else {
-            const container = DocCast(containingDoc ?? doc.embedContainer);
+            const container = DocCast(containingDoc ?? doc.embedContainer ?? doc);
             const showDoc = !Doc.IsSystem(container) ? container : doc;
             options.toggleTarget = undefined;
             DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8077b9af1..beddc0e8a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -10,7 +10,7 @@ import { AclAdmin, AclEdit, DataSym, Doc, DocListCast, Field, HeightSym, WidthSy
 import { InkField } from '../../fields/InkField';
 import { RichTextField } from '../../fields/RichTextField';
 import { ScriptField } from '../../fields/ScriptField';
-import { Cast, NumCast, StrCast } from '../../fields/Types';
+import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
 import { GetEffectiveAcl } from '../../fields/util';
 import { aggregateBounds, emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils';
 import { Docs } from '../documents/Documents';
@@ -189,7 +189,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @action
     onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => {
         const dragDocView = SelectionManager.Views()[0];
-        if (DocListCast(Doc.MyOverlayDocs.data).includes(dragDocView.rootDoc)) return false;
+        const containers = new Set<Doc|undefined>();
+        SelectionManager.Views().forEach(v => containers.add(DocCast(v.rootDoc.embedContainer)));
+        if (containers.size > 1) return false;
         const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 };
         const dragData = new DragManager.DocumentDragData(
             SelectionManager.Views().map(dv => dv.props.Document),
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 1d6c94c13..c9555ab91 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -153,8 +153,8 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                 annotationOn: this.props.rootDoc,
                 title: 'Annotation on ' + this.props.rootDoc.title,
             });
-            marqueeAnno.x = NumCast(this.props.docView.props.Document.freeform_panXMin) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1);
-            marqueeAnno.y = NumCast(this.props.docView.props.Document.freeform_panYMin) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1) + NumCast(this.props.scrollTop);
+            marqueeAnno.x = NumCast(this.props.docView.props.Document.freeform_panX_min) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1);
+            marqueeAnno.y = NumCast(this.props.docView.props.Document.freeform_panY_min) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1) + NumCast(this.props.scrollTop);
             marqueeAnno._height = parseInt(anno.style.height || '0') / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1);
             marqueeAnno._width = parseInt(anno.style.width || '0') / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1);
             anno.remove();
@@ -243,7 +243,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
         this._top = Math.min(this._startY, this._startY + this._height);
         this._width = Math.abs(this._width);
         this._height = Math.abs(this._height);
-        e.stopPropagation();
+        //e.stopPropagation(); // overlay documents are all 'active', yet they can be dragged. if we stop propagation, then they can be marqueed but not dragged.  if we don't stop, then they will be marqueed and dragged, but the marquee will be zero width since the doc will move along with the cursor.
     };
 
     onSelectEnd = (e: PointerEvent) => {
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 9baedae6d..00f9aa879 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -159,7 +159,7 @@ export class OverlayView extends React.Component {
     }
 
     removeOverlayDoc = (doc: Doc | Doc[]) => {
-        (doc instanceof Doc ? [doc] : doc).forEach(doc => Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc));
+        (doc instanceof Doc ? [doc] : doc).forEach(Doc.RemFromMyOverlay);
         return true;
     };
 
@@ -177,6 +177,7 @@ export class OverlayView extends React.Component {
                     offsety = 0;
                 const dref = React.createRef<HTMLDivElement>();
                 const onPointerMove = action((e: PointerEvent, down: number[]) => {
+                 if (e.cancelBubble) return false;  // if the overlay doc processed the move event (e.g., to pan its contents), then the event should be marked as canceled since propagation can't be stopped
                     if (e.buttons === 1) {
                         d.overlayX = e.clientX + offsetx;
                         d.overlayY = e.clientY + offsety;
@@ -196,7 +197,7 @@ export class OverlayView extends React.Component {
                 });
 
                 const onPointerDown = (e: React.PointerEvent) => {
-                    setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction);
+                    setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction, false);
                     offsetx = NumCast(d.overlayX) - e.clientX;
                     offsety = NumCast(d.overlayY) - e.clientY;
                 };
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 75514a090..0c89f1a27 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1623,8 +1623,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     </div>
                 );
             }
-            if (this.isPres) {
-                const selectedItem: boolean = PresBox.Instance?.selectedArray.size > 0;
+            if (this.isPres && PresBox.Instance) {
+                const selectedItem: boolean = PresBox.Instance.selectedArray.size > 0;
                 const type = [DocumentType.AUDIO, DocumentType.VID].includes(DocCast(PresBox.Instance.activeItem?.annotationOn)?.type as any as DocumentType)
                     ? (DocCast(PresBox.Instance.activeItem?.annotationOn)?.type as any as DocumentType)
                     : PresBox.targetRenderedDoc(PresBox.Instance.activeItem)?.type;
@@ -1636,8 +1636,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div className="propertiesView-name" style={{ borderBottom: 0 }}>
                             {this.editableTitle}
                             <div className="propertiesView-presSelected">
-                                <div className="propertiesView-selectedCount">{PresBox.Instance?.selectedArray.size} selected</div>
-                                <div className="propertiesView-selectedList">{PresBox.Instance?.listOfSelected}</div>
+                                <div className="propertiesView-selectedCount">{PresBox.Instance.selectedArray.size} selected</div>
+                                <div className="propertiesView-selectedList">{PresBox.Instance.listOfSelected}</div>
                             </div>
                         </div>
                         {!selectedItem ? null : (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 76dadc76d..e9cc2c894 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -593,7 +593,7 @@ ScriptingGlobals.add(
                     case '<ScriptingRepl />': return OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
                     case "<UndoStack>": return OverlayView.Instance.addWindow(<UndoStack />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
                 }
-                Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+                Doc.AddToMyOverlay(doc);
         }
     },
     'opens up document in location specified',
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 570d9c8fb..d2338d742 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -549,7 +549,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     @action
     startRecording = () => {
         const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _layout_fitWidth: true, _width: 400, _height: 200, mediaState: 'pendingRecording' });
-        //Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
         CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
     };
 
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 33fa434e1..b20d05433 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -292,13 +292,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             PresBox.Instance?.clearSelectedArray();
             pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array
         });
-        if (
+        if ( // open the presentation trail if it's not already opened
             !Array.from(CollectionDockingView.Instance?.tabMap ?? [])
                 .map(d => d.DashDoc)
                 .includes(curPres)
         ) {
-            const docs = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), []);
-            if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1);
+            if (Doc.IsInMyOverlay(curPres)) Doc.RemFromMyOverlay(curPres);
             CollectionDockingView.AddSplit(curPres, OpenWhereMod.right);
             setTimeout(() => DocumentManager.Instance.showDocument(docList.lastElement(), { willPan: true }), 100); // keeps the pinned doc in view since the sidebar shifts things
         }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index f56eaee07..abbb0df4c 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -761,7 +761,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'New Folder' };
         const deleteItem = { script: ScriptField.MakeFunction(`scriptContext.deleteItem()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'Delete' };
         const folderOp = this.childDocs?.length ? [makeFolder] : [];
-        const openEmbedding = { script: ScriptField.MakeFunction(`openDoc(getEmbedding(self), ${OpenWhere.addRight})`)!, icon: 'copy', label: 'Open Embedding' };
+        const openEmbedding = { script: ScriptField.MakeFunction(`openDoc(getEmbedding(self), ${OpenWhere.addRight})`)!, icon: 'copy', label: 'Open New Embedding' };
         const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, icon: 'eye', label: 'Focus or Open' };
         return [
             ...(this.props.contextMenuItems ?? []).filter(mi => (!mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result)),
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 9bf071cc0..3b5dd45d9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -635,7 +635,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     case InkTool.None:
                         if (!(this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) {
                             this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY));
-                            setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, this._hitCluster !== -1 ? true : false);
+                            setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, this._hitCluster !== -1 ? true : false, false);
                         }
                         break;
                 }
@@ -868,9 +868,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             Doc.ActiveTool = InkTool.None;
         } else {
             if (this.tryDragCluster(e, this._hitCluster)) {
+                e.stopPropagation(); // we're moving a cluster, so stop propagation and return true to end panning and let the document drag take over
                 return true;
             }
-            this.pan(e);
+            // pan the view if this is a regular collection, or it's an overlay and the overlay is zoomed (otherwise, there's nothing to pan)
+            if (!this.props.isAnnotationOverlay || (1 - NumCast(this.rootDoc._freeform_scale_min, 1)/ this.getLocalTransform().inverse().Scale)) {
+                this.pan(e);                
+                e.stopPropagation();  // if we are actually panning, stop propagation -- this will preven things like the overlayView from dragging the document while we're panning
+            }
         }
         return false;
     };
@@ -1023,12 +1028,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (deltaScale * invTransform.Scale > 20) {
             deltaScale = 20 / invTransform.Scale;
         }
-        if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._freeform_scaleMin, 1) && this.isAnnotationOverlay) {
+        if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._freeform_scale_min, 1) && this.isAnnotationOverlay) {
             this.setPan(0, 0);
             return;
         }
-        if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._freeform_scaleMin, 1) && this.isAnnotationOverlay) {
-            deltaScale = NumCast(this.rootDoc._freeform_scaleMin, 1) / invTransform.Scale;
+        if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._freeform_scale_min, 1) && this.isAnnotationOverlay) {
+            deltaScale = NumCast(this.rootDoc._freeform_scale_min, 1) / invTransform.Scale;
         }
 
         const localTransform = invTransform.scaleAbout(deltaScale, x, y);
@@ -1040,36 +1045,25 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
 
     @action
-    onPointerWheel = (e: React.WheelEvent): void => {
+    onPointerWheel = (e:React.WheelEvent): void => {
         if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
         PresBox.Instance?.pauseAutoPres();
-        if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
+        if (this.layoutDoc._Transform || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
         e.stopPropagation();
+        const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc)+"_nativeHeight"], this.nativeHeight);
+        const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey],1) ===1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling ;
         switch (!e.ctrlKey ? Doc.UserDoc().freeformScrollMode : freeformScrollMode.Pan) {
             case freeformScrollMode.Pan:
                 // if ctrl is selected then zoom
-                if (e.ctrlKey) {
-                    if (this.props.isContentActive(true)) {
-                        if (this.props.isAnnotationOverlayScrollable) {
-                            // bcz: zooming on a webbox doesn't get the correct coordinates here for unknown reasons.
-                            // so better to do nothing than having things jump around.
-                        } else this.zoom(e.screenX, e.screenY, e.deltaY);
-                    }
-                } // otherwise pan
-                else if (this.props.isContentActive(true)) {
-                    const dx = -e.deltaX;
-                    const dy = -e.deltaY;
-                    if (e.shiftKey) {
-                        !this.props.isAnnotationOverlayScrollable && this.scrollPan({ deltaX: dy, deltaY: 0 });
-                    } else {
-                        !this.props.isAnnotationOverlayScrollable && this.scrollPan({ deltaX: dx, deltaY: dy });
-                    }
+                if (!e.ctrlKey && this.props.isContentActive(true)) {
+                    this.scrollPan({ deltaX: -e.deltaX, deltaY: e.shiftKey ? 0 :-Math.max(-1, Math.min(1,e.deltaY)) });
+                    break;
                 }
-                break;
             default:
             case freeformScrollMode.Zoom:
-                if (this.props.isContentActive(true)) {
-                    !this.props.isAnnotationOverlayScrollable && this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
+                if ((e.ctrlKey || !scrollable) && this.props.isContentActive(true)) {
+                    this.zoom(e.clientX, e.clientY,Math.max(-1, Math.min(1,e.deltaY))); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
+                    e.preventDefault();
                 }
                 break;
         }
@@ -1112,19 +1106,20 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 else if (ranges.yrange.max <= panY - panelHgtMin / 2) panY = ranges.yrange.min - (this.props.originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2);
             }
         }
-        if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) {
+        if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc) {
             this.setPanZoomTransition(panTime);
-            const scale = this.getLocalTransform().inverse().Scale;
-            const minScale = NumCast(this.rootDoc._freeform_scaleMin, 1);
-            const minPanX = NumCast(this.rootDoc._freeform_panXMin, 0);
-            const minPanY = NumCast(this.rootDoc._freeform_panYMin, 0);
-            const newPanX = Math.min(minPanX + (1 - minScale / scale) * NumCast(this.rootDoc._freeform_panXMax, this.nativeWidth), Math.max(minPanX, panX));
+            const minScale = NumCast(this.rootDoc._freeform_scale_min, 1);
+            const scale = (1 - minScale/ this.getLocalTransform().inverse().Scale);
+            const minPanX = NumCast(this.rootDoc._freeform_panX_min, 0);
+            const minPanY = NumCast(this.rootDoc._freeform_panY_min, 0);
+            const maxPanX = NumCast(this.rootDoc._freeform_panX_max, this.nativeWidth);
+            const newPanX = Math.min(minPanX + scale *maxPanX, Math.max(minPanX, panX));
             const fitYscroll = (((this.nativeHeight / this.nativeWidth) * this.props.PanelWidth() - this.props.PanelHeight()) * this.props.ScreenToLocalTransform().Scale) / minScale;
             const nativeHeight = (this.props.PanelHeight() / this.props.PanelWidth() / (this.nativeHeight / this.nativeWidth)) * this.nativeHeight;
             const maxScrollTop = this.nativeHeight / this.props.ScreenToLocalTransform().Scale - this.props.PanelHeight();
             const maxPanY =
                 minPanY + // minPanY + scrolling introduced by view scaling + scrolling introduced by layout_fitWidth
-                (1 - minScale / scale) * NumCast(this.rootDoc._panYMax, nativeHeight) +
+                scale* NumCast(this.rootDoc._panY_max, nativeHeight) +
                 (!this.props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning
             let newPanY = Math.max(minPanY, Math.min(maxPanY, panY));
             if (false && NumCast(this.rootDoc.layout_scrollTop) && NumCast(this.rootDoc._freeform_scale, minScale) !== minScale) {
@@ -1971,6 +1966,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     lightboxPanelWidth = () => Math.max(0, this.props.PanelWidth() - 30);
     lightboxPanelHeight = () => Math.max(0, this.props.PanelHeight() - 30);
     lightboxScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-15, -15);
+    onPassiveWheel = (e:WheelEvent) => {
+        const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc)+"_nativeHeight"], this.nativeHeight);
+        const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey],1) ===1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling ;
+        this.props.isSelected() && !scrollable && e.preventDefault()
+    }
+    _oldWheel:any;
     render() {
         TraceMobx();
         return (
@@ -1978,8 +1979,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 className="collectionfreeformview-container"
                 ref={r => {
                     this.createDashEventsTarget(r);
+                    this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+                    this._oldWheel= r;
                     // prevent wheel events from passivly propagating up through containers
-                    !this.props.isAnnotationOverlay && r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false });
+                     r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
                 }}
                 onWheel={this.onPointerWheel}
                 onClick={this.onClick}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 2a68f9b58..1cc48bebe 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -686,6 +686,12 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
+    onPassiveWheel = (e:WheelEvent) => { 
+        // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
+        if (!this._oldWheel.scrollTop && e.deltaY <= 0) e.preventDefault();
+        e.stopPropagation();
+    }
+    _oldWheel:any;
     @computed get keysDropdown() {
         return (
             <div className="schema-key-search">
@@ -699,16 +705,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                 </div>
                 <div
                     className="schema-key-list"
-                    ref={r =>
-                        r?.addEventListener(
-                            'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
-                            (e: WheelEvent) => {
-                                if (!r.scrollTop && e.deltaY <= 0) e.preventDefault();
-                                e.stopPropagation();
-                            },
-                            { passive: false }
-                        )
-                    }>
+                    ref={r => {
+                        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+                        this._oldWheel= r;
+                        r?.addEventListener('wheel', this.onPassiveWheel, { passive: false } );
+                    }}>
                     {this._menuKeys.map(key => (
                         <div
                             className="schema-search-result"
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 410e0bbdc..0cb849923 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -362,10 +362,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 Doc.GetProto(newDoc).recordingSource = this.dataDoc;
                 Doc.GetProto(newDoc).recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.fieldKey}-recordingStart"]`);
                 Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState');
-                if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc)) {
+                if (Doc.IsInMyOverlay(this.rootDoc)) {
                     newDoc.overlayX = this.rootDoc.x;
                     newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height);
-                    Doc.AddDocToList(Doc.MyOverlayDocs, undefined, newDoc);
+                    Doc.AddToMyOverlay(newDoc);
                 } else {
                     this.props.addDocument?.(newDoc);
                 }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 10ef1e6af..84f82a4b9 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -527,7 +527,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 !this.Document.ignoreClick &&
                 e.button === 0 &&
                 this.pointerEvents !== 'none' &&
-                !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)
+                !Doc.IsInMyOverlay(this.layoutDoc)
             ) {
                 e.stopPropagation();
                 // don't preventDefault anymore.  Goldenlayout, PDF text selection and RTF text selection all need it to go though
diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss
index 2b4867321..57d36932e 100644
--- a/src/client/views/nodes/KeyValuePair.scss
+++ b/src/client/views/nodes/KeyValuePair.scss
@@ -19,7 +19,6 @@
             position: relative;
             margin: 0;
         }
-        .keyValuePair-keyFieldMod,
         .keyValuePair-keyField {
             width: 100%;
             margin-left: 20px;
@@ -28,9 +27,6 @@
             overflow: auto;
             display: inline;
         }
-        .keyValuePair-keyFieldMod {
-            margin-left: 35px;
-        }
     }
 }
 .keyValuePair-td-value {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 509bb667e..91df928c4 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -109,7 +109,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
                             X
                         </button>
                         <input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
-                        <div className={`keyValuePair-keyField${props.fieldKey.includes('_') ? 'Mod' : ''}`} style={{ color: keyStyle }}>
+                        <div className='keyValuePair-keyField' style={{ marginLeft: 35 * (props.fieldKey.match(/_/g)?.length ||0), color: keyStyle }}>
                             {'('.repeat(parenCount)}
                             {props.fieldKey}
                             {')'.repeat(parenCount)}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 3cfc3d696..9cf929679 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -870,7 +870,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 }),
                 returnFalse,
                 () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations),
-                false
+                false, false
             );
         }
     };
@@ -1026,13 +1026,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         croppingProto.videoCrop = true;
         croppingProto.layout_currentTimecode = this.layoutDoc._layout_currentTimecode;
         croppingProto.freeform_scale = viewScale;
-        croppingProto.freeform_scaleMin = viewScale;
+        croppingProto.freeform_scale_min = viewScale;
         croppingProto.freeform_ = anchx / viewScale;
         croppingProto.freeform_panY = anchy / viewScale;
-        croppingProto.freeform_panXMin = anchx / viewScale;
-        croppingProto.freeform_panXMax = anchw / viewScale;
-        croppingProto.freeform_panYMin = anchy / viewScale;
-        croppingProto.freeform_panYMax = anchh / viewScale;
+        croppingProto.freeform_panX_min = anchx / viewScale;
+        croppingProto.freeform_panX_max = anchw / viewScale;
+        croppingProto.freeform_panY_min = anchy / viewScale;
+        croppingProto.freeform_panY_max = anchh / viewScale;
         if (addCrop) {
             DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
         }
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 437079ca4..48808dbad 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -745,6 +745,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     ref={action((r: HTMLIFrameElement | null) => (this._iframe = r))}
                     src={url}
                     onLoad={this.iframeLoaded}
+                    scrolling="no" // ugh.. on windows, I get an inner scroll bar for the iframe's body even though the scrollHeight should be set to the full height of the document.  
                     // the 'allow-top-navigation' and 'allow-top-navigation-by-user-activation' attributes are left out to prevent iframes from redirecting the top-level Dash page
                     // sandbox={"allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts"} />;
                     sandbox={`${this.layoutDoc.allowScripts ? 'allow-scripts' : ''} allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin`}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index e85835002..fb0c0d2ab 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -917,10 +917,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     data_nativeWidth: result.nativeWidth,
                     data_nativeHeight: result.nativeHeight,
                 });
-                if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc)) {
+                if (Doc.IsInMyOverlay(this.rootDoc)) {
                     newDoc.overlayX = this.rootDoc.x;
                     newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height);
-                    Doc.AddDocToList(Doc.MyOverlayDocs, undefined, newDoc);
+                    Doc.AddToMyOverlay(newDoc);
                 } else {
                     this.props.addDocument?.(newDoc);
                 }
@@ -2000,6 +2000,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return this.props.fieldKey + (usePath && (!usePath.includes(':hover') || this._isHovering) ? `_${usePath.replace(':hover', '')}` : '');
     }
     @observable _isHovering = false;
+    onPassiveWheel = (e:WheelEvent) => { 
+        // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
+        if (this.props.isContentActive() && !this.props.allowScroll) {
+            if (!NumCast(this.layoutDoc._layout_scrollTop) && e.deltaY <= 0) e.preventDefault();
+            e.stopPropagation();
+        }
+    }
+    _oldWheel:any;
     render() {
         TraceMobx();
         const active = this.props.isContentActive() || this.props.isSelected();
@@ -2019,18 +2027,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 className="formattedTextBox"
                 onPointerEnter={action(() => (this._isHovering = true))}
                 onPointerLeave={action(() => (this._isHovering = false))}
-                ref={r =>
-                    r?.addEventListener(
-                        'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
-                        (e: WheelEvent) => {
-                            if (this.props.isContentActive() && !this.props.allowScroll) {
-                                if (!NumCast(this.layoutDoc._layout_scrollTop) && e.deltaY <= 0) e.preventDefault();
-                                e.stopPropagation();
-                            }
-                        },
-                        { passive: false }
-                    )
-                }
+                ref={r => {
+                    this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+                    this._oldWheel= r;
+                    r?.addEventListener('wheel', this.onPassiveWheel,  { passive: false } );
+                }}
                 style={{
                     ...(this.props.dontScale
                         ? {}
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss
index eb91c82f3..bf56b4d9e 100644
--- a/src/client/views/nodes/trails/PresBox.scss
+++ b/src/client/views/nodes/trails/PresBox.scss
@@ -951,6 +951,7 @@
         margin-right: unset;
         height: 100%;
         position: relative;
+        user-select: none;
     }
 
     select {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 14d463a6b..913018b69 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -196,7 +196,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         this.turnOffEdit(true);
         this._disposers.selection = reaction(
             () => SelectionManager.Views(),
-            views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation()
+            views => (!PresBox.Instance || views.some(view => view.props.Document === this.rootDoc)) && this.updateCurrentPresentation(),
+            {fireImmediately:true}
         );
         this._disposers.editing = reaction(
             () => this.layoutDoc.presStatus === PresStatus.Edit,
@@ -832,7 +833,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     }
                 });
             LightboxView.SetLightboxDoc(undefined);
-            Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc);
+            Doc.RemFromMyOverlay(this.rootDoc);
             return PresStatus.Edit;
         };
     };
@@ -928,8 +929,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return PresBox.OpenPresMinimized(this.rootDoc, [pt[0] + (this.props.PanelWidth() - 250), pt[1] + 10]);
     };
     exitMinimize = () => {
-        if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
-            Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc);
+        if (Doc.IsInMyOverlay(this.layoutDoc)) {
+            Doc.RemFromMyOverlay(this.rootDoc);
             CollectionDockingView.AddSplit(this.rootDoc, OpenWhereMod.right);
         }
         return PresStatus.Edit;
@@ -941,7 +942,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         doc.overlayY = pt[1];
         doc._height = 30;
         doc._width = PresBox.minimizedWidth;
-        Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+        Doc.AddToMyOverlay(doc);
         PresBox.Instance?.initializePresState(PresBox.Instance.itemIndex);
         return (doc.presStatus = PresStatus.Manual);
     }
@@ -1158,7 +1159,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 }
                 break;
             case 'Escape':
-                if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
+                if (Doc.IsInMyOverlay(this.layoutDoc)) {
                     this.exitClicked();
                 } else if (this.layoutDoc.presStatus === PresStatus.Edit) {
                     this.clearSelectedArray();
@@ -2130,10 +2131,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const propTitle = SettingsManager.propertiesWidth > 0 ? 'Close Presentation Panel' : 'Open Presentation Panel';
         const mode = StrCast(this.rootDoc._type_collection) as CollectionViewType;
         const isMini: boolean = this.toolbarWidth <= 100;
-        const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
         const activeColor = Colors.LIGHT_BLUE;
         const inactiveColor = Colors.WHITE;
-        return mode === CollectionViewType.Carousel3D || inOverlay ? null : (
+        return mode === CollectionViewType.Carousel3D || Doc.IsInMyOverlay(this.rootDoc) ? null : (
             <div id="toolbarContainer" className={'presBox-toolbar'}>
                 {/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
                     <FontAwesomeIcon icon={"plus"} />
@@ -2174,9 +2174,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @computed get topPanel() {
         const mode = StrCast(this.rootDoc._type_collection) as CollectionViewType;
         const isMini: boolean = this.toolbarWidth <= 100;
-        const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
         return (
-            <div className={`presBox-buttons${inOverlay ? ' inOverlay' : ''}`} style={{ background: Doc.ActivePresentation === this.rootDoc ? Colors.LIGHT_BLUE : undefined, display: !this.rootDoc._chromeHidden ? 'none' : undefined }}>
+            <div className={`presBox-buttons${Doc.IsInMyOverlay(this.rootDoc) ? ' inOverlay' : ''}`} style={{ background: Doc.ActivePresentation === this.rootDoc ? Colors.LIGHT_BLUE : undefined, display: !this.rootDoc._chromeHidden ? 'none' : undefined }}>
                 {isMini ? null : (
                     <select className="presBox-viewPicker" style={{ display: this.layoutDoc.presStatus === 'edit' ? 'block' : 'none' }} onPointerDown={e => e.stopPropagation()} onChange={this.viewChanged} value={mode}>
                         <option onPointerDown={StopEvent} value={CollectionViewType.Stacking}>
@@ -2226,7 +2225,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @computed get playButtons() {
         const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0));
         const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0;
-        const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
+        const inOverlay = Doc.IsInMyOverlay(this.rootDoc);
         // Case 1: There are still other frames and should go through all frames before going to next slide
         return (
             <div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== 'edit' ? 'inline-flex' : 'none' }}>
@@ -2400,7 +2399,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const mode = StrCast(this.rootDoc._type_collection) as CollectionViewType;
         const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0));
         const presStart = !this.layoutDoc.presLoop && this.itemIndex === 0;
-        const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
         return this.props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player
             <div className="miniPres" onClick={e => e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}>
                 <div
@@ -2443,7 +2441,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 </div>
             </div>
         ) : (
-            <div className="presBox-cont" style={{ minWidth: inOverlay ? PresBox.minimizedWidth : undefined }}>
+            <div className="presBox-cont" style={{ minWidth: Doc.IsInMyOverlay(this.rootDoc) ? PresBox.minimizedWidth : undefined }}>
                 {this.topPanel}
                 {this.toolbar}
                 {this.newDocumentToolbarDropdown}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 2279ffe84..1f40b82a3 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -322,11 +322,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
 
     removeAllRecordingInOverlay = () => {
-        DocListCast(Doc.MyOverlayDocs.data).forEach(doc => {
-            if (doc.slides === this.rootDoc) {
-                Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc);
-            }
-        });
+        DocListCast(Doc.MyOverlayDocs.data).filter(doc => doc.slides === this.rootDoc).forEach(Doc.RemFromMyOverlay);
     };
 
     static removeEveryExistingRecordingInOverlay = () => {
@@ -334,9 +330,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         DocListCast(Doc.MyOverlayDocs.data).forEach(doc => {
             if (doc.slides !== null) {
                 // if it's a recording video, don't remove from overlay (user can lose data)
-                if (!PresElementBox.videoIsRecorded(DocCast(doc.slides))) return;
-
-                Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc);
+                if (PresElementBox.videoIsRecorded(DocCast(doc.slides))) {
+                    Doc.RemFromMyOverlay(doc);
+                }
             }
         });
     };
@@ -356,7 +352,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         if (!iconClick) PresElementBox.removeEveryExistingRecordingInOverlay();
 
         if (activeItem.recording) {
-            Doc.AddDocToList(Doc.MyOverlayDocs, undefined, DocCast(activeItem.recording));
+            Doc.AddToMyOverlay(DocCast(activeItem.recording));
         }
     };
 
@@ -368,7 +364,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
             // if we already have an existing recording
             this.showRecording(activeItem, true);
             //   // if we already have an existing recording
-            //   Doc.AddDocToList(Doc.MyOverlayDocs, undefined, Cast(activeItem.recording, Doc, null));
+            //   Doc.AddToMyOverlay(Cast(activeItem.recording, Doc, null));
         } else {
             // Remove every recording that already exists in overlay view
             // this is a design decision to clear to focus in on the recoding mode
@@ -392,7 +388,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
             // make recording box appear in the bottom right corner of the screen
             recording.overlayX = window.innerWidth - recording[WidthSym]() - 20;
             recording.overlayY = window.innerHeight - recording[HeightSym]() - 20;
-            Doc.AddDocToList(Doc.MyOverlayDocs, undefined, recording);
+            Doc.AddToMyOverlay(recording);
         }
     };
 
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index d8447deb6..128cfffb2 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -211,6 +211,15 @@ export class Doc extends RefField {
     public static get MyTrails() {
         return DocCast(Doc.ActiveDashboard?.myTrails);
     }
+    public static IsInMyOverlay(doc:Doc) {
+        return DocListCast(Doc.MyOverlayDocs?.data).includes(doc);
+    }
+    public static AddToMyOverlay(doc:Doc) {
+        Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+    }
+    public static RemFromMyOverlay(doc:Doc) {
+        Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc)
+    }
     public static get MyOverlayDocs() {
         return DocCast(Doc.UserDoc().myOverlayDocs);
     }
-- 
cgit v1.2.3-70-g09d2


From 27f518632c24f69fff360bef36eb0e5426167b83 Mon Sep 17 00:00:00 2001
From: James Hu <51237606+jameshu111@users.noreply.github.com>
Date: Wed, 7 Jun 2023 12:30:53 -0400
Subject: Update other uses

---
 src/client/documents/Documents.ts                      | 4 ++--
 src/client/util/Import & Export/DirectoryImportBox.tsx | 2 +-
 src/client/util/ReportManager.tsx                      | 2 +-
 src/client/views/nodes/AudioBox.tsx                    | 2 +-
 src/client/views/nodes/DocumentView.tsx                | 2 +-
 src/client/views/nodes/RecordingBox/RecordingView.tsx  | 2 +-
 src/client/views/nodes/ScreenshotBox.tsx               | 4 ++--
 src/mobile/ImageUpload.tsx                             | 2 +-
 src/server/ApiManagers/UploadManager.ts                | 2 +-
 9 files changed, 11 insertions(+), 11 deletions(-)

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 77f0e1e5e..0030af982 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1844,7 +1844,7 @@ export namespace DocUtils {
     export async function uploadFilesToDocs(files: File[], options: DocumentOptions) {
         const generatedDocuments: Doc[] = [];
         const fileNoGuidPairs: Networking.FileGuidPair[] = [];
-        files.map(file => fileNoGuidPairs.push({file : file}));
+        files.map(file => fileNoGuidPairs.push({file}));
         const upfiles = await Networking.UploadFilesToServer(fileNoGuidPairs);
         for (const {
             source: { name, type },
@@ -1857,7 +1857,7 @@ export namespace DocUtils {
 
     export function uploadFileToDoc(file: File, options: DocumentOptions, overwriteDoc: Doc) {
         const generatedDocuments: Doc[] = [];
-        Networking.UploadFilesToServer([{file: file, guid: overwriteDoc[Id]}]).then(upfiles => {
+        Networking.UploadFilesToServer([{file, guid: overwriteDoc[Id]}]).then(upfiles => {
             const {
                 source: { name, type },
                 result,
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index b9bb22564..1a4c2450e 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -112,7 +112,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
                 sizes.push(file.size);
                 modifiedDates.push(file.lastModified);
             });
-            collector.push(...(await Networking.UploadFilesToServer<Upload.ImageInformation>(batch)));
+            collector.push(...(await Networking.UploadFilesToServer<Upload.ImageInformation>(batch.map(file =>({file})))));
             runInAction(() => (this.completed += batch.length));
         });
 
diff --git a/src/client/util/ReportManager.tsx b/src/client/util/ReportManager.tsx
index 51742d455..4c1020455 100644
--- a/src/client/util/ReportManager.tsx
+++ b/src/client/util/ReportManager.tsx
@@ -173,7 +173,7 @@ export class ReportManager extends React.Component<{}> {
         // upload the files to the server
         if (input.files && input.files.length !== 0) {
             const fileArray: File[] = Array.from(input.files);
-            (Networking.UploadFilesToServer(fileArray)).then(links => {
+            (Networking.UploadFilesToServer(fileArray.map(file =>({file})))).then(links => {
                 console.log('finshed uploading', links.map(this.getServerPath));
                 this.setFileLinks((links ?? []).map(this.getServerPath));
             })
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 0cb849923..6558d215a 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -233,7 +233,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         this.dataDoc[this.fieldKey + '-recordingStart'] = new DateField();
         DocUtils.ActiveRecordings.push(this);
         this._recorder.ondataavailable = async (e: any) => {
-            const [{ result }] = await Networking.UploadFilesToServer(e.data);
+            const [{ result }] = await Networking.UploadFilesToServer({file: e.data});
             if (!(result instanceof Error)) {
                 this.props.Document[this.fieldKey] = new AudioField(result.accessPaths.agnostic.client);
             }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 0769e26d0..687683e6e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1013,7 +1013,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 gumStream = stream;
                 recorder = new MediaRecorder(stream);
                 recorder.ondataavailable = async (e: any) => {
-                    const [{ result }] = await Networking.UploadFilesToServer(e.data);
+                    const [{ result }] = await Networking.UploadFilesToServer({file: e.data});
                     if (!(result instanceof Error)) {
                         const audioField = new AudioField(result.accessPaths.agnostic.client);
                         const audioAnnos = Cast(dataDoc[field + '-audioAnnotations'], listSpec(AudioField), null);
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index 424ebc384..51eb774e2 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -67,7 +67,7 @@ export function RecordingView(props: IRecordingViewProps) {
                 const videoFiles = videos.map((vid, i) => new File(vid.videoChunks, `segvideo${i}.mkv`, { type: vid.videoChunks[0].type, lastModified: Date.now() }));
 
                 // upload the segments to the server and get their server access paths
-                const serverPaths: string[] = (await Networking.UploadFilesToServer(videoFiles)).map(res => (res.result instanceof Error ? '' : res.result.accessPaths.agnostic.server));
+                const serverPaths: string[] = (await Networking.UploadFilesToServer(videoFiles.map(file => ({file})))).map(res => (res.result instanceof Error ? '' : res.result.accessPaths.agnostic.server));
 
                 // concat the segments together using post call
                 const result: Upload.AccessPathInfo | Error = await Networking.PostToServer('/concatVideos', serverPaths);
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 1e178b123..312b3c619 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -224,7 +224,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             const aud_chunks: any = [];
             this._audioRec.ondataavailable = (e: any) => aud_chunks.push(e.data);
             this._audioRec.onstop = async (e: any) => {
-                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks);
+                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({file})));
                 if (!(result instanceof Error)) {
                     this.dataDoc[this.props.fieldKey + '-audio'] = new AudioField(result.accessPaths.agnostic.client);
                 }
@@ -237,7 +237,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             this._videoRec.onstop = async (e: any) => {
                 console.log('screenshotbox: upload');
                 const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
-                const [{ result }] = await Networking.UploadFilesToServer(file);
+                const [{ result }] = await Networking.UploadFilesToServer({file});
                 this.dataDoc[this.fieldKey + '_duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
                 if (!(result instanceof Error)) {
                     // convert this screenshotBox into normal videoBox
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index f910d765e..da38fcaee 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -42,7 +42,7 @@ export class Uploader extends React.Component<ImageUploadProps> {
                     this.process = "Uploading Files";
                     for (let index = 0; index < files.length; ++index) {
                         const file = files[index];
-                        const res = await Networking.UploadFilesToServer(file);
+                        const res = await Networking.UploadFilesToServer({file});
                         this.setOpacity(3, "1"); // Slab 3
                         // For each item that the user has selected
                         res.map(async ({ result }) => {
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 74c06b4a6..94f744848 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -75,7 +75,7 @@ export default class UploadManager extends ApiManager {
                         for (const key in files) {
                             const f = files[key];
                             if (!Array.isArray(f)) {
-                                const result = await DashUploadUtils.upload(f);
+                                const result = await DashUploadUtils.upload(f, key);
                                 result && !(result.result instanceof Error) && results.push(result);
                             }
                         }
-- 
cgit v1.2.3-70-g09d2

