From 5cd64622f14ede408d3baca4a10d155b60392e46 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 13 Apr 2023 22:22:07 -0400
Subject: lots of changes to get rid of ContainingCollectionDoc and
 ContainingCollectionView props.

---
 src/client/views/collections/CollectionView.tsx | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index bc25ad43a..53fbcc3cc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -279,7 +279,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             CollectionView: this,
         };
         return (
-            <div className={'collectionView'} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
+            <div
+                className="collectionView"
+                onContextMenu={this.onContextMenu}
+                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
                 {this.showIsTagged()}
                 {this.renderSubView(this.collectionViewType, props)}
             </div>
-- 
cgit v1.2.3-70-g09d2


From 650cc00d18c97f89aef77f50703aa9b525dd0368 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 14 Apr 2023 11:12:49 -0400
Subject: got rid of CollectionView prop.  fixed DocFocusOrOpen to toggle
 targets and zoom correctly.

---
 src/client/util/DocumentManager.ts                  | 12 +++++++-----
 .../util/Import & Export/DirectoryImportBox.tsx     |  2 +-
 src/client/util/LinkFollower.ts                     |  2 +-
 src/client/views/MainView.tsx                       |  1 -
 src/client/views/PropertiesDocBacklinksSelector.tsx |  2 +-
 src/client/views/PropertiesDocContextSelector.tsx   | 21 +--------------------
 src/client/views/SidebarAnnos.tsx                   |  1 -
 src/client/views/StyleProvider.tsx                  |  4 ++--
 src/client/views/TemplateMenu.tsx                   |  1 -
 src/client/views/collections/CollectionMenu.tsx     |  1 -
 .../views/collections/CollectionNoteTakingView.tsx  |  2 +-
 .../views/collections/CollectionStackingView.tsx    |  2 +-
 src/client/views/collections/CollectionSubView.tsx  |  6 +++---
 src/client/views/collections/CollectionTreeView.tsx |  6 +++---
 src/client/views/collections/CollectionView.tsx     |  1 -
 src/client/views/collections/TabDocView.tsx         |  1 -
 src/client/views/collections/TreeView.tsx           |  6 +++---
 .../collectionFreeForm/CollectionFreeFormView.tsx   | 11 +++++++----
 src/client/views/linking/LinkMenuItem.tsx           |  2 +-
 src/client/views/nodes/AudioBox.tsx                 |  1 -
 src/client/views/nodes/DocumentView.tsx             | 14 +++++++-------
 src/client/views/nodes/ImageBox.tsx                 |  1 -
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx  |  1 -
 src/client/views/nodes/PDFBox.tsx                   |  1 -
 src/client/views/nodes/ScreenshotBox.tsx            |  1 -
 src/client/views/nodes/VideoBox.tsx                 |  2 --
 src/client/views/nodes/WebBox.tsx                   |  1 -
 .../views/nodes/formattedText/FormattedTextBox.tsx  |  1 -
 src/client/views/pdf/PDFViewer.tsx                  |  1 -
 29 files changed, 39 insertions(+), 69 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ad89e8653..e01457b4f 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -227,6 +227,7 @@ export class DocumentManager {
         let rootContextView = docViewPath.shift();
         await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined })));
         if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden;
+        else if (options.openLocation?.startsWith(OpenWhere.toggle) && !options.didMove && rootContextView) MainView.addDocTabFunc(rootContextView.rootDoc, options.openLocation);
     };
 
     // shows a document by first:
@@ -246,10 +247,9 @@ export class DocumentManager {
             const viewIndex = docContextPath.findIndex(doc => this.getDocumentView(doc));
             if (viewIndex !== -1) return res(this.getDocumentView(docContextPath[viewIndex])!);
             options.didMove = true;
-            docContextPath.some(doc => TabDocView.Activate(doc)) || MainView.addDocTabFunc(docContextPath[0], options.openLocation as OpenWhere);
+            docContextPath.some(doc => TabDocView.Activate(doc)) || MainView.addDocTabFunc(docContextPath[0], options.openLocation ?? OpenWhere.addRight);
             this.AddViewRenderedCb(docContextPath[0], dv => res(dv));
         });
-
         docContextPath.shift();
         const childViewIterator = async (docView: DocumentView) => {
             const innerDoc = docContextPath.shift();
@@ -297,15 +297,17 @@ export class DocumentManager {
         }
     }
 }
-export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, openLocation: OpenWhere.addRight }, containingDoc?: Doc) {
+export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) {
     const func = () => {
         const cv = DocumentManager.Instance.getDocumentView(containingDoc);
         const dv = DocumentManager.Instance.getDocumentView(doc, cv);
         if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
             DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
         } else {
-            const showDoc = Doc.BestAlias(DocCast((containingDoc ?? doc.context) !== Doc.MyFilesystem ? containingDoc ?? doc.context : undefined, doc));
-            DocumentManager.Instance.showDocument(showDoc, { ...options, toggleTarget: undefined }, () => DocumentManager.Instance.showDocument(doc, options)).then(() => {
+            const container = DocCast(containingDoc ?? doc.context);
+            const showDoc = !Doc.IsSystem(container) ? container : doc;
+            options.toggleTarget = undefined;
+            DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => {
                 const cv = DocumentManager.Instance.getDocumentView(containingDoc);
                 const dv = DocumentManager.Instance.getDocumentView(doc, cv);
                 dv && Doc.linkFollowHighlight(dv.rootDoc);
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 76b1323c4..b9bb22564 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -157,7 +157,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
             x: NumCast(doc.x),
             y: NumCast(doc.y) + offset,
         };
-        const parent = _.nth(this.props.docViewPath(), -2); // last element of path is this box's document view, 2nd to last is any collection or other document that may contain it.
+        const parent = this.props.DocumentView?.().props.docViewPath().lastElement();
         if (parent?.rootDoc.type === DocumentType.COL) {
             let importContainer: Doc;
             if (docs.length < 50) {
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index d4d7c66f5..ba2edb65c 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -75,7 +75,7 @@ export class LinkFollower {
                         zoomTime: NumCast(sourceDoc.followLinkTransitionTime, 500),
                         zoomScale: Cast(sourceDoc.followLinkZoomScale, 'number', null),
                         easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any,
-                        openLocation: StrCast(sourceDoc.followLinkLocation, OpenWhere.lightbox),
+                        openLocation: StrCast(sourceDoc.followLinkLocation, OpenWhere.lightbox) as OpenWhere,
                         effect: sourceDoc,
                         zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText),
                     };
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 0384d925e..ccc9a7215 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -883,7 +883,6 @@ export class MainView extends React.Component {
                     isSelected={returnFalse}
                     docViewPath={returnEmptyDoclist}
                     moveDocument={this.moveButtonDoc}
-                    CollectionView={undefined}
                     addDocument={this.addButtonDoc}
                     addDocTab={MainView.addDocTabFunc}
                     pinToPres={emptyFunction}
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index 00c3400cb..935d551c6 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -25,7 +25,7 @@ export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDo
 
         if (otherdoc) {
             otherdoc.hidden = false;
-            this.props.addDocTab(Doc.IsPrototype(otherdoc) ? Doc.MakeDelegate(otherdoc) : otherdoc, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
+            this.props.addDocTab(Doc.IsPrototype(otherdoc) ? Doc.MakeDelegate(otherdoc) : otherdoc, OpenWhere.toggleRight);
         }
     };
 
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 93eec61f3..c14d7ef73 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -49,26 +49,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
     getOnClick = (col: Doc, target: Doc) => {
         if (!this.props.DocView) return;
         col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
-        if (col._viewType === CollectionViewType.Freeform) {
-            col._panX = NumCast(target.x) + NumCast(target._width) / 2;
-            col._panY = NumCast(target.y) + NumCast(target._height) / 2;
-        }
-        col.hidden = false;
-        //this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
-        setTimeout(
-            () =>
-                this.props.DocView &&
-                DocFocusOrOpen(
-                    Doc.GetProto(this.props.DocView.props.Document),
-                    {
-                        //
-                        willZoomCentered: true,
-                        openLocation: (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere,
-                    },
-                    col
-                ),
-            100
-        );
+        DocFocusOrOpen(Doc.GetProto(this.props.DocView.props.Document), undefined, col);
     };
 
     render() {
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 2d2b0f83e..b0aab968e 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -243,7 +243,6 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         removeDocument={this.removeDocument}
                         moveDocument={this.moveDocument}
                         addDocument={this.addDocument}
-                        CollectionView={undefined}
                         ScreenToLocalTransform={this.screenToLocalTransform}
                         renderDepth={this.props.renderDepth + 1}
                         viewType={CollectionViewType.Stacking}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 739d6d819..5f16e0ebd 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -5,7 +5,7 @@ import { Shadows } from 'browndash-components';
 import { action, runInAction } from 'mobx';
 import { extname } from 'path';
 import { Doc, Opt, StrListCast } from '../../fields/Doc';
-import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types';
 import { DashColor, lightOrDark, Utils } from '../../Utils';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { DocFocusOrOpen, DocumentManager } from '../util/DocumentManager';
@@ -383,7 +383,7 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
         return doc._viewType === CollectionViewType.Docking ? null : (
             <>
                 {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => {
-                    DocFocusOrOpen(doc, { toggleTarget: true, willPan: true, openLocation: OpenWhere.addRight }, props?.docViewPath().lastElement()?.rootDoc);
+                    DocFocusOrOpen(doc, { toggleTarget: true, willZoomCentered: true, zoomScale: 0 }, DocCast(doc?.context ?? doc?.annotationOn));
                 })}
             </>
         );
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index c5a501aa6..1c816aa05 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -113,7 +113,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 {templateMenu}
                 <CollectionTreeView
                     Document={Doc.MyTemplates}
-                    CollectionView={undefined}
                     styleProvider={DefaultStyleProvider}
                     setHeight={returnFalse}
                     docViewPath={returnEmptyDoclist}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 2007f73aa..5b631676e 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -120,7 +120,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                     isSelected={returnFalse}
                     docViewPath={returnEmptyDoclist}
                     moveDocument={returnFalse}
-                    CollectionView={undefined}
                     addDocument={returnFalse}
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 80e81bc1c..99d4d0bee 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -162,7 +162,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     }
 
     @action
-    moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => {
+    moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string): boolean => {
         return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
     };
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 67f5dc9f4..bdad325d5 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -230,7 +230,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     isAnyChildContentActive = () => this.props.isAnyChildContentActive();
 
     @action
-    moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => {
+    moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
         return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
     };
     createRef = (ele: HTMLDivElement | null) => {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 132ed6fb6..5581ac8fe 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -19,7 +19,6 @@ import { DocComponent } from '../DocComponent';
 import React = require('react');
 
 export interface SubCollectionViewProps extends CollectionViewProps {
-    CollectionView: Opt<CollectionView>;
     isAnyChildContentActive: () => boolean;
 }
 
@@ -201,8 +200,9 @@ export function CollectionSubView<X>(moreProps?: X) {
             }
         }
 
-        addDocument = (doc: Doc | Doc[]) => this.props.addDocument?.(doc) || false;
-
+        addDocument = (doc: Doc | Doc[], annotationKey?: string) => this.props.addDocument?.(doc, annotationKey) || false;
+        removeDocument = (doc: Doc | Doc[], annotationKey?: string) => this.props.removeDocument?.(doc, annotationKey) || false;
+        moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string) => this.props.moveDocument?.(doc, targetCollection, addDocument);
         @action
         protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
             const docDragData = de.complete.docDragData;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 92932fb61..f81c17a7b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -374,10 +374,10 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
     panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1));
 
-    addAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.addDocument(doc, `${this.props.fieldKey}-annotations`) || false;
-    remAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false;
+    addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}-annotations`) || false;
+    remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false;
     moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) =>
-        this.props.CollectionView?.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false;
+        this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false;
 
     @observable _headerHeight = 0;
     @computed get content() {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 53fbcc3cc..d7a889362 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -276,7 +276,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             childLayoutString: this.childLayoutString,
             childHideResizeHandles: this.childHideResizeHandles,
             childHideDecorationTitle: this.childHideDecorationTitle,
-            CollectionView: this,
         };
         return (
             <div
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index ef8f395c5..4bbc3bb44 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -577,7 +577,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
             <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
                 <CollectionFreeFormView
                     Document={this.props.document}
-                    CollectionView={undefined}
                     docViewPath={returnEmptyDoclist}
                     childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
                     noOverlay={true} // don't render overlay Docs since they won't scale
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 8b1dfc767..8fb610b87 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -48,7 +48,7 @@ export interface TreeViewProps {
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
     panelWidth: () => number;
     panelHeight: () => number;
-    addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
+    addDocument: (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => boolean;
     removeDoc: ((doc: Doc | Doc[]) => boolean) | undefined;
     moveDocument: DragManager.MoveFunction;
     isContentActive: (outsideReaction?: boolean) => boolean;
@@ -373,7 +373,7 @@ export class TreeView extends React.Component<TreeViewProps> {
 
     dropping: boolean = false;
     dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, removeDocument: DragManager.RemoveFunction | undefined, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) {
-        const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before);
+        const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, undefined, before);
         const localAdd = (doc: Doc | Doc[]) => {
             const innerAdd = (doc: Doc) => {
                 const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[this.fieldKey])) instanceof ComputedField;
@@ -1186,7 +1186,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 };
                 const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
                 const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
-                const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
+                const addDocument = (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
                 const childLayout = Doc.Layout(pair.layout);
                 const rowHeight = () => {
                     const aspect = Doc.NativeAspect(childLayout);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a3f5e73fb..33fc2ddf3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -311,7 +311,7 @@ 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.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.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);
@@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
         if (didMove) {
             const focusTime = options?.instant ? 0 : options.zoomTime ?? 500;
-            (options.zoomScale || options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale);
+            (options.zoomScale ?? options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale);
             this.setPan(panX, panY, focusTime, true); // 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;
         }
@@ -1181,9 +1181,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const pt2 = xf.transformPoint(NumCast(doc.x) + layoutdoc[WidthSym](), NumCast(doc.y) + layoutdoc[HeightSym]());
         const bounds = { left: pt[0], right: pt2[0], top: pt[1], bot: pt2[1], width: pt2[0] - pt[0], height: pt2[1] - pt[1] };
 
-        if (scale) {
+        if (scale !== undefined) {
             const maxZoom = 5; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context
-            const newScale = Math.min(maxZoom, (1 / (this.nativeDimScaling || 1)) * scale * Math.min(this.props.PanelWidth() / Math.abs(bounds.width), this.props.PanelHeight() / Math.abs(bounds.height)));
+            const newScale =
+                scale === 0
+                    ? NumCast(this.layoutDoc[this.scaleFieldKey])
+                    : Math.min(maxZoom, (1 / (this.nativeDimScaling || 1)) * scale * Math.min(this.props.PanelWidth() / Math.abs(bounds.width), this.props.PanelHeight() / Math.abs(bounds.height)));
             return {
                 panX: this.props.isAnnotationOverlay ? bounds.left - (Doc.NativeWidth(this.layoutDoc) / newScale - bounds.width) / 2 : (bounds.left + bounds.right) / 2,
                 panY: this.props.isAnnotationOverlay ? bounds.top - (Doc.NativeHeight(this.layoutDoc) / newScale - bounds.height) / 2 : (bounds.top + bounds.bot) / 2,
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index d703c9595..19d6c2ae2 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -45,7 +45,7 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume
 
         const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
         dragData.canEmbed = true;
-        dragData.moveDocument = (docView.props.docViewPath().lastElement()?.ComponentView as any)?.props.CollectionView?.moveDocument; // this is equal to docView.props.moveDocument, but moveDocument is not a defined prop of a DocumentView .. but maybe it should be?
+        dragData.dropAction = 'alias';
 
         DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined);
     }
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index a6acf882c..68fb19208 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -663,7 +663,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 startTag={'_timecodeToShow' /* audioStart */}
                 endTag={'_timecodeToHide' /* audioEnd */}
                 bringToFront={emptyFunction}
-                CollectionView={undefined}
                 playFrom={this.playFrom}
                 setTime={this.setPlayheadTime}
                 playing={this.playing}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index be07f1fe5..7107707d1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -22,7 +22,7 @@ import { DictationManager } from '../../util/DictationManager';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { InteractionUtils } from '../../util/InteractionUtils';
-import { FollowLinkScript, LinkFollower } from '../../util/LinkFollower';
+import { FollowLinkScript } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -30,7 +30,6 @@ import { SharingManager } from '../../util/SharingManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from '../../util/UndoManager';
-import { CollectionView } from '../collections/CollectionView';
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from '../DocComponent';
@@ -69,6 +68,7 @@ export enum OpenWhere {
     close = 'close',
     fullScreen = 'fullScreen',
     toggle = 'toggle',
+    toggleRight = 'toggle:right',
     replace = 'replace',
     replaceRight = 'replace:right',
     replaceLeft = 'replace:left',
@@ -87,7 +87,7 @@ export enum OpenWhereMod {
 
 export interface DocFocusOptions {
     willPan?: boolean; // determines whether to pan to target document
-    willZoomCentered?: boolean; // determines whether to zoom in on target document
+    willZoomCentered?: boolean; // determines whether to zoom in on target document.  if zoomScale is 0, this just centers the document
     zoomScale?: number; // percent of containing frame to zoom into document
     zoomTime?: number;
     didMove?: boolean; // whether a document was changed during the showDocument process
@@ -97,7 +97,7 @@ export interface DocFocusOptions {
     effect?: Doc; // animation effect for focus
     noSelect?: boolean; // whether target should be selected after focusing
     playAudio?: boolean; // whether to play audio annotation on focus
-    openLocation?: string; // where to open a missing document
+    openLocation?: OpenWhere; // where to open a missing document
     zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections
     toggleTarget?: boolean; // whether to toggle target on and off
     anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc
@@ -170,9 +170,9 @@ export interface DocumentViewSharedProps {
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
     filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
-    addDocument?: (doc: Doc | Doc[]) => boolean;
-    removeDocument?: (doc: Doc | Doc[]) => boolean;
-    moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
+    addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
+    removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
+    moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean;
     pinToPres: (document: Doc, pinProps: PinProps) => void;
     ScreenToLocalTransform: () => Transform;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 22ecaa299..7c98aa6e4 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -478,7 +478,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     renderDepth={this.props.renderDepth + 1}
                     fieldKey={this.annotationKey}
                     styleProvider={this.props.styleProvider}
-                    CollectionView={undefined}
                     isAnnotationOverlay={true}
                     annotationLayerHostsContent={true}
                     PanelWidth={this.props.PanelWidth}
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index d65ef9c4c..7b437c7de 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -57,7 +57,6 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
                             Document={this.props.place}
                             DataDoc={undefined}
                             fieldKey="data"
-                            CollectionView={undefined}
                             NativeWidth={returnZero}
                             NativeHeight={returnZero}
                             docFilters={returnEmptyFilter}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 502811e35..8f87b9e08 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -547,7 +547,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         removeDocument={this.sidebarRemDocument}
                         moveDocument={this.sidebarMoveDocument}
                         addDocument={this.sidebarAddDocument}
-                        CollectionView={undefined}
                         ScreenToLocalTransform={this.sidebarScreenToLocal}
                         renderDepth={this.props.renderDepth + 1}
                         noSidebar={true}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index e015024fd..aa2b22e28 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -303,7 +303,6 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             removeDocument={returnFalse}
                             moveDocument={returnFalse}
                             addDocument={returnFalse}
-                            CollectionView={undefined}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform}
                             renderDepth={this.props.renderDepth + 1}>
                             <>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index b144c9318..7a7d4fe37 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -963,7 +963,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     startTag={'_timecodeToShow' /* videoStart */}
                     endTag={'_timecodeToHide' /* videoEnd */}
                     bringToFront={emptyFunction}
-                    CollectionView={undefined}
                     playFrom={this.playFrom}
                     setTime={this.setPlayheadTime}
                     playing={this.playing}
@@ -1074,7 +1073,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             NativeHeight={returnZero}
                             renderDepth={this.props.renderDepth + 1}
                             fieldKey={this.annotationKey}
-                            CollectionView={undefined}
                             isAnnotationOverlay={true}
                             annotationLayerHostsContent={true}
                             PanelWidth={this.panelWidth}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 66d0fd385..ef3aa1f47 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -915,7 +915,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
                 fieldKey={this.annotationKey}
-                CollectionView={undefined}
                 setPreviewCursor={this.setPreviewCursor}
                 setBrushViewer={this.setBrushViewer}
                 PanelWidth={this.panelWidth}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index bc2a5d797..5719ea83c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1844,7 +1844,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         removeDocument={this.sidebarRemDocument}
                         moveDocument={this.sidebarMoveDocument}
                         addDocument={this.sidebarAddDocument}
-                        CollectionView={undefined}
                         ScreenToLocalTransform={this.sidebarScreenToLocal}
                         renderDepth={this.props.renderDepth + 1}
                         setHeight={this.setSidebarHeight}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6ab541207..d82a7d1ae 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -530,7 +530,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
                 fieldKey={this.props.fieldKey + '-annotations'}
-                CollectionView={undefined}
                 getScrollHeight={this.getScrollHeight}
                 setPreviewCursor={this.setPreviewCursor}
                 setBrushViewer={this.setBrushViewer}
-- 
cgit v1.2.3-70-g09d2


From 8127616d06b4db2b29de0b13068810fd19e77b5e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 17 Apr 2023 09:26:45 -0400
Subject: minor cleanup of CollectionView

---
 src/client/views/collections/CollectionView.tsx | 90 +++++++------------------
 1 file changed, 25 insertions(+), 65 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index d7a889362..cfb9310b6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -99,18 +99,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
         return viewField as any as CollectionViewType;
     }
 
-    showIsTagged = () => {
-        return null;
-        // this section would display an icon in the bototm right of a collection to indicate that all
-        // photos had been processed through Google's content analysis API and Google's tags had been
-        // assigned to the documents googlePhotosTags field.
-        // const children = DocListCast(this.rootDoc[this.props.fieldKey]);
-        // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
-        // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
-        // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
-        //this.isContentActive();
-    };
-
     screenToLocalTransform = () => (this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()));
     // prettier-ignore
     private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => {
@@ -138,26 +126,25 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
         }
     };
 
-    setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) {
-        const subItems: ContextMenuProps[] = [];
-        subItems.push({ description: 'Freeform', event: () => func(CollectionViewType.Freeform), icon: 'signature' });
-        if (addExtras && CollectionView._safeMode) {
-            ContextMenu.Instance.addItem({ description: 'Test Freeform', event: () => func(CollectionViewType.Invalid), icon: 'project-diagram' });
-        }
-        subItems.push({ description: 'Schema', event: () => func(CollectionViewType.Schema), icon: 'th-list' });
-        subItems.push({ description: 'Tree', event: () => func(CollectionViewType.Tree), icon: 'tree' });
-        subItems.push({ description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' });
-        subItems.push({ description: 'Notetaking', event: () => (func(CollectionViewType.NoteTaking)._autoHeight = true), icon: 'ellipsis-v' });
-        subItems.push({ description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' });
-        subItems.push({ description: 'Multirow', event: () => func(CollectionViewType.Multirow), icon: 'columns' });
-        subItems.push({ description: 'Masonry', event: () => func(CollectionViewType.Masonry), icon: 'columns' });
-        subItems.push({ description: 'Carousel', event: () => func(CollectionViewType.Carousel), icon: 'columns' });
-        subItems.push({ description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' });
-        !Doc.noviceMode && subItems.push({ description: 'Pivot/Time', event: () => func(CollectionViewType.Time), icon: 'columns' });
-        !Doc.noviceMode && subItems.push({ description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' });
-        subItems.push({ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' });
-
+    setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc) {
         if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) {
+            // prettier-ignore
+            const subItems: ContextMenuProps[] = [
+                { description: 'Freeform',    event: () => func(CollectionViewType.Freeform), icon: 'signature' },
+                { description: 'Schema',      event: () => func(CollectionViewType.Schema), icon: 'th-list' },
+                { description: 'Tree',        event: () => func(CollectionViewType.Tree), icon: 'tree' },
+                { description: 'Stacking',    event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' },
+                { description: 'Notetaking',  event: () => (func(CollectionViewType.NoteTaking)._autoHeight = true), icon: 'ellipsis-v' },
+                { description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' },
+                { description: 'Multirow',    event: () => func(CollectionViewType.Multirow), icon: 'columns' },
+                { description: 'Masonry',     event: () => func(CollectionViewType.Masonry), icon: 'columns' },
+                { description: 'Carousel',    event: () => func(CollectionViewType.Carousel), icon: 'columns' },
+                { description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' },
+                { description: 'Pivot/Time',  event: () => func(CollectionViewType.Time), icon: 'columns' },
+                { description: 'Map',         event: () => func(CollectionViewType.Map), icon: 'globe-americas' },
+                { description: 'Grid',        event: () => func(CollectionViewType.Grid), icon: 'th-list' },
+            ];
+
             const existingVm = ContextMenu.Instance.findByDescription(category);
             const catItems = existingVm && 'subitems' in existingVm ? existingVm.subitems : [];
             catItems.push({ description: 'Add a Perspective...', addDivider: true, noexpand: true, subitems: subItems, icon: 'eye' });
@@ -169,16 +156,12 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
         const cm = ContextMenu.Instance;
         if (cm && !e.isPropagationStopped()) {
             // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
-            this.setupViewTypes(
-                'UI Controls...',
-                vtype => {
-                    const newRendition = Doc.MakeAlias(this.rootDoc);
-                    newRendition._viewType = vtype;
-                    this.props.addDocTab(newRendition, OpenWhere.addRight);
-                    return newRendition;
-                },
-                false
-            );
+            this.setupViewTypes('UI Controls...', vtype => {
+                const newRendition = Doc.MakeAlias(this.rootDoc);
+                newRendition._viewType = vtype;
+                this.props.addDocTab(newRendition, OpenWhere.addRight);
+                return newRendition;
+            });
 
             const options = cm.findByDescription('Options...');
             const optionItems = options && 'subitems' in options ? options.subitems : [];
@@ -191,24 +174,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             }
             !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => (this.rootDoc._isLightbox = !this.rootDoc._isLightbox), icon: 'project-diagram' });
 
-            // if (!Doc.noviceMode && false) {
-            //     optionItems.push({
-            //         description: 'Create Branch',
-            //         event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight),
-            //         icon: 'project-diagram',
-            //     });
-            //     optionItems.push({
-            //         description: 'Pull Master',
-            //         event: () => BranchTask(this.rootDoc, 'pull'),
-            //         icon: 'project-diagram',
-            //     });
-            //     optionItems.push({
-            //         description: 'Merge Branches',
-            //         event: () => BranchTask(this.rootDoc, 'merge'),
-            //         icon: 'project-diagram',
-            //     });
-            // }
-
             !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
 
             if (!Doc.noviceMode && !this.rootDoc.annotationOn) {
@@ -253,10 +218,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
     childHideResizeHandles = () => this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles);
     childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle);
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
-    @computed get childLayoutString() {
-        return StrCast(this.rootDoc.childLayoutString, this.props.childLayoutString);
-    }
-
     isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() || this.isAnyChildContentActive();
 
     render() {
@@ -273,7 +234,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             PanelHeight: this.props.PanelHeight,
             ScreenToLocalTransform: this.screenToLocalTransform,
             childLayoutTemplate: this.childLayoutTemplate,
-            childLayoutString: this.childLayoutString,
+            childLayoutString: StrCast(this.rootDoc.childLayoutString, this.props.childLayoutString),
             childHideResizeHandles: this.childHideResizeHandles,
             childHideDecorationTitle: this.childHideDecorationTitle,
         };
@@ -282,7 +243,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
                 className="collectionView"
                 onContextMenu={this.onContextMenu}
                 style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
-                {this.showIsTagged()}
                 {this.renderSubView(this.collectionViewType, props)}
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From f83e5d34794ef675d4627ecef2ed7042b17b1b06 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 18 Apr 2023 10:05:01 -0400
Subject: cleaning up zip/unzip of files

---
 src/client/views/collections/CollectionView.tsx    |  13 ++-
 src/client/views/nodes/DocumentView.tsx            |   2 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |   6 +-
 src/fields/Doc.ts                                  | 128 +++++++++------------
 src/server/ApiManagers/UploadManager.ts            |   9 +-
 5 files changed, 67 insertions(+), 91 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index cfb9310b6..790aa765d 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -156,12 +156,13 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
         const cm = ContextMenu.Instance;
         if (cm && !e.isPropagationStopped()) {
             // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
-            this.setupViewTypes('UI Controls...', vtype => {
-                const newRendition = Doc.MakeAlias(this.rootDoc);
-                newRendition._viewType = vtype;
-                this.props.addDocTab(newRendition, OpenWhere.addRight);
-                return newRendition;
-            });
+            !Doc.noviceMode &&
+                this.setupViewTypes('UI Controls...', vtype => {
+                    const newRendition = Doc.MakeAlias(this.rootDoc);
+                    newRendition._viewType = vtype;
+                    this.props.addDocTab(newRendition, OpenWhere.addRight);
+                    return newRendition;
+                });
 
             const options = cm.findByDescription('Options...');
             const optionItems = options && 'subitems' in options ? options.subitems : [];
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7107707d1..6686f142f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -693,7 +693,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template   ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
             !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
 
-            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Tree) {
+            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.rootDoc._viewType as any)) {
                 const existingOnClick = cm.findByDescription('OnClick...');
                 const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
 
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index c43206629..72e8aedac 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -101,11 +101,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
         this._textBoxDoc = this.props.tbox.props.Document;
 
         if (this.props.docId) {
-            DocServer.GetRefField(this.props.docId).then(
-                action(async dashDoc => {
-                    dashDoc instanceof Doc && (this._dashDoc = dashDoc);
-                })
-            );
+            DocServer.GetRefField(this.props.docId).then(action(dashDoc => dashDoc instanceof Doc && (this._dashDoc = dashDoc)));
         } else {
             this._dashDoc = this.props.tbox.rootDoc;
         }
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 6c808c145..c5af45262 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -705,7 +705,7 @@ export namespace Doc {
         if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!;
         const copy = new Doc(undefined, true);
         cloneMap.set(doc[Id], copy);
-        const filter = [...exclusions, ...Cast(doc.cloneFieldFilter, listSpec('string'), [])];
+        const filter = [...exclusions, ...StrListCast(doc.cloneFieldFilter)];
         await Promise.all(
             Object.keys(doc).map(async key => {
                 if (filter.includes(key)) return;
@@ -725,15 +725,13 @@ export namespace Doc {
                                 const docidsearch = new RegExp('(' + DocsInTextFieldIds.map(exp => '(' + exp + ')').join('|') + ')":"([a-z-A-Z0-9_]*)"', 'g');
                                 const rawdocids = field.Data.match(docidsearch);
                                 const docids = rawdocids?.map((str: string) =>
-                                    DocsInTextFieldIds.reduce((output, exp) => {
-                                        return output.replace(new RegExp(`${exp}":`, 'g'), '');
-                                    }, str)
+                                    DocsInTextFieldIds.reduce((output, exp) => output.replace(new RegExp(`${exp}":`, 'g'), ''), str)
                                         .replace(/"/g, '')
                                         .trim()
                                 );
                                 const results = docids && (await DocServer.GetRefFields(docids));
                                 const docs = results && Array.from(Object.keys(results)).map(key => DocCast(results[key]));
-                                docs && docs.map(doc => Doc.makeClone(doc, cloneMap, linkMap, rtfs, exclusions, cloneLinks));
+                                docs?.map(doc => doc && Doc.makeClone(doc, cloneMap, linkMap, rtfs, exclusions, cloneLinks));
                                 rtfs.push({ copy, key, field });
                             }
                         }
@@ -741,7 +739,7 @@ export namespace Doc {
                 };
                 const docAtKey = doc[key];
                 if (docAtKey instanceof Doc) {
-                    if (!Doc.IsSystem(docAtKey) && (key.startsWith('layout') || key === 'annotationOn' || key === 'proto' || ((key === 'anchor1' || key === 'anchor2') && doc.author === Doc.CurrentUserEmail))) {
+                    if (!Doc.IsSystem(docAtKey) && (key.startsWith('layout') || ['context', 'annotationOn', 'proto'].includes(key) || ((key === 'anchor1' || key === 'anchor2') && doc.author === Doc.CurrentUserEmail))) {
                         assignKey(await Doc.makeClone(docAtKey, cloneMap, linkMap, rtfs, exclusions, cloneLinks));
                     } else {
                         assignKey(docAtKey);
@@ -749,8 +747,7 @@ export namespace Doc {
                 } else if (field instanceof RefField) {
                     assignKey(field);
                 } else if (cfield instanceof ComputedField) {
-                    assignKey(cfield[Copy]());
-                    //   ComputedField.MakeFunction(cfield.script.originalScript));
+                    assignKey(cfield[Copy]()); // ComputedField.MakeFunction(cfield.script.originalScript));
                 } else if (field instanceof ObjectField) {
                     await copyObjectField(field);
                 } else if (field instanceof Promise) {
@@ -804,8 +801,6 @@ export namespace Doc {
         const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ['cloneOf'], cloneLinks);
         const repaired = new Set<Doc>();
         const linkedDocs = Array.from(linkMap.values());
-        const clonedDocs = [...Array.from(cloneMap.values()), ...linkedDocs];
-        clonedDocs.map(clone => Doc.repairClone(clone, cloneMap, repaired));
         linkedDocs.map((link: Doc) => LinkManager.Instance.addLink(link, true));
         rtfMap.map(({ copy, key, field }) => {
             const replacer = (match: any, attr: string, id: string, offset: any, string: any) => {
@@ -816,20 +811,16 @@ export namespace Doc {
                 const mapped = cloneMap.get(id);
                 return href + (mapped ? mapped[Id] : id);
             };
-            const regex = `(${Doc.localServerPath()})([^"]*)`;
-            const re = new RegExp(regex, 'g');
+            const re = new RegExp(`(${Doc.localServerPath()})([^"]*)`, 'g');
             const docidsearch = new RegExp('(' + DocsInTextFieldIds.map(exp => `"${exp}":`).join('|') + ')"([^"]+)"', 'g');
             copy[key] = new RichTextField(field.Data.replace(docidsearch, replacer).replace(re, replacer2), field.Text);
         });
+        const clonedDocs = [...Array.from(cloneMap.values()), ...linkedDocs];
+        clonedDocs.map(clone => Doc.repairClone(clone, cloneMap, repaired));
         return { clone: copy, map: cloneMap, linkMap };
     }
 
-    export async function Zip(doc: Doc) {
-        // const a = document.createElement("a");
-        // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`);
-        // a.href = url;
-        // a.download = `DocExport-${this.props.Document[Id]}.zip`;
-        // a.click();
+    export async function Zip(doc: Doc, zipFilename = 'dashExport.zip') {
         const { clone, map, linkMap } = await Doc.MakeClone(doc);
         clone.LINKS = new List<Doc>(Array.from(linkMap.values()));
         const proms = [] as string[];
@@ -837,76 +828,61 @@ export namespace Doc {
             if (key && ['branchOf', 'cloneOf', 'cursors'].includes(key)) return undefined;
             else if (value instanceof Doc) {
                 if (key !== 'field' && Number.isNaN(Number(key))) {
-                    const __fields = value[FieldsSym]();
-                    return { id: value[Id], __type: 'Doc', fields: __fields };
-                } else {
-                    return { fieldId: value[Id], __type: 'proxy' };
+                    return { id: value[Id], __type: 'Doc', fields: value[FieldsSym]() };
                 }
-            } else if (value instanceof ScriptField) return { script: value.script, __type: 'script' };
-            else if (value instanceof RichTextField) return { Data: value.Data, Text: value.Text, __type: 'RichTextField' };
-            else if (value instanceof ImageField) {
+                return { fieldId: value[Id], __type: 'proxy' };
+            } else if (value instanceof ImageField) {
                 const extension = value.url.href.replace(/.*\./, '');
                 proms.push(value.url.href.replace('.' + extension, '_o.' + extension));
                 return { url: value.url.href, __type: 'image' };
             } else if (value instanceof PdfField) {
                 proms.push(value.url.href);
                 return { url: value.url.href, __type: 'pdf' };
-            } else if (value instanceof AudioField) return { url: value.url.href, __type: 'audio' };
-            else if (value instanceof VideoField) return { url: value.url.href, __type: 'video' };
+            } else if (value instanceof AudioField) {
+                proms.push(value.url.href);
+                return { url: value.url.href, __type: 'audio' };
+            } else if (value instanceof VideoField) {
+                proms.push(value.url.href);
+                return { url: value.url.href, __type: 'video' };
+            } else if (value instanceof ScriptField) return { script: value.script, __type: 'script' };
+            else if (value instanceof RichTextField) return { Data: value.Data, Text: value.Text, __type: 'RichTextField' };
             else if (value instanceof WebField) return { url: value.url.href, __type: 'web' };
             else if (value instanceof MapField) return { url: value.url.href, __type: 'map' };
             else if (value instanceof DateField) return { date: value.toString(), __type: 'date' };
             else if (value instanceof ProxyField) return { fieldId: value.fieldId, __type: 'proxy' };
             else if (value instanceof Array && key !== 'fields') return { fields: value, __type: 'list' };
             else if (value instanceof ComputedField) return { script: value.script, __type: 'computed' };
-            else return value;
+            return value;
         }
 
         const docs: { [id: string]: any } = {};
         Array.from(map.entries()).forEach(f => (docs[f[0]] = f[1]));
-        const docString = JSON.stringify({ id: clone[Id], docs }, decycle(replacer));
-
-        let generateZIP = (proms: string[]) => {
-            var zip = new JSZip();
-            var count = 0;
-            var zipFilename = 'dashExport.zip';
-
-            proms
-                .filter(url => url.startsWith(window.location.origin))
-                .forEach((url, i) => {
-                    var filename = proms[i].replace(window.location.origin + '/', '').replace(/\//g, '%%%');
-                    // loading a file and add it in a zip file
-                    JSZipUtils.getBinaryContent(url, function (err: any, data: any) {
-                        if (err) {
-                            throw err; // or handle the error
-                        }
-                        zip.file(filename, data, { binary: true });
-                        count++;
-                        if (count == proms.length) {
-                            zip.file('doc.json', docString);
-                            zip.generateAsync({ type: 'blob' }).then(function (content) {
-                                saveAs(content, zipFilename);
-                            });
-                        }
-                    });
-                });
-        };
-        generateZIP(proms);
-        const zip = new JSZip();
-
-        zip.file('doc.json', docString);
-
-        // // Generate a directory within the Zip file structure
-        // var img = zip.folder("images");
-
-        // // Add a file to the directory, in this case an image with data URI as contents
-        // img.file("smile.gif", imgData, {base64: true});
+        const jsonDocs = JSON.stringify({ id: clone[Id], docs }, decycle(replacer));
 
-        // Generate the zip file asynchronously
-        zip.generateAsync({ type: 'blob' }).then((content: any) => {
-            // Force down of the Zip file
-            saveAs(content, doc.title + '.zip'); // glr: Possibly change the name of the document to match the title?
-        });
+        const zip = new JSZip();
+        var count = 0;
+        proms
+            .filter(url => url.startsWith(window.location.origin))
+            .forEach((url, i) => {
+                // loading a file and add it in a zip file
+                JSZipUtils.getBinaryContent(url, (err: any, data: any) => {
+                    if (err) throw err; // or handle the error
+                    // // Generate a directory within the Zip file structure
+                    // const assets = zip.folder("assets");
+                    // assets.file(filename, data, {binary: true});
+                    const assetPathOnServer = proms[i].replace(window.location.origin + '/', '').replace(/\//g, '%%%');
+                    zip.file(assetPathOnServer, data, { binary: true });
+                    if (++count == proms.length) {
+                        zip.file('doc.json', jsonDocs);
+                        zip.generateAsync({ type: 'blob' }).then(content => saveAs(content, zipFilename));
+                        // const a = document.createElement("a");
+                        // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`);
+                        // a.href = url;
+                        // a.download = `DocExport-${this.props.Document[Id]}.zip`;
+                        // a.click();
+                    }
+                });
+            });
     }
 
     const _pendingMap: Map<string, boolean> = new Map();
@@ -963,7 +939,7 @@ export namespace Doc {
     // otherwise, it just returns the childDoc
     export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt<Doc>, childDoc: Doc) {
         if (!childDoc || childDoc instanceof Promise || !Doc.GetProto(childDoc)) {
-            console.log('No, no, no!');
+            console.log('Warning: GetLayoutDataDocPair childDoc not defined');
             return { layout: childDoc, data: childDoc };
         }
         const resolvedDataDoc = Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc;
@@ -1553,15 +1529,19 @@ export namespace Doc {
         }
     }
 
-    export async function importDocument(file: File) {
+    ///
+    // imports a previously exported zip file which contains a set of documents and their assets (eg, images, videos)
+    // the 'remap' parameter determines whether the ids of the documents loaded should be kept as they were, or remapped to new ids
+    // If they are not remapped, loading the file will overwrite any existing documents with those ids
+    //
+    export async function importDocument(file: File, remap = false) {
         const upload = Utils.prepend('/uploadDoc');
         const formData = new FormData();
         if (file) {
             formData.append('file', file);
-            formData.append('remap', 'true');
+            formData.append('remap', remap.toString());
             const response = await fetch(upload, { method: 'POST', body: formData });
             const json = await response.json();
-            console.log(json);
             if (json !== 'error') {
                 await DocServer.GetRefFields(json.docids as string[]);
                 const doc = DocCast(await DocServer.GetRefField(json.id));
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 6e28268a9..2cc2ac46c 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -184,9 +184,8 @@ export default class UploadManager extends ApiManager {
                     if (id.endsWith('Proto')) return id;
                     if (id in ids) {
                         return ids[id];
-                    } else {
-                        return (ids[id] = v4());
                     }
+                    return (ids[id] = v4());
                 };
                 const mapFn = (doc: any) => {
                     if (doc.id) {
@@ -266,7 +265,7 @@ export default class UploadManager extends ApiManager {
                                     await Promise.all(
                                         docs.map(
                                             (doc: any) =>
-                                                new Promise<void>(res => {
+                                                new Promise<void>(res =>
                                                     Database.Instance.replace(
                                                         doc.id,
                                                         doc,
@@ -275,8 +274,8 @@ export default class UploadManager extends ApiManager {
                                                             res();
                                                         },
                                                         true
-                                                    );
-                                                })
+                                                    )
+                                                )
                                         )
                                     );
                                 } catch (e) {
-- 
cgit v1.2.3-70-g09d2

