Fixing a regression where clicking a marker to change the active
destination would no longer open the associated info window

Disabling autocomplete once locations have been selected

Change-Id: I5fadd9f42a6b71bd0b015f4839ec6b4b75a00b4c
diff --git a/src/components/destination.js b/src/components/destination.js
index 8a3933a..8071162 100644
--- a/src/components/destination.js
+++ b/src/components/destination.js
@@ -62,6 +62,8 @@
     set: function(placeDesc, updateSearchBox) {
       var normalized = this.normalizeDestination(placeDesc);
 
+      this.setAutocomplete(!normalized);
+
       if (normalized && updateSearchBox !== false) {
         this.$searchBox.prop('value', normalized.display);
       }
@@ -71,6 +73,36 @@
     }
   },
 
+  privates: {
+    /**
+     * This is a bit of a hack; Maps API does not include functionality to
+     * disable autocomplete.
+     */
+    setAutocomplete: function(autocomplete) {
+      if (this.autocomplete !== autocomplete) {
+        this.autocomplete = autocomplete;
+
+        var oldBox = this.$searchBox[autocomplete? 1 : 0],
+            newBox = this.$searchBox[autocomplete? 0 : 1];
+
+        newBox.value = oldBox.value;
+        var active = global.document &&
+          global.document.activeElement === oldBox;
+        newBox.setSelectionRange(oldBox.selectionStart, oldBox.selectionEnd);
+
+        if (autocomplete) {
+          this.$.addClass('autocomplete');
+        } else {
+          this.$.removeClass('autocomplete');
+        }
+
+        if (active) {
+          $(newBox).focus();
+        }
+      }
+    }
+  },
+
   events: [
     /**
      * @param event jQuery Event object for text box focus event.
@@ -92,10 +124,14 @@
   init: function(maps, placeholder, initial) {
     var destination = this;
 
-    var $searchBox = $('<input>')
-      .attr('type', 'text');
+    var $searchBox = $.merge($('<input>'), $('<input>'))
+      .attr('type', 'text')
+      //to make dummy box consistent with search
+      .attr('autocomplete', 'off');
     this.$searchBox = $searchBox;
 
+    $searchBox[0].className = 'autocomplete';
+
     this.setPlaceholder(placeholder);
 
     if (initial) {
@@ -107,18 +143,18 @@
       destination.set(null, false);
     });
 
-    this.$ = $('<div>').addClass('destination')
+    this.$ = $('<div>')
+      .addClass('destination')
+      .addClass('autocomplete')
       .append($searchBox);
 
     this.searchBox = new maps.places.SearchBox($searchBox[0]);
 
+    this.autocomplete = true;
+
     maps.event.addListener(this.searchBox, 'places_changed', function() {
       destination.onSearch(destination.searchBox.getPlaces());
     });
-
-    /* TODO(rosswang): can we for the love of squirrels stop the autocomplete
-     * from popping up after a location has been selected through a map click?
-     */
   }
 });
 
diff --git a/src/components/maps.js b/src/components/maps.js
index f63f893..83a4131 100644
--- a/src/components/maps.js
+++ b/src/components/maps.js
@@ -26,13 +26,16 @@
       }
     },
 
-    deselectDestinationControl: function() {
+    deselectDestinationControl: function(closeInfoWindow) {
       if (this.selectedDestinationControl) {
         this.selectedDestinationControl.deselectControl();
         this.selectedDestinationControl = null;
         this.disableLocationSelection();
         this.clearSearchMarkers();
-        this.closeActiveInfoWindow();
+
+        if (closeInfoWindow !== false) {
+          this.closeActiveInfoWindow();
+        }
       }
     },
 
@@ -78,11 +81,15 @@
     },
 
     createDestinationMarker: function(normalizedPlace, destinationControl) {
+      var widget = this;
+
       var marker = this.createMarker(normalizedPlace, destinationControl,
         this.getAppropriateDestinationMarkerColor(destinationControl));
       destinationControl.marker = marker;
-      marker.onClick.add(
-        $.proxy(this, 'selectDestinationControl', destinationControl));
+
+      marker.onClick.add(function() {
+        widget.selectDestinationControl(destinationControl, false);
+      });
 
       return marker;
     },
@@ -108,6 +115,8 @@
         return;
       }
 
+      var widget = this;
+
       if (destination.marker) {
         destination.marker.removeClient(destination);
       }
@@ -117,8 +126,9 @@
       if (marker) {
         marker.pushClient(destination,
           this.getAppropriateDestinationMarkerColor(destination));
-        marker.onClick.add(
-          $.proxy(this, 'selectDestinationControl', destination));
+        marker.onClick.add(function() {
+          widget.selectDestinationControl(destination, false);
+        });
       }
     },
 
@@ -170,6 +180,7 @@
     },
 
     bindDestinationControl: function (destination) {
+      var widget = this;
       var maps = this.maps;
       var map = this.map;
 
@@ -177,8 +188,9 @@
         destination.setSearchBounds(map.getBounds());
       });
 
-      destination.onFocus.add(
-        $.proxy(this, 'selectDestinationControl', destination));
+      destination.onFocus.add(function() {
+        widget.selectDestinationControl(destination);
+      });
       destination.onSearch.add($.proxy(this, 'showDestinationSearchResults'));
       destination.onSet.add($.proxy(this, 'handleDestinationSet', destination));
     },
@@ -193,13 +205,13 @@
       this.locationSelectionEnabled = false;
     },
 
-    selectDestinationControl: function(dest) {
+    selectDestinationControl: function(dest, closeInfoWindow) {
       if (dest !== this.selectedDestinationControl) {
         var prevDest = this.selectedDestinationControl;
         if (prevDest && prevDest.marker) {
           prevDest.marker.setColor(DestinationMarker.color.BLUE);
         }
-        this.deselectDestinationControl();
+        this.deselectDestinationControl(closeInfoWindow);
 
         this.selectedDestinationControl = dest;
         dest.selectControl();
diff --git a/src/static/index.css b/src/static/index.css
index 5b4a733..70e3946 100644
--- a/src/static/index.css
+++ b/src/static/index.css
@@ -19,6 +19,22 @@
   padding: 8px 16px;
 }
 
+.destination input {
+  display: initial;
+}
+
+.destination input.autocomplete {
+  display: none;
+}
+
+.destination.autocomplete input {
+  display: none;
+}
+
+.destination.autocomplete input.autocomplete {
+  display: initial;
+}
+
 .destination-info .title {
   font-weight: 500;
   font-size: 14px;