From 9d48c95e5a556f5be4abde83d9443e384a33197c Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Mon, 10 Jul 2023 14:26:37 -0400
Subject: Location metadata synced and reactions working

---
 src/client/views/nodes/trails/PresBox.tsx | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 858d83b7a..d1cfb86ae 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -41,6 +41,7 @@ export interface pinDataTypes {
     scrollable?: boolean;
     dataviz?: number[];
     pannable?: boolean;
+    map?:boolean;
     viewType?: boolean;
     inkable?: boolean;
     filters?: boolean;
@@ -378,6 +379,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const inkable = [DocumentType.INK].includes(targetType);
         const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetType) || target?._viewType === CollectionViewType.Stacking;
         const pannable = [DocumentType.IMG, DocumentType.PDF].includes(targetType) || (targetType === DocumentType.COL && target?._viewType === CollectionViewType.Freeform);
+        const map = [DocumentType.MAP].includes(targetType);
         const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(targetType);
         const clippable = [DocumentType.COMPARISON].includes(targetType);
         const datarange = [DocumentType.FUNCPLOT].includes(targetType);
@@ -387,7 +389,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const filters = true;
         const pivot = true;
         const dataannos = false;
-        return { scrollable, pannable, inkable, viewType, pivot, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos };
+        return { scrollable, pannable, inkable, viewType, pivot, map, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos };
     }
 
     @action
@@ -455,6 +457,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 changed = true;
             }
         }
+        if (pinDataTypes?.map || (!pinDataTypes && activeItem.presLat !== undefined)) {
+            if (bestTarget.latitude !== activeItem.presLat) {
+                Doc.SetInPlace(bestTarget, "latitude", NumCast(activeItem.presLat), true);
+                changed = true;
+            }
+            if (bestTarget.longitude !== activeItem.presLong) {
+                Doc.SetInPlace(bestTarget, "longitude", NumCast(activeItem.presLong), true);
+                bestTarget.restoreTargetOn = true;
+                changed = true;
+            }
+        }
         if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.presStartTime !== undefined)) {
             if (bestTarget._layout_currentTimecode !== activeItem.presStartTime) {
                 bestTarget._layout_currentTimecode = activeItem.presStartTime;
@@ -633,6 +646,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 pinDoc.presXRange = undefined; //targetDoc?.xrange;
                 pinDoc.presYRange = undefined; //targetDoc?.yrange;
             }
+            if (pinProps.pinData.map) {
+                pinDoc.presLat = targetDoc?.lat;
+                //...
+            }
             if (pinProps.pinData.poslayoutview)
                 pinDoc.presPinLayoutData = new List<string>(
                     DocListCast(targetDoc[fkey] as ObjectField).map(d =>
-- 
cgit v1.2.3-70-g09d2


From caa2e09edb9c1db0af571013d006179bdc84f755 Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Mon, 31 Jul 2023 12:58:06 -0400
Subject: All mapType stuff and constructor is done

---
 src/client/documents/Documents.ts         |  3 ++
 src/client/views/nodes/MapBox/MapBox.tsx  | 70 +++++++++++++++++++++++--------
 src/client/views/nodes/trails/PresBox.tsx |  9 +++-
 3 files changed, 64 insertions(+), 18 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5cced6d24..ca62028c1 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -221,6 +221,7 @@ export class DocumentOptions {
     openFactoryAsDelegate?: boolean; //
     lat?: NUMt = new NumInfo('latitude of a mapping view');
     lng?: NUMt = new NumInfo('longitude of a mapping view');
+    zoom?: NUMt = new NumInfo('zoom of a mapping view');
     infoWindowOpen?: boolean;
     author?: string;
     _layout_fieldKey?: string;
@@ -289,6 +290,8 @@ export class DocumentOptions {
     presPanY?: number; // panY saved as a view spec
     presLat?: NUMt = new NumInfo('latitude of a map'); // latitude of a map
     presLong?: NUMt = new NumInfo('longitude of map'); // longitude of map
+    presZoom?: NUMt = new NumInfo('zoom of map'); // zoom of map
+    presMapType?:string;
     presViewScale?: number; // viewScale saved as a view Spec
     presTransition?: number; //the time taken for the transition TO a document
     presDuration?: number; //the duration of the slide in presentation view
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 3c8e6203a..ad534f5f2 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -132,15 +132,21 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     private _disposer: {[key:string]:IReactionDisposer} = {}
     componentDidMount() {
         this.props.setContentView?.(this);
-        this._disposer.location = reaction(() => ({lat:this.rootDoc.latitude, lng:this.rootDoc.longitude}), 
+        this._disposer.location = reaction(() => ({lat:this.rootDoc.latitude, lng:this.rootDoc.longitude, zoom:this.rootDoc.zoom,mapType:this.rootDoc.mapType}), 
         (locationObject) => {
 
-            //TODO: SAVE ZOOM? VIEW STYLE?
             this._bingMap.current.setView({
+                mapTypeId: locationObject.mapType,
+                zoom:locationObject.zoom,
                 center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng),
             });
+            // this._bingMap.current.setZoom(locationObject.zoom);
+
+
 
         }, {fireImmediately: true});
+
+        
     }
 
     componentWillUnmount(): void {
@@ -678,7 +684,18 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     updateLayout = () => {
             this.dataDoc.latitude = this._bingMap.current.getCenter().latitude;
             this.dataDoc.longitude = this._bingMap.current.getCenter().longitude;
+            this.dataDoc.zoom = this._bingMap.current.getZoom();
+            // this.dataDoc.mapType = new this.MicrosoftMaps.MapTypeId();
     };
+    /*
+     * Updates maptype
+     */
+    @action
+    updateMapType = () => {
+            this.dataDoc.mapType = this._bingMap.current.getMapTypeId();
+
+    };
+
 
     searched_pin: any;
     /*
@@ -691,13 +708,18 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const location = await this.bingGeocode(this._bingMap, this.bingSearchBarContents);
         this.dataDoc.latitude = location.latitude;
         this.dataDoc.longitude = location.longitude;
+        this.dataDoc.zoom = this._bingMap.current.getZoom();
+        // this.dataDoc.mapType = this._bingMap.current.getMapTypeId();
+        // this.bingSearchBarContents=location.name;
+
         // Centers on the searched location
-        this._bingMap.current.setView({
-            center: new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude),
-        });
-        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
-        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', this.updateLayout);
+        this._bingMap.current.panTo(new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude));
 
+        // this._bingMap.current.setView({
+        //     center: new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude),
+        // });
+        
+        
 
         
         // Creates a temporary pin but does not add it to the dataDoc
@@ -714,12 +736,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     /**
      * Adds all pushpins in dataDoc onto the map (render) - OLD & UNUSED
      */
-    @action
-    addAllPins = () => {
-        this._bingMap.current.entities.clear();
-        if (this.searched_pin) this._bingMap.current.entities.push(this.searched_pin);
-        // this.allMapPushpins.map(pin => this.addPushpin(pin));
-    };
+    // @action
+    // addAllPins = () => {
+    //     this._bingMap.current.entities.clear();
+    //     if (this.searched_pin) this._bingMap.current.entities.push(this.searched_pin);
+    //     // this.allMapPushpins.map(pin => this.addPushpin(pin));
+    // };
 
     /*
      * Returns doc w/ relevant info
@@ -730,7 +752,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title: 'MapAnchor:' + this.rootDoc.title,
                 presLat: NumCast(this.dataDoc.latitude),
                 presLong: NumCast(this.dataDoc.longitude),
-                // presTransition: 1000,
+                presZoom: NumCast(this.dataDoc.zoom),
+                presMapType: this.dataDoc.mapType,
+                // presType: 
                 unrendered: true,
                 annotationOn: this.rootDoc,
             });
@@ -764,8 +788,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     */
     @action
     removePushpin = (pin:any)=>{
-        this._bingMap.current.entities.clear();
-        this.allMapPushpins
+        // this._bingMap.current.entities.clear();
+        // this.allMapPushpins
         this.allMapPushpins.map(pin => this.addPushpin(pin));
     }
 
@@ -798,7 +822,19 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         else this.placePinOn = true;
     };
 
-    bingMapReady = (map: any) => (this._bingMap = map.map);
+    /*
+     * Called when BingMap is first rendered 
+     * Initializes starting values
+     */
+    bingMapReady = (map: any) => {
+        this._bingMap = map.map;
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', this.updateLayout);
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', this.updateMapType);
+        this.updateLayout();
+        this.updateMapType();
+    }
+        
     render() {
         const renderAnnotations = (docFilters?: () => string[]) => null;
         return (
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index d1cfb86ae..0a907c958 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -464,7 +464,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             }
             if (bestTarget.longitude !== activeItem.presLong) {
                 Doc.SetInPlace(bestTarget, "longitude", NumCast(activeItem.presLong), true);
-                bestTarget.restoreTargetOn = true;
+                changed = true;
+            }
+            if (bestTarget.zoom !== activeItem.presZoom) {
+                Doc.SetInPlace(bestTarget, "zoom", NumCast(activeItem.presZoom), true);
+                changed = true;
+            }
+            if (bestTarget.mapType !== activeItem.presMapType) {
+                Doc.SetInPlace(bestTarget, "mapType", StrCast(activeItem.presMapType), true);
                 changed = true;
             }
         }
-- 
cgit v1.2.3-70-g09d2


From 98d40d63fce7e63bce264b07dbb433dfe2b88d0c Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Tue, 15 Aug 2023 14:40:56 -0400
Subject: Freeze

---
 package-lock.json                         | 97 +++++++++++++++++++++++++++++--
 src/client/views/nodes/DocumentView.tsx   |  2 +-
 src/client/views/nodes/MapBox/MapBox.scss |  4 ++
 src/client/views/nodes/MapBox/MapBox.tsx  | 56 ++++++++++++++----
 src/client/views/nodes/trails/PresBox.tsx |  1 +
 5 files changed, 143 insertions(+), 17 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index a62b3306c..e79d94b3a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6507,9 +6507,9 @@
             }
         },
         "browndash-components": {
-            "version": "0.0.92",
-            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.92.tgz",
-            "integrity": "sha512-eE/6WQNZiLnaXUKyoaMm0PDYjExUsFJ9VTAIIxROpYPosIBKWNZ743xaOfmehib5us9hEXJb0CvUFJQb8rzDVw==",
+            "version": "0.0.93",
+            "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.93.tgz",
+            "integrity": "sha512-JL9Hi7Nq+zHZtjLCQSuGhID0Hd7X6sARutyJqbECfsLWACsIC/JfeEQZdUeH5CqO+R7pJKeoWM82AIkWGtN2Xw==",
             "requires": {
                 "@emotion/react": "^11.11.1",
                 "@emotion/styled": "^11.11.0",
@@ -7063,12 +7063,97 @@
                                         "strip-ansi": "^7.0.1"
                                     }
                                 },
+                                "string-width-cjs": {
+                                    "version": "npm:string-width@4.2.3",
+                                    "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+                                    "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+                                    "requires": {
+                                        "emoji-regex": "^8.0.0",
+                                        "is-fullwidth-code-point": "^3.0.0",
+                                        "strip-ansi": "^6.0.1"
+                                    },
+                                    "dependencies": {
+                                        "ansi-regex": {
+                                            "version": "5.0.1",
+                                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+                                            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+                                        },
+                                        "emoji-regex": {
+                                            "version": "8.0.0",
+                                            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+                                            "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+                                        },
+                                        "strip-ansi": {
+                                            "version": "6.0.1",
+                                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+                                            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+                                            "requires": {
+                                                "ansi-regex": "^5.0.1"
+                                            }
+                                        }
+                                    }
+                                },
                                 "strip-ansi": {
                                     "version": "7.1.0",
                                     "bundled": true,
                                     "requires": {
                                         "ansi-regex": "^6.0.1"
                                     }
+                                },
+                                "strip-ansi-cjs": {
+                                    "version": "npm:strip-ansi@6.0.1",
+                                    "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+                                    "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+                                    "requires": {
+                                        "ansi-regex": "^5.0.1"
+                                    },
+                                    "dependencies": {
+                                        "ansi-regex": {
+                                            "version": "5.0.1",
+                                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+                                            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+                                        }
+                                    }
+                                },
+                                "wrap-ansi-cjs": {
+                                    "version": "npm:wrap-ansi@7.0.0",
+                                    "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+                                    "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+                                    "requires": {
+                                        "ansi-styles": "^4.0.0",
+                                        "string-width": "^4.1.0",
+                                        "strip-ansi": "^6.0.0"
+                                    },
+                                    "dependencies": {
+                                        "ansi-regex": {
+                                            "version": "5.0.1",
+                                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+                                            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+                                        },
+                                        "emoji-regex": {
+                                            "version": "8.0.0",
+                                            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+                                            "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+                                        },
+                                        "string-width": {
+                                            "version": "4.2.3",
+                                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+                                            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+                                            "requires": {
+                                                "emoji-regex": "^8.0.0",
+                                                "is-fullwidth-code-point": "^3.0.0",
+                                                "strip-ansi": "^6.0.1"
+                                            }
+                                        },
+                                        "strip-ansi": {
+                                            "version": "6.0.1",
+                                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+                                            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+                                            "requires": {
+                                                "ansi-regex": "^5.0.1"
+                                            }
+                                        }
+                                    }
                                 }
                             }
                         },
@@ -8573,7 +8658,7 @@
                             }
                         },
                         "string-width-cjs": {
-                            "version": "npm:string-width@4.2.3",
+                            "version": "npm:string-width-cjs@4.2.3",
                             "bundled": true,
                             "requires": {
                                 "emoji-regex": "^8.0.0",
@@ -8596,7 +8681,7 @@
                             }
                         },
                         "strip-ansi-cjs": {
-                            "version": "npm:strip-ansi@6.0.1",
+                            "version": "npm:strip-ansi-cjs@6.0.1",
                             "bundled": true,
                             "requires": {
                                 "ansi-regex": "^5.0.1"
@@ -8755,7 +8840,7 @@
                             }
                         },
                         "wrap-ansi-cjs": {
-                            "version": "npm:wrap-ansi@7.0.0",
+                            "version": "npm:wrap-ansi-cjs@7.0.0",
                             "bundled": true,
                             "requires": {
                                 "ansi-styles": "^4.0.0",
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index bb9f45bdd..419800ad5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1626,4 +1626,4 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSour
     });
     embedding && DocServer.UPDATE_SERVER_CACHE(); // if a new embedding was made, update the client's server cache so that it will not come back as a promise
     return links;
-});
+});
\ No newline at end of file
diff --git a/src/client/views/nodes/MapBox/MapBox.scss b/src/client/views/nodes/MapBox/MapBox.scss
index 539c506c7..fcd4fc9be 100644
--- a/src/client/views/nodes/MapBox/MapBox.scss
+++ b/src/client/views/nodes/MapBox/MapBox.scss
@@ -11,6 +11,10 @@
         padding: 12;
         font-size: 17;
     }
+    .mapBox-topbar{
+        display:flex;
+        flex-direction: row;
+    }
 
     .mapBox-overlayButton-sidebar {
         background: #121721;
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 15cf22953..283d57bb6 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,7 +1,7 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { GoogleMapProps, Marker } from '@react-google-maps/api';
 import BingMapsReact from 'bingmaps-react';
-import { EditableText } from 'browndash-components';
+import { EditableText, Toggle } from 'browndash-components';
 import e from 'connect-flash';
 import { truncateSync } from 'fs';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
@@ -65,7 +65,7 @@ const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing
 const script = document.createElement('script');
 script.defer = true;
 script.async = true;
-script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`;
+script.src = `https://maps.googleapis.com/maps/api/js?key=${bingApiKey}&libraries=places,drawing`;
 document.head.appendChild(script);
 
 /**
@@ -665,8 +665,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * Pushpin dblclick
      */
     @action
-    pushpinDblClicked = (pinDoc:Doc,pin:any) => {
-        this.removePushpin(pinDoc,pin);
+    pushpinDblClicked = (pin:any, pinDoc?:Doc) => {
+        if(pinDoc)
+            this.removePushpin(pinDoc,pin);
+        else
+            this._bingMap.current.entities.remove(pin);
     };
     /*
      * Pushpin onclick
@@ -720,7 +723,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (this.placePinOn) {
             this.createPushpin(e.location.latitude, e.location.longitude);
             // this.addAllPins();
-            this.placePinOn = false;
+            // this.placePinOn = false;
         }
     };
 
@@ -779,6 +782,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         var temp = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(location.latitude, location.longitude), {
             color: 'blue',
         });
+        
+        this.MicrosoftMaps.Events.addHandler(temp, 'dblclick', (e: any) => this.pushpinDblClicked(temp));
         if (temp != this.searched_pin || this.searched_pin == null) {
             this._bingMap.current.entities.push(temp);
             this.searched_pin = temp;
@@ -835,7 +840,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this._bingMap.current.entities.push(pushPin);
 
         this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin,pushPin));
-        this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pin,pushPin));
+        this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin));
     }
 
 
@@ -932,11 +937,42 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
                     {this.annotationLayer}
 
-                    <EditableText setEditing={(isEditing: boolean) => ({})} editing onEdit={(newText: string) => (this.bingSearchBarContents = newText)} placeholder="..." text="Boston, MA" />
-
-                    <input type="button" value="Search" onClick={this.bingSearch} />
+                    <EditableText setEditing={(isEditing: boolean) => ({})} editing onEdit={(newText: string) => (this.bingSearchBarContents = newText)} placeholder="Boston, MA" text="Boston, MA" />
+                    <div className='mapBox-topbar'>
+                        <input type="button" value="Search" onClick={this.bingSearch} />
+
+                        {/* {this.placePinOn ? <input type="button" value="Place Pin Mode On" onClick={this.togglePlacePin} /> : <input type="button" value="Place Pin Mode Off" onClick={this.togglePlacePin} />} */}
+                        {/* {this.placePinOn ? <input type="button" value="Place Pin Mode On" onClick={this.togglePlacePin} /> : <input type="button" value="Place Pin Mode Off" onClick={this.togglePlacePin} />}
+
+                        <Toggle
+                            onClick={this.togglePlacePin}
+                            onPointerDown={function noRefCheck(){}}
+                            onPointerDownCapture={function noRefCheck(){}}
+                            onPointerMove={function noRefCheck(){}}
+                            onPointerMoveCapture={function noRefCheck(){}}
+                            onPointerUp={function noRefCheck(){}}
+                            text="Place Pin"
+                            toggleType = "checkbox"
+                            toggleStatus= {false}
+                            type="secondary"
+                        /> */}
+
+                        <input type="checkbox"
+                                    id="switch"
+                                    className="checkbox" 
+                                    checked={this.placePinOn}
+                                    onChange={this.togglePlacePin}
+                                    />
+                                        
+                                <label htmlFor="switch"
+                                    className="toggle">
+                                    <p>
+                                    {this.placePinOn ? 'Place Pin ON' : 'Place Pin OFF'}
+                                    </p>
+                                </label>
+                    </div>
+                    
 
-                    {this.placePinOn ? <input type="button" value="Place Pin Mode On" onClick={this.togglePlacePin} /> : <input type="button" value="Place Pin Mode Off" onClick={this.togglePlacePin} />}
                     {/* {this.pinIsSelected_TEMPORARY? <input type="button" value="Delete Pin" onClick={this.removeSelectedPin} /> : null} */}
                     <BingMapsReact onMapReady={this.bingMapReady} bingMapsKey={bingApiKey} height="100%" mapOptions={this.bingMapOptions} width="100%" viewOptions={this.bingViewOptions}>
                     </BingMapsReact>
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index c0cd3ab70..76f42778b 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -52,6 +52,7 @@ export interface pinDataTypes {
     dataview?: boolean;
     poslayoutview?: boolean;
     dataannos?: boolean;
+    map?: boolean;
 }
 export interface PinProps {
     audioRange?: boolean;
-- 
cgit v1.2.3-70-g09d2


From eb35837e5ffe8e7eba9decea1fae5c163528dc1e Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Mon, 21 Aug 2023 11:59:05 -0400
Subject: Buggy

---
 src/client/documents/Documents.ts               |   5 +-
 src/client/views/nodes/MapBox/MapBox.scss       |   4 +
 src/client/views/nodes/MapBox/MapBox.tsx        | 201 +++++++++++++-----------
 src/client/views/nodes/MapBox/MapPushpinBox.tsx |   4 +-
 src/client/views/nodes/trails/PresBox.tsx       |   5 +-
 5 files changed, 120 insertions(+), 99 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index af4cf2243..eb777aae2 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -368,8 +368,6 @@ export class DocumentOptions {
     waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
-    openFactoryLocation?: string; // an OpenWhere value to place the factory created document
-    openFactoryAsDelegate?: BOOLt = new BoolInfo('create a delegate of the factory');
     _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
     _dragOnlyWithinContainer?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere');
     _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.');
@@ -381,7 +379,6 @@ export class DocumentOptions {
     cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
     dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active - e.g., pileView, group');
     dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)');
-    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
     clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
@@ -1104,7 +1101,7 @@ export namespace Docs {
             );
         }
         export function MapanchorDocument(options: DocumentOptions = {}, id?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id);
+            return InstanceFromProto(Prototypes.get(DocumentType.MAP), options?.data, options, id);
         }
 
         export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
diff --git a/src/client/views/nodes/MapBox/MapBox.scss b/src/client/views/nodes/MapBox/MapBox.scss
index fcd4fc9be..39fa3262e 100644
--- a/src/client/views/nodes/MapBox/MapBox.scss
+++ b/src/client/views/nodes/MapBox/MapBox.scss
@@ -11,6 +11,10 @@
         padding: 12;
         font-size: 17;
     }
+    .mapBox-searchbar{
+        display:flex;
+        flex-direction: row;
+    }
     .mapBox-topbar{
         display:flex;
         flex-direction: row;
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 283d57bb6..bad1a3ebd 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,7 +1,7 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { GoogleMapProps, Marker } from '@react-google-maps/api';
 import BingMapsReact from 'bingmaps-react';
-import { EditableText, Toggle } from 'browndash-components';
+import { EditableText, IconButton, Toggle, Type } from 'browndash-components';
 import e from 'connect-flash';
 import { truncateSync } from 'fs';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
@@ -13,12 +13,12 @@ import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { ScriptField } from '../../../../fields/ScriptField';
 import { NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnIgnore, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
-import { UndoManager } from '../../../util/UndoManager';
+import { undoable, UndoManager } from '../../../util/UndoManager';
 import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
@@ -116,7 +116,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @observable private _marqueeing: number[] | undefined;
     @observable private inputRef = React.createRef<HTMLInputElement>();
     @observable private searchMarkers: google.maps.Marker[] = [];
-    // @observable private searchBox = new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
+    @observable private searchBox =  undefined as any; //  new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
     @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
     @computed get allSidebarDocs() {
         return DocListCast(this.dataDoc[this.SidebarKey]);
@@ -138,45 +138,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     private _ref: React.RefObject<HTMLDivElement> = React.createRef();
     private _disposer: {[key:string]:IReactionDisposer} = {}
     componentDidMount() {
-        this.props.setContentView?.(this);
-        this._disposer.location = reaction(() => ({lat:this.rootDoc.latitude, lng:this.rootDoc.longitude, zoom:this.rootDoc.zoom,mapType:this.rootDoc.mapType}), 
-        (locationObject) => {
-
-            this._bingMap.current.setView({
-                mapTypeId: locationObject.mapType,
-                zoom:locationObject.zoom,
-                center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng),
-            });
-
-        }, {fireImmediately: true});
-        // this._disposer.pins = reaction(() => ({pinList:this.dataDoc[this.annotationKey]}), 
-        // (pinsObject) => {
-        //     this._bingMap.current.entities.clear();
-        //     pinsObject.pinList.map((pushpin: Doc) => (
-        //                         <DocumentView
-        //                             {...this.props}
-        //                             Document={pushpin}
-        //                             DataDoc={undefined}
-        //                             PanelWidth={returnOne}
-        //                             PanelHeight={returnOne}
-        //                             NativeWidth={returnOne} 
-        //                             NativeHeight={returnOne}
-        //                             onClick={()=>new ScriptField(undefined)}
-        //                             onKey={undefined}
-        //                             onDoubleClick={undefined}
-        //                             onBrowseClick={undefined}
-        //                             docFilters={returnEmptyDoclist}
-        //                             docRangeFilters={returnEmptyDoclist}
-        //                             searchFilterDocs={returnEmptyDoclist}
-        //                             isDocumentActive={returnFalse}
-        //                             isContentActive={returnFalse}
-        //                             addDocTab={returnFalse}
-        //                             ScreenToLocalTransform={()=>new Transform(0,0,0)}
-        //                             fitContentsToBox={undefined}
-        //                             focus={returnOne}
-        //                 />));
-
-        // }, {fireImmediately: false});
 
         
     }
@@ -638,7 +599,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      *
      *
      **/
-
+    @observable
     bingSearchBarContents: any = 'Boston, MA'; // For Bing Maps: The contents of the Bing search bar (string)
 
     geoDataRequestOptions = {
@@ -675,7 +636,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * Pushpin onclick
      */
     @action
-    pushpinClicked = (pinDoc:Doc,pin:any) => {
+    pushpinClicked = (pinDoc:Doc) => {
         // TODO:
         // if (sidebarannos is not open) open sidebarannos
         // creates button onclick removes the doc from annotations
@@ -685,27 +646,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.dataDoc.longitude = pinDoc.lng;
 
         
-
-
-    //     @action
-    // onPointerDown = (e: React.PointerEvent) => {
-    //     if (e.button === 2 || e.ctrlKey) {
-    //         AnchorMenu.Instance.Status = 'annotation';
-    //         AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this);
-    //         AnchorMenu.Instance.Pinned = false;
-    //         AnchorMenu.Instance.PinToPres = this.pinToPres;
-    //         AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle;
-    //         AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
-    //         AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion);
-    //         AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
-    //         e.stopPropagation();
-    //     } else if (e.button === 0) {
-    //         e.stopPropagation();
-    //         LinkFollower.FollowLink(undefined, this.annoTextRegion, false);
-    //     }
-    // };
-
-        // TODO: UPDATE FOR DASHDOC SELECTION
     };
 
     /**
@@ -811,10 +751,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 presLat: NumCast(this.dataDoc.latitude),
                 presLong: NumCast(this.dataDoc.longitude),
                 presZoom: NumCast(this.dataDoc.zoom),
-                presMapType: this.dataDoc.mapType,
+                presMapType: StrCast(this.dataDoc.mapType),
                 // preslocationToLookAt:this.dataDoc.locationToLookAt,
                 // presType: 
-                unrendered: true,
+                layout_unrendered: true,
                 annotationOn: this.rootDoc,
             });
         if (anchor) {
@@ -839,7 +779,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         
         this._bingMap.current.entities.push(pushPin);
 
-        this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin,pushPin));
+        this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin));
         this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin));
     }
 
@@ -876,7 +816,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * Map options
      */
     bingMapOptions = {
-        navigationBarMode: 'compact',
+        navigationBarMode: 'square',
         backgroundColor: '#f1f3f4',
         enableInertia: true,
         supportedMapTypes:['grayscale', 'canvasLight'],
@@ -901,19 +841,71 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         else this.placePinOn = true;
     };
 
+    @action
+    searchbarOnEdit=(newText:string)=>{
+        this.bingSearchBarContents = newText
+    }
+
     /*
      * Called when BingMap is first rendered 
      * Initializes starting values
      */
     bingMapReady = (map: any) => {
         this._bingMap = map.map;
-        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
-        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', this.updateLayout);
-        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', this.updateMapType);
-        this.updateLayout();
-        this.updateMapType();
+        if (!this._bingMap.current) {
+            alert("NO Map!?")
+        }
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', undoable(this.mapOnClick, "Added Pin to Map"));
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.updateLayout, "Map Layout Change"));
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, "Map ViewType Change"));
+        //this.updateLayout();
+       // this.updateMapType();
+        this.props.setContentView?.(this);
+        this._disposer.location = reaction(() => ({lat:this.rootDoc.latitude, lng:this.rootDoc.longitude, zoom:this.rootDoc.zoom,mapType:this.rootDoc.mapType}), 
+        (locationObject) => {
+            // if (this._bingMap.current)
+                this._bingMap.current?.setView({
+                    mapTypeId: locationObject.mapType,
+                    zoom:locationObject.zoom,
+                    center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng),
+                });
+
+        }, {fireImmediately: true});
+        // this._disposer.pins = reaction(() => ({pinList:this.dataDoc[this.annotationKey]}), 
+        // (pinsObject) => {
+        //     this._bingMap.current.entities.clear();
+        //     pinsObject.pinList.map((pushpin: Doc) => (
+        //                         <DocumentView
+        //                             {...this.props}
+        //                             Document={pushpin}
+        //                             DataDoc={undefined}
+        //                             PanelWidth={returnOne}
+        //                             PanelHeight={returnOne}
+        //                             NativeWidth={returnOne} 
+        //                             NativeHeight={returnOne}
+        //                             onClick={()=>new ScriptField(undefined)}
+        //                             onKey={undefined}
+        //                             onDoubleClick={undefined}
+        //                             onBrowseClick={undefined}
+        //                             docFilters={returnEmptyDoclist}
+        //                             docRangeFilters={returnEmptyDoclist}
+        //                             searchFilterDocs={returnEmptyDoclist}
+        //                             isDocumentActive={returnFalse}
+        //                             isContentActive={returnFalse}
+        //                             addDocTab={returnFalse}
+        //                             ScreenToLocalTransform={()=>new Transform(0,0,0)}
+        //                             fitContentsToBox={undefined}
+        //                             focus={returnOne}
+        //                 />));
+
+        // }, {fireImmediately: false});
+    }
+    searchbarKeyDown = (e:any)=>{
+        if (e.key === 'Enter') {
+            this.bingSearch()
+          }
+            
     }
-        
     render() {
         const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
@@ -937,9 +929,44 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
                     {this.annotationLayer}
 
-                    <EditableText setEditing={(isEditing: boolean) => ({})} editing onEdit={(newText: string) => (this.bingSearchBarContents = newText)} placeholder="Boston, MA" text="Boston, MA" />
+
+                    <div className='mapBox-searchbar'>
+                        <EditableText 
+                            // editing 
+                            setVal={(newText:string|number) => typeof newText === "string" && this.searchbarOnEdit(newText)}
+                            placeholder="Boston" 
+                            // text="text" 
+                            />
+                        <IconButton
+                        icon={<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="magnifying-glass" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" color="#DFDFDF"><path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg>}
+                        onClick={this.bingSearch}
+                        onDoubleClick={function noRefCheck(){}}
+                        onPointerDown={function noRefCheck(){}}
+                        onPointerDownCapture={function noRefCheck(){}}
+                        onPointerMove={function noRefCheck(){}}
+                        onPointerMoveCapture={function noRefCheck(){}}
+                        onPointerUp={function noRefCheck(){}}
+                        type={Type.TERT}
+                        />
+                        <input type="checkbox"
+                                    id="switch"
+                                    className="checkbox" 
+                                    checked={this.placePinOn}
+                                    onChange={this.togglePlacePin}
+                                    />
+                                        
+                                <label htmlFor="switch"
+                                    className="toggle">
+                                    <p>
+                                    {this.placePinOn ? 'Place Pin ON' : 'Place Pin OFF'}
+                                    </p>
+                                </label>
+                    </div>
+                    
+                    
                     <div className='mapBox-topbar'>
-                        <input type="button" value="Search" onClick={this.bingSearch} />
+                        {/* <input type="button" value="Search" onClick={this.bingSearch} /> */}
+                        
 
                         {/* {this.placePinOn ? <input type="button" value="Place Pin Mode On" onClick={this.togglePlacePin} /> : <input type="button" value="Place Pin Mode Off" onClick={this.togglePlacePin} />} */}
                         {/* {this.placePinOn ? <input type="button" value="Place Pin Mode On" onClick={this.togglePlacePin} /> : <input type="button" value="Place Pin Mode Off" onClick={this.togglePlacePin} />}
@@ -957,19 +984,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                             type="secondary"
                         /> */}
 
-                        <input type="checkbox"
-                                    id="switch"
-                                    className="checkbox" 
-                                    checked={this.placePinOn}
-                                    onChange={this.togglePlacePin}
-                                    />
-                                        
-                                <label htmlFor="switch"
-                                    className="toggle">
-                                    <p>
-                                    {this.placePinOn ? 'Place Pin ON' : 'Place Pin OFF'}
-                                    </p>
-                                </label>
+                        
                     </div>
                     
 
@@ -992,8 +1007,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                                     onKey={undefined}
                                     onDoubleClick={undefined}
                                     onBrowseClick={undefined}
-                                    docFilters={returnEmptyDoclist}
-                                    docRangeFilters={returnEmptyDoclist}
+                                    childFilters={returnEmptyFilter}
+                                    childFiltersByRanges={returnEmptyFilter}
                                     searchFilterDocs={returnEmptyDoclist}
                                     isDocumentActive={returnFalse}
                                     isContentActive={returnFalse}
diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
index 588bddd1a..6369f9e04 100644
--- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx
+++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
@@ -5,6 +5,7 @@ import { FieldView, FieldViewProps } from '../FieldView';
 import React = require('react');
 import { computed } from 'mobx';
 import { MapBox } from './MapBox';
+import { undoable } from '../../../util/UndoManager';
 
 
 /**
@@ -18,7 +19,8 @@ export class MapPushpinBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return FieldView.LayoutString(MapPushpinBox, fieldKey);
     }
     componentDidMount() {
-        this.mapBoxView.addPushpin(this.rootDoc);
+        // if (this.mapBoxView)
+            this.mapBoxView.addPushpin(this.rootDoc);
     }
     componentWillUnmount() {
         // this.mapBoxView.removePushpin(this.rootDoc);
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 76f42778b..1560ce3e1 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -659,7 +659,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 pinDoc.presYRange = undefined; //targetDoc?.yrange;
             }
             if (pinProps.pinData.map) {
-                pinDoc.presLat = targetDoc?.lat;
+                pinDoc.presLat = targetDoc?.latitude;
+                pinDoc.presLong = targetDoc?.longitude;
+                pinDoc.presZoom = targetDoc?.zoom;
+                pinDoc.mapType = targetDoc?.mapType;
                 //...
             }
             if (pinProps.pinData.poslayoutview)
-- 
cgit v1.2.3-70-g09d2


From 2c46608d3207a8463907b0e1904d9b3026d6d1c8 Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Sat, 26 Aug 2023 12:33:47 -0400
Subject: Final1

---
 src/client/util/DocumentManager.ts        |  2 +-
 src/client/views/SidebarAnnos.tsx         |  1 +
 src/client/views/nodes/MapBox/MapBox.tsx  | 77 ++++++++++++++++++++++++++-----
 src/client/views/nodes/trails/PresBox.tsx |  4 +-
 4 files changed, 70 insertions(+), 14 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7c3b5be05..5b627c2f3 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -310,7 +310,7 @@ export class DocumentManager {
         if (viewSpec && docView) {
             if (docView.ComponentView instanceof FormattedTextBox) docView.ComponentView?.focus(viewSpec, options);
             PresBox.restoreTargetDocView(docView, viewSpec, options.zoomTime ?? 500);
-            Doc.linkFollowHighlight(docView.rootDoc, undefined, options.effect);
+            Doc.linkFollowHighlight(viewSpec ? [docView.rootDoc, viewSpec]: docView.rootDoc, undefined, options.effect);
             if (options.playAudio) DocumentManager.playAudioAnno(docView.rootDoc);
             if (options.toggleTarget && (!options.didMove || docView.rootDoc.hidden)) docView.rootDoc.hidden = !docView.rootDoc.hidden;
             if (options.effect) docView.rootDoc[Animation] = options.effect;
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 7635d719e..520485a71 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -87,6 +87,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
 
         const taggedContent = this.childFilters()
             .filter(data => data.split(':')[0])
+            .filter(data => data.split(':')[0] !== 'latitude' && data.split(':')[0] !== 'longitude')
             .map(data => {
                 const key = data.split(':')[0];
                 const val = Field.Copy(this.allMetadata.get(key));
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index dbb38e763..93020354d 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -7,7 +7,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { TbHeartMinus } from 'react-icons/tb';
 import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
-import { Width } from '../../../../fields/DocSymbols';
+import { Highlight, Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { ScriptField } from '../../../../fields/ScriptField';
@@ -133,6 +133,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     componentWillUnmount(): void {
+        this.deselectPin();
         Object.keys(this._disposer).forEach(key => this._disposer[key]?.());
     }
     // iterate allMarkers to size, center, and zoom map to contain all markers
@@ -353,17 +354,18 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
     };
 
-    createNoteAnnotation = undoable(() => {
+    createNoteAnnotation = () => {
         !this.layoutDoc.layout_showSidebar && this.toggleSidebar();
-        setTimeout(() =>{
-          const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false));
-          if (note && this.selectedPin) {
-            note.latitude = this.selectedPin.latitude;
-            note.longitude = this.selectedPin.latitude;
-          }
-        }); // give time for sidebarRef to be created
-    }, "create linked note");
 
+        setTimeout(undoable(() => {
+            const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false));
+            if (note && this.selectedPin) {
+              note.latitude = this.selectedPin.latitude;
+              note.longitude = this.selectedPin.latitude;
+            }
+          },"create note annotation"))
+    
+    }
     sidebarDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
     };
@@ -818,7 +820,60 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.updateLayout, 'Map Layout Change'));
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change'));
-        // this.updateLayout();
+        this.updateLayout();
+        this._disposer.highlight = reaction( () => this.allMapPushpins.map(doc => doc[Highlight]),
+        () => this.allMapPushpins.forEach(doc => {
+
+            // if(doc[Highlight]){
+            //     this.deselectPin();
+            //     this.selectedPin = doc;
+
+            //     Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "match");
+            //     Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.latitude, "match");
+
+            //     this._bingMap.current.entities.remove(this.map_docToPinMap.get(this.selectedPin));
+            //     const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude), {
+            //         color: 'green',
+            //     });
+            //     this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(this.selectedPin as Doc));
+            //     this._bingMap.current.entities.push(newpin);
+            //     this.map_docToPinMap.set(this.selectedPin, newpin);
+
+            //     MapAnchorMenu.Instance.Delete = this.deleteSelectedPin;
+            //     MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
+            //     MapAnchorMenu.Instance.LinkNote = this.createNoteAnnotation;
+            // }
+            // if (doc[Highlight]) {
+            //     this._bingMap.current.entities.remove(this.map_docToPinMap.get(doc));
+            //     const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(doc.latitude, doc.longitude), {
+            //         color: 'orange',
+            //     });
+            //     this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(doc));
+            //     this._bingMap.current.entities.push(newpin);
+            //     this.map_docToPinMap.set(doc, newpin);
+
+            // } 
+            // if (this.map_docToPinMap.get(doc).getColor() == 'orange' && !doc[Highlight]) {
+            //     this._bingMap.current.entities.remove(this.map_docToPinMap.get(doc));
+            //     const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(doc.latitude, doc.longitude), {});
+            //     this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(doc));
+            //     this._bingMap.current.entities.push(newpin);
+            //     this.map_docToPinMap.set(doc, newpin);
+
+            // } 
+            // else if (this.map_docToPinMap.get(doc).getColor() != 'orange' && doc[Highlight]) {
+            //     this._bingMap.current.entities.remove(this.map_docToPinMap.get(doc));
+            //     const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(doc.latitude, doc.longitude), {
+            //         color: 'orange',
+            //     });
+            //     this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(doc));
+            //     this._bingMap.current.entities.push(newpin);
+            //     this.map_docToPinMap.set(doc, newpin);
+            // }
+
+            
+        })
+        , {fireImmediately: true})
         // this.updateMapType();
         this._disposer.location = reaction(
             () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.mapZoom, mapType: this.rootDoc.mapType }),
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index a94f1f04b..afd9bccab 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -661,8 +661,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 pinDoc.config_yRange = undefined; //targetDoc?.yrange;
             }
             if (pinProps.pinData.map) {
-                pinDoc.config_latitude = targetDoc?.latitude;
-                pinDoc.config_longitude = targetDoc?.longitude;
+                // pinDoc.config_latitude = targetDoc?.latitude;
+                // pinDoc.config_longitude = targetDoc?.longitude;
                 pinDoc.config_mapZoom = targetDoc?.mapZoom;
                 pinDoc.config_mapType = targetDoc?.mapType;
                 //...
-- 
cgit v1.2.3-70-g09d2


From 0a813fdf7d73018ad5248d87fecbd9e55f3dc2d7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 26 Aug 2023 21:25:24 -0400
Subject: many fixes to map search bar, dragging pushpin, highlighting pushpins
 on link following

---
 src/client/documents/Documents.ts         |   8 +-
 src/client/views/nodes/MapBox/MapBox.tsx  | 552 +++++++++---------------------
 src/client/views/nodes/MapBox/MapBox2.tsx |   4 +-
 src/client/views/nodes/trails/PresBox.tsx |  16 +-
 4 files changed, 170 insertions(+), 410 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index af8cc07ed..d5d6fb2ba 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -158,6 +158,7 @@ export class DocumentOptions {
     _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
     latitude?: NUMt = new NumInfo('latitude coordinate for map views');
     longitude?: NUMt = new NumInfo('longitude coordinate for map views');
+    map?: STRt = new StrInfo('text location of map');
     _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)');
     _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden');
     _width?: NUMt = new NumInfo('displayed width of a document');
@@ -295,8 +296,9 @@ export class DocumentOptions {
 
     config_latitude?: NUMt = new NumInfo('latitude of a map'); // latitude of a map
     config_longitude?: NUMt = new NumInfo('longitude of map'); // longitude of map
-    config_mapZoom?: NUMt = new NumInfo('zoom of map'); // zoom of map
-    config_mapType?: string;
+    config_map_zoom?: NUMt = new NumInfo('zoom of map'); // zoom of map
+    config_map_type?: string;
+    config_map?: string;
     config_panX?: NUMt = new NumInfo('panX saved as a view spec');
     config_panY?: NUMt = new NumInfo('panY saved as a view spec');
     config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec');
@@ -527,7 +529,7 @@ export namespace Docs {
                 DocumentType.MAP,
                 {
                     layout: { view: MapBox, dataField: defaultDataKey },
-                    options: { _height: 600, _width: 800, nativeDimModifiable: true, systemIcon: 'BsFillPinMapFill' },
+                    options: { map: '', _height: 600, _width: 800, nativeDimModifiable: true, systemIcon: 'BsFillPinMapFill' },
                 },
             ],
             [
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 62d622fd6..94944b83d 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,19 +1,14 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { GoogleMapProps, Marker } from '@react-google-maps/api';
 import BingMapsReact from 'bingmaps-react';
 import { Button, EditableText, IconButton, Type } from 'browndash-components';
-import { docs_v1 } from 'googleapis';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { TbHeartMinus } from 'react-icons/tb';
 import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
 import { Highlight, Width } from '../../../../fields/DocSymbols';
-import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
-import { ScriptField } from '../../../../fields/ScriptField';
 import { DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
@@ -24,9 +19,8 @@ import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
 import { MarqueeAnnotator } from '../../MarqueeAnnotator';
-import { Annotation } from '../../pdf/Annotation';
 import { SidebarAnnos } from '../../SidebarAnnos';
-import { DocumentView, OpenWhere } from '../DocumentView';
+import { DocumentView } from '../DocumentView';
 import { FieldView, FieldViewProps } from '../FieldView';
 import { PinProps, PresBox } from '../trails';
 import { MapAnchorMenu } from './MapAnchorMenu';
@@ -45,29 +39,8 @@ import './MapBox.scss';
  * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps
  */
 
-// const _global = (window /* browser */ || global /* node */) as any;
-
-const mapContainerStyle = {
-    height: '100%',
-};
-
-const defaultCenter = {
-    lat: 42.360081,
-    lng: -71.058884,
-};
-
-const mapOptions = {
-    fullscreenControl: false,
-};
-
 const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing Maps api key here: https://www.bingmapsportal.com/  and then add it to the .env file in the Dash-Web root directory as: _CLIENT_BING_MAPS=<your apikey>
 
-// const script = document.createElement('script');
-// script.defer = true;
-// script.async = true;
-// script.src = `https://maps.googleapis.com/maps/api/js?key=${bingApiKey}&libraries=places,drawing`;
-// document.head.appendChild(script);
-
 /**
  * Consider integrating later: allows for drawing, circling, making shapes on map
  */
@@ -85,169 +58,49 @@ const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing
 // });
 
 @observer
-export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>>() {
-    private _dropDisposer?: DragManager.DragDropDisposer;
-    private _disposers: { [name: string]: IReactionDisposer } = {};
-    private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
-    @observable private _overlayAnnoInfo: Opt<Doc>;
-    showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
+export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
     public static LayoutString(fieldKey: string) {
         return FieldView.LayoutString(MapBox, fieldKey);
     }
-    public get SidebarKey() {
-        return this.fieldKey + '_sidebar';
-    }
+    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+    private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+    private _sidebarRef = React.createRef<SidebarAnnos>();
+    private _ref: React.RefObject<HTMLDivElement> = React.createRef();
+    private _disposers: { [key: string]: IReactionDisposer } = {};
     private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
-    @computed get inlineTextAnnotations() {
-        return this.allMapMarkers.filter(a => a.text_inlineAnnotations);
-    }
 
-    @observable private _map: google.maps.Map = null as unknown as google.maps.Map;
-    @observable private selectedPlace: Doc | undefined;
-    @observable private markerMap: { [id: string]: google.maps.Marker } = {};
-    @observable private center = navigator.geolocation ? navigator.geolocation.getCurrentPosition : defaultCenter;
     @observable private _marqueeing: number[] | undefined;
-    @observable private inputRef = React.createRef<HTMLInputElement>();
-    @observable private searchMarkers: google.maps.Marker[] = [];
-    @observable private searchBox = undefined as any; //  new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
     @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+    @computed get inlineTextAnnotations() {
+        return this.allMapMarkers.filter(a => a.text_inlineAnnotations);
+    }
     @computed get allSidebarDocs() {
         return DocListCast(this.dataDoc[this.SidebarKey]);
     }
     @computed get allMapMarkers() {
         return DocListCast(this.dataDoc[this.annotationKey]);
     }
-    @observable private toggleAddMarker = false;
-    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
-
     @computed get SidebarShown() {
         return this.layoutDoc._layout_showSidebar ? true : false;
     }
+    @computed get sidebarWidthPercent() {
+        return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
+    }
+    @computed get sidebarColor() {
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+    }
+    @computed get SidebarKey() {
+        return this.fieldKey + '_sidebar';
+    }
 
-    static _canAnnotate = true;
-    static _hadSelection: boolean = false;
-    private _sidebarRef = React.createRef<SidebarAnnos>();
-    private _ref: React.RefObject<HTMLDivElement> = React.createRef();
-    private _disposer: { [key: string]: IReactionDisposer } = {};
     componentDidMount() {
         this.props.setContentView?.(this);
     }
 
     componentWillUnmount(): void {
         this.deselectPin();
-        Object.keys(this._disposer).forEach(key => this._disposer[key]?.());
+        Object.keys(this._disposers).forEach(key => this._disposers[key]?.());
     }
-    // iterate allMarkers to size, center, and zoom map to contain all markers
-    private fitBounds = (map: google.maps.Map) => {
-        const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds();
-        const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean);
-        !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds()));
-    };
-
-    /**
-     * Load and render all map markers
-     * @param marker
-     * @param place
-     */
-    @action
-    private markerLoadHandler = (marker: google.maps.Marker, place: Doc) => {
-        place[Id] ? (this.markerMap[place[Id]] = marker) : null;
-    };
-
-    /**
-     * on clicking the map marker, set the selected place to the marker document & set infowindowopen to be true
-     * @param e
-     * @param place
-     */
-    @action
-    private markerClickHandler = (e: google.maps.MapMouseEvent, place: Doc) => {
-        // set which place was clicked
-        this.selectedPlace = place;
-        // place.infoWindowOpen = true;
-    };
-
-    /**
-     * Place the marker on google maps & store the empty marker as a MapMarker Document in allMarkers list
-     * @param position - the LatLng position where the marker is placed
-     * @param map
-     */
-    @action
-    private placeMarker = (position: google.maps.LatLng, map: google.maps.Map) => {
-        const marker = new google.maps.Marker({
-            position: position,
-            map: map,
-        });
-        map.panTo(position);
-        const mapMarker = Docs.Create.PushpinDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
-        this.addDocument(mapMarker, this.annotationKey);
-    };
-
-    _loadPending = true;
-
-    @action
-    centered = () => {
-        if (this._loadPending && this._map.getBounds()) {
-            this._loadPending = false;
-            this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
-        }
-        this.dataDoc.mapLat = this._map.getCenter()?.lat();
-        this.dataDoc.mapLng = this._map.getCenter()?.lng();
-    };
-
-    @action
-    zoomChanged = () => {
-        if (this._loadPending && this._map.getBounds()) {
-            this._loadPending = false;
-            this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
-        }
-        this.dataDoc.mapZoom = this._map.getZoom();
-    };
-
-    /**
-     * function that reads the place inputed from searchbox, then zoom in on the location that's been autocompleted;
-     * add a customized temporary marker on the map
-     */
-    @action
-    private handlePlaceChanged = () => {
-        const place = this.searchBox.getPlace();
-
-        if (!place.geometry || !place.geometry.location) {
-            // user entered the name of a place that wasn't suggested & pressed the enter key, or place details request failed
-            window.alert("No details available for input: '" + place.name + "'");
-            return;
-        }
-
-        // zoom in on the location of the search result
-        if (place.geometry.viewport) {
-            this._map.fitBounds(place.geometry.viewport);
-        } else {
-            this._map.setCenter(place.geometry.location);
-            this._map.setZoom(17);
-        }
-
-        // customize icon => customized icon for the nature of the location selected
-        const icon = {
-            url: place.icon as string,
-            size: new google.maps.Size(71, 71),
-            origin: new google.maps.Point(0, 0),
-            anchor: new google.maps.Point(17, 34),
-            scaledSize: new google.maps.Size(25, 25),
-        };
-
-        // put temporary cutomized marker on searched location
-        this.searchMarkers.forEach(marker => {
-            marker.setMap(null);
-        });
-        this.searchMarkers = [];
-        this.searchMarkers.push(
-            new window.google.maps.Marker({
-                map: this._map,
-                icon,
-                title: place.name,
-                position: place.geometry.location,
-            })
-        );
-    };
 
     /**
      * Called when dragging documents into map sidebar or directly into infowindow; to create a map marker, ref to MapMarkerDocument in Documents.ts
@@ -256,7 +109,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * @returns
      */
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
-        console.log('print all sidebar Docs');
         if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
         const docs = doc instanceof Doc ? [doc] : doc;
         docs.forEach(doc => {
@@ -280,11 +132,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * @param sidebarKey
      * @returns
      */
-    sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
-        // if (this.layoutDoc._layout_showSidebar) this.toggleSidebar();
-        const docs = doc instanceof Doc ? [doc] : doc;
-        return this.removeDocument(doc, sidebarKey);
-    };
+    sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => this.removeDocument(doc, sidebarKey);
 
     /**
      * Toggle sidebar onclick the tiny comment button on the top right corner
@@ -317,14 +165,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map')
         );
     };
-
-    sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
-    @computed get layout_sidebarWidthPercent() {
-        return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
-    }
-    @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
-    }
+    sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
 
     /**
      * Handles toggle of sidebar on click the little comment button
@@ -349,27 +190,27 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     // TODO: Adding highlight box layer to Maps
     @action
     toggleSidebar = () => {
-        //1.2 * w * ? = .2 * w      .2/1.2
         const prevWidth = this.sidebarWidth();
         this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
         this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
     };
 
     createNoteAnnotation = () => {
-        !this.layoutDoc.layout_showSidebar && this.toggleSidebar();
-
-        setTimeout(
-            undoable(
-                action(() => {
-                    const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false));
-                    if (note && this.selectedPin) {
-                        note.latitude = this.selectedPin.latitude;
-                        note.longitude = this.selectedPin.latitude;
-                    }
-                }),
-                'create note annotation'
-            )
+        const createFunc = undoable(
+            action(() => {
+                const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false));
+                if (note && this.selectedPin) {
+                    note.latitude = this.selectedPin.latitude;
+                    note.longitude = this.selectedPin.longitude;
+                    note.map = this.selectedPin.map;
+                }
+            }),
+            'create note annotation'
         );
+        if (!this.layoutDoc.layout_showSidebar) {
+            this.toggleSidebar();
+            setTimeout(createFunc);
+        } else createFunc();
     };
     sidebarDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
@@ -406,37 +247,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false);
     };
 
-    addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => {
-        return this.addDocument(doc, annotationKey);
-    };
+    addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => this.addDocument(doc, annotationKey);
 
     pointerEvents = () => (this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none');
 
-    @computed get annotationLayer() {
-        return (
-            <div className="mapBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
-                {this.inlineTextAnnotations
-                    .sort((a, b) => NumCast(a.y) - NumCast(b.y))
-                    .map(anno => (
-                        <Annotation key={`${anno[Id]}-annotation`} {...this.props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} />
-                    ))}
-            </div>
-        );
-    }
-
-    // Old get anchor function
-    // getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc;
-
-    /**
-     * render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker
-     * @returns
-     */
-    private renderMarkers = () => {
-        return this.allMapMarkers.map(place => (
-            <Marker key={place[Id]} position={{ lat: NumCast(place.lat), lng: NumCast(place.lng) }} onLoad={marker => this.markerLoadHandler(marker, place)} onClick={(e: google.maps.MapMouseEvent) => this.markerClickHandler(e, place)} />
-        ));
-    };
-
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
@@ -473,25 +287,15 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             } else {
                 this._bingSearchManager.geocode({
                     where: query,
-                    callback: action((r: any) => {
-                        res(r.results[0].location);
-                    }),
+                    callback: action((r: any) => res(r.results[0].location)),
                     errorCallback: (e: any) => reject(),
                 });
             }
         });
     };
 
-    /**
-     *
-     *
-     *  ERIC'S BING MAP CODE BELOW
-     *
-     *
-     *
-     **/
     @observable
-    bingSearchBarContents: any = 'enter city/zip/...'; // For Bing Maps: The contents of the Bing search bar (string)
+    bingSearchBarContents: any = this.rootDoc.map; // For Bing Maps: The contents of the Bing search bar (string)
 
     geoDataRequestOptions = {
         entityType: 'PopulatedPlace',
@@ -502,14 +306,14 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * Creates Pushpin doc and adds it to the list of annotations
      */
     @action
-    createPushpin = undoable((latitude: number, longitude: number) => {
+    createPushpin = undoable((latitude: number, longitude: number, map?: string) => {
         // Stores the pushpin as a MapMarkerDocument
         const mapMarker = Docs.Create.PushpinDocument(
             NumCast(latitude),
             NumCast(longitude),
             false,
             [],
-            {}
+            { map: map }
             // ,'pushpinIDamongus'+ this.incrementer++
         );
         this.addDocument(mapMarker, this.annotationKey);
@@ -517,18 +321,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         // mapMarker.infoWindowOpen = true;
     }, 'createpin');
 
-    /*
-     * Pushpin dblclick
-     */
-    // @action
-    // pushpinDblClicked = (pin: any, pinDoc?: Doc) => {
-    //     if (pinDoc) this.removePushpin(pinDoc);
-    //     else this._bingMap.current.entities.remove(pin);
-    // };
-
     // The pin that is selected
-    @observable
-    selectedPin: Doc | undefined;
+    @observable selectedPin: Doc | undefined;
 
     @action
     deselectPin = () => {
@@ -544,6 +338,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             this._bingMap.current.entities.push(newpin);
             this.map_docToPinMap.set(temp, newpin);
             this.selectedPin = undefined;
+            this.bingSearchBarContents = this.rootDoc.map;
         }
     };
 
@@ -558,9 +353,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     pushpinClicked = (pinDoc: Doc) => {
         this.deselectPin();
         this.selectedPin = pinDoc;
+        this.bingSearchBarContents = pinDoc.map;
 
         Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match');
-        Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.latitude, 'match');
+        Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match');
 
         this.recolorPin(this.selectedPin, 'green');
 
@@ -575,7 +371,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         MapAnchorMenu.Instance.jumpTo(cpt[0], cpt[1], true);
 
         document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
-        // Filter sidebar:
     };
 
     /**
@@ -589,54 +384,47 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * Map OnClick
      */
     @action
-    mapOnClick = (e: { location: { latitude: any; longitude: any } }) => this.deselectPin();
+    mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
+        this.props.select(false);
+        this.deselectPin();
+    };
     /*
      * Updates values of layout doc to match the current map
      */
     @action
-    updateLayout = () => {
-        this.dataDoc.latitude = this._bingMap.current.getCenter().latitude;
-        this.dataDoc.longitude = this._bingMap.current.getCenter().longitude;
-        this.dataDoc.mapZoom = this._bingMap.current.getZoom();
-        // if(this.dataDoc.mapType == 'x'){
-        //     this.dataDoc.locationToLookAt
-        // }
-        // this.dataDoc.mapType = new this.MicrosoftMaps.MapTypeId();
+    mapRecentered = () => {
+        if (
+            Math.abs(NumCast(this.dataDoc.latitude) - this._bingMap.current.getCenter().latitude) > 1e-7 || //
+            Math.abs(NumCast(this.dataDoc.longitude) - this._bingMap.current.getCenter().longitude) > 1e-7
+        ) {
+            this.dataDoc.latitude = this._bingMap.current.getCenter().latitude;
+            this.dataDoc.longitude = this._bingMap.current.getCenter().longitude;
+            this.dataDoc.map = '';
+            this.bingSearchBarContents = '';
+        }
+        this.dataDoc.map_zoom = this._bingMap.current.getZoom();
     };
     /*
      * Updates maptype
      */
     @action
-    updateMapType = () => {
-        this.dataDoc.mapType = this._bingMap.current.getMapTypeId();
-    };
+    updateMapType = () => (this.dataDoc.map_type = this._bingMap.current.getMapTypeId());
 
-    searched_pin: any;
     /*
      * For Bing Maps
      * Called by search button's onClick
      * Finds the geocode of the searched contents and sets location to that location
      **/
     @action
-    bingSearch = async () => {
-        const location = await this.bingGeocode(this._bingMap, this.bingSearchBarContents);
-        this.dataDoc.latitude = location.latitude;
-        this.dataDoc.longitude = location.longitude;
-        this.dataDoc.mapZoom = this._bingMap.current.getZoom();
-        // Creates a temporary pin but does not add it to the dataDoc
-        this.createPushpin(this.dataDoc.latitude, this.dataDoc.longitude);
+    bingSearch = () => {
+        return this.bingGeocode(this._bingMap, this.bingSearchBarContents).then(location => {
+            this.dataDoc.latitude = location.latitude;
+            this.dataDoc.longitude = location.longitude;
+            this.dataDoc.map_zoom = this._bingMap.current.getZoom();
+            this.dataDoc.map = this.bingSearchBarContents;
+        });
     };
 
-    /**
-     * Adds all pushpins in dataDoc onto the map (render) - OLD & UNUSED
-     */
-    // @action
-    // addAllPins = () => {
-    //     this._bingMap.current.entities.clear();
-    //     if (this.searched_pin) this._bingMap.current.entities.push(this.searched_pin);
-    //     // this.allMapPushpins.map(pin => this.addPushpin(pin));
-    // };
-
     /*
      * Returns doc w/ relevant info
      */
@@ -644,12 +432,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         /// this should use SELECTED pushpin for lat/long  if there is a selection, otherwise CENTER
         const anchor = Docs.Create.MapanchorDocument({
             title: 'MapAnchor:' + this.rootDoc.title,
+            text: StrCast(this.selectedPin?.map) || StrCast(this.rootDoc.map) || 'map location',
             config_latitude: NumCast(this.selectedPin?.latitude ?? this.dataDoc.latitude),
             config_longitude: NumCast(this.selectedPin?.longitude ?? this.dataDoc.longitude),
-            config_mapZoom: NumCast(this.dataDoc.mapZoom),
-            config_mapType: StrCast(this.dataDoc.mapType),
-            // preslocationToLookAt:this.dataDoc.locationToLookAt,
-            // presType:
+            config_map_zoom: NumCast(this.dataDoc.map_zoom),
+            config_map_type: StrCast(this.dataDoc.map_type),
+            config_map: StrCast(this.selectedPin?.map) || StrCast(this.dataDoc.map),
             layout_unrendered: true,
         });
         if (anchor) {
@@ -684,23 +472,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.map_docToPinMap.set(pin, pushPin);
     };
 
-    @observable
-    pinIsSelected_TEMPORARY: boolean = false; // toggles if remove pin button appears
-
     /*
      *   Input: pin doc
      *   Removes pin from annotations
      */
     @action
-    removePushpin = (pinDoc: Doc) => {
-        // this.allMapPushpins
-        // this.allMapPushpins.map(pin => this.addPushpin(pin));
-        // this._bingMap.current.entities.clear();
+    removePushpin = (pinDoc: Doc) => this.removeDocument(pinDoc, this.annotationKey);
 
-        this.removeDocument(pinDoc, this.annotationKey);
-
-        // this.dataDoc[this.annotationKey]
-    };
     /*
      * Removes pushpin from map render
      */
@@ -725,11 +503,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     tryHideMapAnchorMenu = (e: PointerEvent) => {
         let target = document.elementFromPoint(e.x, e.y);
-
-        while (target != null) {
-            if (target === MapAnchorMenu.top.current) {
-                return;
-            }
+        while (target) {
+            if (target === MapAnchorMenu.top.current) return;
             target = target.parentElement;
         }
         e.stopPropagation();
@@ -738,13 +513,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
     };
 
-    // tryhidemenu = e => if( e.parent... == mapanchormenu.top.currrent) do nothing; else hide menu
-
     @action
     centerOnSelectedPin = () => {
         if (this.selectedPin) {
             this.dataDoc.latitude = this.selectedPin.latitude;
             this.dataDoc.longitude = this.selectedPin.longitude;
+            this.dataDoc.map = this.selectedPin.map ?? '';
+            this.bingSearchBarContents = this.selectedPin.map;
         }
         MapAnchorMenu.Instance.fadeOut(true);
         document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu);
@@ -777,33 +552,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         },
     };
 
-    /**
-     * Toggles mode for placing a pin down on map
-     */
-    @observable
-    placePinOn = false;
-    @action
-    togglePlacePin = () => {
-        if (this.placePinOn) this.placePinOn = false;
-        else this.placePinOn = true;
-    };
-
     @action
-    searchbarOnEdit = (newText: string) => {
-        this.bingSearchBarContents = newText;
-    };
+    searchbarOnEdit = (newText: string) => (this.bingSearchBarContents = newText);
 
     recolorPin = (pin: Doc, color?: string) => {
         this._bingMap.current.entities.remove(this.map_docToPinMap.get(pin));
         this.map_docToPinMap.delete(pin);
-        const newpin = new this.MicrosoftMaps.Pushpin(
-            new this.MicrosoftMaps.Location(pin.latitude, pin.longitude),
-            color
-                ? {
-                      color,
-                  }
-                : {}
-        );
+        const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.latitude, pin.longitude), color ? { color } : {});
         this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(pin));
         this._bingMap.current.entities.push(newpin);
         this.map_docToPinMap.set(pin, newpin);
@@ -822,29 +577,36 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             alert('NO Map!?');
         }
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
-        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.updateLayout, 'Map Layout Change'));
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.mapRecentered, 'Map Layout Change'));
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change'));
-        this.updateLayout();
-        this._disposer.highlight = reaction(
+
+        this._disposers.mapLocation = reaction(
+            () => this.rootDoc.map,
+            mapLoc => (this.bingSearchBarContents = mapLoc),
+            { fireImmediately: true }
+        );
+        this._disposers.highlight = reaction(
             () => this.allMapPushpins.map(doc => doc[Highlight]),
-            () =>
-                this.allMapPushpins
-                    .map(doc => ({ doc, pushpin: DocCast(doc.mapPin) }))
-                    .filter(pair => pair.pushpin)
-                    .forEach(({ doc, pushpin }) => {
-                        if (doc[Highlight] && !this.map_pinHighlighted.get(pushpin)) {
-                            this.recolorPin(pushpin, 'orange');
-                            this.map_pinHighlighted.set(pushpin, true);
-                        } else if (!pushpin[Highlight] && this.map_pinHighlighted.get(pushpin)) {
-                            this.recolorPin(pushpin);
-                            this.map_pinHighlighted.delete(pushpin);
-                        }
-                    }),
+            () => {
+                const allPins = this.allMapPushpins.map(doc => ({ doc, pushpin: DocCast(doc.mapPin) })).filter(pair => pair.pushpin);
+                allPins.forEach(({ doc, pushpin }) => {
+                    if (!pushpin[Highlight] && this.map_pinHighlighted.get(pushpin)) {
+                        this.recolorPin(pushpin);
+                        this.map_pinHighlighted.delete(pushpin);
+                    }
+                });
+                allPins.forEach(({ doc, pushpin }) => {
+                    if (doc[Highlight] && !this.map_pinHighlighted.get(pushpin)) {
+                        this.recolorPin(pushpin, 'orange');
+                        this.map_pinHighlighted.set(pushpin, true);
+                    }
+                });
+            },
             { fireImmediately: true }
         );
-        // this.updateMapType();
-        this._disposer.location = reaction(
-            () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.mapZoom, mapType: this.rootDoc.mapType }),
+
+        this._disposers.location = reaction(
+            () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.map_zoom, mapType: this.rootDoc.map_type }),
             locationObject => {
                 // if (this._bingMap.current)
                 try {
@@ -862,43 +624,50 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
     };
 
-    // Keeps track of when dragging a pin onto map
-    draggingPin = false;
     dragToggle = (e: React.PointerEvent) => {
-        // console.log('DRAGGING TOGGLE');
-        document.addEventListener('drop', this.dropPin, true);
-        document.addEventListener('pointermove', this.pinMove, true);
-        e.stopPropagation();
-    };
-    pinMove = (e: PointerEvent) => {
-        // console.log('MOVING');
-        e.stopPropagation();
-    };
-    dropPin = (e: DragEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
-        document.removeEventListener('drop', this.dropPin, true);
-        document.removeEventListener('pointermove', this.pinMove, true);
-        let target = document.elementFromPoint(e.x, e.y);
+        let dragClone: HTMLDivElement | undefined;
 
-        while (target != null) {
-            if (target === this._ref.current) {
-                const cpt = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
-                const x = cpt[0] - (this.props.PanelWidth() - this.sidebarWidth()) / 2;
-                const y = cpt[1] - 32 /* height of search bar */ - this.props.PanelHeight() / 2;
-                const location = this._bingMap.current.tryPixelToLocation(new this.MicrosoftMaps.Point(x, y));
-                this.createPushpin(location.latitude, location.longitude);
-                break;
+        setupMoveUpEvents(
+            e,
+            e,
+            e => {
+                if (!dragClone) {
+                    dragClone = this._dragRef.current?.cloneNode(true) as HTMLDivElement;
+                    dragClone.style.position = 'absolute';
+                    dragClone.style.zIndex = '10000';
+                    DragManager.Root().appendChild(dragClone);
+                }
+                dragClone.style.transform = `translate(${e.clientX - 15}px, ${e.clientY - 15}px)`;
+                return false;
+            },
+            e => {
+                if (!dragClone) return;
+                DragManager.Root().removeChild(dragClone);
+                let target = document.elementFromPoint(e.x, e.y);
+                while (target) {
+                    if (target === this._ref.current) {
+                        const cpt = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
+                        const x = cpt[0] - (this.props.PanelWidth() - this.sidebarWidth()) / 2;
+                        const y = cpt[1] - 32 /* height of search bar */ - this.props.PanelHeight() / 2;
+                        const location = this._bingMap.current.tryPixelToLocation(new this.MicrosoftMaps.Point(x, y));
+                        this.createPushpin(location.latitude, location.longitude);
+                        break;
+                    }
+                    target = target.parentElement;
+                }
+            },
+            e => {
+                const createPin = () => this.createPushpin(this.rootDoc.latitude, this.rootDoc.longitude, this.rootDoc.map);
+                if (this.bingSearchBarContents) {
+                    this.bingSearch().then(createPin);
+                } else createPin();
             }
-            target = target.parentElement;
-        }
+        );
     };
 
-    searchbarKeyDown = (e: any) => {
-        if (e.key === 'Enter') {
-            this.bingSearch();
-        }
-    };
+    searchbarKeyDown = (e: any) => e.key === 'Enter' && this.bingSearch();
+
+    _dragRef = React.createRef<HTMLDivElement>();
     render() {
         const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
@@ -908,26 +677,18 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     onWheel={e => e.stopPropagation()}
                     onPointerDown={async e => {
                         e.button === 0 && !e.ctrlKey && e.stopPropagation();
-                        // just a simple test of bing maps geocode api
-                        // const loc = await this.bingGeocode(this._bingMap, 'Philadelphia, PA');
-                        // this._bingMap.current.setView({
-                        //     mapTypeId: this.MicrosoftMaps.MapTypeId.aerial,
-                        //     center: new this.MicrosoftMaps.Location(loc.latitude, loc.longitude),
-                        //     zoom: 15,
-                        // });
                     }}
-                    style={{ width: `calc(100% - ${this.layout_sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
+                    style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
                     <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
                     {renderAnnotations(this.opaqueFilter)}
                     {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
-                    {this.annotationLayer}
 
                     <div className="mapBox-searchbar">
                         <EditableText
                             // editing
                             setVal={(newText: string | number) => typeof newText === 'string' && this.searchbarOnEdit(newText)}
                             onEnter={e => this.bingSearch()}
-                            placeholder={this.bingSearchBarContents}
+                            placeholder={this.bingSearchBarContents || 'enter city/zip/...'}
                             textAlign="center"
                         />
                         <IconButton
@@ -939,41 +700,34 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                                 </svg>
                             }
                             onClick={this.bingSearch}
-                            onDoubleClick={function noRefCheck() {}}
-                            onPointerDown={function noRefCheck() {}}
-                            onPointerDownCapture={function noRefCheck() {}}
-                            onPointerMove={function noRefCheck() {}}
-                            onPointerMoveCapture={function noRefCheck() {}}
-                            onPointerUp={function noRefCheck() {}}
                             type={Type.TERT}
                         />
-                        <div draggable={true} style={{ width: 30, height: 30 }} onPointerDown={this.dragToggle}>
+                        <div style={{ width: 30, height: 30 }} ref={this._dragRef} onPointerDown={this.dragToggle}>
                             <Button tooltip="drag to place a pushpin" icon={<FontAwesomeIcon size={'lg'} icon={'bullseye'} />} />
                         </div>
                     </div>
 
                     <BingMapsReact
-                        onMapReady={this.bingMapReady}
+                        onMapReady={this.bingMapReady} //
                         bingMapsKey={bingApiKey}
                         height="100%"
                         mapOptions={this.bingMapOptions}
                         width="100%"
                         viewOptions={this.bingViewOptions}
-                        onPointerUp
-                        {...() => (this.draggingPin = false)}></BingMapsReact>
+                    />
                     <div>
                         {!this._mapReady
                             ? null
                             : this.allMapPushpins.map(pushpin => (
                                   <DocumentView
                                       {...this.props}
+                                      renderDepth={this.props.renderDepth + 1}
                                       Document={pushpin}
                                       DataDoc={undefined}
                                       PanelWidth={returnOne}
                                       PanelHeight={returnOne}
                                       NativeWidth={returnOne}
                                       NativeHeight={returnOne}
-                                      onClick={() => new ScriptField(undefined)}
                                       onKey={undefined}
                                       onDoubleClick={undefined}
                                       onBrowseClick={undefined}
@@ -983,7 +737,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                                       isDocumentActive={returnFalse}
                                       isContentActive={returnFalse}
                                       addDocTab={returnFalse}
-                                      ScreenToLocalTransform={() => new Transform(0, 0, 0)}
+                                      ScreenToLocalTransform={Transform.Identity}
                                       fitContentsToBox={undefined}
                                       focus={returnOne}
                                   />
@@ -1019,7 +773,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     )}
                 </div>
                 {/* </LoadScript > */}
-                <div className="mapBox-sidebar" style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+                <div className="mapBox-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
                     <SidebarAnnos
                         ref={this._sidebarRef}
                         {...this.props}
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index f42dec12c..a54bdcd5e 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -260,7 +260,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         // } else {
         //     alert("Your geolocation is not supported by browser.")
         // };
-        map.setZoom(NumCast(this.dataDoc.mapZoom, 2.5));
+        map.setZoom(NumCast(this.dataDoc.map_zoom, 2.5));
         map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng)));
         setTimeout(() => {
             if (this._loadPending && this._map.getBounds()) {
@@ -292,7 +292,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             this._loadPending = false;
             this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
         }
-        this.dataDoc.mapZoom = this._map.getZoom();
+        this.dataDoc.map_zoom = this._map.getZoom();
     };
 
     /**
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index afd9bccab..6ff22e929 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -471,12 +471,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 Doc.SetInPlace(bestTarget, 'longitude', NumCast(activeItem.config_longitude), true);
                 changed = true;
             }
-            if (bestTarget.zoom !== activeItem.config_mapZoom) {
-                Doc.SetInPlace(bestTarget, 'mapZoom', NumCast(activeItem.config_mapZoom), true);
+            if (bestTarget.zoom !== activeItem.config_map_zoom) {
+                Doc.SetInPlace(bestTarget, 'map_zoom', NumCast(activeItem.config_map_zoom), true);
                 changed = true;
             }
-            if (bestTarget.mapType !== activeItem.config_mapType) {
-                Doc.SetInPlace(bestTarget, 'mapType', StrCast(activeItem.config_mapType), true);
+            if (bestTarget.map_type !== activeItem.config_map_type) {
+                Doc.SetInPlace(bestTarget, 'map_type', StrCast(activeItem.config_map_type), true);
+                changed = true;
+            }
+            if (bestTarget.map !== activeItem.config_map) {
+                Doc.SetInPlace(bestTarget, 'map', StrCast(activeItem.config_map), true);
                 changed = true;
             }
         }
@@ -663,8 +667,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             if (pinProps.pinData.map) {
                 // pinDoc.config_latitude = targetDoc?.latitude;
                 // pinDoc.config_longitude = targetDoc?.longitude;
-                pinDoc.config_mapZoom = targetDoc?.mapZoom;
-                pinDoc.config_mapType = targetDoc?.mapType;
+                pinDoc.config_map_zoom = targetDoc?.map_zoom;
+                pinDoc.config_map_type = targetDoc?.map_type;
                 //...
             }
             if (pinProps.pinData.poslayoutview)
-- 
cgit v1.2.3-70-g09d2


From 9d6c7f8100de3a952d20ad41ab20872737cb909e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 27 Aug 2023 20:25:55 -0400
Subject: lots of cleanup to streamline import orderings (ie packages should
 not mutually import each other directly or via a chain).  change
 raiseWhenDragged to be keepZWhenDragged and got rid of system wide default.

---
 src/Utils.ts                                       |   2 +-
 src/client/DocServer.ts                            |  15 ++-
 src/client/apis/youtube/YoutubeBox.tsx             |   6 +-
 src/client/documents/Documents.ts                  |  10 +-
 src/client/util/CurrentUserUtils.ts                |  11 +-
 src/client/util/DictationManager.ts                |   2 +-
 src/client/util/DocumentManager.ts                 |  22 +++-
 src/client/util/DragManager.ts                     |  21 +---
 src/client/util/DropConverter.ts                   |  14 +--
 src/client/util/GroupManager.tsx                   |   4 +-
 src/client/util/GroupMemberView.tsx                |   2 +-
 src/client/util/SearchUtil.ts                      | 104 ++++++++++++++-
 src/client/util/SettingsManager.tsx                |  89 ++++++-------
 src/client/util/SharingManager.tsx                 |  10 +-
 src/client/util/reportManager/ReportManager.tsx    |   4 +-
 src/client/views/ContextMenuItem.tsx               |   6 +-
 src/client/views/DocumentDecorations.tsx           |  11 +-
 src/client/views/EditableView.tsx                  |   1 -
 src/client/views/FilterPanel.tsx                   |  23 ++--
 src/client/views/LightboxView.tsx                  |  11 +-
 src/client/views/Main.tsx                          |   6 +-
 src/client/views/MainView.tsx                      |  38 +++---
 src/client/views/PropertiesView.tsx                |  20 +--
 src/client/views/SidebarAnnos.tsx                  |   4 +-
 src/client/views/StyleProvider.tsx                 |  15 ++-
 src/client/views/UndoStack.tsx                     |   2 +-
 .../views/collections/CollectionDockingView.tsx    |   4 +-
 src/client/views/collections/CollectionMenu.tsx    |   2 +-
 .../collections/CollectionStackedTimeline.tsx      |   4 +-
 src/client/views/collections/TabDocView.tsx        |  13 +-
 src/client/views/collections/TreeSort.ts           |   6 +
 src/client/views/collections/TreeView.tsx          |  11 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   4 +-
 src/client/views/linking/LinkPopup.tsx             |   3 +-
 .../views/newlightbox/ButtonMenu/ButtonMenu.tsx    |  19 ++-
 src/client/views/newlightbox/NewLightboxView.tsx   | 139 ++++++++++-----------
 src/client/views/nodes/DocumentView.tsx            |  16 ++-
 src/client/views/nodes/FontIconBox/FontIconBox.tsx |  17 +--
 src/client/views/nodes/LinkDocPreview.tsx          |   6 +-
 src/client/views/nodes/LoadingBox.tsx              |   6 +-
 src/client/views/nodes/ScreenshotBox.tsx           |   6 +-
 src/client/views/nodes/VideoBox.tsx                |   5 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  24 ++--
 .../views/nodes/generativeFill/GenerativeFill.tsx  |  33 +++--
 src/client/views/nodes/trails/PresBox.tsx          |   4 +-
 src/client/views/pdf/AnchorMenu.tsx                |  15 +--
 src/client/views/search/IconBar.tsx                |  28 +++--
 src/client/views/search/SearchBox.tsx              | 110 +---------------
 src/client/views/topbar/TopBar.tsx                 |  16 ++-
 src/client/views/webcam/DashWebRTCVideo.tsx        |   6 +-
 src/fields/Doc.ts                                  |  26 +++-
 src/fields/RichTextUtils.ts                        |  10 +-
 52 files changed, 492 insertions(+), 494 deletions(-)
 create mode 100644 src/client/views/collections/TreeSort.ts

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 7f83ab8f5..9a94694a2 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -3,10 +3,10 @@ import v5 = require('uuid/v5');
 import { ColorState } from 'react-color';
 import * as rp from 'request-promise';
 import { Socket } from 'socket.io';
+import { DocumentType } from './client/documents/DocumentTypes';
 import { Colors } from './client/views/global/globalEnums';
 import { Message } from './server/Message';
 import Color = require('color');
-import { DocumentType } from './client/documents/DocumentTypes';
 
 export namespace Utils {
     export let CLICK_TIME = 300;
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 53c7b857a..5fdea131b 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,6 +1,5 @@
 import { runInAction } from 'mobx';
 import * as rp from 'request-promise';
-import * as io from 'socket.io-client';
 import { Doc, DocListCast, Opt } from '../fields/Doc';
 import { UpdatingFromServer } from '../fields/DocSymbols';
 import { FieldLoader } from '../fields/FieldLoader';
@@ -8,13 +7,13 @@ import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols';
 import { ObjectField } from '../fields/ObjectField';
 import { RefField } from '../fields/RefField';
 import { DocCast, StrCast } from '../fields/Types';
-import MobileInkOverlay from '../mobile/MobileInkOverlay';
+//import MobileInkOverlay from '../mobile/MobileInkOverlay';
 import { emptyFunction, Utils } from '../Utils';
 import { GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, YoutubeQueryTypes } from './../server/Message';
 import { DocumentType } from './documents/DocumentTypes';
 import { LinkManager } from './util/LinkManager';
 import { SerializationHelper } from './util/SerializationHelper';
-import { GestureOverlay } from './views/GestureOverlay';
+//import { GestureOverlay } from './views/GestureOverlay';
 
 /**
  * This class encapsulates the transfer and cross-client synchronization of
@@ -189,17 +188,17 @@ export namespace DocServer {
 
         // mobile ink overlay socket events to communicate between mobile view and desktop view
         _socket.addEventListener('receiveGesturePoints', (content: GestureContent) => {
-            MobileInkOverlay.Instance.drawStroke(content);
+            //   MobileInkOverlay.Instance.drawStroke(content);
         });
         _socket.addEventListener('receiveOverlayTrigger', (content: MobileInkOverlayContent) => {
-            GestureOverlay.Instance.enableMobileInkOverlay(content);
-            MobileInkOverlay.Instance.initMobileInkOverlay(content);
+            //GestureOverlay.Instance.enableMobileInkOverlay(content);
+            //    MobileInkOverlay.Instance.initMobileInkOverlay(content);
         });
         _socket.addEventListener('receiveUpdateOverlayPosition', (content: UpdateMobileInkOverlayPositionContent) => {
-            MobileInkOverlay.Instance.updatePosition(content);
+            //   MobileInkOverlay.Instance.updatePosition(content);
         });
         _socket.addEventListener('receiveMobileDocumentUpload', (content: MobileDocumentUploadContent) => {
-            MobileInkOverlay.Instance.uploadDocument(content);
+            //   MobileInkOverlay.Instance.uploadDocument(content);
         });
     }
 
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 05879a247..2da9927c0 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -6,7 +6,7 @@ import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { Utils } from '../../../Utils';
 import { DocServer } from '../../DocServer';
 import { Docs } from '../../documents/Documents';
-import { DocumentDecorations } from '../../views/DocumentDecorations';
+import { DocumentView } from '../../views/nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../../views/nodes/FieldView';
 import '../../views/nodes/WebBox.scss';
 import './YoutubeBox.scss';
@@ -355,9 +355,9 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
             </div>
         );
 
-        const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
+        const frozen = !this.props.isSelected() || DocumentView.Interacting;
 
-        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? '-interactive' : '');
+        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : '');
         return (
             <>
                 <div className={classname}>{content}</div>
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1186446e1..919958b24 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -19,7 +19,6 @@ import { aggregateBounds, OmitKeys, Utils } from '../../Utils';
 import { YoutubeBox } from '../apis/youtube/YoutubeBox';
 import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
-import { DocumentManager } from '../util/DocumentManager';
 import { DragManager, dropActionType } from '../util/DragManager';
 import { DirectoryImportBox } from '../util/Import & Export/DirectoryImportBox';
 import { FollowLinkScript } from '../util/LinkFollower';
@@ -34,12 +33,12 @@ import { ContextMenuProps } from '../views/ContextMenuItem';
 import { DFLT_IMAGE_NATIVE_DIM } from '../views/global/globalCssVariables.scss';
 import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
 import { AudioBox } from '../views/nodes/AudioBox';
-import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { ColorBox } from '../views/nodes/ColorBox';
 import { ComparisonBox } from '../views/nodes/ComparisonBox';
 import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox';
 import { EquationBox } from '../views/nodes/EquationBox';
 import { FieldViewProps } from '../views/nodes/FieldView';
+import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox';
 import { FunctionPlotBox } from '../views/nodes/FunctionPlotBox';
 import { ImageBox } from '../views/nodes/ImageBox';
@@ -394,7 +393,7 @@ export class DocumentOptions {
     onPointerUp?: ScriptField;
     _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
     _dragOnlyWithinContainer?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere');
-    _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.');
+    _keepZWhenDragged?: BOOLt = new BoolInfo('whether a document should keep its z-order when dragged.');
     childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged from the collection');
     dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
@@ -1371,7 +1370,7 @@ export namespace DocUtils {
     export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = [];
 
     export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) {
-        broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1));
+        broadcastEvent && runInAction(() => (Doc.RecordingEvent = Doc.RecordingEvent + 1));
         return DocUtils.ActiveRecordings.map(audio => {
             const sourceDoc = getSourceDoc();
             return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { link_displayLine: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
@@ -1380,7 +1379,6 @@ export namespace DocUtils {
 
     export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; link_displayLine?: boolean }, id?: string, showPopup?: number[]) {
         if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
-        const sv = DocumentManager.Instance.getDocumentView(source);
         if (target.doc === Doc.UserDoc()) return undefined;
 
         const makeLink = action((linkDoc: Doc, showPopup?: number[]) => {
@@ -1840,8 +1838,6 @@ export namespace DocUtils {
             }
             if (overwriteDoc) {
                 Doc.removeCurrentlyLoading(overwriteDoc);
-                // loading doc icons are just labels. so any icon views of loading docs need to be replaced with the proper icon view.
-                DocumentManager.Instance.getAllDocumentViews(overwriteDoc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()));
             }
             generatedDocuments.push(doc);
         }
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index ea995e4af..d52e389d6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -18,7 +18,6 @@ import { CollectionViewType, DocumentType } from "../documents/DocumentTypes";
 import { TreeViewType } from "../views/collections/CollectionTreeView";
 import { DashboardView } from "../views/DashboardView";
 import { Colors } from "../views/global/globalEnums";
-import { MainView } from "../views/MainView";
 import { OpenWhere } from "../views/nodes/DocumentView";
 import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox";
 import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox";
@@ -621,9 +620,9 @@ export class CurrentUserUtils {
 
     static freeTools(): Button[] {
         return [
-            { title: "Bottom",  icon: "arrows-down-to-line",toolTip: "Make doc topmost",                                   btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform
-            { title: "Top",     icon: "arrows-up-to-line",  toolTip: "Make doc bottommost",                                btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform
-            { title: "Z order", icon: "z",                  toolTip: "Bring Forward on Drag (double click to set for all)",waitForDoubleClickToClick:true, btnType: ButtonType.ToggleButton, expertMode: false, funcs: {}, scripts: { onClick: 'toggleRaiseOnDrag(false, _readOnly_)', onDoubleClick:`{ return toggleRaiseOnDrag(true, _readOnly_)`}}, // Only when floating document is selected in freeform
+            { title: "Bottom",  icon: "arrows-down-to-line",toolTip: "Make doc topmost",     btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform
+            { title: "Top",     icon: "arrows-up-to-line",  toolTip: "Make doc bottommost",  btnType: ButtonType.ClickButton,  expertMode: false, funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform
+            { title: "Z order", icon: "z",                  toolTip: "Keep Z order on Drag", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {}, scripts: { onClick: '{ return toggleRaiseOnDrag(_readOnly_);}'}}, // Only when floating document is selected in freeform
         ]
     }
     static viewTools(): Button[] {
@@ -841,7 +840,6 @@ export class CurrentUserUtils {
         doc.isSystem ?? (doc.isSystem = true);
         doc.title ?? (doc.title = Doc.CurrentUserEmail);
         Doc.noviceMode ?? (Doc.noviceMode = true);
-        doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true);
         doc._showLabel ?? (doc._showLabel = true);
         doc.textAlign ?? (doc.textAlign = "left");
         doc.activeTool = InkTool.None;
@@ -996,8 +994,5 @@ export class CurrentUserUtils {
 ScriptingGlobals.add(function MySharedDocs() { return Doc.MySharedDocs; }, "document containing all shared Docs");
 ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode");
 ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering");
-ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called");
-ScriptingGlobals.add(function openPresentation(pres:Doc) { return MainView.Instance.openPresentation(pres); }, "creates a new presentation when called");
-ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called");
 ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar");
 ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; });
\ No newline at end of file
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 717473aa1..0fd7e840c 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -11,7 +11,7 @@ import { Utils } from '../../Utils';
 import { Docs } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
 import { DictationOverlay } from '../views/DictationOverlay';
-import { DocumentView, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView';
+import { DocumentView, OpenWhere } from '../views/nodes/DocumentView';
 import { SelectionManager } from './SelectionManager';
 import { UndoManager } from './UndoManager';
 
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 5b627c2f3..c2827dac7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,4 +1,4 @@
-import { action, computed, observable, ObservableSet } from 'mobx';
+import { action, computed, observable, ObservableSet, observe, reaction } from 'mobx';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
 import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
@@ -23,7 +23,6 @@ export class DocumentManager {
     //global holds all of the nodes (regardless of which collection they're in)
     @observable _documentViews = new Set<DocumentView>();
     @observable public LinkAnchorBoxViews: DocumentView[] = [];
-    @observable public RecordingEvent = 0;
     @observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = [];
     @computed public get DocumentViews() {
         return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath)));
@@ -41,7 +40,22 @@ export class DocumentManager {
     }
 
     //private constructor so no other class can create a nodemanager
-    private constructor() {}
+    private constructor() {
+        if (!Doc.CurrentlyLoading) Doc.CurrentlyLoading = [];
+        observe(Doc.CurrentlyLoading, change => {
+            // watch CurrentlyLoading-- when something is loaded, it's removed from the list and we have to update its icon if it were iconified since LoadingBox icons are different than the media they become
+            switch (change.type as any) {
+                case 'update':
+                    break;
+                case 'remove':
+                    // DocumentManager.Instance.getAllDocumentViews(change as any).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()));
+                    break;
+                case 'splice':
+                    (change as any).removed.forEach((doc: Doc) => DocumentManager.Instance.getAllDocumentViews(doc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify())));
+                    break;
+            }
+        });
+    }
 
     private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = [];
     public AddViewRenderedCb = (doc: Opt<Doc>, func: (dv: DocumentView) => any) => {
@@ -310,7 +324,7 @@ export class DocumentManager {
         if (viewSpec && docView) {
             if (docView.ComponentView instanceof FormattedTextBox) docView.ComponentView?.focus(viewSpec, options);
             PresBox.restoreTargetDocView(docView, viewSpec, options.zoomTime ?? 500);
-            Doc.linkFollowHighlight(viewSpec ? [docView.rootDoc, viewSpec]: docView.rootDoc, undefined, options.effect);
+            Doc.linkFollowHighlight(viewSpec ? [docView.rootDoc, viewSpec] : docView.rootDoc, undefined, options.effect);
             if (options.playAudio) DocumentManager.playAudioAnno(docView.rootDoc);
             if (options.toggleTarget && (!options.didMove || docView.rootDoc.hidden)) docView.rootDoc.hidden = !docView.rootDoc.hidden;
             if (options.effect) docView.rootDoc[Animation] = options.effect;
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 489c9df4a..05da5ebed 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -61,12 +61,6 @@ export namespace DragManager {
     export let StartWindowDrag: Opt<(e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void>;
     export let CompleteWindowDrag: Opt<(aborted: boolean) => void>;
 
-    export function GetRaiseWhenDragged() {
-        return BoolCast(Doc.UserDoc()._raiseWhenDragged);
-    }
-    export function SetRaiseWhenDragged(val: boolean) {
-        Doc.UserDoc()._raiseWhenDragged = val;
-    }
     export function Root() {
         const root = document.getElementById('root');
         if (!root) {
@@ -605,18 +599,9 @@ export namespace DragManager {
     }
 }
 
-ScriptingGlobals.add(function toggleRaiseOnDrag(forAllDocs: boolean, readOnly?: boolean) {
+ScriptingGlobals.add(function toggleRaiseOnDrag(readOnly?: boolean) {
     if (readOnly) {
-        if (SelectionManager.Views().length)
-            return SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged)
-                ? Colors.MEDIUM_BLUE
-                : SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged === false)
-                ? 'transparent'
-                : DragManager.GetRaiseWhenDragged()
-                ? Colors.MEDIUM_BLUE_ALT
-                : Colors.LIGHT_BLUE;
-        return DragManager.GetRaiseWhenDragged() ? Colors.MEDIUM_BLUE_ALT : 'transparent';
+        return SelectionManager.Views().some(dv => dv.rootDoc.keepZWhenDragged);
     }
-    if (!forAllDocs) SelectionManager.Views().map(dv => (dv.rootDoc.raiseWhenDragged ? (dv.rootDoc.raiseWhenDragged = undefined) : dv.rootDoc.raiseWhenDragged === false ? (dv.rootDoc.raiseWhenDragged = true) : (dv.rootDoc.raiseWhenDragged = false)));
-    else DragManager.SetRaiseWhenDragged(!DragManager.GetRaiseWhenDragged());
+    SelectionManager.Views().map(dv => (dv.rootDoc.keepZWhenDragged = !dv.rootDoc.keepZWhenDragged));
 });
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index f235be192..dbdf580cd 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -1,15 +1,15 @@
-import { DragManager } from './DragManager';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { DocumentType } from '../documents/DocumentTypes';
 import { ObjectField } from '../../fields/ObjectField';
-import { StrCast, Cast } from '../../fields/Types';
-import { Docs } from '../documents/Documents';
-import { ScriptField, ComputedField } from '../../fields/ScriptField';
 import { RichTextField } from '../../fields/RichTextField';
-import { ImageField } from '../../fields/URLField';
-import { ScriptingGlobals } from './ScriptingGlobals';
 import { listSpec } from '../../fields/Schema';
+import { ScriptField } from '../../fields/ScriptField';
+import { Cast, StrCast } from '../../fields/Types';
+import { ImageField } from '../../fields/URLField';
+import { Docs } from '../documents/Documents';
+import { DocumentType } from '../documents/DocumentTypes';
 import { ButtonType } from '../views/nodes/FontIconBox/FontIconBox';
+import { DragManager } from './DragManager';
+import { ScriptingGlobals } from './ScriptingGlobals';
 
 export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = undefined, templateField: string = '') {
     if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index c79894032..8973306bf 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -282,7 +282,7 @@ export class GroupManager extends React.Component<{}> {
      */
     private get groupCreationModal() {
         const contents = (
-            <div className="group-create" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+            <div className="group-create" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                 <div className="group-heading" style={{ marginBottom: 0 }}>
                     <p>
                         <b>New Group</b>
@@ -367,7 +367,7 @@ export class GroupManager extends React.Component<{}> {
         const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups;
 
         return (
-            <div className="group-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+            <div className="group-interface" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                 {this.groupCreationModal}
                 {this.currentGroup ? <GroupMemberView group={this.currentGroup} onCloseButtonClick={action(() => (this.currentGroup = undefined))} /> : null}
                 <div className="group-heading">
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx
index 535d8ccc2..7de0f336f 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -29,7 +29,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> {
         const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group);
 
         return !this.props.group ? null : (
-            <div className="editing-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+            <div className="editing-interface" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                 <div className="editing-header">
                     <input
                         className="group-title"
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index d154c48a4..64aa7ba9b 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -1,13 +1,115 @@
 import * as rp from 'request-promise';
 import { DocServer } from '../DocServer';
-import { Doc } from '../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { Utils } from '../../Utils';
 import { DocumentType } from '../documents/DocumentTypes';
+import { StrCast } from '../../fields/Types';
 
 export namespace SearchUtil {
     export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
 
+    export function SearchCollection(rootDoc: Opt<Doc>, query: string) {
+        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
+        const blockedKeys = [
+            'x',
+            'y',
+            'proto',
+            'width',
+            'layout_autoHeight',
+            'acl-Override',
+            'acl-Guest',
+            'embedContainer',
+            'zIndex',
+            'height',
+            'text_scrollHeight',
+            'text_height',
+            'cloneFieldFilter',
+            'isDataDoc',
+            'text_annotations',
+            'dragFactory_count',
+            'text_noTemplate',
+            'proto_embeddings',
+            'isSystem',
+            'layout_fieldKey',
+            'isBaseProto',
+            'xMargin',
+            'yMargin',
+            'links',
+            'layout',
+            'layout_keyValue',
+            'layout_fitWidth',
+            'type_collection',
+            'title_custom',
+            'freeform_panX',
+            'freeform_panY',
+            'freeform_scale',
+        ];
+        query = query.toLowerCase();
+
+        const results = new Map<Doc, string[]>();
+        if (rootDoc) {
+            const docs = DocListCast(rootDoc[Doc.LayoutFieldKey(rootDoc)]);
+            const docIDs: String[] = [];
+            SearchUtil.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
+                const dtype = StrCast(doc.type) as DocumentType;
+                if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) {
+                    const hlights = new Set<string>();
+                    SearchUtil.documentKeys(doc).forEach(
+                        key =>
+                            Field.toString(doc[key] as Field)
+                                .toLowerCase()
+                                .includes(query) && hlights.add(key)
+                    );
+                    blockedKeys.forEach(key => hlights.delete(key));
+
+                    if (Array.from(hlights.keys()).length > 0) {
+                        results.set(doc, Array.from(hlights.keys()));
+                    }
+                }
+                docIDs.push(doc[Id]);
+            });
+        }
+        return results;
+    }
+    /**
+     * @param {Doc} doc - doc for which keys are returned
+     *
+     * This method returns a list of a document doc's keys.
+     */
+    export function documentKeys(doc: Doc) {
+        const keys: { [key: string]: boolean } = {};
+        Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)));
+        return Array.from(Object.keys(keys));
+    }
+
+    /**
+     * @param {Doc[]} docs - docs to be searched through recursively
+     * @param {number, Doc => void} func - function to be called on each doc
+     *
+     * This method iterates through an array of docs and all docs within those docs, calling
+     * the function func on each doc.
+     */
+    export function foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) {
+        let newarray: Doc[] = [];
+        var depth = 0;
+        const visited: Doc[] = [];
+        while (docs.length > 0) {
+            newarray = [];
+            docs.filter(d => d && !visited.includes(d)).forEach(d => {
+                visited.push(d);
+                const fieldKey = Doc.LayoutFieldKey(d);
+                const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
+                const data = d[annos ? fieldKey + '_annotations' : fieldKey];
+                data && newarray.push(...DocListCast(data));
+                const sidebar = d[fieldKey + '_sidebar'];
+                sidebar && newarray.push(...DocListCast(sidebar));
+                func(depth, d);
+            });
+            docs = newarray;
+            depth++;
+        }
+    }
     export interface IdSearchResult {
         ids: string[];
         lines: string[][];
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index bb370e1a4..720badd40 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -13,7 +13,6 @@ import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager
 import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
 import { MainViewModal } from '../views/MainViewModal';
-import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
 import { GroupManager } from './GroupManager';
 import './SettingsManager.scss';
 import { undoBatch } from './UndoManager';
@@ -67,15 +66,15 @@ export class SettingsManager extends React.Component<{}> {
         }
     };
 
-    @computed get userColor() {
+    @computed public static get userColor() {
         return StrCast(Doc.UserDoc().userColor);
     }
 
-    @computed get userVariantColor() {
+    @computed public static get userVariantColor() {
         return StrCast(Doc.UserDoc().userVariantColor);
     }
 
-    @computed get userBackgroundColor() {
+    @computed public static get userBackgroundColor() {
         return StrCast(Doc.UserDoc().userBackgroundColor);
     }
 
@@ -150,35 +149,35 @@ export class SettingsManager extends React.Component<{}> {
                         val: scheme,
                     }))}
                     dropdownType={DropdownType.SELECT}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                     fillWidth
                 />
                 {userTheme === ColorScheme.Custom && (
                     <Group formLabel="Custom Theme">
                         <ColorPicker
                             tooltip={'User Color'} //
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             type={Type.SEC}
                             icon={<FaFillDrip />}
-                            selectedColor={this.userColor}
+                            selectedColor={SettingsManager.userColor}
                             setSelectedColor={this.switchUserColor}
                             setFinalColor={this.switchUserColor}
                         />
                         <ColorPicker
                             tooltip={'User Background Color'}
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             type={Type.SEC}
                             icon={<FaPalette />}
-                            selectedColor={this.userBackgroundColor}
+                            selectedColor={SettingsManager.userBackgroundColor}
                             setSelectedColor={this.switchUserBackgroundColor}
                             setFinalColor={this.switchUserBackgroundColor}
                         />
                         <ColorPicker
                             tooltip={'User Variant Color'}
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             type={Type.SEC}
                             icon={<FaPalette />}
-                            selectedColor={this.userVariantColor}
+                            selectedColor={SettingsManager.userVariantColor}
                             setSelectedColor={this.switchUserVariantColor}
                             setFinalColor={this.switchUserVariantColor}
                         />
@@ -198,7 +197,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'author_date')}
                     toggleStatus={Doc.UserDoc().layout_showTitle !== undefined}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Show Full Toolbar'}
@@ -207,25 +206,25 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc()['documentLinksButton-fullMenu'] = !Doc.UserDoc()['documentLinksButton-fullMenu'])}
                     toggleStatus={BoolCast(Doc.UserDoc()['documentLinksButton-fullMenu'])}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Show Button Labels'}
                     formLabelPlacement={'right'}
                     toggleType={ToggleType.SWITCH}
-                    onClick={e => FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())}
-                    toggleStatus={FontIconBox.GetShowLabels()}
+                    onClick={e => Doc.SetShowIconLabels(!Doc.GetShowIconLabels())}
+                    toggleStatus={Doc.GetShowIconLabels()}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Recognize Ink Gestures'}
                     formLabelPlacement={'right'}
                     toggleType={ToggleType.SWITCH}
-                    onClick={e => FontIconBox.SetRecognizeGestures(!FontIconBox.GetRecognizeGestures())}
-                    toggleStatus={FontIconBox.GetRecognizeGestures()}
+                    onClick={e => Doc.SetRecognizeGestures(!Doc.GetRecognizeGestures())}
+                    toggleStatus={Doc.GetRecognizeGestures()}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Hide Labels In Ink Shapes'}
@@ -234,7 +233,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().activeInkHideTextLabels = !Doc.UserDoc().activeInkHideTextLabels)}
                     toggleStatus={BoolCast(Doc.UserDoc().activeInkHideTextLabels)}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Open Ink Docs in Lightbox'}
@@ -243,7 +242,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().openInkInLightbox = !Doc.UserDoc().openInkInLightbox)}
                     toggleStatus={BoolCast(Doc.UserDoc().openInkInLightbox)}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
                 <Toggle
                     formLabel={'Show Link Lines'}
@@ -252,7 +251,7 @@ export class SettingsManager extends React.Component<{}> {
                     onClick={e => (Doc.UserDoc().showLinkLines = !Doc.UserDoc().showLinkLines)}
                     toggleStatus={BoolCast(Doc.UserDoc().showLinkLines)}
                     size={Size.XSMALL}
-                    color={this.userColor}
+                    color={SettingsManager.userColor}
                 />
             </div>
         );
@@ -284,7 +283,7 @@ export class SettingsManager extends React.Component<{}> {
                     <div className="tab-column-content">
                         {/* <NumberInput/> */}
                         <Group formLabel={'Default Font'}>
-                            <NumberDropdown color={this.userColor} numberDropdownType={'input'} min={0} max={50} step={2} type={Type.TERT} number={0} unit={'px'} setNumber={() => {}} />
+                            <NumberDropdown color={SettingsManager.userColor} numberDropdownType={'input'} min={0} max={50} step={2} type={Type.TERT} number={0} unit={'px'} setNumber={() => {}} />
                             <Dropdown
                                 items={fontFamilies.map(val => {
                                     return {
@@ -301,7 +300,7 @@ export class SettingsManager extends React.Component<{}> {
                                 setSelectedVal={val => {
                                     this.changeFontFamily(val as string);
                                 }}
-                                color={this.userColor}
+                                color={SettingsManager.userColor}
                                 fillWidth
                             />
                         </Group>
@@ -329,12 +328,12 @@ export class SettingsManager extends React.Component<{}> {
     @computed get passwordContent() {
         return (
             <div className="password-content">
-                <EditableText placeholder="Current password" type={Type.SEC} color={this.userColor} val={''} setVal={val => this.changeVal(val as string, 'curr')} fillWidth password />
-                <EditableText placeholder="New password" type={Type.SEC} color={this.userColor} val={''} setVal={val => this.changeVal(val as string, 'new')} fillWidth password />
-                <EditableText placeholder="Confirm new password" type={Type.SEC} color={this.userColor} val={''} setVal={val => this.changeVal(val as string, 'conf')} fillWidth password />
+                <EditableText placeholder="Current password" type={Type.SEC} color={SettingsManager.userColor} val={''} setVal={val => this.changeVal(val as string, 'curr')} fillWidth password />
+                <EditableText placeholder="New password" type={Type.SEC} color={SettingsManager.userColor} val={''} setVal={val => this.changeVal(val as string, 'new')} fillWidth password />
+                <EditableText placeholder="Confirm new password" type={Type.SEC} color={SettingsManager.userColor} val={''} setVal={val => this.changeVal(val as string, 'conf')} fillWidth password />
                 {!this.passwordResultText ? null : <div className={`${this.passwordResultText.startsWith('Error') ? 'error' : 'success'}-text`}>{this.passwordResultText}</div>}
-                <Button type={Type.SEC} text={'Forgot Password'} color={this.userColor} />
-                <Button type={Type.TERT} text={'Submit'} onClick={this.changePassword} color={this.userColor} />
+                <Button type={Type.SEC} text={'Forgot Password'} color={SettingsManager.userColor} />
+                <Button type={Type.TERT} text={'Submit'} onClick={this.changePassword} color={SettingsManager.userColor} />
             </div>
         );
     }
@@ -394,10 +393,10 @@ export class SettingsManager extends React.Component<{}> {
                             dropdownType={DropdownType.SELECT}
                             type={Type.TERT}
                             placement="bottom-start"
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                             fillWidth
                         />
-                        <Toggle formLabel={'Playground Mode'} toggleType={ToggleType.SWITCH} toggleStatus={this.playgroundMode} onClick={this.playgroundModeToggle} color={this.userColor} />
+                        <Toggle formLabel={'Playground Mode'} toggleType={ToggleType.SWITCH} toggleStatus={this.playgroundMode} onClick={this.playgroundModeToggle} color={SettingsManager.userColor} />
                     </div>
                     <div className="tab-column-title" style={{ marginTop: 20, marginBottom: 10 }}>
                         Freeform Navigation
@@ -422,15 +421,21 @@ export class SettingsManager extends React.Component<{}> {
                             dropdownType={DropdownType.SELECT}
                             type={Type.TERT}
                             placement="bottom-start"
-                            color={this.userColor}
+                            color={SettingsManager.userColor}
                         />
                     </div>
                 </div>
                 <div className="tab-column">
                     <div className="tab-column-title">Permissions</div>
                     <div className="tab-column-content">
-                        <Button text={'Manage Groups'} type={Type.TERT} onClick={() => GroupManager.Instance?.open()} color={this.userColor} />
-                        <Toggle toggleType={ToggleType.SWITCH} formLabel={'Default access private'} color={this.userColor} toggleStatus={BoolCast(Doc.defaultAclPrivate)} onClick={action(() => (Doc.defaultAclPrivate = !Doc.defaultAclPrivate))} />
+                        <Button text={'Manage Groups'} type={Type.TERT} onClick={() => GroupManager.Instance?.open()} color={SettingsManager.userColor} />
+                        <Toggle
+                            toggleType={ToggleType.SWITCH}
+                            formLabel={'Default access private'}
+                            color={SettingsManager.userColor}
+                            toggleStatus={BoolCast(Doc.defaultAclPrivate)}
+                            onClick={action(() => (Doc.defaultAclPrivate = !Doc.defaultAclPrivate))}
+                        />
                     </div>
                 </div>
             </div>
@@ -449,7 +454,7 @@ export class SettingsManager extends React.Component<{}> {
         ];
         return (
             <div className="settings-interface">
-                <div className="settings-panel" style={{ background: this.userColor }}>
+                <div className="settings-panel" style={{ background: SettingsManager.userColor }}>
                     <div className="settings-tabs">
                         {tabs.map(tab => {
                             const isActive = this.activeTab === tab.title;
@@ -457,8 +462,8 @@ export class SettingsManager extends React.Component<{}> {
                                 <div
                                     key={tab.title}
                                     style={{
-                                        background: isActive ? this.userBackgroundColor : this.userColor,
-                                        color: isActive ? this.userColor : this.userBackgroundColor,
+                                        background: isActive ? SettingsManager.userBackgroundColor : SettingsManager.userColor,
+                                        color: isActive ? SettingsManager.userColor : SettingsManager.userBackgroundColor,
                                     }}
                                     className={'tab-control ' + (isActive ? 'active' : 'inactive')}
                                     onClick={action(() => (this.activeTab = tab.title))}>
@@ -469,19 +474,19 @@ export class SettingsManager extends React.Component<{}> {
                     </div>
 
                     <div className="settings-user">
-                        <div style={{ color: this.userBackgroundColor }}>{DashVersion}</div>
-                        <div className="settings-username" style={{ color: this.userBackgroundColor }}>
+                        <div style={{ color: SettingsManager.userBackgroundColor }}>{DashVersion}</div>
+                        <div className="settings-username" style={{ color: SettingsManager.userBackgroundColor }}>
                             {Doc.CurrentUserEmail}
                         </div>
-                        <Button text={Doc.GuestDashboard ? 'Exit' : 'Log Out'} type={Type.TERT} color={this.userVariantColor} onClick={() => window.location.assign(Utils.prepend('/logout'))} />
+                        <Button text={Doc.GuestDashboard ? 'Exit' : 'Log Out'} type={Type.TERT} color={SettingsManager.userVariantColor} onClick={() => window.location.assign(Utils.prepend('/logout'))} />
                     </div>
                 </div>
 
                 <div className="close-button">
-                    <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={this.close} color={this.userColor} />
+                    <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={this.close} color={SettingsManager.userColor} />
                 </div>
 
-                <div className="settings-content" style={{ color: this.userColor, background: this.userBackgroundColor }}>
+                <div className="settings-content" style={{ color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}>
                     {tabs.map(tab => (
                         <div key={tab.title} className={'tab-section ' + (this.activeTab === tab.title ? 'active' : 'inactive')}>
                             {tab.ele}
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 81ddeb9e3..9a9097bf7 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -18,10 +18,10 @@ import { DictationOverlay } from '../views/DictationOverlay';
 import { MainViewModal } from '../views/MainViewModal';
 import { DocumentView } from '../views/nodes/DocumentView';
 import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
-import { SearchBox } from '../views/search/SearchBox';
 import { DocumentManager } from './DocumentManager';
 import { GroupManager, UserOptions } from './GroupManager';
 import { GroupMemberView } from './GroupMemberView';
+import { SearchUtil } from './SearchUtil';
 import { SelectionManager } from './SelectionManager';
 import { SettingsManager } from './SettingsManager';
 import './SharingManager.scss';
@@ -446,7 +446,7 @@ export class SharingManager extends React.Component<{}> {
 
         if (this.myDocAcls) {
             const newDocs: Doc[] = [];
-            SearchBox.foreachRecursiveDoc(docs, (depth, doc) => newDocs.push(doc));
+            SearchUtil.foreachRecursiveDoc(docs, (depth, doc) => newDocs.push(doc));
             docs = newDocs.filter(doc => GetEffectiveAcl(doc) === AclAdmin);
         }
 
@@ -527,10 +527,10 @@ export class SharingManager extends React.Component<{}> {
             const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
 
             return !permissions ? null : (
-                <div key={groupKey} className={'container'} style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
+                <div key={groupKey} className={'container'} style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
                     <div className={'padding'}>{StrCast(group.title)}</div>
                     &nbsp;
-                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.Instance.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
+                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
                     <div className={'edit-actions'}>
                         {admin || this.myDocAcls ? (
                             <select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}>
@@ -552,7 +552,7 @@ export class SharingManager extends React.Component<{}> {
                 <div
                     className="sharing-contents"
                     style={{
-                        background: SettingsManager.Instance.userBackgroundColor,
+                        background: SettingsManager.userBackgroundColor,
                         color: StrCast(Doc.UserDoc().userColor),
                     }}>
                     <p className="share-title" style={{ color: StrCast(Doc.UserDoc().userColor) }}>
diff --git a/src/client/util/reportManager/ReportManager.tsx b/src/client/util/reportManager/ReportManager.tsx
index 3cd2d47a0..6a236face 100644
--- a/src/client/util/reportManager/ReportManager.tsx
+++ b/src/client/util/reportManager/ReportManager.tsx
@@ -211,11 +211,11 @@ export class ReportManager extends React.Component<{}> {
      * @returns the component that dispays all issues
      */
     private viewIssuesComponent = () => {
-        const darkMode = isDarkMode(SettingsManager.Instance.userBackgroundColor);
+        const darkMode = isDarkMode(SettingsManager.userBackgroundColor);
         const colors = darkMode ? darkColors : lightColors;
 
         return (
-            <div className="view-issues" style={{ backgroundColor: SettingsManager.Instance.userBackgroundColor, color: colors.text }}>
+            <div className="view-issues" style={{ backgroundColor: SettingsManager.userBackgroundColor, color: colors.text }}>
                 <div className="left" style={{ display: this.rightExpanded ? 'none' : 'flex' }}>
                     <div className="report-header">
                         <h2 style={{ color: colors.text }}>Open Issues</h2>
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index b53379435..c2cbca3e1 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -96,7 +96,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     <div
                         className={`contextMenu-item-background`}
                         style={{
-                            background: SettingsManager.Instance.userColor,
+                            background: SettingsManager.userColor,
                         }}
                     />
                 </div>
@@ -112,7 +112,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     style={{
                         marginLeft: window.innerHeight - this._overPosX - 50 > 0 ? '90%' : '20%',
                         marginTop,
-                        background: SettingsManager.Instance.userBackgroundColor,
+                        background: SettingsManager.userBackgroundColor,
                     }}>
                     {this._items.map(prop => (
                         <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />
@@ -146,7 +146,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     <div
                         className={`contextMenu-item-background`}
                         style={{
-                            background: SettingsManager.Instance.userColor,
+                            background: SettingsManager.userColor,
                         }}
                     />
                     {submenu}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 90425f264..3018dad79 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -57,7 +57,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @observable private _editingTitle = false;
     @observable private _hidden = false;
     @observable public AddToSelection = false; // if Shift is pressed, then this should be set so that clicking on the selection background is ignored so overlapped documents can be added to the selection set.
-    @observable public Interacting = false;
     @observable public pushIcon: IconProp = 'arrow-alt-circle-up';
     @observable public pullIcon: IconProp = 'arrow-alt-circle-down';
     @observable public pullColor: string = 'white';
@@ -330,7 +329,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
      */
     @action
     onRadiusDown = (e: React.PointerEvent): void => {
-        this._isRounding = DocumentDecorations.Instance.Interacting = true;
+        this._isRounding = DocumentView.Interacting = true;
         this._resizeUndo = UndoManager.StartBatch('DocDecs set radius');
         // Call util move event function
         setupMoveUpEvents(
@@ -353,7 +352,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 return false;
             }, // moveEvent
             action(e => {
-                DocumentDecorations.Instance.Interacting = this._isRounding = false;
+                DocumentView.Interacting = this._isRounding = false;
                 this._resizeUndo?.end();
             }), // upEvent
             e => {}, // clickEvent,
@@ -478,7 +477,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @action
     onPointerDown = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
-        this.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
+        DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
         this._resizeHdlId = e.currentTarget.className;
         const bounds = e.currentTarget.getBoundingClientRect();
         this._offX = this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX;
@@ -688,7 +687,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @action
     onPointerUp = (e: PointerEvent): void => {
         this._resizeHdlId = '';
-        this.Interacting = false;
+        DocumentView.Interacting = false;
         this._resizeUndo?.end();
         SnappingManager.clearSnapLines();
 
@@ -895,7 +894,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                         height: bounds.b - bounds.y + this._resizeBorderWidth + 'px',
                         left: bounds.x - this._resizeBorderWidth / 2,
                         top: bounds.y - this._resizeBorderWidth / 2,
-                        pointerEvents: DocumentDecorations.Instance.AddToSelection || this.Interacting ? 'none' : 'all',
+                        pointerEvents: DocumentDecorations.Instance.AddToSelection || DocumentView.Interacting ? 'none' : 'all',
                         display: SelectionManager.Views().length <= 1 || hideDecorations ? 'none' : undefined,
                     }}
                     onPointerDown={this.onBackgroundDown}
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index d60617020..147921596 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -6,7 +6,6 @@ import { ObjectField } from '../../fields/ObjectField';
 import './EditableView.scss';
 import { DocumentIconContainer } from './nodes/DocumentIcon';
 import { OverlayView } from './OverlayView';
-import { EditableText } from 'browndash-components';
 
 export interface EditableProps {
     /**
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 11c2fc86c..b61ff35c7 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -1,23 +1,20 @@
 import React = require('react');
 import { action, computed, observable, ObservableMap } from 'mobx';
 import { observer } from 'mobx-react';
+import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider';
+import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai';
+import { CiCircleRemove } from 'react-icons/ci';
 import Select from 'react-select';
-import { Checkbox, Tooltip } from '@material-ui/core';
 import { Doc, DocListCast, Field, StrListCast } from '../../fields/Doc';
 import { RichTextField } from '../../fields/RichTextField';
-import { StrCast } from '../../fields/Types';
+import { DocumentOptions, FInfo } from '../documents/Documents';
 import { DocumentManager } from '../util/DocumentManager';
 import { UserOptions } from '../util/GroupManager';
+import { SearchUtil } from '../util/SearchUtil';
+import { undoable } from '../util/UndoManager';
 import './FilterPanel.scss';
 import { FieldView } from './nodes/FieldView';
-import { SearchBox } from './search/SearchBox';
-import { undoable } from '../util/UndoManager';
-import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai';
-import { CiCircleRemove } from 'react-icons/ci';
-import { Slider, Rail, Handles, Tracks, Ticks } from 'react-compound-slider';
-import { TooltipRail, Handle, Tick, Track } from './nodes/SliderBox-components';
-import { DocumentOptions, FInfo } from '../documents/Documents';
-import { string32 } from 'pdfjs-dist/types/src/shared/util';
+import { Handle, Tick, TooltipRail, Track } from './nodes/SliderBox-components';
 
 interface filterProps {
     rootDoc: Doc;
@@ -49,7 +46,7 @@ export class FilterPanel extends React.Component<filterProps> {
         const allDocs = new Set<Doc>();
         const targetDoc = this.targetDoc;
         if (targetDoc) {
-            SearchBox.foreachRecursiveDoc([this.targetDoc], (depth, doc) => allDocs.add(doc));
+            SearchUtil.foreachRecursiveDoc([this.targetDoc], (depth, doc) => allDocs.add(doc));
         }
         console.log('this is all Docs' + Array.from(allDocs));
         return Array.from(allDocs);
@@ -62,7 +59,7 @@ export class FilterPanel extends React.Component<filterProps> {
         const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
 
         const keys = new Set<string>(noviceFields);
-        this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key)));
+        this.allDocs.forEach(doc => SearchUtil.documentKeys(doc).filter(key => keys.add(key)));
         const sortedKeys = Array.from(keys.keys())
             .filter(key => key[0])
             .filter(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode)
@@ -236,7 +233,7 @@ export class FilterPanel extends React.Component<filterProps> {
 
     facetValues = (facetHeader: string) => {
         const allCollectionDocs = new Set<Doc>();
-        SearchBox.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
+        SearchUtil.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
         const set = new Set<string>([String.fromCharCode(127) + '--undefined--']);
         if (facetHeader === 'tags')
             allCollectionDocs.forEach(child =>
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index afb76b9ac..8f081b321 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -16,7 +16,6 @@ import { CollectionStackedTimeline } from './collections/CollectionStackedTimeli
 import { TabDocView } from './collections/TabDocView';
 import { GestureOverlay } from './GestureOverlay';
 import './LightboxView.scss';
-import { MainView } from './MainView';
 import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
 import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider';
 
@@ -61,7 +60,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             this._childFilters && (this._childFilters.length = 0);
             this._future = this._history = [];
             Doc.ActiveTool = InkTool.None;
-            MainView.Instance._exploreMode = false;
+            DocumentView.ExploreMode = false;
         } else {
             const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement();
             l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
@@ -270,7 +269,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             addDocTab={this.addDocTab}
                             pinToPres={TabDocView.PinDoc}
                             bringToFront={emptyFunction}
-                            onBrowseClick={MainView.Instance.exploreMode}
+                            onBrowseClick={DocumentView.exploreMode}
                             focus={emptyFunction}
                         />
                     </GestureOverlay>
@@ -335,12 +334,12 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                 <div
                     className="lightboxView-exploreBtn"
                     title="toggle explore mode to navigate among documents only"
-                    style={{ background: MainView.Instance._exploreMode ? 'white' : undefined }}
+                    style={{ background: DocumentView.ExploreMode ? 'white' : undefined }}
                     onClick={action(e => {
                         e.stopPropagation();
-                        MainView.Instance._exploreMode = !MainView.Instance._exploreMode;
+                        DocumentView.ExploreMode = !DocumentView.ExploreMode;
                     })}>
-                    <FontAwesomeIcon color={MainView.Instance._exploreMode ? 'black' : 'white'} icon={'globe-americas'} size="2x" />
+                    <FontAwesomeIcon color={DocumentView.ExploreMode ? 'black' : 'white'} icon={'globe-americas'} size="2x" />
                 </div>
             </div>
         );
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6dd1d53ee..a04309d0c 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -2,18 +2,18 @@
 //     (module as any).hot.accept();
 // }
 
+import * as dotenv from 'dotenv'; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
 import * as React from 'react';
 import * as ReactDOM from 'react-dom/client';
 import { AssignAllExtensions } from '../../extensions/General/Extensions';
 import { FieldLoader } from '../../fields/FieldLoader';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
+import { PingManager } from '../util/PingManager';
 import { ReplayMovements } from '../util/ReplayMovements';
 import { TrackMovements } from '../util/TrackMovements';
 import { CollectionView } from './collections/CollectionView';
-import { MainView } from './MainView';
-import * as dotenv from 'dotenv'; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
-import { PingManager } from '../util/PingManager';
 import './global/globalScripts';
+import { MainView } from './MainView';
 dotenv.config();
 
 AssignAllExtensions();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6a743a5e6..dde04dcc0 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -9,7 +9,6 @@ import { observer } from 'mobx-react';
 import 'normalize.css';
 import * as React from 'react';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { ScriptField } from '../../fields/ScriptField';
 import { DocCast, StrCast } from '../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
@@ -77,7 +76,6 @@ export class MainView extends React.Component {
     public static Live: boolean = false;
     private _docBtnRef = React.createRef<HTMLDivElement>();
 
-    @observable public LastButton: Opt<Doc>;
     @observable private _windowWidth: number = 0;
     @observable private _windowHeight: number = 0;
     @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row)
@@ -529,7 +527,6 @@ export class MainView extends React.Component {
         window.addEventListener('beforeunload', DocServer.UPDATE_SERVER_CACHE);
         window.addEventListener('drop', e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page
         window.addEventListener('dragover', e => e.preventDefault(), false);
-        // document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined));
         document.addEventListener('pointerdown', this.globalPointerDown, true);
         document.addEventListener('pointermove', this.globalPointerMove, true);
         document.addEventListener('pointerup', this.globalPointerClick, true);
@@ -572,11 +569,7 @@ export class MainView extends React.Component {
         Doc.AddDocToList(Doc.MyFilesystem, 'data', folder);
     };
 
-    @observable _exploreMode = false;
-    @computed get exploreMode() {
-        return () => (this._exploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
-    }
-    waitForDoubleClick = () => (this._exploreMode ? 'never' : undefined);
+    waitForDoubleClick = () => (DocumentView.ExploreMode ? 'never' : undefined);
     headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1);
     mainScreenToLocalXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.topOfMainDocContent, 1);
     addHeaderDoc = (doc: Doc | Doc[], annotationKey?: string) => (doc instanceof Doc ? [doc] : doc).reduce((done, doc) => Doc.AddDocToList(this.headerBarDoc, 'data', doc), true);
@@ -747,7 +740,7 @@ export class MainView extends React.Component {
 
     @computed get leftMenuPanel() {
         return (
-            <div key="menu" className="mainView-leftMenuPanel" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), display: LightboxView.LightboxDoc ? 'none' : undefined }}>
+            <div key="menu" className="mainView-leftMenuPanel" style={{ background: SettingsManager.userBackgroundColor, display: LightboxView.LightboxDoc ? 'none' : undefined }}>
                 <DocumentView
                     Document={Doc.MyLeftSidebarMenu}
                     DataDoc={undefined}
@@ -804,16 +797,16 @@ export class MainView extends React.Component {
                     {this.flyout}
                     <div
                         className="mainView-libraryHandle"
-                        style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), left: leftMenuFlyoutWidth - 10 /* ~half width of handle */, display: !this._leftMenuFlyoutWidth ? 'none' : undefined }}
+                        style={{ background: SettingsManager.userBackgroundColor, left: leftMenuFlyoutWidth - 10 /* ~half width of handle */, display: !this._leftMenuFlyoutWidth ? 'none' : undefined }}
                         onPointerDown={this.onFlyoutPointerDown}>
-                        <FontAwesomeIcon icon="chevron-left" color={StrCast(Doc.UserDoc().userColor)} style={{ opacity: '50%' }} size="sm" />
+                        <FontAwesomeIcon icon="chevron-left" color={SettingsManager.userColor} style={{ opacity: '50%' }} size="sm" />
                     </div>
                     <div className="mainView-innerContainer" style={{ width: `calc(100% - ${width}px)` }}>
                         {this.dockingContent}
 
                         {this._hideUI ? null : (
-                            <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), right: this.propertiesWidth() - 1 }}>
-                                <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={StrCast(Doc.UserDoc().userColor)} size="sm" />
+                            <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ background: SettingsManager.userBackgroundColor, right: this.propertiesWidth() - 1 }}>
+                                <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={SettingsManager.userColor} size="sm" />
                             </div>
                         )}
                         <div className="properties-container" style={{ width: this.propertiesWidth() }}>
@@ -857,11 +850,11 @@ export class MainView extends React.Component {
         //setTimeout(action(() => (this._leftMenuFlyoutWidth += 0.5)));
 
         this._sidebarContent.proto = DocCast(button.target);
-        this.LastButton = button;
+        DocumentView.LastPressedSidebarBtn = button;
     });
 
     closeFlyout = action(() => {
-        this.LastButton = undefined;
+        DocumentView.LastPressedSidebarBtn = undefined;
         this._panelContent = 'none';
         this._sidebarContent.proto = undefined;
         this._leftMenuFlyoutWidth = 0;
@@ -879,7 +872,7 @@ export class MainView extends React.Component {
 
     @computed get docButtons() {
         return !Doc.MyDockedBtns ? null : (
-            <div className="mainView-docButtons" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }} ref={this._docBtnRef}>
+            <div className="mainView-docButtons" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }} ref={this._docBtnRef}>
                 <CollectionLinearView
                     Document={Doc.MyDockedBtns}
                     DataDoc={undefined}
@@ -998,8 +991,8 @@ export class MainView extends React.Component {
             <div
                 className={`mainView-container ${this.colorScheme}`}
                 style={{
-                    color: StrCast(Doc.UserDoc().userColor),
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    color: SettingsManager.userColor,
+                    background: SettingsManager.userBackgroundColor,
                 }}
                 onScroll={() => (ele => (ele.scrollTop = ele.scrollLeft = 0))(document.getElementById('root')!)}
                 ref={r => {
@@ -1068,3 +1061,12 @@ export class MainView extends React.Component {
 ScriptingGlobals.add(function selectMainMenu(doc: Doc, title: string) {
     MainView.Instance.selectMenu(doc);
 });
+ScriptingGlobals.add(function createNewPresentation() {
+    return MainView.Instance.createNewPresentation();
+}, 'creates a new presentation when called');
+ScriptingGlobals.add(function openPresentation(pres: Doc) {
+    return MainView.Instance.openPresentation(pres);
+}, 'creates a new presentation when called');
+ScriptingGlobals.add(function createNewFolder() {
+    return MainView.Instance.createNewFolder();
+}, 'creates a new folder in myFiles when called');
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 4fe6847c3..83bd1b860 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -188,7 +188,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             });
 
             rows.push(
-                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: SettingsManager.Instance.userBackgroundColor, textAlign: 'center' }}>
+                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: SettingsManager.userBackgroundColor, textAlign: 'center' }}>
                     <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} />
                 </div>
             );
@@ -1664,7 +1664,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             <div className="propertiesView-title" style={{ width: this.props.width }}>
                                 Properties
                                 <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties')}>
-                                    <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.Instance.userColor} />
+                                    <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.userColor} />
                                 </div>
                             </div>
                         </div>
@@ -1706,8 +1706,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openPresTransitions ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openPresTransitions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
                                     <div className="propertiesView-presentationTrails-title-icon">
@@ -1723,8 +1723,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openPresVisibilityAndDuration ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openPresVisibilityAndDuration ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Visibilty
                                     <div className="propertiesView-presentationTrails-title-icon">
@@ -1740,8 +1740,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openPresProgressivize ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openPresProgressivize ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Progressivize
                                     <div className="propertiesView-presentationTrails-title-icon">
@@ -1757,8 +1757,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     className="propertiesView-presentationTrails-title"
                                     onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))}
                                     style={{
-                                        color: SettingsManager.Instance.userColor,
-                                        backgroundColor: this.openSlideOptions ? SettingsManager.Instance.userVariantColor : SettingsManager.Instance.userBackgroundColor,
+                                        color: SettingsManager.userColor,
+                                        backgroundColor: this.openSlideOptions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                                     }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
                                     <div className="propertiesView-presentationTrails-title-icon">
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index c48a7241a..f3452c780 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -9,11 +9,11 @@ import { emptyFunction, returnAll, returnFalse, returnOne, returnTrue, returnZer
 import { Docs, DocUtils } from '../documents/Documents';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { LinkManager } from '../util/LinkManager';
+import { SearchUtil } from '../util/SearchUtil';
 import { Transform } from '../util/Transform';
 import { CollectionStackingView } from './collections/CollectionStackingView';
 import { FieldViewProps } from './nodes/FieldView';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { SearchBox } from './search/SearchBox';
 import './SidebarAnnos.scss';
 import { StyleProp } from './StyleProvider';
 import React = require('react');
@@ -43,7 +43,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     @computed get allMetadata() {
         const keys = new Map<string, FieldResult<Field>>();
         DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc =>
-            SearchBox.documentKeys(doc)
+            SearchUtil.documentKeys(doc)
                 .filter(key => key[0] && key[0] !== '_' && key[0] === key[0].toUpperCase())
                 .map(key => keys.set(key, doc[key]))
         );
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 24a269927..12935400b 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -4,6 +4,7 @@ import { Tooltip } from '@material-ui/core';
 import { IconButton, Shadows, Size } from 'browndash-components';
 import { action, runInAction } from 'mobx';
 import { extname } from 'path';
+import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs';
 import { Doc, Opt, StrListCast } from '../../fields/Doc';
 import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types';
 import { DashColor, lightOrDark, Utils } from '../../Utils';
@@ -14,15 +15,13 @@ import { LinkManager } from '../util/LinkManager';
 import { SelectionManager } from '../util/SelectionManager';
 import { ColorScheme, SettingsManager } from '../util/SettingsManager';
 import { undoBatch, UndoManager } from '../util/UndoManager';
-import { TreeSort } from './collections/TreeView';
+import { TreeSort } from './collections/TreeSort';
 import { Colors } from './global/globalEnums';
 import { InkingStroke } from './InkingStroke';
-import { MainView } from './MainView';
-import { DocumentViewProps } from './nodes/DocumentView';
+import { DocumentView, DocumentViewProps } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
-import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs';
 import './StyleProvider.scss';
 import React = require('react');
 
@@ -159,7 +158,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ''
             );
         case StyleProp.Color:
-            if (MainView.Instance.LastButton === doc) return SettingsManager.Instance.userBackgroundColor;
+            if (DocumentView.LastPressedSidebarBtn === doc) return SettingsManager.userBackgroundColor;
             if (Doc.IsSystem(doc!)) return StrCast(Doc.UserDoc().userColor)
             if (doc?.type === DocumentType.FONTICON) return Doc.UserDoc().userColor;
             const docColor: Opt<string> = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color));
@@ -194,7 +193,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ? 15
                 : 0;
         case StyleProp.BackgroundColor: {
-            if (MainView.Instance.LastButton === doc) return StrCast(Doc.UserDoc().userColor); // hack to indicate active menu panel item
+            if (DocumentView.LastPressedSidebarBtn === doc) return StrCast(Doc.UserDoc().userColor); // hack to indicate active menu panel item
             let docColor: Opt<string> = StrCast(doc?.[fieldKey + '_backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
             // prettier-ignore
             switch (doc?.type) {
@@ -217,7 +216,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.COL:
                     if (StrCast(Doc.LayoutField(doc)).includes(SliderBox.name)) break;
                     docColor = docColor || (Doc.IsSystem(doc)
-                            ? SettingsManager.Instance.userBackgroundColor
+                            ? SettingsManager.userBackgroundColor
                             : doc.annotationOn
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?._isGroup
@@ -264,7 +263,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString;
             if (StrCast(doc?.pointerEvents) && !props?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc
             if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
-            if (MainView.Instance._exploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
+            if (DocumentView.ExploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
             if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
             if (props?.pointerEvents?.() === 'none') return 'none';
             if (opacity() === 0) return 'none';
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index a551e5332..3fd64d1fd 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -19,7 +19,7 @@ export class UndoStack extends React.Component<UndoStackProps> {
     @observable static HideInline: boolean;
     @observable static Expand: boolean;
     render() {
-        const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.Instance.userBackgroundColor;
+        const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userBackgroundColor;
         return this.props.inline && UndoStack.HideInline ? null : (
             <div className="undoStack-outerContainer">
                 <Popup
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index e15d57306..519b7c905 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
 import * as ReactDOM from 'react-dom/client';
 import * as GoldenLayout from '../../../client/goldenLayout';
 import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { AclAdmin, AclEdit } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -13,6 +14,7 @@ import { emptyFunction, incrementTitleCopy } from '../../../Utils';
 import { DocServer } from '../../DocServer';
 import { Docs } from '../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
 import { InteractionUtils } from '../../util/InteractionUtils';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
@@ -28,8 +30,6 @@ import './CollectionDockingView.scss';
 import { CollectionFreeFormView } from './collectionFreeForm';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
 import { TabDocView } from './TabDocView';
-import { DocumentManager } from '../../util/DocumentManager';
-import { AclAdmin, AclEdit } from '../../../fields/DocSymbols';
 import React = require('react');
 const _global = (window /* browser */ || global) /* node */ as any;
 
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index f65e8698f..5c9dd2058 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -181,7 +181,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
             <div
                 className="collectionMenu-container"
                 style={{
-                    background: SettingsManager.Instance.userBackgroundColor,
+                    background: SettingsManager.userBackgroundColor,
                     // borderColor: StrCast(Doc.UserDoc().userColor)
                 }}>
                 {this.contMenuButtons}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index de58e1fe7..d2be70577 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -2,12 +2,12 @@ import React = require('react');
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
-import { Doc, Opt, StrListCast } from '../../../fields/Doc';
+import { Doc, Opt } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
-import { Cast, NumCast, ScriptCast } from '../../../fields/Types';
+import { Cast, NumCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { emptyFunction, formatTime, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f379d09ff..f6acafa95 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -1,6 +1,6 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
+import { Popup, Type } from 'browndash-components';
 import { clamp } from 'lodash';
 import { action, computed, IReactionDisposer, observable, ObservableSet, reaction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -10,7 +10,7 @@ import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { FieldId } from '../../../fields/RefField';
-import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
 import { DocServer } from '../../DocServer';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
@@ -21,9 +21,8 @@ import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoable, UndoManager } from '../../util/UndoManager';
 import { DashboardView } from '../DashboardView';
-import { Colors, Shadows } from '../global/globalEnums';
+import { Colors } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
-import { MainView } from '../MainView';
 import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
 import { DashFieldView } from '../nodes/formattedText/DashFieldView';
 import { KeyValueBox } from '../nodes/KeyValueBox';
@@ -34,7 +33,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionView } from './CollectionView';
 import './TabDocView.scss';
 import React = require('react');
-import { Popup, Toggle, Type } from 'browndash-components';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 interface TabDocViewProps {
@@ -426,6 +424,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._type_collection !== CollectionViewType.Freeform;
     whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive);
     isContentActive = () => this._isContentActive;
+    waitForDoubleClick = () => (DocumentView.ExploreMode ? 'never' : undefined);
     @computed get docView() {
         return !this._activated || !this._document ? null : (
             <>
@@ -441,8 +440,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     hideTitle={this.props.keyValue}
                     Document={this._document}
                     DataDoc={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
-                    onBrowseClick={MainView.Instance.exploreMode}
-                    waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
+                    onBrowseClick={DocumentView.exploreMode}
+                    waitForDoubleClickToClick={this.waitForDoubleClick}
                     isContentActive={this.isContentActive}
                     isDocumentActive={returnFalse}
                     PanelWidth={this.PanelWidth}
diff --git a/src/client/views/collections/TreeSort.ts b/src/client/views/collections/TreeSort.ts
new file mode 100644
index 000000000..977acd030
--- /dev/null
+++ b/src/client/views/collections/TreeSort.ts
@@ -0,0 +1,6 @@
+export enum TreeSort {
+    AlphaUp = 'alphabetical from z',
+    AlphaDown = 'alphabetical from A',
+    Zindex = 'by Z index',
+    WhenAdded = 'when added',
+}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 3402a8c8d..701150769 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -35,6 +35,7 @@ import { CollectionView } from './CollectionView';
 import './TreeView.scss';
 import React = require('react');
 import { IconButton, Size } from 'browndash-components';
+import { TreeSort } from './TreeSort';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
@@ -77,12 +78,6 @@ const treeBulletWidth = function () {
     return Number(TREE_BULLET_WIDTH.replace('px', ''));
 };
 
-export enum TreeSort {
-    AlphaUp = 'alphabetical from z',
-    AlphaDown = 'alphabetical from A',
-    Zindex = 'by Z index',
-    WhenAdded = 'when added',
-}
 /**
  * Renders a treeView of a collection of documents
  *
@@ -578,7 +573,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             return (
                 <div>
                     {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : (
-                        <div className='treeView-sorting'>
+                        <div className="treeView-sorting">
                             <IconButton
                                 color={sortings[sorting]?.color}
                                 size={Size.XSMALL}
@@ -602,7 +597,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         style={{ cursor: 'inherit' }}
                         key={expandKey + 'more'}
                         title={`Sorted by : ${this.doc.treeView_SortCriterion}. click to cycle`}
-                        className='' //this.doc.treeView_HideTitle ? 'no-indent' : ''}
+                        className="" //this.doc.treeView_HideTitle ? 'no-indent' : ''}
                         onPointerDown={e => {
                             downX = e.clientX;
                             downY = e.clientY;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f5cc1eb53..16d6f1270 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -371,7 +371,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
             layoutDoc._width = NumCast(layoutDoc._width, 300);
             layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? (nd[1] / nd[0]) * NumCast(layoutDoc._width) : 300);
-            (d._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+            !d._keepZWhenDragged && (d.zIndex = zsorted.length + 1 + i); // bringToFront
         }
 
         if (this.layoutDoc._autoArrange || de.metaKey) {
@@ -1267,7 +1267,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     @computed get _pointerEvents() {
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
-        const pointerEvents = DocumentDecorations.Instance.Interacting
+        const pointerEvents = DocumentView.Interacting
             ? 'none'
             : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.());
         return pointerEvents;
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 6895c0746..9a9a89732 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -3,15 +3,14 @@ import { observer } from 'mobx-react';
 import { EditorView } from 'prosemirror-view';
 import { Doc } from '../../../fields/Doc';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils';
-import { DocUtils } from '../../documents/Documents';
 import { Transform } from '../../util/Transform';
 import { undoBatch } from '../../util/UndoManager';
+import { OpenWhere } from '../nodes/DocumentView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { SearchBox } from '../search/SearchBox';
 import { DefaultStyleProvider } from '../StyleProvider';
 import './LinkPopup.scss';
 import React = require('react');
-import { OpenWhere } from '../nodes/DocumentView';
 
 interface LinkPopupProps {
     linkFrom?: () => Doc | undefined;
diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
index ff17e5c12..3a95e5f74 100644
--- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
+++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
@@ -1,14 +1,13 @@
-import './ButtonMenu.scss';
+import { action } from 'mobx';
 import * as React from 'react';
-import { IButtonMenu } from './utils';
-import { NewLightboxView } from '../NewLightboxView';
-import { SelectionManager } from '../../../util/SelectionManager';
-import { CollectionDockingView } from '../../collections/CollectionDockingView';
-import { OpenWhereMod } from '../../nodes/DocumentView';
 import { Doc } from '../../../../fields/Doc';
 import { InkTool } from '../../../../fields/InkField';
-import { MainView } from '../../MainView';
-import { action } from 'mobx';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { CollectionDockingView } from '../../collections/CollectionDockingView';
+import { DocumentView, OpenWhereMod } from '../../nodes/DocumentView';
+import { NewLightboxView } from '../NewLightboxView';
+import './ButtonMenu.scss';
+import { IButtonMenu } from './utils';
 
 export const ButtonMenu = (props: IButtonMenu) => {
     return (
@@ -40,10 +39,10 @@ export const ButtonMenu = (props: IButtonMenu) => {
             <div
                 className="newLightboxView-exploreBtn"
                 title="toggle explore mode to navigate among documents only"
-                style={{ background: MainView.Instance._exploreMode ? 'white' : undefined }}
+                style={{ background: DocumentView.ExploreMode ? 'white' : undefined }}
                 onClick={action(e => {
                     e.stopPropagation();
-                    MainView.Instance._exploreMode = !MainView.Instance._exploreMode;
+                    DocumentView.ExploreMode = !DocumentView.ExploreMode;
                 })}></div>
         </div>
     );
diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx
index 3acbd1a32..ca90f6a0f 100644
--- a/src/client/views/newlightbox/NewLightboxView.tsx
+++ b/src/client/views/newlightbox/NewLightboxView.tsx
@@ -2,35 +2,32 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Utils';
-import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
 import { InkTool } from '../../../fields/InkField';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { LinkManager } from '../../util/LinkManager';
 import { SelectionManager } from '../../util/SelectionManager';
 import { Transform } from '../../util/Transform';
-import { GestureOverlay } from '../GestureOverlay';
-import { MainView } from '../MainView';
-import { DefaultStyleProvider } from '../StyleProvider';
 import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline';
 import { TabDocView } from '../collections/TabDocView';
+import { GestureOverlay } from '../GestureOverlay';
+import { LightboxView } from '../LightboxView';
 import { DocumentView, OpenWhere } from '../nodes/DocumentView';
+import { DefaultStyleProvider } from '../StyleProvider';
+import { IRecommendation } from './components';
 import { ExploreView } from './ExploreView';
-import { IBounds, emptyBounds } from './ExploreView/utils';
+import { emptyBounds, IBounds } from './ExploreView/utils';
 import { NewLightboxHeader } from './Header';
 import './NewLightboxView.scss';
 import { RecommendationList } from './RecommendationList';
-import { IRecommendation } from './components';
-import { fetchKeywords, fetchRecommendations } from './utils';
-import { List } from '../../../fields/List';
-import { LightboxView } from '../LightboxView';
 
 enum LightboxStatus {
-    RECOMMENDATIONS = "recommendations",
-    ANNOTATIONS = "annotations",
-    NONE = "none"
+    RECOMMENDATIONS = 'recommendations',
+    ANNOTATIONS = 'annotations',
+    NONE = 'none',
 }
 
 interface LightboxViewProps {
@@ -63,30 +60,30 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
     @observable private static _docView: Opt<DocumentView>;
 
     // keywords
-    @observable private static _keywords: string[] = []
+    @observable private static _keywords: string[] = [];
     @action public static SetKeywords(kw: string[]) {
-        this._keywords = kw
+        this._keywords = kw;
     }
     @computed public static get Keywords() {
-        return this._keywords
+        return this._keywords;
     }
 
     // query
-    @observable private static _query: string = ''
+    @observable private static _query: string = '';
     @action public static SetQuery(query: string) {
-        this._query = query
+        this._query = query;
     }
     @computed public static get Query() {
-        return this._query
+        return this._query;
     }
 
     // keywords
-    @observable private static _recs: IRecommendation[] = []
+    @observable private static _recs: IRecommendation[] = [];
     @action public static SetRecs(recs: IRecommendation[]) {
-        this._recs = recs
+        this._recs = recs;
     }
     @computed public static get Recs() {
-        return this._recs
+        return this._recs;
     }
 
     // bounds
@@ -108,7 +105,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
     }
 
     // newLightbox sidebar status
-    @observable private static _sidebarStatus: Opt<string> = "";
+    @observable private static _sidebarStatus: Opt<string> = '';
     @action public static SetSidebarStatus(sidebarStatus: Opt<string>) {
         this._sidebarStatus = sidebarStatus;
     }
@@ -129,7 +126,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
             this._docFilters && (this._docFilters.length = 0);
             this._future = this._history = [];
             Doc.ActiveTool = InkTool.None;
-            MainView.Instance._exploreMode = false;
+            DocumentView.ExploreMode = false;
         } else {
             const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement();
             l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
@@ -289,35 +286,38 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
 
     @computed
     get documentView() {
-        if (!LightboxView.LightboxDoc) return null
-        else return (<GestureOverlay isActive={true}>
-                            <DocumentView
-                                ref={action((r: DocumentView | null) => (NewLightboxView._docView = r !== null ? r : undefined))}
-                                Document={LightboxView.LightboxDoc}
-                                DataDoc={undefined}
-                                PanelWidth={this.newLightboxWidth}
-                                PanelHeight={this.newLightboxHeight}
-                                LayoutTemplate={NewLightboxView.LightboxDocTemplate}
-                                isDocumentActive={returnTrue} // without this being true, sidebar annotations need to be activated before text can be selected.
-                                isContentActive={returnTrue}
-                                styleProvider={DefaultStyleProvider}
-                                ScreenToLocalTransform={this.newLightboxScreenToLocal}
-                                renderDepth={0}
-                                rootSelected={returnTrue}
-                                docViewPath={returnEmptyDoclist}
-                                childFilters={this.docFilters}
-                                childFiltersByRanges={returnEmptyFilter}
-                                searchFilterDocs={returnEmptyDoclist}
-                                addDocument={undefined}
-                                removeDocument={undefined}
-                                whenChildContentsActiveChanged={emptyFunction}
-                                addDocTab={this.addDocTab}
-                                pinToPres={TabDocView.PinDoc}
-                                bringToFront={emptyFunction}
-                                onBrowseClick={MainView.Instance.exploreMode}
-                                focus={emptyFunction}
-                            />
-                        </GestureOverlay>)
+        if (!LightboxView.LightboxDoc) return null;
+        else
+            return (
+                <GestureOverlay isActive={true}>
+                    <DocumentView
+                        ref={action((r: DocumentView | null) => (NewLightboxView._docView = r !== null ? r : undefined))}
+                        Document={LightboxView.LightboxDoc}
+                        DataDoc={undefined}
+                        PanelWidth={this.newLightboxWidth}
+                        PanelHeight={this.newLightboxHeight}
+                        LayoutTemplate={NewLightboxView.LightboxDocTemplate}
+                        isDocumentActive={returnTrue} // without this being true, sidebar annotations need to be activated before text can be selected.
+                        isContentActive={returnTrue}
+                        styleProvider={DefaultStyleProvider}
+                        ScreenToLocalTransform={this.newLightboxScreenToLocal}
+                        renderDepth={0}
+                        rootSelected={returnTrue}
+                        docViewPath={returnEmptyDoclist}
+                        childFilters={this.docFilters}
+                        childFiltersByRanges={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
+                        addDocument={undefined}
+                        removeDocument={undefined}
+                        whenChildContentsActiveChanged={emptyFunction}
+                        addDocTab={this.addDocTab}
+                        pinToPres={TabDocView.PinDoc}
+                        bringToFront={emptyFunction}
+                        onBrowseClick={DocumentView.exploreMode}
+                        focus={emptyFunction}
+                    />
+                </GestureOverlay>
+            );
     }
 
     future = () => NewLightboxView._future;
@@ -337,29 +337,28 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
                         NewLightboxView.SetNewLightboxDoc(undefined);
                     }
                 }}>
-                <div className={`app-document`} style={{gridTemplateColumns: `calc(100% - 400px) 400px`}}>
-                <div
-                    className="newLightboxView-contents"
-                    style={{
-                        top: 20,
-                        left: 20,
-                        width: this.newLightboxWidth(),
-                        height: this.newLightboxHeight() - 40,
-                    }}>
+                <div className={`app-document`} style={{ gridTemplateColumns: `calc(100% - 400px) 400px` }}>
+                    <div
+                        className="newLightboxView-contents"
+                        style={{
+                            top: 20,
+                            left: 20,
+                            width: this.newLightboxWidth(),
+                            height: this.newLightboxHeight() - 40,
+                        }}>
                         <NewLightboxHeader height={newLightboxHeaderHeight} width={this.newLightboxWidth()} />
-                        {!NewLightboxView._explore ? 
-                            <div className="newLightboxView-doc" style={{height: this.newLightboxHeight()}}>
+                        {!NewLightboxView._explore ? (
+                            <div className="newLightboxView-doc" style={{ height: this.newLightboxHeight() }}>
                                 {this.documentView}
                             </div>
-                        :
+                        ) : (
                             <div className={`explore`}>
-                                <ExploreView recs={NewLightboxView.Recs} bounds={NewLightboxView.Bounds}/>
+                                <ExploreView recs={NewLightboxView.Recs} bounds={NewLightboxView.Bounds} />
                             </div>
-                        }
-                </div>
-                    <RecommendationList keywords={NewLightboxView.Keywords}/>
+                        )}
+                    </div>
+                    <RecommendationList keywords={NewLightboxView.Keywords} />
                 </div>
-                
             </div>
         );
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index be1eb3901..74eee49e0 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -28,6 +28,7 @@ import { FollowLinkScript } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
+import { SettingsManager } from '../../util/SettingsManager';
 import { SharingManager } from '../../util/SharingManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
@@ -51,7 +52,6 @@ import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
-import { SettingsManager } from '../../util/SettingsManager';
 const { Howl } = require('howler');
 
 interface Window {
@@ -428,7 +428,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if (!this.Document.ignoreClick && this.pointerEvents !== 'none' && this.props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
             let stopPropagate = true;
             let preventDefault = true;
-            (this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
+            !this.rootDoc._keepZWhenDragged && this.props.bringToFront(this.rootDoc);
             if (this._doubleTap) {
                 const defaultDblclick = this.props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
                 if (this.onDoubleClickHandler?.script) {
@@ -744,8 +744,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: 'arrow-up' });
                     zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: 'arrow-down' });
                     zorderItems.push({
-                        description: this.rootDoc._raiseWhenDragged !== false ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged',
-                        event: undoBatch(action(() => (this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined))),
+                        description: !this.rootDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged',
+                        event: undoBatch(action(() => (this.rootDoc._keepZWhenDragged = !this.rootDoc._keepZWhenDragged))),
                         icon: 'hand-point-up',
                     });
                     !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' });
@@ -1114,7 +1114,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             </div>
         );
         const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
-        const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.Instance.userVariantColor));
+        const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userVariantColor));
         const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
         const titleView = !showTitle ? null : (
             <div
@@ -1276,7 +1276,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 @observer
 export class DocumentView extends React.Component<DocumentViewProps> {
     public static ROOT_DIV = 'documentView-effectsWrapper';
+    @observable public static Interacting = false;
     @observable public static LongPress = false;
+    @observable public static ExploreMode = false;
+    @observable public static LastPressedSidebarBtn: Opt<Doc>; // bcz: this is a hack to handle highlighting buttons in the leftpanel menu .. need to find a cleaner approach
+    @computed public static get exploreMode() {
+        return () => (DocumentView.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
+    }
     @observable public docView: DocumentViewInternal | undefined | null;
     @observable public textHtmlOverlay: Opt<string>;
     @observable private _isHovering = false;
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 94650cc88..fc66d40db 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -67,19 +67,6 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         }
     };
 
-    static GetShowLabels() {
-        return BoolCast(Doc.UserDoc()._showLabel);
-    }
-    static SetShowLabels(show: boolean) {
-        Doc.UserDoc()._showLabel = show;
-    }
-    static GetRecognizeGestures() {
-        return BoolCast(Doc.UserDoc()._recognizeGestures);
-    }
-    static SetRecognizeGestures(show: boolean) {
-        Doc.UserDoc()._recognizeGestures = show;
-    }
-
     // Determining UI Specs
     @computed get label() {
         return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title));
@@ -139,7 +126,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
         // Script for checking the outcome of the toggle
         const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)));
-        const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
+        const label = !Doc.GetShowIconLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
 
         return (
             <NumberDropdown
@@ -174,7 +161,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                     Doc.UnBrushAllDocs();
                 })}>
                 {this.Icon(color)}
-                {!this.label || !FontIconBox.GetShowLabels() ? null : (
+                {!this.label || !Doc.GetShowIconLabels() ? null : (
                     <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}>
                         {' '}
                         {this.label}{' '}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index d69009415..42c8ea6a4 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -4,7 +4,7 @@ import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import wiki from 'wikijs';
 import { Doc, DocCastAsync, Opt } from '../../../fields/Doc';
-import { DirectLinks, Height, Width } from '../../../fields/DocSymbols';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
 import { DocServer } from '../../DocServer';
@@ -13,9 +13,9 @@ import { DocumentType } from '../../documents/DocumentTypes';
 import { DragManager } from '../../util/DragManager';
 import { LinkFollower } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
+import { SearchUtil } from '../../util/SearchUtil';
 import { SettingsManager } from '../../util/SettingsManager';
 import { Transform } from '../../util/Transform';
-import { SearchBox } from '../search/SearchBox';
 import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView';
 import './LinkDocPreview.scss';
 import React = require('react');
@@ -174,7 +174,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
             LinkFollower.FollowLink(this._linkDoc, this._linkSrc, false);
         } else if (this.props.hrefs?.length) {
             const webDoc =
-                Array.from(SearchBox.staticSearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ??
+                Array.from(SearchUtil.SearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ??
                 Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, data_useCors: true });
             this.props.docProps?.addDocTab(webDoc, OpenWhere.lightbox);
         }
diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx
index fcbd0128d..0b02626e9 100644
--- a/src/client/views/nodes/LoadingBox.tsx
+++ b/src/client/views/nodes/LoadingBox.tsx
@@ -1,14 +1,14 @@
-import { action, observable, runInAction } from 'mobx';
+import { observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import ReactLoading from 'react-loading';
 import { Doc } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
 import { StrCast } from '../../../fields/Types';
 import { Networking } from '../../Network';
 import { ViewBoxAnnotatableComponent } from '../DocComponent';
 import { FieldView, FieldViewProps } from './FieldView';
 import './LoadingBox.scss';
-import { Id } from '../../../fields/FieldSymbols';
 
 /**
  * LoadingBox Class represents a placeholder doc for documents that are currently
@@ -44,7 +44,7 @@ export class LoadingBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             this.rootDoc.loadingError = 'Upload interrupted, please try again';
         } else {
             const updateFunc = async () => {
-                const result = await Networking.QueryYoutubeProgress(StrCast(this.rootDoc[Id])); // We use the guid of the overwriteDoc to track file uploads. 
+                const result = await Networking.QueryYoutubeProgress(StrCast(this.rootDoc[Id])); // We use the guid of the overwriteDoc to track file uploads.
                 runInAction(() => (this.progress = result.progress));
                 this._timer = setTimeout(updateFunc, 1000);
             };
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 83a29f071..fa19caae1 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -314,7 +314,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             </>
                         </CollectionFreeFormView>
                     </div>
-                    <div style={{ background: SettingsManager.Instance.userColor, position: 'relative', height: this.formattedPanelHeight() }}>
+                    <div style={{ background: SettingsManager.userColor, position: 'relative', height: this.formattedPanelHeight() }}>
                         {!(this.dataDoc[this.fieldKey + '_dictation'] instanceof Doc) ? null : (
                             <FormattedTextBox
                                 {...this.props}
@@ -336,8 +336,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                     </div>
                 </div>
                 {!this.props.isSelected() ? null : (
-                    <div className="screenshotBox-uiButtons" style={{ background: SettingsManager.Instance.userColor }}>
-                        <div className="screenshotBox-recorder" style={{ color: SettingsManager.Instance.userBackgroundColor, background: SettingsManager.Instance.userVariantColor }} key="snap" onPointerDown={this.toggleRecording}>
+                    <div className="screenshotBox-uiButtons" style={{ background: SettingsManager.userColor }}>
+                        <div className="screenshotBox-recorder" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userVariantColor }} key="snap" onPointerDown={this.toggleRecording}>
                             <FontAwesomeIcon icon="file" size="lg" />
                         </div>
                     </div>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 2177adeff..48716b867 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -26,11 +26,10 @@ import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionS
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
-import { DocumentDecorations } from '../DocumentDecorations';
 import { MarqueeAnnotator } from '../MarqueeAnnotator';
 import { AnchorMenu } from '../pdf/AnchorMenu';
 import { StyleProp } from '../StyleProvider';
-import { OpenWhere } from './DocumentView';
+import { DocumentView, OpenWhere } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import { RecordingBox } from './RecordingBox';
 import { PinProps, PresBox } from './trails';
@@ -624,7 +623,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 () => !this._playing && this.Seek(NumCast(this.layoutDoc._layout_currentTimecode))
             );
             this._disposers.youtubeReactionDisposer = reaction(
-                () => Doc.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting,
+                () => Doc.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentView.Interacting,
                 interactive => (iframe.style.pointerEvents = interactive ? 'all' : 'none'),
                 { fireImmediately: true }
             );
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 200d06a0b..bd969b527 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -11,9 +11,10 @@ import { keymap } from 'prosemirror-keymap';
 import { Fragment, Mark, Node, Slice } from 'prosemirror-model';
 import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state';
 import { EditorView } from 'prosemirror-view';
+import { BsMarkdownFill } from 'react-icons/bs';
 import { DateField } from '../../../../fields/DateField';
-import { Doc, DocListCast, StrListCast, Field, Opt } from '../../../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, Height, Width, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
+import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, Height, UpdatingFromServer, Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { List } from '../../../../fields/List';
@@ -25,11 +26,10 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } fro
 import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
-import { gptAPICall, GPTCallType, gptImageCall } from '../../../apis/gpt/GPT';
+import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
 import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
-import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
-import { Networking } from '../../../Network';
+import { CollectionViewType } from '../../../documents/DocumentTypes';
 import { DictationManager } from '../../../util/DictationManager';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
@@ -49,6 +49,7 @@ import { DocumentButtonBar } from '../../DocumentButtonBar';
 import { Colors } from '../../global/globalEnums';
 import { LightboxView } from '../../LightboxView';
 import { AnchorMenu } from '../../pdf/AnchorMenu';
+import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
 import { SidebarAnnos } from '../../SidebarAnnos';
 import { StyleProp } from '../../StyleProvider';
 import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView';
@@ -70,8 +71,6 @@ import { schema } from './schema_rts';
 import { SummaryView } from './SummaryView';
 import applyDevTools = require('prosemirror-dev-tools');
 import React = require('react');
-import { GPTPopup, GPTPopupMode } from '../../pdf/GPTPopup/GPTPopup';
-import { BsMarkdownFill } from 'react-icons/bs';
 const translateGoogleApi = require('translate-google-api');
 export const GoogleRef = 'googleDocId';
 type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@@ -575,7 +574,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         draggedDoc._freeform_fitContentsToBox = true;
                         Doc.SetContainer(draggedDoc, this.rootDoc);
                         const view = this._editorView!;
-                        view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
+                        try {
+                            const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos;
+                            pos && view.dispatch(view.state.tr.insert(pos, node));
+                            added = pos ? true : false; // pos will be null if you don't drop onto an actual text location
+                        } catch (e) {
+                            console.log('Drop failed', e);
+                            added = false;
+                        }
                     }
                 }
             } // otherwise, fall through to outer collection to handle drop
@@ -1119,7 +1125,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     componentDidMount() {
         !this.props.dontSelectOnLoad && this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
         this._cachedLinks = LinkManager.Links(this.Document);
-        this._disposers.breakupDictation = reaction(() => DocumentManager.Instance.RecordingEvent, this.breakupDictation);
+        this._disposers.breakupDictation = reaction(() => Doc.RecordingEvent, this.breakupDictation);
         this._disposers.layout_autoHeight = reaction(
             () => this.layout_autoHeight,
             layout_autoHeight => layout_autoHeight && this.tryUpdateScrollHeight()
diff --git a/src/client/views/nodes/generativeFill/GenerativeFill.tsx b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
index 1400d0f6d..1ec6d6e3f 100644
--- a/src/client/views/nodes/generativeFill/GenerativeFill.tsx
+++ b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
@@ -1,26 +1,25 @@
-import './GenerativeFill.scss';
-import React = require('react');
-import { useEffect, useRef, useState } from 'react';
-import { APISuccess, ImageUtility } from './generativeFillUtils/ImageHandler';
-import { BrushHandler } from './generativeFillUtils/BrushHandler';
-import { IconButton } from 'browndash-components';
 import { Checkbox, FormControlLabel, Slider, TextField } from '@mui/material';
-import { CursorData, ImageDimensions, Point } from './generativeFillUtils/generativeFillInterfaces';
-import { activeColor, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './generativeFillUtils/generativeFillConstants';
-import { PointerHandler } from './generativeFillUtils/PointerHandler';
-import { IoMdUndo, IoMdRedo } from 'react-icons/io';
-import { MainView } from '../../MainView';
+import { IconButton } from 'browndash-components';
+import { useEffect, useRef, useState } from 'react';
+import { CgClose } from 'react-icons/cg';
+import { IoMdRedo, IoMdUndo } from 'react-icons/io';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { Networking } from '../../../Network';
-import { Utils } from '../../../../Utils';
-import { DocUtils, Docs } from '../../../documents/Documents';
+import { List } from '../../../../fields/List';
 import { NumCast } from '../../../../fields/Types';
+import { Utils } from '../../../../Utils';
+import { Docs, DocUtils } from '../../../documents/Documents';
+import { Networking } from '../../../Network';
 import { CollectionDockingView } from '../../collections/CollectionDockingView';
 import { OpenWhereMod } from '../DocumentView';
-import Buttons from './GenerativeFillButtons';
-import { List } from '../../../../fields/List';
-import { CgClose } from 'react-icons/cg';
 import { ImageBox } from '../ImageBox';
+import './GenerativeFill.scss';
+import Buttons from './GenerativeFillButtons';
+import { BrushHandler } from './generativeFillUtils/BrushHandler';
+import { activeColor, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './generativeFillUtils/generativeFillConstants';
+import { CursorData, ImageDimensions, Point } from './generativeFillUtils/generativeFillInterfaces';
+import { APISuccess, ImageUtility } from './generativeFillUtils/ImageHandler';
+import { PointerHandler } from './generativeFillUtils/PointerHandler';
+import React = require('react');
 
 enum BrushStyle {
     ADD,
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 6ff22e929..f750392f5 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
 import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, FieldResult, Opt, StrListCast } from '../../../../fields/Doc';
 import { Animation } from '../../../../fields/DocSymbols';
 import { Copy, Id } from '../../../../fields/FieldSymbols';
 import { InkField } from '../../../../fields/InkField';
@@ -15,7 +15,7 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Ty
 import { AudioField } from '../../../../fields/URLField';
 import { emptyFunction, emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils';
 import { DocServer } from '../../../DocServer';
-import { Docs, DocUtils } from '../../../documents/Documents';
+import { Docs } from '../../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index b0924888a..6a8b06377 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -1,23 +1,20 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
+import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx';
 import { observer } from 'mobx-react';
+import { EditorView } from 'prosemirror-view';
 import { ColorState } from 'react-color';
 import { Doc, Opt } from '../../../fields/Doc';
+import { StrCast } from '../../../fields/Types';
 import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../Utils';
+import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { SelectionManager } from '../../util/SelectionManager';
 import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu';
 import { LinkPopup } from '../linking/LinkPopup';
-import { ButtonDropdown } from '../nodes/formattedText/RichTextMenu';
-import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
-import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
-import { LightboxView } from '../LightboxView';
-import { EditorView } from 'prosemirror-view';
 import './AnchorMenu.scss';
-import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { StrCast } from '../../../fields/Types';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index 6103b245c..540c1b5e1 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -1,17 +1,15 @@
 import { action, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { DocumentType } from "../../documents/DocumentTypes";
-// import "./SearchBox.scss";
-import "./IconBar.scss";
+import { DocumentType } from '../../documents/DocumentTypes';
+import './IconBar.scss';
 import { IconButton } from './IconButton';
-import "./IconButton.scss";
+import './IconButton.scss';
 
 export interface IconBarProps {
     setIcons: (icons: string[]) => void;
 }
 
-
 @observer
 export class IconBar extends React.Component<IconBarProps> {
     public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB, DocumentType.MAP];
@@ -32,7 +30,9 @@ export class IconBar extends React.Component<IconBarProps> {
     }
 
     @action.bound
-    getIcons(): string[] { return this._icons; }
+    getIcons(): string[] {
+        return this._icons;
+    }
 
     constructor(props: any) {
         super(props);
@@ -40,29 +40,33 @@ export class IconBar extends React.Component<IconBarProps> {
     }
 
     @action.bound
-    getList(): string[] { return this.getIcons(); }
+    getList(): string[] {
+        return this.getIcons();
+    }
 
     @action.bound
-    updateList(newList: string[]) { this.updateIcon(newList); }
+    updateList(newList: string[]) {
+        this.updateIcon(newList);
+    }
 
     @action.bound
     resetSelf = () => {
         this._resetClicked = true;
         this.updateList([]);
-    }
+    };
 
     @action.bound
     selectAll = () => {
         this._selectAllClicked = true;
         this.updateList(this._allIcons);
-    }
+    };
 
     render() {
         return (
             <div className="icon-bar">
-                {this._allIcons.map((type: string) =>
+                {this._allIcons.map((type: string) => (
                     <IconButton key={type.toString()} type={type} />
-                )}
+                ))}
             </div>
         );
     }
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 1ceea697a..6b6b0f2ff 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -19,6 +19,7 @@ import { fetchRecommendations } from '../newlightbox/utils';
 import { IRecommendation, Recommendation } from '../newlightbox/components';
 import { Colors } from '../global/globalEnums';
 import { SettingsManager } from '../../util/SettingsManager';
+import { SearchUtil } from '../../util/SearchUtil';
 
 const DAMPENING_FACTOR = 0.9;
 const MAX_ITERATIONS = 25;
@@ -128,34 +129,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         }
     });
 
-    /**
-     * @param {Doc[]} docs - docs to be searched through recursively
-     * @param {number, Doc => void} func - function to be called on each doc
-     *
-     * This method iterates through an array of docs and all docs within those docs, calling
-     * the function func on each doc.
-     */
-    static foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) {
-        let newarray: Doc[] = [];
-        var depth = 0;
-        const visited: Doc[] = [];
-        while (docs.length > 0) {
-            newarray = [];
-            docs.filter(d => d && !visited.includes(d)).forEach(d => {
-                visited.push(d);
-                const fieldKey = Doc.LayoutFieldKey(d);
-                const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
-                const data = d[annos ? fieldKey + '_annotations' : fieldKey];
-                data && newarray.push(...DocListCast(data));
-                const sidebar = d[fieldKey + '_sidebar'];
-                sidebar && newarray.push(...DocListCast(sidebar));
-                func(depth, d);
-            });
-            docs = newarray;
-            depth++;
-        }
-    }
-
     /**
      * @param {Doc[]} docs - docs to be searched through recursively
      * @param {number, Doc => void} func - function to be called on each doc
@@ -213,74 +186,10 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     @action
     searchCollection(query: string) {
         this._selectedResult = undefined;
-        this._results = SearchBox.staticSearchCollection(CollectionDockingView.Instance?.rootDoc, query);
+        this._results = SearchUtil.SearchCollection(CollectionDockingView.Instance?.rootDoc, query);
 
         this.computePageRanks();
     }
-    @action
-    static staticSearchCollection(rootDoc: Opt<Doc>, query: string) {
-        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.SEARCH, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
-        const blockedKeys = [
-            'x',
-            'y',
-            'proto',
-            'width',
-            'layout_autoHeight',
-            'acl-Override',
-            'acl-Guest',
-            'embedContainer',
-            'zIndex',
-            'height',
-            'text_scrollHeight',
-            'text_height',
-            'cloneFieldFilter',
-            'isDataDoc',
-            'text_annotations',
-            'dragFactory_count',
-            'text_noTemplate',
-            'proto_embeddings',
-            'isSystem',
-            'layout_fieldKey',
-            'isBaseProto',
-            'xMargin',
-            'yMargin',
-            'links',
-            'layout',
-            'layout_keyValue',
-            'layout_fitWidth',
-            'type_collection',
-            'title_custom',
-            'freeform_panX',
-            'freeform_panY',
-            'freeform_scale',
-        ];
-        query = query.toLowerCase();
-
-        const results = new Map<Doc, string[]>();
-        if (rootDoc) {
-            const docs = DocListCast(rootDoc[Doc.LayoutFieldKey(rootDoc)]);
-            const docIDs: String[] = [];
-            SearchBox.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
-                const dtype = StrCast(doc.type) as DocumentType;
-                if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) {
-                    const hlights = new Set<string>();
-                    SearchBox.documentKeys(doc).forEach(
-                        key =>
-                            Field.toString(doc[key] as Field)
-                                .toLowerCase()
-                                .includes(query) && hlights.add(key)
-                    );
-                    blockedKeys.forEach(key => hlights.delete(key));
-
-                    if (Array.from(hlights.keys()).length > 0) {
-                        results.set(doc, Array.from(hlights.keys()));
-                    }
-                }
-                docIDs.push(doc[Id]);
-            });
-        }
-        return results;
-    }
 
     /**
      * This method initializes the page rank of every document to the reciprocal
@@ -373,17 +282,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         }
     }
 
-    /**
-     * @param {Doc} doc - doc for which keys are returned
-     *
-     * This method returns a list of a document doc's keys.
-     */
-    static documentKeys(doc: Doc) {
-        const keys: { [key: string]: boolean } = {};
-        Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)));
-        return Array.from(Object.keys(keys));
-    }
-
     /**
      * This method submits a search with the _searchString as its query and updates
      * the results array accordingly.
@@ -518,7 +416,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                             className={className}>
                             <div className="searchBox-result-title">{title as string}</div>
                             <div className="searchBox-result-type">{formattedType}</div>
-                            <div className="searchBox-result-keys" style={{ color: SettingsManager.Instance.userVariantColor }}>
+                            <div className="searchBox-result-keys" style={{ color: SettingsManager.userVariantColor }}>
                                 {result[1].join(', ')}
                             </div>
                         </div>
@@ -530,7 +428,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         const recommendationsJSX: JSX.Element[] = this._recommendations.map(props => <Recommendation {...props} />);
 
         return (
-            <div className="searchBox-container" style={{ pointerEvents: 'all', color: SettingsManager.Instance.userColor, background: SettingsManager.Instance.userBackgroundColor }}>
+            <div className="searchBox-container" style={{ pointerEvents: 'all', color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}>
                 <div className="searchBox-bar">
                     {isLinkSearch ? null : (
                         <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index c194ede32..a2f9de9ab 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -1,13 +1,14 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, IconButton, Size, Type, isDark } from 'browndash-components';
+import { Button, IconButton, isDark, Size, Type } from 'browndash-components';
 import { action, computed, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { FaBug, FaCamera, FaStamp } from 'react-icons/fa';
+import { FaBug, FaCamera } from 'react-icons/fa';
 import { Doc, DocListCast } from '../../../fields/Doc';
 import { AclAdmin, DashVersion } from '../../../fields/DocSymbols';
 import { StrCast } from '../../../fields/Types';
 import { GetEffectiveAcl } from '../../../fields/util';
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 import { DocumentManager } from '../../util/DocumentManager';
 import { PingManager } from '../../util/PingManager';
 import { ReportManager } from '../../util/reportManager/ReportManager';
@@ -15,13 +16,12 @@ import { ServerStats } from '../../util/ServerStats';
 import { SettingsManager } from '../../util/SettingsManager';
 import { SharingManager } from '../../util/SharingManager';
 import { UndoManager } from '../../util/UndoManager';
+import { CollectionDockingView } from '../collections/CollectionDockingView';
 import { ContextMenu } from '../ContextMenu';
 import { DashboardView } from '../DashboardView';
-import { MainView } from '../MainView';
-import { CollectionDockingView } from '../collections/CollectionDockingView';
 import { Colors } from '../global/globalEnums';
+import { DocumentView } from '../nodes/DocumentView';
 import './TopBar.scss';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 
 /**
  * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user
@@ -43,7 +43,7 @@ export class TopBar extends React.Component {
         return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE);
     }
     @computed get backgroundColor() {
-        return PingManager.Instance.IsBeating ? SettingsManager.Instance.userBackgroundColor : Colors.MEDIUM_GRAY;
+        return PingManager.Instance.IsBeating ? SettingsManager.userBackgroundColor : Colors.MEDIUM_GRAY;
     }
 
     @observable happyHeart: boolean = PingManager.Instance.IsBeating;
@@ -76,9 +76,7 @@ export class TopBar extends React.Component {
                         <span style={{ color: isDark(this.backgroundColor) ? Colors.LIGHT_BLUE : Colors.MEDIUM_BLUE, fontWeight: 500 }}>dash</span>
                     </div>
                 )}
-                {Doc.ActiveDashboard && (
-                    <Button text="Explore" tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} color={this.color} onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))} />
-                )}
+                {Doc.ActiveDashboard && <Button text="Explore" tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} color={this.color} onClick={action(() => (DocumentView.ExploreMode = !DocumentView.ExploreMode))} />}
             </div>
         );
     }
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 02e44a793..524492226 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -6,8 +6,8 @@ import { observer } from 'mobx-react';
 import { Doc } from '../../../fields/Doc';
 import { InkTool } from '../../../fields/InkField';
 import '../../views/nodes/WebBox.scss';
-import { DocumentDecorations } from '../DocumentDecorations';
 import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView';
+import { DocumentView } from '../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import './DashWebRTCVideo.scss';
 import { hangup, initialize, refreshVideos } from './WebCamLogic';
@@ -71,8 +71,8 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
             </div>
         );
 
-        const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
-        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? '-interactive' : '');
+        const frozen = !this.props.isSelected() || DocumentView.Interacting;
+        const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : '');
 
         return (
             <>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 4ad38e7fc..f17e10d9e 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -47,7 +47,7 @@ import { FieldId, RefField } from './RefField';
 import { RichTextField } from './RichTextField';
 import { listSpec } from './Schema';
 import { ComputedField, ScriptField } from './ScriptField';
-import { Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types';
+import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types';
 import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
 import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions } from './util';
 import JSZip = require('jszip');
@@ -156,7 +156,26 @@ export function updateCachedAcls(doc: Doc) {
 @scriptingGlobal
 @Deserializable('Doc', updateCachedAcls, ['id'])
 export class Doc extends RefField {
-    @observable public static CurrentlyLoading: Doc[];
+    @observable public static RecordingEvent = 0;
+
+    // this isn't really used at the moment, but is intended to indicate whether ink stroke are passed through a gesture recognizer
+    static GetRecognizeGestures() {
+        return BoolCast(Doc.UserDoc()._recognizeGestures);
+    }
+    static SetRecognizeGestures(show: boolean) {
+        Doc.UserDoc()._recognizeGestures = show;
+    }
+
+    //
+    // This controls whether fontIconButtons will display labels under their icons or not
+    //
+    static GetShowIconLabels() {
+        return BoolCast(Doc.UserDoc()._showLabel);
+    }
+    static SetShowIconLabels(show: boolean) {
+        Doc.UserDoc()._showLabel = show;
+    }
+    @observable public static CurrentlyLoading: Doc[] = []; // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor
     // removes from currently loading display
     @action
     public static removeCurrentlyLoading(doc: Doc) {
@@ -169,9 +188,6 @@ export class Doc extends RefField {
     // adds doc to currently loading display
     @action
     public static addCurrentlyLoading(doc: Doc) {
-        if (!Doc.CurrentlyLoading) {
-            Doc.CurrentlyLoading = [];
-        }
         if (Doc.CurrentlyLoading.indexOf(doc) === -1) {
             Doc.CurrentlyLoading.push(doc);
         }
diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts
index 24cd078f2..5ecf25e08 100644
--- a/src/fields/RichTextUtils.ts
+++ b/src/fields/RichTextUtils.ts
@@ -2,20 +2,20 @@ import { AssertionError } from 'assert';
 import { docs_v1 } from 'googleapis';
 import { Fragment, Mark, Node } from 'prosemirror-model';
 import { sinkListItem } from 'prosemirror-schema-list';
-import { Utils, DashColor } from '../Utils';
-import { Docs, DocUtils } from '../client/documents/Documents';
-import { schema } from '../client/views/nodes/formattedText/schema_rts';
+import { EditorState, TextSelection, Transaction } from 'prosemirror-state';
+import { GoogleApiClientUtils } from '../client/apis/google_docs/GoogleApiClientUtils';
 import { GooglePhotos } from '../client/apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from '../client/DocServer';
+import { Docs, DocUtils } from '../client/documents/Documents';
 import { Networking } from '../client/Network';
 import { FormattedTextBox } from '../client/views/nodes/formattedText/FormattedTextBox';
+import { schema } from '../client/views/nodes/formattedText/schema_rts';
+import { DashColor, Utils } from '../Utils';
 import { Doc, Opt } from './Doc';
 import { Id } from './FieldSymbols';
 import { RichTextField } from './RichTextField';
 import { Cast, StrCast } from './Types';
 import Color = require('color');
-import { EditorState, TextSelection, Transaction } from 'prosemirror-state';
-import { GoogleApiClientUtils } from '../client/apis/google_docs/GoogleApiClientUtils';
 
 export namespace RichTextUtils {
     const delimiter = '\n';
-- 
cgit v1.2.3-70-g09d2

