diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5d0cea400..42cfd2668 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,27 +1,33 @@ #Angularjs-Google-Maps Is Only Possible By; - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## We Love You All diff --git a/README.md b/README.md index 401b3cb8b..420cc4575 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -GoogleMap AngularJS Directive +Google Maps AngularJS Directive =============================

module: undefined +

  • Index

    GoogleMap AngularJS Directive

    module: undefined +

  • Index

    Google Maps AngularJS Directive

    Demo
    Documentation
    Road Trip By StreetView
    Maps Can Talk | Custom Marker

    -

    If you like this, you also may like these;

    +

    If you like this, you also may like these:

    -

    Background

    There is already one for this. However, I found myself doing totally different approach than the existing one, such as;

    +

    Background

    There is already one for this. However, I found myself taking a totally different approach than the existing one, such as:

      -
    1. Everything in tag and attributes.
      Thus, basic users don't even have to know what Javascript is.

      +
    2. Everything in tag and attributes.
      Thus, users don't even need knowledge of JavaScript.

    3. -
    4. Expose all original Google Maps V3 api to the user.
      No hiding, no wraping, or whatsoever. +

    5. Expose all original Google Maps V3 API to the user.
      No hiding, no wrapping or whatsoever. By doing so, programmers don't need to learn how to use this module. You only need to know Google Maps V3 API.

    There is a blog that introduces this module. The title of it is 'Google Map As The Simplest Way'

    -

    To Get Started

    For Bower users,

    +

    To get started

    For Bower users,

    $ bower install ngmap

    1. Include ng-map.min.js: <script src="/bower_components/ngmap/build/scripts/ng-map.min.js"></script>

    2. -
    3. Include Google maps:
      <script src="http://maps.google.com/maps/api/js"></script>

      +
    4. Include Google Maps:
      <script src="http://maps.google.com/maps/api/js"></script>

    5. -
    6. Name your angular app ngMap, or add it as a dependency

      +
    7. Name your AngularJS app ngMap, or add it as a dependency

      var myApp = angular.module('myApp', ['ngMap']);

    @@ -37,10 +37,10 @@

    To Get Started

    For Bower users,

    console.log('markers', map.markers); console.log('shapes', map.shapes); }); -});

    For npm users,

    +});

    For npm users,

    $ npm install ngmap

    -

    For meteor users: https://atmospherejs.com/wormy/angularjs-google-maps

    -

    Lazy Loading of Google Maps Javascript

    Simply wrap the map tag with map-lazy-load="https://maps.google.com/maps/api/js".

    +

    For Meteor users: https://atmospherejs.com/wormy/angularjs-google-maps

    +

    Lazy loading of Google Maps JavaScript

    Simply wrap the map tag with map-lazy-load="https://maps.google.com/maps/api/js".

    <div map-lazy-load="https://maps.google.com/maps/api/js">
       <ng-map center="41,-87" zoom="3"></ng-map>
     </div>

    If you need to pass in an API key to the javascript, you can set a scope @@ -49,7 +49,7 @@

    Lazy Loading of Google Maps Javascript

    Simply wrap the map tag with

    <div map-lazy-load="https://maps.google.com/maps/api/js"
       map-lazy-load-params="{{googleMapsUrl}}">
       <ng-map center="41,-87" zoom="3"></ng-map>
    -</div>

    FAQ

    Grey area in Google maps

    The usual reason why this is happening is that the size of the map is changed after the map has been initialized. If you for some reason change the size of the div, you need to trigger the "resize" event and possible reCenter the map.

    +</div>

    FAQ

    Grey area in Google Maps

    The usual reason why this happens is that the size of the map is changed after the map has been initialized. If you for some reason change the size of the div, you need to trigger the "resize" event and possible recenter the map.

     var center = map.getCenter();
      google.maps.event.trigger(map, "resize");
      map.setCenter(center);

    Ref.

    @@ -57,6 +57,19 @@

    Lazy Loading of Google Maps Javascript

    Simply wrap the map tag with

  • http://stackoverflow.com/questions/13901520/grey-area-in-google-maps
  • http://blog.codebusters.pl/en/google-maps-in-hidden-div/
  • +

    Check if a marker is within Map, Rectangle, or Circle

    `map.getBounds().contains(marker.getPosition());`
      +
    • http://stackoverflow.com/questions/3648545/how-can-i-check-the-marker-is-or-isnt-in-the-bounds-using-google-maps-v3
    • +
    • https://developers.google.com/maps/documentation/javascript/3.exp/reference#Map
    • +
    • https://developers.google.com/maps/documentation/javascript/3.exp/reference#Rectangle
    • +
    • https://developers.google.com/maps/documentation/javascript/3.exp/reference#Circle
    • +
    +

    Calculate distance between two position

    You can check this out: https://developers.google.com/maps/documentation/javascript/distancematrix. +As you see, DistanceMatrix does not require map nor directive.

    +

    Another way to do this, is to use directions directive. As you see it here: https://rawgit.com/allenhwkim/angularjs-google-maps/master/testapp/directions2.html, you have access to DirectionsRenderer by using map.directionsRenderers[id]

    +

    https://developers.google.com/maps/documentation/javascript/reference?hl=en#DirectionsRenderer

    +

    You use getDirections() or directions, then calculate the distance from there. e.g.,

    +

    Distance: + {{ map.directionsRenderers[0].directions.routes[0].legs[0].distance }}

    Directives

    • bicycling-layer
    • custom-control
    • @@ -82,7 +95,7 @@

      Directives

      • traffic-layer
      • transit-layer
      -

      Advanced Examples

        +

        Advanced examples

        • Marker Clusterer
        • Starbucks World Wide
        • Road Trip By StreetView
        • @@ -90,13 +103,13 @@

          Advanced Examples

          Contributors

          Contributing

            -
          • Clone the repository from github
          • -
          • Change to the folder dowloaded
          • +
          • Clone the repository from GitHub.
          • +
          • Change to the cloned directory.
          • npm install to install the build tools
          • -
          • gulp build to build the javascript & doc files in the /build folder & run the unit tests.
          • -
          • gulp clean to cleanup the repository by removing files and folders from previous build.
          • +
          • gulp build to build the JavaScript & doc files in the /build folder & run the unit tests.
          • +
          • gulp clean to clean up the repository by removing files and folders from previous build.
          • gulp test to run the Karma unit test suite.
          • gulp test:e2e to run the Protractor test suite. For the first test run, you may need to update the protractor webdriver manager. It will show the command on screen if this is required (node_modules/gulp-protractor/node_modules/protractor/bin/webdriver-manager update).
          • gulp test:server will start a web server for the testapp on http://localhost:8888
          -

          license

          MIT License

    \ No newline at end of file +

    License

    MIT License

    \ No newline at end of file diff --git a/build/docs/marker.html b/build/docs/marker.html index a69c0d72e..ad93f21b1 100644 --- a/build/docs/marker.html +++ b/build/docs/marker.html @@ -1,26 +1,304 @@ - JSDoc: marker

    Angular directive

    marker source

    Description

    Draw a Google map marker on a map with given options and register events

    + + + + + JSDoc: marker + + + + + +
    +

    + Angular directive +

    +

    + marker + source +

    +
    + + + +
    +
    +
      +
    +
    +
    +

    Description

    +

    Draw a Google map marker on a map with given options and register events

    Requires: map directive

    -

    Restrict To: Element

    Attributes

    + + + + + + + + + + +
    NameTypeDescription
    position String

    address, 'current', or [latitude, longitude] +

    Restrict To: Element

    + +
    +
    +

    Attributes

    + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    position + String + + +

    address, 'current', or [latitude, longitude] example: '1600 Pennsylvania Ave, 20500 Washingtion DC', 'current position', '[40.74, -74.18]'

    -
    centered Boolean

    if set, map will be centered with this marker

    -
    geo-callback Expression

    if position is an address, + +

    centered + Boolean + + +

    if set, map will be centered with this marker

    +
    +
    geo-callback + Expression + + +

    if position is an address, the expression is will be performed when geo-lookup is successful. e.g., geo-callback="showStoreInfo()"

    -
    no-watcher Boolean

    if true, no attribute observer is added. + +

    no-watcher + Boolean + + +

    if true, no attribute observer is added. Useful for many ng-repeat

    -
    <MarkerOption> String

    Any Marker options

    -
    <MapEvent> String

    Any Marker events

    -

    Example

    Usage:
    +            
    +          
    <MarkerOption> + String + + +

    Any Marker options

    +
    +
    <MapEvent> + String + + +

    Any Marker events

    +
    +
    +
    +
    +

    Example

    +
    Usage:
       <map MAP_ATTRIBUTES>
        <marker ANY_MARKER_OPTIONS ANY_MARKER_EVENTS"></MARKER>
       </map>
     Example:
       <map center="[40.74, -74.18]">
    -   <marker position="[40.74, -74.18]" on-click="myfunc()"></div>
    +   <marker position="[40.74, -74.18]" on-click="myfunc()"></marker>
       </map>
       <map center="the cn tower">
    -   <marker position="the cn tower" on-click="myfunc()"></div>
    -  </map>
    \ No newline at end of file + <marker position="the cn tower" on-click="myfunc()"></marker> + </map> +
    +
    +
    +
    + +
    + + + + + + + diff --git a/build/docs/shape.html b/build/docs/shape.html index a9c12fb4b..1903b157e 100644 --- a/build/docs/shape.html +++ b/build/docs/shape.html @@ -18,7 +18,7 @@ <MapEvent> String

    Any Shape events

    Example

    Usage:
       <map MAP_ATTRIBUTES>
    -   <shape name=SHAPE_NAME ANY_SHAPE_OPTIONS ANY_SHAPE_EVENTS"></MARKER>
    +   <shape name="SHAPE_NAME ANY_SHAPE_OPTIONS ANY_SHAPE_EVENTS"></shape>
       </map>
     Example:
       <map zoom="11" center="[40.74, -74.18]">
    diff --git a/build/docs/source/custom-control.html b/build/docs/source/custom-control.html
    index 46dd0b9f5..9a9720bc2 100644
    --- a/build/docs/source/custom-control.html
    +++ b/build/docs/source/custom-control.html
    @@ -33,12 +33,18 @@
         var filtered = parser.filter(attrs);
         var options = parser.getOptions(filtered, {scope: scope});
         var events = parser.getEvents(scope, filtered);
    +    var innerScope = scope.$new();
         /**
          * build a custom control element
          */
         var customControlEl = element[0].parentElement.removeChild(element[0]);
    -    var content = $transclude();
    -    angular.element(customControlEl).append(content);
    +    var content = $transclude( innerScope, function( clone ) {
    +      element.empty();
    +      element.append( clone );
    +      element.on( '$destroy', function() {
    +        innerScope.$destroy();
    +      });
    +    });
         /**
          * set events
          */
    diff --git a/build/docs/source/directions.html b/build/docs/source/directions.html
    index b84db5aa4..e29b08568 100644
    --- a/build/docs/source/directions.html
    +++ b/build/docs/source/directions.html
    @@ -29,6 +29,11 @@
     (function() {
       'use strict';
       var NgMap, $timeout, NavigatorGeolocation;
    +  var requestTimeout, routeRequest;
    +  // Delay for each route render to accumulate all requests into a single one
    +  // This is required for simultaneous origin\waypoints\destination change
    +  // 20ms should be enough to merge all request data
    +  var routeRenderDelay = 20;
       var getDirectionsRenderer = function(options, events) {
         if (options.panel) {
           options.panel = document.getElementById(options.panel) ||
    @@ -50,25 +55,49 @@
           'durationInTraffic', 'waypoints', 'optimizeWaypoints', 
           'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region'
         ];
    -    for(var key in request){
    -      (validKeys.indexOf(key) === -1) && (delete request[key]);
    +    if (request) {
    +      for(var key in request) {
    +        if (request.hasOwnProperty(key)) {
    +          (validKeys.indexOf(key) === -1) && (delete request[key]);
    +        }
    +      }
         }
         if(request.waypoints) {
    -      // Check fo valid values
    -      if(request.waypoints == "[]" || request.waypoints === "") {
    +      // Check for acceptable values
    +      if(!Array.isArray(request.waypoints)) {
             delete request.waypoints;
           }
         }
         var showDirections = function(request) {
    -      directionsService.route(request, function(response, status) {
    -        if (status == google.maps.DirectionsStatus.OK) {
    -          $timeout(function() {
    -            renderer.setDirections(response);
    -          });
    +      if (requestTimeout && request) {
    +        if (!routeRequest) {
    +          routeRequest = request;
    +        } else {
    +          for (var attr in request) {
    +            if (request.hasOwnProperty(attr)) {
    +              routeRequest[attr] = request[attr];
    +            }
    +          }
             }
    -      });
    +      } else {
    +        requestTimeout = $timeout(function() {
    +          if (!routeRequest) {
    +            routeRequest = request;
    +          }
    +          directionsService.route(routeRequest, function(response, status) {
    +            if (status == google.maps.DirectionsStatus.OK) {
    +              renderer.setDirections(response);
    +              // Unset request for the next call
    +              routeRequest = undefined;
    +            }
    +          });
    +          $timeout.cancel(requestTimeout);
    +          // Unset expired timeout for the next call
    +          requestTimeout = undefined;
    +        }, routeRenderDelay);
    +      }
         };
    -    if (request.origin && request.destination) {
    +    if (request && request.origin && request.destination) {
           if (request.origin == 'current-location') {
             NavigatorGeolocation.getCurrentPosition().then(function(ll) {
               request.origin = new google.maps.LatLng(ll.coords.latitude, ll.coords.longitude);
    @@ -97,6 +126,10 @@
           var options = parser.getOptions(filtered, {scope: scope});
           var events = parser.getEvents(scope, filtered);
           var attrsToObserve = parser.getAttrsToObserve(orgAttrs);
    +      var attrsToObserve = [];
    +      if (!filtered.noWatcher) {
    +          attrsToObserve = parser.getAttrsToObserve(orgAttrs);
    +      }
           var renderer = getDirectionsRenderer(options, events);
           mapController.addObject('directionsRenderers', renderer);
           attrsToObserve.forEach(function(attrName) {
    diff --git a/build/docs/source/heatmap-layer.html b/build/docs/source/heatmap-layer.html
    index c5cf4c4b8..ec00e15bf 100644
    --- a/build/docs/source/heatmap-layer.html
    +++ b/build/docs/source/heatmap-layer.html
    @@ -27,7 +27,7 @@
              * set options
              */
             var options = parser.getOptions(filtered, {scope: scope});
    -        options.data = $window[attrs.data] || scope[attrs.data];
    +        options.data = $window[attrs.data] || parseScope(attrs.data, scope);
             if (options.data instanceof Array) {
               options.data = new google.maps.MVCArray(options.data);
             } else {
    @@ -40,6 +40,12 @@
             var events = parser.getEvents(scope, filtered);
             console.log('heatmap-layer options', layer, 'events', events);
             mapController.addObject('heatmapLayers', layer);
    +        //helper get nexted path
    +        function parseScope( path, obj ) {
    +            return path.split('.').reduce( function( prev, curr ) {
    +                return prev[curr];
    +            }, obj || this );
    +        }
           }
          }; // return
       }]);
    diff --git a/build/docs/source/info-window.html b/build/docs/source/info-window.html
    index 9d71331a6..d71126463 100644
    --- a/build/docs/source/info-window.html
    +++ b/build/docs/source/info-window.html
    @@ -105,8 +105,10 @@
                 } else {
                   infoWindow.open(map);
                 }
    -            var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement;
    -            infoWindowContainerEl.className = "ng-map-info-window";
    +            $timeout(function() { // to avoid racing condition
    +              var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement;
    +              infoWindowContainerEl.className = "ng-map-info-window";
    +            });
               });
             });
           };
    diff --git a/build/docs/source/ngmap.custom-marker.html b/build/docs/source/ngmap.custom-marker.html
    index bcd2d44a5..8ce9682da 100644
    --- a/build/docs/source/ngmap.custom-marker.html
    +++ b/build/docs/source/ngmap.custom-marker.html
    @@ -28,10 +28,20 @@
     (function() {
       'use strict';
       var parser, $timeout, $compile, NgMap;
    +  var supportedTransform = (function getSupportedTransform() {
    +    var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' ');
    +    var div = document.createElement('div');
    +    for(var i = 0; i < prefixes.length; i++) {
    +      if(div && div.style[prefixes[i]] !== undefined) {
    +        return prefixes[i];
    +      }
    +    }
    +    return false;
    +  })();
       var CustomMarker = function(options) {
         options = options || {};
         this.el = document.createElement('div');
    -    this.el.style.display = 'inline-block';
    +    this.el.style.display = 'block';
         this.el.style.visibility = "hidden";
         this.visible = true;
         for (var key in options) { /* jshint ignore:line */
    @@ -43,6 +53,8 @@
         CustomMarker.prototype.setContent = function(html, scope) {
           this.el.innerHTML = html;
           this.el.style.position = 'absolute';
    +      this.el.style.top = 0;
    +      this.el.style.left = 0;
           if (scope) {
             $compile(angular.element(this.el).contents())(scope);
           }
    @@ -66,8 +78,12 @@
               var posPixel = _this.getProjection().fromLatLngToDivPixel(_this.position);
               var x = Math.round(posPixel.x - (_this.el.offsetWidth/2));
               var y = Math.round(posPixel.y - _this.el.offsetHeight - 10); // 10px for anchor
    -          _this.el.style.left = x + "px";
    -          _this.el.style.top = y + "px";
    +          if (supportedTransform) {
    +            _this.el.style[supportedTransform] = "translate(" + x + "px, " + y + "px)";
    +          } else {
    +            _this.el.style.left = x + "px";
    +            _this.el.style.top = y + "px";
    +          }
               _this.el.style.visibility = "visible";
             };
             if (_this.el.offsetWidth && _this.el.offsetHeight) {
    @@ -79,14 +95,20 @@
           }
         };
         CustomMarker.prototype.setZIndex = function(zIndex) {
    -      zIndex && (this.zIndex = zIndex); /* jshint ignore:line */
    -      this.el.style.zIndex = this.zIndex;
    +      if (zIndex === undefined) return;
    +      (this.zIndex !== zIndex) && (this.zIndex = zIndex); /* jshint ignore:line */
    +      (this.el.style.zIndex !== this.zIndex) && (this.el.style.zIndex = this.zIndex);
         };
         CustomMarker.prototype.getVisible = function() {
           return this.visible;
         };
         CustomMarker.prototype.setVisible = function(visible) {
    -      this.el.style.display = visible ? 'inline-block' : 'none';
    +      if (this.el.style.display === 'none' && visible)
    +      {
    +          this.el.style.display = 'block';
    +      } else if (this.el.style.display !== 'none' && !visible) {
    +          this.el.style.display = 'none';
    +      }
           this.visible = visible;
         };
         CustomMarker.prototype.addClass = function(className) {
    @@ -127,24 +149,27 @@
           element[0].style.display = 'none';
           console.log("custom-marker options", options);
           var customMarker = new CustomMarker(options);
    -      $timeout(function() { //apply contents, class, and location after it is compiled
    -        scope.$watch('[' + varsToWatch.join(',') + ']', function() {
    +      // Do we really need a timeout with $scope.$apply() here?
    +      setTimeout(function() { //apply contents, class, and location after it is compiled
    +        scope.$watch('[' + varsToWatch.join(',') + ']', function(newVal, oldVal) {
               customMarker.setContent(orgHtml, scope);
             }, true);
             customMarker.setContent(element[0].innerHTML, scope);
    -        var classNames = element[0].firstElementChild.className;
    +        var classNames =
    +          (element[0].firstElementChild) && (element[0].firstElementChild.className || '');
    +        customMarker.class && (classNames += " " + customMarker.class);
             customMarker.addClass('custom-marker');
    -        customMarker.addClass(classNames);
    +        classNames && customMarker.addClass(classNames);
             console.log('customMarker', customMarker, 'classNames', classNames);
             if (!(options.position instanceof google.maps.LatLng)) {
               NgMap.getGeoLocation(options.position).then(
    -                function(latlng) {
    -                  customMarker.setPosition(latlng);
    -                }
    +            function(latlng) {
    +              customMarker.setPosition(latlng);
    +            }
               );
             }
           });
    -      console.log("custom-marker events", "events");
    +      console.log("custom-marker events", events);
           for (var eventName in events) { /* jshint ignore:line */
             google.maps.event.addDomListener(
               customMarker.el, eventName, events[eventName]);
    @@ -172,6 +197,7 @@
           restrict: 'E',
           require: ['?^map','?^ngMap'],
           compile: function(element) {
    +        console.log('el', element);
             setCustomMarker();
             element[0].style.display ='none';
             var orgHtml = element.html();
    diff --git a/build/docs/source/places-auto-complete.html b/build/docs/source/places-auto-complete.html
    index 913fe0e54..010cedb61 100644
    --- a/build/docs/source/places-auto-complete.html
    +++ b/build/docs/source/places-auto-complete.html
    @@ -14,6 +14,7 @@
      * Example:
      *   <script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
      *   <input places-auto-complete types="['geocode']" on-place-changed="myCallback(place)" component-restrictions="{country:'au'}"/>
    + *
      */
     /* global google */
     (function() {
    @@ -28,6 +29,7 @@
           var options = parser.getOptions(filtered, {scope: scope});
           var events = parser.getEvents(scope, filtered);
           var autocomplete = new google.maps.places.Autocomplete(element[0], options);
    +      autocomplete.setOptions({strictBounds: options.strictBounds === true});
           for (var eventName in events) {
             google.maps.event.addListener(autocomplete, eventName, events[eventName]);
           }
    @@ -38,17 +40,32 @@
           };
           google.maps.event.addListener(autocomplete, 'place_changed', updateModel);
           element[0].addEventListener('change', updateModel);
    +      attrs.$observe('rectBounds', function(val) {
    +        if (val) {
    +          var bounds = parser.toOptionValue(val, {key: 'rectBounds'});
    +          autocomplete.setBounds(new google.maps.LatLngBounds(
    +            new google.maps.LatLng(bounds.south_west.lat, bounds.south_west.lng),
    +            new google.maps.LatLng(bounds.north_east.lat, bounds.north_east.lng)));
    +          }
    +      });
    +      attrs.$observe('circleBounds', function(val) {
    +        if (val) {
    +          var bounds = parser.toOptionValue(val, {key: 'circleBounds'});
    +          var circle = new google.maps.Circle(bounds);
    +          autocomplete.setBounds(circle.getBounds());
    +        }
    +      });
           attrs.$observe('types', function(val) {
             if (val) {
               var optionValue = parser.toOptionValue(val, {key: 'types'});
               autocomplete.setTypes(optionValue);
             }
           });
    -	  attrs.$observe('componentRestrictions', function (val) {
    -		 if (val) {
    -		   autocomplete.setComponentRestrictions(scope.$eval(val));
    -		 }
    -	   });
    +      attrs.$observe('componentRestrictions', function (val) {
    +        if (val) {
    +          autocomplete.setComponentRestrictions(scope.$eval(val));
    +        }
    +      });
         };
         return {
           restrict: 'A',
    diff --git a/build/docs/source/shape.html b/build/docs/source/shape.html
    index a6c9fc05f..016e9764b 100644
    --- a/build/docs/source/shape.html
    +++ b/build/docs/source/shape.html
    @@ -29,7 +29,7 @@
      * @example
      * Usage:
      *   <map MAP_ATTRIBUTES>
    - *    <shape name=SHAPE_NAME ANY_SHAPE_OPTIONS ANY_SHAPE_EVENTS"></MARKER>
    + *    <shape name="SHAPE_NAME ANY_SHAPE_OPTIONS ANY_SHAPE_EVENTS"></shape>
      *   </map>
      *
      * Example:
    diff --git a/build/scripts/ng-map.debug.js b/build/scripts/ng-map.debug.js
    index 4cac90d77..cc7410fe0 100644
    --- a/build/scripts/ng-map.debug.js
    +++ b/build/scripts/ng-map.debug.js
    @@ -1,5 +1,5 @@
     /**
    - * AngularJS Google Maps Ver. 1.18.2
    + * AngularJS Google Maps Ver. 1.18.4
      *
      * The MIT License (MIT)
      * 
    @@ -196,7 +196,7 @@ angular.module('ngMap', []);
           }
     
           // set options
    -      mapOptions.zoom = mapOptions.zoom || 15;
    +      mapOptions.zoom = (mapOptions.zoom && !isNaN(mapOptions.zoom)) ? +mapOptions.zoom : 15;
           var center = mapOptions.center;
           var exprRegExp = new RegExp(escapeRegExp(exprStartSymbol) + '.*' + escapeRegExp(exprEndSymbol));
     
    @@ -411,13 +411,20 @@ angular.module('ngMap', []);
         var filtered = parser.filter(attrs);
         var options = parser.getOptions(filtered, {scope: scope});
         var events = parser.getEvents(scope, filtered);
    +    var innerScope = scope.$new();
     
         /**
          * build a custom control element
          */
         var customControlEl = element[0].parentElement.removeChild(element[0]);
    -    var content = $transclude();
    -    angular.element(customControlEl).append(content);
    +    var content = $transclude( innerScope, function( clone ) {
    +      element.empty();
    +      element.append( clone );
    +      element.on( '$destroy', function() {
    +        innerScope.$destroy();
    +      });
    +    });
    +    
     
         /**
          * set events
    @@ -481,11 +488,22 @@ angular.module('ngMap', []);
       'use strict';
       var parser, $timeout, $compile, NgMap;
     
    +  var supportedTransform = (function getSupportedTransform() {
    +    var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' ');
    +    var div = document.createElement('div');
    +    for(var i = 0; i < prefixes.length; i++) {
    +      if(div && div.style[prefixes[i]] !== undefined) {
    +        return prefixes[i];
    +      }
    +    }
    +    return false;
    +  })();
    +
       var CustomMarker = function(options) {
         options = options || {};
     
         this.el = document.createElement('div');
    -    this.el.style.display = 'inline-block';
    +    this.el.style.display = 'block';
         this.el.style.visibility = "hidden";
         this.visible = true;
         for (var key in options) { /* jshint ignore:line */
    @@ -500,6 +518,8 @@ angular.module('ngMap', []);
         CustomMarker.prototype.setContent = function(html, scope) {
           this.el.innerHTML = html;
           this.el.style.position = 'absolute';
    +      this.el.style.top = 0;
    +      this.el.style.left = 0;
           if (scope) {
             $compile(angular.element(this.el).contents())(scope);
           }
    @@ -527,8 +547,12 @@ angular.module('ngMap', []);
               var posPixel = _this.getProjection().fromLatLngToDivPixel(_this.position);
               var x = Math.round(posPixel.x - (_this.el.offsetWidth/2));
               var y = Math.round(posPixel.y - _this.el.offsetHeight - 10); // 10px for anchor
    -          _this.el.style.left = x + "px";
    -          _this.el.style.top = y + "px";
    +          if (supportedTransform) {
    +            _this.el.style[supportedTransform] = "translate(" + x + "px, " + y + "px)";
    +          } else {
    +            _this.el.style.left = x + "px";
    +            _this.el.style.top = y + "px";
    +          }
               _this.el.style.visibility = "visible";
             };
             if (_this.el.offsetWidth && _this.el.offsetHeight) {
    @@ -541,8 +565,9 @@ angular.module('ngMap', []);
         };
     
         CustomMarker.prototype.setZIndex = function(zIndex) {
    -      zIndex && (this.zIndex = zIndex); /* jshint ignore:line */
    -      this.el.style.zIndex = this.zIndex;
    +      if (zIndex === undefined) return;
    +      (this.zIndex !== zIndex) && (this.zIndex = zIndex); /* jshint ignore:line */
    +      (this.el.style.zIndex !== this.zIndex) && (this.el.style.zIndex = this.zIndex);
         };
     
         CustomMarker.prototype.getVisible = function() {
    @@ -550,7 +575,12 @@ angular.module('ngMap', []);
         };
     
         CustomMarker.prototype.setVisible = function(visible) {
    -      this.el.style.display = visible ? 'inline-block' : 'none';
    +      if (this.el.style.display === 'none' && visible)
    +      {
    +          this.el.style.display = 'block';
    +      } else if (this.el.style.display !== 'none' && !visible) {
    +          this.el.style.display = 'none';
    +      }
           this.visible = visible;
         };
     
    @@ -601,29 +631,32 @@ angular.module('ngMap', []);
           console.log("custom-marker options", options);
           var customMarker = new CustomMarker(options);
     
    -      $timeout(function() { //apply contents, class, and location after it is compiled
    +      // Do we really need a timeout with $scope.$apply() here?
    +      setTimeout(function() { //apply contents, class, and location after it is compiled
     
    -        scope.$watch('[' + varsToWatch.join(',') + ']', function() {
    +        scope.$watch('[' + varsToWatch.join(',') + ']', function(newVal, oldVal) {
               customMarker.setContent(orgHtml, scope);
             }, true);
     
             customMarker.setContent(element[0].innerHTML, scope);
    -        var classNames = element[0].firstElementChild.className;
    +        var classNames =
    +          (element[0].firstElementChild) && (element[0].firstElementChild.className || '');
    +        customMarker.class && (classNames += " " + customMarker.class);
             customMarker.addClass('custom-marker');
    -        customMarker.addClass(classNames);
    +        classNames && customMarker.addClass(classNames);
             console.log('customMarker', customMarker, 'classNames', classNames);
     
             if (!(options.position instanceof google.maps.LatLng)) {
               NgMap.getGeoLocation(options.position).then(
    -                function(latlng) {
    -                  customMarker.setPosition(latlng);
    -                }
    +            function(latlng) {
    +              customMarker.setPosition(latlng);
    +            }
               );
             }
     
           });
     
    -      console.log("custom-marker events", "events");
    +      console.log("custom-marker events", events);
           for (var eventName in events) { /* jshint ignore:line */
             google.maps.event.addDomListener(
               customMarker.el, eventName, events[eventName]);
    @@ -658,6 +691,7 @@ angular.module('ngMap', []);
           restrict: 'E',
           require: ['?^map','?^ngMap'],
           compile: function(element) {
    +        console.log('el', element);
             setCustomMarker();
             element[0].style.display ='none';
             var orgHtml = element.html();
    @@ -715,6 +749,12 @@ angular.module('ngMap', []);
       'use strict';
       var NgMap, $timeout, NavigatorGeolocation;
     
    +  var requestTimeout, routeRequest;
    +  // Delay for each route render to accumulate all requests into a single one
    +  // This is required for simultaneous origin\waypoints\destination change
    +  // 20ms should be enough to merge all request data
    +  var routeRenderDelay = 20;
    +
       var getDirectionsRenderer = function(options, events) {
         if (options.panel) {
           options.panel = document.getElementById(options.panel) ||
    @@ -738,28 +778,52 @@ angular.module('ngMap', []);
           'durationInTraffic', 'waypoints', 'optimizeWaypoints', 
           'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region'
         ];
    -    for(var key in request){
    -      (validKeys.indexOf(key) === -1) && (delete request[key]);
    +    if (request) {
    +      for(var key in request) {
    +        if (request.hasOwnProperty(key)) {
    +          (validKeys.indexOf(key) === -1) && (delete request[key]);
    +        }
    +      }
         }
     
         if(request.waypoints) {
    -      // Check fo valid values
    -      if(request.waypoints == "[]" || request.waypoints === "") {
    +      // Check for acceptable values
    +      if(!Array.isArray(request.waypoints)) {
             delete request.waypoints;
           }
         }
     
         var showDirections = function(request) {
    -      directionsService.route(request, function(response, status) {
    -        if (status == google.maps.DirectionsStatus.OK) {
    -          $timeout(function() {
    -            renderer.setDirections(response);
    -          });
    +      if (requestTimeout && request) {
    +        if (!routeRequest) {
    +          routeRequest = request;
    +        } else {
    +          for (var attr in request) {
    +            if (request.hasOwnProperty(attr)) {
    +              routeRequest[attr] = request[attr];
    +            }
    +          }
             }
    -      });
    +      } else {
    +        requestTimeout = $timeout(function() {
    +          if (!routeRequest) {
    +            routeRequest = request;
    +          }
    +          directionsService.route(routeRequest, function(response, status) {
    +            if (status == google.maps.DirectionsStatus.OK) {
    +              renderer.setDirections(response);
    +              // Unset request for the next call
    +              routeRequest = undefined;
    +            }
    +          });
    +          $timeout.cancel(requestTimeout);
    +          // Unset expired timeout for the next call
    +          requestTimeout = undefined;
    +        }, routeRenderDelay);
    +      }
         };
     
    -    if (request.origin && request.destination) {
    +    if (request && request.origin && request.destination) {
           if (request.origin == 'current-location') {
             NavigatorGeolocation.getCurrentPosition().then(function(ll) {
               request.origin = new google.maps.LatLng(ll.coords.latitude, ll.coords.longitude);
    @@ -792,6 +856,11 @@ angular.module('ngMap', []);
           var events = parser.getEvents(scope, filtered);
           var attrsToObserve = parser.getAttrsToObserve(orgAttrs);
     
    +      var attrsToObserve = [];
    +      if (!filtered.noWatcher) {
    +          attrsToObserve = parser.getAttrsToObserve(orgAttrs);
    +      }
    +
           var renderer = getDirectionsRenderer(options, events);
           mapController.addObject('directionsRenderers', renderer);
     
    @@ -1057,7 +1126,7 @@ angular.module('ngMap', []);
              * set options
              */
             var options = parser.getOptions(filtered, {scope: scope});
    -        options.data = $window[attrs.data] || scope[attrs.data];
    +        options.data = $window[attrs.data] || parseScope(attrs.data, scope);
             if (options.data instanceof Array) {
               options.data = new google.maps.MVCArray(options.data);
             } else {
    @@ -1072,6 +1141,13 @@ angular.module('ngMap', []);
             console.log('heatmap-layer options', layer, 'events', events);
     
             mapController.addObject('heatmapLayers', layer);
    +        
    +        //helper get nexted path
    +        function parseScope( path, obj ) {
    +            return path.split('.').reduce( function( prev, curr ) {
    +                return prev[curr];
    +            }, obj || this );
    +        }
           }
          }; // return
       }]);
    @@ -1190,8 +1266,10 @@ angular.module('ngMap', []);
                 } else {
                   infoWindow.open(map);
                 }
    -            var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement;
    -            infoWindowContainerEl.className = "ng-map-info-window";
    +            $timeout(function() { // to avoid racing condition
    +              var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement;
    +              infoWindowContainerEl.className = "ng-map-info-window";
    +            });
               });
             });
           };
    @@ -1879,6 +1957,7 @@ angular.module('ngMap', []);
      * Example:
      *   
      *   
    + *
      */
     /* global google */
     (function() {
    @@ -1895,6 +1974,7 @@ angular.module('ngMap', []);
           var options = parser.getOptions(filtered, {scope: scope});
           var events = parser.getEvents(scope, filtered);
           var autocomplete = new google.maps.places.Autocomplete(element[0], options);
    +      autocomplete.setOptions({strictBounds: options.strictBounds === true});
           for (var eventName in events) {
             google.maps.event.addListener(autocomplete, eventName, events[eventName]);
           }
    @@ -1907,20 +1987,37 @@ angular.module('ngMap', []);
           google.maps.event.addListener(autocomplete, 'place_changed', updateModel);
           element[0].addEventListener('change', updateModel);
     
    +      attrs.$observe('rectBounds', function(val) {
    +        if (val) {
    +          var bounds = parser.toOptionValue(val, {key: 'rectBounds'});
    +          autocomplete.setBounds(new google.maps.LatLngBounds(
    +            new google.maps.LatLng(bounds.south_west.lat, bounds.south_west.lng),
    +            new google.maps.LatLng(bounds.north_east.lat, bounds.north_east.lng)));
    +          }
    +      });
    +
    +      attrs.$observe('circleBounds', function(val) {
    +        if (val) {
    +          var bounds = parser.toOptionValue(val, {key: 'circleBounds'});
    +          var circle = new google.maps.Circle(bounds);
    +          autocomplete.setBounds(circle.getBounds());
    +        }
    +      });
    +
           attrs.$observe('types', function(val) {
             if (val) {
               var optionValue = parser.toOptionValue(val, {key: 'types'});
               autocomplete.setTypes(optionValue);
             }
           });
    -	  
    -	  attrs.$observe('componentRestrictions', function (val) {
    -		 if (val) {
    -		   autocomplete.setComponentRestrictions(scope.$eval(val));
    -		 }
    -	   });
    +
    +      attrs.$observe('componentRestrictions', function (val) {
    +        if (val) {
    +          autocomplete.setComponentRestrictions(scope.$eval(val));
    +        }
    +      });
         };
    -	
    +
         return {
           restrict: 'A',
           require: '?ngModel',
    @@ -1963,7 +2060,7 @@ angular.module('ngMap', []);
      * @example
      * Usage:
      *   
    - *    
    + *    
      *   
      *
      * Example:
    @@ -2382,7 +2479,8 @@ angular.module('ngMap', []);
                 function(_, $1) {
                   return '"'+$1+'"';
                 }
    -          );
    +          )
    +          .replace(/''/g, '""');
           }
         };
       };
    diff --git a/build/scripts/ng-map.js b/build/scripts/ng-map.js
    index c7aae9cb0..5f6eab2c5 100644
    --- a/build/scripts/ng-map.js
    +++ b/build/scripts/ng-map.js
    @@ -8,7 +8,7 @@ factory(root.angular);
     }
     }(this, function(angular) {
     /**
    - * AngularJS Google Maps Ver. 1.18.2
    + * AngularJS Google Maps Ver. 1.18.4
      *
      * The MIT License (MIT)
      * 
    @@ -205,7 +205,7 @@ angular.module('ngMap', []);
           }
     
           // set options
    -      mapOptions.zoom = mapOptions.zoom || 15;
    +      mapOptions.zoom = (mapOptions.zoom && !isNaN(mapOptions.zoom)) ? +mapOptions.zoom : 15;
           var center = mapOptions.center;
           var exprRegExp = new RegExp(escapeRegExp(exprStartSymbol) + '.*' + escapeRegExp(exprEndSymbol));
     
    @@ -420,13 +420,20 @@ angular.module('ngMap', []);
         var filtered = parser.filter(attrs);
         var options = parser.getOptions(filtered, {scope: scope});
         var events = parser.getEvents(scope, filtered);
    +    var innerScope = scope.$new();
     
         /**
          * build a custom control element
          */
         var customControlEl = element[0].parentElement.removeChild(element[0]);
    -    var content = $transclude();
    -    angular.element(customControlEl).append(content);
    +    var content = $transclude( innerScope, function( clone ) {
    +      element.empty();
    +      element.append( clone );
    +      element.on( '$destroy', function() {
    +        innerScope.$destroy();
    +      });
    +    });
    +    
     
         /**
          * set events
    @@ -490,11 +497,22 @@ angular.module('ngMap', []);
       'use strict';
       var parser, $timeout, $compile, NgMap;
     
    +  var supportedTransform = (function getSupportedTransform() {
    +    var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' ');
    +    var div = document.createElement('div');
    +    for(var i = 0; i < prefixes.length; i++) {
    +      if(div && div.style[prefixes[i]] !== undefined) {
    +        return prefixes[i];
    +      }
    +    }
    +    return false;
    +  })();
    +
       var CustomMarker = function(options) {
         options = options || {};
     
         this.el = document.createElement('div');
    -    this.el.style.display = 'inline-block';
    +    this.el.style.display = 'block';
         this.el.style.visibility = "hidden";
         this.visible = true;
         for (var key in options) { /* jshint ignore:line */
    @@ -509,6 +527,8 @@ angular.module('ngMap', []);
         CustomMarker.prototype.setContent = function(html, scope) {
           this.el.innerHTML = html;
           this.el.style.position = 'absolute';
    +      this.el.style.top = 0;
    +      this.el.style.left = 0;
           if (scope) {
             $compile(angular.element(this.el).contents())(scope);
           }
    @@ -536,8 +556,12 @@ angular.module('ngMap', []);
               var posPixel = _this.getProjection().fromLatLngToDivPixel(_this.position);
               var x = Math.round(posPixel.x - (_this.el.offsetWidth/2));
               var y = Math.round(posPixel.y - _this.el.offsetHeight - 10); // 10px for anchor
    -          _this.el.style.left = x + "px";
    -          _this.el.style.top = y + "px";
    +          if (supportedTransform) {
    +            _this.el.style[supportedTransform] = "translate(" + x + "px, " + y + "px)";
    +          } else {
    +            _this.el.style.left = x + "px";
    +            _this.el.style.top = y + "px";
    +          }
               _this.el.style.visibility = "visible";
             };
             if (_this.el.offsetWidth && _this.el.offsetHeight) {
    @@ -550,8 +574,9 @@ angular.module('ngMap', []);
         };
     
         CustomMarker.prototype.setZIndex = function(zIndex) {
    -      zIndex && (this.zIndex = zIndex); /* jshint ignore:line */
    -      this.el.style.zIndex = this.zIndex;
    +      if (zIndex === undefined) return;
    +      (this.zIndex !== zIndex) && (this.zIndex = zIndex); /* jshint ignore:line */
    +      (this.el.style.zIndex !== this.zIndex) && (this.el.style.zIndex = this.zIndex);
         };
     
         CustomMarker.prototype.getVisible = function() {
    @@ -559,7 +584,12 @@ angular.module('ngMap', []);
         };
     
         CustomMarker.prototype.setVisible = function(visible) {
    -      this.el.style.display = visible ? 'inline-block' : 'none';
    +      if (this.el.style.display === 'none' && visible)
    +      {
    +          this.el.style.display = 'block';
    +      } else if (this.el.style.display !== 'none' && !visible) {
    +          this.el.style.display = 'none';
    +      }
           this.visible = visible;
         };
     
    @@ -610,23 +640,26 @@ angular.module('ngMap', []);
           void 0;
           var customMarker = new CustomMarker(options);
     
    -      $timeout(function() { //apply contents, class, and location after it is compiled
    +      // Do we really need a timeout with $scope.$apply() here?
    +      setTimeout(function() { //apply contents, class, and location after it is compiled
     
    -        scope.$watch('[' + varsToWatch.join(',') + ']', function() {
    +        scope.$watch('[' + varsToWatch.join(',') + ']', function(newVal, oldVal) {
               customMarker.setContent(orgHtml, scope);
             }, true);
     
             customMarker.setContent(element[0].innerHTML, scope);
    -        var classNames = element[0].firstElementChild.className;
    +        var classNames =
    +          (element[0].firstElementChild) && (element[0].firstElementChild.className || '');
    +        customMarker.class && (classNames += " " + customMarker.class);
             customMarker.addClass('custom-marker');
    -        customMarker.addClass(classNames);
    +        classNames && customMarker.addClass(classNames);
             void 0;
     
             if (!(options.position instanceof google.maps.LatLng)) {
               NgMap.getGeoLocation(options.position).then(
    -                function(latlng) {
    -                  customMarker.setPosition(latlng);
    -                }
    +            function(latlng) {
    +              customMarker.setPosition(latlng);
    +            }
               );
             }
     
    @@ -667,6 +700,7 @@ angular.module('ngMap', []);
           restrict: 'E',
           require: ['?^map','?^ngMap'],
           compile: function(element) {
    +        void 0;
             setCustomMarker();
             element[0].style.display ='none';
             var orgHtml = element.html();
    @@ -724,6 +758,12 @@ angular.module('ngMap', []);
       'use strict';
       var NgMap, $timeout, NavigatorGeolocation;
     
    +  var requestTimeout, routeRequest;
    +  // Delay for each route render to accumulate all requests into a single one
    +  // This is required for simultaneous origin\waypoints\destination change
    +  // 20ms should be enough to merge all request data
    +  var routeRenderDelay = 20;
    +
       var getDirectionsRenderer = function(options, events) {
         if (options.panel) {
           options.panel = document.getElementById(options.panel) ||
    @@ -747,28 +787,52 @@ angular.module('ngMap', []);
           'durationInTraffic', 'waypoints', 'optimizeWaypoints', 
           'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region'
         ];
    -    for(var key in request){
    -      (validKeys.indexOf(key) === -1) && (delete request[key]);
    +    if (request) {
    +      for(var key in request) {
    +        if (request.hasOwnProperty(key)) {
    +          (validKeys.indexOf(key) === -1) && (delete request[key]);
    +        }
    +      }
         }
     
         if(request.waypoints) {
    -      // Check fo valid values
    -      if(request.waypoints == "[]" || request.waypoints === "") {
    +      // Check for acceptable values
    +      if(!Array.isArray(request.waypoints)) {
             delete request.waypoints;
           }
         }
     
         var showDirections = function(request) {
    -      directionsService.route(request, function(response, status) {
    -        if (status == google.maps.DirectionsStatus.OK) {
    -          $timeout(function() {
    -            renderer.setDirections(response);
    -          });
    +      if (requestTimeout && request) {
    +        if (!routeRequest) {
    +          routeRequest = request;
    +        } else {
    +          for (var attr in request) {
    +            if (request.hasOwnProperty(attr)) {
    +              routeRequest[attr] = request[attr];
    +            }
    +          }
             }
    -      });
    +      } else {
    +        requestTimeout = $timeout(function() {
    +          if (!routeRequest) {
    +            routeRequest = request;
    +          }
    +          directionsService.route(routeRequest, function(response, status) {
    +            if (status == google.maps.DirectionsStatus.OK) {
    +              renderer.setDirections(response);
    +              // Unset request for the next call
    +              routeRequest = undefined;
    +            }
    +          });
    +          $timeout.cancel(requestTimeout);
    +          // Unset expired timeout for the next call
    +          requestTimeout = undefined;
    +        }, routeRenderDelay);
    +      }
         };
     
    -    if (request.origin && request.destination) {
    +    if (request && request.origin && request.destination) {
           if (request.origin == 'current-location') {
             NavigatorGeolocation.getCurrentPosition().then(function(ll) {
               request.origin = new google.maps.LatLng(ll.coords.latitude, ll.coords.longitude);
    @@ -801,6 +865,11 @@ angular.module('ngMap', []);
           var events = parser.getEvents(scope, filtered);
           var attrsToObserve = parser.getAttrsToObserve(orgAttrs);
     
    +      var attrsToObserve = [];
    +      if (!filtered.noWatcher) {
    +          attrsToObserve = parser.getAttrsToObserve(orgAttrs);
    +      }
    +
           var renderer = getDirectionsRenderer(options, events);
           mapController.addObject('directionsRenderers', renderer);
     
    @@ -1066,7 +1135,7 @@ angular.module('ngMap', []);
              * set options
              */
             var options = parser.getOptions(filtered, {scope: scope});
    -        options.data = $window[attrs.data] || scope[attrs.data];
    +        options.data = $window[attrs.data] || parseScope(attrs.data, scope);
             if (options.data instanceof Array) {
               options.data = new google.maps.MVCArray(options.data);
             } else {
    @@ -1081,6 +1150,13 @@ angular.module('ngMap', []);
             void 0;
     
             mapController.addObject('heatmapLayers', layer);
    +        
    +        //helper get nexted path
    +        function parseScope( path, obj ) {
    +            return path.split('.').reduce( function( prev, curr ) {
    +                return prev[curr];
    +            }, obj || this );
    +        }
           }
          }; // return
       }]);
    @@ -1199,8 +1275,10 @@ angular.module('ngMap', []);
                 } else {
                   infoWindow.open(map);
                 }
    -            var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement;
    -            infoWindowContainerEl.className = "ng-map-info-window";
    +            $timeout(function() { // to avoid racing condition
    +              var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement;
    +              infoWindowContainerEl.className = "ng-map-info-window";
    +            });
               });
             });
           };
    @@ -1887,6 +1965,7 @@ angular.module('ngMap', []);
      * Example:
      *   
      *   
    + *
      */
     /* global google */
     (function() {
    @@ -1903,6 +1982,7 @@ angular.module('ngMap', []);
           var options = parser.getOptions(filtered, {scope: scope});
           var events = parser.getEvents(scope, filtered);
           var autocomplete = new google.maps.places.Autocomplete(element[0], options);
    +      autocomplete.setOptions({strictBounds: options.strictBounds === true});
           for (var eventName in events) {
             google.maps.event.addListener(autocomplete, eventName, events[eventName]);
           }
    @@ -1915,20 +1995,37 @@ angular.module('ngMap', []);
           google.maps.event.addListener(autocomplete, 'place_changed', updateModel);
           element[0].addEventListener('change', updateModel);
     
    +      attrs.$observe('rectBounds', function(val) {
    +        if (val) {
    +          var bounds = parser.toOptionValue(val, {key: 'rectBounds'});
    +          autocomplete.setBounds(new google.maps.LatLngBounds(
    +            new google.maps.LatLng(bounds.south_west.lat, bounds.south_west.lng),
    +            new google.maps.LatLng(bounds.north_east.lat, bounds.north_east.lng)));
    +          }
    +      });
    +
    +      attrs.$observe('circleBounds', function(val) {
    +        if (val) {
    +          var bounds = parser.toOptionValue(val, {key: 'circleBounds'});
    +          var circle = new google.maps.Circle(bounds);
    +          autocomplete.setBounds(circle.getBounds());
    +        }
    +      });
    +
           attrs.$observe('types', function(val) {
             if (val) {
               var optionValue = parser.toOptionValue(val, {key: 'types'});
               autocomplete.setTypes(optionValue);
             }
           });
    -	  
    -	  attrs.$observe('componentRestrictions', function (val) {
    -		 if (val) {
    -		   autocomplete.setComponentRestrictions(scope.$eval(val));
    -		 }
    -	   });
    +
    +      attrs.$observe('componentRestrictions', function (val) {
    +        if (val) {
    +          autocomplete.setComponentRestrictions(scope.$eval(val));
    +        }
    +      });
         };
    -	
    +
         return {
           restrict: 'A',
           require: '?ngModel',
    @@ -1971,7 +2068,7 @@ angular.module('ngMap', []);
      * @example
      * Usage:
      *   
    - *    
    + *    
      *   
      *
      * Example:
    @@ -2389,7 +2486,8 @@ angular.module('ngMap', []);
                 function(_, $1) {
                   return '"'+$1+'"';
                 }
    -          );
    +          )
    +          .replace(/''/g, '""');
           }
         };
       };
    diff --git a/build/scripts/ng-map.min.js b/build/scripts/ng-map.min.js
    index b15c17212..08199484e 100644
    --- a/build/scripts/ng-map.min.js
    +++ b/build/scripts/ng-map.min.js
    @@ -1,5 +1,5 @@
     !function(e,t){"object"==typeof exports?module.exports=t(require("angular")):"function"==typeof define&&define.amd?define(["angular"],t):t(e.angular)}(this,function(angular){/**
    - * AngularJS Google Maps Ver. 1.18.2
    + * AngularJS Google Maps Ver. 1.18.4
      *
      * The MIT License (MIT)
      * 
    @@ -22,5 +22,5 @@
      * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
      * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      */
    -return angular.module("ngMap",[]),function(){"use strict";var e,t=function(t,n,o,a,r,i,s,p,c){e=i;var u=this,l=r.startSymbol(),g=r.endSymbol();u.mapOptions,u.mapEvents,u.eventListeners,u.addObject=function(e,t){if(u.map){u.map[e]=u.map[e]||{};var n=Object.keys(u.map[e]).length;u.map[e][t.id||n]=t,u.map instanceof google.maps.Map&&("infoWindows"!=e&&t.setMap&&t.setMap&&t.setMap(u.map),t.centered&&t.position&&u.map.setCenter(t.position),"markers"==e&&u.objectChanged("markers"),"customMarkers"==e&&u.objectChanged("customMarkers"))}},u.deleteObject=function(e,t){if(t.map){var n=t.map[e];for(var o in n)n[o]===t&&(google.maps.event.clearInstanceListeners(t),delete n[o]);t.map&&t.setMap&&t.setMap(null),"markers"==e&&u.objectChanged("markers"),"customMarkers"==e&&u.objectChanged("customMarkers")}},u.observeAttrSetObj=function(t,n,o){if(n.noWatcher)return!1;for(var a=e.getAttrsToObserve(t),r=0;r0||null!=u.map.customMarkers&&Object.keys(u.map.customMarkers).length>0){var e=new google.maps.LatLngBounds;for(var t in u.map.markers)e.extend(u.map.markers[t].getPosition());for(var n in u.map.customMarkers)e.extend(u.map.customMarkers[n].getPosition());u.mapOptions.maximumZoom&&(u.enableMaximumZoomCheck=!0),u.map.fitBounds(e)}},u.objectChanged=function(e){!u.map||"markers"!=e&&"customMarkers"!=e||"auto"!=u.map.zoomToIncludeMarkers||u.zoomToIncludeMarkers()},u.initializeMap=function(){var r=u.mapOptions,i=u.mapEvents,m=u.map;if(u.map=p.getMapInstance(n[0]),s.setStyle(n[0]),m){var f=e.filter(o),v=e.getOptions(f),y=e.getControlOptions(f);r=angular.extend(v,y);for(var h in m){var b=m[h];if("object"==typeof b)for(var M in b)u.addObject(h,b[M])}u.map.showInfoWindow=u.showInfoWindow,u.map.hideInfoWindow=u.hideInfoWindow}r.zoom=r.zoom||15;var O=r.center,w=new RegExp(c(l)+".*"+c(g));if(!r.center||"string"==typeof O&&O.match(w))r.center=new google.maps.LatLng(0,0);else if("string"==typeof O&&O.match(/^[0-9.-]*,[0-9.-]*$/)){var L=parseFloat(O.split(",")[0]),k=parseFloat(O.split(",")[1]);r.center=new google.maps.LatLng(L,k)}else if(!(O instanceof google.maps.LatLng)){var $=r.center;delete r.center,s.getGeoLocation($,r.geoLocationOptions).then(function(e){u.map.setCenter(e);var n=r.geoCallback;n&&a(n)(t)},function(){r.geoFallbackCenter&&u.map.setCenter(r.geoFallbackCenter)})}u.map.setOptions(r);for(var C in i){var j=i[C],A=google.maps.event.addListener(u.map,C,j);u.eventListeners[C]=A}u.observeAttrSetObj(d,o,u.map),u.singleInfoWindow=r.singleInfoWindow,google.maps.event.trigger(u.map,"resize"),google.maps.event.addListenerOnce(u.map,"idle",function(){s.addMap(u),r.zoomToIncludeMarkers&&u.zoomToIncludeMarkers(),t.map=u.map,t.$emit("mapInitialized",u.map),o.mapInitialized&&a(o.mapInitialized)(t,{map:u.map})}),r.zoomToIncludeMarkers&&r.maximumZoom&&google.maps.event.addListener(u.map,"zoom_changed",function(){1==u.enableMaximumZoomCheck&&(u.enableMaximumZoomCheck=!1,google.maps.event.addListenerOnce(u.map,"bounds_changed",function(){u.map.setZoom(Math.min(r.maximumZoom,u.map.getZoom()))}))})},t.google=google;var d=e.orgAttributes(n),m=e.filter(o),f=e.getOptions(m,{scope:t}),v=e.getControlOptions(m),y=angular.extend(f,v),h=e.getEvents(t,m);if(Object.keys(h).length&&void 0,u.mapOptions=y,u.mapEvents=h,u.eventListeners={},f.lazyInit){if(o.id&&0===o.id.indexOf(l,0)&&-1!==o.id.indexOf(g,o.id.length-g.length))var b=o.id.slice(2,-2),M=a(b)(t);else var M=o.id;u.map={id:M},s.addMap(u)}else u.initializeMap();f.triggerResize&&google.maps.event.trigger(u.map,"resize"),n.bind("$destroy",function(){p.returnMapInstance(u.map),s.deleteMap(u)})};t.$inject=["$scope","$element","$attrs","$parse","$interpolate","Attr2MapOptions","NgMap","NgMapPool","escapeRegexpFilter"],angular.module("ngMap").controller("__MapController",t)}(),function(){"use strict";var e,t=function(t,o,a,r){r=r[0]||r[1];var i=e.orgAttributes(o),s=e.filter(a),p=e.getOptions(s,{scope:t}),c=e.getEvents(t,s),u=n(p,c);r.addObject("bicyclingLayers",u),r.observeAttrSetObj(i,a,u),o.bind("$destroy",function(){r.deleteObject("bicyclingLayers",u)})},n=function(e,t){var n=new google.maps.BicyclingLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n},o=function(n){return e=n,{restrict:"E",require:["?^map","?^ngMap"],link:t}};o.$inject=["Attr2MapOptions"],angular.module("ngMap").directive("bicyclingLayer",o)}(),function(){"use strict";var e,t,n=function(t,n,o,a,r){a=a[0]||a[1];var i=e.filter(o),s=e.getOptions(i,{scope:t}),p=e.getEvents(t,i),c=n[0].parentElement.removeChild(n[0]),u=r();angular.element(c).append(u);for(var l in p)google.maps.event.addDomListener(c,l,p[l]);a.addObject("customControls",c);var g=s.position;a.map.controls[google.maps.ControlPosition[g]].push(c),n.bind("$destroy",function(){a.deleteObject("customControls",c)})},o=function(o,a){return e=o,t=a,{restrict:"E",require:["?^map","?^ngMap"],link:n,transclude:!0}};o.$inject=["Attr2MapOptions","NgMap"],angular.module("ngMap").directive("customControl",o)}(),function(){"use strict";var e,t,n,o,a=function(e){e=e||{},this.el=document.createElement("div"),this.el.style.display="inline-block",this.el.style.visibility="hidden",this.visible=!0;for(var t in e)this[t]=e[t]},r=function(){a.prototype=new google.maps.OverlayView,a.prototype.setContent=function(e,t){this.el.innerHTML=e,this.el.style.position="absolute",t&&n(angular.element(this.el).contents())(t)},a.prototype.getDraggable=function(){return this.draggable},a.prototype.setDraggable=function(e){this.draggable=e},a.prototype.getPosition=function(){return this.position},a.prototype.setPosition=function(e){e&&(this.position=e);var n=this;if(this.getProjection()&&"function"==typeof this.position.lng){var o=function(){if(n.getProjection()){var e=n.getProjection().fromLatLngToDivPixel(n.position),t=Math.round(e.x-n.el.offsetWidth/2),o=Math.round(e.y-n.el.offsetHeight-10);n.el.style.left=t+"px",n.el.style.top=o+"px",n.el.style.visibility="visible"}};n.el.offsetWidth&&n.el.offsetHeight?o():t(o,300)}},a.prototype.setZIndex=function(e){e&&(this.zIndex=e),this.el.style.zIndex=this.zIndex},a.prototype.getVisible=function(){return this.visible},a.prototype.setVisible=function(e){this.el.style.display=e?"inline-block":"none",this.visible=e},a.prototype.addClass=function(e){var t=this.el.className.trim().split(" ");-1==t.indexOf(e)&&t.push(e),this.el.className=t.join(" ")},a.prototype.removeClass=function(e){var t=this.el.className.split(" "),n=t.indexOf(e);n>-1&&t.splice(n,1),this.el.className=t.join(" ")},a.prototype.onAdd=function(){this.getPanes().overlayMouseTarget.appendChild(this.el)},a.prototype.draw=function(){this.setPosition(),this.setZIndex(this.zIndex),this.setVisible(this.visible)},a.prototype.onRemove=function(){this.el.parentNode.removeChild(this.el)}},i=function(n,r){return function(i,s,p,c){c=c[0]||c[1];var u=e.orgAttributes(s),l=e.filter(p),g=e.getOptions(l,{scope:i}),d=e.getEvents(i,l);s[0].style.display="none";var m=new a(g);t(function(){i.$watch("["+r.join(",")+"]",function(){m.setContent(n,i)},!0),m.setContent(s[0].innerHTML,i);var e=s[0].firstElementChild.className;m.addClass("custom-marker"),m.addClass(e),g.position instanceof google.maps.LatLng||o.getGeoLocation(g.position).then(function(e){m.setPosition(e)})});for(var f in d)google.maps.event.addDomListener(m.el,f,d[f]);c.addObject("customMarkers",m),c.observeAttrSetObj(u,p,m),s.bind("$destroy",function(){c.deleteObject("customMarkers",m)})}},s=function(a,s,p,c,u,l){e=c,t=a,n=s,o=u;var g=p.startSymbol(),d=p.endSymbol(),m=new RegExp(l(g)+"([^"+d.substring(0,1)+"]+)"+l(d),"g");return{restrict:"E",require:["?^map","?^ngMap"],compile:function(e){r(),e[0].style.display="none";var t=e.html(),n=t.match(m),o=[];return(n||[]).forEach(function(e){var t=e.replace(g,"").replace(d,"");-1==e.indexOf("::")&&-1==e.indexOf("this.")&&-1==o.indexOf(t)&&o.push(e.replace(g,"").replace(d,""))}),i(t,o)}}};s.$inject=["$timeout","$compile","$interpolate","Attr2MapOptions","NgMap","escapeRegexpFilter"],angular.module("ngMap").directive("customMarker",s)}(),function(){"use strict";var e,t,n,o=function(e,t){e.panel&&(e.panel=document.getElementById(e.panel)||document.querySelector(e.panel));var n=new google.maps.DirectionsRenderer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n},a=function(e,o){var a=new google.maps.DirectionsService,r=o;r.travelMode=r.travelMode||"DRIVING";var i=["origin","destination","travelMode","transitOptions","unitSystem","durationInTraffic","waypoints","optimizeWaypoints","provideRouteAlternatives","avoidHighways","avoidTolls","region"];for(var s in r)-1===i.indexOf(s)&&delete r[s];r.waypoints&&("[]"==r.waypoints||""===r.waypoints)&&delete r.waypoints;var p=function(n){a.route(n,function(n,o){o==google.maps.DirectionsStatus.OK&&t(function(){e.setDirections(n)})})};r.origin&&r.destination&&("current-location"==r.origin?n.getCurrentPosition().then(function(e){r.origin=new google.maps.LatLng(e.coords.latitude,e.coords.longitude),p(r)}):"current-location"==r.destination?n.getCurrentPosition().then(function(e){r.destination=new google.maps.LatLng(e.coords.latitude,e.coords.longitude),p(r)}):p(r))},r=function(r,i,s,p){var c=r;e=p,t=i,n=s;var u=function(n,r,i,s){s=s[0]||s[1];var p=c.orgAttributes(r),u=c.filter(i),l=c.getOptions(u,{scope:n}),g=c.getEvents(n,u),d=c.getAttrsToObserve(p),m=o(l,g);s.addObject("directionsRenderers",m),d.forEach(function(e){!function(e){i.$observe(e,function(n){if("panel"==e)t(function(){var e=document.getElementById(n)||document.querySelector(n);e&&m.setPanel(e)});else if(l[e]!==n){var o=c.toOptionValue(n,{key:e});l[e]=o,a(m,l)}})}(e)}),e.getMap().then(function(){a(m,l)}),r.bind("$destroy",function(){s.deleteObject("directionsRenderers",m)})};return{restrict:"E",require:["?^map","?^ngMap"],link:u}};r.$inject=["Attr2MapOptions","$timeout","NavigatorGeolocation","NgMap"],angular.module("ngMap").directive("directions",r)}(),function(){"use strict";angular.module("ngMap").directive("drawingManager",["Attr2MapOptions",function(e){var t=e;return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,n,o,a){a=a[0]||a[1];var r=t.filter(o),i=t.getOptions(r,{scope:e}),s=t.getControlOptions(r),p=t.getEvents(e,r),c=new google.maps.drawing.DrawingManager({drawingMode:i.drawingmode,drawingControl:i.drawingcontrol,drawingControlOptions:s.drawingControlOptions,circleOptions:i.circleoptions,markerOptions:i.markeroptions,polygonOptions:i.polygonoptions,polylineOptions:i.polylineoptions,rectangleOptions:i.rectangleoptions});o.$observe("drawingControlOptions",function(e){c.drawingControlOptions=t.getControlOptions({drawingControlOptions:e}).drawingControlOptions,c.setDrawingMode(null),c.setMap(a.map)});for(var u in p)google.maps.event.addListener(c,u,p[u]);a.addObject("mapDrawingManager",c),n.bind("$destroy",function(){a.deleteObject("mapDrawingManager",c)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("dynamicMapsEngineLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.visualization.DynamicMapsEngineLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=t.filter(a),s=t.getOptions(i,{scope:e}),p=t.getEvents(e,i,p),c=n(s,p);r.addObject("mapsEngineLayers",c)}}}])}(),function(){"use strict";angular.module("ngMap").directive("fusionTablesLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.FusionTablesLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=t.filter(a),s=t.getOptions(i,{scope:e}),p=t.getEvents(e,i,p),c=n(s,p);r.addObject("fusionTablesLayers",c),o.bind("$destroy",function(){r.deleteObject("fusionTablesLayers",c)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("heatmapLayer",["Attr2MapOptions","$window",function(e,t){var n=e;return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=n.filter(a),s=n.getOptions(i,{scope:e});if(s.data=t[a.data]||e[a.data],!(s.data instanceof Array))throw"invalid heatmap data";s.data=new google.maps.MVCArray(s.data);{var p=new google.maps.visualization.HeatmapLayer(s);n.getEvents(e,i)}r.addObject("heatmapLayers",p)}}}])}(),function(){"use strict";var e=function(e,t,n,o,a,r,i){var s=e,p=function(e,r,i){var s;!e.position||e.position instanceof google.maps.LatLng||delete e.position,s=new google.maps.InfoWindow(e);for(var p in r)p&&google.maps.event.addListener(s,p,r[p]);var c=n(function(e){angular.isString(i)?o(i).then(function(t){e(angular.element(t).wrap("
    ").parent())},function(e){throw"info-window template request failed: "+e}):e(i)}).then(function(e){var t=e.html().trim();if(1!=angular.element(t).length)throw"info-window working as a template must have a container";s.__template=t.replace(/\s?ng-non-bindable[='"]+/,"")});return s.__open=function(e,n,o){c.then(function(){a(function(){o&&(n.anchor=o);var a=t(s.__template)(n);s.setContent(a[0]),n.$apply(),o&&o.getPosition?s.open(e,o):o&&o instanceof google.maps.LatLng?(s.open(e),s.setPosition(o)):s.open(e);var r=s.content.parentElement.parentElement.parentElement;r.className="ng-map-info-window"})})},s},c=function(e,t,n,o){o=o[0]||o[1],t.css("display","none");var a,c=s.orgAttributes(t),u=s.filter(n),l=s.getOptions(u,{scope:e}),g=s.getEvents(e,u),d=p(l,g,l.template||t);!l.position||l.position instanceof google.maps.LatLng||(a=l.position),a&&i.getGeoLocation(a).then(function(t){d.setPosition(t),d.__open(o.map,e,t);var a=n.geoCallback;a&&r(a)(e)}),o.addObject("infoWindows",d),o.observeAttrSetObj(c,n,d),o.showInfoWindow=o.map.showInfoWindow=o.showInfoWindow||function(t,n,a){var r="string"==typeof t?t:n,i="string"==typeof t?n:a;if("string"==typeof i)if("undefined"!=typeof o.map.markers&&"undefined"!=typeof o.map.markers[i])i=o.map.markers[i];else{if("undefined"==typeof o.map.customMarkers||"undefined"==typeof o.map.customMarkers[i])throw new Error("Cant open info window for id "+i+". Marker or CustomMarker is not defined");i=o.map.customMarkers[i]}var s=o.map.infoWindows[r],p=i?i:this.getPosition?this:null;s.__open(o.map,e,p),o.singleInfoWindow&&(o.lastInfoWindow&&e.hideInfoWindow(o.lastInfoWindow),o.lastInfoWindow=r)},o.hideInfoWindow=o.map.hideInfoWindow=o.hideInfoWindow||function(e,t){var n="string"==typeof e?e:t,a=o.map.infoWindows[n];a.close()},e.showInfoWindow=o.map.showInfoWindow,e.hideInfoWindow=o.map.hideInfoWindow;var m=d.mapId?{id:d.mapId}:0;i.getMap(m).then(function(t){if(d.visible&&d.__open(t,e),d.visibleOnMarker){var n=d.visibleOnMarker;d.__open(t,e,t.markers[n])}})};return{restrict:"E",require:["?^map","?^ngMap"],link:c}};e.$inject=["Attr2MapOptions","$compile","$q","$templateRequest","$timeout","$parse","NgMap"],angular.module("ngMap").directive("infoWindow",e)}(),function(){"use strict";angular.module("ngMap").directive("kmlLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.KmlLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=t.orgAttributes(o),s=t.filter(a),p=t.getOptions(s,{scope:e}),c=t.getEvents(e,s),u=n(p,c);r.addObject("kmlLayers",u),r.observeAttrSetObj(i,a,u),o.bind("$destroy",function(){r.deleteObject("kmlLayers",u)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("mapData",["Attr2MapOptions","NgMap",function(e,t){var n=e;return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=n.filter(a),s=n.getOptions(i,{scope:e}),p=n.getEvents(e,i,p);t.getMap(r.map.id).then(function(t){for(var n in s){var o=s[n];"function"==typeof e[o]?t.data[n](e[o]):t.data[n](o)}for(var a in p)t.data.addListener(a,p[a])})}}}])}(),function(){"use strict";var e,t,n,o=[],a=[],r=function(n,r,i){var s=i.mapLazyLoadParams||i.mapLazyLoad;if(void 0===window.google||void 0===window.google.maps){a.push({scope:n,element:r,savedHtml:o[a.length]}),window.lazyLoadCallback=function(){e(function(){a.forEach(function(e){e.element.html(e.savedHtml),t(e.element.contents())(e.scope)})},100)};var p=document.createElement("script");p.src=s+(s.indexOf("?")>-1?"&":"?")+"callback=lazyLoadCallback",document.querySelector('script[src="'+p.src+'"]')||document.body.appendChild(p)}else r.html(o),t(r.contents())(n)},i=function(e,t){return!t.mapLazyLoad&&void 0,o.push(e.html()),n=t.mapLazyLoad,void 0!==window.google&&void 0!==window.google.maps?!1:(e.html(""),{pre:r})},s=function(n,o){return t=n,e=o,{compile:i}};s.$inject=["$compile","$timeout"],angular.module("ngMap").directive("mapLazyLoad",s)}(),function(){"use strict";angular.module("ngMap").directive("mapType",["$parse","NgMap",function(e,t){return{restrict:"E",require:["?^map","?^ngMap"],link:function(n,o,a,r){r=r[0]||r[1];var i,s=a.name;if(!s)throw"invalid map-type name";if(i=e(a.object)(n),!i)throw"invalid map-type object";t.getMap().then(function(e){e.mapTypes.set(s,i)}),r.addObject("mapTypes",i)}}}])}(),function(){"use strict";var e=function(){return{restrict:"AE",controller:"__MapController",controllerAs:"ngmap"}};angular.module("ngMap").directive("map",[e]),angular.module("ngMap").directive("ngMap",[e])}(),function(){"use strict";angular.module("ngMap").directive("mapsEngineLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.visualization.MapsEngineLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=t.filter(a),s=t.getOptions(i,{scope:e}),p=t.getEvents(e,i,p),c=n(s,p);r.addObject("mapsEngineLayers",c)}}}])}(),function(){"use strict";var e,t,n,o=function(e,t){var o;if(n.defaultOptions.marker)for(var a in n.defaultOptions.marker)"undefined"==typeof e[a]&&(e[a]=n.defaultOptions.marker[a]);e.position instanceof google.maps.LatLng||(e.position=new google.maps.LatLng(0,0)),o=new google.maps.Marker(e),Object.keys(t).length>0;for(var r in t)r&&google.maps.event.addListener(o,r,t[r]);return o},a=function(a,r,i,s){s=s[0]||s[1];var p,c=e.orgAttributes(r),u=e.filter(i),l=e.getOptions(u,a,{scope:a}),g=e.getEvents(a,u);l.position instanceof google.maps.LatLng||(p=l.position);var d=o(l,g);s.addObject("markers",d),p&&n.getGeoLocation(p).then(function(e){d.setPosition(e),l.centered&&d.map.setCenter(e);var n=i.geoCallback;n&&t(n)(a)}),s.observeAttrSetObj(c,i,d),r.bind("$destroy",function(){s.deleteObject("markers",d)})},r=function(o,r,i){return e=o,t=r,n=i,{restrict:"E",require:["^?map","?^ngMap"],link:a}};r.$inject=["Attr2MapOptions","$parse","NgMap"],angular.module("ngMap").directive("marker",r)}(),function(){"use strict";angular.module("ngMap").directive("overlayMapType",["NgMap",function(e){return{restrict:"E",require:["?^map","?^ngMap"],link:function(t,n,o,a){a=a[0]||a[1];var r=o.initMethod||"insertAt",i=t[o.object];e.getMap().then(function(e){if("insertAt"==r){var t=parseInt(o.index,10);e.overlayMapTypes.insertAt(t,i)}else"push"==r&&e.overlayMapTypes.push(i)}),a.addObject("overlayMapTypes",i)}}}])}(),function(){"use strict";var e=function(e,t){var n=e,o=function(e,o,a,r){if("false"===a.placesAutoComplete)return!1;var i=n.filter(a),s=n.getOptions(i,{scope:e}),p=n.getEvents(e,i),c=new google.maps.places.Autocomplete(o[0],s);for(var u in p)google.maps.event.addListener(c,u,p[u]);var l=function(){t(function(){r&&r.$setViewValue(o.val())},100)};google.maps.event.addListener(c,"place_changed",l),o[0].addEventListener("change",l),a.$observe("types",function(e){if(e){var t=n.toOptionValue(e,{key:"types"});c.setTypes(t)}}),a.$observe("componentRestrictions",function(t){t&&c.setComponentRestrictions(e.$eval(t))})};return{restrict:"A",require:"?ngModel",link:o}};e.$inject=["Attr2MapOptions","$timeout"],angular.module("ngMap").directive("placesAutoComplete",e)}(),function(){"use strict";var e=function(e,t){var n,o=e.name;switch(delete e.name,o){case"circle":e.center instanceof google.maps.LatLng||(e.center=new google.maps.LatLng(0,0)),n=new google.maps.Circle(e);break;case"polygon":n=new google.maps.Polygon(e);break;case"polyline":n=new google.maps.Polyline(e);break;case"rectangle":n=new google.maps.Rectangle(e);break;case"groundOverlay":case"image":var a=e.url,r={opacity:e.opacity,clickable:e.clickable,id:e.id};n=new google.maps.GroundOverlay(a,e.bounds,r)}for(var i in t)t[i]&&google.maps.event.addListener(n,i,t[i]);return n},t=function(t,n,o){var a=t,r=function(t,r,i,s){s=s[0]||s[1];var p,c,u=a.orgAttributes(r),l=a.filter(i),g=a.getOptions(l,{scope:t}),d=a.getEvents(t,l);c=g.name,g.center instanceof google.maps.LatLng||(p=g.center);var m=e(g,d);s.addObject("shapes",m),p&&"circle"==c&&o.getGeoLocation(p).then(function(e){m.setCenter(e),m.centered&&m.map.setCenter(e);var o=i.geoCallback;o&&n(o)(t)}),s.observeAttrSetObj(u,i,m),r.bind("$destroy",function(){s.deleteObject("shapes",m)})};return{restrict:"E",require:["?^map","?^ngMap"],link:r}};t.$inject=["Attr2MapOptions","$parse","NgMap"],angular.module("ngMap").directive("shape",t)}(),function(){"use strict";var e=function(e,t){var n=e,o=function(e,t,n){var o,a;t.container&&(a=document.getElementById(t.container),a=a||document.querySelector(t.container)),a?o=new google.maps.StreetViewPanorama(a,t):(o=e.getStreetView(),o.setOptions(t));for(var r in n)r&&google.maps.event.addListener(o,r,n[r]);return o},a=function(e,a,r){var i=n.filter(r),s=n.getOptions(i,{scope:e}),p=n.getControlOptions(i),c=angular.extend(s,p),u=n.getEvents(e,i);t.getMap().then(function(e){var t=o(e,c,u);e.setStreetView(t),!t.getPosition()&&t.setPosition(e.getCenter()),google.maps.event.addListener(t,"position_changed",function(){t.getPosition()!==e.getCenter()&&e.setCenter(t.getPosition())});var n=google.maps.event.addListener(e,"center_changed",function(){t.setPosition(e.getCenter()),google.maps.event.removeListener(n)})})};return{restrict:"E",require:["?^map","?^ngMap"],link:a}};e.$inject=["Attr2MapOptions","NgMap"],angular.module("ngMap").directive("streetViewPanorama",e)}(),function(){"use strict";angular.module("ngMap").directive("trafficLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.TrafficLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=t.orgAttributes(o),s=t.filter(a),p=t.getOptions(s,{scope:e}),c=t.getEvents(e,s),u=n(p,c);r.addObject("trafficLayers",u),r.observeAttrSetObj(i,a,u),o.bind("$destroy",function(){r.deleteObject("trafficLayers",u)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("transitLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.TransitLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,a,r){r=r[0]||r[1];var i=t.orgAttributes(o),s=t.filter(a),p=t.getOptions(s,{scope:e}),c=t.getEvents(e,s),u=n(p,c);r.addObject("transitLayers",u),r.observeAttrSetObj(i,a,u),o.bind("$destroy",function(){r.deleteObject("transitLayers",u)})}}}])}(),function(){"use strict";var e=/([\:\-\_]+(.))/g,t=/^moz([A-Z])/,n=function(){return function(n){return n.replace(e,function(e,t,n,o){return o?n.toUpperCase():n}).replace(t,"Moz$1")}};angular.module("ngMap").filter("camelCase",n)}(),function(){"use strict";var e=function(){return function(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}};angular.module("ngMap").filter("escapeRegexp",e)}(),function(){"use strict";var e=function(){return function(e){try{return JSON.parse(e),e}catch(t){return e.replace(/([\$\w]+)\s*:/g,function(e,t){return'"'+t+'":'}).replace(/'([^']+)'/g,function(e,t){return'"'+t+'"'})}}};angular.module("ngMap").filter("jsonize",e)}(),function(){"use strict";var isoDateRE=/^(\d{4}\-\d\d\-\d\d([tT][\d:\.]*)?)([zZ]|([+\-])(\d\d):?(\d\d))?$/,Attr2MapOptions=function($parse,$timeout,$log,$interpolate,NavigatorGeolocation,GeoCoder,camelCaseFilter,jsonizeFilter,escapeRegExp){var exprStartSymbol=$interpolate.startSymbol(),exprEndSymbol=$interpolate.endSymbol(),orgAttributes=function(e){e.length>0&&(e=e[0]);for(var t={},n=0;n-1?"&":"?")+"callback=lazyLoadCallback",document.querySelector('script[src="'+a.src+'"]')||document.body.appendChild(a)}else o.resolve(window.google);return o.promise}}};n.$inject=["$q","$timeout"],angular.module("ngMap").service("GoogleMapsApi",n)}(),function(){"use strict";var e,t=function(t){var n=e.defer();return navigator.geolocation?(void 0===t?t={timeout:5e3}:void 0===t.timeout&&(t.timeout=5e3),navigator.geolocation.getCurrentPosition(function(e){n.resolve(e)},function(e){n.reject(e)},t)):n.reject("Browser Geolocation service failed."),n.promise},n=function(n){return e=n,{getCurrentPosition:t}};n.$inject=["$q"],angular.module("ngMap").service("NavigatorGeolocation",n)}(),function(){"use strict";var e,t,n,o=[],a=function(n){var a=t.createElement("div");a.style.width="100%",a.style.height="100%",n.appendChild(a);var r=new e.google.maps.Map(a,{});return o.push(r),r},r=function(e,t){for(var n,a=0;ai?r.reject("could not find map"):e.setTimeout(function(){a(n+100)},100)}o=o||{},t="object"==typeof t?t.id:t;var r=n.defer(),i=o.timeout||1e4;return a(0),r.promise},g=function(e){if(e.map){var t=Object.keys(p).length;p[e.map.id||t]=e}},d=function(e){var t=Object.keys(p).length-1,n=e.map.id||t;if(e.map){for(var o in e.eventListeners){var a=e.eventListeners[o];google.maps.event.removeListener(a)}e.map.controls&&e.map.controls.forEach(function(e){e.clear()})}e.map.heatmapLayers&&Object.keys(e.map.heatmapLayers).forEach(function(t){e.deleteObject("heatmapLayers",e.map.heatmapLayers[t])}),s.deleteMapInstance(n),delete p[n]},m=function(e,t){var a=n.defer();return!e||e.match(/^current/i)?o.getCurrentPosition(t).then(function(e){var t=e.coords.latitude,n=e.coords.longitude,o=new google.maps.LatLng(t,n);a.resolve(o)},function(e){a.reject(e)}):r.geocode({address:e}).then(function(e){a.resolve(e[0].geometry.location)},function(e){a.reject(e)}),a.promise},f=function(e,t){return function(n){if(n){var o=i("set-"+e),r=a.toOptionValue(n,{key:e});t[o]&&(e.match(/center|position/)&&"string"==typeof r?m(r).then(function(e){t[o](e)}):t[o](r))}}},v=function(e){var t=e.getAttribute("default-style");"true"==t?(e.style.display="block",e.style.height="300px"):("block"!=c(e,"display")&&(e.style.display="block"),c(e,"height").match(/^(0|auto)/)&&(e.style.height="300px"))};angular.module("ngMap").provider("NgMap",function(){var p={};this.setDefaultOptions=function(e){p=e};var c=function(c,y,h,b,M,O,w,L){return e=c,t=y[0],n=h,o=b,a=M,r=O,i=w,s=L,{defaultOptions:p,addMap:g,deleteMap:d,getMap:l,initMap:u,setStyle:v,getGeoLocation:m,observeAndSet:f}};c.$inject=["$window","$document","$q","NavigatorGeolocation","Attr2MapOptions","GeoCoder","camelCaseFilter","NgMapPool"],this.$get=c})}(),function(){"use strict";var e,t=function(t,n){n=n||t.getCenter();var o=e.defer(),a=new google.maps.StreetViewService;return a.getPanoramaByLocation(n||t.getCenter,100,function(e,t){t===google.maps.StreetViewStatus.OK?o.resolve(e.location.pano):o.resolve(!1)}),o.promise},n=function(e,t){var n=new google.maps.StreetViewPanorama(e.getDiv(),{enableCloseButton:!0});n.setPano(t)},o=function(o){return e=o,{getPanorama:t,setPanorama:n}};o.$inject=["$q"],angular.module("ngMap").service("StreetView",o)}(),"ngMap"}); \ No newline at end of file +return angular.module("ngMap",[]),function(){"use strict";var e,t=function(t,n,o,r,a,i,s,p,c){e=i;var u=this,l=a.startSymbol(),g=a.endSymbol();u.mapOptions,u.mapEvents,u.eventListeners,u.addObject=function(e,t){if(u.map){u.map[e]=u.map[e]||{};var n=Object.keys(u.map[e]).length;u.map[e][t.id||n]=t,u.map instanceof google.maps.Map&&("infoWindows"!=e&&t.setMap&&t.setMap&&t.setMap(u.map),t.centered&&t.position&&u.map.setCenter(t.position),"markers"==e&&u.objectChanged("markers"),"customMarkers"==e&&u.objectChanged("customMarkers"))}},u.deleteObject=function(e,t){if(t.map){var n=t.map[e];for(var o in n)n[o]===t&&(google.maps.event.clearInstanceListeners(t),delete n[o]);t.map&&t.setMap&&t.setMap(null),"markers"==e&&u.objectChanged("markers"),"customMarkers"==e&&u.objectChanged("customMarkers")}},u.observeAttrSetObj=function(t,n,o){if(n.noWatcher)return!1;for(var r=e.getAttrsToObserve(t),a=0;a0||null!=u.map.customMarkers&&Object.keys(u.map.customMarkers).length>0){var e=new google.maps.LatLngBounds;for(var t in u.map.markers)e.extend(u.map.markers[t].getPosition());for(var n in u.map.customMarkers)e.extend(u.map.customMarkers[n].getPosition());u.mapOptions.maximumZoom&&(u.enableMaximumZoomCheck=!0),u.map.fitBounds(e)}},u.objectChanged=function(e){!u.map||"markers"!=e&&"customMarkers"!=e||"auto"!=u.map.zoomToIncludeMarkers||u.zoomToIncludeMarkers()},u.initializeMap=function(){var a=u.mapOptions,i=u.mapEvents,m=u.map;if(u.map=p.getMapInstance(n[0]),s.setStyle(n[0]),m){var f=e.filter(o),v=e.getOptions(f),y=e.getControlOptions(f);a=angular.extend(v,y);for(var h in m){var b=m[h];if("object"==typeof b)for(var M in b)u.addObject(h,b[M])}u.map.showInfoWindow=u.showInfoWindow,u.map.hideInfoWindow=u.hideInfoWindow}a.zoom=a.zoom&&!isNaN(a.zoom)?+a.zoom:15;var O=a.center,w=new RegExp(c(l)+".*"+c(g));if(!a.center||"string"==typeof O&&O.match(w))a.center=new google.maps.LatLng(0,0);else if("string"==typeof O&&O.match(/^[0-9.-]*,[0-9.-]*$/)){var L=parseFloat(O.split(",")[0]),k=parseFloat(O.split(",")[1]);a.center=new google.maps.LatLng(L,k)}else if(!(O instanceof google.maps.LatLng)){var $=a.center;delete a.center,s.getGeoLocation($,a.geoLocationOptions).then(function(e){u.map.setCenter(e);var n=a.geoCallback;n&&r(n)(t)},function(){a.geoFallbackCenter&&u.map.setCenter(a.geoFallbackCenter)})}u.map.setOptions(a);for(var C in i){var j=i[C],A=google.maps.event.addListener(u.map,C,j);u.eventListeners[C]=A}u.observeAttrSetObj(d,o,u.map),u.singleInfoWindow=a.singleInfoWindow,google.maps.event.trigger(u.map,"resize"),google.maps.event.addListenerOnce(u.map,"idle",function(){s.addMap(u),a.zoomToIncludeMarkers&&u.zoomToIncludeMarkers(),t.map=u.map,t.$emit("mapInitialized",u.map),o.mapInitialized&&r(o.mapInitialized)(t,{map:u.map})}),a.zoomToIncludeMarkers&&a.maximumZoom&&google.maps.event.addListener(u.map,"zoom_changed",function(){1==u.enableMaximumZoomCheck&&(u.enableMaximumZoomCheck=!1,google.maps.event.addListenerOnce(u.map,"bounds_changed",function(){u.map.setZoom(Math.min(a.maximumZoom,u.map.getZoom()))}))})},t.google=google;var d=e.orgAttributes(n),m=e.filter(o),f=e.getOptions(m,{scope:t}),v=e.getControlOptions(m),y=angular.extend(f,v),h=e.getEvents(t,m);if(Object.keys(h).length&&void 0,u.mapOptions=y,u.mapEvents=h,u.eventListeners={},f.lazyInit){if(o.id&&0===o.id.indexOf(l,0)&&-1!==o.id.indexOf(g,o.id.length-g.length))var b=o.id.slice(2,-2),M=r(b)(t);else var M=o.id;u.map={id:M},s.addMap(u)}else u.initializeMap();f.triggerResize&&google.maps.event.trigger(u.map,"resize"),n.bind("$destroy",function(){p.returnMapInstance(u.map),s.deleteMap(u)})};t.$inject=["$scope","$element","$attrs","$parse","$interpolate","Attr2MapOptions","NgMap","NgMapPool","escapeRegexpFilter"],angular.module("ngMap").controller("__MapController",t)}(),function(){"use strict";var e,t=function(t,o,r,a){a=a[0]||a[1];var i=e.orgAttributes(o),s=e.filter(r),p=e.getOptions(s,{scope:t}),c=e.getEvents(t,s),u=n(p,c);a.addObject("bicyclingLayers",u),a.observeAttrSetObj(i,r,u),o.bind("$destroy",function(){a.deleteObject("bicyclingLayers",u)})},n=function(e,t){var n=new google.maps.BicyclingLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n},o=function(n){return e=n,{restrict:"E",require:["?^map","?^ngMap"],link:t}};o.$inject=["Attr2MapOptions"],angular.module("ngMap").directive("bicyclingLayer",o)}(),function(){"use strict";var e,t,n=function(t,n,o,r,a){r=r[0]||r[1];{var i=e.filter(o),s=e.getOptions(i,{scope:t}),p=e.getEvents(t,i),c=t.$new(),u=n[0].parentElement.removeChild(n[0]);a(c,function(e){n.empty(),n.append(e),n.on("$destroy",function(){c.$destroy()})})}for(var l in p)google.maps.event.addDomListener(u,l,p[l]);r.addObject("customControls",u);var g=s.position;r.map.controls[google.maps.ControlPosition[g]].push(u),n.bind("$destroy",function(){r.deleteObject("customControls",u)})},o=function(o,r){return e=o,t=r,{restrict:"E",require:["?^map","?^ngMap"],link:n,transclude:!0}};o.$inject=["Attr2MapOptions","NgMap"],angular.module("ngMap").directive("customControl",o)}(),function(){"use strict";var e,t,n,o,r=function(){for(var e="transform WebkitTransform MozTransform OTransform msTransform".split(" "),t=document.createElement("div"),n=0;n-1&&t.splice(n,1),this.el.className=t.join(" ")},a.prototype.onAdd=function(){this.getPanes().overlayMouseTarget.appendChild(this.el)},a.prototype.draw=function(){this.setPosition(),this.setZIndex(this.zIndex),this.setVisible(this.visible)},a.prototype.onRemove=function(){this.el.parentNode.removeChild(this.el)}},s=function(t,n){return function(r,i,s,p){p=p[0]||p[1];var c=e.orgAttributes(i),u=e.filter(s),l=e.getOptions(u,{scope:r}),g=e.getEvents(r,u);i[0].style.display="none";var d=new a(l);setTimeout(function(){r.$watch("["+n.join(",")+"]",function(){d.setContent(t,r)},!0),d.setContent(i[0].innerHTML,r);var e=i[0].firstElementChild&&(i[0].firstElementChild.className||"");d.class&&(e+=" "+d.class),d.addClass("custom-marker"),e&&d.addClass(e),l.position instanceof google.maps.LatLng||o.getGeoLocation(l.position).then(function(e){d.setPosition(e)})});for(var m in g)google.maps.event.addDomListener(d.el,m,g[m]);p.addObject("customMarkers",d),p.observeAttrSetObj(c,s,d),i.bind("$destroy",function(){p.deleteObject("customMarkers",d)})}},p=function(r,a,p,c,u,l){e=c,t=r,n=a,o=u;var g=p.startSymbol(),d=p.endSymbol(),m=new RegExp(l(g)+"([^"+d.substring(0,1)+"]+)"+l(d),"g");return{restrict:"E",require:["?^map","?^ngMap"],compile:function(e){i(),e[0].style.display="none";var t=e.html(),n=t.match(m),o=[];return(n||[]).forEach(function(e){var t=e.replace(g,"").replace(d,"");-1==e.indexOf("::")&&-1==e.indexOf("this.")&&-1==o.indexOf(t)&&o.push(e.replace(g,"").replace(d,""))}),s(t,o)}}};p.$inject=["$timeout","$compile","$interpolate","Attr2MapOptions","NgMap","escapeRegexpFilter"],angular.module("ngMap").directive("customMarker",p)}(),function(){"use strict";var e,t,n,o,r,a=20,i=function(e,t){e.panel&&(e.panel=document.getElementById(e.panel)||document.querySelector(e.panel));var n=new google.maps.DirectionsRenderer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n},s=function(e,i){var s=new google.maps.DirectionsService,p=i;p.travelMode=p.travelMode||"DRIVING";var c=["origin","destination","travelMode","transitOptions","unitSystem","durationInTraffic","waypoints","optimizeWaypoints","provideRouteAlternatives","avoidHighways","avoidTolls","region"];if(p)for(var u in p)p.hasOwnProperty(u)&&-1===c.indexOf(u)&&delete p[u];p.waypoints&&(Array.isArray(p.waypoints)||delete p.waypoints);var l=function(n){if(o&&n)if(r)for(var i in n)n.hasOwnProperty(i)&&(r[i]=n[i]);else r=n;else o=t(function(){r||(r=n),s.route(r,function(t,n){n==google.maps.DirectionsStatus.OK&&(e.setDirections(t),r=void 0)}),t.cancel(o),o=void 0},a)};p&&p.origin&&p.destination&&("current-location"==p.origin?n.getCurrentPosition().then(function(e){p.origin=new google.maps.LatLng(e.coords.latitude,e.coords.longitude),l(p)}):"current-location"==p.destination?n.getCurrentPosition().then(function(e){p.destination=new google.maps.LatLng(e.coords.latitude,e.coords.longitude),l(p)}):l(p))},p=function(o,r,a,p){var c=o;e=p,t=r,n=a;var u=function(n,o,r,a){a=a[0]||a[1];var p=c.orgAttributes(o),u=c.filter(r),l=c.getOptions(u,{scope:n}),g=c.getEvents(n,u),d=c.getAttrsToObserve(p),d=[];u.noWatcher||(d=c.getAttrsToObserve(p));var m=i(l,g);a.addObject("directionsRenderers",m),d.forEach(function(e){!function(e){r.$observe(e,function(n){if("panel"==e)t(function(){var e=document.getElementById(n)||document.querySelector(n);e&&m.setPanel(e)});else if(l[e]!==n){var o=c.toOptionValue(n,{key:e});l[e]=o,s(m,l)}})}(e)}),e.getMap().then(function(){s(m,l)}),o.bind("$destroy",function(){a.deleteObject("directionsRenderers",m)})};return{restrict:"E",require:["?^map","?^ngMap"],link:u}};p.$inject=["Attr2MapOptions","$timeout","NavigatorGeolocation","NgMap"],angular.module("ngMap").directive("directions",p)}(),function(){"use strict";angular.module("ngMap").directive("drawingManager",["Attr2MapOptions",function(e){var t=e;return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,n,o,r){r=r[0]||r[1];var a=t.filter(o),i=t.getOptions(a,{scope:e}),s=t.getControlOptions(a),p=t.getEvents(e,a),c=new google.maps.drawing.DrawingManager({drawingMode:i.drawingmode,drawingControl:i.drawingcontrol,drawingControlOptions:s.drawingControlOptions,circleOptions:i.circleoptions,markerOptions:i.markeroptions,polygonOptions:i.polygonoptions,polylineOptions:i.polylineoptions,rectangleOptions:i.rectangleoptions});o.$observe("drawingControlOptions",function(e){c.drawingControlOptions=t.getControlOptions({drawingControlOptions:e}).drawingControlOptions,c.setDrawingMode(null),c.setMap(r.map)});for(var u in p)google.maps.event.addListener(c,u,p[u]);r.addObject("mapDrawingManager",c),n.bind("$destroy",function(){r.deleteObject("mapDrawingManager",c)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("dynamicMapsEngineLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.visualization.DynamicMapsEngineLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){a=a[0]||a[1];var i=t.filter(r),s=t.getOptions(i,{scope:e}),p=t.getEvents(e,i,p),c=n(s,p);a.addObject("mapsEngineLayers",c)}}}])}(),function(){"use strict";angular.module("ngMap").directive("fusionTablesLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.FusionTablesLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){a=a[0]||a[1];var i=t.filter(r),s=t.getOptions(i,{scope:e}),p=t.getEvents(e,i,p),c=n(s,p);a.addObject("fusionTablesLayers",c),o.bind("$destroy",function(){a.deleteObject("fusionTablesLayers",c)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("heatmapLayer",["Attr2MapOptions","$window",function(e,t){var n=e;return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){function i(e,t){return e.split(".").reduce(function(e,t){return e[t]},t||this)}a=a[0]||a[1];var s=n.filter(r),p=n.getOptions(s,{scope:e});if(p.data=t[r.data]||i(r.data,e),!(p.data instanceof Array))throw"invalid heatmap data";p.data=new google.maps.MVCArray(p.data);{var c=new google.maps.visualization.HeatmapLayer(p);n.getEvents(e,s)}a.addObject("heatmapLayers",c)}}}])}(),function(){"use strict";var e=function(e,t,n,o,r,a,i){var s=e,p=function(e,a,i){var s;!e.position||e.position instanceof google.maps.LatLng||delete e.position,s=new google.maps.InfoWindow(e);for(var p in a)p&&google.maps.event.addListener(s,p,a[p]);var c=n(function(e){angular.isString(i)?o(i).then(function(t){e(angular.element(t).wrap("
    ").parent())},function(e){throw"info-window template request failed: "+e}):e(i)}).then(function(e){var t=e.html().trim();if(1!=angular.element(t).length)throw"info-window working as a template must have a container";s.__template=t.replace(/\s?ng-non-bindable[='"]+/,"")});return s.__open=function(e,n,o){c.then(function(){r(function(){o&&(n.anchor=o);var a=t(s.__template)(n);s.setContent(a[0]),n.$apply(),o&&o.getPosition?s.open(e,o):o&&o instanceof google.maps.LatLng?(s.open(e),s.setPosition(o)):s.open(e),r(function(){var e=s.content.parentElement.parentElement.parentElement;e.className="ng-map-info-window"})})})},s},c=function(e,t,n,o){o=o[0]||o[1],t.css("display","none");var r,c=s.orgAttributes(t),u=s.filter(n),l=s.getOptions(u,{scope:e}),g=s.getEvents(e,u),d=p(l,g,l.template||t);!l.position||l.position instanceof google.maps.LatLng||(r=l.position),r&&i.getGeoLocation(r).then(function(t){d.setPosition(t),d.__open(o.map,e,t);var r=n.geoCallback;r&&a(r)(e)}),o.addObject("infoWindows",d),o.observeAttrSetObj(c,n,d),o.showInfoWindow=o.map.showInfoWindow=o.showInfoWindow||function(t,n,r){var a="string"==typeof t?t:n,i="string"==typeof t?n:r;if("string"==typeof i)if("undefined"!=typeof o.map.markers&&"undefined"!=typeof o.map.markers[i])i=o.map.markers[i];else{if("undefined"==typeof o.map.customMarkers||"undefined"==typeof o.map.customMarkers[i])throw new Error("Cant open info window for id "+i+". Marker or CustomMarker is not defined");i=o.map.customMarkers[i]}var s=o.map.infoWindows[a],p=i?i:this.getPosition?this:null;s.__open(o.map,e,p),o.singleInfoWindow&&(o.lastInfoWindow&&e.hideInfoWindow(o.lastInfoWindow),o.lastInfoWindow=a)},o.hideInfoWindow=o.map.hideInfoWindow=o.hideInfoWindow||function(e,t){var n="string"==typeof e?e:t,r=o.map.infoWindows[n];r.close()},e.showInfoWindow=o.map.showInfoWindow,e.hideInfoWindow=o.map.hideInfoWindow;var m=d.mapId?{id:d.mapId}:0;i.getMap(m).then(function(t){if(d.visible&&d.__open(t,e),d.visibleOnMarker){var n=d.visibleOnMarker;d.__open(t,e,t.markers[n])}})};return{restrict:"E",require:["?^map","?^ngMap"],link:c}};e.$inject=["Attr2MapOptions","$compile","$q","$templateRequest","$timeout","$parse","NgMap"],angular.module("ngMap").directive("infoWindow",e)}(),function(){"use strict";angular.module("ngMap").directive("kmlLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.KmlLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){a=a[0]||a[1];var i=t.orgAttributes(o),s=t.filter(r),p=t.getOptions(s,{scope:e}),c=t.getEvents(e,s),u=n(p,c);a.addObject("kmlLayers",u),a.observeAttrSetObj(i,r,u),o.bind("$destroy",function(){a.deleteObject("kmlLayers",u)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("mapData",["Attr2MapOptions","NgMap",function(e,t){var n=e;return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){a=a[0]||a[1];var i=n.filter(r),s=n.getOptions(i,{scope:e}),p=n.getEvents(e,i,p);t.getMap(a.map.id).then(function(t){for(var n in s){var o=s[n];"function"==typeof e[o]?t.data[n](e[o]):t.data[n](o)}for(var r in p)t.data.addListener(r,p[r])})}}}])}(),function(){"use strict";var e,t,n,o=[],r=[],a=function(n,a,i){var s=i.mapLazyLoadParams||i.mapLazyLoad;if(void 0===window.google||void 0===window.google.maps){r.push({scope:n,element:a,savedHtml:o[r.length]}),window.lazyLoadCallback=function(){e(function(){r.forEach(function(e){e.element.html(e.savedHtml),t(e.element.contents())(e.scope)})},100)};var p=document.createElement("script");p.src=s+(s.indexOf("?")>-1?"&":"?")+"callback=lazyLoadCallback",document.querySelector('script[src="'+p.src+'"]')||document.body.appendChild(p)}else a.html(o),t(a.contents())(n)},i=function(e,t){return!t.mapLazyLoad&&void 0,o.push(e.html()),n=t.mapLazyLoad,void 0!==window.google&&void 0!==window.google.maps?!1:(e.html(""),{pre:a})},s=function(n,o){return t=n,e=o,{compile:i}};s.$inject=["$compile","$timeout"],angular.module("ngMap").directive("mapLazyLoad",s)}(),function(){"use strict";angular.module("ngMap").directive("mapType",["$parse","NgMap",function(e,t){return{restrict:"E",require:["?^map","?^ngMap"],link:function(n,o,r,a){a=a[0]||a[1];var i,s=r.name;if(!s)throw"invalid map-type name";if(i=e(r.object)(n),!i)throw"invalid map-type object";t.getMap().then(function(e){e.mapTypes.set(s,i)}),a.addObject("mapTypes",i)}}}])}(),function(){"use strict";var e=function(){return{restrict:"AE",controller:"__MapController",controllerAs:"ngmap"}};angular.module("ngMap").directive("map",[e]),angular.module("ngMap").directive("ngMap",[e])}(),function(){"use strict";angular.module("ngMap").directive("mapsEngineLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.visualization.MapsEngineLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){a=a[0]||a[1];var i=t.filter(r),s=t.getOptions(i,{scope:e}),p=t.getEvents(e,i,p),c=n(s,p);a.addObject("mapsEngineLayers",c)}}}])}(),function(){"use strict";var e,t,n,o=function(e,t){var o;if(n.defaultOptions.marker)for(var r in n.defaultOptions.marker)"undefined"==typeof e[r]&&(e[r]=n.defaultOptions.marker[r]);e.position instanceof google.maps.LatLng||(e.position=new google.maps.LatLng(0,0)),o=new google.maps.Marker(e),Object.keys(t).length>0;for(var a in t)a&&google.maps.event.addListener(o,a,t[a]);return o},r=function(r,a,i,s){s=s[0]||s[1];var p,c=e.orgAttributes(a),u=e.filter(i),l=e.getOptions(u,r,{scope:r}),g=e.getEvents(r,u);l.position instanceof google.maps.LatLng||(p=l.position);var d=o(l,g);s.addObject("markers",d),p&&n.getGeoLocation(p).then(function(e){d.setPosition(e),l.centered&&d.map.setCenter(e);var n=i.geoCallback;n&&t(n)(r)}),s.observeAttrSetObj(c,i,d),a.bind("$destroy",function(){s.deleteObject("markers",d)})},a=function(o,a,i){return e=o,t=a,n=i,{restrict:"E",require:["^?map","?^ngMap"],link:r}};a.$inject=["Attr2MapOptions","$parse","NgMap"],angular.module("ngMap").directive("marker",a)}(),function(){"use strict";angular.module("ngMap").directive("overlayMapType",["NgMap",function(e){return{restrict:"E",require:["?^map","?^ngMap"],link:function(t,n,o,r){r=r[0]||r[1];var a=o.initMethod||"insertAt",i=t[o.object];e.getMap().then(function(e){if("insertAt"==a){var t=parseInt(o.index,10);e.overlayMapTypes.insertAt(t,i)}else"push"==a&&e.overlayMapTypes.push(i)}),r.addObject("overlayMapTypes",i)}}}])}(),function(){"use strict";var e=function(e,t){var n=e,o=function(e,o,r,a){if("false"===r.placesAutoComplete)return!1;var i=n.filter(r),s=n.getOptions(i,{scope:e}),p=n.getEvents(e,i),c=new google.maps.places.Autocomplete(o[0],s);c.setOptions({strictBounds:s.strictBounds===!0});for(var u in p)google.maps.event.addListener(c,u,p[u]);var l=function(){t(function(){a&&a.$setViewValue(o.val())},100)};google.maps.event.addListener(c,"place_changed",l),o[0].addEventListener("change",l),r.$observe("rectBounds",function(e){if(e){var t=n.toOptionValue(e,{key:"rectBounds"});c.setBounds(new google.maps.LatLngBounds(new google.maps.LatLng(t.south_west.lat,t.south_west.lng),new google.maps.LatLng(t.north_east.lat,t.north_east.lng)))}}),r.$observe("circleBounds",function(e){if(e){var t=n.toOptionValue(e,{key:"circleBounds"}),o=new google.maps.Circle(t);c.setBounds(o.getBounds())}}),r.$observe("types",function(e){if(e){var t=n.toOptionValue(e,{key:"types"});c.setTypes(t)}}),r.$observe("componentRestrictions",function(t){t&&c.setComponentRestrictions(e.$eval(t))})};return{restrict:"A",require:"?ngModel",link:o}};e.$inject=["Attr2MapOptions","$timeout"],angular.module("ngMap").directive("placesAutoComplete",e)}(),function(){"use strict";var e=function(e,t){var n,o=e.name;switch(delete e.name,o){case"circle":e.center instanceof google.maps.LatLng||(e.center=new google.maps.LatLng(0,0)),n=new google.maps.Circle(e);break;case"polygon":n=new google.maps.Polygon(e);break;case"polyline":n=new google.maps.Polyline(e);break;case"rectangle":n=new google.maps.Rectangle(e);break;case"groundOverlay":case"image":var r=e.url,a={opacity:e.opacity,clickable:e.clickable,id:e.id};n=new google.maps.GroundOverlay(r,e.bounds,a)}for(var i in t)t[i]&&google.maps.event.addListener(n,i,t[i]);return n},t=function(t,n,o){var r=t,a=function(t,a,i,s){s=s[0]||s[1];var p,c,u=r.orgAttributes(a),l=r.filter(i),g=r.getOptions(l,{scope:t}),d=r.getEvents(t,l);c=g.name,g.center instanceof google.maps.LatLng||(p=g.center);var m=e(g,d);s.addObject("shapes",m),p&&"circle"==c&&o.getGeoLocation(p).then(function(e){m.setCenter(e),m.centered&&m.map.setCenter(e);var o=i.geoCallback;o&&n(o)(t)}),s.observeAttrSetObj(u,i,m),a.bind("$destroy",function(){s.deleteObject("shapes",m)})};return{restrict:"E",require:["?^map","?^ngMap"],link:a}};t.$inject=["Attr2MapOptions","$parse","NgMap"],angular.module("ngMap").directive("shape",t)}(),function(){"use strict";var e=function(e,t){var n=e,o=function(e,t,n){var o,r;t.container&&(r=document.getElementById(t.container),r=r||document.querySelector(t.container)),r?o=new google.maps.StreetViewPanorama(r,t):(o=e.getStreetView(),o.setOptions(t));for(var a in n)a&&google.maps.event.addListener(o,a,n[a]);return o},r=function(e,r,a){var i=n.filter(a),s=n.getOptions(i,{scope:e}),p=n.getControlOptions(i),c=angular.extend(s,p),u=n.getEvents(e,i);t.getMap().then(function(e){var t=o(e,c,u);e.setStreetView(t),!t.getPosition()&&t.setPosition(e.getCenter()),google.maps.event.addListener(t,"position_changed",function(){t.getPosition()!==e.getCenter()&&e.setCenter(t.getPosition())});var n=google.maps.event.addListener(e,"center_changed",function(){t.setPosition(e.getCenter()),google.maps.event.removeListener(n)})})};return{restrict:"E",require:["?^map","?^ngMap"],link:r}};e.$inject=["Attr2MapOptions","NgMap"],angular.module("ngMap").directive("streetViewPanorama",e)}(),function(){"use strict";angular.module("ngMap").directive("trafficLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.TrafficLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){a=a[0]||a[1];var i=t.orgAttributes(o),s=t.filter(r),p=t.getOptions(s,{scope:e}),c=t.getEvents(e,s),u=n(p,c);a.addObject("trafficLayers",u),a.observeAttrSetObj(i,r,u),o.bind("$destroy",function(){a.deleteObject("trafficLayers",u)})}}}])}(),function(){"use strict";angular.module("ngMap").directive("transitLayer",["Attr2MapOptions",function(e){var t=e,n=function(e,t){var n=new google.maps.TransitLayer(e);for(var o in t)google.maps.event.addListener(n,o,t[o]);return n};return{restrict:"E",require:["?^map","?^ngMap"],link:function(e,o,r,a){a=a[0]||a[1];var i=t.orgAttributes(o),s=t.filter(r),p=t.getOptions(s,{scope:e}),c=t.getEvents(e,s),u=n(p,c);a.addObject("transitLayers",u),a.observeAttrSetObj(i,r,u),o.bind("$destroy",function(){a.deleteObject("transitLayers",u)})}}}])}(),function(){"use strict";var e=/([\:\-\_]+(.))/g,t=/^moz([A-Z])/,n=function(){return function(n){return n.replace(e,function(e,t,n,o){return o?n.toUpperCase():n}).replace(t,"Moz$1")}};angular.module("ngMap").filter("camelCase",n)}(),function(){"use strict";var e=function(){return function(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}};angular.module("ngMap").filter("escapeRegexp",e)}(),function(){"use strict";var e=function(){return function(e){try{return JSON.parse(e),e}catch(t){return e.replace(/([\$\w]+)\s*:/g,function(e,t){return'"'+t+'":'}).replace(/'([^']+)'/g,function(e,t){return'"'+t+'"'}).replace(/''/g,'""')}}};angular.module("ngMap").filter("jsonize",e)}(),function(){"use strict";var isoDateRE=/^(\d{4}\-\d\d\-\d\d([tT][\d:\.]*)?)([zZ]|([+\-])(\d\d):?(\d\d))?$/,Attr2MapOptions=function($parse,$timeout,$log,$interpolate,NavigatorGeolocation,GeoCoder,camelCaseFilter,jsonizeFilter,escapeRegExp){var exprStartSymbol=$interpolate.startSymbol(),exprEndSymbol=$interpolate.endSymbol(),orgAttributes=function(e){e.length>0&&(e=e[0]);for(var t={},n=0;n-1?"&":"?")+"callback=lazyLoadCallback",document.querySelector('script[src="'+r.src+'"]')||document.body.appendChild(r)}else o.resolve(window.google);return o.promise}}};n.$inject=["$q","$timeout"],angular.module("ngMap").service("GoogleMapsApi",n)}(),function(){"use strict";var e,t=function(t){var n=e.defer();return navigator.geolocation?(void 0===t?t={timeout:5e3}:void 0===t.timeout&&(t.timeout=5e3),navigator.geolocation.getCurrentPosition(function(e){n.resolve(e)},function(e){n.reject(e)},t)):n.reject("Browser Geolocation service failed."),n.promise},n=function(n){return e=n,{getCurrentPosition:t}};n.$inject=["$q"],angular.module("ngMap").service("NavigatorGeolocation",n) +}(),function(){"use strict";var e,t,n,o=[],r=function(n){var r=t.createElement("div");r.style.width="100%",r.style.height="100%",n.appendChild(r);var a=new e.google.maps.Map(r,{});return o.push(a),a},a=function(e,t){for(var n,r=0;ri?a.reject("could not find map"):e.setTimeout(function(){r(n+100)},100)}o=o||{},t="object"==typeof t?t.id:t;var a=n.defer(),i=o.timeout||1e4;return r(0),a.promise},g=function(e){if(e.map){var t=Object.keys(p).length;p[e.map.id||t]=e}},d=function(e){var t=Object.keys(p).length-1,n=e.map.id||t;if(e.map){for(var o in e.eventListeners){var r=e.eventListeners[o];google.maps.event.removeListener(r)}e.map.controls&&e.map.controls.forEach(function(e){e.clear()})}e.map.heatmapLayers&&Object.keys(e.map.heatmapLayers).forEach(function(t){e.deleteObject("heatmapLayers",e.map.heatmapLayers[t])}),s.deleteMapInstance(n),delete p[n]},m=function(e,t){var r=n.defer();return!e||e.match(/^current/i)?o.getCurrentPosition(t).then(function(e){var t=e.coords.latitude,n=e.coords.longitude,o=new google.maps.LatLng(t,n);r.resolve(o)},function(e){r.reject(e)}):a.geocode({address:e}).then(function(e){r.resolve(e[0].geometry.location)},function(e){r.reject(e)}),r.promise},f=function(e,t){return function(n){if(n){var o=i("set-"+e),a=r.toOptionValue(n,{key:e});t[o]&&(e.match(/center|position/)&&"string"==typeof a?m(a).then(function(e){t[o](e)}):t[o](a))}}},v=function(e){var t=e.getAttribute("default-style");"true"==t?(e.style.display="block",e.style.height="300px"):("block"!=c(e,"display")&&(e.style.display="block"),c(e,"height").match(/^(0|auto)/)&&(e.style.height="300px"))};angular.module("ngMap").provider("NgMap",function(){var p={};this.setDefaultOptions=function(e){p=e};var c=function(c,y,h,b,M,O,w,L){return e=c,t=y[0],n=h,o=b,r=M,a=O,i=w,s=L,{defaultOptions:p,addMap:g,deleteMap:d,getMap:l,initMap:u,setStyle:v,getGeoLocation:m,observeAndSet:f}};c.$inject=["$window","$document","$q","NavigatorGeolocation","Attr2MapOptions","GeoCoder","camelCaseFilter","NgMapPool"],this.$get=c})}(),function(){"use strict";var e,t=function(t,n){n=n||t.getCenter();var o=e.defer(),r=new google.maps.StreetViewService;return r.getPanoramaByLocation(n||t.getCenter,100,function(e,t){t===google.maps.StreetViewStatus.OK?o.resolve(e.location.pano):o.resolve(!1)}),o.promise},n=function(e,t){var n=new google.maps.StreetViewPanorama(e.getDiv(),{enableCloseButton:!0});n.setPano(t)},o=function(o){return e=o,{getPanorama:t,setPanorama:n}};o.$inject=["$q"],angular.module("ngMap").service("StreetView",o)}(),"ngMap"}); \ No newline at end of file diff --git a/build/scripts/ng-map.no-dependency.js b/build/scripts/ng-map.no-dependency.js index d08b0858d..f28c8d191 100644 --- a/build/scripts/ng-map.no-dependency.js +++ b/build/scripts/ng-map.no-dependency.js @@ -8,7 +8,7 @@ factory(); } }(this, function() { /** - * AngularJS Google Maps Ver. 1.18.2 + * AngularJS Google Maps Ver. 1.18.4 * * The MIT License (MIT) * @@ -205,7 +205,7 @@ angular.module('ngMap', []); } // set options - mapOptions.zoom = mapOptions.zoom || 15; + mapOptions.zoom = (mapOptions.zoom && !isNaN(mapOptions.zoom)) ? +mapOptions.zoom : 15; var center = mapOptions.center; var exprRegExp = new RegExp(escapeRegExp(exprStartSymbol) + '.*' + escapeRegExp(exprEndSymbol)); @@ -420,13 +420,20 @@ angular.module('ngMap', []); var filtered = parser.filter(attrs); var options = parser.getOptions(filtered, {scope: scope}); var events = parser.getEvents(scope, filtered); + var innerScope = scope.$new(); /** * build a custom control element */ var customControlEl = element[0].parentElement.removeChild(element[0]); - var content = $transclude(); - angular.element(customControlEl).append(content); + var content = $transclude( innerScope, function( clone ) { + element.empty(); + element.append( clone ); + element.on( '$destroy', function() { + innerScope.$destroy(); + }); + }); + /** * set events @@ -490,11 +497,22 @@ angular.module('ngMap', []); 'use strict'; var parser, $timeout, $compile, NgMap; + var supportedTransform = (function getSupportedTransform() { + var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' '); + var div = document.createElement('div'); + for(var i = 0; i < prefixes.length; i++) { + if(div && div.style[prefixes[i]] !== undefined) { + return prefixes[i]; + } + } + return false; + })(); + var CustomMarker = function(options) { options = options || {}; this.el = document.createElement('div'); - this.el.style.display = 'inline-block'; + this.el.style.display = 'block'; this.el.style.visibility = "hidden"; this.visible = true; for (var key in options) { /* jshint ignore:line */ @@ -509,6 +527,8 @@ angular.module('ngMap', []); CustomMarker.prototype.setContent = function(html, scope) { this.el.innerHTML = html; this.el.style.position = 'absolute'; + this.el.style.top = 0; + this.el.style.left = 0; if (scope) { $compile(angular.element(this.el).contents())(scope); } @@ -536,8 +556,12 @@ angular.module('ngMap', []); var posPixel = _this.getProjection().fromLatLngToDivPixel(_this.position); var x = Math.round(posPixel.x - (_this.el.offsetWidth/2)); var y = Math.round(posPixel.y - _this.el.offsetHeight - 10); // 10px for anchor - _this.el.style.left = x + "px"; - _this.el.style.top = y + "px"; + if (supportedTransform) { + _this.el.style[supportedTransform] = "translate(" + x + "px, " + y + "px)"; + } else { + _this.el.style.left = x + "px"; + _this.el.style.top = y + "px"; + } _this.el.style.visibility = "visible"; }; if (_this.el.offsetWidth && _this.el.offsetHeight) { @@ -550,8 +574,9 @@ angular.module('ngMap', []); }; CustomMarker.prototype.setZIndex = function(zIndex) { - zIndex && (this.zIndex = zIndex); /* jshint ignore:line */ - this.el.style.zIndex = this.zIndex; + if (zIndex === undefined) return; + (this.zIndex !== zIndex) && (this.zIndex = zIndex); /* jshint ignore:line */ + (this.el.style.zIndex !== this.zIndex) && (this.el.style.zIndex = this.zIndex); }; CustomMarker.prototype.getVisible = function() { @@ -559,7 +584,12 @@ angular.module('ngMap', []); }; CustomMarker.prototype.setVisible = function(visible) { - this.el.style.display = visible ? 'inline-block' : 'none'; + if (this.el.style.display === 'none' && visible) + { + this.el.style.display = 'block'; + } else if (this.el.style.display !== 'none' && !visible) { + this.el.style.display = 'none'; + } this.visible = visible; }; @@ -610,23 +640,26 @@ angular.module('ngMap', []); void 0; var customMarker = new CustomMarker(options); - $timeout(function() { //apply contents, class, and location after it is compiled + // Do we really need a timeout with $scope.$apply() here? + setTimeout(function() { //apply contents, class, and location after it is compiled - scope.$watch('[' + varsToWatch.join(',') + ']', function() { + scope.$watch('[' + varsToWatch.join(',') + ']', function(newVal, oldVal) { customMarker.setContent(orgHtml, scope); }, true); customMarker.setContent(element[0].innerHTML, scope); - var classNames = element[0].firstElementChild.className; + var classNames = + (element[0].firstElementChild) && (element[0].firstElementChild.className || ''); + customMarker.class && (classNames += " " + customMarker.class); customMarker.addClass('custom-marker'); - customMarker.addClass(classNames); + classNames && customMarker.addClass(classNames); void 0; if (!(options.position instanceof google.maps.LatLng)) { NgMap.getGeoLocation(options.position).then( - function(latlng) { - customMarker.setPosition(latlng); - } + function(latlng) { + customMarker.setPosition(latlng); + } ); } @@ -667,6 +700,7 @@ angular.module('ngMap', []); restrict: 'E', require: ['?^map','?^ngMap'], compile: function(element) { + void 0; setCustomMarker(); element[0].style.display ='none'; var orgHtml = element.html(); @@ -724,6 +758,12 @@ angular.module('ngMap', []); 'use strict'; var NgMap, $timeout, NavigatorGeolocation; + var requestTimeout, routeRequest; + // Delay for each route render to accumulate all requests into a single one + // This is required for simultaneous origin\waypoints\destination change + // 20ms should be enough to merge all request data + var routeRenderDelay = 20; + var getDirectionsRenderer = function(options, events) { if (options.panel) { options.panel = document.getElementById(options.panel) || @@ -747,28 +787,52 @@ angular.module('ngMap', []); 'durationInTraffic', 'waypoints', 'optimizeWaypoints', 'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region' ]; - for(var key in request){ - (validKeys.indexOf(key) === -1) && (delete request[key]); + if (request) { + for(var key in request) { + if (request.hasOwnProperty(key)) { + (validKeys.indexOf(key) === -1) && (delete request[key]); + } + } } if(request.waypoints) { - // Check fo valid values - if(request.waypoints == "[]" || request.waypoints === "") { + // Check for acceptable values + if(!Array.isArray(request.waypoints)) { delete request.waypoints; } } var showDirections = function(request) { - directionsService.route(request, function(response, status) { - if (status == google.maps.DirectionsStatus.OK) { - $timeout(function() { - renderer.setDirections(response); - }); + if (requestTimeout && request) { + if (!routeRequest) { + routeRequest = request; + } else { + for (var attr in request) { + if (request.hasOwnProperty(attr)) { + routeRequest[attr] = request[attr]; + } + } } - }); + } else { + requestTimeout = $timeout(function() { + if (!routeRequest) { + routeRequest = request; + } + directionsService.route(routeRequest, function(response, status) { + if (status == google.maps.DirectionsStatus.OK) { + renderer.setDirections(response); + // Unset request for the next call + routeRequest = undefined; + } + }); + $timeout.cancel(requestTimeout); + // Unset expired timeout for the next call + requestTimeout = undefined; + }, routeRenderDelay); + } }; - if (request.origin && request.destination) { + if (request && request.origin && request.destination) { if (request.origin == 'current-location') { NavigatorGeolocation.getCurrentPosition().then(function(ll) { request.origin = new google.maps.LatLng(ll.coords.latitude, ll.coords.longitude); @@ -801,6 +865,11 @@ angular.module('ngMap', []); var events = parser.getEvents(scope, filtered); var attrsToObserve = parser.getAttrsToObserve(orgAttrs); + var attrsToObserve = []; + if (!filtered.noWatcher) { + attrsToObserve = parser.getAttrsToObserve(orgAttrs); + } + var renderer = getDirectionsRenderer(options, events); mapController.addObject('directionsRenderers', renderer); @@ -1066,7 +1135,7 @@ angular.module('ngMap', []); * set options */ var options = parser.getOptions(filtered, {scope: scope}); - options.data = $window[attrs.data] || scope[attrs.data]; + options.data = $window[attrs.data] || parseScope(attrs.data, scope); if (options.data instanceof Array) { options.data = new google.maps.MVCArray(options.data); } else { @@ -1081,6 +1150,13 @@ angular.module('ngMap', []); void 0; mapController.addObject('heatmapLayers', layer); + + //helper get nexted path + function parseScope( path, obj ) { + return path.split('.').reduce( function( prev, curr ) { + return prev[curr]; + }, obj || this ); + } } }; // return }]); @@ -1199,8 +1275,10 @@ angular.module('ngMap', []); } else { infoWindow.open(map); } - var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement; - infoWindowContainerEl.className = "ng-map-info-window"; + $timeout(function() { // to avoid racing condition + var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement; + infoWindowContainerEl.className = "ng-map-info-window"; + }); }); }); }; @@ -1887,6 +1965,7 @@ angular.module('ngMap', []); * Example: * * + * */ /* global google */ (function() { @@ -1903,6 +1982,7 @@ angular.module('ngMap', []); var options = parser.getOptions(filtered, {scope: scope}); var events = parser.getEvents(scope, filtered); var autocomplete = new google.maps.places.Autocomplete(element[0], options); + autocomplete.setOptions({strictBounds: options.strictBounds === true}); for (var eventName in events) { google.maps.event.addListener(autocomplete, eventName, events[eventName]); } @@ -1915,20 +1995,37 @@ angular.module('ngMap', []); google.maps.event.addListener(autocomplete, 'place_changed', updateModel); element[0].addEventListener('change', updateModel); + attrs.$observe('rectBounds', function(val) { + if (val) { + var bounds = parser.toOptionValue(val, {key: 'rectBounds'}); + autocomplete.setBounds(new google.maps.LatLngBounds( + new google.maps.LatLng(bounds.south_west.lat, bounds.south_west.lng), + new google.maps.LatLng(bounds.north_east.lat, bounds.north_east.lng))); + } + }); + + attrs.$observe('circleBounds', function(val) { + if (val) { + var bounds = parser.toOptionValue(val, {key: 'circleBounds'}); + var circle = new google.maps.Circle(bounds); + autocomplete.setBounds(circle.getBounds()); + } + }); + attrs.$observe('types', function(val) { if (val) { var optionValue = parser.toOptionValue(val, {key: 'types'}); autocomplete.setTypes(optionValue); } }); - - attrs.$observe('componentRestrictions', function (val) { - if (val) { - autocomplete.setComponentRestrictions(scope.$eval(val)); - } - }); + + attrs.$observe('componentRestrictions', function (val) { + if (val) { + autocomplete.setComponentRestrictions(scope.$eval(val)); + } + }); }; - + return { restrict: 'A', require: '?ngModel', @@ -1971,7 +2068,7 @@ angular.module('ngMap', []); * @example * Usage: * - * + * * * * Example: @@ -2389,7 +2486,8 @@ angular.module('ngMap', []); function(_, $1) { return '"'+$1+'"'; } - ); + ) + .replace(/''/g, '""'); } }; }; diff --git a/controllers/map-controller.js b/controllers/map-controller.js index 9e39fbfca..7879557af 100644 --- a/controllers/map-controller.js +++ b/controllers/map-controller.js @@ -170,7 +170,7 @@ } // set options - mapOptions.zoom = mapOptions.zoom || 15; + mapOptions.zoom = (mapOptions.zoom && !isNaN(mapOptions.zoom)) ? +mapOptions.zoom : 15; var center = mapOptions.center; var exprRegExp = new RegExp(escapeRegExp(exprStartSymbol) + '.*' + escapeRegExp(exprEndSymbol)); diff --git a/directives/custom-control.js b/directives/custom-control.js index 5eee27dc8..72387f00a 100644 --- a/directives/custom-control.js +++ b/directives/custom-control.js @@ -34,13 +34,20 @@ var filtered = parser.filter(attrs); var options = parser.getOptions(filtered, {scope: scope}); var events = parser.getEvents(scope, filtered); + var innerScope = scope.$new(); /** * build a custom control element */ var customControlEl = element[0].parentElement.removeChild(element[0]); - var content = $transclude(); - angular.element(customControlEl).append(content); + var content = $transclude( innerScope, function( clone ) { + element.empty(); + element.append( clone ); + element.on( '$destroy', function() { + innerScope.$destroy(); + }); + }); + /** * set events diff --git a/directives/custom-marker.js b/directives/custom-marker.js index a0d56fdb7..116842e25 100644 --- a/directives/custom-marker.js +++ b/directives/custom-marker.js @@ -29,11 +29,22 @@ 'use strict'; var parser, $timeout, $compile, NgMap; + var supportedTransform = (function getSupportedTransform() { + var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' '); + var div = document.createElement('div'); + for(var i = 0; i < prefixes.length; i++) { + if(div && div.style[prefixes[i]] !== undefined) { + return prefixes[i]; + } + } + return false; + })(); + var CustomMarker = function(options) { options = options || {}; this.el = document.createElement('div'); - this.el.style.display = 'inline-block'; + this.el.style.display = 'block'; this.el.style.visibility = "hidden"; this.visible = true; for (var key in options) { /* jshint ignore:line */ @@ -48,6 +59,8 @@ CustomMarker.prototype.setContent = function(html, scope) { this.el.innerHTML = html; this.el.style.position = 'absolute'; + this.el.style.top = 0; + this.el.style.left = 0; if (scope) { $compile(angular.element(this.el).contents())(scope); } @@ -75,8 +88,12 @@ var posPixel = _this.getProjection().fromLatLngToDivPixel(_this.position); var x = Math.round(posPixel.x - (_this.el.offsetWidth/2)); var y = Math.round(posPixel.y - _this.el.offsetHeight - 10); // 10px for anchor - _this.el.style.left = x + "px"; - _this.el.style.top = y + "px"; + if (supportedTransform) { + _this.el.style[supportedTransform] = "translate(" + x + "px, " + y + "px)"; + } else { + _this.el.style.left = x + "px"; + _this.el.style.top = y + "px"; + } _this.el.style.visibility = "visible"; }; if (_this.el.offsetWidth && _this.el.offsetHeight) { @@ -89,8 +106,9 @@ }; CustomMarker.prototype.setZIndex = function(zIndex) { - zIndex && (this.zIndex = zIndex); /* jshint ignore:line */ - this.el.style.zIndex = this.zIndex; + if (zIndex === undefined) return; + (this.zIndex !== zIndex) && (this.zIndex = zIndex); /* jshint ignore:line */ + (this.el.style.zIndex !== this.zIndex) && (this.el.style.zIndex = this.zIndex); }; CustomMarker.prototype.getVisible = function() { @@ -98,7 +116,12 @@ }; CustomMarker.prototype.setVisible = function(visible) { - this.el.style.display = visible ? 'inline-block' : 'none'; + if (this.el.style.display === 'none' && visible) + { + this.el.style.display = 'block'; + } else if (this.el.style.display !== 'none' && !visible) { + this.el.style.display = 'none'; + } this.visible = visible; }; @@ -149,29 +172,32 @@ console.log("custom-marker options", options); var customMarker = new CustomMarker(options); - $timeout(function() { //apply contents, class, and location after it is compiled + // Do we really need a timeout with $scope.$apply() here? + setTimeout(function() { //apply contents, class, and location after it is compiled - scope.$watch('[' + varsToWatch.join(',') + ']', function() { + scope.$watch('[' + varsToWatch.join(',') + ']', function(newVal, oldVal) { customMarker.setContent(orgHtml, scope); }, true); customMarker.setContent(element[0].innerHTML, scope); - var classNames = element[0].firstElementChild.className; + var classNames = + (element[0].firstElementChild) && (element[0].firstElementChild.className || ''); + customMarker.class && (classNames += " " + customMarker.class); customMarker.addClass('custom-marker'); - customMarker.addClass(classNames); + classNames && customMarker.addClass(classNames); console.log('customMarker', customMarker, 'classNames', classNames); if (!(options.position instanceof google.maps.LatLng)) { NgMap.getGeoLocation(options.position).then( - function(latlng) { - customMarker.setPosition(latlng); - } + function(latlng) { + customMarker.setPosition(latlng); + } ); } }); - console.log("custom-marker events", "events"); + console.log("custom-marker events", events); for (var eventName in events) { /* jshint ignore:line */ google.maps.event.addDomListener( customMarker.el, eventName, events[eventName]); @@ -206,6 +232,7 @@ restrict: 'E', require: ['?^map','?^ngMap'], compile: function(element) { + console.log('el', element); setCustomMarker(); element[0].style.display ='none'; var orgHtml = element.html(); diff --git a/directives/directions.js b/directives/directions.js index 979f21d5f..f90d6324c 100644 --- a/directives/directions.js +++ b/directives/directions.js @@ -30,6 +30,12 @@ 'use strict'; var NgMap, $timeout, NavigatorGeolocation; + var requestTimeout, routeRequest; + // Delay for each route render to accumulate all requests into a single one + // This is required for simultaneous origin\waypoints\destination change + // 20ms should be enough to merge all request data + var routeRenderDelay = 20; + var getDirectionsRenderer = function(options, events) { if (options.panel) { options.panel = document.getElementById(options.panel) || @@ -53,28 +59,52 @@ 'durationInTraffic', 'waypoints', 'optimizeWaypoints', 'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region' ]; - for(var key in request){ - (validKeys.indexOf(key) === -1) && (delete request[key]); + if (request) { + for(var key in request) { + if (request.hasOwnProperty(key)) { + (validKeys.indexOf(key) === -1) && (delete request[key]); + } + } } if(request.waypoints) { - // Check fo valid values - if(request.waypoints == "[]" || request.waypoints === "") { + // Check for acceptable values + if(!Array.isArray(request.waypoints)) { delete request.waypoints; } } var showDirections = function(request) { - directionsService.route(request, function(response, status) { - if (status == google.maps.DirectionsStatus.OK) { - $timeout(function() { - renderer.setDirections(response); - }); + if (requestTimeout && request) { + if (!routeRequest) { + routeRequest = request; + } else { + for (var attr in request) { + if (request.hasOwnProperty(attr)) { + routeRequest[attr] = request[attr]; + } + } } - }); + } else { + requestTimeout = $timeout(function() { + if (!routeRequest) { + routeRequest = request; + } + directionsService.route(routeRequest, function(response, status) { + if (status == google.maps.DirectionsStatus.OK) { + renderer.setDirections(response); + // Unset request for the next call + routeRequest = undefined; + } + }); + $timeout.cancel(requestTimeout); + // Unset expired timeout for the next call + requestTimeout = undefined; + }, routeRenderDelay); + } }; - if (request.origin && request.destination) { + if (request && request.origin && request.destination) { if (request.origin == 'current-location') { NavigatorGeolocation.getCurrentPosition().then(function(ll) { request.origin = new google.maps.LatLng(ll.coords.latitude, ll.coords.longitude); @@ -107,6 +137,11 @@ var events = parser.getEvents(scope, filtered); var attrsToObserve = parser.getAttrsToObserve(orgAttrs); + var attrsToObserve = []; + if (!filtered.noWatcher) { + attrsToObserve = parser.getAttrsToObserve(orgAttrs); + } + var renderer = getDirectionsRenderer(options, events); mapController.addObject('directionsRenderers', renderer); diff --git a/directives/heatmap-layer.js b/directives/heatmap-layer.js index d01589ff3..75a85d013 100644 --- a/directives/heatmap-layer.js +++ b/directives/heatmap-layer.js @@ -31,7 +31,7 @@ * set options */ var options = parser.getOptions(filtered, {scope: scope}); - options.data = $window[attrs.data] || scope[attrs.data]; + options.data = $window[attrs.data] || parseScope(attrs.data, scope); if (options.data instanceof Array) { options.data = new google.maps.MVCArray(options.data); } else { @@ -46,6 +46,13 @@ console.log('heatmap-layer options', layer, 'events', events); mapController.addObject('heatmapLayers', layer); + + //helper get nexted path + function parseScope( path, obj ) { + return path.split('.').reduce( function( prev, curr ) { + return prev[curr]; + }, obj || this ); + } } }; // return }]); diff --git a/directives/info-window.js b/directives/info-window.js index 3227ee89b..6233b7169 100644 --- a/directives/info-window.js +++ b/directives/info-window.js @@ -111,8 +111,10 @@ } else { infoWindow.open(map); } - var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement; - infoWindowContainerEl.className = "ng-map-info-window"; + $timeout(function() { // to avoid racing condition + var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement; + infoWindowContainerEl.className = "ng-map-info-window"; + }); }); }); }; diff --git a/directives/places-auto-complete.js b/directives/places-auto-complete.js index 506f424c0..982ac42f9 100644 --- a/directives/places-auto-complete.js +++ b/directives/places-auto-complete.js @@ -14,6 +14,7 @@ * Example: * * + * */ /* global google */ (function() { @@ -30,6 +31,7 @@ var options = parser.getOptions(filtered, {scope: scope}); var events = parser.getEvents(scope, filtered); var autocomplete = new google.maps.places.Autocomplete(element[0], options); + autocomplete.setOptions({strictBounds: options.strictBounds === true}); for (var eventName in events) { google.maps.event.addListener(autocomplete, eventName, events[eventName]); } @@ -42,20 +44,37 @@ google.maps.event.addListener(autocomplete, 'place_changed', updateModel); element[0].addEventListener('change', updateModel); + attrs.$observe('rectBounds', function(val) { + if (val) { + var bounds = parser.toOptionValue(val, {key: 'rectBounds'}); + autocomplete.setBounds(new google.maps.LatLngBounds( + new google.maps.LatLng(bounds.south_west.lat, bounds.south_west.lng), + new google.maps.LatLng(bounds.north_east.lat, bounds.north_east.lng))); + } + }); + + attrs.$observe('circleBounds', function(val) { + if (val) { + var bounds = parser.toOptionValue(val, {key: 'circleBounds'}); + var circle = new google.maps.Circle(bounds); + autocomplete.setBounds(circle.getBounds()); + } + }); + attrs.$observe('types', function(val) { if (val) { var optionValue = parser.toOptionValue(val, {key: 'types'}); autocomplete.setTypes(optionValue); } }); - - attrs.$observe('componentRestrictions', function (val) { - if (val) { - autocomplete.setComponentRestrictions(scope.$eval(val)); - } - }); + + attrs.$observe('componentRestrictions', function (val) { + if (val) { + autocomplete.setComponentRestrictions(scope.$eval(val)); + } + }); }; - + return { restrict: 'A', require: '?ngModel', diff --git a/directives/shape.js b/directives/shape.js index 57ae66ecb..eba766203 100644 --- a/directives/shape.js +++ b/directives/shape.js @@ -29,7 +29,7 @@ * @example * Usage: * - * + * * * * Example: diff --git a/filters/jsonize.js b/filters/jsonize.js index c13e8529b..e0f2a32d7 100644 --- a/filters/jsonize.js +++ b/filters/jsonize.js @@ -25,7 +25,8 @@ function(_, $1) { return '"'+$1+'"'; } - ); + ) + .replace(/''/g, '""'); } }; }; diff --git a/gulpfile.js b/gulpfile.js index 6ad16f8a4..e259cd1f4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,7 +14,7 @@ var gutil = require('gulp-util'); var tap = require('gulp-tap'); var bump = require('gulp-bump'); var shell = require('gulp-shell'); -var karma = require('karma').server; +var karma = require('karma').Server; var connect = require('gulp-connect'); var gulpProtractor = require("gulp-protractor").protractor; var File = require('vinyl'); @@ -168,10 +168,10 @@ gulp.task('build', function(callback) { }); gulp.task('test', function (done) { - karma.start({ + new karma({ configFile: __dirname + '/config/karma.conf.js', singleRun: true - }, done); + }, done).start(); }); gulp.task('test:server', function() { diff --git a/index.js b/index.js new file mode 100644 index 000000000..ad505ec18 --- /dev/null +++ b/index.js @@ -0,0 +1,2 @@ +require('./build/scripts/ng-map.js'); +module.exports = 'ngMap'; \ No newline at end of file diff --git a/package.json b/package.json index 132df2b72..6c47091dc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ngmap", - "version": "1.18.2", - "main": "build/scripts/ng-map.js", + "version": "1.18.4", + "main": "index.js", "description": "The Simplest AngularJS Google Maps V3 Directive", "repository": { "type": "git", diff --git a/spec/lib/markerclusterer.js b/spec/lib/markerclusterer.js index 30fed5fd0..722015a8a 100644 --- a/spec/lib/markerclusterer.js +++ b/spec/lib/markerclusterer.js @@ -336,7 +336,6 @@ ClusterIcon.prototype.createCss = function (pos) { * @return {google.maps.Point} The position in pixels. */ ClusterIcon.prototype.getPosFromLatLng_ = function (latlng) { - console.log(this.getProjection()) var pos = this.getProjection().fromLatLngToDivPixel(latlng); pos.x -= this.anchorIcon_[1]; pos.y -= this.anchorIcon_[0]; diff --git a/spec/services/ng-map-pool-spec.js b/spec/services/ng-map-pool-spec.js index 6324cf6cd..1d4661eec 100644 --- a/spec/services/ng-map-pool-spec.js +++ b/spec/services/ng-map-pool-spec.js @@ -8,13 +8,6 @@ describe('NgMapPool', function() { beforeEach(inject(function ($rootScope, _NgMapPool_, _$window_) { scope = $rootScope; NgMapPool = _NgMapPool_, $window = _$window_; - $window.google = { - maps: { - Map: function() { - this.getDiv = function() {}; - } - } - }; })); describe("#getMapInstance #returnMapInstance", function() { diff --git a/testapp/all-examples.json b/testapp/all-examples.json index b61db0056..d0122598b 100644 --- a/testapp/all-examples.json +++ b/testapp/all-examples.json @@ -471,6 +471,18 @@ "path": "testapp/overlay-symbol-dashed.html", "title": null }, + "places-auto-complete-strictbounds-circle.html": { + "path": "testapp/places-auto-complete-strictbounds-circle.html", + "title": "Place Autocomplete Address Form With Circle Bound Restriction" + }, + "places-auto-complete-strictbounds-rect.html": { + "path": "testapp/places-auto-complete-strictbounds-rect.html", + "title": "Place Autocomplete Address Form With Rectangual Bound Restriction" + }, + "places-auto-complete-strictbounds.html": { + "path": "testapp/places-auto-complete-strictbounds.html", + "title": "Place Autocomplete Address Form" + }, "places-auto-complete.html": { "path": "testapp/places-auto-complete.html", "title": "Place Autocomplete Address Form" diff --git a/testapp/layer-kml-features.html b/testapp/layer-kml-features.html index 62e739367..30b0aca8f 100644 --- a/testapp/layer-kml-features.html +++ b/testapp/layer-kml-features.html @@ -17,7 +17,7 @@
    + url="http://googlemaps.github.io/kml-samples/kml/Placemark/placemark.kml"> {{description}}
    diff --git a/testapp/layer-kml.html b/testapp/layer-kml.html index d19a40662..faaff6010 100644 --- a/testapp/layer-kml.html +++ b/testapp/layer-kml.html @@ -6,7 +6,7 @@ - + diff --git a/testapp/map-geolocation.html b/testapp/map-geolocation.html index 5798ad6e3..6c02109d1 100644 --- a/testapp/map-geolocation.html +++ b/testapp/map-geolocation.html @@ -13,7 +13,7 @@
    - Loation found using HTML5. + Location found using HTML5. diff --git a/testapp/marker-remove.html b/testapp/marker-remove.html index 7e65414be..4a634b661 100644 --- a/testapp/marker-remove.html +++ b/testapp/marker-remove.html @@ -5,9 +5,11 @@ + + + + + + + + Auto Complete Type: +
    + + Bounds Lat: + Lng: + Radius: + +
    +
    + + Enter an address:
    + +
    + +
    + Address = {{vm.place.formatted_address}}
    + Location: {{vm.place.geometry.location}}
    +
    + + address : {{vm.address}} + +
    + + + + + diff --git a/testapp/places-auto-complete-strictbounds-rect.html b/testapp/places-auto-complete-strictbounds-rect.html new file mode 100644 index 000000000..1da83f769 --- /dev/null +++ b/testapp/places-auto-complete-strictbounds-rect.html @@ -0,0 +1,70 @@ + + + +Place Autocomplete Address Form With Rectangual Bound Restriction + + + + + + + + + + Auto Complete Type: +
    + + Bounds Lat: + Lng: + Lat: + Lng: + +
    +
    + + Enter an address:
    + +
    + +
    + Address = {{vm.place.formatted_address}}
    + Location: {{vm.place.geometry.location}}
    +
    + + address : {{vm.address}} + +
    + + + + + diff --git a/testapp/places-auto-complete-strictbounds.html b/testapp/places-auto-complete-strictbounds.html new file mode 100644 index 000000000..0f970ed0c --- /dev/null +++ b/testapp/places-auto-complete-strictbounds.html @@ -0,0 +1,70 @@ + + + +Place Autocomplete Address Form + + + + + + + + + + Auto Complete Type: +
    + + Bounds Lat: + Lng: + Lat: + Lng: + +
    +
    + + Enter an address:
    + +
    + +
    + Address = {{vm.place.formatted_address}}
    + Location: {{vm.place.geometry.location}}
    +
    + + address : {{vm.address}} + +
    + + + + +