PageSourceSearch

https://springfieldyellowcab.com/wp-content/plugins/limolabs-icabb…/ngmap/build/scripts/ng-map.js?ver=1

js springfieldyellowcab.com collected 2026-10-08 21:59:08 UTC 77,879 bytes, 2,413 lines download raw bytes

1var ngMap = angular.module('ngMap', []);
2
3/**
4 * @ngdoc service
5 * @name Attr2Options
6 * @description 
7 *   Converts tag attributes to options used by google api v3 objects, map, marker, polygon, circle, etc.
8 */
9/* global google */
10(function() {
11  'use strict';
12
13  var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
14  var MOZ_HACK_REGEXP = /^moz([A-Z])/;  
15
16  function camelCase(name) {
17    return name.
18      replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
19        return offset ? letter.toUpperCase() : letter;
20      }).
21      replace(MOZ_HACK_REGEXP, 'Moz$1');
22  }
23
24  function JSONize(str) {
25    try {       // if parsable already, return as it is
26      JSON.parse(str);
27      return str;
28    } catch(e) { // if not parsable, change little
29      return str
30        // wrap keys without quote with valid double quote
31        .replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'})
32        // replacing single quote wrapped ones to double quote 
33        .replace(/'([^']+)'/g, function(_, $1){return '"'+$1+'"'})
34    }
35  }
36
37  var Attr2Options = function($parse, $timeout, NavigatorGeolocation, GeoCoder) { 
38
39    /**
40     * Returns the attributes of an element as hash
41     * @memberof Attr2Options
42     * @param {HTMLElement} el html element
43     * @returns {Hash} attributes
44     */
45    var orgAttributes = function(el) {
46      (el.length > 0) && (el = el[0]);
47      var orgAttributes = {};
48      for (var i=0; i<el.attributes.length; i++) {
49        var attr = el.attributes[i];
50        orgAttributes[attr.name] = attr.value;
51      }
52      return orgAttributes;
53    };
54
55    var toOptionValue = function(input, options) {
56      var output, key=options.key, scope=options.scope;
57      try { // 1. Number?
58        var num = Number(input);
59        if (isNaN(num)) {
60          throw "Not a number";
61        } else  {
62          output = num;
63        }
64      } catch(err) { 
65        try { // 2.JSON?
66          if (input.match(/^[\+\-]?[0-9\.]+,[ ]*\ ?[\+\-]?[0-9\.]+$/)) { // i.e "-1.0, 89.89"
67            input = "["+input+"]";
68          }
69          output = JSON.parse(JSONize(input));
70          if (output instanceof Array) {
71            var t1stEl = output[0];
72            if (t1stEl.constructor == Object) { // [{a:1}] : not lat/lng ones
73            } else if (t1stEl.constructor == Array) { // [[1,2],[3,4]] 
74              output =  output.map(function(el) {
75                return new google.maps.LatLng(el[0], el[1]);
76              });
77            } else if(!isNaN(parseFloat(t1stEl)) && isFinite(t1stEl)) {
78              return new google.maps.LatLng(output[0], output[1]);
79            }
80          }
81        } catch(err2) {
82          // 3. Object Expression. i.e. LatLng(80,-49)
83          if (input.match(/^[A-Z][a-zA-Z0-9]+\(.*\)$/)) {
84            try {
85              var exp = "new google.maps."+input;
86              output = eval(exp); // TODO, still eval
87            } catch(e) {
88              output = input;
89            } 
90          // 4. Object Expression. i.e. MayTypeId.HYBRID 
91          } else if (input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/)) {
92            try {
93              var matches = input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/);
94              output = google.maps[matches[1]][matches[2]];
95            } catch(e) {
96              output = input;
97            } 
98          // 5. Object Expression. i.e. HYBRID 
99          } else if (input.match(/^[A-Z]+$/)) {
100            try {
101              var capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);
102              if (key.match(/temperatureUnit|windSpeedUnit|labelColor/)) {
103                capitalizedKey = capitalizedKey.replace(/s$/,"");
104                output = google.maps.weather[capitalizedKey][input];
105              } else {
106                output = google.maps[capitalizedKey][input];
107              }
108            } catch(e) {
109              output = input;
110            }
111          } else {
112            output = input;
113          }
114        } // catch(err2)
115      } // catch(err)
116      return output;
117    };
118
119    var getAttrsToObserve = function(attrs) {
120      var attrsToObserve = [];
121      if (attrs["ng-repeat"] || attrs.ngRepeat) {  // if element is created by ng-repeat, don't observe any
122        void(0);
123      } else {
124        for (var attrName in attrs) {
125          var attrValue = attrs[attrName];
126          if (attrValue && attrValue.match(/\{\{.*\}\}/)) { // if attr value is {{..}}
127            void 0;
128            attrsToObserve.push(camelCase(attrName));
129          }
130        }
131      }
132      return attrsToObserve;
133    };
134
135    /**
136     * filters attributes by skipping angularjs methods $.. $$..
137     * @memberof Attr2Options
138     * @param {Hash} attrs tag attributes
139     * @returns {Hash} filterd attributes
140     */
141    var filter = function(attrs) {
142      var options = {};
143      for(var key in attrs) {
144        if (key.match(/^\$/) || key.match(/^ng[A-Z]/)) {
145          void(0);
146        } else {
147          options[key] = attrs[key];
148        }
149      }
150      return options;
151    };
152
153    /**
154     * converts attributes hash to Google Maps API v3 options  
155     * ```
156     *  . converts numbers to number   
157     *  . converts class-like string to google maps instance   
158     *    i.e. `LatLng(1,1)` to `new google.maps.LatLng(1,1)`  
159     *  . converts constant-like string to google maps constant    
160     *    i.e. `MapTypeId.HYBRID` to `google.maps.MapTypeId.HYBRID`   
161     *    i.e. `HYBRID"` to `google.maps.MapTypeId.HYBRID`  
162     * ```
163     * @memberof Attr2Options
164     * @param {Hash} attrs tag attributes
165     * @param {scope} scope angularjs scope
166     * @returns {Hash} options converted attributess
167     */
168    var getOptions = function(attrs, scope) {
169      var options = {};
170      for(var key in attrs) {
171        if (attrs[key]) {
172          if (key.match(/^on[A-Z]/)) { //skip events, i.e. on-click
173            continue;
174          } else if (key.match(/ControlOptions$/)) { // skip controlOptions
175            continue;
176          } else {
177            options[key] = toOptionValue(attrs[key], {scope:scope, key: key});
178          }
179        } // if (attrs[key])
180      } // for(var key in attrs)
181      return options;
182    };
183
184    /**
185     * converts attributes hash to scope-specific event function 
186     * @memberof Attr2Options
187     * @param {scope} scope angularjs scope
188     * @param {Hash} attrs tag attributes
189     * @returns {Hash} events converted events
190     */
191    var getEvents = function(scope, attrs) {
192      var events = {};
vendor: 6,172 bytes, lines 193-374
193      var toLowercaseFunc = function($1){
194        return "_"+$1.toLowerCase();
195      };
196      var eventFunc = function(attrValue) {
197        var matches = attrValue.match(/([^\(]+)\(([^\)]*)\)/);
198        var funcName = matches[1];
199        var argsStr = matches[2].replace(/event[ ,]*/,'');  //remove string 'event'
200        var argsExpr = $parse("["+argsStr+"]"); //for perf when triggering event
201        return function(event) {
202          var args = argsExpr(scope); //get args here to pass updated model values
203          function index(obj,i) {return obj[i];}
204          var f = funcName.split('.').reduce(index, scope);
205          f && f.apply(this, [event].concat(args));
206          $timeout( function() {
207            scope.$apply();
208          });
209        };
210      };
211
212      for(var key in attrs) {
213        if (attrs[key]) {
214          if (!key.match(/^on[A-Z]/)) { //skip if not events
215            continue;
216          }
217          
218          //get event name as underscored. i.e. zoom_changed
219          var eventName = key.replace(/^on/,'');
220          eventName = eventName.charAt(0).toLowerCase() + eventName.slice(1);
221          eventName = eventName.replace(/([A-Z])/g, toLowercaseFunc);
222
223          var attrValue = attrs[key];
224          events[eventName] = new eventFunc(attrValue);
225        }
226      }
227      return events;
228    };
229
230    /**
231     * control means map controls, i.e streetview, pan, etc, not a general control
232     * @memberof Attr2Options
233     * @param {Hash} filtered filtered tag attributes
234     * @returns {Hash} Google Map options
235     */
236    var getControlOptions = function(filtered) {
237      var controlOptions = {};
238      if (typeof filtered != 'object') {
239        return false;
240      }
241
242      for (var attr in filtered) {
243        if (filtered[attr]) {
244          if (!attr.match(/(.*)ControlOptions$/)) { 
245            continue; // if not controlOptions, skip it
246          }
247
248          //change invalid json to valid one, i.e. {foo:1} to {"foo": 1}
249          var orgValue = filtered[attr];
250          var newValue = orgValue.replace(/'/g, '"');
251          newValue = newValue.replace(/([^"]+)|("[^"]+")/g, function($0, $1, $2) {
252            if ($1) {
253              return $1.replace(/([a-zA-Z0-9]+?):/g, '"$1":');
254            } else {
255              return $2; 
256            } 
257          });
258          try {
259            var options = JSON.parse(newValue);
260            for (var key in options) { //assign the right values
261              if (options[key]) {
262                var value = options[key];
263                if (typeof value === 'string') {
264                  value = value.toUpperCase();
265                } else if (key === "mapTypeIds") {
266                  value = value.map( function(str) {
267                    if (str.match(/^[A-Z]+$/)) { // if constant
268                      return google.maps.MapTypeId[str.toUpperCase()];
269                    } else { // else, custom map-type
270                      return str;
271                    }
272                  });
273                } 
274                
275                if (key === "style") {
276                  var str = attr.charAt(0).toUpperCase() + attr.slice(1);
277                  var objName = str.replace(/Options$/,'')+"Style";
278                  options[key] = google.maps[objName][value];
279                } else if (key === "position") {
280                  options[key] = google.maps.ControlPosition[value];
281                } else {
282                  options[key] = value;
283                }
284              }
285            }
286            controlOptions[attr] = options;
287          } catch (e) {
288            void 0;
289          }
290        }
291      } // for
292
293      return controlOptions;
294    };
295
296    return {
297      camelCase: camelCase,
298      filter: filter,
299      getOptions: getOptions,
300      getEvents: getEvents,
301      getControlOptions: getControlOptions,
302      toOptionValue: toOptionValue,
303      getAttrsToObserve: getAttrsToObserve,
304      orgAttributes: orgAttributes
305    }; // return
306
307  }; 
308
309  angular.module('ngMap').service('Attr2Options', ['$parse', '$timeout', 'NavigatorGeolocation', 'GeoCoder', Attr2Options]);
310})();
311
312/**
313 * @ngdoc service
314 * @name GeoCoder
315 * @description
316 *   Provides [defered/promise API](https://docs.angularjs.org/api/ng/service/$q) service for Google Geocoder service
317 */
318/* global google */
319(function() {
320  'use strict';
321  var GeoCoder = function($q) {
322    return {
323      /**
324       * @memberof GeoCoder
325       * @param {Hash} options https://developers.google.com/maps/documentation/geocoding/#geocoding
326       * @example
327       * ```
328       *   GeoCoder.geocode({address: 'the cn tower'}).then(function(result) {
329       *     //... do something with result
330       *   });
331       * ```
332       * @returns {HttpPromise} Future object
333       */
334      geocode : function(options) {
335        var deferred = $q.defer();
336        var geocoder = new google.maps.Geocoder();
337        geocoder.geocode(options, function (results, status) {
338          if (status == google.maps.GeocoderStatus.OK) {
339            deferred.resolve(results);
340          } else {
341            deferred.reject('Geocoder failed due to: '+ status);
342          }
343        });
344        return deferred.promise;
345      }
346    }
347  };
348
349  angular.module('ngMap').service('GeoCoder', ['$q', GeoCoder]);
350})();
351
352/**
353 * @ngdoc service
354 * @name NavigatorGeolocation
355 * @description
356 *  Provides [defered/promise API](https://docs.angularjs.org/api/ng/service/$q) service for navigator.geolocation methods
357 */
358/* global google */
359(function() {
360  'use strict';
361
362  var NavigatorGeolocation = function($q) {
363    return {
364      /**
365       * @memberof NavigatorGeolocation
366       * @param {function} success success callback function
367       * @param {function} failure failure callback function
368       * @example
369       * ```
370       *  NavigatorGeolocation.getCurrentPosition()
371       *    .then(function(position) {
372       *      var lat = position.coords.latitude, lng = position.coords.longitude;
373       *      .. do something lat and lng
374       *    });
375       * ```
376       * @returns {HttpPromise} Future object
377       */
378      getCurrentPosition: function() {
379        var deferred = $q.defer();
380        if (navigator.geolocation) {
381          navigator.geolocation.getCurrentPosition(
382            function(position) {
383              deferred.resolve(position);
384            }, function(evt) {
385              void 0;
386              deferred.reject(evt);
387            }
388          );
389        } else {
390          deferred.reject("Browser Geolocation service failed.");
391        }
392        return deferred.promise;
393      },
394
395      watchPosition: function() {
396        return "TODO";
397      },
398
399      clearWatch: function() {
400        return "TODO";
401      }
402    };
403  }; 
404
405  angular.module('ngMap').service('NavigatorGeolocation', ['$q', NavigatorGeolocation]);
406})();
407
408/**
409 * @ngdoc service
410 * @name StreetView
411 * @description
412 *  Provides [defered/promise API](https://docs.angularjs.org/api/ng/service/$q) service 
413 *  for [Google StreetViewService](https://developers.google.com/maps/documentation/javascript/streetview)
414 */
415/* global google */
416(function() {
417  'use strict';
418
419  var StreetView = function($q) {
420
421    /**
422     * Retrieves panorama id from the given map (and or position)
423     * @memberof StreetView
424     * @param {map} map Google map instance
425     * @param {LatLng} latlng Google LatLng instance  
426     *   default: the center of the map
427     * @example
428     *   StreetView.getPanorama(map).then(function(panoId) {
429     *     $scope.panoId = panoId;
430     *   });
431     * @returns {HttpPromise} Future object
432     */
433    var getPanorama = function(map, latlng) {
434      latlng = latlng || map.getCenter();
435      var deferred = $q.defer();
436      var svs = new google.maps.StreetViewService();
437      svs.getPanoramaByLocation( (latlng||map.getCenter), 100, function (data, status) {
438        // if streetView available
439        if (status === google.maps.StreetViewStatus.OK) {
440          deferred.resolve(data.location.pano);
441        } else {
442          // no street view available in this range, or some error occurred
443          deferred.resolve(false);
444          //deferred.reject('Geocoder failed due to: '+ status);
445        }
446      });
447      return deferred.promise;
448    };
449
450    /**
451     * Set panorama view on the given map with the panorama id
452     * @memberof StreetView
453     * @param {map} map Google map instance
454     * @param {String} panoId Panorama id fro getPanorama method
455     * @example
456     *   StreetView.setPanorama(map, panoId);
457     */
458    var setPanorama = function(map, panoId) {
459      var svp = new google.maps.StreetViewPanorama(map.getDiv(), {enableCloseButton: true});
460      svp.setPano(panoId);
461    };
462
463    return {
464      getPanorama: getPanorama,
465      setPanorama: setPanorama
466    }; // return
467
468  };
469
470  angular.module('ngMap').service('StreetView', ['$q', StreetView]);
471})();
472
473/**
474 * @ngdoc directive
475 * @name bicycling-layer
476 * @requires Attr2Options 
477 * @description 
478 *   Requires:  map directive
479 *   Restrict To:  Element
480 *
481 * @example
482 * Example: 
483 *
484 *   <map zoom="13" center="34.04924594193164, -118.24104309082031">
485 *     <bicycling-layer></bicycling-layer>
486 *    </map>
487 */
488/*jshint -W089*/
489ngMap.directive('bicyclingLayer', ['Attr2Options', function(Attr2Options) {
490  var parser = Attr2Options;
491  
492  var getLayer = function(options, events) {
493    var layer = new google.maps.BicyclingLayer(options);
494    for (var eventName in events) {
495      google.maps.event.addListener(layer, eventName, events[eventName]);
496    }
497    return layer;
498  };
499  
500  return {
501    restrict: 'E',
502    require: '^map',
503
504    link: function(scope, element, attrs, mapController) {
505      var orgAttrs = parser.orgAttributes(element);
506      var filtered = parser.filter(attrs);
507      var options = parser.getOptions(filtered);
508      var events = parser.getEvents(scope, filtered);
509
510      void 0;
511
512      var layer = getLayer(options, events);
513      mapController.addObject('bicyclingLayers', layer);
514      mapController.observeAttrSetObj(orgAttrs, attrs, layer);  //observers
515      element.bind('$destroy', function() {
516        mapController.deleteObject('bicyclingLayers', layer);
517      });
518    }
519   }; // return
520}]);
521
522/**
523 * @ngdoc directive
524 * @name cloud-layer
525 * @requires Attr2Options 
526 * @description 
527 *   Requires:  map directive
528 *   Restrict To:  Element
529 *
530 * @example
531 * Example: 
532 *
533 *   <map zoom="13" center="34.04924594193164, -118.24104309082031">
534 *     <cloud-layer></cloud-layer>
535 *    </map>
536 */
537/*jshint -W089*/
538ngMap.directive('cloudLayer', ['Attr2Options', function(Attr2Options) {
539  var parser = Attr2Options;
540  
541  var getLayer = function(options, events) {
542    var layer = new google.maps.weather.CloudLayer(options);
543    for (var eventName in events) {
544      google.maps.event.addListener(layer, eventName, events[eventName]);
545    }
546    return layer;
547  };
548  
549  return {
550    restrict: 'E',
551    require: '^map',
552
553    link: function(scope, element, attrs, mapController) {
554      var orgAttrs = parser.orgAttributes(element);
555      var filtered = parser.filter(attrs);
556      var options = parser.getOptions(filtered);
557      var events = parser.getEvents(scope, filtered);
558      void 0;
559
560      var layer = getLayer(options, events);
561      mapController.addObject('cloudLayers', layer);
562      mapController.observeAttrSetObj(orgAttrs, attrs, layer);  //observers
563      element.bind('$destroy', function() {
564        mapController.deleteObject('cloudLayers', layer);
565      });
566    }
567   }; // return
568}]);
569
570/*jshint -W030*/
571/* global google, ngMap */
572/**
573 * @ngdoc directive
574 * @name custom-control
575 * @requires Attr2Options 
576 * @requires $compile
577 * @description 
578 *   Build custom control and set to the map with position
579 *   
580 *   Requires:  map directive
581 *
582 *   Restrict To:  Element
583 *
584 * @param {String} position position of this control
585 *        i.e. TOP_RIGHT
586 * @param {Number} index index of the control
587 * @example
588 *
589 * Example: 
590 *  <map center="41.850033,-87.6500523" zoom="3">
591 *    <custom-control id="home" position="TOP_LEFT" index="1">
592 *      <div style="background-color: white;">
593 *        <b>Home</b>
594 *      </div>
595 *    </custom-control>
596 *  </map>
597 *
598 */
599/*jshint -W089*/
600ngMap.directive('customControl', ['Attr2Options', '$compile', function(Attr2Options, $compile)  {
601  'use strict';
602  var parser = Attr2Options;
603
604  return {
605    restrict: 'E',
606    require: '^map',
607    link: function(scope, element, attrs, mapController) {
608      var orgAttrs = parser.orgAttributes(element);
609      var filtered = parser.filter(attrs);
610      var options = parser.getOptions(filtered, scope);
611      var events = parser.getEvents(scope, filtered);
612      void 0;
613
614      /**
615       * build a custom control element
616       */
617      var customControlEl = element[0].parentElement.removeChild(element[0]);
618      $compile(customControlEl.innerHTML.trim())(scope);
619
620      /**
621       * set events
622       */
623      for (var eventName in events) {
624        google.maps.event.addDomListener(customControlEl, eventName, events[eventName]);
625      }
626
627      mapController.addObject('customControls', customControlEl);
628      scope.$on('mapInitialized', function(evt, map) {
629        var position = options.position;
630        map.controls[google.maps.ControlPosition[position]].push(customControlEl);
631      });
632
633    } //link
634  }; // return
635}]);// function
636
637/**
638 * @ngdoc directive
639 * @name directions
640 * @description 
641 *   Enable directions on map. e.g., origin, destination, draggable, waypoints, etc
642 *   
643 *   Requires:  map directive
644 *
645 *   Restrict To:  Element 
646 *
647 * @param {String} &lt;DirectionsRendererOptions> Any DirectionsRendererOptions, 
648 *   https://developers.google.com/maps/documentation/javascript/reference#DirectionsRendererOptions
649 * @param {String} &lt;DirectionsRequest Options> Any DirectionsRequest options, 
650 *   https://developers.google.com/maps/documentation/javascript/reference#DirectionsRequest
651 * @example
652 * Example: 
653 *   <map zoom="14" center="37.7699298, -122.4469157">
654 *     <directions 
655 *       draggable="true"
656 *       panel="directions-panel"
657 *       travel-mode="{{travelMode}}"
658 *       waypoints="[{location:'kingston', stopover:true}]"
659 *       origin="{{origin}}"
660 *       destination="{{destination}}">
661 *     </directions>
662 *   </map> 
663 */
664/* global google */
665(function() {
666  'use strict';
667
668  var getDirectionsRenderer = function(options, events) {
669    if (options.panel) {
670      options.panel = document.getElementById(options.panel) || document.querySelector(options.panel);
671    }
672    var renderer = new google.maps.DirectionsRenderer(options);
673    for (var eventName in events) {
674      google.maps.event.addListener(renderer, eventName, events[eventName]);
675    }
676    return renderer;
677  };
678
679  var directions = function(Attr2Options, $timeout) {
680    var parser = Attr2Options;
681    var directionsService = new google.maps.DirectionsService();
682
683    var updateRoute = function(renderer, options) {
684      /* filter out valid keys only for DirectionsRequest object*/
685      var request = options;
686      request.travelMode = request.travelMode || 'DRIVING';
687      var validKeys = [
688        'origin', 'destination', 'travelMode', 'transitOptions', 'unitSystem',
689        'durationInTraffic', 'waypoints', 'optimizeWaypoints', 
690        'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region'
691      ];
692      for(var key in request){
693        (validKeys.indexOf(key) === -1) && (delete request[key]);
694      }
695
696      if (request.origin && request.destination) {
697        void 0;
698        directionsService.route(request, function(response, status) {
699          if (status == google.maps.DirectionsStatus.OK) {
700            $timeout(function() {
701              renderer.setDirections(response);
702            });
703          }
704        });
705      } 
706    };
707
708    var linkFunc = function(scope, element, attrs, mapController) {
709      var orgAttrs = parser.orgAttributes(element);
710      var filtered = parser.filter(attrs);
711      var options = parser.getOptions(filtered);
712      var events = parser.getEvents(scope, filtered);
713      var attrsToObserve = parser.getAttrsToObserve(orgAttrs);
714
715      var renderer = getDirectionsRenderer(options, events);
716      mapController.addObject('directionsRenderers', renderer);
717      
718      attrsToObserve.forEach(function(attrName) {
719        (function(attrName) {
720          attrs.$observe(attrName, function(val) {
721            if (options[attrName] !== val) { //apply only if changed
722              var optionValue = parser.toOptionValue(val, {key: attrName});
723              void 0;
724              options[attrName] = optionValue;
725              updateRoute(renderer, options);
726            }
727          });
728        })(attrName);
729      });
730
731      scope.$on('mapInitialized', function(event, map) {
732        updateRoute(renderer, options);
733      });
734      scope.$on('$destroy', function(event, map) {
735        mapController.deleteObject('directionsRenderers', renderer);
736      });
737    };
738    
739    return {
740      restrict: 'E',
741      require: '^map',
742      link: linkFunc
743    }
744  }; // var directions
745  directions.$inject = ['Attr2Options', '$timeout'];
746
747  angular.module('ngMap').directive('directions', directions);
748})();
749
750
751/**
752 * @ngdoc directive
753 * @name drawing-manager
754 * @requires Attr2Options
755 * @description
756 *   Requires:  map directive
757 *   Restrict To:  Element
758 *
759 * @example
760 * Example:
761 *
762 *  <map zoom="13" center="37.774546, -122.433523" map-type-id="SATELLITE">
763 *    <drawing-manager  on-overlaycomplete="onMapOverlayCompleted()" position="ControlPosition.TOP_CENTER" drawingModes="POLYGON,CIRCLE" drawingControl="true" circleOptions="fillColor: '#F
763FFF00';fillOpacity: 1;strokeWeight: 5;clickable: false;zIndex: 1;editable: true;" ></drawing-manager>
764 *  </map>
765 *
766 *  TODO: Add remove button.
767 *  currently, for out solution, we have the shapes/markers in our own controller, and we use some css classes to change the shape button
768 *  to a remove button (<div>X</div>) and have the remove operation in our own controller.
769 */
770/*jshint -W089*/
771ngMap.directive('drawingManager', ['Attr2Options', function(Attr2Options) {
772  var parser = Attr2Options;
773
774  return {
775    restrict: 'E',
776    require: '^map',
777
778    link: function(scope, element, attrs, mapController) {
779      var orgAttrs = parser.orgAttributes(element);
780      var filtered = parser.filter(attrs);
781      var options = parser.getOptions(filtered);
782      var controlOptions = parser.getControlOptions(filtered);
783      var events = parser.getEvents(scope, filtered);
784
785      void 0;
786
787      /**
788       * set options
789       */
790      var drawingManager = new google.maps.drawing.DrawingManager({
791        drawingMode: options.drawingmode,
792        drawingControl: options.drawingcontrol,
793        drawingControlOptions: controlOptions.drawingControlOptions,
794        circleOptions:options.circleoptions,
795        markerOptions:options.markeroptions,
796        polygonOptions:options.polygonoptions,
797        polylineOptions:options.polylineoptions,
798        rectangleOptions:options.rectangleoptions
799      });
800
801
802      /**
803       * set events
804       */
805      var events = parser.getEvents(scope, filtered);
806      for (var eventName in events) {
807        google.maps.event.addListener(drawingManager, eventName, events[eventName]);
808      }
809
810      mapController.addObject('mapDrawingManager', drawingManager);
811    }
812  }; // return
813}]);
814
815/**
816 * @ngdoc directive
817 * @name dynamic-maps-engine-layer
818 * @description 
819 *   Requires:  map directive
820 *   Restrict To:  Element
821 *
822 * @example
823 * Example: 
824 *   <map zoom="14" center="[59.322506, 18.010025]">
825 *     <dynamic-maps-engine-layer layer-id="06673056454046135537-08896501997766553811"></dynamic-maps-engine-layer>
826 *    </map>
827 */
828/*jshint -W089*/
829ngMap.directive('dynamicMapsEngineLayer', ['Attr2Options', function(Attr2Options) {
830  var parser = Attr2Options;
831
832  var getDynamicMapsEngineLayer = function(options, events) {
833    var layer = new google.maps.visualization.DynamicMapsEngineLayer(options);
834
835    for (var eventName in events) {
836      google.maps.event.addListener(layer, eventName, events[eventName]);
837    }
838
839    return layer;
840  };
841
842  
843  return {
844    restrict: 'E',
845    require: '^map',
846
847    link: function(scope, element, attrs, mapController) {
848      var filtered = parser.filter(attrs);
849      var options = parser.getOptions(filtered);
850      var events = parser.getEvents(scope, filtered, events);
851      void 0;
852
853      var layer = getDynamicMapsEngineLayer(options, events);
854      mapController.addObject('mapsEngineLayers', layer);
855    }
856   }; // return
857}]);
858
859/**
860 * @ngdoc directive
861 * @name fusion-tables-layer
862 * @description 
863 *   Requires:  map directive
864 *   Restrict To:  Element
865 *
866 * @example
867 * Example: 
868 *   <map zoom="11" center="41.850033, -87.6500523">
869 *     <fusion-tables-layer query="{
870 *       select: 'Geocodable address',
871 *       from: '1mZ53Z70NsChnBMm-qEYmSDOvLXgrreLTkQUvvg'}">
872 *     </fusion-tables-layer>
873 *   </map>
874 */
875/*jshint -W089*/
876ngMap.directive('fusionTablesLayer', ['Attr2Options', function(Attr2Options) {
877  var parser = Attr2Options;
878
879  var getLayer = function(options, events) {
880    var layer = new google.maps.FusionTablesLayer(options);
881
882    for (var eventName in events) {
883      google.maps.event.addListener(layer, eventName, events[eventName]);
884    }
885
886    return layer;
887  };
888
889  
890  return {
891    restrict: 'E',
892    require: '^map',
893
894    link: function(scope, element, attrs, mapController) {
895      var filtered = parser.filter(attrs);
896      var options = parser.getOptions(filtered);
897      var events = parser.getEvents(scope, filtered, events);
898      void 0;
899
900      var layer = getLayer(options, events);
901      mapController.addObject('fusionTablesLayers', layer);
902    }
903   }; // return
904}]);
905
906/**
907 * @ngdoc directive
908 * @name heatmap-layer
909 * @requires Attr2Options 
910 * @description 
911 *   Requires:  map directive
912 *   Restrict To:  Element
913 *
914 * @example
915 * Example: 
916 *
917 *   <map zoom="11" center="[41.875696,-87.624207]">
918 *     <heatmap-layer data="taxiData"></heatmap-layer>
919 *   </map>
920 */
921/*jshint -W089*/
922ngMap.directive('heatmapLayer', ['Attr2Options', '$window', function(Attr2Options, $window) {
923  var parser = Attr2Options;
924  
925  return {
926    restrict: 'E',
927    require: '^map',
928
929    link: function(scope, element, attrs, mapController) {
930      var filtered = parser.filter(attrs);
931
932      /**
933       * set options 
934       */
935      var options = parser.getOptions(filtered);
936      options.data = $window[attrs.data] || scope[attrs.data];
937      if (options.data instanceof Array) {
938        options.data = new google.maps.MVCArray(options.data);
939      } else {
940        throw "invalid heatmap data";
941      }
942      var layer = new google.maps.visualization.HeatmapLayer(options);
943
944      /**
945       * set events 
946       */
947      var events = parser.getEvents(scope, filtered);
948      void 0;
949
950      mapController.addObject('heatmapLayers', layer);
951    }
952   }; // return
953}]);
954
955/**
956 * @ngdoc directive
957 * @name info-window
958 * @requires Attr2Options
959 * @requires $compile
960 * @description
961 *   Defines infoWindow and provides compile method
962 *
963 *   Requires:  map directive
964 *
965 *   Restrict To:  Element
966 *
967 * @param {Boolean} visible Indicates to show it when map is initialized
968 * @param {Boolean} visible-on-marker Indicates to show it on a marker when map is initialized
969 * @param {Expression} geo-callback if position is an address, the expression is will be performed when geo-lookup is successful. e.g., geo-callback="showDetail()"
970 * @param {String} &lt;InfoWindowOption> Any InfoWindow options,
971 *        https://developers.google.com/maps/documentation/javascript/reference?csw=1#InfoWindowOptions
972 * @param {String} &lt;InfoWindowEvent> Any InfoWindow events, https://developers.google.com/maps/documentation/javascript/reference
973 * @example
974 * Usage:
975 *   <map MAP_ATTRIBUTES>
976 *    <info-window id="foo" ANY_OPTIONS ANY_EVENTS"></info-window>
977 *   </map>
978 *
979 * Example:
980 *  <map center="41.850033,-87.6500523" zoom="3">
981 *    <info-window id="1" position="41.850033,-87.6500523" >
982 *      <div ng-non-bindable>
983 *        Chicago, IL<br/>
984 *        LatLng: {{chicago.lat()}}, {{chicago.lng()}}, <br/>
985 *        World Coordinate: {{worldCoordinate.x}}, {{worldCoordinate.y}}, <br/>
986 *        Pixel Coordinate: {{pixelCoordinate.x}}, {{pixelCoordinate.y}}, <br/>
987 *        Tile Coordinate: {{tileCoordinate.x}}, {{tileCoordinate.y}} at Zoom Level {{map.getZoom()}}
988 *      </div>
989 *    </info-window>
990 *  </map>
991 */
992/* global google */
993(function() {
994  'use strict';
995
996  var infoWindow = function(Attr2Options, $compile, $timeout, $parse)  {
997    var parser = Attr2Options;
998
999    var getInfoWindow = function(options, events, element) {
1000      var infoWindow;
1001
1002      /**
1003       * set options
1004       */
1005      if (options.position && !(options.position instanceof google.maps.LatLng)) {
1006        delete options.position;
1007      }
1008      infoWindow = new google.maps.InfoWindow(options);
1009
1010      /**
1011       * set events
1012       */
1013      if (Object.keys(events).length > 0) {
1014        void 0;
1015      }
1016      for (var eventName in events) {
1017        if (eventName) {
1018          google.maps.event.addListener(infoWindow, eventName, events[eventName]);
1019        }
1020      }
1021
1022      /**
1023       * set template ane template-relate functions
1024       * it must have a container element with ng-non-bindable
1025       */
1026      var template = element.html().trim();
1027      if (angular.element(template).length != 1) {
1028        throw "info-window working as a template must have a container";
1029      }
1030      infoWindow.__template = template.replace(/\s?ng-non-bindable[='"]+/,"");
1031
1032      infoWindow.__compile = function(scope, anchor) {
1033        anchor && (scope['this'] = anchor);
1034        var el = $compile(infoWindow.__template)(scope);
1035        infoWindow.setContent(el[0]);
1036        scope.$apply();
1037      };
1038
1039      infoWindow.__open = function(map, scope, anchor) {
1040        $timeout(function() {
1041          infoWindow.__compile(scope, anchor);
1042          if (anchor && anchor.getPosition) {
1043            infoWindow.open(map, anchor);
1044          } else if (anchor && anchor instanceof google.maps.LatLng) {
1045            infoWindow.open(map);
1046            infoWindow.setPosition(anchor);
1047          } else {
1048            infoWindow.open(map);
1049          }
1050        });
1051      };
1052
1053      return infoWindow;
1054    };
1055
1056    var linkFunc = function(scope, element, attrs, mapController) {
1057      element.css('display','none');
1058      var orgAttrs = parser.orgAttributes(element);
1059      var filtered = parser.filter(attrs);
1060      var options = parser.getOptions(filtered, scope);
1061      var events = parser.getEvents(scope, filtered);
1062      void 0;
1063
1064      var address;
1065      if (options.position && !(options.position instanceof google.maps.LatLng)) {
1066        address = options.position;
1067      }
1068      var infoWindow = getInfoWindow(options, events, element);
1069      if (address) {
1070        mapController.getGeoLocation(address).then(function(latlng) {
1071          infoWindow.setPosition(latlng);
1072          infoWindow.__open(mapController.map, scope, latlng);
1073          var geoCallback = attrs.geoCallback;
1074          geoCallback && $parse(geoCallback)(scope);
1075        });
1076      }
1077
1078      mapController.addObject('infoWindows', infoWindow);
1079      mapController.observeAttrSetObj(orgAttrs, attrs, infoWindow); /* observers */
1080
1081      scope.$on('mapInitialized', function(evt, map) {
1082        infoWindow.visible && infoWindow.__open(map, scope);
1083        if (infoWindow.visibleOnMarker) {
1084          var markerId = infoWindow.visibleOnMarker;
1085          infoWindow.__open(map, scope, map.markers[markerId]);
1086        }
1087      });
1088
1089      /**
1090       * provide showInfoWindow method to scope
1091       */
1092
1093      scope.showInfoWindow  = function(e, id, marker) {
1094        var infoWindow = mapController.map.infoWindows[id];
1095        var anchor = marker ? marker : (this.getPosition ? this 
1095: null);
1096        infoWindow.__open(mapController.map, scope, anchor);
1097      };
1098
1099      /**
1100       * provide hideInfoWindow method to scope
1101       */
1102      scope.hideInfoWindow  = scope.hideInfoWindow ||
1103        function(event, id) {
1104          var infoWindow = mapController.map.infoWindows[id];
1105          infoWindow.close();
1106        };
1107
1108    }; //link
1109
1110    return {
1111      restrict: 'E',
1112      require: '^map',
1113      link: linkFunc
1114    };
1115
1116  }; // infoWindow
1117  infoWindow.$inject = ['Attr2Options', '$compile', '$timeout', '$parse'];
1118
1119  angular.module('ngMap').directive('infoWindow', infoWindow);
1120})();
1121
1122/**
1123 * @ngdoc directive
1124 * @name kml-layer
1125 * @requires Attr2Options 
1126 * @description 
1127 *   renders Kml layer on a map
1128 *   Requires:  map directive
1129 *   Restrict To:  Element
1130 *
1131 * @param {Url} url url of the kml layer
1132 * @param {KmlLayerOptions} KmlLayerOptions
1133 *   (https://developers.google.com/maps/documentation/javascript/reference#KmlLayerOptions)  
1134 * @param {String} &lt;KmlLayerEvent> Any KmlLayer events, https://developers.google.com/maps/documentation/javascript/reference
1135 * @example
1136 * Usage: 
1137 *   <map MAP_ATTRIBUTES>
1138 *    <kml-layer ANY_KML_LAYER ANY_KML_LAYER_EVENTS"></kml-layer>
1139 *   </map>
1140 *
1141 * Example: 
1142 *
1143 *   <map zoom="11" center="[41.875696,-87.624207]">
1144 *     <kml-layer url="https://gmaps-samples.googlecode.com/svn/trunk/ggeoxml/cta.kml" ></kml-layer>
1145 *    </map>
1146 */
1147/*jshint -W089*/
1148ngMap.directive('kmlLayer', ['Attr2Options', function(Attr2Options) {
1149  var parser = Attr2Options;
1150  
1151  var getKmlLayer = function(options, events) {
1152    var kmlLayer = new google.maps.KmlLayer(options);
1153    for (var eventName in events) {
1154      google.maps.event.addListener(kmlLayer, eventName, events[eventName]);
1155    }
1156    return kmlLayer;
1157  };
1158  
1159  return {
1160    restrict: 'E',
1161    require: '^map',
1162
1163    link: function(scope, element, attrs, mapController) {
1164      var orgAttrs = parser.orgAttributes(element);
1165      var filtered = parser.filter(attrs);
1166      var options = parser.getOptions(filtered);
1167      var events = parser.getEvents(scope, filtered);
1168      void 0;
1169
1170      var kmlLayer = getKmlLayer(options, events);
1171      mapController.addObject('kmlLayers', kmlLayer);
1172      mapController.observeAttrSetObj(orgAttrs, attrs, kmlLayer);  //observers
1173      element.bind('$destroy', function() {
1174        mapController.deleteObject('kmlLayers', kmlLayer);
1175      });
1176    }
1177   }; // return
1178}]);
1179
1180/**
1181 * @ngdoc directive
1182 * @name map-data
1183 * @description 
1184 *   set map data
1185 *   Requires:  map directive
1186 *   Restrict To:  Element
1187 *
1188 * @param {String} method-name, run map.data[method-name] with attribute value
1189 * @example
1190 * Example: 
1191 *
1192 *   <map zoom="11" center="[41.875696,-87.624207]">
1193 *     <map-data load-geo-json="https://storage.googleapis.com/maps-devrel/google.json"></map-data>
1194 *    </map>
1195 */
1196ngMap.directive('mapData', ['Attr2Options', function(Attr2Options) {
1197  var parser = Attr2Options;
1198  
1199  return {
1200    restrict: 'E',
1201    require: '^map',
1202
1203    link: function(scope, element, attrs, mapController) {
1204      var filtered = parser.filter(attrs);
1205      var options = parser.getOptions(filtered);
1206      var events = parser.getEvents(scope, filtered, events);
1207
1208      void 0;
1209      scope.$on('mapInitialized', function(event, map) {
1210        /**
1211         * options
1212         */
1213        for (var key in options) {
1214          if (key) {
1215            var val = options[key];
1216            if (typeof scope[val] === "function") {
1217              map.data[key](scope[val]);
1218            } else {
1219              map.data[key](val);
1220            }
1221          } // if (key)
1222        }
1223
1224        /**
1225         * events
1226         */
1227        for (var eventName in events) {
1228          if (events[eventName]) {
1229            map.data.addListener(eventName, events[eventName]);
1230          }
1231        }
1232      });
1233    }
1234   }; // return
1235}]);
1236
1237/**
1238 * @ngdoc directive
1239 * @name lazy-load
1240 * @requires Attr2Options 
1241 * @description 
1242 *   Requires: Delay the initialization of directive until required .js loads
1243 *   Restrict To: Attribute 
1244 *
1245 * @param {String} lazy-load
1246      script source file location
1247 *    example:  
1248 *      'http://maps.googlecom/maps/api/js'   
1249
1250 * @example
1251 * Example: 
1252 *
1253 *   <div lazy-load="http://maps.google.com/maps/api/js">
1254 *     <map center="Brampton" zoom="10">
1255 *       <marker position="Brampton"></marker>
1256 *     </map>
1257 *   </div>
1258 */
1259/*jshint -W089*/
1260ngMap.directive('mapLazyLoad', ['$compile', '$timeout', function($compile, $timeout) {
1261  'use strict';
1262  var directiveDefinitionObject = {
1263    compile: function(tElement, tAttrs) {
1264      (!tAttrs.mapLazyLoad) && void 0;
1265      var savedHtml = tElement.html(), src = tAttrs.mapLazyLoad;
1266      /**
1267       * if already loaded, stop processing it
1268       */
1269      if (document.querySelector('script[src="'+src+'?callback=lazyLoadCallback"]')) {
1270        return false;
1271      }
1272
1273      tElement.html('');  // will compile again after script is loaded
1274      return {
1275        pre: function(scope, element, attrs) {
1276          window.lazyLoadCallback = function() {
1277            void 0;
1278            $timeout(function() { /* give some time to load */
1279              element.html(savedHtml);
1280              $compile(element.contents())(scope);
1281            }, 100);
1282          };
1283          if(window.google === undefined || window.google.maps === undefined) {
1284            var scriptEl = document.createElement('script');
1285            scriptEl.src = src + (src.indexOf('?') > -1 ? '&' : '?') + 'callback=lazyLoadCallback';
1286            document.body.appendChild(scriptEl);
1287          } else {
1288            element.html(savedHtml);
1289            $compile(element.contents())(scope);
1290          }
1291        }
1292      };
1293    }
1294  };
1295  return directiveDefinitionObject;
1296}]);
1297
1298/**
1299 * @ngdoc directive
1300 * @name map-type
1301 * @requires Attr2Options 
1302 * @description 
1303 *   Requires:  map directive
1304 *   Restrict To:  Element
1305 *
1306 * @example
1307 * Example: 
1308 *
1309 *   <map zoom="13" center="34.04924594193164, -118.24104309082031">
1310 *     <map-type name="coordinate" object="coordinateMapType"></map-type>
1311 *   </map>
1312 */
1313/*jshint -W089*/
1314ngMap.directive('mapType', ['Attr2Options', '$window', function(Attr2Options, $window) {
1315  var parser = Attr2Options;
1316  
1317  return {
1318    restrict: 'E',
1319    require: '^map',
1320
1321    link: function(scope, element, attrs, mapController) {
1322      var mapTypeName = attrs.name, mapTypeObject;
1323      if (!mapTypeName) {
1324        throw "invalid map-type name";
1325      }
1326      if (attrs.object) {
1327        var __scope = scope[attrs.object] ? scope : $window;
1328        mapTypeObject = __scope[attrs.object];
1329        if (typeof mapTypeObject == "function") {
1330          mapTypeObject = new mapTypeObject();
1331        }
1332      }
1333      if (!mapTypeObject) {
1334        throw "invalid map-type object";
1335      }
1336
1337      scope.$on('mapInitialized', function(evt, map) {
1338        map.mapTypes.set(mapTypeName, mapTypeObject);
1339      });
1340      mapController.addObject('mapTypes', mapTypeObject);
1341    }
1342   }; // return
1343}]);
1344
1345/**
1346 * @ngdoc directive
1347 * @name map
1348 * @requires Attr2Options
1349 * @description
1350 *   Implementation of {@link MapController}
1351 *   Initialize a Google map within a `<div>` tag with given options and register events
1352 *   It accepts children directives; marker, shape, or marker-clusterer
1353 *
1354 *   It initialize map, children tags, then emits message as soon as the action is done
1355 *   The message emitted from this directive is;
1356 *     . mapInitialized
1357 *
1358 *   Restrict To:
1359 *     Element
1360 *
1361 * @param {Expression} geo-callback if center is an address or current location, the expression is will be executed when geo-lookup is successful. e.g., geo-callback="showMyStoreInfo()"
1362 * @param {Array} geo-fallback-center 
1363 *    The center of map incase geolocation failed. i.e. [0,0]
1364 * @param {String} init-event The name of event to initialize this map. 
1365 *        If this option is given, the map won't be initialized until the event is received.
1366 *        To invoke the event, use $scope.$emit or $scope.$broacast. 
1367 *        i.e. <map init-event="init-map" ng-click="$emit('init-map')" center=... ></map>
1368 * @param {String} &lt;MapOption> Any Google map options, 
1369 *        https://developers.google.com/maps/documentation/javascript/reference?csw=1#MapOptions
1370 * @param {String} &lt;MapEvent> Any Google map events, 
1371 *        https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/map_events.html
1372 * @example
1373 * Usage:
1374 *   <map MAP_OPTIONS_OR_MAP_EVENTS ..>
1375 *     ... Any children directives
1376 *   </map>
1377 * 
1378 * Example:
1379 *   <map center="[40.74, -74.18]" on-click="doThat()">
1380 *   </map>
1381 *
1382 *   <map geo-fallback-center="[40.74, -74.18]">
1383 *   </map>
1384 */
1385/* global google */
1386(function() {
1387  'use strict';
1388
1389  function getStyle(el,styleProp) {
1390    var y;
1391    if (el.currentStyle) {
1392      y = el.currentStyle[styleProp];
1393    } else if (window.getComputedStyle) {
1394      y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
1395    }
1396    return y;
1397  }
1398
1399  var mapDirective = function(Attr2Options, $timeout, $parse) {
1400    var parser = Attr2Options;
1401
1402    /**
1403     * Initialize map and events
1404     * @memberof map
1405     * @param {$scope} scope
1406     * @param {angular.element} element
1407     * @param {Hash} attrs
1408     * @ctrl {MapController} ctrl
1409     */
1410    var linkFunc = function(scope, element, attrs, ctrl) {
1411      var orgAttrs = parser.orgAttributes(element);
1412
1413      scope.google = google;  //used by $scope.eval in Attr2Options to avoid eval()
1414
1415      /**
1416       * create a new `div` inside map tag, so that it does not touch map element
1417       * https://stackoverflow.com/questions/20955356
1418       */
1419      var el = document.createElement("div");
1420      el.style.width = "100%";
1421      el.style.height = "100%";
1422      element.prepend(el);
1423
1424      /**
1425       * if style is not given to the map element, set display and height
1426       */
1427      if (getStyle(element[0], 'display') != "block") {
1428        element.css('display','block');
1429      }
1430      if (getStyle(element[0], 'height').match(/^(0|auto)/)) {
1431        element.css('height','300px');
1432      }
1433
1434      /**
1435       * disable drag event
1436       */
1437      element[0].addEventListener('dragstart', function(event) {
1438        event.preventDefault();
1439        return false;
1440      });
1441
1442      /**
1443       * initialize function
1444       */
1445      var initializeMap = function(mapOptions, mapEvents) {
1446        var map = new google.maps.Map(el, {});
1447        map.markers = {};
1448        map.shapes = {};
1449       
1450        /**
1451         * resize the map to prevent showing partially, in case intialized too early
1452         */
1453        $timeout(function() {
1454          google.maps.event.trigger(map, "resize");
1455        });
1456
1457        /**
1458         * set options
1459         */
1460        mapOptions.zoom = mapOptions.zoom || 15;
1461        var center = mapOptions.center;
1462        if (!center) {
1463          mapOptions.center = new google.maps.LatLng(0,0);
1464        } else if (!(center instanceof google.maps.LatLng)) {
1465          delete mapOptions.center;
1466          ctrl.getGeoLocation(center).then(function(latlng) {
1467            map.setCenter(latlng);
1468            var geoCallback = attrs.geoCallback;
1469            geoCallback && $parse(geoCallback)(scope);
1470          }, function(error) {
1471            map.setCenter(options.geoFallbackCenter);
1472          });
1473        }
1474        map.setOptions(mapOptions);
1475
1476        /**
1477         * set events
1478         */
1479        for (var eventName in mapEvents) {
1480          if (eventName) {
1481            google.maps.event.addListener(map, eventName, mapEvents[eventName]);
1482          }
1483        }
1484
1485        /**
1486         * set observers
1487         */
1488        ctrl.observeAttrSetObj(orgAttrs, attrs, map);
1489
1490        /**
1491         * set controller and set objects
1492         * so that map can be used by other directives; marker or shape 
1493         * ctrl._objects are gathered when marker and shape are initialized before map is set
1494         */
1495        ctrl.map = map;   /* so that map can be used by other directives; marker or shape */
1496        ctrl.addObjects(ctrl._objects);
1497
1498        // /* providing method to add a marker used by user scope */
1499        // map.addMarker = ctrl.addMarker;
1500
1501        /**
1502         * set map for scope and controller and broadcast map event
1503         * scope.map will be overwritten if user have multiple maps in a scope,
1504         * thus the last map will be set as scope.map.
1505         * however an `mapInitialized` event will be emitted every time.
1506         */
1507        scope.map = map;
1508        scope.map.scope = scope;
1509        google.maps.event.addListenerOnce(map, "idle", function() {
1510          scope.$emit('mapInitialized', map);  
1511        });
1512
1513        // the following lines will be deprecated on behalf of mapInitialized
1514        // to collect maps, we should use scope.maps in your own controller, i.e. MyCtrl
1515        scope.maps = scope.maps || {}; 
1516        scope.maps[options.id||Object.keys(scope.maps).length] = map;
1517        scope.$emit('mapsInitialized', scope.maps);  
1518      }; // function initializeMap()
1519
1520      /**
1521       * get map options and events
1522       */
1523      var filtered = parser.filter(attrs);
1524      var options = parser.getOptions(filtered, scope);
1525      var controlOptions = parser.getControlOptions(filtered);
1526      var mapOptions = angular.extend(options, controlOptions);
1527      var mapEvents = parser.getEvents(scope, filtered);
1528      void 0;
1529
1530      if (attrs.initEvent) { // allows controlled initialization
1531        scope.$on(attrs.initEvent, function() {
1532          !ctrl.map && initializeMap(mapOptions, mapEvents); // init if not done
1533        });
1534      } else {
1535        initializeMap(mapOptions, mapEvents);
1536      } // if
1537    };
1538
1539    return {
1540      restrict: 'AE',
1541      controller: 'MapController',
1542      link: linkFunc
1543    }; 
1544  };
1545
1546  angular.module('ngMap').directive('map', ['Attr2Options', '$timeout', '$parse', mapDirective]);
1547})();
1548
1549/* global google */
1550(function() {
1551  'use strict';
1552
1553  /**
1554   * @ngdoc controller
1555   * @name MapController
1556   * @requires $scope
1557   * @property {Hash} controls collection of Controls initiated within `map` directive
1558   * @property {Hash} markers collection of Markers initiated within `map` directive
1559   * @property {Hash} shapes collection of shapes initiated within `map` directive
1560   */
1561  var MapController = function($q, NavigatorGeolocation, GeoCoder, Attr2Options) { 
1562    var parser = Attr2Options;
1563    var _this = this;
1564
1565    var observeAndSet = function(attrs, attrName, object) {
1566      attrs.$observe(attrName, function(val) {
1567        if (val) {
1568          void 0;
1569          var setMethod = parser.camelCase('set-'+attrName);
1570          var optionValue = parser.toOptionValue(val, {key: attrName});
1571          void 0;
1572          if (object[setMethod]) { //if set method does exist
1573            /* if an location is being observed */
1574            if (attrName.match(/center|position/) && 
1575              typeof optionValue == 'string') {
1576              _this.getGeoLocation(optionValue).then(function(latlng) {
1577                object[setMethod](latlng);
1578              });
1579            } else {
1580              object[setMethod](optionValue);
1581            }
1582          }
1583        }
1584      });
1585    };
1586
1587    this.map = null;
1588    this._objects = []; /* temporary collection of map objects */
1589
1590    /**
1591     * Add an object to the collection of group
1592     * @memberof MapController
1593     * @function addObject
1594     * @param groupName the name of collection that object belongs to
1595     * @param obj  an object to add into a collection, i.e. marker, shape
1596     */
1597    this.addObject = function(groupName, obj) {
1598      /**
1599       * objects, i.e. markers and shapes, are initialized before map is initialized
1600       * so, we collect those objects, then, we will add to map when map is initialized
1601       * However the case as in ng-repeat, we can directly add to map
1602       */
1603      if (this.map) {
1604        this.map[groupName] = this.map[groupName] || {};
1605        var len = Object.keys(this.map[groupName]).length;
1606        this.map[groupName][obj.id || len] = obj;
1607        if (groupName != "infoWindows" && obj.setMap) { //infoWindow.setMap works like infoWindow.open
1608          obj.setMap && obj.setMap(this.map);
1609        }
1610        if (obj.centered && obj.position) {
1611          this.map.setCenter(obj.position);
1612        }
1613      } else {
1614        obj.groupName = groupName;
1615        this._objects.push(obj);
1616      }
1617    };
1618
1619    /**
1620     * Delete an object from the collection and remove from map
1621     * @memberof MapController
1622     * @function deleteObject
1623     * @param {Array} objs the collection of objects. i.e., map.markers
1624     * @param {Object} obj the object to be removed. i.e., marker
1625     */
1626    this.deleteObject = function(groupName, obj) {
1627      /* delete from group */
1628      var objs = obj.map[groupName];
1629      for (var name in objs) {
1630        objs[name] === obj && (delete objs[name]);
1631      }
1632
1633      /* delete from map */
1634      obj.map && obj.setMap && obj.setMap(null);
1635    };
1636
1637    /**
1638     * Add collected objects to map
1639     * @memberof MapController
1640     * @function addObjects
1641     * @param {Array} objects the collection of objects. i.e., map.markers
1642     */
1643    this.addObjects = function(objects) {
1644      for (var i=0; i<objects.length; i++) {
1645        var obj=objects[i];
1646        if (obj instanceof google.maps.Marker) {
1647          this.addObject('markers', obj);
1648        } else if (obj instanceof google.maps.Circle ||
1649          obj instanceof google.maps.Polygon ||
1650          obj instanceof google.maps.Polyline ||
1651          obj instanceof google.maps.Rectangle ||
1652          obj instanceof google.maps.GroundOverlay) {
1653          this.addObject('shapes', obj);
1654        } else {
1655          this.addObject(obj.groupName, obj);
1656        }
1657      }
1658    };
1659
1660    /**
1661     * returns the location of an address or 'current-location'
1662     * @memberof MapController
1663     * @function getGeoLocation
1664     * @param {String} string an address to find the location
1665     * @returns {Promise} latlng the location of the address
1666     */
1667    this.getGeoLocation = function(string) {
1668      var deferred = $q.defer();
1669      if (!string || string.match(/^current/i)) { // current location
1670        NavigatorGeolocation.getCurrentPosition().then(
1671          function(position) {
1672            var lat = position.coords.latitude;
1673            var lng = position.coords.longitude;
1674            var latLng = new google.maps.LatLng(lat,lng);
1675            deferred.resolve(latLng);
1676          },
1677          function(error) {
1678            deferred.reject(error);
1679          }
1680        );
1681      } else {
1682        GeoCoder.geocode({address: string}).then(
1683          function(results) {
1684            deferred.resolve(results[0].geometry.location);
1685          },
1686          function(error) {
1687            deferred.reject(error);
1688          }
1689        );
1690      }
1691
1692      return deferred.promise;
1693    };
1694
1695    /**
1696     * watch changes of attribute values and do appropriate action based on attribute name
1697     * @memberof MapController
1698     * @function observeAttrSetObj
1699     * @param {Hash} orgAttrs attributes before its initialization
1700     * @param {Hash} attrs    attributes after its initialization
1701     * @param {Object} obj    map object that an action is to be done
1702     */
1703    this.observeAttrSetObj = function(orgAttrs, attrs, obj) {
1704      var attrsToObserve = parser.getAttrsToObserve(orgAttrs);
1705      if (Object.keys(attrsToObserve).length) {
1706        void 0;
1707      }
1708      for (var i=0; i<attrsToObserve.length; i++) {
1709        observeAndSet(attrs, attrsToObserve[i], obj);
1710      }
1711    };
1712
1713
1714  }; // MapController
1715
1716  MapController.$inject = ['$q', 'NavigatorGeolocation', 'GeoCoder', 'Attr2Options'];
1717  angular.module('ngMap').controller('MapController', MapController);
1718})();
1719
1720/**
1721 * @ngdoc directive
1722 * @name maps-engine-layer
1723 * @description 
1724 *   Requires:  map directive
1725 *   Restrict To:  Element
1726 *
1727 * @example
1728 * Example: 
1729 *   <map zoom="14" center="[59.322506, 18.010025]">
1730 *     <maps-engine-layer layer-id="06673056454046135537-08896501997766553811"></maps-engine-layer>
1731 *    </map>
1732 */
1733/*jshint -W089*/
1734ngMap.directive('mapsEngineLayer', ['Attr2Options', function(Attr2Options) {
1735  var parser = Attr2Options;
1736
1737  var getMapsEngineLayer = function(options, events) {
1738    var layer = new google.maps.visualization.MapsEngineLayer(options);
1739
1740    for (var eventName in events) {
1741      google.maps.event.addListener(layer, eventName, events[eventName]);
1742    }
1743
1744    return layer;
1745  };
1746
1747  
1748  return {
1749    restrict: 'E',
1750    require: '^map',
1751
1752    link: function(scope, element, attrs, mapController) {
1753      var filtered = parser.filter(attrs);
1754      var options = parser.getOptions(filtered);
1755      var events = parser.getEvents(scope, filtered, events);
1756      void 0;
1757
1758      var layer = getMapsEngineLayer(options, events);
1759      mapController.addObject('mapsEngineLayers', layer);
1760    }
1761   }; // return
1762}]);
1763
1764/**
1765 * @ngdoc directive
1766 * @name marker
1767 * @requires Attr2Options 
1768 * @requires NavigatorGeolocation
1769 * @description 
1770 *   Draw a Google map marker on a map with given options and register events  
1771 *   
1772 *   Requires:  map directive
1773 *
1774 *   Restrict To:  Element 
1775 *
1776 * @param {String} position address, 'current', or [latitude, longitude]  
1777 *    example:  
1778 *      '1600 Pennsylvania Ave, 20500  Washingtion DC',   
1779 *      'current position',  
1780 *      '[40.74, -74.18]'  
1781 * @param {Boolean} centered if set, map will be centered with this marker
1782 * @param {Expression} geo-callback if position is an address, the expression is will be performed when geo-lookup is successful. e.g., geo-callback="showStoreInfo()"
1783 * @param {String} &lt;MarkerOption> Any Marker options, https://developers.google.com/maps/documentation/javascript/reference?csw=1#MarkerOptions  
1784 * @param {String} &lt;MapEvent> Any Marker events, https://developers.google.com/maps/documentation/javascript/reference
1785 * @example
1786 * Usage: 
1787 *   <map MAP_ATTRIBUTES>
1788 *    <marker ANY_MARKER_OPTIONS ANY_MARKER_EVENTS"></MARKER>
1789 *   </map>
1790 *
1791 * Example: 
1792 *   <map center="[40.74, -74.18]">
1793 *    <marker position="[40.74, -74.18]" on-click="myfunc()"></div>
1794 *   </map>
1795 *
1796 *   <map center="the cn tower">
1797 *    <marker position="the cn tower" on-click="myfunc()"></div>
1798 *   </map>
1799 */
1800/* global google */
1801(function() {
1802  'use strict';
1803
1804  var getMarker = function(options, events) {
1805    var marker;
1806
1807    /**
1808     * set options
1809     */
1810    if (options.icon instanceof Object) {
1811      if ((""+options.icon.path).match(/^[A-Z_]+$/)) {
1812        options.icon.path =  google.maps.SymbolPath[options.icon.path];
1813      }
1814      for (var key in options.icon) {
1815        var arr = options.icon[key];
1816        if (key == "anchor" || key == "origin") {
1817          options.icon[key] = new google.maps.Point(arr[0], arr[1]);
1818        } else if (key == "size" || key == "scaledSize") {
1819          options.icon[key] = new google.maps.Size(arr[0], arr[1]);
1820        } 
1821      }
1822    }
1823    if (!(options.position instanceof google.maps.LatLng)) {
1824      options.position = new google.maps.LatLng(0,0);
1825    } 
1826    marker = new google.maps.Marker(options);
1827
1828    /**
1829     * set events
1830     */
1831    if (Object.keys(events).length > 0) {
1832      void 0;
1833    }
1834    for (var eventName in events) {
1835      if (eventName) {
1836        google.maps.event.addListener(marker, eventName, events[eventName]);
1837      }
1838    }
1839
1840    return marker;
1841  };
1842
1843  var marker = function(Attr2Options, $parse) {
1844    var parser = Attr2Options;
1845    var linkFunc = function(scope, element, attrs, mapController) {
1846      var orgAttrs = parser.orgAttributes(element);
1847      var filtered = parser.filter(attrs);
1848      var markerOptions = parser.getOptions(filtered, scope);
1849      var markerEvents = parser.getEvents(scope, filtered);
1850      void 0;
1851
1852      var address;
1853      if (!(markerOptions.position instanceof google.maps.LatLng)) {
1854        address = markerOptions.position;
1855      }
1856      var marker = getMarker(markerOptions, markerEvents);
1857      mapController.addObject('markers', marker);
1858      if (address) {
1859        mapController.getGeoLocation(address).then(function(latlng) {
1860          marker.setPosition(latlng);
1861          markerOptions.centered && marker.map.setCenter(latlng);
1862          var geoCallback = attrs.geoCallback;
1863          geoCallback && $parse(geoCallback)(scope);
1864        });
1865      }
1866
1867      /**
1868       * set observers
1869       */
1870      mapController.observeAttrSetObj(orgAttrs, attrs, marker); /* observers */
1871      element.bind('$destroy', function() {
1872        mapController.deleteObject('markers', marker);
1873      });
1874    };
1875
1876    return {
1877      restrict: 'E',
1878      require: '^map',
1879      link: linkFunc
1880    };
1881  };
1882
1883  marker.$inject = ['Attr2Options', '$parse'];
1884  angular.module('ngMap').directive('marker', marker); 
1885
1886})();
1887
1888/**
1889 * @ngdoc directive
1890 * @name overlay-map-type
1891 * @requires Attr2Options 
1892 * @description 
1893 *   Requires:  map directive
1894 *   Restrict To:  Element
1895 *
1896 * @example
1897 * Example: 
1898 *
1899 *   <map zoom="13" center="34.04924594193164, -118.24104309082031">
1900 *     <overlay-map-type index="0" object="coordinateMapType"></map-type>
1901 *   </map>
1902 */
1903/*jshint -W089*/
1904ngMap.directive('overlayMapType', ['Attr2Options', '$window', function(Attr2Options, $window) {
1905  var parser = Attr2Options;
1906  
1907  return {
1908    restrict: 'E',
1909    require: '^map',
1910
1911    link: function(scope, element, attrs, mapController) {
1912      var overlayMapTypeObject;
1913      var initMethod = attrs.initMethod || "insertAt";
1914      if (attrs.object) {
1915        var __scope = scope[attrs.object] ? scope : $window;
1916        overlayMapTypeObject = __scope[attrs.object];
1917        if (typeof overlayMapTypeObject == "function") {
1918          overlayMapTypeObject = new overlayMapTypeObject();
1919        }
1920      }
1921      if (!overlayMapTypeObject) {
1922        throw "invalid map-type object";
1923      }
1924
1925      scope.$on('mapInitialized', function(evt, map) {
1926        if (initMethod == "insertAt") {
1927          var index = parseInt(attrs.index, 10);
1928          map.overlayMapTypes.insertAt(index, overlayMapTypeObject);
1929        } else if (initMethod == "push") {
1930          map.overlayMapTypes.push(overlayMapTypeObject);
1931        }
1932      });
1933      mapController.addObject('overlayMapTypes', overlayMapTypeObject);
1934    }
1935   }; // return
1936}]);
1937
1938/**
1939 * @ngdoc directive
1940 * @name places-auto-complete
1941 * @requires Attr2Options 
1942 * @description 
1943 *   Provides address auto complete feature to an input element
1944 *   Requires: input tag
1945 *   Restrict To: Attribute
1946 *
1947 * @param {AutoCompleteOptions} Any AutocompleteOptions
1948 *    https://developers.google.com/maps/documentation/javascript/3.exp/reference#AutocompleteOptions
1949 *
1950 * @example
1951 * Example: 
1952 *   <script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
1953 *   <input places-auto-complete types="['geocode']" />
1954 */
1955/* global google */
1956(function() {
1957  'use strict';
1958
1959  var placesAutoComplete = function(Attr2Options, $timeout) {
1960    var parser = Attr2Options;
1961
1962    var linkFunc = function(scope, element, attrs, ngModelCtrl) {
1963      var filtered = parser.filter(attrs);
1964      var options = parser.getOptions(filtered);
1965      var events = parser.getEvents(scope, filtered);
1966      void 0;
1967      var autocomplete = new google.maps.places.Autocomplete(element[0], options);
1968      for (var eventName in events) {
1969        google.maps.event.addListener(autocomplete, eventName, events[eventName]);
1970      }
1971      element[0].addEventListener('change', function() {
1972        $timeout(function(){
1973          ngModelCtrl && ngModelCtrl.$setViewValue(element.val());
1974        },100);
1975      });
1976
1977      attrs.$observe('types', function(val) {
1978        if (val) {
1979          void 0;
1980          var optionValue = parser.toOptionValue(val, {key: 'types'});
1981          void 0;
1982          autocomplete.setTypes(optionValue);
1983        }
1984      });
1985    };
1986
1987    return {
1988      restrict: 'A',
1989      require: '?ngModel',
1990      link: linkFunc
1991    };
1992  };
1993
1994  placesAutoComplete.$inject = ['Attr2Options', '$timeout'];
1995  angular.module('ngMap').directive('placesAutoComplete', placesAutoComplete); 
1996
1997})();
1998
1999/**
2000 * @ngdoc directive
2001 * @name shape
2002 * @requires Attr2Options 
2003 * @description 
2004 *   Initialize a Google map shape in map with given options and register events  
2005 *   The shapes are:
2006 *     . circle
2007 *     . polygon
2008 *     . polyline
2009 *     . rectangle
2010 *     . groundOverlay(or image)
2011 *   
2012 *   Requires:  map directive
2013 *
2014 *   Restrict To:  Element
2015 *
2016 * @param {Boolean} centered if set, map will be centered with this marker
2017 * @param {Expression} geo-callback if shape is a circle and the center is an address, the expression is will be performed when geo-lookup is successful. e.g., geo-callback="showDetail()"
2018 * @param {String} &lt;OPTIONS>
2019 *   For circle, [any circle options](https://developers.google.com/maps/documentation/javascript/reference#CircleOptions)  
2020 *   For polygon, [any polygon options](https://developers.google.com/maps/documentation/javascript/reference#PolygonOptions)  
2021 *   For polyline, [any polyline options](https://developers.google.com/maps/documentation/javascript/reference#PolylineOptions)   
2022 *   For rectangle, [any rectangle options](https://developers.google.com/maps/documentation/javascript/reference#RectangleOptions)   
2023 *   For image, [any groundOverlay options](https://developers.google.com/maps/documentation/javascript/reference#GroundOverlayOptions)   
2024 * @param {String} &lt;MapEvent> Any Shape events, https://developers.google.com/maps/documentation/javascript/reference
2025 * @example
2026 * Usage: 
2027 *   <map MAP_ATTRIBUTES>
2028 *    <shape name=SHAPE_NAME ANY_SHAPE_OPTIONS ANY_SHAPE_EVENTS"></MARKER>
2029 *   </map>
2030 *
2031 * Example: 
2032 *
2033 *   <map zoom="11" center="[40.74, -74.18]">
2034 *     <shape id="polyline" name="polyline" geodesic="true" stroke-color="#FF0000" stroke-opacity="1.0" stroke-weight="2"
2035 *      path="[[40.74,-74.18],[40.64,-74.10],[40.54,-74.05],[40.44,-74]]" ></shape>
2036 *    </map>
2037 *
2038 *   <map zoom="11" center="[40.74, -74.18]">
2039 *     <shape id="polygon" name="polygon" stroke-color="#FF0000" stroke-opacity="1.0" stroke-weight="2"
2040 *      paths="[[40.74,-74.18],[40.64,-74.18],[40.84,-74.08],[40.74,-74.18]]" ></shape>
2041 *   </map>
2042 *   
2043 *   <map zoom="11" center="[40.74, -74.18]">
2044 *     <shape id="rectangle" name="rectangle" stroke-color='#FF0000' stroke-opacity="0.8" stroke-weight="2"
2045 *      bounds="[[40.74,-74.18], [40.78,-74.14]]" editable="true" ></shape>
2046 *   </map>
2047 *
2048 *   <map zoom="11" center="[40.74, -74.18]">
2049 *     <shape id="circle" name="circle" stroke-color='#FF0000' stroke-opacity="0.8"stroke-weight="2" 
2050 *      center="[40.70,-74.14]" radius="4000" editable="true" ></shape>
2051 *   </map>
2052 *
2053 *   <map zoom="11" center="[40.74, -74.18]">
2054 *     <shape id="image" name="image" url="https://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg"
2055 *      bounds="[[40.71,-74.22],[40.77,-74.12]]" opacity="0.7" clickable="true" ></shape>
2056 *   </map>
2057 *
2058 *  For full-working example, please visit 
2059 *    [shape example](https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/shape.html)
2060 */
2061/* global google */
2062(function() {
2063  'use strict';
2064
2065  var getBounds = function(points) {
2066    return new google.maps.LatLngBounds(points[0], points[1]);
2067  };
2068  
2069  var getShape = function(options, events) {
2070    var shape;
2071
2072    var shapeName = options.name;
2073    delete options.name;  //remove name bcoz it's not for options
2074    void 0;
2075
2076    /**
2077     * set options
2078     */
2079    if (options.icons) {
2080      for (var i=0; i<options.icons.length; i++) {
2081        var el = options.icons[i];
2082        if (el.icon.path.match(/^[A-Z_]+$/)) {
2083          el.icon.path =  google.maps.SymbolPath[el.icon.path];
2084        }
2085      }
2086    }
2087    switch(shapeName) {
2088      case "circle":
2089        if (!(options.center instanceof google.maps.LatLng)) {
2090          options.center = new google.maps.LatLng(0,0);
2091        } 
2092        shape = new google.maps.Circle(options);
2093        break;
2094      case "polygon":
2095        shape = new google.maps.Polygon(options);
2096        break;
2097      case "polyline": 
2098        shape = new google.maps.Polyline(options);
2099        break;
2100      case "rectangle": 
2101        if (options.bounds) {
2102          options.bounds = getBounds(options.bounds);
2103        }
2104        shape = new google.maps.Rectangle(options);
2105        break;
2106      case "groundOverlay":
2107      case "image":
2108        var url = options.url;
2109        var bounds = getBounds(options.bounds);
2110        var opts = {opacity: options.opacity, clickable: options.clickable, id:options.id};
2111        shape = new google.maps.GroundOverlay(url, bounds, opts);
2112        break;
2113    }
2114
2115    /**
2116     * set events
2117     */
2118    for (var eventName in events) {
2119      if (events[eventName]) {
2120        google.maps.event.addListener(shape, eventName, events[eventName]);
2121      }
2122    }
2123    return shape;
2124  };
2125
2126  var shape = function(Attr2Options, $parse) {
2127    var parser = Attr2Options;
2128
2129    var linkFunc = function(scope, element, attrs, mapController) {
2130      var orgAttrs = parser.orgAttributes(element);
2131      var filtered = parser.filter(attrs);
2132      var shapeOptions = parser.getOptions(filtered);
2133      var shapeEvents = parser.getEvents(scope, filtered);
2134
2135      var address, shapeType;
2136      shapeType = shapeOptions.name;
2137      if (!(shapeOptions.center instanceof google.maps.LatLng)) {
2138        address = shapeOptions.center;
2139      }
2140      var shape = getShape(shapeOptions, shapeEvents);
2141      mapController.addObject('shapes', shape);
2142
2143      if (address && shapeType == 'circle') {
2144        mapController.getGeoLocation(address).then(function(latlng) {
2145          shape.setCenter(latlng);
2146          shape.centered && shape.map.setCenter(latlng);
2147          var geoCallback = attrs.geoCallback;
2148          geoCallback && $parse(geoCallback)(scope);
2149        });
2150      }
2151
2152      /**
2153       * set observers
2154       */
2155      mapController.observeAttrSetObj(orgAttrs, attrs, shape); 
2156      element.bind('$destroy', function() {
2157        mapController.deleteObject('shapes', shape);
2158      });
2159    };
2160
2161    return {
2162      restrict: 'E',
2163      require: '^map',
2164      link: linkFunc
2165     }; // return
2166  };
2167  shape.$inject = ['Attr2Options', '$parse'];
2168
2169  angular.module('ngMap').directive('shape', shape);
2170
2171})();
2172
2173/**
2174 * @ngdoc directive
2175 * @name streetview-panorama
2176 * @requires Attr2Options
2177 * @description
2178 *   Requires:  map directive
2179 *   Restrict To:  Element
2180 *
2181 * @param container Optional, id or css selector, if given, streetview will be in the given html element
2182 * @param {String} &lt;StreetViewPanoramaOption> Any Google StreetViewPanorama options, 
2183 *        https://developers.google.com/maps/documentation/javascript/reference?csw=1#StreetViewPanoramaOptions
2184 * @param {String} &lt;StreetViewPanoramaEvent> Any Google StreetViewPanorama events, 
2185 *        https://developers.google.com/maps/documentation/javascript/reference#StreetViewPanorama 
2186 *
2187 * @example
2188 *   <map zoom="11" center="[40.688738,-74.043871]" >
2189 *     <street-view-panorama
2190 *       click-to-go="true"
2191 *       disable-default-ui="true"
2192 *       disable-double-click-zoom="true"
2193 *       enable-close-button="true"
2194 *       pano="my-pano"
2195 *       position="40.688738,-74.043871"
2196 *       pov="{heading:0, pitch: 90}"
2197 *       scrollwheel="false"
2198 *       visible="true">
2199 *     </street-view-panorama>
2200 *   </map>
2201 */
2202/* global google */
2203(function() {
2204  'use strict';
2205   
2206  var streetViewPanorama = function(Attr2Options) {
2207    var parser = Attr2Options;
2208  
2209    var getStreetViewPanorama = function(map, options, events) {
2210      var svp, container;
2211      if (options.container) {
2212        container = document.getElementById(options.container);
2213        container = container || document.querySelector(options.container);
2214      }
2215      if (container) {
2216        svp = new google.maps.StreetViewPanorama(container, options);
2217      } else {
2218        svp = map.getStreetView();
2219        svp.setOptions(options);
2220      }
2221
2222      for (var eventName in events) {
2223        eventName &&
2224          google.maps.event.addListener(svp, eventName, events[eventName]);
2225      }
2226      return svp;
2227    };
2228
2229    var linkFunc = function(scope, element, attrs, mapController) {
2230      var orgAttrs = parser.orgAttributes(element);
2231      var filtered = parser.filter(attrs);
2232      var options = parser.getOptions(filtered);
2233      var controlOptions = parser.getControlOptions(filtered);
2234      var svpOptions = angular.extend(options, controlOptions);
2235
2236      var svpEvents = parser.getEvents(scope, filtered);
2237      void 0;
2238 
2239      scope.$on('mapInitialized', function(evt, map) {
2240        var svp = getStreetViewPanorama(map, svpOptions, svpEvents);
2241
2242        map.setStreetView(svp);
2243        (!svp.getPosition()) && svp.setPosition(map.getCenter());
2244        google.maps.event.addListener(svp, 'position_changed', function() {
2245          if (svp.getPosition() !== map.getCenter()) {
2246            map.setCenter(svp.getPosition());
2247          }
2248        });
2249        //needed for geo-callback
2250        var listener = google.maps.event.addListener(map, 'center_changed', function() {
2251          svp.setPosition(map.getCenter());
2252          google.maps.event.removeListener(listener);
2253        });
2254      });
2255
2256    }; //link
2257
2258    return {
2259      restrict: 'E',
2260      require: '^map',
2261      link: linkFunc
2262    };
2263
2264  };
2265  streetViewPanorama.$inject = ['Attr2Options'];
2266
2267  angular.module('ngMap').directive('streetViewPanorama', streetViewPanorama);
2268})();
2269
2270/**
2271 * @ngdoc directive
2272 * @name traffic-layer
2273 * @requires Attr2Options 
2274 * @description 
2275 *   Requires:  map directive
2276 *   Restrict To:  Element
2277 *
2278 * @example
2279 * Example: 
2280 *
2281 *   <map zoom="13" center="34.04924594193164, -118.24104309082031">
2282 *     <traffic-layer></traffic-layer>
2283 *    </map>
2284 */
2285/*jshint -W089*/
2286ngMap.directive('trafficLayer', ['Attr2Options', function(Attr2Options) {
2287  var parser = Attr2Options;
2288  
2289  var getLayer = function(options, events) {
2290    var layer = new google.maps.TrafficLayer(options);
2291    for (var eventName in events) {
2292      google.maps.event.addListener(layer, eventName, events[eventName]);
2293    }
2294    return layer;
2295  };
2296  
2297  return {
2298    restrict: 'E',
2299    require: '^map',
2300
2301    link: function(scope, element, attrs, mapController) {
2302      var orgAttrs = parser.orgAttributes(element);
2303      var filtered = parser.filter(attrs);
2304      var options = parser.getOptions(filtered);
2305      var events = parser.getEvents(scope, filtered);
2306      void 0;
2307
2308      var layer = getLayer(options, events);
2309      mapController.addObject('trafficLayers', layer);
2310      mapController.observeAttrSetObj(orgAttrs, attrs, layer);  //observers
2311      element.bind('$destroy', function() {
2312        mapController.deleteObject('trafficLayers', layer);
2313      });
2314    }
2315   }; // return
2316}]);
2317
2318/**
2319 * @ngdoc directive
2320 * @name transit-layer
2321 * @requires Attr2Options 
2322 * @description 
2323 *   Requires:  map directive
2324 *   Restrict To:  Element
2325 *
2326 * @example
2327 * Example: 
2328 *
2329 *   <map zoom="13" center="34.04924594193164, -118.24104309082031">
2330 *     <transit-layer></transit-layer>
2331 *    </map>
2332 */
2333/*jshint -W089*/
2334ngMap.directive('transitLayer', ['Attr2Options', function(Attr2Options) {
2335  var parser = Attr2Options;
2336  
2337  var getLayer = function(options, events) {
2338    var layer = new google.maps.TransitLayer(options);
2339    for (var eventName in events) {
2340      google.maps.event.addListener(layer, eventName, events[eventName]);
2341    }
2342    return layer;
2343  };
2344  
2345  return {
2346    restrict: 'E',
2347    require: '^map',
2348
2349    link: function(scope, element, attrs, mapController) {
2350      var orgAttrs = parser.orgAttributes(element);
2351      var filtered = parser.filter(attrs);
2352      var options = parser.getOptions(filtered);
2353      var events = parser.getEvents(scope, filtered);
2354      void 0;
2355
2356      var layer = getLayer(options, events);
2357      mapController.addObject('transitLayers', layer);
2358      mapController.observeAttrSetObj(orgAttrs, attrs, layer);  //observers
2359      element.bind('$destroy', function() {
2360        mapController.deleteObject('transitLayers', layer);
2361      });
2362    }
2363   }; // return
2364}]);
2365
2366/**
2367 * @ngdoc directive
2368 * @name weather-layer
2369 * @requires Attr2Options 
2370 * @description 
2371 *   Requires:  map directive
2372 *   Restrict To:  Element
2373 *
2374 * @example
2375 * Example: 
2376 *
2377 *   <map zoom="13" center="34.04924594193164, -118.24104309082031">
2378 *     <weather-layer></weather-layer>
2379 *    </map>
2380 */
2381/*jshint -W089*/
2382ngMap.directive('weatherLayer', ['Attr2Options', function(Attr2Options) {
2383  var parser = Attr2Options;
2384  
2385  var getLayer = function(options, events) {
2386    var layer = new google.maps.weather.WeatherLayer(options);
2387    for (var eventName in events) {
2388      google.maps.event.addListener(layer, eventName, events[eventName]);
2389    }
2390    return layer;
2391  };
2392  
2393  return {
2394    restrict: 'E',
2395    require: '^map',
2396
2397    link: function(scope, element, attrs, mapController) {
2398      var orgAttrs = parser.orgAttributes(element);
2399      var filtered = parser.filter(attrs);
2400      var options = parser.getOptions(filtered);
2401      var events = parser.getEvents(scope, filtered);
2402
2403      void 0;
2404
2405      var layer = getLayer(options, events);
2406      mapController.addObject('weatherLayers', layer);
2407      mapController.observeAttrSetObj(orgAttrs, attrs, layer);  //observers
2408      element.bind('$destroy', function() {
2409        mapController.deleteObject('weatherLayers', layer);
2410      });
2411    }
2412   }; // return
2413}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.