From 142cb372c6dec9fa641786784cbdd6dca6896d33 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 15 Apr 2020 00:42:07 -0700
Subject: added robust error checking for lat, lng and address values, reverts
 to previous on invalid entry or zero results

---
 src/client/views/collections/CollectionMapView.tsx | 63 +++++++++++++++-------
 1 file changed, 44 insertions(+), 19 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 64946e59e..5b8b6e75a 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -12,6 +12,7 @@ import { DocumentManager } from "../../util/DocumentManager";
 import { UndoManager, undoBatch } from "../../util/UndoManager";
 import { IReactionDisposer, reaction, computed, runInAction } from "mobx";
 import requestPromise = require("request-promise");
+import { emptyFunction } from "../../../Utils";
 
 type MapSchema = makeInterface<[typeof documentSchema]>;
 const MapSchema = makeInterface(documentSchema);
@@ -119,11 +120,11 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     }
 
     private respondToAddressChange = async (newAddress: string, doc: Doc) => {
-        const { results } = await query(newAddress);
-        if (!results?.length) {
-            return;
+        const response = await query(newAddress);
+        if (!response || response.status === "ZERO_RESULTS") {
+            return false;
         }
-        const { geometry, formatted_address } = results[0];
+        const { geometry, formatted_address } = response.results[0];
         const { lat, lng } = geometry.location;
         runInAction(() => {
             if (doc["mapLocation-lat"] !== lat || doc["mapLocation-lng"] !== lng) {
@@ -136,18 +137,20 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                 Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true);
             }
         });
+        return true;
     }
 
     private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, doc: Doc) => {
-        const { results } = await query({ lat: NumCast(newLat), lng: NumCast(newLng) });
-        if (!results?.length) {
-            return;
+        const response = await query({ lat: NumCast(newLat), lng: NumCast(newLng) });
+        if (!response || response.status === "ZERO_RESULTS") {
+            return false;
         }
-        const { formatted_address } = results[0];
+        const { formatted_address } = response.results[0];
         if (formatted_address !== doc["mapLocation-address"]) {
             this._cancelAddrReq.set(doc[Id], true);
             Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true);
         }
+        return true;
     }
 
     @computed get contents() {
@@ -156,23 +159,45 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
         this.latlngUpdaters.forEach(disposer => disposer());
         this.latlngUpdaters = [];
         return this.childLayoutPairs.map(({ layout }) => {
+            const id = layout[Id];
             this.addressUpdaters.push(reaction(
                 () => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] }),
-                ({ lat, lng }) => {
-                    if (this._cancelLocReq.get(layout[Id])) {
-                        this._cancelLocReq.set(layout[Id], false);
-                    } else if (lat !== undefined && lng !== undefined) {
-                        this.respondToLocationChange(lat, lng, layout);
+                emptyFunction,
+                {
+                    equals: (previous, { lat, lng }) => {
+                        if (this._cancelLocReq.get(id)) {
+                            this._cancelLocReq.set(id, false);
+                        } else if (lat !== undefined && lng !== undefined) {
+                            this.respondToLocationChange(lat, lng, layout).then(success => {
+                                if (!success) {
+                                    this._cancelLocReq.set(id, true);
+                                    runInAction(() => {
+                                        layout["mapLocation-lat"] = previous.lat;
+                                        layout["mapLocation-lng"] = previous.lng;
+                                    });
+                                }
+                            });
+                        }
+                        return previous === { lat, lng };
                     }
                 }
             ));
             this.latlngUpdaters.push(reaction(
-                () => ({ address: Cast(layout["mapLocation-address"], "string", null) }),
-                ({ address }) => {
-                    if (this._cancelAddrReq.get(layout[Id])) {
-                        this._cancelAddrReq.set(layout[Id], false);
-                    } else if (address?.length) {
-                        this.respondToAddressChange(address, layout);
+                () => Cast(layout["mapLocation-address"], "string", null),
+                emptyFunction,
+                {
+                    equals: (previous, address) => {
+                        if (this._cancelAddrReq.get(id)) {
+                            this._cancelAddrReq.set(id, false);
+                        } else if (address?.length) {
+                            this.respondToAddressChange(address, layout).then(success => {
+                                if (!success) {
+                                    this._cancelAddrReq.set(id, true);
+                                    layout["mapLocation-address"] = previous;
+                                }
+                            });
+                        }
+                        return previous === address;
                     }
                 }
             ));
-- 
cgit v1.2.3-70-g09d2


From 15f3a7898268b8fc6eded456515726a2c40b6b46 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 15 Apr 2020 01:22:18 -0700
Subject: using interesting mobx paradigm to manage value interception

---
 src/client/views/collections/CollectionMapView.tsx | 49 ++++++++++------------
 1 file changed, 21 insertions(+), 28 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 5b8b6e75a..4fbccac33 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -10,7 +10,7 @@ import { CollectionSubView } from "./CollectionSubView";
 import React = require("react");
 import { DocumentManager } from "../../util/DocumentManager";
 import { UndoManager, undoBatch } from "../../util/UndoManager";
-import { IReactionDisposer, reaction, computed, runInAction } from "mobx";
+import { IReactionDisposer, reaction, computed, runInAction, Lambda } from "mobx";
 import requestPromise = require("request-promise");
 import { emptyFunction } from "../../../Utils";
 
@@ -42,8 +42,8 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     private _cancelAddrReq = new Map<string, boolean>();
     private _cancelLocReq = new Map<string, boolean>();
     private _initialLookupPending = new Map<string, boolean>();
-    private addressUpdaters: IReactionDisposer[] = [];
-    private latlngUpdaters: IReactionDisposer[] = [];
+    private addressUpdaters: Lambda[] = [];
+    private latlngUpdaters: Lambda[] = [];
 
     /**
      * Note that all the uses of runInAction below are not included
@@ -153,18 +153,17 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
         return true;
     }
 
-    @computed get contents() {
+    @computed get reactiveContents() {
         this.addressUpdaters.forEach(disposer => disposer());
         this.addressUpdaters = [];
         this.latlngUpdaters.forEach(disposer => disposer());
         this.latlngUpdaters = [];
         return this.childLayoutPairs.map(({ layout }) => {
             const id = layout[Id];
-            this.addressUpdaters.push(reaction(
-                () => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] }),
-                emptyFunction,
-                {
-                    equals: (previous, { lat, lng }) => {
+            this.addressUpdaters.push(
+                computed(() => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] }))
+                    .observe(({ oldValue, newValue }) => {
+                        const { lat, lng } = newValue;
                         if (this._cancelLocReq.get(id)) {
                             this._cancelLocReq.set(id, false);
                         } else if (lat !== undefined && lng !== undefined) {
@@ -172,35 +171,29 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                                 if (!success) {
                                     this._cancelLocReq.set(id, true);
                                     runInAction(() => {
-                                        layout["mapLocation-lat"] = previous.lat;
-                                        layout["mapLocation-lng"] = previous.lng;
+                                        layout["mapLocation-lat"] = oldValue ? oldValue.lat : undefined;
+                                        layout["mapLocation-lng"] = oldValue ? oldValue.lng : undefined;
                                     });
                                 }
                             });
                         }
-                        return previous === { lat, lng };
-                    }
-                }
-            ));
-            this.latlngUpdaters.push(reaction(
-                () => Cast(layout["mapLocation-address"], "string", null),
-                emptyFunction,
-                {
-                    equals: (previous, address) => {
+                    })
+            );
+            this.latlngUpdaters.push(
+                computed(() => Cast(layout["mapLocation-address"], "string", null))
+                    .observe(({ oldValue, newValue }) => {
                         if (this._cancelAddrReq.get(id)) {
                             this._cancelAddrReq.set(id, false);
-                        } else if (address?.length) {
-                            this.respondToAddressChange(address, layout).then(success => {
+                        } else if (newValue?.length) {
+                            this.respondToAddressChange(newValue, layout).then(success => {
                                 if (!success) {
                                     this._cancelAddrReq.set(id, true);
-                                    layout["mapLocation-address"] = previous;
+                                    layout["mapLocation-address"] = oldValue;
                                 }
                             });
                         }
-                        return previous === address;
-                    }
-                }
-            ));
+                    })
+            );
             return this.renderMarker(layout);
         });
     }
@@ -233,7 +226,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                         });
                     })}
                 >
-                    {this.contents}
+                    {this.reactiveContents}
                 </GeoMap>
             </div>
         </div>;
-- 
cgit v1.2.3-70-g09d2


From 86885c0e97322ae99f331e594a5c67cf04cb4ec2 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 15 Apr 2020 12:33:21 -0400
Subject: extended getLocation to work with the map itself in addition to
 makers so that document titles can be used to indicate locations.

---
 src/client/views/collections/CollectionMapView.tsx | 35 +++++++++++-----------
 1 file changed, 17 insertions(+), 18 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 4fbccac33..583594057 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -1,18 +1,17 @@
 import { GoogleApiWrapper, Map as GeoMap, MapProps, Marker } from "google-maps-react";
+import { computed, Lambda, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, Opt, DocListCast, FieldResult } from "../../../new_fields/Doc";
+import { Doc, DocListCast, FieldResult, Opt } from "../../../new_fields/Doc";
 import { documentSchema } from "../../../new_fields/documentSchemas";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { makeInterface } from "../../../new_fields/Schema";
 import { Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
+import { DocumentManager } from "../../util/DocumentManager";
+import { undoBatch, UndoManager } from "../../util/UndoManager";
 import "./CollectionMapView.scss";
 import { CollectionSubView } from "./CollectionSubView";
 import React = require("react");
-import { DocumentManager } from "../../util/DocumentManager";
-import { UndoManager, undoBatch } from "../../util/UndoManager";
-import { IReactionDisposer, reaction, computed, runInAction, Lambda } from "mobx";
 import requestPromise = require("request-promise");
-import { emptyFunction } from "../../../Utils";
 
 type MapSchema = makeInterface<[typeof documentSchema]>;
 const MapSchema = makeInterface(documentSchema);
@@ -58,15 +57,15 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
             const lat: Opt<number> = Cast(doc[fieldKey + "-lat"], "number", null) || (Cast(doc[fieldKey + "-lat"], "string", null) && Number(Cast(doc[fieldKey + "-lat"], "string", null))) || undefined;
             const lng: Opt<number> = Cast(doc[fieldKey + "-lng"], "number", null) || (Cast(doc[fieldKey + "-lng"], "string", null) && Number(Cast(doc[fieldKey + "-lng"], "string", null))) || undefined;
             const zoom: Opt<number> = Cast(doc[fieldKey + "-zoom"], "number", null) || (Cast(doc[fieldKey + "-zoom"], "string", null) && Number(Cast(doc[fieldKey + "-zoom"], "string", null))) || undefined;
-            const address: Opt<string> = Cast(doc[fieldKey + "-address"], "string", null);
+            const address: Opt<string> = Cast(doc[fieldKey + "-address"], "string", (lat === undefined || lng === undefined ? Cast(doc.title, "string", null) : null));
             if (lat !== undefined && lng !== undefined) {
                 return ({ lat, lng, zoom });
             } else if (address) {
                 const id = doc[Id];
                 if (!this._initialLookupPending.get(id)) {
-                    this._initialLookupPending.set(id, true);
+                    this._initialLookupPending.set(id, true); ``
                     setTimeout(() => {
-                        this.respondToAddressChange(address, doc).then(() => this._initialLookupPending.delete(id));
+                        this.respondToAddressChange(address, fieldKey, doc).then(() => this._initialLookupPending.delete(id));
                     });
                 }
                 return defaultLocation;
@@ -119,7 +118,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
             />;
     }
 
-    private respondToAddressChange = async (newAddress: string, doc: Doc) => {
+    private respondToAddressChange = async (newAddress: string, fieldKey: string, doc: Doc) => {
         const response = await query(newAddress);
         if (!response || response.status === "ZERO_RESULTS") {
             return false;
@@ -127,28 +126,28 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
         const { geometry, formatted_address } = response.results[0];
         const { lat, lng } = geometry.location;
         runInAction(() => {
-            if (doc["mapLocation-lat"] !== lat || doc["mapLocation-lng"] !== lng) {
+            if (doc[fieldKey + "-lat"] !== lat || doc[fieldKey + "-lng"] !== lng) {
                 this._cancelLocReq.set(doc[Id], true);
-                Doc.SetInPlace(doc, "mapLocation-lat", lat, true);
-                Doc.SetInPlace(doc, "mapLocation-lng", lng, true);
+                Doc.SetInPlace(doc, fieldKey + "-lat", lat, true);
+                Doc.SetInPlace(doc, fieldKey + "-lng", lng, true);
             }
             if (formatted_address !== newAddress) {
                 this._cancelAddrReq.set(doc[Id], true);
-                Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true);
+                Doc.SetInPlace(doc, fieldKey + "-address", formatted_address, true);
             }
         });
         return true;
     }
 
-    private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, doc: Doc) => {
+    private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, fieldKey: string, doc: Doc) => {
         const response = await query({ lat: NumCast(newLat), lng: NumCast(newLng) });
         if (!response || response.status === "ZERO_RESULTS") {
             return false;
         }
         const { formatted_address } = response.results[0];
-        if (formatted_address !== doc["mapLocation-address"]) {
+        if (formatted_address !== doc[fieldKey + "-address"]) {
             this._cancelAddrReq.set(doc[Id], true);
-            Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true);
+            Doc.SetInPlace(doc, fieldKey + "-address", formatted_address, true);
         }
         return true;
     }
@@ -167,7 +166,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                         if (this._cancelLocReq.get(id)) {
                             this._cancelLocReq.set(id, false);
                         } else if (lat !== undefined && lng !== undefined) {
-                            this.respondToLocationChange(lat, lng, layout).then(success => {
+                            this.respondToLocationChange(lat, lng, "mapLocation", layout).then(success => {
                                 if (!success) {
                                     this._cancelLocReq.set(id, true);
                                     runInAction(() => {
@@ -185,7 +184,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                         if (this._cancelAddrReq.get(id)) {
                             this._cancelAddrReq.set(id, false);
                         } else if (newValue?.length) {
-                            this.respondToAddressChange(newValue, layout).then(success => {
+                            this.respondToAddressChange(newValue, "mapLocation", layout).then(success => {
                                 if (!success) {
                                     this._cancelAddrReq.set(id, true);
                                     layout["mapLocation-address"] = oldValue;
-- 
cgit v1.2.3-70-g09d2


From 531aab6465459557055c0c02e35b1029192263b4 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 15 Apr 2020 10:19:58 -0700
Subject: final cleanup

---
 src/client/views/collections/CollectionMapView.tsx | 83 +++++++++++-----------
 1 file changed, 42 insertions(+), 41 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 4fbccac33..062419b74 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -1,6 +1,6 @@
 import { GoogleApiWrapper, Map as GeoMap, MapProps, Marker } from "google-maps-react";
 import { observer } from "mobx-react";
-import { Doc, Opt, DocListCast, FieldResult } from "../../../new_fields/Doc";
+import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../new_fields/Doc";
 import { documentSchema } from "../../../new_fields/documentSchemas";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { makeInterface } from "../../../new_fields/Schema";
@@ -10,9 +10,8 @@ import { CollectionSubView } from "./CollectionSubView";
 import React = require("react");
 import { DocumentManager } from "../../util/DocumentManager";
 import { UndoManager, undoBatch } from "../../util/UndoManager";
-import { IReactionDisposer, reaction, computed, runInAction, Lambda } from "mobx";
+import { computed, runInAction, Lambda } from "mobx";
 import requestPromise = require("request-promise");
-import { emptyFunction } from "../../../Utils";
 
 type MapSchema = makeInterface<[typeof documentSchema]>;
 const MapSchema = makeInterface(documentSchema);
@@ -23,8 +22,14 @@ export type LocationData = google.maps.LatLngLiteral & {
     zoom?: number;
 };
 
+interface DocLatLng {
+    lat: FieldResult<Field>;
+    lng: FieldResult<Field>;
+}
+
 // Nowhere, Oklahoma
 const defaultLocation = { lat: 35.1592238, lng: -98.444512, zoom: 15 };
+const noResults = "ZERO_RESULTS";
 
 const query = async (data: string | google.maps.LatLngLiteral) => {
     const contents = typeof data === "string" ? `address=${data.replace(/\s+/g, "+")}` : `latlng=${data.lat},${data.lng}`;
@@ -42,8 +47,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     private _cancelAddrReq = new Map<string, boolean>();
     private _cancelLocReq = new Map<string, boolean>();
     private _initialLookupPending = new Map<string, boolean>();
-    private addressUpdaters: Lambda[] = [];
-    private latlngUpdaters: Lambda[] = [];
+    private responders: { location: Lambda, address: Lambda }[] = [];
 
     /**
      * Note that all the uses of runInAction below are not included
@@ -66,7 +70,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                 if (!this._initialLookupPending.get(id)) {
                     this._initialLookupPending.set(id, true);
                     setTimeout(() => {
-                        this.respondToAddressChange(address, doc).then(() => this._initialLookupPending.delete(id));
+                        this.respondToAddressChange(doc, address).then(() => this._initialLookupPending.delete(id));
                     });
                 }
                 return defaultLocation;
@@ -119,30 +123,45 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
             />;
     }
 
-    private respondToAddressChange = async (newAddress: string, doc: Doc) => {
+    private respondToAddressChange = async (doc: Doc, newAddress: string, oldAddress?: string) => {
+        if (newAddress === oldAddress) {
+            return false;
+        }
         const response = await query(newAddress);
-        if (!response || response.status === "ZERO_RESULTS") {
+        const id = doc[Id];
+        if (!response || response.status === noResults) {
+            this._cancelAddrReq.set(id, true);
+            doc["mapLocation-address"] = oldAddress;
             return false;
         }
         const { geometry, formatted_address } = response.results[0];
         const { lat, lng } = geometry.location;
         runInAction(() => {
             if (doc["mapLocation-lat"] !== lat || doc["mapLocation-lng"] !== lng) {
-                this._cancelLocReq.set(doc[Id], true);
+                this._cancelLocReq.set(id, true);
                 Doc.SetInPlace(doc, "mapLocation-lat", lat, true);
                 Doc.SetInPlace(doc, "mapLocation-lng", lng, true);
             }
             if (formatted_address !== newAddress) {
-                this._cancelAddrReq.set(doc[Id], true);
+                this._cancelAddrReq.set(id, true);
                 Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true);
             }
         });
         return true;
     }
 
-    private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, doc: Doc) => {
-        const response = await query({ lat: NumCast(newLat), lng: NumCast(newLng) });
-        if (!response || response.status === "ZERO_RESULTS") {
+    private respondToLocationChange = async (doc: Doc, newLatLng: DocLatLng, oldLatLng: Opt<DocLatLng>) => {
+        if (newLatLng === oldLatLng) {
+            return false;
+        }
+        const response = await query({ lat: NumCast(newLatLng.lat), lng: NumCast(newLatLng.lng) });
+        const id = doc[Id];
+        if (!response || response.status === noResults) {
+            this._cancelLocReq.set(id, true);
+            runInAction(() => {
+                doc["mapLocation-lat"] = oldLatLng?.lat;
+                doc["mapLocation-lng"] = oldLatLng?.lng;
+            });
             return false;
         }
         const { formatted_address } = response.results[0];
@@ -154,46 +173,28 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     }
 
     @computed get reactiveContents() {
-        this.addressUpdaters.forEach(disposer => disposer());
-        this.addressUpdaters = [];
-        this.latlngUpdaters.forEach(disposer => disposer());
-        this.latlngUpdaters = [];
+        this.responders.forEach(({ location, address }) => { location(); address(); });
+        this.responders = [];
         return this.childLayoutPairs.map(({ layout }) => {
             const id = layout[Id];
-            this.addressUpdaters.push(
-                computed(() => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] }))
+            this.responders.push({
+                location: computed(() => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] }))
                     .observe(({ oldValue, newValue }) => {
-                        const { lat, lng } = newValue;
                         if (this._cancelLocReq.get(id)) {
                             this._cancelLocReq.set(id, false);
-                        } else if (lat !== undefined && lng !== undefined) {
-                            this.respondToLocationChange(lat, lng, layout).then(success => {
-                                if (!success) {
-                                    this._cancelLocReq.set(id, true);
-                                    runInAction(() => {
-                                        layout["mapLocation-lat"] = oldValue ? oldValue.lat : undefined;
-                                        layout["mapLocation-lng"] = oldValue ? oldValue.lng : undefined;
-                                    });
-                                }
-                            });
+                        } else if (newValue.lat !== undefined && newValue.lng !== undefined) {
+                            this.respondToLocationChange(layout, newValue, oldValue);
                         }
-                    })
-            );
-            this.latlngUpdaters.push(
-                computed(() => Cast(layout["mapLocation-address"], "string", null))
+                    }),
+                address: computed(() => Cast(layout["mapLocation-address"], "string", null))
                     .observe(({ oldValue, newValue }) => {
                         if (this._cancelAddrReq.get(id)) {
                             this._cancelAddrReq.set(id, false);
                         } else if (newValue?.length) {
-                            this.respondToAddressChange(newValue, layout).then(success => {
-                                if (!success) {
-                                    this._cancelAddrReq.set(id, true);
-                                    layout["mapLocation-address"] = oldValue;
-                                }
-                            });
+                            this.respondToAddressChange(layout, newValue, oldValue);
                         }
                     })
-            );
+            });
             return this.renderMarker(layout);
         });
     }
-- 
cgit v1.2.3-70-g09d2


From 9a2d00da67b0436d28dd64f8a25aa8a2b1a5140d Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 15 Apr 2020 10:40:07 -0700
Subject: syntax

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

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 1d8ad2458..b5043d1c5 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -207,7 +207,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
         const { Document, fieldKey, active, google } = this.props;
         let center = this.getLocation(Document, `${fieldKey}-mapCenter`);
         if (center === undefined) {
-            center = childLayoutPairs.map(pair => this.getLocation(pair.layout, fieldKey)).find(layout => layout);
+            center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey)).find(layout => layout);
             if (center === undefined) {
                 center = defaultLocation;
             }
-- 
cgit v1.2.3-70-g09d2


From da6d058cd842209bdfd0f618e1cc19c99139135b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 15 Apr 2020 14:14:57 -0400
Subject: improved title support for map entries using @ to reset address. 
 added lockedPosition support for maps... kinda.

---
 src/client/views/collections/CollectionMapView.tsx | 43 ++++++++++++++--------
 1 file changed, 28 insertions(+), 15 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 583594057..f533a3874 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -1,5 +1,5 @@
 import { GoogleApiWrapper, Map as GeoMap, MapProps, Marker } from "google-maps-react";
-import { computed, Lambda, runInAction } from "mobx";
+import { computed, Lambda, runInAction, action } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, DocListCast, FieldResult, Opt } from "../../../new_fields/Doc";
 import { documentSchema } from "../../../new_fields/documentSchemas";
@@ -54,22 +54,22 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
 
     private getLocation = (doc: Opt<Doc>, fieldKey: string): Opt<LocationData> => {
         if (doc) {
-            const lat: Opt<number> = Cast(doc[fieldKey + "-lat"], "number", null) || (Cast(doc[fieldKey + "-lat"], "string", null) && Number(Cast(doc[fieldKey + "-lat"], "string", null))) || undefined;
-            const lng: Opt<number> = Cast(doc[fieldKey + "-lng"], "number", null) || (Cast(doc[fieldKey + "-lng"], "string", null) && Number(Cast(doc[fieldKey + "-lng"], "string", null))) || undefined;
-            const zoom: Opt<number> = Cast(doc[fieldKey + "-zoom"], "number", null) || (Cast(doc[fieldKey + "-zoom"], "string", null) && Number(Cast(doc[fieldKey + "-zoom"], "string", null))) || undefined;
-            const address: Opt<string> = Cast(doc[fieldKey + "-address"], "string", (lat === undefined || lng === undefined ? Cast(doc.title, "string", null) : null));
-            if (lat !== undefined && lng !== undefined) {
-                return ({ lat, lng, zoom });
-            } else if (address) {
+            const titleLoc = StrCast(doc.title).startsWith("@") ? StrCast(doc.title).substring(1) : undefined;
+            const lat = Cast(doc[fieldKey + "-lat"], "number", null) || (Cast(doc[fieldKey + "-lat"], "string", null) && Number(Cast(doc[fieldKey + "-lat"], "string", null))) || undefined;
+            const lng = Cast(doc[fieldKey + "-lng"], "number", null) || (Cast(doc[fieldKey + "-lng"], "string", null) && Number(Cast(doc[fieldKey + "-lng"], "string", null))) || undefined;
+            const zoom = Cast(doc[fieldKey + "-zoom"], "number", null) || (Cast(doc[fieldKey + "-zoom"], "string", null) && Number(Cast(doc[fieldKey + "-zoom"], "string", null))) || undefined;
+            const address = titleLoc || StrCast(doc[fieldKey + "-address"], StrCast(doc.title));
+            if (titleLoc || (address && (lat === undefined || lng === undefined))) {
                 const id = doc[Id];
                 if (!this._initialLookupPending.get(id)) {
-                    this._initialLookupPending.set(id, true); ``
+                    this._initialLookupPending.set(id, true);
                     setTimeout(() => {
+                        titleLoc && Doc.SetInPlace(doc, "title", titleLoc, true);
                         this.respondToAddressChange(address, fieldKey, doc).then(() => this._initialLookupPending.delete(id));
                     });
                 }
-                return defaultLocation;
             }
+            return (lat === undefined || lng === undefined) ? defaultLocation : { lat, lng, zoom };
         }
         return undefined;
     }
@@ -217,12 +217,25 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                     zoom={center.zoom || 10}
                     initialCenter={center}
                     center={center}
+                    onIdle={(_props: any, map: any) => {
+                        if (this.layoutDoc.lockedTransform) {
+                            map.setZoom(center?.zoom || 10);
+                        } else {
+                            center?.zoom !== map.getZoom() && undoBatch(action(() => {
+                                Document[fieldKey + "-mapCenter-zoom"] = map.getZoom();
+                            }))();
+                        }
+                    }}
                     onDragend={undoBatch((_props: MapProps, map: google.maps.Map) => {
-                        const { lat, lng } = map.getCenter();
-                        runInAction(() => {
-                            Document[fieldKey + "-mapCenter-lat"] = lat();
-                            Document[fieldKey + "-mapCenter-lng"] = lng();
-                        });
+                        if (this.layoutDoc.lockedTransform) {
+                            center?.lat && center.lng && map.setCenter(center);
+                        } else {
+                            const { lat, lng } = map.getCenter();
+                            runInAction(() => {
+                                Document[fieldKey + "-mapCenter-lat"] = lat();
+                                Document[fieldKey + "-mapCenter-lng"] = lng();
+                            });
+                        }
                     })}
                 >
                     {this.reactiveContents}
-- 
cgit v1.2.3-70-g09d2


From 4d1782cbb359de2b672786df24985fbcf4be238a Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 15 Apr 2020 14:49:57 -0400
Subject: fixed bug just added with initial location of map

---
 src/client/views/collections/CollectionMapView.tsx | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 3051b1ae7..2cb25fd9a 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -57,13 +57,13 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
      * and address–updating reactions. 
      */
 
-    private getLocation = (doc: Opt<Doc>, fieldKey: string): Opt<LocationData> => {
+    private getLocation = (doc: Opt<Doc>, fieldKey: string, returnDefault: boolean = true): Opt<LocationData> => {
         if (doc) {
             const titleLoc = StrCast(doc.title).startsWith("@") ? StrCast(doc.title).substring(1) : undefined;
             const lat = Cast(doc[`${fieldKey}-lat`], "number", null) || (Cast(doc[`${fieldKey}-lat`], "string", null) && Number(Cast(doc[`${fieldKey}-lat`], "string", null))) || undefined;
             const lng = Cast(doc[`${fieldKey}-lng`], "number", null) || (Cast(doc[`${fieldKey}-lng`], "string", null) && Number(Cast(doc[`${fieldKey}-lng`], "string", null))) || undefined;
             const zoom = Cast(doc[`${fieldKey}-zoom`], "number", null) || (Cast(doc[`${fieldKey}-zoom`], "string", null) && Number(Cast(doc[`${fieldKey}-zoom`], "string", null))) || undefined;
-            const address = titleLoc || StrCast(doc[`${fieldKey}-address`], StrCast(doc.title));
+            const address = titleLoc || StrCast(doc[`${fieldKey}-address`], StrCast(doc.title).replace(/^-/, ""));
             if (titleLoc || (address && (lat === undefined || lng === undefined))) {
                 const id = doc[Id];
                 if (!this._initialLookupPending.get(id)) {
@@ -74,7 +74,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                     });
                 }
             }
-            return (lat === undefined || lng === undefined) ? defaultLocation : { lat, lng, zoom };
+            return (lat === undefined || lng === undefined) ? (returnDefault ? defaultLocation : undefined) : { lat, lng, zoom };
         }
         return undefined;
     }
@@ -205,9 +205,9 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     render() {
         const { childLayoutPairs } = this;
         const { Document, fieldKey, active, google } = this.props;
-        let center = this.getLocation(Document, `${fieldKey}-mapCenter`);
+        let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false);
         if (center === undefined) {
-            center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey)).find(layout => layout);
+            center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey, false)).find(layout => layout);
             if (center === undefined) {
                 center = defaultLocation;
             }
-- 
cgit v1.2.3-70-g09d2


From 7d3b2880bebf034607b946360c3e08338cf1d115 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 15 Apr 2020 14:04:13 -0700
Subject: fixed fieldKey errors:

---
 src/client/views/collections/CollectionMapView.tsx | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 2cb25fd9a..c80555a2e 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -99,8 +99,9 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     }
 
     private renderMarkerIcon = (layout: Doc) => {
-        const { Document, fieldKey } = this.props;
-        const iconUrl = StrCast(Document.mapIconUrl, null);
+        const { Document } = this.props;
+        const fieldKey = Doc.LayoutFieldKey(layout);
+        const iconUrl = StrCast(layout.mapIconUrl, StrCast(Document.mapIconUrl));
         if (iconUrl) {
             const iconWidth = NumCast(layout[`${fieldKey}-iconWidth`], 45);
             const iconHeight = NumCast(layout[`${fieldKey}-iconHeight`], 45);
@@ -114,7 +115,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     }
 
     private renderMarker = (layout: Doc) => {
-        const location = this.getLocation(layout, this.props.fieldKey);
+        const location = this.getLocation(layout, Doc.LayoutFieldKey(layout));
         return !location ? (null) :
             <Marker
                 key={layout[Id]}
@@ -175,10 +176,10 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
     }
 
     @computed get reactiveContents() {
-        const { fieldKey } = this.props;
         this.responders.forEach(({ location, address }) => { location(); address(); });
         this.responders = [];
         return this.childLayoutPairs.map(({ layout }) => {
+            const fieldKey = Doc.LayoutFieldKey(layout);
             const id = layout[Id];
             this.responders.push({
                 location: computed(() => ({ lat: layout[`${fieldKey}-lat`], lng: layout[`${fieldKey}-lng`] }))
@@ -207,7 +208,7 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
         const { Document, fieldKey, active, google } = this.props;
         let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false);
         if (center === undefined) {
-            center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey, false)).find(layout => layout);
+            center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false)).find(layout => layout);
             if (center === undefined) {
                 center = defaultLocation;
             }
-- 
cgit v1.2.3-70-g09d2


From 35a31253ed3c7f4d31cebc2d1f2d6b1b4084108c Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 15 Apr 2020 22:27:38 -0700
Subject: cleanup

---
 src/client/views/collections/CollectionMapView.tsx | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index c80555a2e..7b7828d7d 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -208,10 +208,8 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
         const { Document, fieldKey, active, google } = this.props;
         let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false);
         if (center === undefined) {
-            center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false)).find(layout => layout);
-            if (center === undefined) {
-                center = defaultLocation;
-            }
+            const childLocations = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false));
+            center = childLocations.find(location => location) || defaultLocation;
         }
         return <div className="collectionMapView" ref={this.createDashEventsTarget}>
             <div className={"collectionMapView-contents"}
@@ -225,17 +223,20 @@ class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> &
                     center={center}
                     onIdle={(_props?: MapProps, map?: google.maps.Map) => {
                         if (this.layoutDoc.lockedTransform) {
-                            map?.setZoom(center?.zoom || 10); // reset zoom (probably can tell the map to disallow zooming somehow)
+                            // reset zoom (ideally, we could probably can tell the map to disallow zooming somehow instead)
+                            map?.setZoom(center?.zoom || 10);
+                            map?.setCenter({ lat: center?.lat!, lng: center?.lng! });
                         } else {
                             const zoom = map?.getZoom();
-                            center?.zoom !== zoom && undoBatch(action(() => {
+                            (center?.zoom !== zoom) && undoBatch(action(() => {
                                 Document[`${fieldKey}-mapCenter-zoom`] = zoom;
                             }))();
                         }
                     }}
                     onDragend={(_props?: MapProps, map?: google.maps.Map) => {
                         if (this.layoutDoc.lockedTransform) {
-                            map?.setCenter({ lat: center?.lat!, lng: center?.lng! }); // reset the drag (probably can tell the map to disallow dragging somehow)
+                            // reset the drag (ideally, we could probably can tell the map to disallow dragging somehow instead)
+                            map?.setCenter({ lat: center?.lat!, lng: center?.lng! });
                         } else {
                             undoBatch(action(({ lat, lng }) => {
                                 Document[`${fieldKey}-mapCenter-lat`] = lat();
-- 
cgit v1.2.3-70-g09d2

