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/views/nodes/MapBox/MapBox.tsx | 552 +++++++++----------------------
 1 file changed, 153 insertions(+), 399 deletions(-)

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

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}
-- 
cgit v1.2.3-70-g09d2

